Skip to content

fix(cli-generator): page-all extraction, fail-fast auth, help placeholders, CI clippy; AnyType Default - #17620

Closed
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1788370176-benchling-cli-fixes
Closed

fix(cli-generator): page-all extraction, fail-fast auth, help placeholders, CI clippy; AnyType Default#17620
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1788370176-benchling-cli-fixes

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Description

Linear ticket: Refs https://github.com/fern-demo/benchling-cli/pull/1

Fixes the seven generator/runtime defects reported against the generated Benchling CLI (fern-demo/benchling-cli#1) at the source, so they disappear on regeneration rather than requiring hand patches in the generated repo.

Changes Made

Rust model generator (generators/rust/model)

  • hasDefaultImpl now returns true for unknown, matching StructGenerator.typeSupportsDefault. Aliases of unknown (AnyType(pub serde_json::Value)) therefore derive Default, so containing structs that derive Default compile. Required unknown fields also pick up #[serde(default)] like every other Default-able field type.

CLI runtime (generators/cli/sdk)

  • --page-all with captured output: pages are now merged into one flat item array instead of [envelope, envelope]. merge_captured_pages uses x-fern-pagination.results (PaginationConfig::results_path(), new) and falls back to the formatter's extract_items heuristic; unrecognized shapes are left untouched rather than dropping data. --format csv|table|json|jsonl --page-all now match the plain-list shape.
  • Fail fast on missing credentials: executor.rs checks AuthProvider::requires_credentials() (new: non-empty security requirements with no anonymous {} alternative) + has_credentials_for() before dispatching and returns missing_credentials_error (new shared helper, also used for the 401/403 path) listing the env vars/flags to set. Public and optional-auth ops are untouched.
  • <NAME>_OUTPUT / <NAME>_USER_AGENT_SUFFIX in --format / --user-agent-suffix help (root app.rs, openapi/commands.rs, graphql/commands.rs, --schema globalFlags) are replaced with env_var_prefix(binary_name) (benchlingBENCHLING_).
  • Replaced the 3.14 literal in a formatter test that failed cargo clippy --all-targets (clippy::approx_constant).

CLI generator emitters (generators/cli/src)

  • README/reference: full --format list, correct default (table on TTY, json piped), --page-all marked paginated-only, -o, --output <PATH> documented as binary-response-only.

  • Generated ci.yml: drop RUSTFLAGS: "-A warnings", add a clippy job (cargo clippy --all-targets), publish now needs: [check, clippy, compile, test, version].

  • Unreleased changelogs: generators/cli/changes/unreleased/fix-page-all-auth-help-ci.yml, generators/rust/sdk/changes/unreleased/fix-any-type-default.yml.

  • Regenerated seed: rust-sdk/{exhaustive,unknown} (shows DocumentedUnknownType/MyAlias gaining Default), cli/cli-basic-auth.

  • Updated README.md generator (if applicable)

Testing

  • Unit tests added/updated — Rust: test_execute_method_fails_fast_when_required_credentials_missing, merge_captured_pages tests (heuristic, declared dotted path, pre-extracted arrays, unrecognized shape), requires_credentials semantics. TS: emitPublishWorkflow.test.ts asserts clippy job / needs / no -A warnings.
  • Manual testing completed — dropped the updated runtime into a local checkout of fern-demo/benchling-cli and ran against a 2-page mock of GET /dna-sequence/items:

Before:

$ benchling dna-sequence list --format csv --page-all
items,nextToken
"{""id"":""seq_1"",""name"":""a""}, {""id"":""seq_2"",""name"":""b""}",p2
"{""id"":""seq_3"",""name"":""c""}",
$ unset BENCHLING_API_KEY; benchling dna-sequence list      # request sent, exit 0

After:

$ benchling dna-sequence list --format csv --page-all
id,name
seq_1,a
seq_2,b
seq_3,c
$ benchling dna-sequence list --format json --page-all
[{"id":"seq_1","name":"a"},{"id":"seq_2","name":"b"},{"id":"seq_3","name":"c"}]
$ unset BENCHLING_API_KEY; benchling dna-sequence list      # no request sent, exit 2
{"error":{"code":401,"message":"Access denied. Authentication credentials are missing. Set BENCHLING_CLIENT_ID environment variable, BENCHLING_CLIENT_SECRET environment variable, BENCHLING_API_KEY environment variable.","reason":"authError"}}
  • generators/cli/sdk: cargo test --lib 1971 passed; cargo clippy --all-targets reports only pre-existing warnings, none in touched code.
  • pnpm turbo run compile/test --filter @fern-api/cli-generator --filter @fern-api/rust-model green (440 + 18 tests); pnpm format clean.
  • pnpm seed test --generator rust-sdk --fixture exhaustive --fixture unknown and --generator cli --fixture cli-basic-auth pass; seed/rust-sdk/exhaustive cargo build OK.

Link to Devin session: https://app.devin.ai/sessions/d3e6c0a2eab24903ae7765c8a4c54032
Open in Devin Desktop: https://app.devin.ai/desktop/session/d3e6c0a2eab24903ae7765c8a4c54032?variant=devin


Devin Review

willkendall01 and others added 2 commits September 2, 2026 17:29
…lders, CI clippy; fix(rust): AnyType Default

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nitpickybot nitpickybot 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.

AI Review Summary

Solid fix set: page-all merging, fail-fast auth, help placeholders, CI clippy, and unknown Default. A couple of correctness concerns: the fail-fast check lives in build_http_request where it may also trip for dry-run/other paths that previously succeeded, and merge_captured_pages uses per-page heuristics that can silently pick different keys or fall back to raw envelopes; also the new --page-all merge changes the -o/--output / raw formats' payload shape. Docs/tests look consistent.

  • 🟡 3 warning(s)
  • 🔵 2 suggestion(s)

AI Review

🔵 suggestion — generators/cli/sdk/src/openapi/executor.rs (line 12401)

These new tests sit outside the mod tests { ... } block (the diff shows } closing the module right above at 12399). They compile as top-level items in the non-test build too unless the surrounding file/section is #[cfg(test)]. Confirm they're inside a #[cfg(test)] region; otherwise #[tokio::test]/json! helpers will leak into release builds.

