CD #82
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Using multiple workflow .yaml files | |
# https://stackoverflow.com/questions/64009546/how-to-run-multiple-github-actions-workflows-from-sub-directories | |
# TODO | |
# Preventing concurrent workflows (e.g. multiple merges to master at once) | |
# https://github.blog/changelog/2021-04-19-github-actions-limit-workflow-run-or-job-concurrency/ | |
# From: https://github.community/t/how-to-limit-concurrent-workflow-runs/16844/ | |
# | |
# Further split sub-directories' actions/workflows for more granular control. | |
# - https://stackoverflow.com/questions/64009546/how-to-run-multiple-github-actions-workflows-from-sub-directories | |
# If we decide to use Docker - Using local Dockerfile in pipeline: | |
# steps: | |
# - name: Check out code | |
# uses: actions/checkout@v3 | |
# - name: Build docker images | |
# run: docker build -t local < .devcontainer/Dockerfile # .devcontainer is the local path | |
# - name: Run tests | |
# run: docker run -it -v $PWD:/srv -w/srv local make test | |
# OR | |
# - name: Build docker images | |
# run: docker-compose build | |
# - name: Run tests | |
# run: docker-compose run test | |
# Ref: https://stackoverflow.com/questions/61154750/use-local-dockerfile-in-a-github-action | |
name: CD | |
on: | |
workflow_dispatch: | |
inputs: | |
clientVersion: | |
description: Custom version for the app rather than what's in the local config file (package.json, build.gradle, etc.); increments if 'true' is passed. | |
type: string | |
required: false | |
default: "" | |
# Publish your release in GitHub and have your pipeline react to deploy the package | |
release: | |
types: [ published ] | |
# Run the pipeline on merge to `master` and do the release/deploy then. | |
# pull_request: | |
# types: [ closed ] | |
# branches: [ master ] | |
# | |
# To run upon merge in general, apparently, there is no `merge` event, only `merge_group` which specifies merging | |
# when certain checks are required. Thus, mark "all checks" via `checks_requested`. | |
# See: | |
# - https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#merge_group | |
# merge_group: | |
# branches: [ checks_requested ] | |
# | |
# Run on CI completion (the `if:` in the `deploy` job below would need updating accordingly) | |
workflow_run: | |
workflows: [ 'CI' ] | |
types: [ completed ] | |
branches: [ master ] | |
defaults: | |
run: | |
shell: bash | |
working-directory: ./ | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
gitUserName: ${{ github.actor }} | |
gitUserEmail: ${{ github.actor }}@users.noreply.github.com | |
nodeVersion: 16 | |
clientVersion: "" # Can be declared via `env`, `workflow_dispatch.inputs`, or `release` -> `github.ref_name` | |
jobs: | |
cd-client: | |
runs-on: ubuntu-latest | |
outputs: | |
CLIENT_CACHE_ID: ${{ env.CLIENT_CACHE_ID }} | |
# Only run on merge to master, but not on PR to master since PRs are just drafts, not officially prod-ready code. | |
# | |
# Note: At least one job in each workflow must have no dependencies, i.e. no `needs` block. | |
# However, we can get around that using a conditional expression, i.e. `if` block. | |
# | |
# See: | |
# - https://github.community/t/depend-on-another-workflow/16311/3 | |
# - https://stackoverflow.com/questions/66205887/only-run-github-actions-step-if-not-a-pull-request/66206183#66206183 | |
# if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && (github.event.pull_request.merged || github.event.workflow_run.conclusion == 'success') }} | |
steps: | |
- name: CD - Abort run if CI failed | |
if: ${{ github.event.workflow_run.conclusion != null && github.event.workflow_run.conclusion != 'success' }} | |
# See: | |
# - Docs: https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_run | |
# - Example (SO post): https://stackoverflow.com/questions/67516571/github-action-triggered-by-success-of-a-different-action | |
run: | | |
echo "${{ github.event.workflow_run.name }} had conclusion of ${{ github.event.workflow_run.conclusion }}. Aborting..." >&2 | |
exit 1 | |
- name: CD:Client - Checkout repository branch | |
uses: actions/checkout@v3 | |
- name: CD:Client - Set NodeJS version | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.nodeVersion }} | |
# Consolidate any source of the new client version into one place, `env.clientVersion`, for ease of use | |
# throughout all other workflows/jobs/actions/steps. | |
# | |
# Since the only `release` event we listen to is `publish`, we can safely assume the ref-name is the tag name. | |
# | |
# See: | |
# - "Release" event and object info: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release | |
- name: CD:Client - Set version number | |
run: | | |
if [[ "$GITHUB_EVENT_NAME" == 'release' ]]; then | |
echo "clientVersion=$GITHUB_REF_NAME" >> $GITHUB_ENV | |
elif [[ -n "${{ inputs.clientVersion }}" ]]; then | |
echo "clientVersion=${{ inputs.clientVersion }}" >> $GITHUB_ENV | |
fi | |
# It seems strangely difficult to link different workflows together without re-running them. | |
# As such, we can't just arbitrarily add a dependency on CI without making sure this CD run uses the | |
# correct respective CI run. | |
# | |
# Thus, rather than use the `gh` API or similar to get the previous CI run, simply re-init the front-end. | |
# This ensures the code used in this workflow is the correct version. | |
# i.e. We might have multiple CI/CD pipelines running at once, each with a different version of the code, | |
# so don't get the most up-to-date version of the code, rather get the version associated with this specific | |
# run (via the `CLIENT_CACHE_ID`). | |
# | |
# Note that we can't use the `needs` object here since this job needs to remain dependency-free. | |
- name: CD:Client CD - Init | |
uses: ./.github/workflows/actions/client/init | |
env: | |
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} | |
gitUserName: ${{ env.gitUserName }} | |
gitUserEmail: ${{ env.gitUserEmail }} | |
nodeVersion: ${{ env.nodeVersion }} | |
- name: CD:Client - Output cache ID | |
id: cd-client-output-cache-id | |
run: | | |
echo "CLIENT_CACHE_ID=${{ env.CLIENT_CACHE_ID }}" >> $GITHUB_ENV | |
echo "CLIENT_CACHE_ID=${{ env.CLIENT_CACHE_ID }}" >> $GITHUB_OUTPUT | |
cd-deploy: | |
runs-on: ubuntu-latest | |
needs: [ cd-client ] # This automatically checks if `${{ needs.cd-client.result == 'success' }}` so job won't run if prev job was skipped or failed | |
env: | |
CLIENT_CACHE_ID: ${{ needs.cd-client.outputs.CLIENT_CACHE_ID }} | |
permissions: | |
pages: write # Grant write permissions to deploy to the `gh-pages` (or whatever is specified in "Settings") branch | |
id-token: write # to verify the deployment originates from an appropriate source | |
deployments: write | |
packages: write | |
actions: write | |
contents: write | |
steps: | |
- name: CD:Client - Checkout repository branch | |
uses: actions/checkout@v3 | |
- name: CD:Client - Set NodeJS version | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.nodeVersion }} | |
- name: CD:Client - Deploy website | |
uses: ./.github/workflows/actions/client/deploy | |
env: | |
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} | |
gitUserName: ${{ env.gitUserName }} | |
gitUserEmail: ${{ env.gitUserEmail }} | |
nodeVersion: ${{ env.nodeVersion }} | |
clientVersion: ${{ env.clientVersion }} |