Repository navigation
124 lines (112 loc) · 5.52 KB
/
Copy pathdeploy-icons.yml
File metadata and controls
124 lines (112 loc) · 5.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
name: Deploy boxel-icons
# Publishes packages/boxel-icons to the icon CDN that cards' `static icon`
# imports resolve against.
#
# The CDN is a single global bucket, not one per environment: the host
# hardcodes `boxel-icons.boxel.ai` (runtime-common/virtual-network.ts,
# runtime-common/realm.ts), so staging and production read the same objects.
# That is why this runs off a merge to main rather than hanging on either
# environment's deploy — an icon has to be on the CDN before any environment
# renders a card that imports it, and a per-environment trigger would leave
# whichever environment deploys second serving 403s in the meantime.
#
# The sync is additive. `aws s3 sync` without `--delete` only ever adds or
# overwrites, so an icon dropped from the package does not vanish from under
# cards that still import it; stale objects are cheap, a missing one errors
# the whole card at index time. Pruning is a deliberate, separate act.
on:
push:
branches:
- main
paths:
- "packages/boxel-icons/**"
# Re-run by hand to backfill objects missing from the bucket. On an
# icons-cache hit a run uploads only missing objects and ones whose size
# changed (see the sync step).
workflow_dispatch:
permissions:
contents: read
id-token: write
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
# Serialize: two merges landing together would otherwise race the same
# bucket, and the later sync is the one that should win.
concurrency: deploy-icons
env:
AWS_REGION: us-east-1
AWS_ROLE_ARN: arn:aws:iam::120317779495:role/boxel-icons
AWS_CLOUDFRONT_DISTRIBUTION: E3RWB9TW185XFG
steps:
- name: Refuse to run from non-main branches
# The `push` trigger is already main-only, but `workflow_dispatch` lets
# the operator pick any ref. This bucket is the single global CDN both
# staging and production read, and the sync never deletes, so a run from
# a feature or stale branch would publish unmerged icons or overwrite
# main's bytes with older ones, and no later run would fully undo it.
# Fail before configuring AWS credentials so no write can happen off-main.
run: |
set -eo pipefail
REF="${{ github.ref }}"
if [[ "$REF" != "refs/heads/main" ]]; then
echo "::error::This workflow may only run against refs/heads/main." >&2
echo "Got ref: $REF" >&2
exit 1
fi
echo "Confirmed run from main."
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Init
uses: ./.github/actions/init
- name: Restore boxel-icons build cache
id: icons-cache
uses: ./.github/actions/restore-icons-cache
# The full build, not just `build:js`, even though only `dist` is
# synced: the cache key covers `dist` and `declarations` together, and a
# js-only build on a cache miss would save a cache that later jobs
# restore expecting declarations to be there too.
- name: Build boxel-icons
if: steps.icons-cache.outputs.cache-hit != 'true'
run: pnpm --filter @cardstack/boxel-icons build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
role-to-assume: ${{ env.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
# `deploy:s3` stamps each object it uploads with an explicit
# Cache-Control. Without one, a browser falls back to heuristic
# freshness, a tenth of the object's age when it was fetched, and every
# upload resets that age. For days after a publish a returning browser
# would revalidate every icon a card imports, on every boot. One day
# fresh matches the distribution's default TTL. The stale-while-revalidate
# window lets a later boot use its cached copy while it refreshes in the
# background. Not `immutable`: an icon-set update can change the bytes
# behind an existing path. `aws s3 sync` stamps only what it uploads, and
# it skips a file whose size is unchanged and whose mtime is no newer
# than its object. A build restored from the icons cache keeps the mtimes
# of the run that saved it, so a dispatch on a cache hit re-uploads
# nothing that already exists. A new value reaches every object only
# when an input to the icons cache key changes and forces a fresh build.
# Editing the value in packages/boxel-icons/package.json is one such change.
- name: Sync to S3
run: pnpm --filter @cardstack/boxel-icons deploy:s3
# Overwritten icons would otherwise be served from the edge cache for up
# to the cache policy's DefaultTTL (a day). A 403 for a not-yet-published
# icon is only cached for CloudFront's short default error TTL, so new
# icons become reachable without this; the invalidation is for changed
# bytes.
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id "$AWS_CLOUDFRONT_DISTRIBUTION" \
--paths '/@cardstack/boxel-icons/*'
- name: Send notification to Discord
# A flaky webhook should not fail a deploy that has already happened.
continue-on-error: true
timeout-minutes: 2
uses: cardstack/gh-actions/discord-notification-deploy@main
with:
app: "boxel-icons"
status: ${{ job.status }}
environment: production
webhook: ${{ secrets.DISCORD_WEBHOOK }}