Skip to content

fix(sites): deploy handles rebuilt output, symlinks, nested bunny.jsonc, and upload and publish failures - #247

Open
jamie-at-bunny wants to merge 2 commits into
mainfrom
sites-deploy
Open

jamie-at-bunny wants to merge 2 commits into
mainfrom
sites-deploy

Conversation

@jamie-at-bunny

Copy link
Copy Markdown
Member

Fixes bunny sites deploy edge cases around rebuilt output, symlinks, nested config, and failed uploads or publishes.

@changeset-bot

changeset-bot Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 41c7c53

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@bunny.net/cli Patch
@bunny.net/cli-darwin-arm64 Patch
@bunny.net/cli-darwin-x64 Patch
@bunny.net/cli-linux-arm64 Patch
@bunny.net/cli-linux-x64 Patch
@bunny.net/cli-windows-x64 Patch

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

@bunnynet-devops

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-07T16:29:22.558910Z f53b002 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[High risk] Modifies site deployment logic and file collection.

Fix the linked-site override before merging because it can publish to a site the user did not choose.

Fix All in Claude CodeFindings

  1. P1 Nested config overrides linked site ▶
  2. P2 Circular links still stop deploys ▶

Summary

This PR gives rebuilt output a content-based deploy ID when its git SHA is already used. It also follows allowed symlinks, discovers nested site configs, names failed uploads, keeps build logs off stdout, and warns when the edge has not confirmed publication.

  • Nested config discovery can override the user's linked site.
  • Circular link chains still stop file collection.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Read site config] --> B[Choose site]
  B --> C[Build and collect files]
  C --> D[Hash content and choose deploy ID]
  D --> E{Content already uploaded?}
  E -->|No| F[Upload files and save deploy]
  E -->|Yes| G[Publish deploy]
  F --> G
  G --> H[Check edge response and purge again]
  H --> I{Deploy confirmed?}
  I -->|Yes| J[Report result]
  I -->|No| K[Warn and report result]
Loading

Reviews (1) · Last reviewed commit: "fix(sites): deploy handles rebuilt outpu..." · Reviewed by Greptile

const { site, offerLink } = await selectSite(coreClient, {
site: args.site,
// Site selection reads bunny.jsonc from cwd, so a nested config's name is passed in explicitly.
site: args.site ?? (cwdConfig ? undefined : siteConfig?.config.name),

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 Nested config overrides linked site

If the working directory has a linked site but no site config, discovering a nested bunny.jsonc overrides that link. Passing its sites.name as args.site makes selectSite treat it as an explicit choice and skip .bunny/site.json. The command can then publish to another site without the user choosing it.

This violates the repository's required order: explicit choice, linked site, then configured name. Use the nested name only after checking the linked site.

Context Used: AGENTS.md (source)

Fix in Claude Code

Comment on lines +45 to +46
} catch {
return true; // Dangling: statSync below finds nothing and it's skipped.

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 Circular links still stop deploys

A circular link such as a -> b -> a aborts the deploy instead of being skipped. realpathSync throws ELOOP, but this catch treats every error as a dangling link and returns true. The following statSync throws again because throwIfNoEntry: false does not suppress ELOOP.

Skip unresolved circular links before calling statSync, and add a test for a link chain that loops. The current test only covers a directory pointing back to an ancestor.

Fix in Claude Code

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

Copy link
Copy Markdown

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: f53b00247e

ℹ️ 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 on lines +304 to +306
const { site, offerLink } = await selectSite(coreClient, {
site: args.site,
// Site selection reads bunny.jsonc from cwd, so a nested config's name is passed in explicitly.
site: args.site ?? (cwdConfig ? undefined : siteConfig?.config.name),

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 linked-site precedence for nested configurations

When a deploy is launched from a monorepo root containing .bunny/site.json and the selected directory is under a nested bunny.jsonc with sites.name, passing that name through site makes selectSite() treat it as an explicit reference and bypass the linked-site lookup. This reverses the documented explicit → manifest → config precedence and can publish the nested build to the config-named production site instead of the linked site; provide the nested name as a configuration fallback after manifest resolution rather than as args.site.

Useful? React with 👍 / 👎.

Comment on lines +157 to +158
const deployId =
alreadyUploaded?.id ?? (shaTaken ? identity.contentHash : identity.id);

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 Mark hash-fallback deployments as content-derived

When a clean git SHA is already associated with different bytes, this branch changes the selected ID to identity.contentHash but leaves identity.source as "git". The newly written DeployRecord and the deploy command's JSON response therefore claim that the content-hash ID was chosen from git, and deployments list renders the original SHA as its source; carry a content-derived source through DeployTarget when this fallback is selected.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This review was skipped because it would exceed your organization's monthly flex usage limit. Raise the limit in billing settings or wait until the next billing period resets limits.

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.

2 participants