diff --git a/.github/workflows/aws_deploy.yml b/.github/workflows/aws_deploy.yml index 0e82e576b..9bd78ea3e 100644 --- a/.github/workflows/aws_deploy.yml +++ b/.github/workflows/aws_deploy.yml @@ -22,6 +22,10 @@ on: release_tag: required: false type: string + ref: + required: false + type: string + default: "" concurrency: group: deploy-${{ inputs.environment }}${{ inputs.concurrency_tag }} @@ -42,6 +46,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.sha }} - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 @@ -53,16 +59,19 @@ jobs: id: ecr-login uses: aws-actions/amazon-ecr-login@v2 + - name: Resolve commit SHA + run: echo "commit_sha=${{ inputs.ref || github.sha }}" >> $GITHUB_ENV + - name: Check if image with tag already exists run: | - echo "image-exists=$(if aws ecr describe-images --repository-name=$repository --image-ids imageTag=${{ github.sha }} > /dev/null 2>&1; then echo true; else echo false; fi)" >> $GITHUB_ENV + echo "image-exists=$(if aws ecr describe-images --repository-name=$repository --image-ids imageTag=${{ env.commit_sha }} > /dev/null 2>&1; then echo true; else echo false; fi)" >> $GITHUB_ENV - name: Build, tag, and push docker image to ECR if there is no image, failing for releases id: build-image if: ${{ env.image-exists == 'false' }} env: registry: ${{ steps.ecr-login.outputs.registry }} - commit_tag: ${{ github.sha }} + commit_tag: ${{ env.commit_sha }} run: | if [[ ${{ inputs.environment }} == 'production' ]]; then echo "Error: Deployment to production environment is not allowed as there is no docker image (i.e. the AWS deploy on staging was unsuccessful for this commit)." @@ -100,7 +109,7 @@ jobs: id: update-image-tags env: registry: ${{ steps.ecr-login.outputs.registry }} - commit_tag: ${{ github.sha }} + commit_tag: ${{ inputs.ref || github.sha }} readable_tag: ${{ inputs.environment }}-${{ env.additional-tag }} run: | manifest=$(aws ecr batch-get-image --repository-name $repository --image-ids imageTag=$commit_tag --output text --query images[].imageManifest) diff --git a/.github/workflows/manual_review_code_pipeline.yml b/.github/workflows/manual_review_code_pipeline.yml index 2ea0719ca..561c06b76 100644 --- a/.github/workflows/manual_review_code_pipeline.yml +++ b/.github/workflows/manual_review_code_pipeline.yml @@ -1,15 +1,15 @@ -name: Manual review app code pipeline +name: Manual review app build and deploy concurrency: - group: review-${{ inputs.review_app_key }} + group: deploy-review${{ inputs.pr_number }} on: workflow_dispatch: inputs: - review_app_key: + pr_number: required: true type: string - description: "The review app ID to deploy code for." + description: "The PR number of the review app to deploy code for. Note: this is NOT the ticket number" defaults: run: @@ -22,8 +22,8 @@ jobs: with: aws_account_id: 837698168072 aws_role_prefix: core-dev - aws_task_prefix: core-review-${{ inputs.review_app_key }} - concurrency_tag: ${{ inputs.review_app_key }} + aws_task_prefix: core-review-${{ inputs.pr_number }} + concurrency_tag: ${{ inputs.pr_number }} environment: review permissions: id-token: write diff --git a/.github/workflows/review_pipeline.yml b/.github/workflows/review_pipeline.yml index 307aa0381..cfc79f9f3 100644 --- a/.github/workflows/review_pipeline.yml +++ b/.github/workflows/review_pipeline.yml @@ -9,30 +9,91 @@ on: required: true type: string description: "The number of the PR for which to deploy a review app. Note: this is NOT the ticket number" + pull_request: + types: [synchronize] + +concurrency: + group: deploy-review${{ github.event.pull_request.number || inputs.pr_number || github.event.issue.number }} permissions: {} jobs: get_pr_details: name: Get PR details - if: github.event_name == 'workflow_dispatch' || (github.event.issue.pull_request && startsWith(github.event.comment.body, '/deploy-review')) + if: github.event_name == 'workflow_dispatch' || (github.event.issue.pull_request && startsWith(github.event.comment.body, '/deploy-review')) || github.event_name == 'pull_request' runs-on: ubuntu-latest outputs: pr_number: ${{ steps.get_pr_details.outputs.pr_number }} + pr_head_sha: ${{ steps.get_pr_details.outputs.pr_head_sha }} steps: - - name: Get PR number + - name: Get PR number and HEAD SHA id: get_pr_details uses: actions/github-script@v7 with: script: | + let prNumber; if (context.eventName === 'workflow_dispatch') { - core.setOutput('pr_number', '${{ inputs.pr_number }}'); + prNumber = '${{ inputs.pr_number }}'; + } else if (context.eventName === 'pull_request') { + prNumber = context.payload.pull_request.number.toString(); } else { - core.setOutput('pr_number', context.issue.number.toString()); + prNumber = context.issue.number.toString(); } + core.setOutput('pr_number', prNumber); + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: parseInt(prNumber), + }); + core.setOutput('pr_head_sha', pr.head.sha); + + check_review_app_exists: + name: Check if review app exists + if: github.event_name == 'pull_request' + needs: [get_pr_details] + runs-on: ubuntu-latest + permissions: + id-token: write + outputs: + exists: ${{ steps.check.outputs.exists }} + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: eu-west-2 + role-to-assume: arn:aws:iam::837698168072:role/core-dev-deployment + + - name: Check if ECS service exists + id: check + run: | + if aws ecs describe-services --cluster core-review-${{ needs.get_pr_details.outputs.pr_number }}-app --services core-review-${{ needs.get_pr_details.outputs.pr_number }}-app --query "services[?status=='ACTIVE']" | grep -q 'serviceName'; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + + deployment_started_comment: + name: Comment deployment started + if: github.event_name != 'pull_request' + needs: [get_pr_details] + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Comment on PR + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ needs.get_pr_details.outputs.pr_number }}, + body: 'Starting review app deployment...', + }); infra: name: Deploy review app infrastructure + if: github.event_name != 'pull_request' needs: [get_pr_details] uses: communitiesuk/submit-social-housing-lettings-and-sales-data-infrastructure/.github/workflows/create_review_app_infra.yml@main with: @@ -43,6 +104,7 @@ jobs: code: name: Deploy review app code + if: github.event_name != 'pull_request' needs: [get_pr_details, infra] uses: ./.github/workflows/aws_deploy.yml with: @@ -51,11 +113,28 @@ jobs: aws_task_prefix: core-review-${{ needs.get_pr_details.outputs.pr_number }} concurrency_tag: ${{ needs.get_pr_details.outputs.pr_number }} environment: review + ref: ${{ needs.get_pr_details.outputs.pr_head_sha }} + permissions: + id-token: write + + auto_update_code: + name: Auto-update review app code + if: github.event_name == 'pull_request' && needs.check_review_app_exists.outputs.exists == 'true' + needs: [get_pr_details, check_review_app_exists] + uses: ./.github/workflows/aws_deploy.yml + with: + aws_account_id: 837698168072 + aws_role_prefix: core-dev + aws_task_prefix: core-review-${{ needs.get_pr_details.outputs.pr_number }} + concurrency_tag: ${{ needs.get_pr_details.outputs.pr_number }} + environment: review + ref: ${{ needs.get_pr_details.outputs.pr_head_sha }} permissions: id-token: write comment: name: Add link to PR + if: github.event_name != 'pull_request' needs: [get_pr_details, code] runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/review_teardown_pipeline.yml b/.github/workflows/review_teardown_pipeline.yml index 8925b3340..dad9a0e8c 100644 --- a/.github/workflows/review_teardown_pipeline.yml +++ b/.github/workflows/review_teardown_pipeline.yml @@ -1,27 +1,83 @@ name: Review app teardown pipeline concurrency: - group: review-${{ github.event.pull_request.number }} + group: deploy-review${{ github.event.pull_request.number || inputs.pr_number }} on: pull_request: types: - closed workflow_dispatch: + inputs: + pr_number: + required: true + type: string + description: "The PR number of the review app to tear down. Note: this is NOT the ticket number" env: app_repo_role: arn:aws:iam::815624722760:role/core-application-repo aws_account_id: 837698168072 aws_region: eu-west-2 aws_role_prefix: core-dev - aws_task_prefix: core-review-${{ github.event.pull_request.number }} jobs: + get_pr_number: + name: Get PR number + runs-on: ubuntu-latest + outputs: + pr_number: ${{ steps.get.outputs.pr_number }} + steps: + - name: Get PR number + id: get + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "pr_number=${{ inputs.pr_number }}" >> $GITHUB_OUTPUT + else + echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + fi + + check_review_app_exists: + name: Check if review app exists + needs: [get_pr_number] + runs-on: ubuntu-latest + permissions: + id-token: write + outputs: + exists: ${{ steps.check.outputs.exists }} + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ env.aws_region }} + role-to-assume: ${{ env.app_repo_role }} + + - name: Configure AWS credentials for review environment + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ env.aws_region }} + role-to-assume: arn:aws:iam::${{ env.aws_account_id }}:role/${{ env.aws_role_prefix }}-deployment + role-chaining: true + + - name: Check if ECS service exists + id: check + env: + aws_task_prefix: core-review-${{ needs.get_pr_number.outputs.pr_number }} + run: | + if aws ecs describe-services --cluster ${{ env.aws_task_prefix }}-app --services ${{ env.aws_task_prefix }}-app --query "services[?status=='ACTIVE']" | grep -q 'serviceName'; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + database: name: Drop database + if: needs.check_review_app_exists.outputs.exists == 'true' + needs: [get_pr_number, check_review_app_exists] runs-on: ubuntu-latest permissions: id-token: write + env: + aws_task_prefix: core-review-${{ needs.get_pr_number.outputs.pr_number }} steps: - name: Configure AWS credentials @@ -55,10 +111,11 @@ jobs: infra: name: Teardown review app - needs: [database] + if: needs.check_review_app_exists.outputs.exists == 'true' + needs: [get_pr_number, check_review_app_exists, database] uses: communitiesuk/submit-social-housing-lettings-and-sales-data-infrastructure/.github/workflows/destroy_review_app_infra.yml@main with: - key: ${{ github.event.pull_request.number }} + key: ${{ needs.get_pr_number.outputs.pr_number }} app_repo_role: arn:aws:iam::815624722760:role/core-application-repo permissions: id-token: write