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
97 changes: 73 additions & 24 deletions .github/workflows/codra-cli-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,77 @@ on:
description: Publish @codra/cli to npm (requires NPM_TOKEN secret)
type: boolean
default: false
include_darwin_x64:
description: Include Intel macOS darwin-x64 build (macos-13; can queue for a long time)
type: boolean
default: false
allow_partial_binaries:
description: Package only available artifacts. Dry runs (publish=false) allow partial by default; publish=true requires full set unless this is true
type: boolean
default: false

jobs:
resolve-matrix:
name: Resolve release matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
expected_platforms: ${{ steps.set-matrix.outputs.expected_platforms }}
allow_partial: ${{ steps.set-matrix.outputs.allow_partial }}
expect_all_pack: ${{ steps.set-matrix.outputs.expect_all_pack }}
steps:
- name: Compute matrix and packaging policy
id: set-matrix
env:
INCLUDE_DARWIN_X64: ${{ inputs.include_darwin_x64 }}
PUBLISH: ${{ inputs.publish }}
ALLOW_PARTIAL_BINARIES: ${{ inputs.allow_partial_binaries }}
run: |
python3 <<'PY'
import json
import os

include_darwin_x64 = os.environ.get("INCLUDE_DARWIN_X64", "false").lower() == "true"
publish = os.environ.get("PUBLISH", "false").lower() == "true"
allow_partial_input = os.environ.get("ALLOW_PARTIAL_BINARIES", "false").lower() == "true"

matrix_include = [
{"target": "linux-x64", "os": "ubuntu-latest", "artifact": "codra-linux-x64", "bin_name": "codra"},
{"target": "linux-arm64", "os": "ubuntu-24.04-arm", "artifact": "codra-linux-arm64", "bin_name": "codra"},
{"target": "darwin-arm64", "os": "macos-14", "artifact": "codra-darwin-arm64", "bin_name": "codra"},
{"target": "win32-x64", "os": "windows-latest", "artifact": "codra-win32-x64.exe", "bin_name": "codra.exe"},
]
if include_darwin_x64:
matrix_include.append(
{
"target": "darwin-x64",
"os": "macos-13",
"artifact": "codra-darwin-x64",
"bin_name": "codra",
}
)

platforms = [entry["target"] for entry in matrix_include]
# publish=false dry runs may package partial binaries; publish=true requires full set unless opted in
allow_partial = (not publish) or allow_partial_input
expect_all_pack = publish and (not allow_partial_input)

github_output = os.environ["GITHUB_OUTPUT"]
with open(github_output, "a", encoding="utf-8") as handle:
handle.write(f"matrix={json.dumps({'include': matrix_include})}\n")
handle.write(f"expected_platforms={','.join(platforms)}\n")
handle.write(f"allow_partial={'1' if allow_partial else '0'}\n")
handle.write(f"expect_all_pack={'1' if expect_all_pack else '0'}\n")
PY

build-binaries:
name: build ${{ matrix.target }}
needs: resolve-matrix
runs-on: ${{ matrix.os }}
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- target: linux-x64
os: ubuntu-latest
artifact: codra-linux-x64
bin_name: codra
- target: linux-arm64
os: ubuntu-24.04-arm
artifact: codra-linux-arm64
bin_name: codra
- target: darwin-x64
os: macos-13
artifact: codra-darwin-x64
bin_name: codra
- target: darwin-arm64
os: macos-14
artifact: codra-darwin-arm64
bin_name: codra
- target: win32-x64
os: windows-latest
artifact: codra-win32-x64.exe
bin_name: codra.exe
matrix: ${{ fromJSON(needs.resolve-matrix.outputs.matrix) }}

steps:
- name: Check out repository
Expand Down Expand Up @@ -67,7 +109,7 @@ jobs:

package-npm:
name: Package @codra/cli npm tarball
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Let dry-run packaging execute after failed shards

Under GitHub Actions needs semantics, if any selected build-binaries matrix job times out or fails, package-npm is skipped unless the job has an if condition such as always(). That means the new dry-run partial-binary mode never gets a chance to package the artifacts from successful shards, so a scarce runner timeout still aborts verification instead of producing the intended partial tarball.

Useful? React with 👍 / 👎.

needs: build-binaries
needs: [resolve-matrix, build-binaries]
runs-on: ubuntu-latest

