Skip to content

build main

build main #947

Workflow file for this run

---
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 }}