Skip to content
Merged
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
151 changes: 151 additions & 0 deletions .github/workflows/tag-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
name: Tag release

on:
push:
tags:
- "v*"

permissions: {}

concurrency:
group: tag-release-${{ github.ref }}
cancel-in-progress: false

env:
BUN_VERSION: "1.3.14"

jobs:
prepare-release:
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 1
persist-credentials: false

- name: Create draft GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="$GITHUB_REF_NAME"
if gh release view "$tag" >/dev/null 2>&1; then
echo "GitHub release ${tag} already exists; keeping it"
else
gh release create "$tag" \
--target "$GITHUB_SHA" \
--title "$tag" \
--generate-notes \
--draft \
--verify-tag
fi

build-release:
name: build ${{ matrix.target }}
needs: prepare-release
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- target: darwin-arm64
runner: macos-15
bun-target: bun-darwin-arm64
output: opencodex-darwin-arm64
- target: darwin-x64
runner: macos-15-intel
bun-target: bun-darwin-x64
output: opencodex-darwin-x64
- target: linux-x64
runner: ubuntu-latest
bun-target: bun-linux-x64
output: opencodex-linux-x64
- target: linux-arm64
runner: ubuntu-24.04-arm
bun-target: bun-linux-arm64
output: opencodex-linux-arm64
- target: windows-x64
runner: windows-latest
bun-target: bun-windows-x64
output: opencodex-windows-x64.exe
- target: windows-arm64
runner: windows-11-arm
bun-target: bun-windows-arm64
output: opencodex-windows-arm64.exe
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 1
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: ${{ env.BUN_VERSION }}

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Build release binary
shell: bash
env:
TARGET: ${{ matrix.bun-target }}
OUTPUT: ${{ matrix.output }}
run: |
set -euo pipefail
release_dir="$GITHUB_WORKSPACE/dist/release"
mkdir -p "$release_dir"
out="$release_dir/$OUTPUT"
bun build --compile src/cli/index.ts --target "$TARGET" --outfile "$out"
if [[ "$RUNNER_OS" != "Windows" ]]; then
chmod +x "$out"
fi
if command -v file >/dev/null 2>&1; then
file "$out"
fi

- name: Upload build artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ${{ matrix.target }}
path: dist/release/${{ matrix.output }}
if-no-files-found: error

publish-release:
name: publish release assets
needs: build-release
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
- name: Download build artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
merge-multiple: true

- name: Upload assets and checksums
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
cd dist
shopt -s nullglob
assets=(opencodex-*)
if [[ ${#assets[@]} -ne 6 ]]; then
printf 'expected six release binaries, found %s\n' "${#assets[@]}" >&2
printf '%s\n' "${assets[@]}" >&2
exit 1
fi
sha256sum "${assets[@]}" | sort -k2 > checksums.txt
gh release upload "$GITHUB_REF_NAME" "${assets[@]}" checksums.txt --clobber
gh release edit "$GITHUB_REF_NAME" --draft=false
14 changes: 14 additions & 0 deletions structure/06_docs-and-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ bun run build
| --- | --- | --- |
| `.github/workflows/ci.yml` | `pull_request` to `main`/`dev`, `push` to `main`/`preview`/`dev`, or manual dispatch when runtime/package paths change | Cross-platform runtime/package quality gate. Linux runs the suite as four parallel shards (`test 1/4`–`4/4`) plus a consolidated `gates` job; macOS runs the full suite. Windows runs the full suite only on a `push` to `main`/`preview` or a manual dispatch — it is the shipping boundary, not the pull-request lane, because it was last to finish in every sampled run at roughly three times the Linux median. The aggregate `ci` job asserts `platform-windows` actually succeeded on those boundary events rather than accepting a skip. `npm-global-smoke` always remains GitHub-hosted because it mutates the global package prefix. |
| `.github/workflows/release.yml` | Manual dispatch only | npm publish/dry-run workflow. It requires the exact `GITHUB_SHA` to have a successful Cross-platform CI run before publish or dry-run. |
| `.github/workflows/tag-release.yml` | `push` of a `v*` tag | Creates a draft GitHub Release, compiles standalone Bun binaries for macOS, Linux, and Windows on x64 and arm64 runners, uploads the six assets, publishes SHA-256 checksums, and then makes the release public. |
| `.github/workflows/deploy-docs.yml` | `push` to `main` touching `docs-site/**` or the workflow, or manual dispatch | Build and publish the Astro/Starlight docs site to GitHub Pages. |
| `.github/workflows/service-lifecycle.yml` | `pull_request` to `main`/`dev` and `push`, both filtered on the service path set (`src/service.ts`, `src/cli.ts`, `src/cli/index.ts`, `src/lib/bun-runtime.ts`, `package.json`, `bun.lock`, the workflow), or manual dispatch | Service-lifecycle smoke on three platforms: Linux systemd, macOS launchd, and Windows Scheduled Tasks. Each installs, verifies, stops via `ocx stop`, and uninstalls. The path list is kept in sync with the `release.yml` service-gate regex. |
| `.github/workflows/enforce-pr-target.yml` | `pull_request_target` (opened, reopened, edited, labeled, unlabeled, ready_for_review, synchronize) plus default-branch `status` events filtered to successful `CodeRabbit` statuses | The `enforce-target` gate: rejects pull requests whose head ancestry sits on the `main` tip while far behind `dev`, rejects empty or malformed descriptions, requires a GUI screenshot when the title/body mentions `gui` (immediately waivable with the maintainer-controlled `gui-screenshot-waived` label; legacy maintainer comments remain compatibility evidence on later PR events), keeps contributor PRs in draft until a four-box readiness checklist is complete, verifies the CI / latest-dev / Codex+CodeRabbit-findings claims (review threads plus current-head CodeRabbit review-body findings outside the diff range), and adds a `review-ready` status label at the ready moment. CodeRabbit status SHAs must resolve to exactly one open current-head PR before writes. Stacked child PRs targeting another open PR's head skip the wrong-base gate. |
Expand Down Expand Up @@ -253,3 +254,16 @@ The Release workflow remains manual and publish-focused. Before any dry-run or p
checks that the exact release commit (`GITHUB_SHA`) already has a successful Cross-platform CI run.
This keeps release runs short and makes release a deployment of a verified commit rather than a
second CI pipeline.

### Standalone binary releases

Push a version tag after the release commit is ready:

```bash
git tag v<version>
git push origin v<version>
```

The tag workflow publishes `opencodex-{darwin,linux,windows}-{x64,arm64}` binaries and a
`checksums.txt` asset to the matching GitHub Release. npm publishing remains controlled by the
manual `release.yml` workflow.