Skip to content

Commit 223f30c

Browse files
ostermanjoshmyers
authored andcommitted
Add webhook support (#14)
* Add webhook support * fix outputs * fix args * Ignore special characters * change to form * add missing secret * format * use json * Update docs * Update desc
1 parent ff2e84c commit 223f30c

File tree

6 files changed

+180
-9
lines changed

6 files changed

+180
-9
lines changed

README.md

+47-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# terraform-aws-ecs-codepipeline [![Build Status](https://travis-ci.org/cloudposse/terraform-aws-ecs-codepipeline.svg?branch=master)](https://travis-ci.org/cloudposse/terraform-aws-ecs-codepipeline) [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-aws-ecs-codepipeline.svg)](https://github.com/cloudposse/terraform-aws-ecs-codepipeline/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com)
77

88

9-
Terraform Module for CI/CD with AWS Code Pipeline and Code Build for ECS.
9+
Terraform Module for CI/CD with AWS Code Pipeline using GitHub webhook triggers and Code Build for ECS.
1010

1111

1212
---
@@ -42,8 +42,32 @@ We literally have [*hundreds of terraform modules*][terraform_modules] that are
4242

4343
## Usage
4444

45+
46+
### Trigger on GitHub Push
47+
48+
In this example, we'll trigger the pipeline anytime the `master` branch is updated.
49+
```hcl
50+
module "ecs_push_pipeline" {
51+
source = "git::https://github.com/cloudposse/terraform-aws-ecs-codepipeline.git?ref=tags/0.1.2"
52+
name = "app"
53+
namespace = "eg"
54+
stage = "staging"
55+
github_oauth_token = "xxxxxxxxxxxxxx"
56+
repo_owner = "cloudposse"
57+
repo_name = "example"
58+
branch = "master"
59+
service_name = "example"
60+
ecs_cluster_name = "example-ecs-cluster"
61+
privileged_mode = "true"
62+
}
63+
```
64+
65+
### Trigger on GitHub Releases
66+
67+
In this example, we'll trigger anytime a new GitHub release is cut by setting the even type to `release` and using the `json_path` to *exactly* match an `action` of `published`.
68+
4569
```hcl
46-
module "ecs_codepipeline" {
70+
module "ecs_release_pipeline" {
4771
source = "git::https://github.com/cloudposse/terraform-aws-ecs-codepipeline.git?ref=tags/0.1.2"
4872
name = "app"
4973
namespace = "eg"
@@ -55,8 +79,12 @@ module "ecs_codepipeline" {
5579
service_name = "example"
5680
ecs_cluster_name = "example-ecs-cluster"
5781
privileged_mode = "true"
82+
github_webhook_events = ["release"]
83+
webhook_filter_json_path = "$.action"
84+
webhook_filter_match_equals = "published"
5885
}
5986
```
87+
(Thanks to [Stack Overflow](https://stackoverflow.com/questions/52516087/trigger-aws-codepipeline-by-github-release-webhook#comment91997146_52524711))
6088

6189

6290

@@ -94,23 +122,31 @@ Available targets:
94122
| enabled | Enable `CodePipeline` creation | string | `true` | no |
95123
| environment_variables | A list of maps, that contain both the key 'name' and the key 'value' to be used as additional environment variables for the build. | list | `<list>` | no |
96124
| github_oauth_token | GitHub Oauth Token with permissions to access private repositories | string | - | yes |
125+
| github_webhook_events | A list of events which should trigger the webhook. See a list of [available events](https://developer.github.com/v3/activity/events/types/). | list | `<list>` | no |
97126
| image_repo_name | ECR repository name to store the Docker image built by this module. Used as CodeBuild ENV variable when building Docker images. [For more info](http://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker.html) | string | `UNSET` | no |
98127
| image_tag | Docker image tag in the ECR repository, e.g. 'latest'. Used as CodeBuild ENV variable when building Docker images. [For more info](http://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker.html) | string | `latest` | no |
99128
| name | Solution name, e.g. 'app' or 'jenkins' | string | `app` | no |
100129
| namespace | Namespace, which could be your organization name, e.g. 'cp' or 'cloudposse' | string | `global` | no |
101-
| poll_source_changes | Periodically check the location of your source content and run the pipeline if changes are detected | string | `true` | no |
130+
| poll_source_changes | Periodically check the location of your source content and run the pipeline if changes are detected | string | `false` | no |
102131
| privileged_mode | If set to true, enables running the Docker daemon inside a Docker container on the CodeBuild instance. Used when building Docker images | string | `false` | no |
103132
| repo_name | GitHub repository name of the application to be built and deployed to ECS. | string | - | yes |
104133
| repo_owner | GitHub Organization or Username. | string | - | yes |
105134
| service_name | ECS Service Name | string | - | yes |
106135
| stage | Stage, e.g. 'prod', 'staging', 'dev', or 'test' | string | `default` | no |
107136
| tags | Additional tags (e.g. `map('BusinessUnit', 'XYZ')` | map | `<map>` | no |
137+
| webhook_authentication | The type of authentication to use. One of IP, GITHUB_HMAC, or UNAUTHENTICATED. | string | `GITHUB_HMAC` | no |
138+
| webhook_enabled | Set to false to prevent the module from creating any webhook resources | string | `true` | no |
139+
| webhook_filter_json_path | The JSON path to filter on. | string | `$.ref` | no |
140+
| webhook_filter_match_equals | The value to match on (e.g. refs/heads/{Branch}) | string | `refs/heads/{Branch}` | no |
141+
| webhook_target_action | The name of the action in a pipeline you want to connect to the webhook. The action must be from the source (first) stage of the pipeline. | string | `Source` | no |
108142

109143
## Outputs
110144

111145
| Name | Description |
112146
|------|-------------|
113147
| badge_url | The URL of the build badge when badge_enabled is enabled |
148+
| webhook_id | The CodePipeline webhook's ARN. |
149+
| webhook_url | The CodePipeline webhook's URL. POST events to this endpoint to trigger the target. |
114150

115151

116152

@@ -136,6 +172,14 @@ Check out these related projects.
136172

137173

138174

175+
176+
## References
177+
178+
For additional context, refer to some of these links.
179+
180+
- [aws_codepipeline_webhook](https://www.terraform.io/docs/providers/aws/r/codepipeline_webhook.html) - Provides a CodePipeline Webhook
181+
182+
139183
## Help
140184

141185
**Got a question?**

README.yaml

+37-2
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,36 @@ related:
5353

5454
# Short description of this project
5555
description: |-
56-
Terraform Module for CI/CD with AWS Code Pipeline and Code Build for ECS.
56+
Terraform Module for CI/CD with AWS Code Pipeline using GitHub webhook triggers and Code Build for ECS.
5757
5858
# How to use this project
5959
usage: |-
60+
61+
### Trigger on GitHub Push
62+
63+
In this example, we'll trigger the pipeline anytime the `master` branch is updated.
64+
```hcl
65+
module "ecs_push_pipeline" {
66+
source = "git::https://github.com/cloudposse/terraform-aws-ecs-codepipeline.git?ref=tags/0.1.2"
67+
name = "app"
68+
namespace = "eg"
69+
stage = "staging"
70+
github_oauth_token = "xxxxxxxxxxxxxx"
71+
repo_owner = "cloudposse"
72+
repo_name = "example"
73+
branch = "master"
74+
service_name = "example"
75+
ecs_cluster_name = "example-ecs-cluster"
76+
privileged_mode = "true"
77+
}
78+
```
79+
80+
### Trigger on GitHub Releases
81+
82+
In this example, we'll trigger anytime a new GitHub release is cut by setting the even type to `release` and using the `json_path` to *exactly* match an `action` of `published`.
83+
6084
```hcl
61-
module "ecs_codepipeline" {
85+
module "ecs_release_pipeline" {
6286
source = "git::https://github.com/cloudposse/terraform-aws-ecs-codepipeline.git?ref=tags/0.1.2"
6387
name = "app"
6488
namespace = "eg"
@@ -70,8 +94,14 @@ usage: |-
7094
service_name = "example"
7195
ecs_cluster_name = "example-ecs-cluster"
7296
privileged_mode = "true"
97+
github_webhook_events = ["release"]
98+
webhook_filter_json_path = "$.action"
99+
webhook_filter_match_equals = "published"
73100
}
74101
```
102+
(Thanks to [Stack Overflow](https://stackoverflow.com/questions/52516087/trigger-aws-codepipeline-by-github-release-webhook#comment91997146_52524711))
103+
104+
75105
76106
# Example usage
77107
examples: |-
@@ -86,6 +116,11 @@ include:
86116
- "docs/targets.md"
87117
- "docs/terraform.md"
88118

119+
references:
120+
- name: "aws_codepipeline_webhook"
121+
description: "Provides a CodePipeline Webhook"
122+
url: "https://www.terraform.io/docs/providers/aws/r/codepipeline_webhook.html"
123+
89124
# Contributors to this project
90125
contributors:
91126
- name: "Erik Osterman"

docs/terraform.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,29 @@
1616
| enabled | Enable `CodePipeline` creation | string | `true` | no |
1717
| environment_variables | A list of maps, that contain both the key 'name' and the key 'value' to be used as additional environment variables for the build. | list | `<list>` | no |
1818
| github_oauth_token | GitHub Oauth Token with permissions to access private repositories | string | - | yes |
19+
| github_webhook_events | A list of events which should trigger the webhook. See a list of [available events](https://developer.github.com/v3/activity/events/types/). | list | `<list>` | no |
1920
| image_repo_name | ECR repository name to store the Docker image built by this module. Used as CodeBuild ENV variable when building Docker images. [For more info](http://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker.html) | string | `UNSET` | no |
2021
| image_tag | Docker image tag in the ECR repository, e.g. 'latest'. Used as CodeBuild ENV variable when building Docker images. [For more info](http://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker.html) | string | `latest` | no |
2122
| name | Solution name, e.g. 'app' or 'jenkins' | string | `app` | no |
2223
| namespace | Namespace, which could be your organization name, e.g. 'cp' or 'cloudposse' | string | `global` | no |
23-
| poll_source_changes | Periodically check the location of your source content and run the pipeline if changes are detected | string | `true` | no |
24+
| poll_source_changes | Periodically check the location of your source content and run the pipeline if changes are detected | string | `false` | no |
2425
| privileged_mode | If set to true, enables running the Docker daemon inside a Docker container on the CodeBuild instance. Used when building Docker images | string | `false` | no |
2526
| repo_name | GitHub repository name of the application to be built and deployed to ECS. | string | - | yes |
2627
| repo_owner | GitHub Organization or Username. | string | - | yes |
2728
| service_name | ECS Service Name | string | - | yes |
2829
| stage | Stage, e.g. 'prod', 'staging', 'dev', or 'test' | string | `default` | no |
2930
| tags | Additional tags (e.g. `map('BusinessUnit', 'XYZ')` | map | `<map>` | no |
31+
| webhook_authentication | The type of authentication to use. One of IP, GITHUB_HMAC, or UNAUTHENTICATED. | string | `GITHUB_HMAC` | no |
32+
| webhook_enabled | Set to false to prevent the module from creating any webhook resources | string | `true` | no |
33+
| webhook_filter_json_path | The JSON path to filter on. | string | `$.ref` | no |
34+
| webhook_filter_match_equals | The value to match on (e.g. refs/heads/{Branch}) | string | `refs/heads/{Branch}` | no |
35+
| webhook_target_action | The name of the action in a pipeline you want to connect to the webhook. The action must be from the source (first) stage of the pipeline. | string | `Source` | no |
3036

3137
## Outputs
3238

3339
| Name | Description |
3440
|------|-------------|
3541
| badge_url | The URL of the build badge when badge_enabled is enabled |
42+
| webhook_id | The CodePipeline webhook's ARN. |
43+
| webhook_url | The CodePipeline webhook's URL. POST events to this endpoint to trigger the target. |
3644

main.tf

+45-2
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ data "aws_iam_policy_document" "codebuild" {
162162
}
163163
}
164164

165+
data "aws_caller_identity" "default" {}
166+
167+
data "aws_region" "default" {}
168+
165169
module "build" {
166170
source = "git::https://github.com/cloudposse/terraform-aws-codebuild.git?ref=tags/0.11.0"
167171
enabled = "${var.enabled}"
@@ -260,6 +264,45 @@ resource "aws_codepipeline" "source_build_deploy" {
260264
}
261265
}
262266

263-
data "aws_caller_identity" "default" {}
267+
resource "random_string" "webhook_secret" {
268+
count = "${var.webhook_enabled == "true" ? 1 : 0}"
269+
length = 32
264270

265-
data "aws_region" "default" {}
271+
# Special characters are not allowed in webhook secret (AWS silently ignores webhook callbacks)
272+
special = false
273+
}
274+
275+
locals {
276+
webhook_secret = "${join("", random_string.webhook_secret.*.result)}"
277+
webhook_url = "${join("", aws_codepipeline_webhook.webhook.*.url)}"
278+
}
279+
280+
resource "aws_codepipeline_webhook" "webhook" {
281+
count = "${var.webhook_enabled == "true" ? 1 : 0}"
282+
name = "${module.codepipeline_label.id}"
283+
authentication = "${var.webhook_authentication}"
284+
target_action = "${var.webhook_target_action}"
285+
target_pipeline = "${aws_codepipeline.source_build_deploy.name}"
286+
287+
authentication_configuration {
288+
secret_token = "${local.webhook_secret}"
289+
}
290+
291+
filter {
292+
json_path = "${var.webhook_filter_json_path}"
293+
match_equals = "${var.webhook_filter_match_equals}"
294+
}
295+
}
296+
297+
module "github_webhooks" {
298+
source = "git::https://github.com/cloudposse/terraform-github-repository-webhooks.git?ref=tags/0.1.1"
299+
enabled = "${var.webhook_enabled}"
300+
github_organization = "${var.repo_owner}"
301+
github_repositories = ["${var.repo_name}"]
302+
github_token = "${var.github_oauth_token}"
303+
webhook_url = "${local.webhook_url}"
304+
webhook_secret = "${local.webhook_secret}"
305+
webhook_content_type = "json"
306+
name = "web"
307+
events = ["${var.github_webhook_events}"]
308+
}

outputs.tf

+11
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,14 @@ output "badge_url" {
22
description = "The URL of the build badge when badge_enabled is enabled"
33
value = "${module.build.badge_url}"
44
}
5+
6+
output "webhook_id" {
7+
description = "The CodePipeline webhook's ARN."
8+
value = "${join("", aws_codepipeline_webhook.webhook.*.id)}"
9+
}
10+
11+
output "webhook_url" {
12+
description = "The CodePipeline webhook's URL. POST events to this endpoint to trigger the target."
13+
value = "${local.webhook_url}"
14+
sensitive = true
15+
}

variables.tf

+31-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ variable "github_oauth_token" {
3232
description = "GitHub Oauth Token with permissions to access private repositories"
3333
}
3434

35+
variable "github_webhook_events" {
36+
description = "A list of events which should trigger the webhook. See a list of [available events](https://developer.github.com/v3/activity/events/types/)."
37+
default = ["push"]
38+
}
39+
3540
variable "repo_owner" {
3641
description = "GitHub Organization or Username."
3742
}
@@ -75,7 +80,7 @@ variable "buildspec" {
7580
# It is recommended you avoid using boolean values and use explicit strings
7681
variable "poll_source_changes" {
7782
type = "string"
78-
default = "true"
83+
default = "false"
7984
description = "Periodically check the location of your source content and run the pipeline if changes are detected"
8085
}
8186

@@ -136,3 +141,28 @@ variable "environment_variables" {
136141

137142
description = "A list of maps, that contain both the key 'name' and the key 'value' to be used as additional environment variables for the build."
138143
}
144+
145+
variable "webhook_enabled" {
146+
description = "Set to false to prevent the module from creating any webhook resources"
147+
default = "true"
148+
}
149+
150+
variable "webhook_target_action" {
151+
description = "The name of the action in a pipeline you want to connect to the webhook. The action must be from the source (first) stage of the pipeline."
152+
default = "Source"
153+
}
154+
155+
variable "webhook_authentication" {
156+
description = "The type of authentication to use. One of IP, GITHUB_HMAC, or UNAUTHENTICATED."
157+
default = "GITHUB_HMAC"
158+
}
159+
160+
variable "webhook_filter_json_path" {
161+
description = "The JSON path to filter on."
162+
default = "$.ref"
163+
}
164+
165+
variable "webhook_filter_match_equals" {
166+
description = "The value to match on (e.g. refs/heads/{Branch})"
167+
default = "refs/heads/{Branch}"
168+
}

0 commit comments

Comments
 (0)