Skip to content

Deploy the UW Directory #131

Deploy the UW Directory

Deploy the UW Directory #131

Workflow file for this run

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 }}
UW_DIRECTORY_DEPLOY_MS_TEAMS_WEBHOOK_URL: ${{ secrets.UW_DIRECTORY_DEPLOY_MS_TEAMS_WEBHOOK_URL }}
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.UW_DIRECTORY_DEPLOY_MS_TEAMS_WEBHOOK_URL }}"
- name: Install Poetry with pip
run: |
python -m pip install --upgrade pip
python -m pip install poetry
poetry --version
- name: Run Poetry Install
run: |
sudo apt-get -y install jq
poetry install
- uses: actions/checkout@v3
- 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.UW_DIRECTORY_DEPLOY_MS_TEAMS_WEBHOOK_URL }}"