Skip to content

feat(boxel-cli): Add publish/unpublish and Actions to use them#4851

Open
backspace wants to merge 15 commits into
mainfrom
cs-11161-extract-workspace-sync-action
Open

feat(boxel-cli): Add publish/unpublish and Actions to use them#4851
backspace wants to merge 15 commits into
mainfrom
cs-11161-extract-workspace-sync-action

Conversation

@backspace
Copy link
Copy Markdown
Contributor

@backspace backspace commented May 15, 2026

I noticed that boxel-home PR previews are broken:

image

This is because the interface to _publish-realm changed:

Publishing https://realms-staging.stack.cards/boxel_homepage_realm/boxel-home-pr-57/ to https://boxel_homepage_realm.staging.boxel.dev/boxel-home-pr-57/
Failed to publish realm (HTTP 202):
{
  "data": {
    "type": "published_realm",
    "id": "23ea3f2a-9c7a-4028-ad3a-7be647ed476b",
    "attributes": {
      "sourceRealmURL": "https://realms-staging.stack.cards/boxel_homepage_realm/boxel-home-pr-57/",
      "publishedRealmURL": "https://boxel_homepage_realm.staging.boxel.dev/boxel-home-pr-57/",
      "lastPublishedAt": "1778870465062",
      "status": "pending"
    }
  }
}

HTTP 202 is actually expected now!

I also noticed that boxel-catalog, boxel-home, and boxel-skills were all using duplicative bespoke workflows to accomplish similar tasks, with use of cardstack/boxel-cli, npm Boxel CLI, and the old workspace sync CLI.

This extracts the preview/sync workflows into the monorepo so they can be used from external repositories and tested in-monorepo in case of interface changes like the above.

How to exercise

Assuming you’ve created a profile already, something like this:

cd packages/boxel-cli
pnpm build
./dist/index.js realm publish https://realms-staging.stack.cards/buck/wittering-dragon-6/ https://buck.staging.boxel.dev/wittering-dragon-6/
./dist/index.js realm unpublish https://buck.staging.boxel.dev/wittering-dragon-6/

backspace and others added 5 commits May 15, 2026 14:57
The boxel-cli integration test suite covers the publish/unpublish and
readiness-check HTTP contract the realm-server exposes. CS-11161 was the
result of a realm-server-only PR changing /_publish-realm from a
synchronous 200 to an async 202 + poll model without anything tripping in
that PR's CI — boxel-cli-test only ran when packages/boxel-cli/** files
changed. Widening the trigger to also include realm-server changes makes
that class of drift fail pre-merge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

Host Test Results

    1 files  ± 0      1 suites  ±0   1h 35m 16s ⏱️ + 5m 59s
2 709 tests +44  2 694 ✅ +44  15 💤 ±0  0 ❌ ±0 
2 728 runs  +44  2 713 ✅ +44  15 💤 ±0  0 ❌ ±0 

Results for commit 2424d89. ± Comparison against earlier commit 496ccc3.

Realm Server Test Results

    1 files  ± 0      1 suites  ±0   8m 4s ⏱️ -14s
1 431 tests +20  1 431 ✅ +20  0 💤 ±0  0 ❌ ±0 
1 522 runs  +24  1 522 ✅ +24  0 💤 ±0  0 ❌ ±0 

Results for commit 2424d89. ± Comparison against earlier commit 496ccc3.

@backspace backspace marked this pull request as ready for review May 15, 2026 22:54
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43a358d0ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/boxel-cli/src/commands/realm/publish.ts Outdated
Comment thread .github/actions/publish-preview-realm/action.yml
backspace and others added 6 commits May 15, 2026 18:04
Commander exposes negated options (`--no-foo`) on the positive key
(`foo`) defaulting to `true`. The CLI shim for `boxel realm publish`
was reading `opts.noWait` / `opts.noRepublish`, which Commander never
sets — so `--no-wait` and `--no-republish` were silently ignored.
The programmatic `publishRealm(...)` API was unaffected, which is why
the integration tests still passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extracts `publishCliOptsToOptions` so the Commander-flag → PublishOptions
translation is testable without a realm-server. The new tests would have
caught the CS-11161 bug class: they assert (a) Commander populates the
positive `wait` / `republish` keys for negated flags (not `noWait` /
`noRepublish`), and (b) the translation lowers `--no-wait` to
`waitForReady: false` and `--no-republish` to `republish: false`.

The integration tests exercise the programmatic publishRealm() API only
and missed both halves.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The realm-server-url input description claimed defaults were inferred
for stack.cards / boxel.ai / localhost, but this action's own inference
block only knows the two CI environments and hard-fails otherwise.
Localhost works fine in workspace-sync and unpublish-preview-realm
because they forward to _setup-boxel-cli without inferring a URL
themselves, but here the action needs the URL to compose the source-
realm URL. Documenting the actual contract rather than expanding the
inference, since no CI workflow invokes this against a localhost
matrix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the boxel-cli-test stack setup (build host/icons/ui via the
reusable test-web-assets workflow, start matrix, register realm users,
boot the dev services) and then invokes publish-preview-realm,
workspace-sync, and unpublish-preview-realm against the local stack —
referencing each action at @\${{ github.sha }} the same way a real
consumer would. Delete this workflow once a successful run is captured.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub Actions doesn't allow expressions in a workflow step's `uses:`
ref — only literal strings. The `github.action_ref` expression that
works in the actions' own internal `uses:` clauses is evaluated by a
different parser context (composite-action steps) and isn't usable
here. The demo workflow only runs on this branch anyway, so pinning to
the branch name resolves to the latest pushed tip at run time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@backspace backspace changed the title Add CLI publish/unpublish and Actions to use them feat(boxel-cli) Add publish/unpublish and Actions to use them May 19, 2026
@backspace backspace changed the title feat(boxel-cli) Add publish/unpublish and Actions to use them feat(boxel-cli): Add publish/unpublish and Actions to use them May 19, 2026
backspace and others added 3 commits May 19, 2026 07:33
GitHub Actions' workflow parser rejects expressions in a composite
action's `uses:` ref (the same restriction that hit the demo workflow,
just at a different parser layer). That meant the three top-level
actions could not call `_setup-boxel-cli@\${{ github.action_ref }}`
and have it run at the ref the consumer pinned.

Inlining the setup scaffolding (clone boxel, install pnpm, build the
CLI, configure the profile) into each action removes the cross-action
`uses:` and makes them parseable. The cost is ~50 lines of duplication
across three files; the comment block at the top of `runs:` calls that
out so future edits stay in sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The realm-server and vite host both speak HTTPS+HTTP/2 only (the
prerenderer needs HTTP/2 multiplexing, see infra:ensure-dev-cert). The
previous demo workflow's http:// probe and http:// action inputs would
never match the running services — the readiness loop spun for 10
minutes and timed out. Update the probe to mirror boxel-cli-test
(curl -sk + %{http_code} check) and pass https://localhost:4201/ to the
action inputs.

Matrix stays on http://localhost:8008 — synapse doesn't terminate TLS
locally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous setup wrote BOXEL_SRC/packages/boxel-cli/bin to
$GITHUB_PATH, but that directory holds the script named `boxel.js`
(the file package.json's `bin: { boxel }` maps to). Even when
$GITHUB_PATH did propagate, the next step would fail to find a
`boxel` binary. Symlinking the entry point into /usr/local/bin —
which is already on the default PATH — gives subsequent steps the
same `boxel` command that npm/pnpm-installed callers see.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant