test: global preload resets process-global gate state per test, fixin… #4
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| permissions: | |
| contents: write | |
| jobs: | |
| test: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Cache bun install | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} | |
| restore-keys: | | |
| bun-${{ runner.os }}- | |
| - name: Install dependencies (frozen lockfile) | |
| # Frozen so CI-green == what ships. A frozen install does NOT re-resolve | |
| # versions, so bunfig.toml's minimumReleaseAge age-gate never blocks it | |
| # (that gate only applies to NEW resolutions, not to replaying bun.lock). | |
| run: bun install --frozen-lockfile | |
| - name: Patch Bun-incompatible dependencies | |
| run: node scripts/patches/patch-mastra.cjs | |
| - name: Run tests | |
| run: bun test | |
| - name: Run broker conformance matrix | |
| run: bun run test:broker-conformance | |
| - name: Run broker latency quality gate | |
| run: bun run quality:brokers | |
| - name: Run typecheck | |
| run: bun run typecheck | |
| verify-npm-wrapper: | |
| name: Verify npm Wrapper (${{ matrix.os }}) | |
| needs: test | |
| runs-on: ${{ matrix.os }} | |
| env: | |
| GORDON_NPM_VERSION: ${{ github.ref_name }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: | |
| - ubuntu-latest | |
| - macos-latest | |
| - windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Prepare npm wrapper | |
| run: npm run prepare:npm-wrapper | |
| - name: Check npm wrapper | |
| run: npm run check:npm-wrapper | |
| - name: Smoke test npm wrapper | |
| run: npm run smoke:npm-wrapper | |
| - name: Audit npm pack contents (no source files, no .map) | |
| run: node scripts/npm/audit-npm-pack.cjs | |
| - name: Audit npm pack content for credential leaks | |
| if: matrix.os == 'ubuntu-latest' | |
| run: node scripts/npm/audit-npm-pack-content.cjs | |
| - name: Source map guardrail (block sourcemap leak) | |
| run: node scripts/build/check-no-sourcemaps.cjs | |
| verify-public-dist: | |
| name: Verify Public Dist Bundle | |
| needs: test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Prepare public dist bundle | |
| run: node scripts/build/prepare-public-dist.cjs --out-dir .public-dist | |
| - name: Verify public dist bundle | |
| run: | | |
| test -f .public-dist/README.md | |
| test -f .public-dist/install.sh | |
| test -f .public-dist/install.ps1 | |
| test -f .public-dist/Formula/gordon.rb | |
| test -f .public-dist/bucket/gordon.json | |
| create-source-release: | |
| name: Create Source Release | |
| needs: | |
| - test | |
| - verify-npm-wrapper | |
| - verify-public-dist | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Generate CycloneDX SBOM | |
| # Software Bill of Materials attached to every release. CycloneDX 1.5 JSON. | |
| run: | | |
| npm install --package-lock-only --ignore-scripts | |
| node scripts/dev/codegen/generate-sbom.cjs --output gordon-sbom.json | |
| - name: Create or update GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| generate_release_notes: true | |
| files: gordon-sbom.json | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build: | |
| name: Build ${{ matrix.target }} | |
| needs: | |
| - create-source-release | |
| runs-on: ${{ matrix.os }} | |
| # Experimental targets (windows-arm64) may fail without blocking the | |
| # release. Under the optionalDependencies model this is fully non-blocking: | |
| # a missing platform sub-package just isn't published, and the launcher | |
| # degrades gracefully on that host instead of crashing. | |
| continue-on-error: ${{ matrix.experimental == true }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Standard glibc Linux | |
| - target: linux-x64 | |
| bun_target: bun-linux-x64 | |
| os: ubuntu-latest | |
| binary_name: gordon-linux-x64 | |
| - target: linux-arm64 | |
| bun_target: bun-linux-arm64 | |
| os: ubuntu-latest | |
| binary_name: gordon-linux-arm64 | |
| # Alpine / musl Linux (separate libc — glibc binaries crash on Alpine) | |
| - target: linux-x64-musl | |
| bun_target: bun-linux-x64-musl | |
| os: ubuntu-latest | |
| binary_name: gordon-linux-x64-musl | |
| - target: linux-arm64-musl | |
| bun_target: bun-linux-arm64-musl | |
| os: ubuntu-latest | |
| binary_name: gordon-linux-arm64-musl | |
| # macOS | |
| - target: darwin-x64 | |
| bun_target: bun-darwin-x64 | |
| os: macos-latest | |
| binary_name: gordon-darwin-x64 | |
| - target: darwin-arm64 | |
| bun_target: bun-darwin-arm64 | |
| os: macos-latest | |
| binary_name: gordon-darwin-arm64 | |
| # Windows — both architectures | |
| - target: windows-x64 | |
| bun_target: bun-windows-x64 | |
| os: windows-latest | |
| binary_name: gordon-windows-x64.exe | |
| - target: windows-arm64 | |
| bun_target: bun-windows-arm64 | |
| os: windows-latest | |
| binary_name: gordon-windows-arm64.exe | |
| experimental: true | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Cache bun install | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} | |
| restore-keys: | | |
| bun-${{ runner.os }}- | |
| - name: Install dependencies (frozen lockfile) | |
| run: bun install --frozen-lockfile | |
| - name: Patch Bun-incompatible dependencies | |
| run: node scripts/patches/patch-mastra.cjs | |
| - name: Build binary | |
| # Cross-compile through scripts/build/build.ts so the shipped binary | |
| # carries the exact EXTERNALS list a local `bun run build:binary` uses | |
| # (no CI-vs-local drift). Retry: Bun's cross-compile runtime download is | |
| # occasionally truncated on windows-arm64; the fix is just to try again. | |
| shell: bash | |
| run: | | |
| set -e | |
| attempt=1 | |
| max=3 | |
| until bun scripts/build/build.ts --binary \ | |
| --target ${{ matrix.bun_target }} \ | |
| --outfile ${{ matrix.binary_name }}; do | |
| if [ $attempt -ge $max ]; then | |
| echo "Build failed after $attempt attempts" | |
| exit 1 | |
| fi | |
| echo "Build attempt $attempt failed, retrying..." | |
| attempt=$((attempt + 1)) | |
| sleep 10 | |
| done | |
| - name: Upload binary artifact | |
| # Build-once, promote: the publish job downloads these artifacts rather | |
| # than rebuilding. Also uploaded to the GH Release below for the | |
| # direct-binary channel (install.sh / Homebrew / Scoop). | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: binary-${{ matrix.target }} | |
| path: ${{ matrix.binary_name }} | |
| if-no-files-found: error | |
| retention-days: 1 | |
| - name: Upload binary to release | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| & gh release upload "${env:GITHUB_REF_NAME}" "${{ matrix.binary_name }}#${{ matrix.binary_name }}" --clobber | |
| publish: | |
| name: Stage + Publish | |
| needs: build | |
| runs-on: ubuntu-latest | |
| # id-token: write enables OIDC so `npm publish --provenance` signs each | |
| # tarball (root wrapper + every platform sub-package) with SLSA Build L3 | |
| # attestations. contents: write is for the manifest commit + SHA256SUMS | |
| # asset upload. | |
| permissions: | |
| id-token: write | |
| contents: write | |
| env: | |
| VERSION: ${{ github.ref_name }} | |
| steps: | |
| - name: Checkout source repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| registry-url: https://registry.npmjs.org | |
| - name: Download built binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist-assets | |
| pattern: binary-* | |
| merge-multiple: true | |
| - name: Stage per-platform npm sub-packages | |
| # Generates one @general-liquidity/gordon-<target> package dir per | |
| # available binary + a manifest with per-asset sha256. Missing targets | |
| # (e.g. a failed windows-arm64) are simply skipped, not fatal. | |
| run: | | |
| node scripts/npm/stage-platform-packages.cjs \ | |
| --binaries dist-assets \ | |
| --out staging \ | |
| --version "${VERSION}" \ | |
| --manifest staging/manifest.json | |
| - name: Wire per-asset hashes into Formula / Scoop / SHA256SUMS | |
| # Deterministic, asset-name-keyed (replaces the fragile ordered-sed): | |
| # correct per-arch hashes, no x64/arm64 reuse. | |
| run: node scripts/npm/apply-release-hashes.cjs --manifest staging/manifest.json --version "${VERSION}" | |
| - name: Prepare npm wrapper metadata | |
| env: | |
| GORDON_NPM_VERSION: ${{ github.ref_name }} | |
| run: npm run prepare:npm-wrapper | |
| - name: Resolve source branch | |
| run: | | |
| SOURCE_BRANCH=$(git branch -r --contains "${GITHUB_SHA}" | grep -v HEAD | sed 's|origin/||' | grep '^v' | head -1 | xargs) | |
| if [ -z "${SOURCE_BRANCH}" ]; then | |
| SOURCE_BRANCH=$(git branch -r --contains "${GITHUB_SHA}" | grep -v HEAD | sed 's|origin/||' | head -1 | xargs) | |
| fi | |
| if [ -z "${SOURCE_BRANCH}" ]; then | |
| SOURCE_BRANCH="main" | |
| fi | |
| echo "SOURCE_BRANCH=${SOURCE_BRANCH}" >> "$GITHUB_ENV" | |
| git checkout "${SOURCE_BRANCH}" | |
| - name: Commit source manifest updates | |
| run: | | |
| git config user.name "Tiberiu Toca" | |
| git config user.email "tibi.toca@gmail.com" | |
| git add Formula/gordon.rb scripts/scoop/gordon.json scripts/SHA256SUMS npm/package.json npm/README.md npm/LICENSE | |
| git diff --cached --quiet || git commit -m "chore: publish assets for ${VERSION}" | |
| git push origin "HEAD:${SOURCE_BRANCH}" | |
| - name: Upload SHA256SUMS to release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: gh release upload "${VERSION}" scripts/SHA256SUMS#SHA256SUMS --clobber | |
| - name: Determine npm dist-tag | |
| id: dist-tag | |
| run: | | |
| # Pre-release tags (v0.1.0-alpha.1, -beta, -rc, -friends) publish to a | |
| # side channel so `npm install -g @general-liquidity/gordon` (which | |
| # resolves @latest) never picks them up. Clean tags go to @latest. | |
| if echo "${{ github.ref_name }}" | grep -qE 'friends|alpha|beta|rc'; then | |
| echo "tag=next" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "tag=latest" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Publish platform sub-packages to npm | |
| # Sub-packages FIRST so the root wrapper's optionalDependencies already | |
| # resolve on the registry when it publishes. Each gets its own provenance | |
| # attestation. A publish failure of one target should not silently pass — | |
| # but a target that was never staged simply has no dir to iterate. | |
| working-directory: staging/@general-liquidity | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: | | |
| set -e | |
| for dir in */; do | |
| pkg="${dir%/}" | |
| echo "Publishing @general-liquidity/${pkg}..." | |
| ( cd "${pkg}" && npm publish --access public --provenance --tag "${{ steps.dist-tag.outputs.tag }}" ) | |
| done | |
| - name: Publish root wrapper to npm | |
| working-directory: npm | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: npm publish --access public --provenance --tag "${{ steps.dist-tag.outputs.tag }}" |