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
26 changes: 13 additions & 13 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# GitHub Actions workflows

This directory drives three kinds of automation: the **release pipeline** (tag → build → Pages → GitHub Release → stamped spec branch), **continuous deploy from `main`** (rolling docs site and unstamped spec branch), and **PR gating** (spec tests, docs smoke-build, spellcheck).
This directory drives three kinds of automation: the **release pipeline** (publish → build → GitHub Release → stamped spec branch → dispatch deploy pages to refresh), **continuous deploy from `main`**, and **PR gating** (spec tests, docs smoke-build, spellcheck).

## Workflows

- [release.yaml](release.yaml) — `release: published` or `workflow_dispatch`. Full release: build, version snapshot, Pages deploy, GitHub Release, stamped spec branch.
- [release.yaml](release.yaml) — `release: published` or `workflow_dispatch`. Full release: build, version snapshot, GitHub Release assets, stamped spec branch; dispatches [deploy.yaml](deploy.yaml) to refresh Pages (does not deploy Pages itself).

- [sync-release-notes.yaml](sync-release-notes.yaml) — `release: published|edited` or `workflow_dispatch`. Mirrors release notes into `docs-releases/` via PR.
- [publish-spec.yaml](publish-spec.yaml) — `workflow_dispatch` only. Manual recovery: re-push `assembled-spec` from existing release assets. The automatic stamped-spec publish is the `publish-spec` job inside [release.yaml](release.yaml) (`needs: github-release`).
- [deploy.yaml](deploy.yaml) — `push: main` or dispatch. Rolling Pages deploy + pushes `assembled-spec-main` (unstamped).
- [deploy.yaml](deploy.yaml) — `push: main` or dispatch (`/next` always tracks main; spec `info.version` stays unstamped `0.0.0`) + pushes `assembled-spec-main` (unstamped).
- [test.yaml](test.yaml) — push/PR. `make build`, speccheck, test filling, lint.
- [test-deploy.yaml](test-deploy.yaml) — PR to `main`. Smoke-builds the site with and without a synthesized version snapshot.
- [spellcheck.yaml](spellcheck.yaml) — push/PR. `rojopolis/spellcheck-github-actions`.
Expand All @@ -22,18 +22,19 @@ flowchart TD

subgraph releaseWf [release.yaml]
buildRelease[build-release]
deployPages[deploy-pages]
ghRelease[github-release]
publishSpec[publish-spec]
buildRelease --> deployPages
triggerDeploy[trigger-deploy]
buildRelease --> ghRelease
ghRelease --> publishSpec
ghRelease --> triggerDeploy
end

buildRelease -->|"docs-snapshot, openrpc.json, refs-openrpc.json"| artifacts[("Actions artifacts")]
deployPages --> pages[("GitHub Pages")]
ghRelease -->|"upload assets (additive)"| ghReleasePage[("GitHub Release")]
publishSpec -->|"force push"| assembledSpec[("assembled-spec branch")]
triggerDeploy -->|"gh workflow run deploy.yaml"| deployWf[deploy.yaml]
deployWf --> pages[("GitHub Pages")]

ghReleasePage -->|"release: published"| syncNotes[sync-release-notes.yaml]
syncNotes -->|"PR"| notesPR[("docs-releases/ PR")]
Expand All @@ -48,7 +49,7 @@ Versioned API docs on Pages are assembled from past release snapshots plus the c
```mermaid
flowchart LR
mainPush["push to main"] --> deployWf[deploy.yaml]
deployWf --> pagesMain[("Pages: /next + latest landing")]
deployWf --> pagesMain[("Pages: /next from main + latest landing")]
deployWf -->|"force push"| assembledMain[("assembled-spec-main (unstamped)")]

releasePublish2["release: published"] --> releaseWf2[release.yaml]
Expand All @@ -57,20 +58,18 @@ flowchart LR
ghRel -.->|"gh release download"| assembleScript["assemble-versions.js (MAX_VERSIONS=10)"]
assembleScript -->|"writes"| apiVersions[("api_versions.json + api_versioned_docs/version-X.Y.Z/")]
apiVersions -.-> deployWf
apiVersions -.-> releaseWf2
releaseWf2 -->|"trigger-deploy"| deployWf
```

