11name : deploy-surface
22
3- # Reusable single- surface deploy. Builds the site and rsyncs ONE
4- # surface's dist/ subfolder to its document root for the chosen env.
3+ # Reusable surface deploy: build ONCE, rsync each requested surface's
4+ # dist/ subfolder to its document root for the chosen env.
55#
6- # This is the shared engine behind both the auto-staging deploy (called
7- # once per surface in a matrix) and the per-surface production tag
8- # deploys, and it can be run by hand from the Actions tab via
9- # workflow_dispatch ("deploy my sites independently").
6+ # This is the shared engine behind both the auto-staging deploy (one
7+ # call with surface=all) and the per-surface production tag deploys
8+ # (one call with that surface), and it can be run by hand from the
9+ # Actions tab via workflow_dispatch ("deploy my sites independently",
10+ # or surface=all for a whole release in one click).
11+ #
12+ # Astro has no partial build - every build emits every surface - so the
13+ # expensive part (install, prebuild downloads, build, and on production
14+ # the full baseline gates) runs in ONE job and the per-surface legs are
15+ # artifact-download + rsync only. Beyond the compute saved, this means
16+ # every surface in a deploy ships from literally the same build instead
17+ # of N builds that could drift (e.g. a registry package publishing
18+ # mid-release).
1019#
1120# The surface -> document-root mapping below is the single source of
1221# truth; it mirrors the host layout documented in docs/deploy-targets.md.
1524 workflow_dispatch :
1625 inputs :
1726 surface :
18- description : Which surface to deploy
27+ description : Which surface to deploy (all = every surface, one build)
1928 type : choice
2029 required : true
30+ default : all
2131 options :
32+ - all
2233 - architecture
2334 - main
2435 - plays
3647 workflow_call :
3748 inputs :
3849 surface :
50+ description : A surface name, or "all" for every surface
3951 required : true
4052 type : string
4153 env :
@@ -52,7 +64,24 @@ permissions:
5264 packages : read
5365
5466jobs :
55- deploy :
67+ resolve :
68+ runs-on : ubuntu-latest
69+ outputs :
70+ surfaces : ${{ steps.s.outputs.surfaces }}
71+ steps :
72+ - id : s
73+ run : |
74+ surface="${{ inputs.surface }}"
75+ case "$surface" in
76+ all)
77+ echo 'surfaces=["architecture","main","cultures","plays","misfits","writing"]' >> "$GITHUB_OUTPUT" ;;
78+ architecture|main|cultures|plays|misfits|writing)
79+ echo "surfaces=[\"$surface\"]" >> "$GITHUB_OUTPUT" ;;
80+ *)
81+ echo "::error::unknown surface '$surface' (expected a surface name or 'all')"; exit 1 ;;
82+ esac
83+
84+ build :
5685 runs-on : ubuntu-latest
5786 steps :
5887 - uses : actions/checkout@v7
@@ -75,10 +104,39 @@ jobs:
75104 # to staging.kaihacks.ai when DEPLOY_ENV=staging.
76105 DEPLOY_ENV=staging npm run build
77106 fi
107+ - name : upload dist
108+ uses : actions/upload-artifact@v4
109+ with :
110+ name : dist-${{ inputs.env }}
111+ path : dist
112+ # dist carries dot-paths the sites need (.well-known/security.txt,
113+ # the apex .htaccess rewrites). upload-artifact excludes hidden
114+ # files by default since v4.4; without this flag they would vanish
115+ # from the artifact and the rsync --delete below would then REMOVE
116+ # them from the live document roots.
117+ include-hidden-files : true
118+ retention-days : 1
119+
120+ deploy :
121+ needs : [resolve, build]
122+ runs-on : ubuntu-latest
123+ strategy :
124+ # Surfaces deploy independently: one failing leg does not block the
125+ # others, and a single leg can be re-run on its own ("re-run failed
126+ # jobs") without rebuilding - the artifact is the build.
127+ fail-fast : false
128+ matrix :
129+ surface : ${{ fromJSON(needs.resolve.outputs.surfaces) }}
130+ steps :
131+ - name : download dist
132+ uses : actions/download-artifact@v4
133+ with :
134+ name : dist-${{ inputs.env }}
135+ path : dist
78136 - name : resolve rsync target
79137 id : target
80138 run : |
81- surface="${{ inputs .surface }}"
139+ surface="${{ matrix .surface }}"
82140 env="${{ inputs.env }}"
83141 base="/home/c216mkgp1lzk/public_html"
84142 if [ "$env" = "production" ]; then
@@ -144,7 +202,7 @@ jobs:
144202 run : |
145203 rsync -avz --delete --exclude '/_assets/' \
146204 -e "ssh -i ~/.ssh/kaihacksai" \
147- "./dist/${{ inputs .surface }}/" \
205+ "./dist/${{ matrix .surface }}/" \
148206 "c216mkgp1lzk@92.205.150.56:${{ steps.target.outputs.target }}"
149207 - name : Deploy shared assets via rsync (NO --delete)
150208 # Ship the hashed /_assets/ bundle the HTML references. No --delete:
0 commit comments