Skip to content
Merged
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
57 changes: 57 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,8 +5,27 @@ on:
branches:
- main

# Never cancel a release in flight: a publish that is interrupted between npm
# and the git tags cannot be undone. Runs therefore queue instead. GitHub keeps
# only one pending run per group, so a third push while a release is running
# silently drops the one waiting behind it — the commits still ship, on the
# next run, but nothing announces the skip. Keeping this job short is what
# keeps that window small.
concurrency: ${{ github.workflow }}-${{ github.ref }}

# This repository installs a local pre-push gate that re-runs the full test
# suite. It exists to save a CI round trip from a developer's machine; inside
# CI it is pure duplication, and `scripts/pre-push.sh` reads this to stand
# down. Set at the workflow level so it reaches every push, including the ones
# a JS action spawns.
env:
SKIP_HOOKS: "1"
Comment thread
elkaix marked this conversation as resolved.

# Fail closed: a job gets no token scope it does not ask for, so the repository
# or organisation default can never quietly hand write access to a job that
# only reads. Every job below grants itself exactly what it needs.
permissions: {}

jobs:
# Publishing to npm is irreversible — never let a commit that fails CI or
# Nix Build ship. Those workflows run in parallel on the same push, so this
Expand DownExpand Up@@ -94,6 +113,32 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

# The `prepare` script reinstalls the local hooks during the install
# above, so this has to run after it, not before. `SKIP_HOOKS` already
# tells the hook to stand down; deleting it as well removes the last way
# the suite could run inside this job — an environment that reaches the
# hook scrubbed, or a hook that stops honouring the variable.
#
# Worth the belt and braces: on the publish path, the push these hooks
# would gate carries the version tags, and it runs after npm has already
# accepted the packages. A hook failure there — one flaky test under
# runner load is enough — leaves the release published but untagged, and
# skips every job that depends on it: docs, native artifacts, the VS Code
# extension, the Homebrew tap, the CDN.
- name: Disarm the local git hooks
run: |
# `--git-path hooks` is git's own resolution of core.hooksPath, so
# this deletes from the directory git will actually read rather than
# assuming `.git/hooks`.
hooks_dir=$(git rev-parse --git-path hooks)
rm -f -- "${hooks_dir}/pre-push" "${hooks_dir}/pre-commit"
if [ -e "${hooks_dir}/pre-push" ] || [ -e "${hooks_dir}/pre-commit" ]; then
echo "::error::A git hook survived removal in ${hooks_dir}."
echo "::error::The release push would re-run the full test suite; fix this before releasing."
exit 1
fi
echo "Local git hooks disarmed (${hooks_dir})."

- name: Generate Pythinker Code built-in catalog
shell: bash
run: |
Expand DownExpand Up@@ -378,6 +423,8 @@ jobs:
redeploy-cdn:
timeout-minutes: 10
name: Redeploy CDN
# Posts to a webhook with a secret; it never touches the GitHub API.
permissions: {}
needs:
- release
- publish-native-assets
Expand DownExpand Up@@ -453,6 +500,9 @@ jobs:
verify-cdn-release:
timeout-minutes: 20
name: Verify release consistency
# Checkout only; verify-release-consistency.mjs uses no GitHub token.
permissions:
contents: read
needs:
- release
- redeploy-cdn
Expand DownExpand Up@@ -485,6 +535,9 @@ jobs:

update-brew-tap:
timeout-minutes: 15
# Checkout only; the tap push uses a minted app token, not this one.
permissions:
contents: read
name: Update Homebrew tap
needs: release
if: needs.release.outputs.packages_published == 'true'
Expand DownExpand Up@@ -535,6 +588,10 @@ jobs:
native-artifacts:
name: Native release artifact
needs: release
# Matches the `contents: read` that _native-build.yml declares for itself;
# a called workflow cannot exceed what the calling job grants.
permissions:
contents: read
if: needs.release.outputs.pythinker_native_release == 'true'
uses: ./.github/workflows/_native-build.yml
with:
Expand Down
Loading