Skip to content

fix: 7077 batch role (#1395) #1252

fix: 7077 batch role (#1395)

fix: 7077 batch role (#1395) #1252

Workflow file for this run

name: CD
on:
push:
branches:
- main
- prerelease
permissions:
contents: read
jobs:
release-please:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
tag_name: ${{ steps.release.outputs.tag_name }}
release_created: ${{ steps.release.outputs.release_created }}
steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}
fetch-depth: 0
- name: Configure Release-Please for Branch
run: |
if [[ "${{ github.ref_name }}" == "prerelease" ]]; then
echo "Configuring for pre-releases..."
cp prerelease-config.json release-please-config.json
fi
- name: Run Release-Please
id: release
uses: googleapis/release-please-action@v4
with:
target-branch: ${{ github.ref_name }}
- name: Cleanup
if: always()
run: |
if [[ "${{ github.ref_name }}" == "prerelease" ]]; then
git checkout -- release-please-config.json || true
fi
orchestrator:
name: Orchestrator
needs:
- release-please
runs-on: ubuntu-latest
outputs:
# Docs
should-deploy-docs: ${{ steps.changed-website-files.outputs.any_modified == 'true' || null }}
# App
should-build-app: ${{ needs.release-please.outputs.release_created || steps.changed-api-files.outputs.any_modified == 'true' || steps.changed-selfserve-files.outputs.any_modified == 'true' || steps.changed-internal-files.outputs.any_modified == 'true' || null }}
should-build-api: ${{ needs.release-please.outputs.release_created || steps.changed-api-files.outputs.any_modified == 'true' || null }}
should-build-selfserve: ${{ needs.release-please.outputs.release_created || steps.changed-selfserve-files.outputs.any_modified == 'true' || null }}
should-build-internal: ${{ needs.release-please.outputs.release_created || steps.changed-internal-files.outputs.any_modified == 'true' || null }}
# Assets
should-build-assets: ${{ needs.release-please.outputs.release_created || steps.changed-assets-files.outputs.any_modified == 'true' || null }}
# Docker
should-build-and-push-docker: ${{ needs.release-please.outputs.release_created || steps.changed-api-docker-files.outputs.any_modified == 'true' || steps.changed-selfserve-docker-files.outputs.any_modified == 'true' || steps.changed-internal-docker-files.outputs.any_modified == 'true' || steps.changed-cli-docker-files.outputs.any_modified == 'true' || null}}
should-build-and-push-api-docker: ${{ needs.release-please.outputs.release_created || steps.changed-api-docker-files.outputs.any_modified == 'true' || steps.changed-api-files.outputs.any_modified == 'true' || null }}
should-build-and-push-cli-docker: ${{ needs.release-please.outputs.release_created || steps.changed-cli-docker-files.outputs.any_modified == 'true' || steps.changed-api-files.outputs.any_modified == 'true' || null }}
should-build-and-push-selfserve-docker: ${{ needs.release-please.outputs.release_created || steps.changed-selfserve-docker-files.outputs.any_modified == 'true' || steps.changed-selfserve-files.outputs.any_modified == 'true' || null }}
should-build-and-push-internal-docker: ${{ needs.release-please.outputs.release_created || steps.changed-internal-docker-files.outputs.any_modified == 'true' || steps.changed-internal-files.outputs.any_modified == 'true' || null }}
# Terraform account
should-apply-account-terraform: ${{ needs.release-please.outputs.release_created || steps.changed-accounts-terraform-files.outputs.any_modified == 'true' || null }}
# Terraform environment
should-apply-environment-terraform: ${{ needs.release-please.outputs.release_created || steps.changed-environments-terraform-files.outputs.any_modified == 'true' || null }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: tj-actions/changed-files@v47
id: changed-api-files
with:
files: |
app/api/**
- uses: tj-actions/changed-files@v47
id: changed-selfserve-files
with:
files: |
app/selfserve/**
- uses: tj-actions/changed-files@v47
id: changed-internal-files
with:
files: |
app/internal/**
- uses: tj-actions/changed-files@v47
id: changed-assets-files
with:
files: |
app/cdn/**
- uses: tj-actions/changed-files@v47
id: changed-api-docker-files
with:
files: |
infra/docker/api/**
- uses: tj-actions/changed-files@v47
id: changed-cli-docker-files
with:
files: |
infra/docker/cli/**
- uses: tj-actions/changed-files@v47
id: changed-selfserve-docker-files
with:
files: |
infra/docker/selfserve/**
- uses: tj-actions/changed-files@v47
id: changed-internal-docker-files
with:
files: |
infra/docker/internal/**
- uses: tj-actions/changed-files@v47
id: changed-accounts-terraform-files
with:
files: |
infra/terraform/accounts/**
infra/terraform/modules/**
files_ignore: |
infra/terraform/modules/service/**
- uses: tj-actions/changed-files@v47
id: changed-environments-terraform-files
with:
files: |
infra/terraform/environments/{dev,int,prep,prod}/**
infra/terraform/modules/**
files_ignore: |
infra/terraform/modules/account/**
infra/terraform/modules/github/**
infra/terraform/modules/remote-state/**
- uses: tj-actions/changed-files@v47
id: changed-website-files
with:
files: |
website/**
docs/**
docs:
name: Documentation
if: ${{ needs.orchestrator.outputs.should-deploy-docs }}
concurrency:
group: deploy-documentation
needs:
- orchestrator
uses: ./.github/workflows/deploy-documentation.yaml
with:
deploy: true
permissions:
contents: read
pages: write
id-token: write
get-version:
name: Get latest app versions
needs:
- orchestrator
runs-on: ubuntu-latest
outputs:
api: ${{ steps.api-version.outputs.version }}
cli: ${{ steps.cli-version.outputs.version }}
selfserve: ${{ steps.selfserve-version.outputs.version }}
internal: ${{ steps.internal-version.outputs.version }}
assets: ${{ steps.assets-version.outputs.version }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- id: api-version
uses: dvsa/.github/.github/actions/get-vol-app-version@v5.0.10
with:
project-path: app/api infra/docker/api
- id: cli-version
uses: dvsa/.github/.github/actions/get-vol-app-version@v5.0.10
with:
project-path: app/api infra/docker/cli
- id: selfserve-version
uses: dvsa/.github/.github/actions/get-vol-app-version@v5.0.10
with:
project-path: app/selfserve infra/docker/selfserve
- id: internal-version
uses: dvsa/.github/.github/actions/get-vol-app-version@v5.0.10
with:
project-path: app/internal infra/docker/internal
- id: assets-version
uses: dvsa/.github/.github/actions/get-vol-app-version@v5.0.10
with:
project-path: app/cdn
- name: Add to summary
run: |
echo "#### App versions:" >> $GITHUB_STEP_SUMMARY
echo "**API**: \`${{ steps.api-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
echo "**CLI**: \`${{ steps.cli-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Selfserve**: \`${{ steps.selfserve-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Internal**: \`${{ steps.internal-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Assets**: \`${{ steps.assets-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
cdn-nonprod:
name: CDN
if: ${{ needs.orchestrator.outputs.should-build-assets }}
concurrency:
group: assets-nonprod
needs:
- orchestrator
- get-version
uses: ./.github/workflows/assets.yaml
with:
push: true
account: nonprod
version: ${{ needs.get-version.outputs.assets }}
permissions:
contents: read
id-token: write
app:
name: App
if: ${{ needs.orchestrator.outputs.should-build-app || needs.orchestrator.outputs.should-build-and-push-docker }}
concurrency:
group: app-${{ matrix.project }}-${{ needs.get-version.outputs[matrix.project] }}
needs:
- orchestrator
- get-version
strategy:
fail-fast: false
matrix:
project:
- api
- selfserve
- internal
exclude:
- project: ${{ (needs.orchestrator.outputs.should-build-api || needs.orchestrator.outputs.should-build-and-push-api-docker || needs.orchestrator.outputs.should-build-and-push-cli-docker) && 'ignored' || 'api' }}
- project: ${{ (needs.orchestrator.outputs.should-build-selfserve || needs.orchestrator.outputs.should-build-and-push-selfserve-docker) && 'ignored' || 'selfserve' }}
- project: ${{ (needs.orchestrator.outputs.should-build-internal || needs.orchestrator.outputs.should-build-and-push-internal-docker) && 'ignored' || 'internal' }}
uses: ./.github/workflows/php.yaml
with:
project: ${{ matrix.project }}
should-upload-artefact: true
artefact-name: ${{ matrix.project}}
retention-days: 1
version: ${{ needs.get-version.outputs[matrix.project] }}
permissions:
contents: read
docker:
name: Docker
if: ${{ always() && !cancelled() && !failure() && (needs.orchestrator.outputs.should-build-app || needs.orchestrator.outputs.should-build-and-push-docker) }}
concurrency:
group: docker-${{ matrix.project }}-${{ needs.get-version.outputs[matrix.project] }}
needs:
- orchestrator
- get-version
- app
strategy:
fail-fast: false
matrix:
project:
- api
- cli
- selfserve
- internal
exclude:
- project: ${{ needs.orchestrator.outputs.should-build-and-push-api-docker && 'ignored' || 'api' }}
- project: ${{ needs.orchestrator.outputs.should-build-and-push-cli-docker && 'ignored' || 'cli' }}
- project: ${{ needs.orchestrator.outputs.should-build-and-push-selfserve-docker && 'ignored' || 'selfserve' }}
- project: ${{ needs.orchestrator.outputs.should-build-and-push-internal-docker && 'ignored' || 'internal' }}
uses: ./.github/workflows/docker.yaml
with:
project: ${{ matrix.project }}
version: ${{ needs.get-version.outputs[matrix.project] }}
app-artefact-name: ${{ matrix.project == 'cli' && 'api' || matrix.project }}
push: true
permissions:
contents: read
id-token: write
packages: write
terraform-account-nonprod:
name: Account (nonprod)
if: ${{ needs.orchestrator.outputs.should-apply-account-terraform }}
concurrency:
group: terraform-account-nonprod
needs:
- orchestrator
uses: ./.github/workflows/deploy-account.yaml
with:
account: nonprod
apply: true
permissions:
contents: read
id-token: write
pull-requests: write
secrets: inherit
deploy_dev:
name: (dev)
if: |
always() &&
!cancelled() &&
!failure() &&
(needs.orchestrator.outputs.should-apply-environment-terraform || needs.docker.result == 'success' || needs.cdn.result == 'success')
needs:
- get-version
- orchestrator
- docker
- cdn-nonprod
- terraform-account-nonprod
concurrency:
group: ${{ github.workflow }}-dev
uses: ./.github/workflows/deploy-and-test.yaml
with:
account: nonprod
environment: dev
api-image-tag: ${{ needs.get-version.outputs.api }}
cli-image-tag: ${{ needs.get-version.outputs.cli }}
selfserve-image-tag: ${{ needs.get-version.outputs.selfserve }}
internal-image-tag: ${{ needs.get-version.outputs.internal }}
assets-version: ${{ needs.get-version.outputs.assets }}
etl_ref: ${{ needs.release-please.outputs.release_created && format('release-{0}', needs.release-please.outputs.tag_name) || 'main' }}
aws_role: ${{ vars.ACCOUNT_NONPROD_TEST_OIDC_ROLE }}
bucket_name: ${{ vars.ACCOUNT_NONPROD_S3_REPORT_BUCKET }}
bucket_key: ${{ vars.S3_REPORT_BUCKET_KEY }}
batch_job_queue: ${{ vars.ACCOUNT_NONPROD_BATCH_JOB_QUEUE }}
batch_job_definition: ${{ vars.ACCOUNT_NONPROD_BATCH_JOB_DEFINITION }}
permissions:
contents: write
id-token: write
pull-requests: write
checks: write
secrets:
VOL_GITHUB_APP_PRIVATE_KEY: ${{ secrets.VOL_GITHUB_APP_PRIVATE_KEY }}
deploy_int:
name: (int)
if: |
always() &&
!cancelled() &&
!failure() &&
needs.deploy_dev.result == 'success'
needs:
- get-version
- orchestrator
- deploy_dev
concurrency:
group: ${{ github.workflow }}-int
uses: ./.github/workflows/deploy-and-test.yaml
with:
account: nonprod
environment: int
api-image-tag: ${{ needs.get-version.outputs.api }}
cli-image-tag: ${{ needs.get-version.outputs.cli }}
selfserve-image-tag: ${{ needs.get-version.outputs.selfserve }}
internal-image-tag: ${{ needs.get-version.outputs.internal }}
assets-version: ${{ needs.get-version.outputs.assets }}
etl_ref: ${{ needs.release-please.outputs.release_created && format('release-{0}', needs.release-please.outputs.tag_name) || 'main' }}
aws_role: ${{ vars.ACCOUNT_NONPROD_TEST_OIDC_ROLE }}
bucket_name: ${{ vars.ACCOUNT_NONPROD_S3_REPORT_BUCKET }}
bucket_key: ${{ vars.S3_REPORT_BUCKET_KEY }}
batch_job_queue: ${{ vars.ACCOUNT_NONPROD_BATCH_JOB_QUEUE }}
batch_job_definition: ${{ vars.ACCOUNT_NONPROD_BATCH_JOB_DEFINITION }}
permissions:
contents: write
id-token: write
pull-requests: write
checks: write
secrets:
VOL_GITHUB_APP_PRIVATE_KEY: ${{ secrets.VOL_GITHUB_APP_PRIVATE_KEY }}
push-to-prod-ecr:
name: Push Docker Images to PROD ECR
permissions:
contents: read
id-token: write
if: |
always() &&
!cancelled() &&
!failure() &&
needs.release-please.outputs.release_created &&
needs.deploy_int.result == 'success'
runs-on: ubuntu-24.04-arm
needs:
- release-please
- get-version
- deploy_int
env:
NONPROD_REGISTRY: 054614622558.dkr.ecr.eu-west-1.amazonaws.com
PROD_REGISTRY: 146997448015.dkr.ecr.eu-west-1.amazonaws.com
AWS_REGION: ${{ vars.DVSA_AWS_REGION }}
strategy:
fail-fast: false
matrix:
include:
- project: api
repo: vol-app
- project: cli
repo: vol-app
- project: selfserve
repo: vol-app
- project: internal
repo: vol-app
- project: liquibase
repo: vol-app
- project: vft
repo: vol-qa
steps:
- name: Configure AWS credentials for NONPROD
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: ${{ vars.ACCOUNT_NONPROD_TF_OIDC_ROLE }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to NONPROD ECR
uses: docker/login-action@v3
with:
registry: ${{ env.NONPROD_REGISTRY }}
- name: Determine image tag
id: image-tag
run: |
# Set the image tag based on the project
if [ "${{ matrix.project }}" == "api" ]; then
echo "tag=${{ needs.get-version.outputs.api }}" >> $GITHUB_OUTPUT
elif [ "${{ matrix.project }}" == "cli" ]; then
echo "tag=${{ needs.get-version.outputs.cli }}" >> $GITHUB_OUTPUT
elif [ "${{ matrix.project }}" == "selfserve" ]; then
echo "tag=${{ needs.get-version.outputs.selfserve }}" >> $GITHUB_OUTPUT
elif [ "${{ matrix.project }}" == "internal" ]; then
echo "tag=${{ needs.get-version.outputs.internal }}" >> $GITHUB_OUTPUT
elif [ "${{ matrix.project }}" == "liquibase" ]; then
# For liquibase, use the latest tag
echo "tag=latest" >> $GITHUB_OUTPUT
fi
- name: Pull image from NONPROD ECR
run: |
if [ "${{ matrix.project }}" == "vft" ]; then
# For vft, always use latest tag
echo "Pulling image from NONPROD ECR: ${NONPROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest"
docker pull ${NONPROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest
# Tag for local reference
docker tag ${NONPROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest local-image:latest
else
echo "Pulling image from NONPROD ECR: ${NONPROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:${{ steps.image-tag.outputs.tag }}"
docker pull ${NONPROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:${{ steps.image-tag.outputs.tag }}
# Tag for local reference
docker tag ${NONPROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:${{ steps.image-tag.outputs.tag }} local-image:${{ steps.image-tag.outputs.tag }}
fi
- name: Configure AWS credentials for PROD
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: ${{ vars.ACCOUNT_PROD_TF_OIDC_ROLE }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to PROD ECR
uses: docker/login-action@v3
with:
registry: ${{ env.PROD_REGISTRY }}
- name: Remove existing latest tag from PROD ECR
run: |
echo "Removing existing latest tag from PROD ECR if it exists"
aws ecr batch-delete-image --repository-name ${{ matrix.repo }}/${{ matrix.project }} --image-ids imageTag=latest || true
- name: Push image to PROD ECR
run: |
if [ "${{ matrix.project }}" == "vft" ]; then
# For vft, always use latest tag
echo "Tagging image for PROD ECR: ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest"
docker tag local-image:latest ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest
echo "Pushing image to PROD ECR: ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest"
docker push ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest
else
# Tag the local image for PROD ECR
echo "Tagging image for PROD ECR: ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:${{ steps.image-tag.outputs.tag }}"
docker tag local-image:${{ steps.image-tag.outputs.tag }} ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:${{ steps.image-tag.outputs.tag }}
echo "Pushing image to PROD ECR: ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:${{ steps.image-tag.outputs.tag }}"
docker push ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:${{ steps.image-tag.outputs.tag }}
# Also push as latest if not liquibase (which already uses latest)
if [ "${{ matrix.project }}" != "liquibase" ]; then
echo "Tagging image as latest for PROD ECR: ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest"
docker tag local-image:${{ steps.image-tag.outputs.tag }} ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest
echo "Pushing latest tag to PROD ECR: ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest"
docker push ${PROD_REGISTRY}/${{ matrix.repo }}/${{ matrix.project }}:latest
fi
fi
cdn-prod:
name: CDN
if: ${{ needs.orchestrator.outputs.should-build-assets && needs.release-please.outputs.release_created }}
concurrency:
group: assets-prod
needs:
- orchestrator
- get-version
uses: ./.github/workflows/assets.yaml
with:
push: true
account: prod
version: ${{ needs.get-version.outputs.assets }}
permissions:
contents: read
id-token: write
terraform-account-prod-plan:
name: Account (prod) plan
if: ${{ always() && !cancelled() && !failure() && needs.release-please.outputs.release_created }}
concurrency:
group: terraform-account-prod
needs:
- release-please
- orchestrator
- deploy_int
- push-to-prod-ecr
uses: ./.github/workflows/deploy-account.yaml
with:
account: prod
permissions:
contents: read
id-token: write
pull-requests: write
secrets: inherit
terraform-account-prod:
name: Account (prod)
if: ${{ always() && !cancelled() && !failure() && needs.release-please.outputs.release_created && needs.terraform-account-prod-plan.result != 'failure' }}
concurrency:
group: terraform-account-prod
needs:
- terraform-account-prod-plan
- release-please
- orchestrator
- push-to-prod-ecr
uses: ./.github/workflows/deploy-account.yaml
with:
account: prod
apply: true
permissions:
contents: read
id-token: write
pull-requests: write
secrets: inherit
deploy_prep:
name: (prep)
if: |
always() &&
!cancelled() &&
!failure() &&
needs.release-please.outputs.release_created
needs:
- release-please
- get-version
- orchestrator
- terraform-account-prod
- push-to-prod-ecr
concurrency:
group: ${{ github.workflow }}-prep
uses: ./.github/workflows/deploy-and-test.yaml
with:
account: prod
environment: prep
api-image-tag: ${{ needs.get-version.outputs.api }}
cli-image-tag: ${{ needs.get-version.outputs.cli }}
selfserve-image-tag: ${{ needs.get-version.outputs.selfserve }}
internal-image-tag: ${{ needs.get-version.outputs.internal }}
assets-version: ${{ needs.get-version.outputs.assets }}
etl_ref: ${{ needs.release-please.outputs.tag_name && format('release-{0}', needs.release-please.outputs.tag_name) || 'main' }}
aws_role: ${{ vars.ACCOUNT_PROD_TEST_OIDC_ROLE }}
bucket_name: ${{ vars.ACCOUNT_PROD_S3_REPORT_BUCKET }}
bucket_key: ${{ vars.S3_REPORT_BUCKET_KEY }}
batch_job_queue: ${{ vars.ACCOUNT_PROD_BATCH_JOB_QUEUE }}
batch_job_definition: ${{ vars.ACCOUNT_PROD_BATCH_JOB_DEFINITION }}
permissions:
contents: write
id-token: write
pull-requests: write
checks: write
secrets:
VOL_GITHUB_APP_PRIVATE_KEY: ${{ secrets.VOL_GITHUB_APP_PRIVATE_KEY }}
deploy_prod:
name: (prod)
if: |
always() &&
!cancelled() &&
!failure() &&
needs.release-please.outputs.release_created &&
!contains(needs.get-version.outputs.api, 'rc') &&
!contains(needs.get-version.outputs.cli, 'rc') &&
!contains(needs.get-version.outputs.selfserve, 'rc') &&
!contains(needs.get-version.outputs.internal, 'rc') &&
!contains(needs.get-version.outputs.assets, 'rc')
needs:
- release-please
- get-version
- orchestrator
- terraform-account-prod
- push-to-prod-ecr
concurrency:
group: ${{ github.workflow }}-prod
uses: ./.github/workflows/deploy-and-test.yaml
with:
account: prod
environment: prod
api-image-tag: ${{ needs.get-version.outputs.api }}
cli-image-tag: ${{ needs.get-version.outputs.cli }}
selfserve-image-tag: ${{ needs.get-version.outputs.selfserve }}
internal-image-tag: ${{ needs.get-version.outputs.internal }}
assets-version: ${{ needs.get-version.outputs.assets }}
etl_ref: ${{ needs.release-please.outputs.tag_name && format('release-{0}', needs.release-please.outputs.tag_name) || 'main' }}
aws_role: ${{ vars.ACCOUNT_PROD_TEST_OIDC_ROLE }}
bucket_name: ${{ vars.ACCOUNT_PROD_S3_REPORT_BUCKET }}
bucket_key: ${{ vars.S3_REPORT_BUCKET_KEY }}
batch_job_queue: ${{ vars.ACCOUNT_PROD_BATCH_JOB_QUEUE }}
batch_job_definition: ${{ vars.ACCOUNT_PROD_BATCH_JOB_DEFINITION }}
permissions:
contents: write
id-token: write
pull-requests: write
checks: write
secrets:
VOL_GITHUB_APP_PRIVATE_KEY: ${{ secrets.VOL_GITHUB_APP_PRIVATE_KEY }}