steps:
Expand All @@ -91,6 +133,7 @@ jobs:
env:
CODRA_USE_ARTIFACTS: '1'
CODRA_ARTIFACTS_DIR: ${{ github.workspace }}/packages/codra-npm-cli/artifacts
CODRA_ALLOW_PARTIAL_BINARIES: ${{ needs.resolve-matrix.outputs.allow_partial }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Align publish packaging with the selected matrix

When publish=true and the default include_darwin_x64=false is used, this passes CODRA_ALLOW_PARTIAL_BINARIES=0 into build-platform-binaries.js, whose TARGETS array still includes codra-darwin-x64; because that artifact was never built/downloaded, the package job exits before validation/publish. This contradicts the new selected-matrix policy and makes the default guarded publish path unusable unless maintainers either include the scarce Intel macOS runner or explicitly allow a partial publish.

Useful? React with 👍 / 👎.

run: npm run build:from-artifacts

- name: Test npm wrapper
Expand All @@ -100,14 +143,15 @@ jobs:
- name: Validate npm pack contents
working-directory: packages/codra-npm-cli
env:
CODRA_EXPECT_ALL_PLATFORMS: '1'
CODRA_EXPECT_PLATFORMS: ${{ needs.resolve-matrix.outputs.expect_all_pack == '1' && needs.resolve-matrix.outputs.expected_platforms || '' }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve partial mode during pack validation

In the default dry-run path (publish=false, include_darwin_x64=false), the earlier artifact packaging step succeeds with CODRA_ALLOW_PARTIAL_BINARIES=1, but npm test later removes bin/native and rebuilds only the host binary; this validation step then runs npm pack --dry-run, whose prepack sees the downloaded artifacts directory and invokes build-platform-binaries.js without the partial flag. Since codra-darwin-x64 was intentionally not built, validation fails before the tarball can be checked, so the new default dry run is still blocked by the optional Intel macOS artifact.

Useful? React with 👍 / 👎.

run: npm run pack:dry

- name: Build npm tarball (no publish)
working-directory: packages/codra-npm-cli
env:
CODRA_USE_ARTIFACTS: '1'
CODRA_ARTIFACTS_DIR: ${{ github.workspace }}/packages/codra-npm-cli/artifacts
CODRA_ALLOW_PARTIAL_BINARIES: ${{ needs.resolve-matrix.outputs.allow_partial }}
run: npm pack

- name: Upload npm tarball artifact
Expand All @@ -124,9 +168,14 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
CODRA_USE_ARTIFACTS: '1'
CODRA_ARTIFACTS_DIR: ${{ github.workspace }}/packages/codra-npm-cli/artifacts
CODRA_ALLOW_PARTIAL_BINARIES: ${{ inputs.allow_partial_binaries == true && '1' || '' }}
CODRA_EXPECT_PLATFORMS: ${{ inputs.allow_partial_binaries != true && needs.resolve-matrix.outputs.expected_platforms || '' }}
run: |
if [ -z "$NODE_AUTH_TOKEN" ]; then
echo "NPM_TOKEN secret is required when publish=true"
exit 1
fi
if [ "${{ inputs.allow_partial_binaries }}" != "true" ]; then
CODRA_ALLOW_PARTIAL_BINARIES=0 node scripts/build-platform-binaries.js
fi
npm publish --access public
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ npm install -g @codra/cli # coming soon
codra run --task summarize-context --jsonl
```

The [`@codra/cli`](packages/codra-npm-cli/) package is a thin Node wrapper that spawns the native `codra` binary built from `codra-cli`. Multi-platform npm distribution is in progress (linux/macOS/Windows targets); a manual [release workflow](.github/workflows/codra-cli-release.yml) packages all platform binaries before publish (see [packages/codra-npm-cli/README.md](packages/codra-npm-cli/README.md)).
The [`@codra/cli`](packages/codra-npm-cli/) package is a thin Node wrapper that spawns the native `codra` binary built from `codra-cli`. Multi-platform npm distribution is in progress (linux/macOS/Windows targets); a manual [release workflow](.github/workflows/codra-cli-release.yml) packages platform binaries before publish. Intel macOS (`darwin-x64`) is optional in dry runs because `macos-13` runners can queue for a long time; npm publish stays guarded and off by default (see [packages/codra-npm-cli/README.md](packages/codra-npm-cli/README.md)).

## Roadmap

Expand Down
17 changes: 10 additions & 7 deletions packages/codra-npm-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,19 @@ npm run build:from-artifacts
```

- Fails if any artifact is missing (default).
- Set `CODRA_ALLOW_PARTIAL_BINARIES=1` to package only available artifacts (local testing).
- Set `CODRA_ALLOW_PARTIAL_BINARIES=1` to package only available artifacts (local testing or CI dry runs).

### Manual GitHub Actions release

Workflow: [`.github/workflows/codra-cli-release.yml`](../../.github/workflows/codra-cli-release.yml)

- Trigger: **workflow_dispatch** only (not automatic on push).
- Builds matrix: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64.
- Job `package-npm`: downloads artifacts, runs `build:from-artifacts`, `npm test`, `npm pack`, uploads tarball.
- **npm publish is disabled by default.** Set workflow input `publish: true` and configure `NPM_TOKEN` secret to publish.
- **Always builds:** linux-x64, linux-arm64, darwin-arm64, win32-x64.
- **Optional:** darwin-x64 (Intel macOS) when `include_darwin_x64: true`. Off by default because `macos-13` runner availability can be slow and block the workflow.
- Job `package-npm` runs after the selected matrix finishes (it does not wait for darwin-x64 when that input is false).
- **Dry run (`publish: false`):** may package partial binaries (`CODRA_ALLOW_PARTIAL_BINARIES=1`) so tarball verification is not blocked by one scarce runner.
- **Real publish (`publish: true`):** requires every platform in the selected matrix unless `allow_partial_binaries: true` is set explicitly. `NPM_TOKEN` secret is required; the publish step is skipped when `publish: false`.
- Recommended dry-run dispatch: `publish=false`, `include_darwin_x64=false`.

## Local vs release packaging

Expand All @@ -86,11 +89,11 @@ When ready to publish (maintainers only):
1. Run **Codra CLI release** workflow (or supply all artifacts locally).
2. `npm login` (only if publishing manually).
3. `npm test`
4. `CODRA_EXPECT_ALL_PLATFORMS=1 npm run pack:dry`
5. Verify tarball lists all five `bin/native/<platform>/` binaries.
4. `CODRA_EXPECT_PLATFORMS=linux-x64,linux-arm64,darwin-arm64,win32-x64 npm run pack:dry` (add `darwin-x64` when Intel macOS is included).
5. Verify tarball lists every required `bin/native/<platform>/` binary.
6. Publish via workflow with `publish: true` **or** `npm publish --access public` (guarded).

Do not publish until all target binaries are included unless intentionally shipping a preview.
Do not publish until all required target binaries are included unless intentionally shipping a preview with `allow_partial_binaries: true`.

## Supported commands

Expand Down
32 changes: 25 additions & 7 deletions packages/codra-npm-cli/scripts/pack-dry-run.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,26 @@ const EXPECTED_NATIVE = SUPPORTED_PLATFORM_KEYS.map((key) => {
return `bin/native/${key}/${name}`;
});

function expectedNativePaths() {
if (process.env.CODRA_EXPECT_PLATFORMS) {
const keys = process.env.CODRA_EXPECT_PLATFORMS.split(',')
.map((key) => key.trim())
.filter(Boolean);
return keys.map((key) => {
const name = key.startsWith('win32') ? 'codra.exe' : 'codra';
return `bin/native/${key}/${name}`;
});
}

if (process.env.CODRA_EXPECT_ALL_PLATFORMS === '1') {
return EXPECTED_NATIVE;
}

return [];
}

function main() {
const expectAll = process.env.CODRA_EXPECT_ALL_PLATFORMS === '1';
const expectedNative = expectedNativePaths();

const output = execSync('npm pack --dry-run 2>&1', {
cwd: packageRoot,
Expand All @@ -23,7 +41,9 @@ function main() {
shell: true,
env: {
...process.env,
CODRA_USE_ARTIFACTS: process.env.CODRA_USE_ARTIFACTS || (expectAll ? '1' : process.env.CODRA_USE_ARTIFACTS),
CODRA_USE_ARTIFACTS:
process.env.CODRA_USE_ARTIFACTS ||
(expectedNative.length > 0 ? '1' : process.env.CODRA_USE_ARTIFACTS),
},
});

Expand Down Expand Up @@ -54,11 +74,9 @@ function main() {
errors.push('no bin/native/<platform>-<arch>/ binary in pack (run npm run build first)');
}

if (expectAll) {
for (const expected of EXPECTED_NATIVE) {
if (!fileLines.includes(expected)) {
errors.push(`missing release binary: ${expected}`);
}
for (const expected of expectedNative) {
if (!fileLines.includes(expected)) {
errors.push(`missing release binary: ${expected}`);
}
}

Expand Down
Loading