fix(sites): flag consistency - #135
Conversation
`confirm()` blocks forever when stdin isn't a TTY, so `sites delete`, `sites deployments publish`, `sites deployments prune` and the shared `domains remove` would hang in CI, and print the prompt to stdout ahead of the `--output json` payload. Add `requireConfirmable()` next to `isInteractive()` and call it before each of those confirmations, so an unattended run fails fast with a `--force` hint.
`--force` already skips the confirmation, so `sites delete --force` with nothing linked would open the picker and delete whichever site was highlighted, unprompted. Thread `force` into `selectSite` from delete, deployments publish/prune and the domains resolver (only `remove` defines the flag) so those runs error with the same hint a non-interactive run gets. `deploy --force` means "redeploy unchanged content" and still gets the picker.
yargs coerces `--keep abc` to NaN, and NaN passes straight through pruneVictims' `Math.max(0, keep)` into `slice(NaN)`, which behaves like `slice(0)`: every deploy but current and previous gets deleted. Negative counts did the same. Validate the count in the handler via resolveKeepCount so it fails before any state is touched.
`sitePositionalBuilder`/`siteOptionBuilder` bundled `--link` with the site target, so `open`, `ssl`, `delete` and `deployments prune` advertised a flag none of them acts on: they never call `offerLink`, and delete/prune hardcode `link: false`. Split the flag into its own `siteLinkOption` and mount it only where offerLink runs. An explicit `--link` was also dropped whenever the site came from `--site` or `bunny.jsonc`, so `deploy --site my-site --link` never wrote the manifest. Those paths now link on request; the picker keeps prompting unless the flag already decided it.
`prune` used the `--site` flag builder despite having no positionals of its own, so `bunny sites deployments prune my-site` failed with "Unknown argument" while `deployments list my-site` worked. Declare `[site]` like the sibling subcommands; yargs keeps accepting the `--site` form.
The scaffold only ever used the framework preset, so a project with `sites.dir: "build"` deployed `build/` locally and the preset's `dist/` from CI, and a configured `sites.build` was dropped entirely. Thread the `sites` block through scaffoldSitesWorkflow into renderSitesWorkflow (both for `ci init` and the offer inside `sites create`), report the effective directory in the detection and success lines, and quote a configured build command that a bare YAML scalar couldn't carry.
Every other sites command resolves the site through `sites.name`, but create never read the config, so `bunny sites create --output json` in a configured project failed with "Site name is required." Use the configured name when no positional is passed, and say where it came from in text output.
|
@codex review |
🦋 Changeset detectedLatest commit: 222ce65 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Greptile SummaryThis PR standardizes Sites command flags and makes generated CI workflows honor project configuration.
Confidence Score: 5/5The PR appears safe to merge. The previously reported nested-config workflow-root issue is addressed by running build steps from the configured project directory and passing the correspondingly prefixed directory to the deployment action; no blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/cli/src/commands/sites/ci/init.ts | Loads Sites configuration and passes its root, build command, and output directory into workflow scaffolding. |
| packages/cli/src/commands/sites/ci/scaffold.ts | Computes the nested project prefix, performs project-relative framework detection, and configures workflow paths and dependency caching. |
| packages/cli/src/commands/sites/ci/workflow.ts | Renders configured build commands, working directories, cache paths, and repository-relative deployment directories into GitHub Actions YAML. |
| packages/cli/src/commands/sites/interactive.ts | Centralizes Sites link-option handling and prevents forced destructive commands from falling through to an interactive site picker. |
| packages/cli/src/core/ui.ts | Adds a confirmation guard so unattended destructive commands require an explicit force flag. |
| packages/cli/src/commands/sites/deployments/prune.ts | Adds positional site selection and validates that the deployment retention count is a non-negative integer. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Config["Nested bunny.jsonc"] --> Scaffold["CI scaffold"]
Scaffold --> WorkingDir["defaults.run.working-directory"]
Scaffold --> DeployDir["Repository-relative deploy directory"]
WorkingDir --> Build["Build in configured project root"]
Build --> Action["deploy-site action"]
DeployDir --> Action
Reviews (3): Last reviewed commit: "fix(sites): apply an explicit --link dur..." | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5fd2a7d423
ℹ️ 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".
`ci init` writes the workflow at the git root, but `sites.dir` and `sites.build` resolve against the bunny.jsonc directory. With the config in a monorepo package, CI ran the build from the checkout root and deployed `<repo>/dist` instead of `<repo>/packages/site/dist`. Pass the config directory through as `projectRoot`: framework and package-manager detection now run there, run steps get `defaults.run.working-directory`, the action's `directory` input takes the prefix (its inputs aren't affected by run defaults), and a lockfile of the project's own becomes `cache-dependency-path` so setup-node still finds one. Paths are compared through realpath, and a bunny.jsonc above the git root can't be expressed in a repo-rooted workflow, so its paths are dropped with a warning.
The unsafe-token regex let YAML-typed commands through: `run: true` parses as a boolean, `run: null` as null and `run: 1.5` as a number, and Actions rejects a `run` that isn't a string. Drop the pattern list and emit `sites.build` as a quoted scalar unconditionally; preset commands come from our own table and stay readable.
… preset An unrecognized bundler falls back to the static preset, so a configured `sites.build` of `npm run build` emitted a lone run step: the runner had no dependencies and the workflow failed on a build that works locally. When the project has a package.json, that branch now gets the detected package manager's setup and install steps first.
offerLink() runs at the end of a handler, but every command returns from its `--output json` branch before reaching it, so `--link --output json` reported success and left `.bunny/site.json` unwritten. Link during resolution instead, where the flag is unambiguous, and keep offerLink for the picker's prompt. The confirmation line is suppressed under json so the payload stays clean.
No description provided.