From 54740ed76046ca8744ba2cefb5b3112995cd737e Mon Sep 17 00:00:00 2001 From: neil-sproston Date: Thu, 22 Jan 2026 12:20:10 +0000 Subject: [PATCH 1/7] [GPCAPIM-166] Enable force new deployment for ECS service --- infrastructure/environments/preview/main.tf | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/infrastructure/environments/preview/main.tf b/infrastructure/environments/preview/main.tf index 1de81361..9cf33cb0 100644 --- a/infrastructure/environments/preview/main.tf +++ b/infrastructure/environments/preview/main.tf @@ -218,6 +218,7 @@ resource "aws_ecs_service" "branch" { desired_count = var.desired_count launch_type = "FARGATE" enable_execute_command = true + force_new_deployment = true network_configuration { subnets = local.private_subnet_ids @@ -230,10 +231,6 @@ resource "aws_ecs_service" "branch" { container_port = var.container_port } - lifecycle { - ignore_changes = [task_definition] - } - depends_on = [aws_lb_listener_rule.branch] } From 0e6e37e31e9e399298cac1f6dfb7be96890b04b2 Mon Sep 17 00:00:00 2001 From: neil-sproston Date: Thu, 22 Jan 2026 13:00:48 +0000 Subject: [PATCH 2/7] [GPCAPIM-166] Remove unneeded comments. --- .github/workflows/preview-env.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/preview-env.yml b/.github/workflows/preview-env.yml index acb73e37..ed790653 100644 --- a/.github/workflows/preview-env.yml +++ b/.github/workflows/preview-env.yml @@ -79,7 +79,6 @@ jobs: echo "tf_state_key=$TF_STATE_KEY" >> $GITHUB_OUTPUT # ALB listener rule priority - derive from PR number (must be unique per listener) - # You can tweak this formula if you like. if [ -n "${{ github.event.number }}" ]; then PRIORITY=$(( 1000 + ${{ github.event.number }} )) else From 157b3099209c34d0c6e29b6626518dbc1d92fc37 Mon Sep 17 00:00:00 2001 From: neil-sproston Date: Thu, 22 Jan 2026 13:16:44 +0000 Subject: [PATCH 3/7] [GPCAPIM-166] Make terraform always act on ecs service --- .github/workflows/preview-env.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/preview-env.yml b/.github/workflows/preview-env.yml index ed790653..ad7ab23e 100644 --- a/.github/workflows/preview-env.yml +++ b/.github/workflows/preview-env.yml @@ -134,7 +134,9 @@ jobs: TF_VAR_image_tag: ${{ steps.meta.outputs.branch_name }} TF_VAR_alb_rule_priority: ${{ steps.meta.outputs.alb_rule_priority }} run: | - terraform apply -auto-approve + terraform apply \ + -replace="aws_ecs_service.branch" \ + -auto-approve - name: Capture preview TF outputs if: github.event.action != 'closed' From 7bf95d48de4b835b570990ee8cf43018533de2b2 Mon Sep 17 00:00:00 2001 From: neil-sproston Date: Thu, 22 Jan 2026 14:38:12 +0000 Subject: [PATCH 4/7] [GPCAPIM-166] Force redeployment on PR updates and await completion --- .github/workflows/preview-env.yml | 38 ++++++++++++++++--- .../environments/preview/outputs.tf | 15 +++++--- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/.github/workflows/preview-env.yml b/.github/workflows/preview-env.yml index ad7ab23e..24e3ebda 100644 --- a/.github/workflows/preview-env.yml +++ b/.github/workflows/preview-env.yml @@ -9,7 +9,6 @@ env: AWS_ACCOUNT_ID: "900119715266" ECR_REPOSITORY_NAME: "whoami" TF_STATE_BUCKET: "cds-cdg-dev-tfstate-900119715266" - CORE_STATE_KEY: "dev/terraform.tfstate" PREVIEW_STATE_PREFIX: "dev/preview/" python_version: "3.14" @@ -135,7 +134,6 @@ jobs: TF_VAR_alb_rule_priority: ${{ steps.meta.outputs.alb_rule_priority }} run: | terraform apply \ - -replace="aws_ecs_service.branch" \ -auto-approve - name: Capture preview TF outputs @@ -144,10 +142,29 @@ jobs: working-directory: infrastructure/environments/preview run: | terraform output -json > tf-output.json + URL=$(jq -r '.url.value' tf-output.json) - TG=$(jq -r '.target_group_arn.value' tf-output.json) echo "preview_url=$URL" >> $GITHUB_OUTPUT - echo "target_group=$TG" >> $GITHUB_OUTPUT + + TG=$(jq -r '.target_group_arn.value' tf-output.json) + echo "target_group=$TG" >> $GITHUB_OUTPUT + + ECS_SERVICE=$(jq -r '.ecs_service_name.value' tf-output.json) + echo "ecs_service=$ECS_SERVICE" >> $GITHUB_OUTPUT + + ECS_CLUSTER=$(jq -r '.ecs_cluster_name.value' tf-output.json) + echo "ecs_cluster=$ECS_CLUSTER" >> $GITHUB_OUTPUT + + # ---------- Ensure re-deployment (PR updated) ---------- + - name: Force ECS service redeployment + if: github.event.action == 'synchronize' + id: await-redeployment + run: | + aws ecs update-service \ + --cluster ${{ steps.tf-output.outputs.ecs_cluster }} \ + --service ${{ steps.tf-output.outputs.ecs_service }} \ + --force-new-deployment \ + --region ${{ env.AWS_REGION }} # ---------- DESTROY (PR closed) ---------- - name: Terraform init (destroy) @@ -169,6 +186,15 @@ jobs: run: | terraform destroy -auto-approve + # ---------- Wait on AWS taks and notify ---------- + - name: Await deployment completion + if: github.event.action != 'closed' + run: | + aws ecs wait services-stable \ + --cluster ${{ steps.tf-output.outputs.ecs_cluster }} \ + --services ${{ steps.tf-output.outputs.ecs_service }} \ + --region ${{ env.AWS_REGION }} + - name: Comment function name on PR if: github.event_name == 'pull_request' && github.event.action != 'closed' uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd @@ -176,9 +202,11 @@ jobs: script: | const alb = '${{ steps.tf-output.outputs.target_group }}'; const url = '${{ steps.tf-output.outputs.preview_url }}'; + const cluster = '${{ steps.tf-output.outputs.ecs_cluster }}'; + const service = '${{ steps.tf-output.outputs.ecs_service }}'; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: `ALB Target: \`${alb}\`\nPreview URL: ${url}` + body: `Deployment Complete\nALB Target: \`${alb}\`\nPreview URL: \`${url}\`\nECS Cluster: \`${cluster}\`\nECS Service: \`${service}\``, }); diff --git a/infrastructure/environments/preview/outputs.tf b/infrastructure/environments/preview/outputs.tf index 7f5bf93e..4264dd5d 100644 --- a/infrastructure/environments/preview/outputs.tf +++ b/infrastructure/environments/preview/outputs.tf @@ -3,12 +3,17 @@ output "url" { value = "https://${local.effective_host_name}" } -# output "service_arn" { -# description = "ARN of the ECS service for this preview environment" -# value = aws_ecs_service.branch.arn -# } - output "target_group_arn" { description = "ARN of the ALB target group for this preview environment" value = aws_lb_target_group.branch.arn } + +output "ecs_service_name" { + description = "Name of the ECS service for this preview environment" + value = aws_ecs_service.branch.name +} + +output "ecs_cluster_name" { + description = "Name of the ECS cluster for this preview environment" + value = local.ecs_cluster_name +} From 6623854b319ca939e6f417b57acedf2563b66d4d Mon Sep 17 00:00:00 2001 From: neil-sproston Date: Thu, 22 Jan 2026 15:24:19 +0000 Subject: [PATCH 5/7] [GPCAPIM-166] Enhance notification layout --- .github/workflows/preview-env.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/preview-env.yml b/.github/workflows/preview-env.yml index 24e3ebda..3f7b5783 100644 --- a/.github/workflows/preview-env.yml +++ b/.github/workflows/preview-env.yml @@ -147,7 +147,7 @@ jobs: echo "preview_url=$URL" >> $GITHUB_OUTPUT TG=$(jq -r '.target_group_arn.value' tf-output.json) - echo "target_group=$TG" >> $GITHUB_OUTPUT + echo "target_group=$TG" >> $GITHUB_OUTPUT ECS_SERVICE=$(jq -r '.ecs_service_name.value' tf-output.json) echo "ecs_service=$ECS_SERVICE" >> $GITHUB_OUTPUT @@ -155,7 +155,7 @@ jobs: ECS_CLUSTER=$(jq -r '.ecs_cluster_name.value' tf-output.json) echo "ecs_cluster=$ECS_CLUSTER" >> $GITHUB_OUTPUT - # ---------- Ensure re-deployment (PR updated) ---------- + # ---------- Ensure re-deployment (PR updated) ---------- - name: Force ECS service redeployment if: github.event.action == 'synchronize' id: await-redeployment @@ -204,9 +204,17 @@ jobs: const url = '${{ steps.tf-output.outputs.preview_url }}'; const cluster = '${{ steps.tf-output.outputs.ecs_cluster }}'; const service = '${{ steps.tf-output.outputs.ecs_service }}'; + const lines = [ + '**Deployment Complete**', + `- Preview URL: [${url}](${url})`, + `- ECS Cluster: \`${cluster}\``, + `- ECS Service: \`${service}\``, + `- ALB Target: \`${alb}\``, + ]; + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: `Deployment Complete\nALB Target: \`${alb}\`\nPreview URL: \`${url}\`\nECS Cluster: \`${cluster}\`\nECS Service: \`${service}\``, + body: lines.join('\n'), }); From 24fab25f348a9bdc3e82ca036f9aa43deabea4e4 Mon Sep 17 00:00:00 2001 From: neil-sproston Date: Thu, 22 Jan 2026 15:32:00 +0000 Subject: [PATCH 6/7] [GPCAPIM-166] Tidy up terraform file layout. --- infrastructure/environments/preview/main.tf | 28 ++----------------- .../environments/preview/terraform.tf | 21 ++++++++++++++ 2 files changed, 23 insertions(+), 26 deletions(-) create mode 100644 infrastructure/environments/preview/terraform.tf diff --git a/infrastructure/environments/preview/main.tf b/infrastructure/environments/preview/main.tf index 9cf33cb0..f28bba5a 100644 --- a/infrastructure/environments/preview/main.tf +++ b/infrastructure/environments/preview/main.tf @@ -1,31 +1,9 @@ -terraform { - required_version = ">= 1.4.0" - - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 5.0" - } - } - - # Typically you'll set a different key per branch in CI (e.g. dev/preview/.tfstate) - backend "s3" { - bucket = "cds-cdg-dev-tfstate-900119715266" - key = "dev/preview/branch_name.tfstate" - region = "eu-west-2" - } -} - -provider "aws" { - region = "eu-west-2" -} - -data "aws_region" "current" {} - ############################ # 1. Import core outputs ############################ +data "aws_region" "current" {} + data "terraform_remote_state" "core" { backend = "s3" config = { @@ -233,5 +211,3 @@ resource "aws_ecs_service" "branch" { depends_on = [aws_lb_listener_rule.branch] } - - diff --git a/infrastructure/environments/preview/terraform.tf b/infrastructure/environments/preview/terraform.tf new file mode 100644 index 00000000..d36fe2ae --- /dev/null +++ b/infrastructure/environments/preview/terraform.tf @@ -0,0 +1,21 @@ +terraform { + required_version = ">= 1.4.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } + + # Typically you'll set a different key per branch in CI (e.g. dev/preview/.tfstate) + backend "s3" { + bucket = "cds-cdg-dev-tfstate-900119715266" + key = "dev/preview/branch_name.tfstate" + region = "eu-west-2" + } +} + +provider "aws" { + region = "eu-west-2" +} From 0b18a75bb37b88a0f584699b76ed2e5e60a70ce2 Mon Sep 17 00:00:00 2001 From: neil-sproston Date: Thu, 22 Jan 2026 15:51:01 +0000 Subject: [PATCH 7/7] Enhance comment management for deployment notifications in preview environment --- .github/workflows/preview-env.yml | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/.github/workflows/preview-env.yml b/.github/workflows/preview-env.yml index 3f7b5783..b313402f 100644 --- a/.github/workflows/preview-env.yml +++ b/.github/workflows/preview-env.yml @@ -204,6 +204,30 @@ jobs: const url = '${{ steps.tf-output.outputs.preview_url }}'; const cluster = '${{ steps.tf-output.outputs.ecs_cluster }}'; const service = '${{ steps.tf-output.outputs.ecs_service }}'; + const owner = context.repo.owner; + const repo = context.repo.repo; + const issueNumber = context.issue.number; + + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number: issueNumber, + per_page: 100, + }); + + for (const comment of comments) { + const isBot = comment.user?.login === 'github-actions[bot]'; + const isPreviewUpdate = comment.body?.includes('Deployment Complete'); + + if (isBot && isPreviewUpdate) { + await github.rest.issues.deleteComment({ + owner, + repo, + comment_id: comment.id, + }); + } + } + const lines = [ '**Deployment Complete**', `- Preview URL: [${url}](${url})`, @@ -213,8 +237,8 @@ jobs: ]; await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, + owner, + repo, + issue_number: issueNumber, body: lines.join('\n'), });