Skip to content

feat(cli): optional Apple container runtime for local generation - #17541

Open
devin-ai-integration[bot] wants to merge 5 commits into
mainfrom
devin/1787767011-apple-container-optional
Open

feat(cli): optional Apple container runtime for local generation#17541
devin-ai-integration[bot] wants to merge 5 commits into
mainfrom
devin/1787767011-apple-container-optional

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Description

Refs #16854. Supersedes #16856 (community PR by @davidbarratt, whose commits are included here) — I couldn't push to that fork branch (403), so this branch carries their work plus review fixes.

Docker stays the default and recommended runtime; Apple's container is opt-in via --container-engine container / --runner container.

The community PR assumed Apple's CLI is command-compatible with Docker, but it isn't for image pulls, so both pull paths would have failed:

  • pullImage() ran container pull <img>; Apple namespaces it as container image pull <img> (hit by the missing-image retry in runContainer).
  • pull: true passed run --pull always, which Apple's container run has no flag for — this is reached in production by LocalParserRunner (pull: isDefaultImage).

Changes Made

  • runDocker.ts: pullImage uses ["image", "pull", img] for container, ["pull", img] otherwise; an always-pull request under container becomes an explicit pull before run instead of --pull always. Docker/Podman behavior unchanged.
  • runDocker.ts: run/start failures under container append a hint to start the runtime with container system start.
  • CONTAINER_RUNNERS in @fern-api/core-utils is now the single source of the runner values; ContainerRunner derives from it and all three yargs choices reuse it, so flags can't drift from the union.
  • Changelog reworded to frame Apple container as optional, with Docker as the default/recommended runtime.
  • Tests: added Apple pull-path regressions (container image pull on explicit pull and on missing-image retry, no --pull passed to container run) plus a Docker retry case; fixed lastRunnerBinary() to actually read the last call and swapped CONSOLE_LOGGERNOOP_LOGGER.

Testing

  • Unit tests added/updated
pnpm turbo run test --filter @fern-api/docker-utils --filter @fern-api/generator-cli
@fern-api/docker-utils:  Test Files 3 passed (3) | Tests 11 passed (11)
@fern-api/generator-cli: Test Files 42 passed | 1 skipped (43) | Tests 425 passed (426)
  • pnpm turbo run compile for @fern-api/core-utils, @fern-api/docker-utils, @fern-api/cli, @fern-api/cli-v2: 94/94 tasks successful.
  • pnpm lint:biome, biome format, and prettier on the changelog: clean.
  • Manual testing completed — the Apple runtime only exists on macOS/Apple Silicon, so the corrected commands are covered by unit tests rather than an end-to-end run.

Link to Devin session: https://app.devin.ai/sessions/6938948da2234246b7734659a978956b


Open in Devin Review

davidbarratt and others added 4 commits July 2, 2026 10:28
Add Apple's `container` runtime as an accepted value for the
`--container-engine` flag (cli-v2) and `--runner` flag (legacy CLI),
alongside `docker` and `podman`. Apple's container CLI mirrors Docker's
command structure (run/pull/exec/cp/rm), so no per-command branching is
needed; the existing subprocess invocations work as-is.

The "not installed" error now resolves an engine-specific install URL via
an exhaustive switch instead of a docker/podman-only ternary, so container
users are pointed at the right place.

Closes #16854

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apple's container CLI namespaces image commands and has no run --pull flag, so explicit pulls use container image pull and always-pull is satisfied by pulling before run. Failures under the Apple runtime hint at container system start.

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

Adds Apple container as an opt-in runtime, centralizes the runner list in CONTAINER_RUNNERS, and fixes Apple-specific pull semantics (container image pull, no --pull on run). The pull-path fix and test coverage look right. Two concerns: a likely missing/implicit dependency plus value-import of a type in generator-cli, and the Apple "start the runtime" hint being appended to every non-zero exit (including ordinary generator failures). Also worth confirming other Docker-only run flags (--platform, --network) are actually accepted by Apple's CLI, since that was the root cause the PR set out to fix.

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

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

@@ -1,3 +1,5 @@
import { ContainerRunner } from "@fern-api/core-utils";

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 is a type-only usage — under verbatimModuleSyntax a value import here emits a runtime import from a module this file otherwise doesn't need. Also double-check @fern-api/core-utils is declared in packages/generator-cli/package.json; no package.json change is in this PR.

Suggested change
import { ContainerRunner } from "@fern-api/core-utils";
import type { ContainerRunner } from "@fern-api/core-utils";

Comment on lines +184 to +187
throw new Error(
`Container exited with code ${exitCode}.\n${stdout}\n${stderr}` +
(containerRunner === "container" ? `\n${APPLE_CONTAINER_SERVICE_HINT}` : "")
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

This appends the "start the runtime with container system start" hint to every non-zero exit, including a generator that legitimately failed with exit code 1. That's misleading noise for the common case. Consider gating it on a signal that the runtime isn't up (e.g. stderr matching connection/daemon errors) — same for the startContainer variant below.

Comment on lines +53 to +58
// Apple's `container run` has no `--pull` option, so an always-pull request is
// satisfied by pulling explicitly beforehand.
const pullBeforeRun = pull && runner === "container";
if (pullBeforeRun) {
await pullImage(imageName, runner, signal);
}

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 PR premise is that Apple's CLI isn't Docker-flag-compatible — --pull is fixed here, but the same run invocation still passes Docker-shaped flags (--platform, and --network where used). Apple's container run exposes --arch/--os rather than --platform, so pull: true paths are fixed but platform paths will still fail. Worth verifying/translating those too, or at least documenting the limitation.

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

@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: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

@github-actions

Copy link
Copy Markdown
Contributor

Docs Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-08-26T04:13:04Z).

Fixture main PR Delta
docs 255.9s (n=5) 270.4s (35 versions) +14.5s (+5.7%)

Docs generation runs fern generate --docs --preview end-to-end against the benchmark fixture with 35 API versions (each version: markdown processing + OpenAPI-to-IR + FDR upload).
Delta is computed against the nightly baseline on main.
Baseline from nightly run(s) on main (latest: 2026-08-26T04:13:04Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-08-26 18:45 UTC

@github-actions

Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-08-26T04:13:04Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
csharp-sdk square 75s (n=5) 111s (n=5) 59s -16s (-21.3%)
go-sdk square 136s (n=5) 285s (n=5) 106s -30s (-22.1%)
java-sdk square 225s (n=5) 279s (n=5) 216s -9s (-4.0%)
php-sdk square 68s (n=5) N/A 46s -22s (-32.4%)
python-sdk square 153s (n=5) 245s (n=5) 125s -28s (-18.3%)
ruby-sdk-v2 square 95s (n=5) 129s (n=5) 90s -5s (-5.3%)
rust-sdk square 227s (n=5) 215s (n=5) 260s +33s (+14.5%)
swift-sdk square 60s (n=5) 450s (n=5) 59s -1s (-1.7%)
ts-sdk square 138s (n=5) 150s (n=5) 125s -13s (-9.4%)

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-08-26T04:13:04Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-08-26 18:47 UTC

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