## Maintainer runbook

### Cut a release

Cut a release `vX.Y.Z` (UI **Draft a new release**, or `gh release create vX.Y.Z`). Publishing the release triggers [release.yaml](release.yaml) automatically; no manual steps are required for Pages, the GitHub Release, or `assembled-spec`.
Cut a release `vX.Y.Z` (UI **Draft a new release**, or `gh release create vX.Y.Z`). Publishing the release triggers [release.yaml](release.yaml) automatically; no manual steps are required for the GitHub Release, `assembled-spec`, or Pages (the `trigger-deploy` job dispatches [deploy.yaml](deploy.yaml) after assets are attached).

### Automated Release Notes PR

NOTE: The release will then trigger a release notes PR. Because we publish the draft to NEXT, the actual commit sha of the repo doesn't change on tag push. This then can sometimes
not invalidate the cache. The subsequent automated PR that follows, forces the version and the release notes to invalidate the github pages CDN, when merged. This will guarantee that
the latest release invalidates the github pages cache and deploys.
NOTE: The release also triggers a release notes PR. [release.yaml](release.yaml) dispatches [deploy.yaml](deploy.yaml) after attaching the snapshot asset. The subsequent automated PR that follows, forces the version and the release notes to invalidate the github pages CDN, when merged. This will guarantee that the latest release invalidates the github pages cache and deploys.

### Re-run a release

Expand Down Expand Up @@ -99,7 +98,8 @@ Confirm `docs-snapshot-vX.Y.Z.tar.gz` exists on the GitHub Release for that tag.
## Contracts between jobs

- `build-release` uploads two artifacts: `openrpc-spec` (`openrpc.json` + `refs-openrpc.json`) and `docs-snapshot` (the `.tar.gz`). Both `github-release` and `publish-spec` download `openrpc-spec`; `github-release` also downloads `docs-snapshot`.
- `concurrency.group: "pages"` is shared with [deploy.yaml](deploy.yaml). Both set `cancel-in-progress: false`, so a release and an in-flight main deploy queue rather than cancel each other.
- [deploy.yaml](deploy.yaml) After `github-release` attaches assets, `trigger-deploy` runs `gh workflow run deploy.yaml --ref main`. `/next` is always built from main HEAD (unstamped `0.0.0`);
- `concurrency.group: "pages"` applies only to [deploy.yaml](deploy.yaml) (`cancel-in-progress: false`).
- `assembled-spec` is **stamped** (version baked in via `npm run spec:set-version`); `assembled-spec-main` is **unstamped** (rolling head of `main`). Consumers pin to one or the other deliberately.
- [sync-release-notes.yaml](sync-release-notes.yaml) keys its PR branch off `steps.sync.outputs.slug`—repeated edits to the same release update the same PR rather than spawning new ones.
- `release: published` (and `edited`) fires the sync-release-notes workflow in parallel with `release.yaml`; `github-release` attaches assets additively to the already-published release and does not draft/publish it.
7 changes: 1 addition & 6 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,10 @@ jobs:
- name: Install JS dependencies
run: npm ci

- name: Assemble versioned docs from releases
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: node scripts/assemble-versions.js

- name: Build docs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run build:docs
run: npm run build:docs:ci:deploy

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
Expand Down
35 changes: 12 additions & 23 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ on:

permissions:
contents: write
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build-release:
Expand Down Expand Up @@ -55,7 +49,7 @@ jobs:
# Spec is already built (make build) and stamped (spec:set-version).
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run docs:copy && npm run build:docusaurus
run: npm run build:docs:ci:release

- name: Snapshot versioned docs
run: |
Expand All @@ -65,11 +59,6 @@ jobs:
"api_versioned_docs/version-${VER}" \
"api_versioned_sidebars/version-${VER}-sidebars.json"

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: build