🔵 suggestion — generators/cli/sdk/src/openapi/commands.rs (line 115)

env_var_prefix only strips -. Binary names with ., spaces, or leading digits produce invalid env var names (my.cliMY.CLI). Consider mapping all non-alphanumerics to _:

    binary_name
        .to_uppercase()
        .chars()
        .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
        .collect()

To request another review, comment /ai-review on this pull request.

Comment on lines +2839 to +2843
let items_path: Option<String> = match results_path {
Some(path) if !path.trim().is_empty() => Some(path.to_string()),
_ => pages
.iter()
.find_map(|p| crate::formatter::extract_items(p).map(|(key, _)| key.to_string())),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 warning

The heuristic branch picks the key from the first page that yields any array, then requires every page to have an array at that key. If page 1 is empty-ish (e.g. {"items": [], "warnings": ["..."]}) extract_items may select warnings, and subsequent pages then mismatch → you return the raw envelopes. Consider deriving the key per the first page that has a non-empty array and verifying it exists across all pages before committing, or preferring a key present in every page.

Comment on lines +2802 to +2804
if pagination.page_all && pages_fetched > 0 {
let results_path = endpoint_pag.map(|p| p.results_path());
return Ok(Some(merge_captured_pages(captured_values, results_path)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 warning

This merge now applies to every captured --page-all invocation, including --format raw/http and -o <PATH> binary captures where callers previously received the per-page values verbatim. Worth gating on the output pipeline (only for structured formats) so raw/binary paging output isn't reshaped into a JSON array.

Comment on lines +1095 to +1100
if auth_metadata.requires_credentials() && !auth_provider.has_credentials_for(auth_metadata)
{
return Err(crate::auth::missing_credentials_error(
auth_provider.as_ref(),
));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 warning

Placing the fail-fast check inside build_http_request means it also fires for --dry-run (and any other non-sending caller of this function). Previously --dry-run without credentials would print the request; now it errors. If that's intentional, note it in the changelog; otherwise move the check to the send path or skip it when dry-run is set.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Devin Review found 2 potential issues.

Devin Review

Comment thread generators/cli/sdk/src/openapi/executor.rs
Comment thread generators/cli/sdk/src/openapi/executor.rs
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-09-02T04:06:59Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
rust-sdk square 225s (n=5) 228s (n=5) 195s -30s (-13.3%)

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 fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-09-02T04:06:59Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-09-02 17:46 UTC

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

Superseded by stack #17621#17622#17623#17624#17625 (same changes split per fix, plus the two review fixes). Closing.

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