diff --git a/pipelines/multi-branch/template.yml b/pipelines/multi-branch/template.yml new file mode 100644 index 0000000..3ffe2c3 --- /dev/null +++ b/pipelines/multi-branch/template.yml @@ -0,0 +1,81 @@ +resource_types: +- name: terraform + type: registry-image + source: + repository: ljfranklin/terraform-resource + +- name: gcs + type: registry-image + source: + repository: frodenas/gcs-resource + +resources: +- name: branch + type: git + source: + uri: https://github.com/concourse/examples + branch: ((branch)) + +- name: examples + type: git + source: + uri: https://github.com/concourse/examples + +- name: build-artifact + type: gcs + source: + bucket: concourse-examples + json_key: ((gcp_service_account_key)) + regexp: multi-branch/features/((feature))/my-app-(.+)\.tgz + +- name: staging-env + type: terraform + source: + env_name: ((feature)) + backend_type: gcs + backend_config: + bucket: concourse-examples + prefix: multi-branch/terraform + credentials: ((gcp_service_account_key)) + +jobs: +- name: test + plan: + - in_parallel: + - get: branch + trigger: true + - get: examples + - task: unit + file: examples/tasks/go-test.yml + input_mapping: {repo: branch} + params: {MODULE: apps/golang} + +- name: build + plan: + - in_parallel: + - get: branch + passed: [test] + trigger: true + - get: examples + - task: build + file: examples/tasks/go-build.yml + params: + MODULE: apps/golang + BINARY_NAME: my-app + input_mapping: {repo: branch} + - put: build-artifact + params: {file: "binary/my-app-*.tgz"} + +- name: deploy + plan: + - in_parallel: + - get: build-artifact + passed: [build] + trigger: true + - get: examples + - load_var: bundle_url + file: build-artifact/url + - put: staging-env + params: + terraform_source: examples/terraform/staging + vars: {bundle_url: ((.:bundle_url))} diff --git a/pipelines/multi-branch/tracker.yml b/pipelines/multi-branch/tracker.yml new file mode 100644 index 0000000..73b2442 --- /dev/null +++ b/pipelines/multi-branch/tracker.yml @@ -0,0 +1,104 @@ +resource_types: +- name: git-branches + type: registry-image + source: + repository: aoldershaw/git-branches-resource + +- name: terraform + type: registry-image + source: + repository: ljfranklin/terraform-resource + +resources: +- name: feature-branches + type: git-branches + source: + uri: https://github.com/concourse/examples + # The "(?Ppattern)" syntax defines a named capture group. + # aoldershaw/git-branches-resource emits the value of each named capture + # group under the `groups` key. + # + # e.g. feature/some-feature ==> {"groups": {"feature": "some-feature"}} + branch_regex: 'feature/(?P.*)' + +- name: examples + type: git + source: + uri: https://github.com/concourse/examples + +- name: staging-env + type: terraform + source: + backend_type: gcs + backend_config: &terraform_backend_config + bucket: concourse-examples + prefix: multi-branch/terraform + credentials: ((gcp_service_account_key)) + +jobs: +- name: set-feature-pipelines + plan: + - in_parallel: + - get: feature-branches + trigger: true + - get: examples + - load_var: branches + file: feature-branches/branches.json + - across: + - var: branch + values: ((.:branches)) + set_pipeline: dev + file: examples/pipelines/multi-branch/template.yml + instance_vars: {feature: ((.:branch.groups.feature))} + vars: {branch: ((.:branch.name))} + +- name: cleanup-inactive-workspaces + plan: + - in_parallel: + - get: feature-branches + passed: [set-feature-pipelines] + trigger: true + - get: examples + - task: find-inactive-workspaces + config: + platform: linux + image_resource: + type: registry-image + source: {repository: hashicorp/terraform} + inputs: + - name: feature-branches + outputs: + - name: extra-workspaces + params: + TERRAFORM_BACKEND_CONFIG: + gcs: *terraform_backend_config + run: + path: sh + args: + - -c + - | + set -euo pipefail + + apk add -q jq + + active_features="$(jq '[.[].groups.feature]' feature-branches/branches.json)" + + jq -n "{terraform: {backend: $TERRAFORM_BACKEND_CONFIG}}" > backend.tf.json + terraform init + + # List all active workspaces, ignoring the default workspace + active_workspaces="$(terraform workspace list | grep -v '^[*]' | tr -d ' ' | jq --raw-input --slurp 'split("\n") | map(select(. != ""))')" + + jq -n "$active_workspaces - $active_features" > extra-workspaces/workspaces.json + - load_var: extra_workspaces + file: extra-workspaces/workspaces.json + - across: + - var: workspace + values: ((.:extra_workspaces)) + put: staging-env + params: + terraform_source: examples/terraform/staging + env_name: ((.:workspace)) + action: destroy + get_params: + action: destroy diff --git a/tasks/go-build.yml b/tasks/go-build.yml new file mode 100644 index 0000000..31c019a --- /dev/null +++ b/tasks/go-build.yml @@ -0,0 +1,28 @@ +platform: linux + +image_resource: + type: registry-image + source: { repository: golang } + +inputs: +- name: repo + path: . + +outputs: +- name: binary + +params: + MODULE: + BINARY_NAME: + +run: + path: sh + args: + - -ce + - | + root=$(pwd) + cd "$MODULE" + go build -o "/tmp/$BINARY_NAME" + + timestamp=$(date '+%Y%m%d%H%M%S') + tar czf "$root/binary/$BINARY_NAME-$timestamp.tgz" -C /tmp "$BINARY_NAME" diff --git a/tasks/go-test.yml b/tasks/go-test.yml new file mode 100644 index 0000000..2f8b24d --- /dev/null +++ b/tasks/go-test.yml @@ -0,0 +1,20 @@ +platform: linux + +image_resource: + type: registry-image + source: { repository: golang } + +inputs: +- name: repo + path: . + +params: + MODULE: + +run: + path: sh + args: + - -ce + - | + cd "$MODULE" + go test -v ./... diff --git a/terraform/staging/main.tf b/terraform/staging/main.tf new file mode 100644 index 0000000..df8fdaf --- /dev/null +++ b/terraform/staging/main.tf @@ -0,0 +1,14 @@ +variable "bundle_url" { + type = string + default = "" +} + +resource "null_resource" "fake_deployment" { + triggers = { + bundle_url = var.bundle_url + } + + provisioner "local-exec" { + command = "echo \"pretending to deploy from ${var.bundle_url}\"..." + } +}