meal-order-manager/.github/workflows/weekly-menu.yml

166 lines
6 KiB
YAML

name: Weekly Menu Scrape & Publish
on:
schedule:
# Monday 7:30am EST = 12:30 UTC
- cron: '30 12 * * 1'
# Monday 7:30am EDT = 11:30 UTC
- cron: '30 11 * * 1'
workflow_dispatch:
permissions:
id-token: write
contents: read
concurrency:
group: weekly-menu
cancel-in-progress: false
jobs:
scrape-and-publish:
runs-on: ubuntu-latest
# A hung Playwright scrape would otherwise hold the weekly-menu concurrency
# group for the 360-minute default.
timeout-minutes: 30
env:
AWS_REGION: us-east-1
steps:
- name: Timezone guard
if: github.event_name == 'schedule'
env:
CRON: ${{ github.event.schedule }}
run: |
OFFSET=$(TZ='America/New_York' date +%z)
echo "Cron: $CRON | Eastern offset: $OFFSET"
if { [ "$OFFSET" = "-0400" ] && [ "$CRON" = "30 12 * * 1" ]; } || \
{ [ "$OFFSET" = "-0500" ] && [ "$CRON" = "30 11 * * 1" ]; }; then
echo "Wrong-timezone cron fired — skipping"
echo "SKIP_RUN=true" >> "$GITHUB_ENV"
fi
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
if: env.SKIP_RUN != 'true'
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
if: env.SKIP_RUN != 'true'
with:
python-version: '3.12.14'
- name: Install dependencies
if: env.SKIP_RUN != 'true'
run: |
pip install -r requirements.txt
playwright install chromium --with-deps
- name: Configure AWS credentials
if: env.SKIP_RUN != 'true'
uses: aws-actions/configure-aws-credentials@cbe3b392738ccf3f987d68400dafcf4b0624a56c # v6.2.4
with:
role-to-assume: ${{ secrets.AWS_WEEKLY_MENU_ROLE_ARN }}
aws-region: us-east-1
- name: Scrape menu
if: env.SKIP_RUN != 'true'
run: python3 src/scraper/scrape_menu.py
# Deploy targets come from Parameter Store, written by Terraform
# (terraform/ssm.tf). They replace the CloudFormation stack outputs this
# job used to read; there is no CloudFormation stack any more.
- name: Get deploy parameters
if: env.SKIP_RUN != 'true'
id: stack
run: |
set -euo pipefail
get_param() {
aws ssm get-parameter --name "$1" --query 'Parameter.Value' --output text
}
API_URL=$(get_param /meal-order-manager/deploy/api-url)
FORM_BUCKET=$(get_param /meal-order-manager/deploy/form-bucket)
DIST_ID=$(get_param /meal-order-manager/deploy/distribution-id)
FORM_URL=$(get_param /meal-order-manager/deploy/form-url)
for v in "$API_URL" "$FORM_BUCKET" "$DIST_ID" "$FORM_URL"; do
if [ -z "$v" ] || [ "$v" = "None" ]; then
echo "A /meal-order-manager/deploy/* parameter is missing; has Terraform been applied?" >&2
exit 1
fi
done
echo "api_url=$API_URL" >> "$GITHUB_OUTPUT"
echo "form_bucket=$FORM_BUCKET" >> "$GITHUB_OUTPUT"
echo "dist_id=$DIST_ID" >> "$GITHUB_OUTPUT"
echo "form_url=$FORM_URL" >> "$GITHUB_OUTPUT"
- name: Get discount settings
if: env.SKIP_RUN != 'true'
id: discount
env:
API_URL: ${{ steps.stack.outputs.api_url }}
run: |
SETTINGS=$(python3 scripts/upload_menu.py settings --api-url "$API_URL")
BULK=$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["bulk_discount_percent"])' "$SETTINGS")
SUBSIDY=$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["company_subsidy_percent"])' "$SETTINGS")
echo "bulk_discount=$BULK" >> "$GITHUB_OUTPUT"
echo "company_subsidy=$SUBSIDY" >> "$GITHUB_OUTPUT"
- name: Get Google Client ID
if: env.SKIP_RUN != 'true'
id: google
run: |
GOOGLE_CLIENT_ID=$(aws ssm get-parameter \
--name /meal-order-manager/google-client-id \
--query 'Parameter.Value' \
--output text)
if [ "$GOOGLE_CLIENT_ID" = "None" ] || [ -z "$GOOGLE_CLIENT_ID" ]; then
echo "Google client ID is required for cloud form generation" >&2
exit 1
fi
echo "client_id=$GOOGLE_CLIENT_ID" >> "$GITHUB_OUTPUT"
- name: Generate order form
if: env.SKIP_RUN != 'true'
env:
API_URL: ${{ steps.stack.outputs.api_url }}
BULK_DISCOUNT: ${{ steps.discount.outputs.bulk_discount }}
COMPANY_SUBSIDY: ${{ steps.discount.outputs.company_subsidy }}
GOOGLE_CLIENT_ID: ${{ steps.google.outputs.client_id }}
run: |
python3 src/server/generate_form.py \
--api-url "$API_URL" \
--bulk-discount "$BULK_DISCOUNT" \
--company-subsidy "$COMPANY_SUBSIDY" \
--google-client-id "$GOOGLE_CLIENT_ID"
- name: Publish menu through API
if: env.SKIP_RUN != 'true'
env:
API_URL: ${{ steps.stack.outputs.api_url }}
run: python3 scripts/upload_menu.py publish --api-url "$API_URL"
- name: Upload form to S3
if: env.SKIP_RUN != 'true'
env:
FORM_BUCKET: ${{ steps.stack.outputs.form_bucket }}
run: |
WEEK=$(date +%Y-W%U)
aws s3 cp "output/order-form-$WEEK.html" \
"s3://${FORM_BUCKET}/index.html" \
--content-type "text/html" \
--cache-control "no-cache"
aws s3 cp "output/order-form-$WEEK.html" \
"s3://${FORM_BUCKET}/archive/$WEEK.html" \
--content-type "text/html"
- name: Invalidate CloudFront cache
if: env.SKIP_RUN != 'true'
env:
DIST_ID: ${{ steps.stack.outputs.dist_id }}
run: |
aws cloudfront create-invalidation \
--distribution-id "$DIST_ID" \
--paths "/index.html"
- name: Notify Slack
if: env.SKIP_RUN != 'true'
env:
FORM_URL: ${{ steps.stack.outputs.form_url }}
run: python3 scripts/notify_slack.py "$FORM_URL"