Render markdown tables instead of printing their markup #473
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: CI | |
| # One entrypoint for every trigger. Jobs gate on the event: | |
| # - pull_request / push to main / workflow_dispatch → checks + build & package | |
| # the affected packages (the CLI leg wraps its SEA binary but STOPS before | |
| # publish). | |
| # - release / workflow_dispatch → build the tagged package once, then publish | |
| # it. workflow_dispatch's publish-package step always runs --dry-run, so a | |
| # manual dispatch exercises the whole pipeline without touching npm. | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| release: | |
| types: [ created ] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to test (e.g. claude-sdk-cli@1.0.0-beta.5)' | |
| required: true | |
| jobs: | |
| # --- PR and main: correctness + affected build & package ------------------ | |
| checks: | |
| if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' | |
| uses: ./.github/workflows/checks.yml | |
| secrets: inherit | |
| detect: | |
| if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| packages: ${{ steps.affected.outputs.packages }} | |
| build-packages: ${{ steps.affected.outputs.build-packages }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: ./.github/actions/setup | |
| - run: pnpm i --frozen-lockfile | |
| - name: Compute affected packages | |
| id: affected | |
| env: | |
| EVENT: ${{ github.event_name }} | |
| BASE_REF: ${{ github.base_ref }} | |
| BEFORE: ${{ github.event.before }} | |
| run: | | |
| if [ "$EVENT" = "pull_request" ]; then | |
| # Diff the PR against its base branch tip. | |
| git fetch --no-tags origin "$BASE_REF" | |
| BASE="origin/$BASE_REF" | |
| elif [ "$EVENT" = "push" ]; then | |
| # On a main push, origin/main IS the pushed commit, so an origin/main | |
| # base returns nothing. Use the push's previous commit instead. | |
| BASE="$BEFORE" | |
| if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ]; then | |
| BASE="HEAD^" | |
| fi | |
| else | |
| # workflow_dispatch (or anything else): there is no "before" commit, | |
| # and the dispatched ref may carry several commits since it diverged | |
| # from main. Diff from where this ref branched off main (the merge-base), | |
| # not origin/main directly, so commits main gained afterward don't leak | |
| # into the diff. If the ref IS main (merge-base == HEAD, e.g. dispatched | |
| # directly on main), there's nothing to diverge from, so fall back to | |
| # HEAD^ same as the push case. | |
| git fetch --no-tags origin main | |
| MERGE_BASE=$(git merge-base origin/main HEAD) | |
| if [ "$MERGE_BASE" = "$(git rev-parse HEAD)" ]; then | |
| BASE="HEAD^" | |
| else | |
| BASE="$MERGE_BASE" | |
| fi | |
| fi | |
| # Exclude platforms/* — they have no build task and are published only | |
| # through the release SEA path, so they must never enter this matrix. | |
| LIST=$(pnpm exec turbo run build --filter="...[$BASE]" --filter='!./platforms/*' --dry-run=json | jq -c '[.packages[] | select(. != "//")]') | |
| echo "packages=$LIST" >> "$GITHUB_OUTPUT" | |
| echo "Affected: $LIST" | |
| # packages/keychain-native is a native N-API addon with no dist/ output and | |
| # no Linux cross-compile toolchain set up here; it's built and verified only | |
| # through publish-keychain-native.yml (verify-keychain-native on PR/main, | |
| # publish-keychain-native on release), never this generic matrix. It stays | |
| # IN the plain "packages" list above so verify-keychain-native's contains() | |
| # check can still see it — only the build matrix's own list excludes it. | |
| BUILD_LIST=$(echo "$LIST" | jq -c '[.[] | select(. != "@shellicar/keychain-native")]') | |
| echo "build-packages=$BUILD_LIST" >> "$GITHUB_OUTPUT" | |
| echo "Build-affected: $BUILD_LIST" | |
| build: | |
| needs: detect | |
| if: ${{ (github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'workflow_dispatch') && needs.detect.outputs.build-packages != '' && needs.detect.outputs.build-packages != '[]' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| package: ${{ fromJSON(needs.detect.outputs.build-packages) }} | |
| uses: ./.github/workflows/build-package.yml | |
| with: | |
| package: ${{ matrix.package }} | |
| secrets: inherit | |
| wrap: | |
| needs: [ detect, build ] | |
| if: ${{ (github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'workflow_dispatch') && needs.detect.outputs.packages != '' && contains(fromJSON(needs.detect.outputs.packages), '@shellicar/claude-sdk-cli') }} | |
| permissions: | |
| contents: read | |
| id-token: write # publish-sea's platform/launcher jobs declare it; the caller must grant it even when publish is false | |
| uses: ./.github/workflows/publish-sea.yml | |
| with: | |
| artifact: dist-claude-sdk-cli # build-package names the CLI artifact dist-<basename> | |
| publish: false | |
| secrets: inherit | |
| # --- Release: build the tagged package once, then publish it -------------- | |
| prepare: | |
| if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| package: ${{ steps.tag.outputs.package }} | |
| package-dir: ${{ steps.tag.outputs.package-dir }} | |
| version: ${{ steps.tag.outputs.version }} | |
| is-cli: ${{ steps.tag.outputs.is-cli }} | |
| is-native: ${{ steps.tag.outputs.is-native }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: ./.github/actions/setup | |
| - name: Parse release tag | |
| id: tag | |
| env: | |
| EVENT: ${{ github.event_name }} | |
| DISPATCH_TAG: ${{ github.event.inputs.tag }} | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| if [ "$EVENT" = "workflow_dispatch" ]; then TAG="$DISPATCH_TAG"; else TAG="$RELEASE_TAG"; fi | |
| case "$TAG" in | |
| *@*) ;; | |
| *) echo "❌ Tag '$TAG' is not in package@version format"; exit 1 ;; | |
| esac | |
| BASENAME="${TAG%%@*}" | |
| VERSION="${TAG#*@}" | |
| # Tags use the unscoped name (claude-sdk-cli@x); resolve it to the full | |
| # workspace name + dir so build-package (which takes the full name) and | |
| # the publish path agree. | |
| BASENAME="$BASENAME" node -e ' | |
| const fs = require("fs"); | |
| const base = process.env.BASENAME; | |
| let dirs = ["apps", "packages", "platforms"].flatMap((r) => { | |
| try { return fs.readdirSync(r).map((p) => r + "/" + p); } catch { return []; } | |
| }); | |
| dirs.push("scripts"); | |
| dirs = dirs.filter((d) => { try { fs.statSync(d + "/package.json"); return true; } catch { return false; } }); | |
| const dir = dirs.find((d) => JSON.parse(fs.readFileSync(d + "/package.json", "utf8")).name.split("/").pop() === base); | |
| if (!dir) { process.stderr.write("No workspace package for tag name " + base + "\n"); process.exit(1); } | |
| const name = JSON.parse(fs.readFileSync(dir + "/package.json", "utf8")).name; | |
| const out = process.env.GITHUB_OUTPUT; | |
| fs.appendFileSync(out, "package=" + name + "\n"); | |
| fs.appendFileSync(out, "package-dir=" + dir + "\n"); | |
| ' | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| # The SEA path is claude-sdk-cli only; every other package is a plain publish. | |
| if [ "$BASENAME" = "claude-sdk-cli" ]; then | |
| echo "is-cli=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is-cli=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| if [ "$BASENAME" = "keychain-native" ]; then | |
| echo "is-native=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is-native=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| release-build: | |
| needs: prepare | |
| if: (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && needs.prepare.outputs.is-native == 'false' | |
| uses: ./.github/workflows/build-package.yml | |
| with: | |
| package: ${{ needs.prepare.outputs.package }} | |
| secrets: inherit | |
| publish-generic: | |
| needs: [ prepare, release-build ] | |
| if: ${{ (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && needs.prepare.outputs.is-cli == 'false' && needs.prepare.outputs.is-native == 'false' }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| uses: ./.github/workflows/publish-generic.yml | |
| with: | |
| package-dir: ${{ needs.prepare.outputs.package-dir }} | |
| version: ${{ needs.prepare.outputs.version }} | |
| artifact: ${{ needs.release-build.outputs.artifact }} | |
| secrets: inherit | |
| publish-sea: | |
| needs: [ prepare, release-build ] | |
| if: ${{ (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && needs.prepare.outputs.is-cli == 'true' }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| uses: ./.github/workflows/publish-sea.yml | |
| with: | |
| artifact: ${{ needs.release-build.outputs.artifact }} | |
| version: ${{ needs.prepare.outputs.version }} | |
| publish: true | |
| secrets: inherit | |
| publish-keychain-native: | |
| needs: prepare | |
| if: ${{ (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && needs.prepare.outputs.is-native == 'true' }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| uses: ./.github/workflows/publish-keychain-native.yml | |
| with: | |
| version: ${{ needs.prepare.outputs.version }} | |
| publish: true | |
| verify-keychain-native: | |
| needs: detect | |
| if: ${{ (github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'workflow_dispatch') && needs.detect.outputs.packages != '' && contains(fromJSON(needs.detect.outputs.packages), '@shellicar/keychain-native') }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| uses: ./.github/workflows/publish-keychain-native.yml | |
| with: | |
| version: 0.0.0-verify | |
| publish: false | |
| secrets: inherit | |
| # --- Aggregate gate: one stable check name the branch ruleset can require. | |
| # --- The real jobs carry per-PR matrix names (build (…), wrap (…)), which a | |
| # --- ruleset can't pin; this single job can. It needs every other job and | |
| # --- passes when each one succeeded or skipped — the publish jobs skipping on | |
| # --- a PR is expected — and fails only when one actually failed or cancelled. | |
| gate: | |
| needs: [ checks, detect, build, wrap, prepare, release-build, publish-generic, publish-sea, publish-keychain-native, verify-keychain-native ] | |
| if: always() | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Require every needed job to have succeeded or skipped | |
| if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} | |
| run: | | |
| echo "A needed job failed or was cancelled" | |
| exit 1 |