Skip to content

docs: add seeking-co-maintainer banner (refs #5) #102

docs: add seeking-co-maintainer banner (refs #5)

docs: add seeking-co-maintainer banner (refs #5) #102

Workflow file for this run

name: deploy
# Build and publish the static web client to GitHub Pages, stamping
# the commit SHA into the version badge as part of the build so every
# deployed page carries a clickable link to the exact commit it came
# from.
#
# REQUIRED ONE-TIME REPO SETTING: Settings → Pages → Build and
# deployment → Source must be set to "GitHub Actions". With the
# legacy "Deploy from a branch" source selected, the auto-managed
# pages-build-deployment workflow keeps running instead of this one
# and no SHA stamping happens.
on:
push:
branches: [master]
workflow_dispatch:
# Pages deployment permissions. `contents: write` is needed so the
# workflow can push a per-deploy tag back to origin (see the "Tag
# this deploy" step below); without it the GITHUB_TOKEN only has
# read access and the push would be rejected.
permissions:
contents: write
pages: write
id-token: write
# Only one concurrent Pages deploy at a time, but do not cancel in
# flight — if two pushes land in quick succession we want both to
# deploy sequentially, not race.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: JS module syntax check
# No build step means a JavaScript syntax error ships straight to
# users. A duplicate top-level declaration is a SyntaxError that
# aborts the WHOLE module (this bit us in v0.7.0–v0.9.0: app.js
# silently failed to load). Parse every module AS an ES module via
# `node --check` (.mjs) so module-scope errors — duplicate top-level
# let/const/function/class, bad import/export syntax — fail the
# deploy before anything goes live. `--check` only parses; it does
# not resolve imports, so bare specifiers and relative paths are fine.
run: |
node --version
fail=0
for f in js/*.js lib/*.js; do
tmp="$(mktemp --suffix=.mjs)"
cp "$f" "$tmp"
if err="$(node --check "$tmp" 2>&1)"; then
echo "ok $f"
else
echo "FAIL $f"; echo "$err"; fail=1
fi
rm -f "$tmp"
done
if [ "$fail" -ne 0 ]; then
echo "::error::JavaScript module syntax check failed — not deploying"
exit 1
fi
- name: Sync version badge from package.json
# Single source of truth for the semantic version is package.json.
# This step rewrites the two "v?.?.?" tokens that immediately
# precede the <!-- BUILD_SHA --> markers in index.html to match.
# Means future version bumps only need to touch package.json.
run: |
python - <<'PY'
import json, re
version = json.load(open('package.json'))['version']
print(f"Syncing version badge to v{version}")
with open('index.html', 'r', encoding='utf-8') as f:
html = f.read()
# Rewrite any >v1.2.3<!-- BUILD_SHA --> → >v{version}<!-- BUILD_SHA -->
new_html, n = re.subn(
r'>v\d+\.\d+\.\d+(<!-- BUILD_SHA -->)',
lambda m: f'>v{version}{m.group(1)}',
html
)
if n == 0:
print('WARNING: no version badge tokens found in index.html')
else:
print(f'Rewrote {n} version badge(s)')
with open('index.html', 'w', encoding='utf-8') as f:
f.write(new_html)
PY
- name: Inject short commit SHA into version badge
# Replaces the <!-- BUILD_SHA --> comment placeholder in the
# version badge with a clickable link to the commit. Locally
# the comment is invisible so the badge shows just the
# semantic version; deployed builds gain " · abc1234" that
# opens the commit on GitHub.
env:
SHA_FULL: ${{ github.sha }}
REPO: ${{ github.repository }}
run: |
python - <<'PY'
import os
sha_full = os.environ['SHA_FULL']
repo = os.environ['REPO']
sha_short = sha_full[:7]
sha_url = f"https://github.com/{repo}/commit/{sha_full}"
print(f"Stamping {sha_short} -> {sha_url}")
with open('index.html', 'r', encoding='utf-8') as f:
html = f.read()
replacement = f' <a class="version-sha" href="{sha_url}" target="_blank" rel="noopener" title="Commit this build was deployed from">{sha_short}</a>'
# Replace every BUILD_SHA marker in the file so all version
# labels (sidebar logo + About card) are stamped, not just
# the first one.
new_html = html.replace('<!-- BUILD_SHA -->', replacement)
if new_html == html:
print('WARNING: <!-- BUILD_SHA --> marker not found in index.html; badge not stamped')
with open('index.html', 'w', encoding='utf-8') as f:
f.write(new_html)
PY
- name: Stage static site
# Copy only the files the browser actually needs. Leaves tools/,
# docs/, .github/, package.json, node_modules/, etc. out of the
# Pages artifact so the public deploy is not bloated with Python
# scripts and CI config. The test/ self-test harness IS published
# (it's a static, dependency-free page) so module regressions can
# be checked in a real browser straight from the live deploy.
run: |
mkdir -p _site
cp index.html _site/
cp flasher.html _site/
cp privacy.html _site/
cp hubs.json _site/
cp -r css js lib test _site/
# .nojekyll disables Jekyll processing so GitHub Pages serves
# files with underscores and other Jekyll-hostile names.
touch _site/.nojekyll
- name: Mirror bridge binaries to Pages (stable download URLs)
# GitHub release assets are served from a shared host behind
# rotating SAS-token URLs, so the download URL changes every time
# — which means a SmartScreen "report as safe" can't attach to a
# fixed URL, and per-URL reputation never accrues. Mirror the
# latest bridge release into the Pages site under /bridge/ at a
# stable, version-independent path so the in-app download (and the
# URL users report to SmartScreen) never changes.
env:
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p _site/bridge
TAG=$(gh release list --repo "$GITHUB_REPOSITORY" --limit 200 --json tagName,createdAt \
-q 'map(select(.tagName|startswith("bridge-v"))) | sort_by(.createdAt) | last | .tagName')
if [ -z "$TAG" ] || [ "$TAG" = "null" ]; then
echo "::warning::no bridge-v* release found; /bridge/ download links will 404"
else
echo "Mirroring bridge release $TAG"
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir _site/bridge \
--pattern 'ws_bridge-*' --pattern 'SHA256SUMS.txt'
# Version-independent aliases so the in-app download URL is fixed
# across bridge releases (the versioned files stay too).
cd _site/bridge
for f in ws_bridge-*-windows-amd64.exe; do cp -f "$f" ws_bridge-windows-amd64.exe; done
for f in ws_bridge-*-linux-amd64; do cp -f "$f" ws_bridge-linux-amd64; done
for f in ws_bridge-*-darwin-arm64; do cp -f "$f" ws_bridge-darwin-arm64; done
ls -la
fi
- uses: actions/configure-pages@v6
- uses: actions/upload-pages-artifact@v5
with:
path: _site
- id: deployment
uses: actions/deploy-pages@v5
- name: Tag this deploy
# Runs after a successful Pages publish, so the tag only
# exists for builds that actually went live. Tag format is
# `v{package.json version}-{short SHA}` — semver-friendly,
# unique per commit, and matches the short SHA users see in
# the version badge, so a bug report carrying that hex
# string resolves to a real git ref immediately.
#
# Manually re-running the workflow on the same commit
# (workflow_dispatch) re-uses the same tag, so the push is
# skipped if the tag already exists on origin.
#
# Auth: actions/checkout@v4 has already configured git with
# a credential helper backed by the workflow's GITHUB_TOKEN,
# so `git push` just works as long as contents: write is
# declared in permissions above.
run: |
VERSION=$(node -p "require('./package.json').version")
SHORT_SHA=$(git rev-parse --short=7 HEAD)
TAG="v${VERSION}-${SHORT_SHA}"
echo "Proposed tag: ${TAG}"
if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q "${TAG}"; then
echo "Tag ${TAG} already exists on origin, skipping"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -a "${TAG}" -m "Auto-tag: deployed $(date -u +%Y-%m-%dT%H:%M:%SZ) to GitHub Pages"
git push origin "${TAG}"
echo "Pushed ${TAG}"