Skip to content

Continuous Delivery #58

Continuous Delivery

Continuous Delivery #58

name: Continuous Delivery
on:
workflow_dispatch:
inputs:
merge:
description: Merge staging into master first? (y/N)
required: false
default: 'n'
concurrency:
group: cd-${{ github.ref_name }}
env:
PROJECT_NAME: amber-api
jobs:
branch_check:
name: Branch Check
runs-on: ubuntu-latest
steps:
- name: Validate branch
run: |
if [ "$GITHUB_REF_NAME" != 'staging' ] && [ "$GITHUB_REF_NAME" != 'master' ]; then
echo 'This workflow can only be run on branches staging and master.'
exit 1
fi
metadata:
name: Metadata
runs-on: ubuntu-latest
needs: branch_check
outputs:
has_diff: ${{ steps.get_metadata.outputs.has_diff }}
stage: ${{ steps.get_metadata.outputs.stage }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Get metadata
id: get_metadata
env:
INPUT_MERGE: ${{ github.event.inputs.merge }}
run: |
if [ "$GITHUB_REF_NAME" = 'master' ]; then
if [ "${INPUT_MERGE,,}" = 'y' ]; then
git fetch origin staging
if ! git diff origin/master origin/staging --exit-code; then
echo 'has_diff=true' >> "$GITHUB_OUTPUT"
else
echo 'has_diff=false' >> "$GITHUB_OUTPUT"
fi
fi
echo 'stage=production' >> "$GITHUB_OUTPUT"
else
echo 'stage=staging' >> "$GITHUB_OUTPUT"
fi
merge:
name: Merge
runs-on: ubuntu-latest
needs: metadata
if: github.event.inputs.merge == 'y'
outputs:
sha: ${{ steps.get_sha.outputs.sha }}
steps:
- name: Validate inputs
env:
HAS_DIFF: ${{ fromJSON(needs.metadata.outputs.has_diff || false) }}
run: |
if [ "$GITHUB_REF_NAME" != 'master' ]; then
echo 'Can only merge when the workflow target branch is master.'
exit 1
fi
if ! $HAS_DIFF; then
echo 'There is no diff so a merge is not necessary, skipping next steps.'
fi
- name: Checkout code
if: fromJSON(needs.metadata.outputs.has_diff)
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run merge
if: fromJSON(needs.metadata.outputs.has_diff)
uses: devmasx/merge-branch@854d3ac71ed1e9deb668e0074781b81fdd6e771f # tag=v1.4.0
with:
type: now
from_branch: staging
target_branch: master
github_token: ${{ github.token }}
- name: Get merge commit SHA
id: get_sha
if: fromJSON(needs.metadata.outputs.has_diff)
run: |
git fetch origin master
echo 'sha='"$(git rev-parse origin/master)" >> "$GITHUB_OUTPUT"
continuous_integration:
name: Continuous Integration
needs: [metadata, merge]
if: fromJSON(needs.metadata.outputs.has_diff)
uses: csvalpha/amber-api/.github/workflows/continuous-integration.yml@staging
with:
sha: ${{ needs.merge.outputs.sha }}
secrets:
codecov_token: ${{ secrets.CODECOV_TOKEN }}
rails_master_key: ${{ secrets.RAILS_MASTER_KEY }}
publish_image:
name: Publish Image
needs: [metadata, merge]
if: fromJSON(needs.metadata.outputs.has_diff)
uses: csvalpha/amber-api/.github/workflows/publish-image.yml@staging
with:
sha: ${{ needs.merge.outputs.sha }}
secrets:
sentry_auth_token: ${{ secrets.SENTRY_AUTH_TOKEN }}
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: [metadata, merge, continuous_integration, publish_image]
if: |
(github.ref_name == 'staging' || github.ref_name == 'master') && ((github.ref_name == 'master' &&
github.event.inputs.merge == 'y' && fromJSON(needs.metadata.outputs.has_diff) && success()) ||
((github.event.inputs.merge != 'y' || !fromJSON(needs.metadata.outputs.has_diff)) && !cancelled()))
steps:
- name: Get environment URL
id: get_url
run: |
if [ "$GITHUB_REF_NAME" = 'master' ]; then
echo 'environment_url=https://csvalpha.nl/api' >> "$GITHUB_OUTPUT"
else
echo 'environment_url=https://staging.csvalpha.nl/api' >> "$GITHUB_OUTPUT"
fi
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ needs.merge.outputs.sha }}
- name: Start deployment
uses: bobheadxi/deployments@648679e8e4915b27893bd7dbc35cb504dc915bc8 # v1.5.0
id: start_deployment
with:
step: start
env: ${{ needs.metadata.outputs.stage }}
- name: Deploy
uses: appleboy/ssh-action@7eaf76671a0d7eec5d98ee897acda4f968735a17 # v1.2.0
env:
STAGE: ${{ needs.metadata.outputs.stage }}
with:
host: ssh.csvalpha.nl
username: github-actions
key: ${{ secrets.SSH_PRIVATE_KEY }}
envs: PROJECT_NAME,STAGE
script: |
cd /opt/docker/$PROJECT_NAME/$STAGE
docker-compose pull
docker-compose run --rm web rails db:migrate
docker-compose up -d
- name: Finalize Sentry release
uses: getsentry/action-release@e769183448303de84c5a06aaaddf9da7be26d6c7 # v1.7.0
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG_NAME }}
SENTRY_PROJECT: ${{ env.PROJECT_NAME }}
with:
environment: ${{ needs.metadata.outputs.stage }}
version: ${{ needs.merge.outputs.sha }}
set_commits: skip
- name: Finish deployment
uses: bobheadxi/deployments@648679e8e4915b27893bd7dbc35cb504dc915bc8 # v1.5.0
if: steps.start_deployment.conclusion == 'success' && always()
with:
step: finish
status: ${{ job.status }}
deployment_id: ${{ steps.start_deployment.outputs.deployment_id }}
env: ${{ needs.metadata.outputs.stage }}
env_url: ${{ steps.get_url.outputs.environment_url }}
update_check_run:
name: Update Check Run
runs-on: ubuntu-latest
needs: [branch_check, metadata, merge, continuous_integration, publish_image, deploy]
if: (github.ref_name == 'staging' || github.ref_name == 'master') && always()
steps:
- name: Get conclusion
id: get_conclusion
env:
RESULTS: ${{ join(needs.*.result, ' ') }}
run: |
echo 'conclusion=success' >> "$GITHUB_OUTPUT"
for RESULT in $RESULTS; do
if [ "$RESULT" = 'cancelled' ] || [ "$RESULT" = 'failure' ]; then
echo 'conclusion='"$RESULT" >> "$GITHUB_OUTPUT"
break
fi
done
- name: Update Continuous Delivery check run
uses: guidojw/actions/update-check-run@ec8c080252c6b8903a4431211b78c543609f5f89 # v1.4.6
with:
app_id: ${{ vars.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
sha: ${{ needs.merge.outputs.sha }}
name: Continuous Delivery
conclusion: ${{ steps.get_conclusion.outputs.conclusion }}
details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}