build main #947
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
--- | |
name: build main | |
# Actions that take place after a workflow trigger on the master/main branch. | |
# If a DOCKERHUB_USERNAME secret is defined the image is pushed. | |
# If a TRIGGER_AWX secret is defined the image is deployed to Kubernetes. | |
# Actions also run if the repository is tagged. | |
# Every tag is deployed to staging and every production-grade tag | |
# (of the form N.N.N) is deployed to production. | |
# --------------- | |
# Control secrets | |
# --------------- | |
# | |
# At the GitHub 'organisation' or 'project' level you are expected to | |
# have the following GitHub 'Repository Secrets' defined | |
# (i.e. via 'Settings -> Secrets'): - | |
# | |
# BE_IMAGE_TAG optional - default is a valid version | |
# BE_NAMESPACE optional - default xchem | |
# FE_IMAGE_TAG optional - default is a valid version | |
# FE_NAMESPACE optional - default xchem | |
# STACK_NAMESPACE optional - default xchem | |
# | |
# DOCKERHUB_USERNAME optional | |
# DOCKERHUB_TOKEN optional - required if DOCKERHUB_USERNAME | |
# | |
# TRIGGER_AWX optional - set to 'yes' to deploy 'official' builds via AWX | |
# you also need to define the repository environments | |
# 'awx/fragalysis-staging' and 'awx/fragalysis-production'. | |
# You should not set this and TRIGGER_DEVELOPER_AWX. | |
# TRIGGER_DEVELOPER_AWX optional - set to 'yes' to deploy a developer-specific build via AWX | |
# you also need to set the repository environment | |
# 'awx/fragalysis-developer'. | |
# You should not set this and TRIGGER_AWX. | |
# | |
# SLACK_NOTIFY_STAGING_WEBHOOK optional - required for Slack notifications | |
# SLACK_NOTIFY_PRODUCTION_WEBHOOK optional - required for Slack notifications | |
# | |
# ----------- | |
# Environment (GitHub Environments) | |
# ----------- | |
# | |
# Environment awx/fragalysis-staging | |
# Environment awx/fragalysis-production | |
# Environment awx/fragalysis-developer | |
# | |
# For automated deployment we expect the following in the environment: - | |
# | |
# AWX_HOST The fully-qualified URL to AWX. | |
# If not set, AWX triggering does not take place. | |
# AWX_USER The username of someone that can execute the AWX Job. | |
# AWX_USER_PASSWORD The user's password. | |
# AWX_TEMPLATE_NAME The template to run (for developer environments) | |
on: | |
push: | |
tags: | |
- '**' | |
# Build if triggered externally. | |
# The trigger can provide a number of (optional) inputs... | |
workflow_dispatch: | |
inputs: | |
be_namespace: | |
description: The fragalysis-backend namespace (to pull from) | |
required: false | |
be_image_tag: | |
description: The fragalysis-backend image container tag (to pull from) | |
required: false | |
fe_namespace: | |
description: The fragalysis-frontend namespace (to clone from) | |
required: false | |
fe_image_tag: | |
description: The fragalysis-frontend image container tag (to pull from) | |
required: false | |
stack_namespace: | |
description: The fragalysis-stack Docker Hub namespace (to publish to) | |
required: false | |
stack_image_tag: | |
description: The image tag to apply to the fragalysis-stack image | |
required: false | |
env: | |
# The following 'defaults' are used in the 'Initialise workflow variables' step, | |
# which creates 'outputs' for use in steps and jobs that follow it. | |
# The values set here are used unless a matching secret is found. | |
# Secrets are the way users dynamically control the behaviour of this Action. | |
# | |
# For Jobs conditional on the presence of a secret see this Gist... | |
# https://gist.github.com/jonico/24ffebee6d2fa2e679389fac8aef50a3 | |
# | |
# New (tagged) production stack builds should always be preceded by a change to one | |
# or both of the Backend or Frontend tags. i.e. before we make a production | |
# release the author needs to change one or both of: - | |
# | |
# - BE_IMAGE_TAG | |
# - FE_IMAGE_TAG | |
# | |
# | |
# Commit the changes and then tag or make a release from the stack repository. | |
BE_IMAGE_TAG: 2024.09.3 | |
FE_IMAGE_TAG: 2024.09.2 | |
BE_NAMESPACE: xchem | |
FE_NAMESPACE: xchem | |
STACK_NAMESPACE: xchem | |
jobs: | |
build: | |
runs-on: ubuntu-latest | |
outputs: | |
deploy: ${{ steps.vars.outputs.deploy }} | |
deploy_developer: ${{ steps.vars.outputs.deploy_developer }} | |
production_tag: ${{ steps.vars.outputs.production_tag }} | |
push: ${{ steps.vars.outputs.push }} | |
tag: ${{ steps.vars.outputs.tag }} | |
version: ${{ steps.vars.outputs.version }} | |
steps: | |
- name: Inject slug/short variables | |
uses: rlespinasse/github-slug-action@v4 | |
- name: Initialise workflow variables | |
id: vars | |
env: | |
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | |
TRIGGER_AWX: ${{ secrets.TRIGGER_AWX }} | |
TRIGGER_DEVELOPER_AWX: ${{ secrets.TRIGGER_DEVELOPER_AWX }} | |
run: | | |
# BE_NAMESPACE | |
BE_NAMESPACE="${{ env.BE_NAMESPACE }}" | |
if [ -n "${{ github.event.inputs.be_namespace }}" ]; then BE_NAMESPACE="${{ github.event.inputs.be_namespace }}"; | |
elif [ -n "${{ secrets.BE_NAMESPACE }}" ]; then BE_NAMESPACE="${{ secrets.BE_NAMESPACE }}"; fi | |
echo BE_NAMESPACE=${BE_NAMESPACE} | |
echo "BE_NAMESPACE=${BE_NAMESPACE}" >> $GITHUB_OUTPUT | |
# BE_IMAGE_TAG | |
BE_IMAGE_TAG="${{ env.BE_IMAGE_TAG }}" | |
if [ -n "${{ github.event.inputs.be_image_tag }}" ]; then BE_IMAGE_TAG="${{ github.event.inputs.be_image_tag }}"; | |
elif [ -n "${{ secrets.BE_IMAGE_TAG }}" ]; then BE_IMAGE_TAG="${{ secrets.BE_IMAGE_TAG }}"; fi | |
echo BE_IMAGE_TAG=${BE_IMAGE_TAG} | |
echo "BE_IMAGE_TAG=${BE_IMAGE_TAG}" >> $GITHUB_OUTPUT | |
# FE_NAMESPACE | |
FE_NAMESPACE="${{ env.FE_NAMESPACE }}" | |
if [ -n "${{ github.event.inputs.fe_namespace }}" ]; then FE_NAMESPACE="${{ github.event.inputs.fe_namespace }}"; | |
elif [ -n "${{ secrets.FE_NAMESPACE }}" ]; then FE_NAMESPACE="${{ secrets.FE_NAMESPACE }}"; fi | |
echo FE_NAMESPACE=${FE_NAMESPACE} | |
echo "FE_NAMESPACE=${FE_NAMESPACE}" >> $GITHUB_OUTPUT | |
# FE_IMAGE_TAG | |
FE_IMAGE_TAG="${{ env.FE_IMAGE_TAG }}" | |
if [ -n "${{ github.event.inputs.fe_image_tag }}" ]; then FE_IMAGE_TAG="${{ github.event.inputs.fe_image_tag }}"; | |
elif [ -n "${{ secrets.FE_IMAGE_TAG }}" ]; then FE_IMAGE_TAG="${{ secrets.FE_IMAGE_TAG }}"; fi | |
echo FE_IMAGE_TAG=${FE_IMAGE_TAG} | |
echo "FE_IMAGE_TAG=${FE_IMAGE_TAG}" >> $GITHUB_OUTPUT | |
# STACK_NAMESPACE | |
STACK_NAMESPACE="${{ env.STACK_NAMESPACE }}" | |
if [ -n "${{ github.event.inputs.stack_namespace }}" ]; then STACK_NAMESPACE="${{ github.event.inputs.stack_namespace }}"; | |
elif [ -n "${{ secrets.STACK_NAMESPACE }}" ]; then STACK_NAMESPACE="${{ secrets.STACK_NAMESPACE }}"; fi | |
echo STACK_NAMESPACE=${STACK_NAMESPACE} | |
echo "STACK_NAMESPACE=${STACK_NAMESPACE}" >> $GITHUB_OUTPUT | |
# Set a version | |
STACK_VERSION="0.0.0" | |
if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then STACK_VERSION="${{ env.GITHUB_REF_SLUG }}"; | |
else STACK_VERSION="${{ github.ref_name }}.${{ github.run_number }}"; fi | |
echo STACK_VERSION=${STACK_VERSION} | |
echo "STACK_VERSION=${STACK_VERSION}" >> $GITHUB_OUTPUT | |
# What image tag are we creating? 'latest' (if not tagged) or a GitHub tag? | |
TAG="latest" | |
if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then TAG="${{ env.GITHUB_REF_SLUG }}"; fi | |
echo tag=${TAG} | |
echo "tag=${TAG}" >> $GITHUB_OUTPUT | |
# Do we push, i.e. is DOCKERHUB_USERNAME defined? | |
echo push=${{ env.DOCKERHUB_USERNAME != '' }} | |
echo "push=${{ env.DOCKERHUB_USERNAME != '' }}" >> $GITHUB_OUTPUT | |
# Do we deploy official images, i.e. is TRIGGER_AWX 'yes'? | |
echo deploy=${{ env.TRIGGER_AWX == 'yes' }} | |
echo "deploy=${{ env.TRIGGER_AWX == 'yes' }}" >> $GITHUB_OUTPUT | |
# Do we deploy developer images, i.e. is TRIGGER_DEVELOPER_AWX 'yes'? | |
echo deploy_developer=${{ env.TRIGGER_DEVELOPER_AWX == 'yes' }} | |
echo "deploy_developer=${{ env.TRIGGER_DEVELOPER_AWX == 'yes' }}" >> $GITHUB_OUTPUT | |
# Do we deploy to production, i.e. is there a TAG of the form N.N.N? | |
HAS_PRODUCTION_TAG=false | |
if [[ ${{ env.GITHUB_REF_SLUG }} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then HAS_PRODUCTION_TAG=true; fi | |
echo production_tag=${HAS_PRODUCTION_TAG} | |
echo "production_tag=${HAS_PRODUCTION_TAG}" >> $GITHUB_OUTPUT | |
# Do we send Slack notifications, i.e. is SLACK_NOTIFY_WEBHOOK defined? | |
echo notify=${{ env.SLACK_NOTIFY_WEBHOOK != '' }} | |
echo "notify=${{ env.SLACK_NOTIFY_WEBHOOK != '' }}" >> $GITHUB_OUTPUT | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Display build args | |
run: | | |
echo BE_NAMESPACE=${{ steps.vars.outputs.BE_NAMESPACE }} | |
echo BE_IMAGE_TAG=${{ steps.vars.outputs.BE_IMAGE_TAG }} | |
echo FE_NAMESPACE=${{ steps.vars.outputs.FE_NAMESPACE }} | |
echo FE_IMAGE_TAG=${{ steps.vars.outputs.FE_IMAGE_TAG }} | |
echo STACK_NAMESPACE=${{ steps.vars.outputs.STACK_NAMESPACE }} | |
echo STACK_VERSION=${{ steps.vars.outputs.STACK_VERSION }} | |
- name: Build | |
uses: docker/build-push-action@v5 | |
with: | |
tags: ${{ steps.vars.outputs.STACK_NAMESPACE }}/fragalysis-stack:${{ steps.vars.outputs.tag }} | |
build-args: | | |
BE_NAMESPACE=${{ steps.vars.outputs.BE_NAMESPACE }} | |
BE_IMAGE_TAG=${{ steps.vars.outputs.BE_IMAGE_TAG }} | |
FE_NAMESPACE=${{ steps.vars.outputs.FE_NAMESPACE }} | |
FE_IMAGE_TAG=${{ steps.vars.outputs.FE_IMAGE_TAG }} | |
STACK_NAMESPACE=${{ steps.vars.outputs.STACK_NAMESPACE }} | |
STACK_VERSION=${{ steps.vars.outputs.tag }} | |
- name: Login to DockerHub | |
if: steps.vars.outputs.push == 'true' | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
- name: Push | |
if: steps.vars.outputs.push == 'true' | |
run: docker push ${{ steps.vars.outputs.STACK_NAMESPACE }}/fragalysis-stack:${{ steps.vars.outputs.tag }} | |
deploy-staging: | |
# A fixed job that deploys to the Fragalysis Staging Kubernetes Namespace | |
# using a pre-defined AWX Job Template name, | |
# and the awx/fragalysis-production environment. | |
# | |
# All builds, tagged or otherwise, are deployed to staging. | |
needs: build | |
if: | | |
needs.build.outputs.push == 'true' && | |
needs.build.outputs.deploy == 'true' | |
runs-on: ubuntu-latest | |
environment: awx/fragalysis-production | |
env: | |
slack_notify_staging_webhook: ${{ secrets.SLACK_NOTIFY_STAGING_WEBHOOK }} | |
steps: | |
- name: Notify staging deployment started | |
if: ${{ env.slack_notify_staging_webhook != '' }} | |
uses: rtCamp/action-slack-notify@v2 | |
env: | |
SLACK_WEBHOOK: ${{ env.slack_notify_staging_webhook }} | |
SLACK_TITLE: A new STAGING deployment has begun | |
SLACK_MESSAGE: Image tag is "${{ needs.build.outputs.tag }}" | |
SLACK_FOOTER: '' | |
MSG_MINIMAL: true | |
- name: Deploy staging | |
id: deploy_staging | |
uses: informaticsmatters/trigger-awx-action@v1 | |
with: | |
template: Staging Fragalysis Stack | |
template-host: ${{ secrets.AWX_HOST }} | |
template-user: ${{ secrets.AWX_USER }} | |
template-user-password: ${{ secrets.AWX_USER_PASSWORD }} | |
template-var: stack_image_tag | |
template-var-value: ${{ needs.build.outputs.tag }} | |
continue-on-error: true | |
- name: Notify staging deployment failure | |
if: ${{ env.slack_notify_staging_webhook != '' && steps.deploy_staging.outcome == 'failure' }} | |
uses: rtCamp/action-slack-notify@v2 | |
env: | |
SLACK_WEBHOOK: ${{ env.slack_notify_staging_webhook }} | |
SLACK_TITLE: The STAGING deployment FAILED | |
SLACK_MESSAGE: Please review the corresponding fragalysis-stack GitHuib Action Log | |
SLACK_FOOTER: '' | |
MSG_MINIMAL: true | |
- name: Notify staging deployment complete | |
if: ${{ env.slack_notify_staging_webhook != '' && steps.deploy_staging.outcome == 'success' }} | |
uses: rtCamp/action-slack-notify@v2 | |
env: | |
SLACK_WEBHOOK: ${{ env.slack_notify_staging_webhook }} | |
SLACK_TITLE: A new STAGING deployment is ready | |
SLACK_MESSAGE: Image tag is "${{ needs.build.outputs.tag }}" | |
SLACK_FOOTER: '' | |
MSG_MINIMAL: true | |
deploy-production: | |
# A fixed job that deploys to the Fragalysis Production Kubernetes Namespace | |
# using a pre-defined AWX Job Template name, | |
# and the awx/fragalysis-production environment. | |
# | |
# Only builds triggered by production-grade tags are deployed to production. | |
needs: build | |
if: | | |
needs.build.outputs.push == 'true' && | |
needs.build.outputs.deploy == 'true' && | |
needs.build.outputs.production_tag == 'true' | |
runs-on: ubuntu-latest | |
environment: awx/fragalysis-production | |
env: | |
slack_notify_production_webhook: ${{ secrets.SLACK_NOTIFY_PRODUCTION_WEBHOOK }} | |
steps: | |
- name: Notify production deployment started | |
if: ${{ env.slack_notify_production_webhook != '' }} | |
uses: rtCamp/action-slack-notify@v2 | |
env: | |
SLACK_WEBHOOK: ${{ env.slack_notify_production_webhook }} | |
SLACK_TITLE: A new PRODUCTION deployment has begun | |
SLACK_MESSAGE: Image tag is "${{ needs.build.outputs.tag }}" | |
SLACK_FOOTER: '' | |
MSG_MINIMAL: true | |
- name: Deploy production | |
id: deploy_production | |
uses: informaticsmatters/trigger-awx-action@v1 | |
with: | |
template: Production Fragalysis Stack | |
template-host: ${{ secrets.AWX_HOST }} | |
template-user: ${{ secrets.AWX_USER }} | |
template-user-password: ${{ secrets.AWX_USER_PASSWORD }} | |
template-var: stack_image_tag | |
template-var-value: ${{ needs.build.outputs.tag }} | |
continue-on-error: true | |
- name: Notify production deployment failure | |
if: ${{ env.slack_notify_production_webhook != '' && steps.deploy_production.outcome == 'failure' }} | |
uses: rtCamp/action-slack-notify@v2 | |
env: | |
SLACK_WEBHOOK: ${{ env.slack_notify_production_webhook }} | |
SLACK_TITLE: The PRODUCTION deployment FAILED | |
SLACK_MESSAGE: Please review the corresponding fragalysis-stack GitHuib Action Log | |
SLACK_FOOTER: '' | |
MSG_MINIMAL: true | |
- name: Notify production deployment complete | |
if: ${{ env.slack_notify_production_webhook != '' && steps.deploy_production.outcome == 'success'}} | |
uses: rtCamp/action-slack-notify@v2 | |
env: | |
SLACK_WEBHOOK: ${{ env.slack_notify_production_webhook }} | |
SLACK_TITLE: A new PRODUCTION deployment is ready | |
SLACK_MESSAGE: Image tag is "${{ needs.build.outputs.tag }}" | |
SLACK_FOOTER: '' | |
MSG_MINIMAL: true | |
deploy-developer: | |
# Deploys to a developer's Fragalysis Kubernetes Namespace | |
# using an environment-defined AWX Job Template name, | |
# and the awx/fragalysis-developer environment. | |
needs: build | |
if: | | |
needs.build.outputs.push == 'true' && | |
needs.build.outputs.deploy_developer == 'true' | |
runs-on: ubuntu-latest | |
environment: awx/fragalysis-developer | |
steps: | |
- name: Deploy developer | |
uses: informaticsmatters/trigger-awx-action@v1 | |
with: | |
template: ${{ secrets.AWX_TEMPLATE_NAME }} | |
template-host: ${{ secrets.AWX_HOST }} | |
template-user: ${{ secrets.AWX_USER }} | |
template-user-password: ${{ secrets.AWX_USER_PASSWORD }} | |
template-var: stack_image_tag | |
template-var-value: ${{ needs.build.outputs.tag }} |