diff --git a/.github/scripts/dispatch_internal_repo_workflow.sh b/.github/scripts/dispatch_internal_repo_workflow.sh new file mode 100755 index 00000000..72717d28 --- /dev/null +++ b/.github/scripts/dispatch_internal_repo_workflow.sh @@ -0,0 +1,252 @@ +#!/bin/bash + +# Triggers a remote GitHub workflow in nhs-notify-internal and waits for completion. + +# Usage: +# ./dispatch_internal_repo_workflow.sh \ +# --infraRepoName \ +# --releaseVersion \ +# --targetWorkflow \ +# --targetEnvironment \ +# --targetComponent \ +# --targetAccountGroup \ +# --terraformAction \ +# --internalRef \ +# --overrides \ +# --overrideProjectName \ +# --overrideRoleName + +# +# All arguments are required except terraformAction, and internalRef. +# Example: +# ./dispatch_internal_repo_workflow.sh \ +# --infraRepoName "nhs-notify-dns" \ +# --releaseVersion "v1.2.3" \ +# --targetWorkflow "deploy.yaml" \ +# --targetEnvironment "prod" \ +# --targetComponent "web" \ +# --targetAccountGroup "core" \ +# --terraformAction "apply" \ +# --internalRef "main" \ +# --overrides "tf_var=someString" \ +# --overrideProjectName nhs \ +# --overrideRoleName nhs-service-iam-role + +set -e + +while [[ $# -gt 0 ]]; do + case $1 in + --infraRepoName) # Name of the infrastructure repo in NHSDigital org (required) + infraRepoName="$2" + shift 2 + ;; + --releaseVersion) # Release version, commit, or tag to deploy (required) + releaseVersion="$2" + shift 2 + ;; + --targetWorkflow) # Name of the workflow file to call in nhs-notify-internal (required) + targetWorkflow="$2" + shift 2 + ;; + --targetEnvironment) # Terraform environment to deploy (required) + targetEnvironment="$2" + shift 2 + ;; + --targetComponent) # Terraform component to deploy (required) + targetComponent="$2" + shift 2 + ;; + --targetAccountGroup) # Terraform account group to deploy (required) + targetAccountGroup="$2" + shift 2 + ;; + --terraformAction) # Terraform action to run (optional) + terraformAction="$2" + shift 2 + ;; + --internalRef) # Internal repo reference branch or tag (optional, default: "main") + internalRef="$2" + shift 2 + ;; + --overrides) # Terraform overrides for passing in extra variables (optional) + overrides="$2" + shift 2 + ;; + --overrideProjectName) # Override the project name (optional) + overrideProjectName="$2" + shift 2 + ;; + --overrideRoleName) # Override the role name (optional) + overrideRoleName="$2" + shift 2 + ;; + *) + echo "[ERROR] Unknown argument: $1" + exit 1 + ;; + esac +done + +# Set default values if not provided +if [[ -z "$PR_TRIGGER_PAT" ]]; then + echo "[ERROR] PR_TRIGGER_PAT environment variable is not set or is empty." + exit 1 +fi + +if [[ -z "$overrides" ]]; then + overrides="" +fi + +if [[ -z "$internalRef" ]]; then + internalRef="main" +fi + +echo "==================== Workflow Dispatch Parameters ====================" +echo " infraRepoName: $infraRepoName" +echo " releaseVersion: $releaseVersion" +echo " targetWorkflow: $targetWorkflow" +echo " targetEnvironment: $targetEnvironment" +echo " targetComponent: $targetComponent" +echo " targetAccountGroup: $targetAccountGroup" +echo " terraformAction: $terraformAction" +echo " internalRef: $internalRef" +echo " overrides: $overrides" +echo " overrideProjectName: $overrideProjectName" +echo " overrideRoleName: $overrideRoleName" +echo " targetProject: $targetProject" + +DISPATCH_EVENT=$(jq -ncM \ + --arg infraRepoName "$infraRepoName" \ + --arg releaseVersion "$releaseVersion" \ + --arg targetEnvironment "$targetEnvironment" \ + --arg targetAccountGroup "$targetAccountGroup" \ + --arg targetComponent "$targetComponent" \ + --arg terraformAction "$terraformAction" \ + --arg targetWorkflow "$targetWorkflow" \ + --arg overrides "$overrides" \ + --arg overrideProjectName "$overrideProjectName" \ + --arg overrideRoleName "$overrideRoleName" \ + --arg targetProject "$targetProject" \ + '{ + "ref": "'"$internalRef"'", + "inputs": ( + (if $infraRepoName != "" then { "infraRepoName": $infraRepoName } else {} end) + + (if $terraformAction != "" then { "terraformAction": $terraformAction } else {} end) + + (if $overrideProjectName != "" then { "overrideProjectName": $overrideProjectName } else {} end) + + (if $overrideRoleName != "" then { "overrideRoleName": $overrideRoleName } else {} end) + + (if $targetProject != "" then { "targetProject": $targetProject } else {} end) + + { + "releaseVersion": $releaseVersion, + "targetEnvironment": $targetEnvironment, + "targetAccountGroup": $targetAccountGroup, + "targetComponent": $targetComponent, + "overrides": $overrides, + } + ) + }') + +echo "[INFO] Triggering workflow '$targetWorkflow' in nhs-notify-internal..." + +trigger_response=$(curl -s -L \ + --fail \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${PR_TRIGGER_PAT}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/NHSDigital/nhs-notify-internal/actions/workflows/$targetWorkflow/dispatches" \ + -d "$DISPATCH_EVENT" 2>&1) + +if [[ $? -ne 0 ]]; then + echo "[ERROR] Failed to trigger workflow. Response: $trigger_response" + exit 1 +fi + +echo "[INFO] Workflow trigger request sent successfully, waiting for completion..." + +sleep 10 # Wait a few seconds before checking for the presence of the api to account for GitHub updating + +# Poll GitHub API to check the workflow status +workflow_run_url="" + +for _ in {1..18}; do + + response=$(curl -s -L \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${PR_TRIGGER_PAT}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/NHSDigital/nhs-notify-internal/actions/runs?event=workflow_dispatch") + + if ! echo "$response" | jq empty 2>/dev/null; then + echo "[ERROR] Invalid JSON response from GitHub API during workflow polling:" + echo "$response" + exit 1 + fi + + workflow_run_url=$(echo "$response" | jq -r \ + --arg targetWorkflow "$targetWorkflow" \ + --arg targetEnvironment "$targetEnvironment" \ + --arg targetAccountGroup "$targetAccountGroup" \ + --arg targetComponent "$targetComponent" \ + --arg terraformAction "$terraformAction" \ + '.workflow_runs[] + | select(.path == ".github/workflows/" + $targetWorkflow) + | select(.name + | contains($targetEnvironment) + and contains($targetAccountGroup) + and contains($targetComponent) + and contains($terraformAction) + ) + | .url') + + if [[ -n "$workflow_run_url" && "$workflow_run_url" != null ]]; then + # Workflow_run_url is a list of all workflows which were run for this combination of inputs, but are the API uri + workflow_run_url=$(echo "$workflow_run_url" | head -n 1) + + # Take the first and strip it back to being an accessible url + # Example https://api.github.com/repos/MyOrg/my-repo/actions/runs/12346789 becomes + # becomes https://github.com/MyOrg/my-repo/actions/runs/12346789 + workflow_run_ui_url=${workflow_run_url/api./} # Strips the api. prefix + workflow_run_ui_url=${workflow_run_ui_url/\/repos/} # Strips the repos/ uri + echo "[INFO] Found workflow run url: $workflow_run_ui_url" + break + fi + + echo "[$(date '+%Y-%m-%d %H:%M:%S')] Waiting for workflow to start..." + sleep 10 +done + +if [[ -z "$workflow_run_url" || "$workflow_run_url" == null ]]; then + echo "[ERROR] Failed to get the workflow run url. Exiting." + exit 1 +fi + +# Wait for workflow completion +while true; do + sleep 10 + response=$(curl -s -L \ + -H "Authorization: Bearer ${PR_TRIGGER_PAT}" \ + -H "Accept: application/vnd.github+json" \ + "$workflow_run_url") + + status=$(echo "$response" | jq -r '.status') + echo "[$(date '+%Y-%m-%d %H:%M:%S')] Workflow status: $status" + + if [ "$status" == "completed" ]; then + conclusion=$(echo "$response" | jq -r '.conclusion') + echo "[$(date '+%Y-%m-%d %H:%M:%S')] Workflow conclusion: $conclusion" + + if [ -z "$conclusion" ] || [ "$conclusion" == "null" ]; then + echo "[WARN] Workflow marked completed but conclusion not yet available, retrying..." + sleep 5 + continue + fi + + if [ "$conclusion" == "success" ]; then + echo "[SUCCESS] Workflow completed successfully!" + exit 0 + else + echo "[FAIL] Workflow failed with conclusion: $conclusion" + exit 1 + fi + fi +done diff --git a/.github/workflows/pr_closed.disabled b/.github/workflows/pr_closed.disabled index c5ef9c1f..5230b024 100644 --- a/.github/workflows/pr_closed.disabled +++ b/.github/workflows/pr_closed.disabled @@ -36,6 +36,7 @@ jobs: deploy-main: needs: check-merge-or-workflow-dispatch name: Deploy changes to main in dev AWS account + runs-on: ubuntu-latest if: needs.check-merge-or-workflow-dispatch.outputs.deploy == 'true' permissions: @@ -47,12 +48,18 @@ jobs: matrix: component: [acct, app] - uses: ./.github/workflows/reusable_internal_repo_build.yaml - secrets: inherit - with: - releaseVersion: main - targetWorkflow: "dispatch-deploy-static-notify-bounded-context-env.yaml" ## Replace with correct targetWorkflow - targetEnvironment: "main" - targetAccountGroup: "nhs-notify-bounded-context-dev" ## Replace with correct targetAccountGroup - targetComponent: ${{ matrix.component }} - terraformAction: "apply" + steps: + - name: Checkout repository + uses: actions/checkout@v5.0.0 + + - name: Updating Main Environment + env: + PR_TRIGGER_PAT: ${{ secrets.PR_TRIGGER_PAT }} + run: | + bash .github/scripts/dispatch_internal_repo_workflow.sh \ + --releaseVersion "main" \ + --targetWorkflow "dispatch-deploy-static-notify-bounded-context-env.yaml" ## Replace with correct targetWorkflow \ + --targetEnvironment "main" \ + --targetAccountGroup "nhs-notify-bounded-context-dev" ## Replace with correct targetAccountGroup \ + --targetComponent "${{ matrix.component }}" \ + --terraformAction "apply" diff --git a/.github/workflows/release_created.disabled b/.github/workflows/release_created.disabled index d8c3070e..a1e2896a 100644 --- a/.github/workflows/release_created.disabled +++ b/.github/workflows/release_created.disabled @@ -13,6 +13,7 @@ concurrency: jobs: deploy-main: name: Deploy changes to main in nonprod AWS Account + runs-on: ubuntu-latest permissions: id-token: write @@ -23,12 +24,18 @@ jobs: matrix: component: [component1, component2] ## Replace with correct components - uses: ./.github/workflows/reusable_internal_repo_build.yaml - secrets: inherit - with: - releaseVersion: ${{ github.event.release.tag_name }} - targetWorkflow: "dispatch-deploy-static-notify-bounded-context-env.yaml" ## Replace with correct targetWorkflow - targetEnvironment: "main" - targetAccountGroup: "nhs-notify-bounded-context-nonprod" ## Replace with correct targetAccountGroup - targetComponent: ${{ matrix.component }} - terraformAction: "apply" + steps: + - name: Checkout repository + uses: actions/checkout@v5.0.0 + + - name: Updating Main Environment + env: + PR_TRIGGER_PAT: ${{ secrets.PR_TRIGGER_PAT }} + run: | + bash .github/scripts/dispatch_internal_repo_workflow.sh \ + --releaseVersion "${{ github.event.release.tag_name }}" \ + --targetWorkflow "dispatch-deploy-static-notify-bounded-context-env.yaml" ## Replace with correct targetWorkflow \ + --targetEnvironment "main" \ + --targetAccountGroup "nhs-notify-bounded-context-nonprod" ## Replace with correct targetAccountGroup \ + --targetComponent "${{ matrix.component }}" \ + --terraformAction "apply" diff --git a/.github/workflows/reusable_internal_repo_build.disabled b/.github/workflows/reusable_internal_repo_build.disabled deleted file mode 100644 index eb58164e..00000000 --- a/.github/workflows/reusable_internal_repo_build.disabled +++ /dev/null @@ -1,144 +0,0 @@ -## This workflow is DISABLED. -## To enable, rename from .disabled to .yaml and replace any references as per the comments. -name: Call Notify Internal Infrastructure Deployment -## Sub workflow which plans and deploys Notify components as part of the workflow. -## Review Gates may be required to proceed on triggered builds. - -on: - workflow_call: - inputs: - releaseVersion: - type: string - description: The Github release version, commit, or tag. - default: main - targetWorkflow: - type: string - description: The name of the github workflow to call. - default: main - targetEnvironment: - type: string - description: The Terraform environment to deploy - default: main - targetComponent: - type: string - description: The Terraform component to deploy - required: true - targetAccountGroup: - type: string - description: The Terraform group to deploy - required: true - terraformAction: - type: string - description: The Terraform component to deploy - default: plan - -concurrency: - group: ${{ inputs.targetEnvironment }}-${{ inputs.targetAccountGroup }}-${{ inputs.targetComponent }}-${{ inputs.terraformAction }} - -jobs: - trigger: - runs-on: ubuntu-latest - - permissions: - id-token: write - contents: read - - steps: - - uses: actions/checkout@v4 - - - name: Trigger nhs-notify-internal static environment workflow deployment - shell: bash - run: | - set -x - - DISPATCH_EVENT=$(jq -ncM \ - --arg releaseVersion ${{ inputs.releaseVersion }} \ - --arg targetEnvironment ${{ inputs.targetEnvironment }} \ - --arg targetAccountGroup ${{ inputs.targetAccountGroup }} \ - --arg targetComponent ${{ inputs.targetComponent }} \ - --arg terraformAction ${{ inputs.terraformAction }} \ - '{ "ref": "main", - "inputs": { - "releaseVersion", $releaseVersion, - "targetEnvironment", $targetEnvironment, - "targetAccountGroup", $targetAccountGroup, - "targetComponent", $targetComponent, - "terraformAction", $terraformAction - } - }') - - # Trigger The workflow - curl -L \ - --fail \ - --silent \ - -X POST \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.PR_TRIGGER_PAT }}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/NHSDigital/nhs-notify-internal/actions/workflows/${{ inputs.targetWorkflow }}/dispatches" \ - -d "${DISPATCH_EVENT}" - - echo "Workflow triggered successfully. HTTP response. Waiting for the workflow to complete.." - - # Poll GitHub API to check the workflow status - run_id="" - for i in {1..12}; do - in_progress=$(curl -s \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.PR_TRIGGER_PAT }}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/NHSDigital/nhs-notify-internal/actions/runs?event=workflow_dispatch&status=in_progress") - - run_id=$(echo "$in_progress" | jq -r \ - --arg env "${{ inputs.targetEnvironment }}" \ - --arg component "${{ inputs.targetComponent }}" \ - --arg group "${{ inputs.targetAccountGroup }}" \ - --arg releaseVersion "${{ inputs.releaseVersion }}" \ - '.workflow_runs[] - | select(.name | contains($env) and contains($component) and contains($group) and contains($releaseVersion)) - | .id' | head -n 1) - - if [[ -n "$run_id" && "$run_id" != null ]]; then - echo "Found workflow run with ID: $run_id" - break - fi - - echo "Waiting for workflow to start..." - sleep 10 - done - - if [[ -z "$run_id" || "$run_id" == null ]]; then - echo "Failed to get the workflow run ID. Exiting." - exit 1 - fi - - # Wait for workflow completion - while true; do - sleep 10 - status=$(curl -s \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.PR_TRIGGER_PAT }}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/NHSDigital/nhs-notify-internal/actions/runs/$run_id" \ - | jq -r '.status') - - conclusion=$(curl -s \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.PR_TRIGGER_PAT }}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/NHSDigital/nhs-notify-internal/actions/runs/$run_id" \ - | jq -r '.conclusion') - - if [ "$status" == "completed" ]; then - if [ "$conclusion" == "success" ]; then - echo "Workflow completed successfully." - exit 0 - else - echo "Workflow failed with conclusion: $conclusion" - exit 1 - fi - fi - - echo "Workflow still running..." - sleep 20 - done