Deploy the UW Directory #125
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: Deploy the UW Directory | |
on: | |
workflow_dispatch: | |
inputs: | |
target-stage: | |
required: true | |
default: eval | |
description: > | |
(target-stage) | |
Which cluster you want to deploy to. | |
Choose from dev, eval, prod. | |
target-version: | |
required: false | |
description: > | |
(target-version) | |
The semver you want to deploy. If you do not provide this, the workflow | |
will promote from the "previous" cluster (dev -> eval, eval -> prod). | |
associated-record: | |
required: false | |
description: > | |
(associated-record) | |
Only required if target-stage is prod. | |
A link to an RFC, Jira, or other document associated | |
with this change. | |
env: | |
GCLOUD_TOKEN: ${{ secrets.GCR_TOKEN }} | |
#TODO Replace with Deploy WebHook - Testing with this for now, while coordinating with the team | |
TEAMS_INTEGRATIONS_DAILY_WEB_TESTS: ${{ secrets.TEAMS_INTEGRATIONS_DAILY_WEB_TESTS }} | |
jobs: | |
# The `configure` job reconciles the target version (if it wasn't explicitly provided) | |
# and prepares the deployment context. Additionally, a Teams notification is sent at the | |
# start of the deployment in the `deploy` job, and another notification is sent upon | |
# deployment completion (regardless of success or failure) in the `notify-teams-finish` job. | |
configure: | |
env: | |
target_stage: ${{ github.event.inputs.target-stage }} | |
target_version: ${{ github.event.inputs.target-version }} | |
associated_record: ${{ github.event.inputs.associated-record }} | |
outputs: | |
target-version: ${{ steps.reconcile-version.outputs.target-version }} | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
# We require a deployment record for the prod endpoint to make it | |
# harder to accidentally deploy to prod; unfortunately we cannot | |
# currently validate this record, because endpoints usually require | |
# authentication. | |
- name: Verify prod deployment record | |
if: github.event.inputs.target-stage == 'prod' | |
run: | | |
if [[ -z "${{ env.associated_record }}" ]] | |
then | |
echo "Deployment to prod requires a link to an associated record" | |
exit 1 | |
fi | |
# If the entity who created this deployment did not provide a version, | |
# we will derive the version from the target stage's "previous" environment. | |
# This means that deployments to eval will promote from dev, and deployments | |
# to prod will promote from eval. It's OK if the same version is re-deployed, | |
# it will have the same net effect of a `kubectl rollout restart`. | |
# If the entity does provide a semver (target_version), that is used. | |
# Output: `target-version`: The reconciled version to deploy. | |
- name: Reconcile target deployment version | |
id: reconcile-version | |
run: | | |
set -x | |
if [[ -z "${{ env.target_version }}" ]] | |
then | |
case "${target_stage}" in | |
prod) | |
source_stage=eval | |
;; | |
dev) | |
source_stage=poetry | |
;; | |
*) | |
source_stage=dev | |
;; | |
esac | |
target_version=$(./scripts/get-deployed-version.sh -s ${target_stage}) | |
if [[ "${source_stage}" == "poetry" ]] | |
then | |
source ./scripts/globals.sh | |
target_version=$(get_poetry_version) | |
else | |
target_version=$(./scripts/get-deployed-version.sh -s ${source_stage}) | |
fi | |
else | |
target_version="${{ env.target_version }}" | |
fi | |
echo "***target_version=${target_version}" >> $GITHUB_OUTPUT | |
echo "::set-output name=target-version::${target_version}" | |
# The deploy job simply runs the deploy script. This script will wait for | |
# deployments to complete before exiting. If the deployment times out, | |
# it will be considered a failure, even if some pods succeed. | |
deploy: | |
runs-on: ubuntu-latest | |
strategy: | |
max-parallel: 1 | |
timeout-minutes: 12 # 10 minutes, plus some Actions overhead wiggle room. | |
needs: [ configure ] | |
concurrency: | |
group: ${{ github.repository }} | |
cancel-in-progress: false | |
env: | |
target_version: ${{ needs.configure.outputs.target-version }} | |
target_stage: ${{ github.event.inputs.target-stage }} | |
associated_record: ${{ github.event.inputs.associated-record }} | |
permissions: | |
contents: read | |
id-token: write | |
steps: | |
- uses: actions/checkout@v3 | |
- name: Notify Teams of Deployment Start | |
run: | | |
associated_record="${{ github.event.inputs.associated-record }}" | |
target_stage="${{ github.event.inputs.target-stage }}" | |
# Determine associated record value based on target stage and input | |
if [ -z "$associated_record" ]; then | |
if [ "$target_stage" != "prod" ]; then | |
associated_record="Not required (deployment to $target_stage)" | |
else | |
associated_record="Missing (required for production)" | |
fi | |
fi | |
curl -H "Content-Type: application/json" \ | |
-d '{ | |
"type": "message", | |
"attachments": [ | |
{ | |
"contentType": "application/vnd.microsoft.card.adaptive", | |
"content": { | |
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json", | |
"type": "AdaptiveCard", | |
"version": "1.4", | |
"body": [ | |
{ | |
"type": "TextBlock", | |
"size": "Large", | |
"weight": "Bolder", | |
"text": "UW Directory - Deployment Notification" | |
}, | |
{ | |
"type": "TextBlock", | |
"text": "Deployment to stage **${{ github.event.inputs.target-stage }}** is starting.", | |
"wrap": true | |
}, | |
{ | |
"type": "FactSet", | |
"facts": [ | |
{"title": "Stage:", "value": "${{ github.event.inputs.target-stage }}"}, | |
{"title": "Version:", "value": "${{ needs.configure.outputs.target-version }}"}, | |
{"title": "Associated Record:", "value": "'"${associated_record}"'"}, | |
{"title": "Initiated By:", "value": "${{ github.actor }}"} | |
] | |
} | |
] | |
} | |
} | |
] | |
}' \ | |
"${{ env.IDENTITY_UW_DEPLOY_MS_TEAMS_WEBHOOK_URL }}" | |
- uses: ./.github/actions/configure-docker | |
with: | |
project-name: ${{ secrets.IAM_GCR_REPO }} | |
gcr-token: ${{ secrets.GCR_TOKEN }} | |
- run: | | |
gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} | |
./scripts/deploy.sh -g -t ${target_stage} -v ${target_version} -r "${{ github.event.inputs.associated-record }}" | |
# probably need to account for -x, --dry-run at some point. lets see how things go. | |
notify-teams-finish: | |
runs-on: ubuntu-latest | |
needs: [ configure, deploy ] | |
steps: | |
- name: Notify Teams of Deployment Completion | |
if: always() # This step runs regardless of success or failure | |
run: | | |
deploy_result="${{ needs.deploy.result }}" | |
deploy_status="Failed" | |
associated_record="${{ github.event.inputs.associated-record }}" | |
target_stage="${{ github.event.inputs.target-stage }}" | |
if [ "$deploy_result" == "success" ]; then | |
deploy_status="Succeeded" | |
fi | |
# Determine associated record value based on target stage and input | |
if [ -z "$associated_record" ]; then | |
if [ "$target_stage" != "prod" ]; then | |
associated_record="Not required (deployment to $target_stage)" | |
else | |
associated_record="Missing (required for production)" | |
fi | |
fi | |
curl -H "Content-Type: application/json" \ | |
-d '{ | |
"type": "message", | |
"attachments": [ | |
{ | |
"contentType": "application/vnd.microsoft.card.adaptive", | |
"content": { | |
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json", | |
"type": "AdaptiveCard", | |
"version": "1.4", | |
"body": [ | |
{ | |
"type": "TextBlock", | |
"size": "Large", | |
"weight": "Bolder", | |
"text": "UW Directory - Deployment Notification" | |
}, | |
{ | |
"type": "TextBlock", | |
"text": "Deployment to stage **${{ github.event.inputs.target-stage }}** has **'"$deploy_status"'**.", | |
"wrap": true | |
}, | |
{ | |
"type": "FactSet", | |
"facts": [ | |
{"title": "Stage:", "value": "${{ github.event.inputs.target-stage }}"}, | |
{"title": "Version:", "value": "${{ needs.configure.outputs.target-version }}"}, | |
{"title": "Associated Record:", "value": "'"${associated_record}"'"}, | |
{"title": "Initiated By:", "value": "${{ github.actor }}"}, | |
{"title": "Status:", "value": "'"$deploy_status"'"} | |
] | |
} | |
], | |
"actions": [ | |
{ | |
"type": "Action.OpenUrl", | |
"title": "View Workflow", | |
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
} | |
] | |
} | |
} | |
] | |
}' \ | |
"${{ env.IDENTITY_UW_DEPLOY_MS_TEAMS_WEBHOOK_URL }}" | |