Skip to content

Continuous Delivery #49

Continuous Delivery

Continuous Delivery #49

name: Continuous Delivery
on:
workflow_dispatch:
inputs:
merge:
description: Merge staging into main first? (y/N)
required: false
default: 'n'
concurrency:
group: cd-${{ github.ref_name }}
env:
PROJECT_NAME: arora-api
jobs:
branch_check:
name: Branch Check
runs-on: ubuntu-latest
steps:
- name: Validate branch
run: |
if [ "$GITHUB_REF_NAME" != 'staging' ] && [ "$GITHUB_REF_NAME" != 'main' ]; then
echo 'This workflow can only be run on branches staging and main.'
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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Get metadata
id: get_metadata
env:
INPUT_MERGE: ${{ github.event.inputs.merge }}
run: |
if [ "$GITHUB_REF_NAME" = 'main' ]; then
if [ "${INPUT_MERGE,,}" = 'y' ]; then
git fetch origin staging
if ! git diff origin/main 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" != 'main' ]; then
echo 'Can only merge when the workflow target branch is main.'
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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- 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: main
github_token: ${{ github.token }}
- name: Get merge commit SHA
id: get_sha
if: fromJSON(needs.metadata.outputs.has_diff)
run: |
git fetch origin main
echo 'sha='"$(git rev-parse origin/main)" >> "$GITHUB_OUTPUT"
continuous_integration:
name: Continuous Integration
needs: [metadata, merge]
if: fromJSON(needs.metadata.outputs.has_diff)
uses: guidojw/arora-api/.github/workflows/continuous-integration.yml@staging
with:
sha: ${{ needs.merge.outputs.sha }}
publish_image:
name: Publish Image
needs: [metadata, merge]
if: fromJSON(needs.metadata.outputs.has_diff)
uses: guidojw/arora-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 == 'main') && ((github.ref_name == 'main' &&
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" = 'main' ]; then
echo 'environment_url=https://nsadmin.guidojw.nl/api' >> "$GITHUB_OUTPUT"
else
echo 'environment_url=https://staging.nsadmin.guidojw.nl/api' >> "$GITHUB_OUTPUT"
fi
- name: Checkout code
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
ref: ${{ needs.merge.outputs.sha }}
- name: Install cloudflared
run: |
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared '"$(lsb_release -cs)"' main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update && sudo apt install cloudflared
- name: Set up SSH key
uses: shimataro/ssh-key-action@685d0f20da72e4b53cc81d373a2ed0a867770e46 # v2.5.1
with:
key: ${{ secrets.SSH_PRIVATE_KEY }}
known_hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
config: |
Host maya
HostName ${{ secrets.SSH_HOST }}
User github-actions
ProxyCommand cloudflared access ssh --hostname %h --id ${{ secrets.CLOUDFLARE_SERVICE_TOKEN_ID }} --secret ${{ secrets.CLOUDFLARE_SERVICE_TOKEN_SECRET }}
- name: Start deployment
uses: bobheadxi/deployments@88ce5600046c82542f8246ac287d0a53c461bca3 # v1.4.0
id: start_deployment
with:
step: start
env: ${{ needs.metadata.outputs.stage }}
- name: Deploy
env:
STAGE: ${{ needs.metadata.outputs.stage }}
run: |
ssh maya '
cd /opt/docker/'"$PROJECT_NAME"'/'"$STAGE"'
docker-compose pull
docker-compose run --rm app yarn run typeorm migration:run
docker-compose up -d
'
- name: Finalize Sentry release
uses: getsentry/action-release@4744f6a65149f441c5f396d5b0877307c0db52c7 # v1.4.1
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@88ce5600046c82542f8246ac287d0a53c461bca3 # v1.4.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 == 'main') && 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@870d7c8de5aeb08420bb88d8fbddb0222a9eac61 # v1.4.0
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 }}