Skip to content

fix(release): keep empty changelogs versioned #4

fix(release): keep empty changelogs versioned

fix(release): keep empty changelogs versioned #4

Workflow file for this run

name: CI
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]
permissions:
contents: write
concurrency:
# Release tags never cancel; ordinary CI is cancellable per ref.
group: ci-${{ github.ref }}
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/v') }}
jobs:
# ---------------------------------------------------------------------------
# PR + main branch: lint/typecheck (native-free) and the test suite.
# These never run on tags — a tag is cut from an already-green main.
# ---------------------------------------------------------------------------
check:
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3.14"
- name: Cache bun dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-1.3.14-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Lint and type check (native-free)
run: bun run ci:check:full
# ---------------------------------------------------------------------------
# PR + main branch: sharded full test suite. Unlike dev CI (changed-path
# affected), Main CI runs the COMPLETE task union via CI_FORCE_FULL. Long-tail
# tasks are sub-split (coding-agent tests 16-way, rust-test 4 nextest
# partitions) so no single shard dominates wall-time. The `test` aggregate job
# keeps the stable branch-protection status name.
# ---------------------------------------------------------------------------
main_plan:
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI_FORCE_FULL: "1"
CI_CODING_AGENT_TEST_SHARDS: "16"
CI_RUST_TEST_PARTITIONS: "4"
outputs:
matrix: ${{ steps.plan.outputs.matrix }}
has_tasks: ${{ steps.plan.outputs.has_tasks }}
has_native: ${{ steps.plan.outputs.has_native }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3.14"
- name: Compute full Main CI task matrix
id: plan
run: bun scripts/ci-dev-affected.ts --matrix-json
main_native:
if: ${{ !startsWith(github.ref, 'refs/tags/v') && needs.main_plan.outputs.has_native == 'true' }}
needs: [main_plan]
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3.14"
- name: Cache bun dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-1.3.14-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Build native addon (linux-x64 baseline + modern)
env:
TARGET_PLATFORM: linux
TARGET_ARCH: x64
TARGET_VARIANTS: baseline modern
run: bun run ci:build:native
- name: Verify required native addon variants
run: |
test -f packages/natives/native/pi_natives.linux-x64-baseline.node
test -f packages/natives/native/pi_natives.linux-x64-modern.node
- name: Upload native addon(s)
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: main-native-${{ github.run_id }}
path: |
packages/natives/native/pi_natives.linux-x64-baseline.node
packages/natives/native/pi_natives.linux-x64-modern.node
if-no-files-found: error
retention-days: 1
overwrite: true
main_shards:
name: test-shard / ${{ matrix.key }}
if: ${{ always() && !startsWith(github.ref, 'refs/tags/v') && needs.main_plan.outputs.has_tasks == 'true' && needs.main_native.result != 'failure' && needs.main_native.result != 'cancelled' }}
needs: [main_plan, main_native]
runs-on: ubuntu-22.04
timeout-minutes: ${{ matrix.rust && 90 || 60 }}
strategy:
fail-fast: false
max-parallel: 16
matrix: ${{ fromJSON(needs.main_plan.outputs.matrix) }}
env:
CI_FORCE_FULL: "1"
CI_CODING_AGENT_TEST_SHARDS: "16"
CI_RUST_TEST_PARTITIONS: "4"
AFFECTED_TASK_KEY: ${{ matrix.key }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3.14"
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
if: ${{ matrix.rust }}
with:
toolchain: nightly-2026-04-29
- uses: taiki-e/install-action@56545b37b57562edd73171cb6c62cc509db4c34e # v2
if: ${{ matrix.nextest }}
with:
tool: nextest@0.9.137
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
if: ${{ matrix.rust }}
with:
shared-key: main-rust-linux-x64
save-if: ${{ github.ref == 'refs/heads/main' }}
cache-workspace-crates: true
- name: Cache bun dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-1.3.14-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Download native addon(s)
if: ${{ matrix.native }}
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: main-native-${{ github.run_id }}
path: packages/natives/native
- name: Run task shard
env:
GITHUB_ACTIONS: ""
run: bun scripts/ci-dev-affected.ts --task="$AFFECTED_TASK_KEY"
# Branch protection must keep requiring this stable aggregate status.
test:
if: ${{ always() && !startsWith(github.ref, 'refs/tags/v') }}
needs: [main_plan, main_native, main_shards]
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Fail closed unless every shard succeeded
run: |
plan='${{ needs.main_plan.result }}'
native='${{ needs.main_native.result }}'
shards='${{ needs.main_shards.result }}'
echo "main_plan=$plan main_native=$native main_shards=$shards"
test "$plan" = success
case "$native" in success|skipped) ;; *) echo "native gate failed"; exit 1;; esac
test "$shards" = success
# ---------------------------------------------------------------------------
# Tag (vX.Y.Z) only: build native addons for every published platform,
# build the standalone binaries, then publish to npm and cut the GitHub
# Release. Self-contained — no dependency on a separate main CI run.
# ---------------------------------------------------------------------------
native:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
timeout-minutes: 90
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-22.04, platform: linux, arch: x64, variant: baseline, rust_checks: true }
- { os: ubuntu-22.04, platform: linux, arch: x64, variant: modern }
- { os: ubuntu-22.04, platform: linux, arch: arm64, target: aarch64-unknown-linux-gnu }
- { os: macos-14, platform: darwin, arch: arm64 }
- { os: macos-15-intel, platform: darwin, arch: x64, variant: baseline }
- { os: windows-latest, platform: win32, arch: x64, variant: baseline }
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: ./.github/actions/build-native
with:
hash: ${{ github.sha }}
platform: ${{ matrix.platform }}
arch: ${{ matrix.arch }}
variant: ${{ matrix.variant }}
target: ${{ matrix.target }}
rust_checks: ${{ matrix.rust_checks && 'true' || 'false' }}
save_cache: "true"
binaries:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [native]
timeout-minutes: 60
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-22.04, platform: linux, arch: x64, target_id: linux-x64, binary_path: packages/coding-agent/binaries/gjc-linux-x64 }
- { os: ubuntu-24.04-arm, platform: linux, arch: arm64, target_id: linux-arm64, binary_path: packages/coding-agent/binaries/gjc-linux-arm64 }
- { os: macos-14, platform: darwin, arch: arm64, target_id: darwin-arm64, binary_path: packages/coding-agent/binaries/gjc-darwin-arm64 }
- { os: macos-15-intel, platform: darwin, arch: x64, target_id: darwin-x64, binary_path: packages/coding-agent/binaries/gjc-darwin-x64 }
- { os: windows-latest, platform: win32, arch: x64, target_id: win32-x64, binary_path: packages/coding-agent/binaries/gjc-windows-x64.exe }
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3.14"
- name: Cache bun dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-1.3.14-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Download native addon(s)
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: pi-natives-${{ matrix.platform }}-${{ matrix.arch }}*
path: packages/natives/native
merge-multiple: true
- name: Build release binary
env:
RELEASE_TARGETS: ${{ matrix.target_id }}
run: bun run ci:release:build-binaries
- name: Smoke release binary
if: runner.os != 'Windows'
run: |
runtime_dir="$(mktemp -d)"
HOME="$runtime_dir/home" XDG_DATA_HOME="$runtime_dir/xdg" "${{ matrix.binary_path }}" --version
HOME="$runtime_dir/home" XDG_DATA_HOME="$runtime_dir/xdg" "${{ matrix.binary_path }}" --smoke-test
- name: Smoke release binary (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$runtimeDir = Join-Path $env:TEMP ("gjc-runtime-" + [System.Guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Force -Path $runtimeDir | Out-Null
$env:HOME = Join-Path $runtimeDir "home"
$env:XDG_DATA_HOME = Join-Path $runtimeDir "xdg"
& "${{ matrix.binary_path }}" --version
& "${{ matrix.binary_path }}" --smoke-test
- name: Upload release binary artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: gjc-binary-${{ matrix.target_id }}
path: ${{ matrix.binary_path }}
publish:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [native, binaries]
timeout-minutes: 45
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3.14"
- name: Cache bun dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-1.3.14-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Download all native addons
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: pi-natives-*
path: packages/natives/native
merge-multiple: true
- name: Publish packages to npm
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
shell: bash
run: |
set -euo pipefail
evidence_dir="$RUNNER_TEMP/release-evidence"
mkdir -p "$evidence_dir"
bun scripts/ci-release-publish.ts --prepare-evidence --evidence-dir "$evidence_dir"
npm_config="$(mktemp "$RUNNER_TEMP/npmrc.XXXXXX")"
trap 'rm -f "$npm_config"' EXIT
printf "//registry.npmjs.org/:_authToken=%s\n" "$NPM_TOKEN" > "$npm_config"
NPM_CONFIG_USERCONFIG="$npm_config" NODE_AUTH_TOKEN="$NPM_TOKEN" \
bun scripts/ci-release-publish.ts --publish-from-evidence \
--evidence-dir "$evidence_dir" \
--release-serialization-key gajae-production-release
- name: Download release binaries
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: gjc-binary-*
path: release-binaries
merge-multiple: true
- name: Create GitHub Release
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
with:
tag_name: ${{ github.ref_name }}
draft: false
prerelease: false
generate_release_notes: true
files: release-binaries/gjc-*