mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 00:25:34 +08:00
Add the agent-driven release process: docs, sync script, tag job
- RELEASING.md documents the lockstep three-package prepare flow and the marked-changelog convention - CHANGELOG.md starts with an Unreleased section and the marked 0.0.1 entry that becomes the GitHub release body - AGENTS.md states repo-wide build/test conventions and defers docs-site specifics to docs/AGENTS.md - scripts/sync-versions.mjs stamps runtime and compiler from the CLI version; the workflow's sync check now hints at it - release.yml gains a github-release job that tags v<version> after a successful publish, never gating npm
This commit is contained in:
@@ -81,7 +81,7 @@ jobs:
|
||||
# configured on npmjs.com with a GitHub Actions trusted publisher
|
||||
# pointing at repository vercel-labs/scriptc, workflow release.yml,
|
||||
# environment Release. A package missing that configuration fails
|
||||
# loudly with an OIDC authentication error before anything uploads.
|
||||
# with an OIDC authentication error before anything uploads.
|
||||
# Trusted publishing requires npm >= 11.5.1 (bundled with Node 24).
|
||||
|
||||
- name: Install and build
|
||||
@@ -96,6 +96,7 @@ jobs:
|
||||
V=$(node -p "require('./$pkg/package.json').version")
|
||||
if [ "$V" != "$VERSION" ]; then
|
||||
echo "Version mismatch: $pkg is $V, expected $VERSION"
|
||||
echo "Run 'node scripts/sync-versions.mjs' to stamp runtime and compiler from the CLI version, then commit"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
@@ -136,3 +137,49 @@ jobs:
|
||||
publish_dir packages/cli
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# The GitHub release is a tag and notes only — scriptc has no platform
|
||||
# binary assets to stage (programs compile on the user's machine) — so
|
||||
# it runs AFTER a successful npm publish and never gates it. The body is
|
||||
# the CHANGELOG.md block between the release:start/release:end markers,
|
||||
# which RELEASING.md keeps on the latest entry only.
|
||||
github-release:
|
||||
name: Create GitHub Release
|
||||
needs: [check-release, publish]
|
||||
if: needs.check-release.outputs.should_release == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract changelog entry
|
||||
run: |
|
||||
VERSION="${{ needs.check-release.outputs.version }}"
|
||||
awk '/<!-- release:start -->/{found=1; next} /<!-- release:end -->/{exit} found{print}' CHANGELOG.md > /tmp/release-notes.md
|
||||
|
||||
LINES=$(wc -l < /tmp/release-notes.md | tr -d ' ')
|
||||
if [ "$LINES" -lt 2 ]; then
|
||||
echo "Error: No release notes found between <!-- release:start --> and <!-- release:end --> markers in CHANGELOG.md"
|
||||
exit 1
|
||||
fi
|
||||
echo "Extracted release notes for $VERSION ($LINES lines)"
|
||||
|
||||
- name: Create GitHub Release
|
||||
run: |
|
||||
VERSION="${{ needs.check-release.outputs.version }}"
|
||||
TAG="v$VERSION"
|
||||
|
||||
if gh release view "$TAG" &>/dev/null; then
|
||||
echo "Release $TAG already exists, skipping"
|
||||
else
|
||||
echo "Creating release $TAG..."
|
||||
gh release create "$TAG" \
|
||||
--target "$GITHUB_SHA" \
|
||||
--title "$TAG" \
|
||||
--notes-file /tmp/release-notes.md
|
||||
fi
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Agent Guide
|
||||
|
||||
Guidance for agents (and humans) working on this repository. These conventions apply repo-wide; the docs site under `docs/` additionally has its own conventions in `docs/AGENTS.md`.
|
||||
|
||||
## Build and test
|
||||
|
||||
```bash
|
||||
pnpm install && pnpm -r build # build the workspace
|
||||
SCRIPTC_TEST_WORKERS=4 pnpm test # plain lane: differential corpus + diagnostics snapshots
|
||||
SCRIPTC_SAN=1 pnpm test # sanitized lane: the same corpus under ASan + refcount audit
|
||||
```
|
||||
|
||||
Both lanes green is the bar before shipping any change. `SCRIPTC_TEST_WORKERS` caps the vitest worker pool so concurrent agents don't contend for cores; full-suite runs also queue behind an advisory lock per lane.
|
||||
|
||||
Corpus programs are differential tests against Node: every program runs under Node and as a compiled native binary, and stdout, stderr, and exit codes must match byte-for-byte. A new feature lands with corpus programs that pin its behavior both ways.
|
||||
|
||||
## Where things live
|
||||
|
||||
- `packages/compiler` — the frontend (tsc API to IR), the typed IR with validator and serializer, and the LLVM and C backends.
|
||||
- `packages/runtime` — the C runtime compiled into every scriptc binary.
|
||||
- `packages/cli` — `scriptc build | run | coverage`.
|
||||
- `tests/` — the differential corpus, diagnostics snapshots, and the harness.
|
||||
- `docs/` — the documentation site (standalone pnpm workspace); see `docs/AGENTS.md`.
|
||||
- `scripts/` — repo tooling, including the release version stamp.
|
||||
|
||||
## Releases
|
||||
|
||||
Releases are maintainer-run; see [RELEASING.md](./RELEASING.md).
|
||||
@@ -0,0 +1,22 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to scriptc will be documented in this file.
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.0.1
|
||||
|
||||
<!-- release:start -->
|
||||
|
||||
The first release: `scriptc` on npm, with `@scriptc/compiler` and `@scriptc/runtime` underneath it.
|
||||
|
||||
### Features
|
||||
|
||||
- **The CLI**: `scriptc build` compiles a TypeScript or JavaScript entry point into a self-contained native executable, `scriptc run` builds and runs it in one step, and `scriptc coverage` reports statement by statement what compiles statically and which specific constructs block, each with a diagnostic code.
|
||||
- **The static tier**: programs compile to native code with no JavaScript engine in the binary. Type checking is the real TypeScript compiler; what compiles behaves byte-for-byte like Node, enforced by a differential test corpus.
|
||||
- **`--dynamic`**: an embedded JavaScript engine (quickjs-ng) executes what cannot compile statically. Values crossing back into static code are validated at runtime, so a mismatched type throws a catchable `TypeError`. Static remains the default; a binary never silently grows an engine.
|
||||
- **npm dependencies** (with `--dynamic`): packages resolve with Node's own resolution algorithm, typecheck against their shipped `.d.ts`, and their JavaScript is embedded into the binary at build time. Binaries never read `node_modules` at runtime.
|
||||
- **Platforms**: macOS arm64 is the primary platform; Linux and Windows binaries build by cross-compilation, each verified by its own differential test lane.
|
||||
- **Documentation** at [scriptc.dev](https://scriptc.dev).
|
||||
|
||||
<!-- release:end -->
|
||||
@@ -0,0 +1,18 @@
|
||||
# Releasing
|
||||
|
||||
Releases are manual, single-commit affairs. The maintainer controls the changelog voice and format. The three npm packages — `@scriptc/runtime`, `@scriptc/compiler`, `scriptc` — always publish together at the same version.
|
||||
|
||||
To prepare a release:
|
||||
|
||||
1. Bump the version in `packages/cli/package.json`
|
||||
2. Run `node scripts/sync-versions.mjs` to stamp the same version into `packages/runtime` and `packages/compiler`
|
||||
3. Fold the `## Unreleased` section of `CHANGELOG.md` into a new `## <version>` entry (newest first, below `## Unreleased`), and leave `## Unreleased` empty for the next cycle
|
||||
4. Wrap the new entry in `<!-- release:start -->` and `<!-- release:end -->` markers; this marked block is also the GitHub release body
|
||||
5. Remove the `<!-- release:start -->` and `<!-- release:end -->` markers from the previous release entry; only the latest release should have markers
|
||||
6. Commit to `main`
|
||||
|
||||
CI (`.github/workflows/release.yml`) compares the version in `packages/cli/package.json` to what `scriptc` has on npm. If it differs, it builds the workspace, verifies all three package versions match (a mismatch fails with a hint to run `scripts/sync-versions.mjs`), and publishes to npm in dependency order — `@scriptc/runtime`, then `@scriptc/compiler`, then `scriptc` — so each package's dependencies are resolvable the moment it lands. After the publish succeeds, a separate job creates the git tag `v<version>` and the GitHub release with the marked changelog entry as its body.
|
||||
|
||||
Two deliberate differences from repositories that ship prebuilt binaries: there are no platform binary assets to build or stage — scriptc compiles programs on the user's machine with the local clang — so the GitHub release is a tag and release notes only, and the npm publish never waits on the GitHub release (the release job runs after the publish, not before it).
|
||||
|
||||
Publishing uses npm trusted publishing (OIDC) — there is no npm token secret. The one-time setup is already done: each of the three packages is configured on npmjs.com with a GitHub Actions trusted publisher pointing at repository `vercel-labs/scriptc`, workflow `release.yml`, environment `Release`. A package missing that configuration fails with an OIDC authentication error before anything is uploaded. Re-runs are safe: any package already on the registry at the target version is skipped, so a partially published release can be resumed by re-running the workflow.
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env node
|
||||
// Stamps the version from packages/cli/package.json into packages/runtime
|
||||
// and packages/compiler, so the three published packages move in lockstep.
|
||||
// Usage: node scripts/sync-versions.mjs
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = fileURLToPath(new URL("..", import.meta.url));
|
||||
const manifest = (pkg) => `${root}packages/${pkg}/package.json`;
|
||||
const read = (path) => JSON.parse(readFileSync(path, "utf8"));
|
||||
|
||||
const version = read(manifest("cli")).version;
|
||||
if (typeof version !== "string" || version.length === 0) {
|
||||
console.error("packages/cli/package.json has no version");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (const pkg of ["runtime", "compiler"]) {
|
||||
const path = manifest(pkg);
|
||||
const json = read(path);
|
||||
if (json.version === version) {
|
||||
console.log(`packages/${pkg}: already ${version}`);
|
||||
continue;
|
||||
}
|
||||
console.log(`packages/${pkg}: ${json.version} -> ${version}`);
|
||||
json.version = version;
|
||||
writeFileSync(path, JSON.stringify(json, null, 2) + "\n");
|
||||
}
|
||||
Reference in New Issue
Block a user