Skip to content

Preview [PR 34 - cms/main_page/contact] #462

Preview [PR 34 - cms/main_page/contact]

Preview [PR 34 - cms/main_page/contact] #462

Workflow file for this run

# Workflow for building and deploying Hugo site (Production + Preview)
name: Deploy Hugo site - Production and Preview
run-name: ${{ github.event_name == 'pull_request' && format('Preview [PR {0} - {1}] {2} ', github.event.pull_request.number, github.head_ref, github.event.head_commit.message) || format('[{0}] {1}', github.ref_name, github.event.head_commit.message) }}
on:
# Only push to default branch — avoids double trigger when pushing to a PR branch (push + pull_request synchronize)
push:
branches: [main]
# Runs on pull requests for Deploy Preview Links (one run per commit on a PR)
pull_request:
types: [opened, synchronize, reopened, closed]
# Allows you to run this workflow manually from the Actions tab (choice input with options)
workflow_dispatch:
inputs:
nomad_job_template:
required: false
description: The Nomad job template to use for the deployment.
type: choice
options:
- nomad/template.nomad
- nomad/decap.template.nomad
default: nomad/template.nomad
use_decap:
required: false
description: Override Decap usage. Set to "true" or "false" to override branch-based determination; leave as "auto" for automatic.
type: choice
options:
- auto
- "true"
- "false"
default: auto
workflow_call: # allows reusing the workflow (string input; choice not supported for workflow_call)
# inputs:
# nomad_job_template:
# required: false
# description: The Nomad job template to use for the deployment (e.g. nomad/template.nomad or nomad/decap.template.nomad).
# type: string
# default: nomad/template.nomad
# use_decap:
# required: false
# description: Override USE_DECAP ("true" or "false"); leave empty for branch-based determination.
# type: string
# default: ""
# target:
# required: false
# type: string
# secrets:
# token:
# required: false
# env:
# CONTAINER_PROJECT: "coastal-science.github.io" # "rcg-containers" # repo name dynamically extracted from `github.repository` by removing `github.owner`
# Allow one concurrent deployment
concurrency:
group: ${{ github.repository }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('branch-{0}', github.ref_name) }}
cancel-in-progress: true
jobs:
generate-timestamp:
permissions: {}
runs-on: ubuntu-latest
steps:
- name: Set TIMESTAMP and get REPO_NAME
id: date
run: |
export DATE=$(date +'%Y%m%d-%H%M%S')
REPO_NAME=${GITHUB_REPOSITORY#$GITHUB_REPOSITORY_OWNER/}
echo "TIMESTAMP=$DATE" >> $GITHUB_ENV
echo "REPO_NAME=$REPO_NAME" >> $GITHUB_ENV
outputs:
TIMESTAMP: ${{ env.TIMESTAMP }}
REPO_NAME: ${{ env.REPO_NAME }}
######################################################
## Build and publish a staging site to GitHub Pages ##
######################################################
configure-pages:
runs-on: ubuntu-latest
permissions: # read-all
contents: read
pages: read
steps:
- name: Setup Pages
id: pages
uses: actions/configure-pages@v2
outputs:
base_url: ${{ steps.pages.outputs.base_url }}
# Build job
build-website:
needs:
- generate-timestamp
- configure-pages
runs-on: ubuntu-latest
container:
image: peaceiris/hugo
env:
HUGO_VERSION: "${{ vars.HUGO_VERSION }}" # 0.147.8 # latest # 0.126.1
HUGO_FORMS: ${{ vars.HUGO_FORMS }}
HUGO_GOOGLEANALYTICS: ${{ vars.HUGO_GOOGLEANALYTICS }}
REPO_NAME: ${{ needs.generate-timestamp.outputs.REPO_NAME }}
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
steps:
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: ${{ vars.HUGO_VERSION }}
extended: true
- name: Pre-Build ls
run: |
ls -lah
echo "${{ needs.generate-timestamp.outputs.TIMESTAMP }}" from env
echo "${{ needs.configure-pages.outputs.base_url }}/" from env
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true # Fetch Hugo themes (true OR recursive) # failing on ubuntu container
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
# set-safe-directory: '/__w/coastal-science.github.io/coastal-science.github.io' # The process '/usr/bin/git' failed with exit code 128
# set-safe-directory: '/__w/${{ env.REPO_NAME }}/${{ env.REPO_NAME }}' # The process '/usr/bin/git' failed with exit code 128, resorting to manual call
- name: Set safe directory workaround
run: |
git config --global --add safe.directory /__w/${{ env.REPO_NAME }}/${{ env.REPO_NAME }}
- name: Build with Hugo
env:
# For maximum backward compatibility with Hugo modules
HUGO_ENVIRONMENT: staging
HUGO_ENV: staging
run: |
hugo \
--gc \
--buildDrafts \
--minify \
--baseURL "${{ needs.configure-pages.outputs.base_url }}/"
- name: Post-Build ls
run: ls -lah public/
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
# Deployment job
deploy-gh-pages:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: write
id-token: write
pages: write
runs-on: ubuntu-latest
needs: build-website
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
############################################
## Create and publish docker image ##
## (handles both production and preview) ##
############################################
build-website-and-container-build:
environment: docker-image
# if: github.ref == 'refs/heads/main'
# Skip build if PR is closed (cleanup job handles that)
if: github.event_name != 'pull_request' || github.event.action != 'closed'
needs:
- generate-timestamp
env:
HUGO_VERSION: ${{ vars.HUGO_VERSION }} # 0.147.8 # latest # 0.126.1
HUGO_FORMS: ${{ vars.HUGO_FORMS }}
HUGO_GOOGLEANALYTICS: ${{ vars.HUGO_GOOGLEANALYTICS }}
REGISTRY: ghcr.io # docker.github.sfu.ca
IMAGE_NAME: ${{ github.repository }}
REPO_NAME: ${{ needs.generate-timestamp.outputs.REPO_NAME }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
outputs:
tags: ${{ steps.meta.outputs.tags }}
commit_sha: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
pr_number: ${{ github.event.pull_request.number || '' }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true # Fetch Hugo themes (true OR recursive) # failing on ubuntu container
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
# set-safe-directory: '/__w/coastal-science.github.io/coastal-science.github.io'
# set-safe-directory: '/__w/${{ env.REPO_NAME }}/${{ env.REPO_NAME }}' # The process '/usr/bin/git' failed with exit code 128, resorting to manual call
- name: Set safe directory workaround
run: |
git config --global --add safe.directory /__w/${{ env.REPO_NAME }}/${{ env.REPO_NAME }}
- name: Generate tags
id: tags
run: |
# Get the current branch name
branch_name=$(git rev-parse --abbrev-ref HEAD)
# docker tag limit is 128 characters
# The timestamp (YYYY_MM_DD_HH_MM_SS), commit id (7),
# and punctuation (additional _) take up 29 characters.
# For 3 catalogs the branch names is can occupy the
# remaining characters = floor((128-29*3)/3) = 13
branch_name=${branch_name:0:13}
# Get the abbreviated commit hash
commit_hash=$(git rev-parse --short HEAD)
# Get the current commit datetime (without timezone)
commit_date=$(git show -s --format=%ci HEAD)
# remove last five characters (timezone information)
commit_date=${commit_date:0:${#commit_date}-5} #-5 digits causes 'expression < 0' error. Instead dynamically get the string length.
# Get the current commit datetime (without timezone)
commit_date=$(git show -s --date=format:'%Y%m%d-%H%M' --format=%cd HEAD)
# Combine the parts into the desired format
result="${branch_name}_${commit_hash}_${commit_date}"
# remove leading/trailing spaces
# formatted_result=$(awk '{$1=$1;print}')
formatted_result=$(echo $result | xargs)
# Replace spaces, colons, and dashes with underscores
formatted_result=$(echo "$formatted_result" | sed 's/[ :\-]/_/g')
#branch_name=$(echo $branch_name | xargs)
#branch_name=$(echo "$branch_name" | sed 's/[ :\-]/_/g')
commit_hash=$(echo $commit_hash | xargs)
commit_hash=$(echo "$commit_hash" | sed 's/[ :\-]/_/g')
commit_date=$(echo $commit_date | xargs)
#commit_date=$(echo "$commit_date" | sed 's/[ :\-]/_/g')
# Print the final result and return it
echo "$formatted_result"
#echo "branch_name=${branch_name}" >> "$GITHUB_OUTPUT"
echo "commit_hash=${commit_hash}" >> "$GITHUB_OUTPUT"
echo "commit_date=${commit_date}" >> "$GITHUB_OUTPUT"
- name: List repos in workspace
run: |
ls -lah
du -sh *
echo The current workspace repo is..
pwd
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: ${{ vars.HUGO_VERSION }}
extended: true
- name: Build and Minify with Hugo
env:
# For maximum backward compatibility with Hugo modules
HUGO_ENVIRONMENT: ${{ github.event_name == 'pull_request' && 'preview' || 'production' }}
HUGO_ENV: ${{ github.event_name == 'pull_request' && 'preview' || 'production' }}
run: |
hugo \
--gc \
--minify \
--baseURL "${{ env.HUGO_BASEURL }}/"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@v3 #343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5 #96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # /${{ env.SERVICE }}
labels: |
org.opencontainers.image.version=${{ needs.generate-timestamp.outputs.TIMESTAMP }}
tags: |
# branch event
type=ref,event=branch
# pull request event
type=ref,event=pr,format=pr-{{number}}
# minimal (short sha)
type=sha
# pull request sha with prefix
type=sha,prefix=pr-
# commit date tag (for branches only)
type=raw,value=${{ steps.tags.outputs.commit_date }}
# latest tag (for branches only)
type=raw,value=latest
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
env:
HUGO_BASEURL: "${{ vars.HUGO_BASEURL }}"
with:
context: .
file: Dockerfile.prod
build-contexts: |
public=./public
nginx=./nginx
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
push: true
# - name: Build website with Dockerfile.prod
# env:
# HUGO_BASEURL: "${{ vars.HUGO_BASEURL }}"
# ORIGINS: "${{ vars.ORIGINS }}"
# OAUTH_CLIENT_ID: "${{ vars.OAUTH_GITHUB_CLIENT_ID }}"
# OAUTH_GITHUB_CLIENT_SECRET: "${{ secrets.OAUTH_GITHUB_CLIENT_SECRET }}"
# CMS_BACKEND_DEBUG: ${{ vars.CMS_BACKEND_DEBUG || ''}}
# run: |
# echo "${{ steps.meta.outputs.labels }}"
# prefix="--label "
# LABELS=$(sed "s/^/$prefix/" <<< "${{ steps.meta.outputs.labels }}")
# echo $LABELS
# echo "${{ steps.meta.outputs.tags }}"
# docker compose -f docker-compose.yaml -f docker-compose.override.yaml build website
# docker tag website ${{ steps.meta.outputs.tags }}
# # docker tag website ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tags.outputs.branch_name }}
# docker tag website ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tags.outputs.commit_hash }}
# docker tag website ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tags.outputs.commit_date }}
# docker tag website ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# docker push --all-tags ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Deploy docker image to orchestrator (handles both production and preview)
deploy-service:
# Skip deployment if PR is closed (cleanup job handles that)
if: github.event_name != 'pull_request' || github.event.action != 'closed'
# if: false
# if: github.ref == 'refs/heads/main'
needs:
- generate-timestamp
- build-website-and-container-build
permissions:
contents: read
packages: read
statuses: write
environment:
name: docker-image
# url: https://${{ vars.HUGO_BASEURL }}
url: ${{ steps.set-env.outputs.nomad_url }}
# url: https://${{ vars.__SERVICE__ }}-${{ env.ENVIRONMENT == 'production' && 'latest' || 'dev' }}.ruthjoy.researchcomputinggroup.ca
runs-on: ubuntu-latest
# runs-on: [ self-hosted, rcg ]
# container:
# image: alpine:3.18
env:
NOMAD_VERSION: ${{ vars.NOMAD_VERSION || '1.11.1' }}
REPO_NAME: ${{ needs.generate-timestamp.outputs.REPO_NAME }}
SERVICE: "${{ vars.__SERVICE__ }}"
JOB_DRIVER: "${{ vars.__JOB_DRIVER__ }}"
__REGISTRY__: ghcr.io # docker.github.sfu.ca
# CONTAINER_PROJECT: "coastal-science.github.io" # "rcg-containers" # repo name dynamically extracted from `github.resposity` by removing `github.owner`
CONTAINER_PROJECT: ${{ needs.generate-timestamp.outputs.REPO_NAME }}
# __IMAGE_NAME__="${{ secrets.REGISTRY_SERVER }}/${{ env.CONTAINER_PROJECT }}/${{ env.SERVICE }}"
IMAGE_NAME: ${{ vars.__REGISTRY__ }}/${{ github.repository }}
FORCE_PULL: ${{ vars.__IMAGE_FORCE_PULL__ }}
#__DATACENTERS__="${{ secrets.NOMAD_SERVER_DATACENTERS }}" \
# __NAMESPACE__="${{ secrets.NOMAD_SERVER_NAMESPACE }}" \
NOMAD_SERVER_DATACENTERS: "${{ vars.__DATACENTERS__ }}"
NOMAD_SERVER_NAMESPACE: "${{ vars.__NAMESPACE__ }}"
__REGISTRY_USERNAME__: "${{ github.actor }}"
__REGISTRY_PASSWORD__: "${{ secrets.GITHUB_TOKEN }}"
__RESEARCHER__: "${{ secrets.__RESEARCHER__ }}"
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
PR_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
outputs:
url: ${{ steps.set-env.outputs.nomad_url }}
nomad_url_1: ${{ steps.set-env.outputs.nomad_url }}
environment_suffix: ${{ steps.set-env.outputs.environment_suffix }}
environment: ${{ steps.set-env.outputs.environment }}
job_name: ${{ steps.setup-nomad.outputs.job_name }}
steps:
- name: Determine environment and suffix
id: set-env
run: |
# TODO: Option (based on needs) to deploy to nomad url with ENVIRONMENT_SUFFIX=commit_sha (if not a PR)
# GITHUB_SHA_SHORT="${{ github.sha }}".SubString(0, 8))"
GITHUB_SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
ENVIRONMENT="production" # TODO: suspicion that the variable is unused and can be removed
ENVIRONMENT_SUFFIX="prod"
NOMAD_JOB_TEMPLATE=nomad/decap.template.nomad
NOMAD_FILE="${{ vars.__SERVICE__ }}.nomad"
IMAGE_TAG="main" # branch name of production main branch
else
ENVIRONMENT="development"
ENVIRONMENT_SUFFIX="dev" # default suffix for development environment. Overridden by PR number for PRs.
NOMAD_JOB_TEMPLATE=nomad/template.nomad
NOMAD_FILE="${{ vars.__SERVICE__ }}.nomad"
fi
# Update from input when it exists and is different from branch-based value
if [ -n "${{ inputs.nomad_job_template }}" ] && [ "${{ inputs.nomad_job_template }}" != "${NOMAD_JOB_TEMPLATE}" ]; then
echo "::notice title=Nomad template updated::nomad_job_template was '${NOMAD_JOB_TEMPLATE}' (branch-based), updated to '${{ inputs.nomad_job_template }}' (input)."
NOMAD_JOB_TEMPLATE="${{ inputs.nomad_job_template }}"
fi
echo NOMAD_FILE=${NOMAD_FILE}
# Extract branch name from refs/heads/branch-name, fallback to commit SHA
# GITHUB_REF is automatically set by GitHub Actions (e.g., refs/heads/branch-name)
# GITHUB_SHA is automatically set by GitHub Actions (full commit SHA)
BRANCH_NAME="$GITHUB_REF_NAME"
PR_NUMBER="${{ github.event.pull_request.number }}"
# If GITHUB_REF_NAME matches '<pr_number>/merge', extract just the branch name for BRANCH_NAME.
# Otherwise, use GITHUB_REF_NAME as-is.
# GITHUB_REF_NAME format for PRs: "<pr_number>/merge"
if [[ "${GITHUB_REF_NAME}" =~ ^[0-9]+/merge$ ]]; then
# For PRs, get the source branch name from github.head_ref if available
if [ -n "${{ github.head_ref }}" ]; then
BRANCH_NAME="${{ github.head_ref }}"
IMAGE_TAG="pr-${PR_NUMBER}"
ENVIRONMENT_SUFFIX="pr-${PR_NUMBER}-${GITHUB_SHORT_SHA}"
echo "::notice title=PR environment suffix::pr-${PR_NUMBER}-${GITHUB_SHORT_SHA}"
fi
else
if [ -n "${GITHUB_REF_NAME}" ]; then
IMAGE_TAG="${GITHUB_REF_NAME}"
else
IMAGE_TAG="${GITHUB_SHORT_SHA}"
fi
fi
echo ENVIRONMENT=${ENVIRONMENT}, \
ENVIRONMENT_SUFFIX=${ENVIRONMENT_SUFFIX}, \
BRANCH_NAME=${BRANCH_NAME}, \
GITHUB_REF=${GITHUB_REF}, \
GITHUB_REF_NAME=${GITHUB_REF_NAME}, \
github.head_ref=${{ github.head_ref }}, \
PR_NUMBER=${PR_NUMBER}, \
IMAGE_TAG=${IMAGE_TAG}, \
NOMAD_JOB_TEMPLATE=${NOMAD_JOB_TEMPLATE}, \
NOMAD_FILE=${NOMAD_FILE}
# Construct URL from Nomad template pattern: ${__SERVICE__}-${__ENVIRONMENT__}.${__RESEARCHER__}.researchcomputinggroup.ca
NOMAD_URL="https://${{ vars.__SERVICE__ }}-${ENVIRONMENT_SUFFIX}.${{ secrets.__RESEARCHER__ }}.researchcomputinggroup.ca"
# Determine WEB_URL based on event type
# WEB_URL="${{ github.ref == 'refs/heads/main' && secrets.__DOMAIN_NAME__ || 'sinkhole' }}"
# Determine WEB_URL and PREVIEW_URL based on event type
# Using shell logic below instead of GitHub expressions to avoid parsing issues
WEB_URL="sinkhole.${__RESEARCHER__}.researchcomputinggroup.ca"
# PREVIEW_URL="" # TODO: (remove) PREVIEW_URL was used for PRs, but now we use NOMAD_URL
# if [ "${{ github.event_name }}" = "pull_request" ]; then
# # For PRs
# PREVIEW_URL="${NOMAD_URL}"
# fi
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
# For production main branch
WEB_URL="${{ secrets.__DOMAIN_NAME__ }}"
fi
echo "environment=${ENVIRONMENT}" >> $GITHUB_OUTPUT
echo "environment_suffix=${ENVIRONMENT_SUFFIX}" >> $GITHUB_OUTPUT
echo "nomad_url=${NOMAD_URL}" >> $GITHUB_OUTPUT
echo "web_url=${WEB_URL}" >> $GITHUB_OUTPUT
echo "nomad_job_template=${NOMAD_JOB_TEMPLATE}" >> $GITHUB_OUTPUT
echo "nomad_file=${NOMAD_FILE}" >> $GITHUB_OUTPUT
echo "preview_url=${PREVIEW_URL}" >> $GITHUB_OUTPUT
echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT
echo "Determined environment: ${ENVIRONMENT}, suffix: ${ENVIRONMENT_SUFFIX}, image_tag: ${IMAGE_TAG}"
- name: Prepare Environment. Setup `nomad` CLI.
id: setup-nomad-cli
uses: hashicorp/setup-nomad@v1.0.0
with:
version: ${{ env.NOMAD_VERSION}} # Specify the desired version, or "latest"
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true # Fetch Hugo themes (true OR recursive) # failing on ubuntu container
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
# set-safe-directory: '/__w/coastal-science.github.io/coastal-science.github.io' # The process '/usr/bin/git' failed with exit code 128
# set-safe-directory: '${{ env.REPO_NAME }}/${{ env.REPO_NAME }}' # The process '/usr/bin/git' failed with exit code 128, resorting to manual call
- name: Set safe directory workaround
run: |
git config --global --add safe.directory /__w/${{ env.REPO_NAME }}/${{ env.REPO_NAME }}
- name: Test Nomad
run: NOMAD_TOKEN=${{ secrets.NOMAD_SERVER_TOKEN }} NOMAD_ADDR=${{ secrets.NOMAD_SERVER_ADDRESS }} nomad status
- name: Setup Nomad Job
id: setup-nomad
env:
ENVIRONMENT_SUFFIX: ${{ steps.set-env.outputs.environment_suffix }}
ENVIRONMENT: ${{ steps.set-env.outputs.environment }}
WEB_URL: ${{ steps.set-env.outputs.web_url }}
NOMAD_JOB_TEMPLATE: ${{ steps.set-env.outputs.nomad_job_template }}
NOMAD_FILE: ${{ steps.set-env.outputs.nomad_file }}
IMAGE_TAG: ${{ steps.set-env.outputs.image_tag }}
run: |
# Use ENVIRONMENT_SUFFIX consistently for both PRs and branches
JOB_NAME="${{ env.SERVICE }}-${ENVIRONMENT_SUFFIX}"
# NOMAD_JOB_TEMPLATE="nomad/template.nomad"
NOMAD_JOB_TEMPLATE="${NOMAD_JOB_TEMPLATE}"
NOMAD_OUTPUT_FILE="${NOMAD_FILE}"
export __SERVICE__="${{ env.SERVICE }}"
export __JOB_DRIVER__="${{ env.JOB_DRIVER }}"
export __ENVIRONMENT__="${ENVIRONMENT_SUFFIX}"
export __WEB_URL__="${WEB_URL}"
export __JOB_NAME__="${JOB_NAME}"
export __IMAGE_NAME__="${{ env.IMAGE_NAME }}"
export __IMAGE_TAG__="${IMAGE_TAG}"
export __IMAGE_FORCE_PULL__="${{ env.FORCE_PULL || 'false' }}"
export __DATACENTERS__="${{ env.NOMAD_SERVER_DATACENTERS }}"
export __NAMESPACE__="${{ env.NOMAD_SERVER_NAMESPACE }}"
export __RESEARCHER__="${{ env.__RESEARCHER__ }}"
export __REGISTRY_USERNAME__="${{ env.__REGISTRY_USERNAME__ }}"
export __REGISTRY_PASSWORD__="${{ env.__REGISTRY_PASSWORD__ }}"
# USE_DECAP: workflow input overrides branch-based determination when set
USE_DECAP_INPUT="${{ inputs.use_decap }}"
if [ -n "${USE_DECAP_INPUT}" ] && [ "${USE_DECAP_INPUT}" != "auto" ]; then
USE_DECAP_INPUT=$(echo "${USE_DECAP_INPUT}" | tr '[:upper:]' '[:lower:]')
case "${USE_DECAP_INPUT}" in
true | yes)
export __USE_DECAP__="true"
echo "::notice title=USE_DECAP override::use_decap input set to 'true' (overrides environment/branch-based auto determination)."
;;
false | no)
export __USE_DECAP__="false"
echo "::notice title=USE_DECAP override::use_decap input set to 'false' (overrides environment/branch-based auto determination)."
;;
*) echo "::warning title=Invalid use_decap::Ignoring use_decap='${USE_DECAP_INPUT}'; using environment/branch-based value." ;;
esac
fi
if [ -z "${__USE_DECAP__:-}" ]; then
env_lower=$(echo "${ENVIRONMENT}" | tr '[:upper:]' '[:lower:]')
export __USE_DECAP__="$([ "$env_lower" = "main" ] || [ "$env_lower" = "prod" ] || [ "$env_lower" = "production" ] && echo 'true' || echo 'false')"
fi
export __DECAP_IMAGE_NAME__="itsmejoeeey/docker-decap-cms-standalone"
export __DECAP_IMAGE_TAG__="latest"
export __CMS_BACKEND_DEBUG__="${{ vars.CMS_BACKEND_DEBUG || 0 }}"
export __ORIGINS__="${{ vars.ORIGINS }}"
export __OAUTH_CLIENT_ID__="${{ vars.OAUTH_GITHUB_CLIENT_ID }}"
export __OAUTH_CLIENT_SECRET__="${{ secrets.OAUTH_GITHUB_CLIENT_SECRET }}"
# Substitute variables in template
echo "Extracting __*__ variables from template: $NOMAD_JOB_TEMPLATE"
echo "Output file: $NOMAD_OUTPUT_FILE"
# GNU gettext envsubst format: '${VAR1} ${VAR2} ${VAR3}'
# Extract all ${__*__} patterns, get unique variable names (with __ prefix/suffix)
# envsubst only replaces variables in the format string; others (e.g. ${meta.role}, ${node.unique.name}, ${NOMAD_ADDR_http}) are left unchanged.
SHELL_FORMAT_STRING=$(grep -oE '\$\{__[A-Z_]+__\}' "$NOMAD_JOB_TEMPLATE" | sort -u | awk '{printf "%s ", $1}')
if [ -z "$SHELL_FORMAT_STRING" ]; then
echo "Warning: No __*__ variables found in template"
fi
echo "Substituting variables: $SHELL_FORMAT_STRING"
envsubst "$SHELL_FORMAT_STRING" < "$NOMAD_JOB_TEMPLATE" > "$NOMAD_OUTPUT_FILE"
echo "===== Rendered Nomad job ====="
cat "$NOMAD_OUTPUT_FILE"
echo "===== Validating substituted variables and rendered Nomad job ====="
# Extract all remaining __*__ variables after envsubst and report if any non-substituted variables remain
REMAINING_SUBSTITUTIONS=$(grep -oE '\$\{__[A-Z_]+__\}' "$NOMAD_OUTPUT_FILE" | sort -u)
if [ -n "$REMAINING_SUBSTITUTIONS" ]; then
echo "Warning: The following variable substitutions were NOT completed in $NOMAD_OUTPUT_FILE:"
echo "$REMAINING_SUBSTITUTIONS"
exit 1
else
echo "All __*__ variables were successfully substituted in $NOMAD_OUTPUT_FILE."
fi
NOMAD_TOKEN=${{ secrets.NOMAD_SERVER_TOKEN }} NOMAD_ADDR=${{ secrets.NOMAD_SERVER_ADDRESS }} \
nomad job validate "$NOMAD_OUTPUT_FILE" || {
echo "===== Nomad job file ====="
cat "$NOMAD_OUTPUT_FILE"
exit 1
}
echo "nomad_file=${NOMAD_OUTPUT_FILE}" >> $GITHUB_OUTPUT
echo "job_name=${JOB_NAME}" >> $GITHUB_OUTPUT
- name: Deploy TIMESTAMPED Website To Nomad
# if: github.event_name != 'pull_request'
id: deploy
env:
JOB_NAME: ${{ steps.setup-nomad.outputs.job_name }}
NOMAD_FILE: ${{ steps.setup-nomad.outputs.nomad_file }}
run: |
nomad version
NOMAD_TOKEN=${{ secrets.NOMAD_SERVER_TOKEN }} NOMAD_ADDR=${{ secrets.NOMAD_SERVER_ADDRESS }} \
nomad job stop -verbose ${JOB_NAME} || true
echo "Nomad job stop result=$?"
sleep 10s
echo "Submitting job from: ${NOMAD_FILE}"
NOMAD_TOKEN=${{ secrets.NOMAD_SERVER_TOKEN }} NOMAD_ADDR=${{ secrets.NOMAD_SERVER_ADDRESS }} \
nomad job run -verbose "${NOMAD_FILE}"
DEPLOY_RESULT=$?
echo "Nomad job deploy result=${DEPLOY_RESULT}"
echo "deploy_success=$([ ${DEPLOY_RESULT} -eq 0 ] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
- name: Create GitHub commit status for deployment
if: github.event_name == 'pull_request'
run: |
STATUS_URL="https://api.github.com/repos/${{ github.repository }}/statuses/${{ env.PR_SHA }}"
# Determine status parameters based on deployment result
if [ "${{ steps.deploy.outputs.deploy_success }}" = "true" ]; then
STATE="success"
TARGET_URL="${{ steps.set-env.outputs.nomad_url }}"
DESCRIPTION="Preview deployment ready"
else
STATE="failure"
TARGET_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
DESCRIPTION="Preview deployment failed"
fi
curl -X POST "${STATUS_URL}" \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
-d "{
\"state\": \"${STATE}\",
\"target_url\": \"${TARGET_URL}\",
\"description\": \"${DESCRIPTION}\",
\"context\": \"deploy/preview\"
}"
echo "Created commit status: deploy/preview -> ${STATE} (${TARGET_URL})"
- name: Summary output URLs
run: |
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo https://"${{ secrets.__DOMAIN_NAME__ }}" >> "$GITHUB_STEP_SUMMARY"
echo "${{ steps.set-env.outputs.nomad_url }}" >> "$GITHUB_STEP_SUMMARY"
else
echo "${{ steps.set-env.outputs.nomad_url }}" >> "$GITHUB_STEP_SUMMARY"
fi
# Cleanup PR Nomad jobs after deploy: (1) synchronize → stop previous PR job(s) for this PR; (2) push main → stop merged PR's job. Both need deploy-service. Conditionals on steps.
cleanup-pr-after-deploy:
if: (github.event_name == 'pull_request' && github.event.action == 'synchronize') || (github.event_name == 'push' && github.ref == 'refs/heads/main')
needs:
- deploy-service
permissions:
contents: read
packages: read
environment:
name: docker-image
runs-on: ubuntu-latest
env:
NOMAD_VERSION: ${{ vars.NOMAD_VERSION || '1.11.1' }}
SERVICE: "${{ vars.__SERVICE__ }}"
steps:
- name: Checkout repository (required for local action)
uses: actions/checkout@v4
- name: Prepare Environment. Setup `nomad` CLI
uses: hashicorp/setup-nomad@v1.0.0
with:
version: ${{ env.NOMAD_VERSION }}
# --- synchronize: stop previous PR job(s) for this PR (keep current) ---
- name: 1. Stop and purge previous PR job(s) for this PR
if: github.event_name == 'pull_request' && github.event.action == 'synchronize'
env:
NOMAD_TOKEN: ${{ secrets.NOMAD_SERVER_TOKEN }}
NOMAD_ADDR: ${{ secrets.NOMAD_SERVER_ADDRESS }}
CURRENT_JOB: ${{ needs.deploy-service.outputs.job_name }}
PREFIX: ${{ env.SERVICE }}-pr-${{ github.event.pull_request.number }}-
run: |
echo "Current job (keep): ${CURRENT_JOB}"
echo "Looking for other jobs with prefix: ${PREFIX}"
# List all jobs and filter by prefix in the first column; skip header row.
JOBS=$(NOMAD_TOKEN="${NOMAD_TOKEN}" NOMAD_ADDR="${NOMAD_ADDR}" nomad job status 2>/dev/null \
| awk -v p="${PREFIX}" 'NR>1 && index($1, p) == 1 {print $1}' || true)
# Each job ID is on its own line; count non-empty lines for total.
TOTAL=$(printf '%s\n' "${JOBS}" | sed '/^$/d' | wc -l | tr -d ' ')
echo "Found ${TOTAL} matching job(s):"
echo "${JOBS}"
CLEANED=0
for job in ${JOBS}; do
[ -z "${job}" ] && continue
if [ "${job}" != "${CURRENT_JOB}" ]; then
echo "Stopping and purging previous PR job: ${job}"
NOMAD_TOKEN="${NOMAD_TOKEN}" NOMAD_ADDR="${NOMAD_ADDR}" nomad job stop -purge -verbose "${job}" || true
CLEANED=$((CLEANED + 1))
fi
done
if [ "${CLEANED}" -eq 0 ]; then
echo "No previous PR jobs to clean up."
else
echo "Cleaned up ${CLEANED} previous PR job(s)."
fi
# --- push main: stop merged PR's job (from GitHub API by commit SHA, not message) ---
- name: Get merged PR number from commit (GitHub API)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
id: pr
env:
GH_TOKEN: ${{ github.token }}
run: |
# On a push event (e.g. merge to main), github.event.pull_request isn’t set, so we get the merged PR number from the commits API (GET .../commits/{sha}/pulls) using github.sha instead of the event payload.
# GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls returns PRs associated with this commit.
# Works for merge commits and custom merge messages; does not depend on message template.
PAYLOAD=$(gh api "repos/${{ github.repository }}/commits/${{ github.sha }}/pulls" --jq '.[0] // empty' 2>/dev/null || true)
PR_NUM=$(echo "$PAYLOAD" | jq -r '.number // empty' 2>/dev/null)
HEAD_SHA=$(echo "$PAYLOAD" | jq -r '.head.sha // empty' 2>/dev/null)
if [ -n "${PR_NUM}" ]; then
echo "pr_number=${PR_NUM}" >> $GITHUB_OUTPUT
echo "head_sha=${HEAD_SHA}" >> $GITHUB_OUTPUT
echo "Found merged PR #${PR_NUM} head_sha=${HEAD_SHA} (from API)"
else
echo "pr_number=" >> $GITHUB_OUTPUT
echo "head_sha=" >> $GITHUB_OUTPUT
echo "No PR associated with commit ${{ github.sha }} (e.g. direct push to main)"
fi
- name: Determine Nomad job name (SERVICE-pr-N-SHORT_SHA)
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.pr.outputs.pr_number != ''
id: job-name-merged
run: |
PR_NUM="${{ steps.pr.outputs.pr_number }}"
SHORT_SHA=$(echo "${{ steps.pr.outputs.head_sha }}" | cut -c1-7)
echo "job_name=${{ env.SERVICE }}-pr-${PR_NUM}-${SHORT_SHA}" >> $GITHUB_OUTPUT
echo "Nomad job name: ${{ env.SERVICE }}-pr-${PR_NUM}-${SHORT_SHA}"
- name: 2. Cleanup merged PR Nomad job when push to main
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.pr.outputs.pr_number != ''
uses: ./.github/actions/cleanup-pr-nomad-job
with:
job_name: ${{ steps.job-name-merged.outputs.job_name }}
nomad_version: ${{ env.NOMAD_VERSION }}
nomad_token: ${{ secrets.NOMAD_SERVER_TOKEN }}
nomad_addr: ${{ secrets.NOMAD_SERVER_ADDRESS }}
# Cleanup Nomad deployment when PR is closed (without merge). When merged, cleanup runs in cleanup-pr-after-deploy. Job name = SERVICE-pr-N-SHORT_SHA.
cleanup-pr-deployment:
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == false
permissions:
contents: read
packages: read
environment:
name: docker-image
runs-on: ubuntu-latest
env:
NOMAD_VERSION: ${{ vars.NOMAD_VERSION || '1.11.1' }}
SERVICE: "${{ vars.__SERVICE__ }}"
steps:
- name: Checkout repository (required for local action)
uses: actions/checkout@v4
- name: Determine Nomad job name (SERVICE-pr-N-SHORT_SHA)
id: job-name
run: |
PR_NUM="${{ github.event.pull_request.number }}"
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
echo "job_name=${{ env.SERVICE }}-pr-${PR_NUM}-${SHORT_SHA}" >> $GITHUB_OUTPUT
echo "Nomad job name: ${{ env.SERVICE }}-pr-${PR_NUM}-${SHORT_SHA}"
- name: 3. Cleanup PR Nomad job when PR is closed (without merge)
uses: ./.github/actions/cleanup-pr-nomad-job
with:
job_name: ${{ steps.job-name.outputs.job_name }}
nomad_version: ${{ env.NOMAD_VERSION }}
nomad_token: ${{ secrets.NOMAD_SERVER_TOKEN }}
nomad_addr: ${{ secrets.NOMAD_SERVER_ADDRESS }}
# Cleanup workspace on the runner
cleanup-runner-workspace:
if: ${{ always() }}
permissions: {}
needs:
- build-website-and-container-build
- deploy-service
runs-on: ubuntu-latest
# runs-on: [ self-hosted, rcg ]
steps:
- name: Current workspace
run: du -shc ${GITHUB_WORKSPACE}
- name: Clean Up Docker Images
if: needs.build-website-and-container-build.result != 'skipped'
run: docker rmi -f $(docker images '${{ needs.build-website-and-container-build.outputs.tags }}' -a -q) || echo "No docker images found to remove...skipping removal."
- name: Clean Up Workspace
run: rm -rf ${GITHUB_WORKSPACE}