Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/scripts/notify-site-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash
# Pin the Doenet site's tracked DoenetML version to a concrete published version.
#
# Called by publish.yml after a dev or production npm publish. POSTs to the
# site's /api/info/updateTrackedDoenetmlVersion endpoint, which updates the
# doenetmlVersions row that tracks the given npm dist-tag so the jsDelivr bundle
# URL becomes immutable (browser-cacheable) instead of a moving tag — users get
# the new bundle without clearing their cache.
#
# Environment:
# SECRET - shared bearer secret (repo secret DOENET_VERSION_UPDATE_SECRET)
# TAG - npm dist-tag being pinned: "dev" or "latest"
# VERSION - concrete version just published (e.g. 0.7.21 or 0.7.21-dev.343)
#
# Production (doenet.org) is REQUIRED: a failure fails the job so GitHub notifies
# and the job can be re-run. dev3 is BEST-EFFORT because it auto-scales to zero
# and may be asleep when a publish happens.

set -u

if [[ -z "${SECRET:-}" ]]; then
echo "::error::DOENET_VERSION_UPDATE_SECRET is not set — add it as a repository secret"
exit 1
fi
if [[ -z "${TAG:-}" || -z "${VERSION:-}" ]]; then
echo "::error::TAG and VERSION must both be set (TAG='${TAG:-}', VERSION='${VERSION:-}')"
exit 1
fi

# $1 = site base URL, $2 = required ("true" fails the job on error)
post() {
local url="$1" required="$2"
echo "Pinning ${TAG} -> ${VERSION} on ${url} ..."
if curl -fsS --connect-timeout 15 --max-time 60 \
-X POST "${url}/api/info/updateTrackedDoenetmlVersion" \
-H "Authorization: Bearer ${SECRET}" \
-H "Content-Type: application/json" \
-d "{\"tag\":\"${TAG}\",\"version\":\"${VERSION}\"}"; then
echo ""
echo " updated ${url}"
elif [[ "${required}" == "true" ]]; then
echo ""
echo "::error::Failed to pin DoenetML version on ${url}"
exit 1
else
echo ""
echo "::warning::Failed to pin DoenetML version on ${url} (best-effort; the site may be asleep)"
fi
}

post "https://doenet.org" true
post "https://dev3.doenet.org" false

echo "Done."
53 changes: 53 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
dev-release:
name: Dev Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.compute-version.outputs.version }}
if: >-
(github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
Expand Down Expand Up @@ -71,10 +73,14 @@ jobs:
run: node .github/scripts/verify-ci.mjs

- name: Update versions
id: compute-version
run: |
CURRENT_VERSION=$(node -p "require('./packages/doenetml/package.json').version")
VERSION="${CURRENT_VERSION}-dev.${{ github.run_number }}"
npm run version -- ${VERSION} --no-git-tag-version
# Exposed as a job output so the notify-site-dev job can pin the
# Doenet site to the exact version published here.
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

- name: Build workspaces
run: |
Expand Down Expand Up @@ -206,6 +212,8 @@ jobs:
name: Production Release
runs-on: ubuntu-latest
environment: production
outputs:
version: ${{ steps.release-tag.outputs.version }}
if: >-
github.event_name == 'release' ||
(github.event_name == 'workflow_dispatch' && inputs.channel == 'production')
Expand Down Expand Up @@ -298,3 +306,48 @@ jobs:
run: npm run publish -w @doenet/vscode-extension
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}

# After a dev publish, pin the Doenet site's tracked dev DoenetML version to
# the exact version just published, so users get the new bundle immediately
# from an immutable jsDelivr URL instead of waiting out a browser cache.
#
# This runs as a separate job so a failure here does NOT republish to npm:
# GitHub notifies on the failed job and "Re-run failed jobs" retries only
# this step. The site endpoint is idempotent, so retries are safe.
#
# Requires the repository-level secret DOENET_VERSION_UPDATE_SECRET (must be
# repo-level, not only in the `production` environment, so both this dev job
# and the production job below can read it — same requirement as VSCE_PAT).
notify-site-dev:
name: Pin dev version on Doenet sites
needs: dev-release
runs-on: ubuntu-latest
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.dry_run) }}
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Pin tracked dev version
env:
SECRET: ${{ secrets.DOENET_VERSION_UPDATE_SECRET }}
TAG: dev
VERSION: ${{ needs.dev-release.outputs.version }}
run: bash .github/scripts/notify-site-version.sh

# After a production publish, pin the site's tracked `latest` DoenetML version
# to the released version. Same rationale and retry behavior as the dev job.
notify-site-prod:
name: Pin latest version on Doenet sites
needs: production-release
runs-on: ubuntu-latest
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.dry_run) }}
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Pin tracked latest version
env:
SECRET: ${{ secrets.DOENET_VERSION_UPDATE_SECRET }}
TAG: latest
VERSION: ${{ needs.production-release.outputs.version }}
run: bash .github/scripts/notify-site-version.sh