feat(cli): add --skip-if-no-diff flag to fern generate#15137
feat(cli): add --skip-if-no-diff flag to fern generate#15137Swimburger wants to merge 1 commit intomainfrom
Conversation
Decouples the no-diff skip behavior from automationMode by introducing a new skipIfNoDiff field on GithubStepConfig and a --skip-if-no-diff yargs option on fern generate (default false, strictly opt-in). - GithubStep.ts: both gates (PR mode + push mode) now check skipIfNoDiff via a new exported shouldCheckNoDiff helper; existing-PR lookup, fresh-branch naming, and automerge behavior remain gated on automationMode. - fern automations generate: sets skipIfNoDiff: true to preserve today's behavior exactly. - Threads skipIfNoDiff through generateAPIWorkspaces, generateAPIWorkspace, runLocalGenerationForWorkspace, and the remote path (runRemoteGenerationForAPIWorkspace -> runRemoteGenerationForGenerator -> createAndStartJob) mirroring the automationMode plumbing. - Adds unit tests proving the decoupling (skipIfNoDiff=true + automationMode=false skips; skipIfNoDiff=false + automationMode=true does NOT skip). Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
SDK Generation Benchmark ResultsComparing PR branch against latest nightly baseline on Full benchmark table (click to expand)
main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via |
Docs Generation Benchmark ResultsComparing PR branch against latest nightly baseline on
Docs generation runs |
| retryRateLimited: argv["retry-rate-limited"], | ||
| requireEnvVars: argv["require-env-vars"] | ||
| requireEnvVars: argv["require-env-vars"], | ||
| skipIfNoDiff: argv["skip-if-no-diff"] |
There was a problem hiding this comment.
Self-review nit: skipIfNoDiff is threaded into the API branch but NOT into the generateDocsWorkspace call below (line 895). That's semantically correct — docs generation doesn't go through GithubStep — but fern generate --docs --skip-if-no-diff silently accepts and ignores the flag. Option A: leave as-is (matches how --retry-rate-limited etc. behave for docs). Option B: add a validation error like the --dynamic-ir-only + --docs check at line 831. Leaning A; flagging for visibility.
| boolean: true, | ||
| default: false, | ||
| description: | ||
| "Skip opening a PR / pushing when the generated output has no diff from the base branch." |
There was a problem hiding this comment.
Self-review nit (description clarity): The description "Skip opening a PR / pushing when the generated output has no diff from the base branch" is accurate but only applies when the generator has a github output mode (pull-request or push). For generators with local-file-system output or publish-to-registry output, the flag is a no-op. Could tighten to something like: "For generators with GitHub output (pull-request/push), skip opening the PR or pushing when the generated output has no diff from the base branch." Not a must-fix.
| fernignoreContents: string | undefined; | ||
| automationMode?: boolean; | ||
| autoMerge?: boolean; | ||
| skipIfNoDiff?: boolean; |
There was a problem hiding this comment.
Self-review: The inner createJob now accepts skipIfNoDiff but doesn't forward it to Fiddle — matches how automationMode / autoMerge / runId are currently handled (threaded in, parked behind the existing TODO at lines 181–186). When FER-9671 is actioned, add skipIfNoDiff to the forwarded flags and update the TODO comment here. Happy to do a follow-up once Fiddle's API is ready.
| // pipeline from running at all. This tree-hash check is a safety net for edge cases | ||
| // where the version changes but the generated output doesn't. | ||
| if (this.config.automationMode) { | ||
| if (shouldCheckNoDiff(this.config)) { |
There was a problem hiding this comment.
Self-review (confirming intent): For automationMode: false + skipIfNoDiff: true + an existing PR found by the pre-check at line 102, we still reach this gate post-commit on the existing PR's branch. That means: "update the existing PR, but if the commit produced no diff vs. base, skip the push." Matches the task requirement and the existing-PR pre-check is untouched.
Worth flagging in release notes if this ever lands on a non-automation path: previously those callers would push an empty commit to the existing PR; with --skip-if-no-diff they won't. Intended, but a subtle behavior change.
| /** When true: separate PRs per generation, automerge support, run_id in body */ | ||
| automationMode?: boolean; | ||
| /** When true: skip opening a PR / pushing when the generated output has no diff from the base branch. */ | ||
| skipIfNoDiff?: boolean; |
There was a problem hiding this comment.
Self-review nit: I inserted skipIfNoDiff between automationMode and autoMerge, splitting the automation-related grouping. Considered moving it after autoMerge or to its own section, but left it here since the fields read top-to-bottom as "what gates PR/push behavior." Open to rearranging. The autoMerge docstring below still says "only effective when automationMode && !hasBreakingChanges" — accurate, but now that skipIfNoDiff doesn't share automationMode's coupling, maybe worth a brief note that the two are independent gates.
| generated output has no diff from the base branch. The existing no-diff skip behavior is | ||
| decoupled from `automationMode` and now gated behind its own `skipIfNoDiff` config. | ||
| `fern automations generate` continues to skip no-diff PRs by default. | ||
| type: feat |
There was a problem hiding this comment.
Self-review: Typed as feat → minor bump. This is strictly additive (new flag, default false) and preserves fern automations generate behavior exactly, so chore (patch bump) would also be defensible. I went with feat because the flag is user-facing — but if you prefer a patch release, flip this to chore.
Description
Adds an opt-in
--skip-if-no-diffflag tofern generateand decouples the existing no-diff skip behavior fromautomationMode.Previously, the tree-hash check in
GithubStepthat skips PR creation / push when generated output has no diff vs. the base branch was gated behindif (this.config.automationMode). That conflated two concepts (automation PR shape vs. no-diff skip). This PR introduces a dedicatedskipIfNoDiffconfig so non-automation callers can opt into the skip without inheriting automation's other side effects (separate PRs per generation, automerge,run_idin body, etc.).Behavior for
fern automations generateis preserved — it now explicitly setsskipIfNoDiff: truealongsideautomationMode: true.Changes Made
GithubStepConfig(packages/generator-cli/src/pipeline/types.ts): addedskipIfNoDiff?: boolean; updated theautomationModedoc comment to drop the "no-diff skip" responsibility.GithubStep.ts: both no-diff gates (PR mode and push mode) now call a new exported helpershouldCheckNoDiff(config)instead of readingautomationMode. The existing-PR lookup (line 102), fresh-branch naming, and automerge logic remain gated onautomationModeand are untouched.fern automations generate(packages/cli/cli/src/cli.ts): setsskipIfNoDiff: trueto preserve today's behavior exactly.fern generate(packages/cli/cli/src/cli.ts): new yargs option--skip-if-no-diff(boolean,default: false, strictly opt-in). Threaded through both the API and docs branches.automationMode:generateAPIWorkspaces→generateAPIWorkspace→runLocalGenerationForWorkspace→ intoGithubStepConfig.runRemoteGenerationForAPIWorkspace→runRemoteGenerationForGenerator→createAndStartJob.packages/generator-cli/src/__test__/skip-if-no-diff.test.ts): unit tests for the newshouldCheckNoDiffhelper covering the decoupling requirements:skipIfNoDiff: true, automationMode: false→ skipsskipIfNoDiff: false, automationMode: true→ does NOT skip (proves decoupling)undefineddefaults to no skippackages/cli/cli/changes/unreleased/add-skip-if-no-diff-flag.yml(feat).What's specifically worth a careful look
fern automations generate: the gate swap fromautomationMode→skipIfNoDiffatGithubStep.ts:161and:304relies on the call site inaddAutomationsGenerateCommandalso settingskipIfNoDiff: true. Please confirm there are no other in-tree callers that construct aGithubStepConfigwithautomationMode: truebut withoutskipIfNoDiff: true— they would silently stop skipping no-diff PRs.createAndStartJobnow acceptsskipIfNoDiffbut does not forward it to the Fiddle API (the innercreateJobtakes the param but doesn't include it in the generator config). This mirrors the existing handling ofautomationMode(there's a pre-existing TODO around forwarding automation flags once Fiddle's API is updated). As a result,--skip-if-no-diffis fully wired for the local generation path but is a no-op on the remote path until Fiddle learns about it. Flagging in case reviewers want a Fiddle-side change in this PR instead of a follow-up.shouldEnableAutomerge/resolveBranchActiontests. The runtime flow throughGithubStep.executePullRequestMode/executePushModeis not exercised by integration tests (the one existingGithubStepCLI test inpr.test.tsis skipped). If heavier coverage is desired here, happy to add it.Testing
shouldCheckNoDiff)pnpm turbo run test --filter @fern-api/generator-cli→ 184 passed, 1 pre-existing skippedpnpm run check(biome) → cleanpnpm turbo run compileon@fern-api/generator-cli,@fern-api/local-workspace-runner,@fern-api/remote-workspace-runner,@fern-api/cli→ all pass (tsc)fern generate --skip-if-no-diffagainst a real repo (not run locally in this session)Link to Devin session: https://app.devin.ai/sessions/f4dcbe307826491cb7d3a7b15d2f4691
Requested by: @Swimburger