mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-09-30 19:33:12 +00:00
Some checks are pending
Deploy / Deploy to prod (push) Waiting to run
* fix(cutover): write Slack secrets into empty Terraform shells DescribeSecret succeeds on HCP-created shells with no version, so skip-if-exists left roster and Slack tokens unset. * feat(infra): migrate afterhours to HCP Terraform (PLAT-74) Replace the mgmt SAM stack with a prod-only HCP workspace, in-repo hcptf IAM, stub Lambdas, and zip CD on push to main. * fix(cutover): retry DDB unprocessed items and skip past at() holidays Unprocessed BatchWriteItem rows and leftover past at() schedules would drop roster data or abort holiday recreation during prod cutover.
150 lines
5.9 KiB
YAML
150 lines
5.9 KiB
YAML
name: Deploy
|
|
|
|
# Terraform owns Lambda skeletons. This workflow ships zips to prod and calls
|
|
# update-function-code. It never creates an HCP run. No GitHub Releases and no
|
|
# tagging in this workflow.
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths-ignore:
|
|
- "terraform/**"
|
|
- "docs/**"
|
|
- "README.md"
|
|
- "SETUP.md"
|
|
- "AGENTS.md"
|
|
workflow_dispatch:
|
|
inputs:
|
|
ref:
|
|
description: "Git ref to build and deploy (tag, branch, or SHA). Empty means the workflow ref."
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
deploy:
|
|
name: Deploy to prod
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
environment: prod
|
|
concurrency:
|
|
group: deploy-afterhours-prod
|
|
cancel-in-progress: false
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
env:
|
|
AWS_REGION: us-east-1
|
|
DEPLOY_ROLE_ARN: ${{ vars.DEPLOY_ROLE_ARN }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Resolve commit
|
|
id: commit
|
|
run: |
|
|
set -euo pipefail
|
|
sha="$(git rev-parse HEAD)"
|
|
echo "sha=${sha}" >> "$GITHUB_OUTPUT"
|
|
echo "Building ${sha}"
|
|
|
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Build function zips
|
|
env:
|
|
GIT_SHA: ${{ steps.commit.outputs.sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
python scripts/package_lambdas.py --git-sha "${GIT_SHA}" --out-dir build/packages
|
|
python - <<'PY'
|
|
import os, zipfile
|
|
from pathlib import Path
|
|
sha = os.environ["GIT_SHA"]
|
|
names = [
|
|
"slack_bot",
|
|
"weekly_post",
|
|
"roster_sync",
|
|
"roster_api",
|
|
"ring_scheduler",
|
|
"holiday_router",
|
|
"release_notifier",
|
|
]
|
|
for name in names:
|
|
path = Path("build/packages") / f"{name}.zip"
|
|
if not path.is_file():
|
|
raise SystemExit(f"missing {path}")
|
|
with zipfile.ZipFile(path) as zf:
|
|
info = zf.read("shared/build_info.py").decode()
|
|
if sha not in info:
|
|
raise SystemExit(f"{path} missing GIT_SHA {sha}")
|
|
if "shared/sentry_init.py" not in zf.namelist():
|
|
raise SystemExit(f"{path} missing bundled shared package")
|
|
print("zips ok")
|
|
PY
|
|
|
|
- name: Configure AWS credentials using OIDC
|
|
uses: aws-actions/configure-aws-credentials@cbe3b392738ccf3f987d68400dafcf4b0624a56c # v6.2.4
|
|
with:
|
|
role-to-assume: ${{ env.DEPLOY_ROLE_ARN }}
|
|
aws-region: us-east-1
|
|
audience: sts.amazonaws.com
|
|
|
|
- name: Get deploy parameters
|
|
id: deploy
|
|
run: |
|
|
set -euo pipefail
|
|
prefix=/afterhours-shift-manager/deploy
|
|
ARTIFACTS_BUCKET=$(aws ssm get-parameter --name "${prefix}/artifacts-bucket" --query Parameter.Value --output text)
|
|
{
|
|
echo "artifacts_bucket=${ARTIFACTS_BUCKET}"
|
|
echo "slack_bot=$(aws ssm get-parameter --name "${prefix}/slack_bot-function-name" --query Parameter.Value --output text)"
|
|
echo "weekly_post=$(aws ssm get-parameter --name "${prefix}/weekly_post-function-name" --query Parameter.Value --output text)"
|
|
echo "roster_sync=$(aws ssm get-parameter --name "${prefix}/roster_sync-function-name" --query Parameter.Value --output text)"
|
|
echo "roster_api=$(aws ssm get-parameter --name "${prefix}/roster_api-function-name" --query Parameter.Value --output text)"
|
|
echo "ring_scheduler=$(aws ssm get-parameter --name "${prefix}/ring_scheduler-function-name" --query Parameter.Value --output text)"
|
|
echo "holiday_router=$(aws ssm get-parameter --name "${prefix}/holiday_router-function-name" --query Parameter.Value --output text)"
|
|
echo "release_notifier=$(aws ssm get-parameter --name "${prefix}/release_notifier-function-name" --query Parameter.Value --output text)"
|
|
} >> "${GITHUB_OUTPUT}"
|
|
|
|
- name: Upload zips and update function code
|
|
env:
|
|
ARTIFACTS_BUCKET: ${{ steps.deploy.outputs.artifacts_bucket }}
|
|
GIT_SHA: ${{ steps.commit.outputs.sha }}
|
|
SLACK_BOT: ${{ steps.deploy.outputs.slack_bot }}
|
|
WEEKLY_POST: ${{ steps.deploy.outputs.weekly_post }}
|
|
ROSTER_SYNC: ${{ steps.deploy.outputs.roster_sync }}
|
|
ROSTER_API: ${{ steps.deploy.outputs.roster_api }}
|
|
RING_SCHEDULER: ${{ steps.deploy.outputs.ring_scheduler }}
|
|
HOLIDAY_ROUTER: ${{ steps.deploy.outputs.holiday_router }}
|
|
RELEASE_NOTIFIER: ${{ steps.deploy.outputs.release_notifier }}
|
|
run: |
|
|
set -euo pipefail
|
|
keys=(
|
|
slack_bot:"${SLACK_BOT}"
|
|
weekly_post:"${WEEKLY_POST}"
|
|
roster_sync:"${ROSTER_SYNC}"
|
|
roster_api:"${ROSTER_API}"
|
|
ring_scheduler:"${RING_SCHEDULER}"
|
|
holiday_router:"${HOLIDAY_ROUTER}"
|
|
release_notifier:"${RELEASE_NOTIFIER}"
|
|
)
|
|
for pair in "${keys[@]}"; do
|
|
name="${pair%%:*}"
|
|
fn="${pair#*:}"
|
|
key="functions/${name}/${GIT_SHA}.zip"
|
|
aws s3 cp "build/packages/${name}.zip" "s3://${ARTIFACTS_BUCKET}/${key}"
|
|
aws lambda update-function-code \
|
|
--function-name "${fn}" \
|
|
--s3-bucket "${ARTIFACTS_BUCKET}" \
|
|
--s3-key "${key}" \
|
|
--query '{Function:FunctionName,Sha256:CodeSha256,Updated:LastModified}' \
|
|
--output table
|
|
aws lambda wait function-updated-v2 --function-name "${fn}"
|
|
done
|