name: Deploy infrastructure on: push: branches: - "dev" - "prod" workflow_dispatch: jobs: determine_stage: runs-on: ubuntu-latest outputs: stage: ${{ steps.set-stage.outputs.stage }} terraform_apply: ${{ steps.set-stage.outputs.terraform_apply }} env: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} steps: - name: Determine stage from branch id: set-stage shell: bash run: | BRANCH="${GITHUB_REF_NAME}" if [[ "$BRANCH" == "prod" ]]; then echo "stage=prod" >> "$GITHUB_OUTPUT" echo "terraform_apply=false" >> "$GITHUB_OUTPUT" elif [[ "$BRANCH" == "dev" ]]; then echo "stage=dev" >> "$GITHUB_OUTPUT" echo "terraform_apply=true" >> "$GITHUB_OUTPUT" else # Feature branch echo "stage=dev" >> "$GITHUB_OUTPUT" echo "terraform_apply=false" >> "$GITHUB_OUTPUT" fi # ============================================================ # Shared Terraform (infra) # ============================================================ shared_terraform: needs: determine_stage runs-on: ubuntu-latest env: STAGE: ${{ needs.determine_stage.outputs.stage }} TERRAFORM_APPLY: ${{ needs.determine_stage.outputs.terraform_apply }} steps: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.DEV_AWS_REGION }} - uses: hashicorp/setup-terraform@v3 - name: Terraform Init working-directory: infrastructure/terraform/shared run: terraform init -reconfigure - name: Terraform Workspace working-directory: infrastructure/terraform/shared run: terraform workspace select ${STAGE} || terraform workspace new ${STAGE} - name: Terraform Plan working-directory: infrastructure/terraform/shared run: terraform plan -var-file=${STAGE}.tfvars -out=tfplan - name: Terraform Apply if: env.TERRAFORM_APPLY == 'true' working-directory: infrastructure/terraform/shared run: terraform apply -auto-approve tfplan # ============================================================ # Ara Engine image and Push # ============================================================ ara_engine_image: needs: [determine_stage, shared_terraform] uses: ./.github/workflows/_build_image.yml with: ecr_repo: engine-${{ needs.determine_stage.outputs.stage }} dockerfile_path: backend/docker/engine.Dockerfile build_context: . secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} # ============================================================ # Deploy Ara Engine Lambda # ============================================================ ara_engine_lambda: needs: [ara_engine_image, determine_stage] uses: ./.github/workflows/_deploy_lambda.yml with: lambda_name: ara_engine lambda_path: infrastructure/terraform/lambda/engine stage: ${{ needs.determine_stage.outputs.stage }} ecr_repo: engine-${{ needs.determine_stage.outputs.stage }} image_digest: ${{ needs.ara_engine_image.outputs.image_digest }} terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} TF_VAR_db_host: ${{ secrets.DEV_DB_HOST }} TF_VAR_db_name: ${{ secrets.DEV_DB_NAME }} TF_VAR_db_port: ${{ secrets.DEV_DB_PORT }} TF_VAR_api_key: ${{ secrets.DEV_API_KEY }} TF_VAR_secret_key: ${{ secrets.DEV_SECRET_KEY }} TF_VAR_epc_auth_token: ${{ secrets.DEV_EPC_AUTH_TOKEN }} TF_VAR_google_solar_api_key: ${{ secrets.DEV_GOOGLE_SOLAR_API_KEY }} # ============================================================ # Build Address 2 UPRN image and Push # ============================================================ address2uprn_image: needs: [determine_stage, shared_terraform] uses: ./.github/workflows/_build_image.yml with: ecr_repo: address2uprn-${{ needs.determine_stage.outputs.stage }} dockerfile_path: backend/address2UPRN/handler/Dockerfile build_context: . build_args: | DEV_DB_HOST=$DEV_DB_HOST DEV_DB_PORT=$DEV_DB_PORT DEV_DB_NAME=$DEV_DB_NAME EPC_AUTH_TOKEN=$EPC_AUTH_TOKEN secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} DEV_DB_PORT: ${{ secrets.DEV_DB_PORT }} DEV_DB_NAME: ${{ secrets.DEV_DB_NAME }} EPC_AUTH_TOKEN: ${{ secrets.DEV_EPC_AUTH_TOKEN }} # ============================================================ # Deploy Address 2 UPRN Lambda # ============================================================ address2uprn_lambda: needs: [address2uprn_image, determine_stage] uses: ./.github/workflows/_deploy_lambda.yml with: lambda_name: address2uprn lambda_path: infrastructure/terraform/lambda/address2UPRN stage: ${{ needs.determine_stage.outputs.stage }} ecr_repo: address2uprn-${{ needs.determine_stage.outputs.stage }} image_digest: ${{ needs.address2uprn_image.outputs.image_digest }} terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} # ============================================================ # Build Postcode Splitter image and Push # ============================================================ postcodeSplitter_image: needs: [determine_stage, shared_terraform] uses: ./.github/workflows/_build_image.yml with: ecr_repo: postcode_splitter-${{ needs.determine_stage.outputs.stage }} dockerfile_path: backend/postcode_splitter/handler/Dockerfile build_context: . build_args: | DEV_DB_HOST=$DEV_DB_HOST DEV_DB_PORT=$DEV_DB_PORT DEV_DB_NAME=$DEV_DB_NAME secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} DEV_DB_PORT: ${{ secrets.DEV_DB_PORT }} DEV_DB_NAME: ${{ secrets.DEV_DB_NAME }} # ============================================================ # Deploy Postcode Splitter Lambda # ============================================================ postcodeSplitter_lambda: needs: [postcodeSplitter_image, determine_stage, address2uprn_lambda] uses: ./.github/workflows/_deploy_lambda.yml with: lambda_name: postcodeSplitter lambda_path: infrastructure/terraform/lambda/postcodeSplitter stage: ${{ needs.determine_stage.outputs.stage }} ecr_repo: postcode_splitter-${{ needs.determine_stage.outputs.stage }} image_digest: ${{ needs.postcodeSplitter_image.outputs.image_digest }} terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} # ============================================================ # Condition ETL image and Push # ============================================================ condition_etl_image: needs: [determine_stage, shared_terraform] uses: ./.github/workflows/_build_image.yml with: ecr_repo: condition-etl-${{ needs.determine_stage.outputs.stage }} dockerfile_path: backend/condition/handler/Dockerfile build_context: . build_args: | DEV_DB_HOST=$DEV_DB_HOST DEV_DB_PORT=$DEV_DB_PORT DEV_DB_NAME=$DEV_DB_NAME secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} DEV_DB_PORT: ${{ secrets.DEV_DB_PORT }} DEV_DB_NAME: ${{ secrets.DEV_DB_NAME }} # ============================================================ # Deploy Condition ETL Lambda # ============================================================ condition_etl_lambda: needs: [condition_etl_image, determine_stage] uses: ./.github/workflows/_deploy_lambda.yml with: lambda_name: condition-etl lambda_path: infrastructure/terraform/lambda/condition-etl stage: ${{ needs.determine_stage.outputs.stage }} ecr_repo: condition-etl-${{ needs.determine_stage.outputs.stage }} image_digest: ${{ needs.condition_etl_image.outputs.image_digest }} terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} # ============================================================ # Categorisation image and Push # ============================================================ categorisation_image: needs: [determine_stage, shared_terraform] uses: ./.github/workflows/_build_image.yml with: ecr_repo: categorisation-${{ needs.determine_stage.outputs.stage }} dockerfile_path: backend/categorisation/handler/Dockerfile build_context: . build_args: | DEV_DB_HOST=$DEV_DB_HOST DEV_DB_PORT=$DEV_DB_PORT DEV_DB_NAME=$DEV_DB_NAME secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} DEV_DB_PORT: ${{ secrets.DEV_DB_PORT }} DEV_DB_NAME: ${{ secrets.DEV_DB_NAME }} # ============================================================ # Deploy Categorisation Lambda # ============================================================ categorisation_lambda: needs: [categorisation_image, determine_stage] uses: ./.github/workflows/_deploy_lambda.yml with: lambda_name: categorisation lambda_path: infrastructure/terraform/lambda/categorisation stage: ${{ needs.determine_stage.outputs.stage }} ecr_repo: categorisation-${{ needs.determine_stage.outputs.stage }} image_digest: ${{ needs.categorisation_image.outputs.image_digest }} terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} # ============================================================ # Build OrdanceSurvey image and Push # ============================================================ ordnanceSurvey_image: needs: [determine_stage, shared_terraform] uses: ./.github/workflows/_build_image.yml with: ecr_repo: ordnance-${{ needs.determine_stage.outputs.stage }} dockerfile_path: backend/ordnanceSurvey/handler/Dockerfile build_context: . build_args: | DEV_DB_HOST=$DEV_DB_HOST DEV_DB_PORT=$DEV_DB_PORT DEV_DB_NAME=$DEV_DB_NAME secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} DEV_DB_PORT: ${{ secrets.DEV_DB_PORT }} DEV_DB_NAME: ${{ secrets.DEV_DB_NAME }} # ============================================================ # Deploy OrdanceSurvey Lambda # ============================================================ ordnanceSurvey_lambda: needs: [ordnanceSurvey_image, determine_stage] uses: ./.github/workflows/_deploy_lambda.yml with: lambda_name: ordnanceSurvey lambda_path: infrastructure/terraform/lambda/ordnanceSurvey stage: ${{ needs.determine_stage.outputs.stage }} ecr_repo: ordnance-${{ needs.determine_stage.outputs.stage }} image_digest: ${{ needs.ordnanceSurvey_image.outputs.image_digest }} terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} TF_VAR_ORDNANCE_SURVEY_API_KEY: ${{ secrets.ORDNANCE_SURVEY_API_KEY }} # ============================================================ # Deploy FastAPI Lambda # ============================================================ fast_api_lambda: needs: [determine_stage, ara_engine_lambda, categorisation_lambda] uses: ./.github/workflows/_deploy_lambda.yml with: lambda_name: ara_fast_api lambda_path: infrastructure/terraform/lambda/fast-api stage: ${{ needs.determine_stage.outputs.stage }} terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} TF_VAR_db_host: ${{ secrets.DEV_DB_HOST }} TF_VAR_db_name: ${{ secrets.DEV_DB_NAME }} TF_VAR_db_port: ${{ secrets.DEV_DB_PORT }} TF_VAR_api_key: ${{ secrets.FASTAPI_API_KEY }} TF_VAR_secret_key: ${{ secrets.NEXTAUTH_SECRET }} TF_VAR_domain_name: ${{ secrets.ARA_DEV_DOMAIN_NAME }} TF_VAR_epc_auth_token: ${{ secrets.DEV_EPC_AUTH_TOKEN }} TF_VAR_google_solar_api_key: ${{ secrets.DEV_GOOGLE_SOLAR_API_KEY }} # ============================================================ # Deploy ACM Certificate for Cloudfront # ============================================================ cloudfront_acm: needs: [determine_stage, shared_terraform, fast_api_lambda] runs-on: ubuntu-latest env: STAGE: ${{ needs.determine_stage.outputs.stage }} TERRAFORM_APPLY: ${{ needs.determine_stage.outputs.terraform_apply }} steps: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.DEV_AWS_REGION }} - uses: hashicorp/setup-terraform@v3 - name: Terraform Init working-directory: infrastructure/terraform/cdn_certificate run: terraform init -reconfigure - name: Terraform Workspace working-directory: infrastructure/terraform/cdn_certificate run: | terraform workspace select $STAGE \ || terraform workspace new $STAGE - name: Terraform Plan working-directory: infrastructure/terraform/cdn_certificate run: | terraform plan \ -var="stage=${STAGE}" \ -out=tfplan - name: Terraform Apply if: env.TERRAFORM_APPLY == 'true' working-directory: infrastructure/terraform/cdn_certificate run: terraform apply -auto-approve tfplan # ============================================================ # Deploy Cloudfront CDN # ============================================================ cloudfront_cdn: needs: [determine_stage, cloudfront_acm] runs-on: ubuntu-latest env: STAGE: ${{ needs.determine_stage.outputs.stage }} TERRAFORM_APPLY: ${{ needs.determine_stage.outputs.terraform_apply }} steps: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.DEV_AWS_REGION }} - uses: hashicorp/setup-terraform@v3 - name: Terraform Init working-directory: infrastructure/terraform/cdn run: terraform init -reconfigure - name: Terraform Workspace working-directory: infrastructure/terraform/cdn run: | terraform workspace select $STAGE \ || terraform workspace new $STAGE - name: Terraform Plan working-directory: infrastructure/terraform/cdn run: | terraform plan \ -var="stage=${STAGE}" \ -out=tfplan - name: Terraform Apply if: env.TERRAFORM_APPLY == 'true' working-directory: infrastructure/terraform/cdn run: terraform apply -auto-approve tfplan