From 99ec6ab5792cac4d4beff716358141e69e444f50 Mon Sep 17 00:00:00 2001 From: Yilin Jing Date: Sat, 26 Sep 2026 02:05:32 -0400 Subject: [PATCH 1/2] Index: upload each changed project as archives/.tar.gz Co-Authored-By: Claude Opus 5.5 --- .github/workflows/index.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/index.yml b/.github/workflows/index.yml index 5a85ec9..cb36dde 100644 --- a/.github/workflows/index.yml +++ b/.github/workflows/index.yml @@ -30,6 +30,29 @@ jobs: git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git commit -m "Update index.json" index.json git push + # `sp fetch ` and `sp duplicate ` download a project as + # releases/download/archives/.tar.gz, one archive per project, replaced in place. + # Only the projects this push changed are rebuilt; a manual run rebuilds them all. + - run: | + gh release view archives > /dev/null 2>&1 || + gh release create archives --latest=false --title archives \ + --notes "One archive per project, which sp fetch and sp duplicate download." + if [ -n "$BEFORE" ] && git cat-file -e "$BEFORE" 2> /dev/null; then + ids=$(git diff --name-only "$BEFORE" HEAD -- projects | cut -d/ -f2 | sort -u) + else + ids=$(ls projects) + fi + for id in $ids; do + if [ -d "projects/$id" ]; then + tar czf "$id.tar.gz" -C projects "$id" + gh release upload archives "$id.tar.gz" --clobber + else + gh release delete-asset archives "$id.tar.gz" --yes || true # never uploaded + fi + done + env: + GH_TOKEN: ${{ github.token }} + BEFORE: ${{ github.event.before }} # The site builds each project's page from this repo when the canvas deploys, which a # push here does not do on its own: this starts that build, so a merged project opens # on the web within minutes. The hook is the super-prototyping Pages project's. From 17ef125f3c107f1c7bf58ef3b81cc17c88e6192b Mon Sep 17 00:00:00 2001 From: Yilin Jing Date: Sat, 26 Sep 2026 02:46:52 -0400 Subject: [PATCH 2/2] Archives: rebuild what changed since the last archived commit A run that concurrency cancelled would have left its projects out, since each run diffed only its own push. The release now records the commit its archives are of. The step runs after the deploy hook, so a failed upload cannot keep a project off the site, and a full rebuild drops the archives of removed projects. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/index.yml | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/.github/workflows/index.yml b/.github/workflows/index.yml index cb36dde..a098231 100644 --- a/.github/workflows/index.yml +++ b/.github/workflows/index.yml @@ -30,32 +30,39 @@ jobs: git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git commit -m "Update index.json" index.json git push + # The site builds each project's page from this repo when the canvas deploys, which a + # push here does not do on its own: this starts that build, so a merged project opens + # on the web within minutes. The hook is the super-prototyping Pages project's. + - run: curl -fsS -X POST "$HOOK" > /dev/null + env: + HOOK: ${{ secrets.PAGES_DEPLOY_HOOK }} # `sp fetch ` and `sp duplicate ` download a project as # releases/download/archives/.tar.gz, one archive per project, replaced in place. - # Only the projects this push changed are rebuilt; a manual run rebuilds them all. + # After the deploy hook, so a failed upload cannot keep a merged project off the site. + # The release's `archived-at` holds the commit its archives are of, and each run rebuilds + # what changed since: a run that concurrency cancelled leaves nothing out, which + # github.event.before would. With no such commit, it rebuilds them all, and drops the + # archive of any project that is gone. - run: | gh release view archives > /dev/null 2>&1 || gh release create archives --latest=false --title archives \ --notes "One archive per project, which sp fetch and sp duplicate download." - if [ -n "$BEFORE" ] && git cat-file -e "$BEFORE" 2> /dev/null; then - ids=$(git diff --name-only "$BEFORE" HEAD -- projects | cut -d/ -f2 | sort -u) + have=$(gh release view archives --json assets --jq '.assets[].name') + at=$(gh release download archives -p archived-at -O - 2> /dev/null || true) + if [ -n "$at" ] && git cat-file -e "$at" 2> /dev/null; then + ids=$(git diff --name-only "$at" HEAD -- projects | cut -d/ -f2 | sort -u) else - ids=$(ls projects) + ids=$( (ls projects; echo "$have" | sed -n 's/\.tar\.gz$//p') | sort -u) fi for id in $ids; do if [ -d "projects/$id" ]; then tar czf "$id.tar.gz" -C projects "$id" gh release upload archives "$id.tar.gz" --clobber - else - gh release delete-asset archives "$id.tar.gz" --yes || true # never uploaded + elif echo "$have" | grep -qx "$id.tar.gz"; then + gh release delete-asset archives "$id.tar.gz" --yes fi done + git rev-parse HEAD > archived-at + gh release upload archives archived-at --clobber env: GH_TOKEN: ${{ github.token }} - BEFORE: ${{ github.event.before }} - # The site builds each project's page from this repo when the canvas deploys, which a - # push here does not do on its own: this starts that build, so a merged project opens - # on the web within minutes. The hook is the super-prototyping Pages project's. - - run: curl -fsS -X POST "$HOOK" > /dev/null - env: - HOOK: ${{ secrets.PAGES_DEPLOY_HOOK }}