Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,18 @@ The [`master`](https://github.com/codequest-eu/terraform-single-page-app/tree/ma

## Inputs

| Name | Description | Type | Default | Required |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | :----: | :----------------: | :------: |
| bucket | Kebab-cased bucket name override | string | `""` | no |
| certificate\_arn | ACM certificate ARN to use instead of the default cloudfront certificate | string | `""` | no |
| cloudfront\_price\_class | CloudFront price class, which specifies where the distribution should be replicated, one of: PriceClass_100, PriceClass_200, PriceClass_All | string | `"PriceClass_100"` | no |
| domains | List of domains which will serve the application. If empty, will use the default cloudfront domain | list | `<list>` | no |
| environment | Kebab-cased name of the environment, eg. production, staging, development, preview. Will be included in resource names | string | n/a | yes |
| project | Kebab-cased name of the project. Will be included in resource names | string | n/a | yes |
| static\_cors\_max\_age\_seconds | How long can CORS OPTIONS request responses be cached | string | `"3600"` | no |
| static\_path | Base path for static assets | string | `"/static"` | no |
| tags | Additional tags to add to each resource that supports them | map | `<map>` | no |
| Name | Description | Type | Default | Required |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | :----: | :------------------: | :------: |
| bucket | Kebab-cased bucket name override | string | `""` | no |
| certificate\_arn | ACM certificate ARN to use instead of the default cloudfront certificate | string | `""` | no |
| cloudfront\_price\_class | CloudFront price class, which specifies where the distribution should be replicated, one of: PriceClass_100, PriceClass_200, PriceClass_All | string | `"PriceClass_100"` | no |
| domains | List of domains which will serve the application. If empty, will use the default cloudfront domain | list | `<list>` | no |
| environment | Kebab-cased name of the environment, eg. production, staging, development, preview. Will be included in resource names | string | n/a | yes |
| project | Kebab-cased name of the project. Will be included in resource names | string | n/a | yes |
| pull\_request\_path\_re | Regular expression which extracts the base directory of a PR as it's first match group | string | `"^/(PR-\\d+)($|/)"` | no |
| static\_cors\_max\_age\_seconds | How long can CORS OPTIONS request responses be cached | string | `"3600"` | no |
| static\_path | Base path for static assets | string | `"/static"` | no |
| tags | Additional tags to add to each resource that supports them | map | `<map>` | no |

## Outputs

Expand Down
2 changes: 1 addition & 1 deletion example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module "basic" {

resource "aws_s3_bucket_object" "basic_index" {
bucket = "${module.basic.bucket_name}"
key = "index.html"
key = "PR-1/index.html"
content = "<h1>Hello world</h1>"
content_type = "text/html"
cache_control = "no-cache no-store"
Expand Down
46 changes: 40 additions & 6 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
provider "aws" {
alias = "middleware"
}

resource "aws_s3_bucket" "assets" {
bucket = "${var.bucket != "" ? var.bucket : "${local.name_prefix}-assets"}"
acl = "private"
Expand Down Expand Up @@ -94,13 +98,12 @@ resource "aws_cloudfront_distribution" "assets" {
forward = "none"
}
}
}

custom_error_response {
error_code = 404
error_caching_min_ttl = 0
response_code = 200
response_page_path = "/index.html"
lambda_function_association {
event_type = "origin-request"
lambda_arn = "${module.pull_request_router.arn}"
include_body = false
}
}

restrictions {
Expand All @@ -118,3 +121,34 @@ resource "aws_cloudfront_distribution" "assets" {

tags = "${local.tags}"
}

module "middleware_common" {
source = "./middleware_common"

name_prefix = "${local.name_prefix}"

providers = {
aws = "aws.middleware"
}
}

data "template_file" "pull_request_router" {
template = "${file("${path.module}/templates/pull-request-router.js")}"

vars {
path_re = "${var.pull_request_path_re}"
}
}

module "pull_request_router" {
source = "./middleware"

name = "${local.name_prefix}-pull-request-router"
code = "${data.template_file.pull_request_router.rendered}"
role_arn = "${module.middleware_common.role_arn}"
tags = "${local.tags}"

providers = {
aws = "aws.middleware"
}
}
19 changes: 19 additions & 0 deletions templates/pull-request-router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const path = require("path")

const r = String.raw
const pathRe = new RegExp(r`${path_re}`)

exports.handler = (evt, ctx, cb) => {
const { request } = evt.Records[0].cf
console.log("<-", request.uri)

const match = pathRe.exec(request.uri)
const extension = path.extname(request.uri)

if (match && !extension) {
request.uri = `/$${match[1]}/index.html`
}

console.log("->", request.uri)
cb(null, request)
}
5 changes: 5 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@ variable "bucket" {
description = "Kebab-cased bucket name override"
default = ""
}

variable "pull_request_path_re" {
description = "Regular expression which extracts the base directory of a PR as it's first match group"
default = "^/(PR-\\d+)($|/)"
}