- name: Upload openrpc spec
uses: actions/upload-artifact@v4
with:
Expand All @@ -84,17 +73,6 @@ jobs:
name: docs-snapshot
path: docs-snapshot-*.tar.gz

deploy-pages:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build-release
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

github-release:
runs-on: ubuntu-latest
needs: build-release
Expand Down Expand Up @@ -151,3 +129,14 @@ jobs:
git add -f refs-openrpc.json
git commit -m "release ${TAG}"
git push -fu origin assembled-spec

trigger-deploy:
runs-on: ubuntu-latest
needs: github-release
permissions:
actions: write
steps:
- name: Refresh Pages from main
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh workflow run deploy.yaml --ref main --repo "$GITHUB_REPOSITORY"
1 change: 0 additions & 1 deletion .github/workflows/sync-release-notes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ jobs:
Source: ${{ steps.sync.outputs.html_url }}
After this PR is merged, edit the markdown directly via PR for any future fixes — no need to republish the GitHub Release.
The PR also forces a Pages cache invalidation, so the release is fully visible.
add-paths: |
docs-releases/**
delete-branch: true
15 changes: 14 additions & 1 deletion docs-releases/sidebars.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
import {readdirSync} from 'node:fs';
import {fileURLToPath} from 'node:url';
import semver from 'semver';

// Order release docs by descending semver precedence (newest on top). Built
// explicitly here rather than via sidebar_position frontmatter so arbitrary
// prereleases sort correctly and new release files are picked up automatically.
const dir = fileURLToPath(new URL('.', import.meta.url));
const releaseDocs = readdirSync(dir)
.filter((f) => f.endsWith('.md') && f !== 'index.md')
.map((f) => f.replace(/\.md$/, ''))
.filter((id) => semver.valid(id.replace(/^v/, '')))
.sort((a, b) => semver.rcompare(a, b));

const sidebars: SidebarsConfig = {
releasesSidebar: [{type: 'autogenerated', dirName: '.'}],
releasesSidebar: ['index', ...releaseDocs],
};

export default sidebars;
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
"build": "make build",
"build:spec": "make build",
"build:test": "make test",
"build:docs": "npm run build:spec && npm run docs:copy && npm run build:docusaurus",
"build:docs:core": "npm run docs:copy && npm run build:docusaurus",
"build:docs": "npm run build:spec && npm run build:docs:core",
"build:docs:ci": "node scripts/assemble-versions.js && npm run build:docs:core",
"build:docs:ci:deploy": "npm run build:spec && npm run build:docs:ci",
"build:docs:ci:release": "npm run build:docs:ci",
"lint": "npm run graphql:validate",
"clean": "rm -rf build && mkdir -p build",
"graphql:schema": "node scripts/graphql.js",
Expand Down
10 changes: 1 addition & 9 deletions scripts/sync-release-note.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { join } from "node:path";
import { argv, env, exit } from "node:process";


const flags = {};
for (let i = 2; i < argv.length; i++) {
const a = argv[i];
Expand All @@ -20,14 +21,6 @@ function slugify(s) {
return String(s).replace(/[^A-Za-z0-9.+-]/g, "-");
}

// this puts the newest releases first
function sidebarPos(t) {
const m = String(t).match(/^v?(\d+)\.(\d+)\.(\d+)/);
if (!m) return 0;
const [, maj, min, pat] = m.map(Number);
return -(maj * 1_000_000 + min * 1_000 + pat);
}

function escapeFrontmatter(s) {
return String(s).replace(/"/g, '\\"');
}
Expand Down Expand Up @@ -102,7 +95,6 @@ function buildMarkdown(r) {
"---",
`title: "${escapeFrontmatter(r.title)}"`,
`sidebar_label: "${escapeFrontmatter(r.tag)}"`,
`sidebar_position: ${sidebarPos(r.tag)}`,
`slug: /${slugify(r.tag)}`,
r.publishedAt ? `date: ${r.publishedAt}` : null,
"---",
Expand Down
Loading