Skip to content

feat(cli-v2): support --output with GitHub PR URLs in fern generate#14901

Open
Swimburger wants to merge 3 commits intomainfrom
devin/1775857638-output-pr-url-v2
Open

feat(cli-v2): support --output with GitHub PR URLs in fern generate#14901
Swimburger wants to merge 3 commits intomainfrom
devin/1775857638-output-pr-url-v2

Conversation

@Swimburger
Copy link
Copy Markdown
Member

@Swimburger Swimburger commented Apr 10, 2026

Description

Refs internal Slack discussion (Niels)

Allows fern generate --output https://github.com/owner/repo/pull/123 to resolve the PR's head branch and push generated code directly to it, updating the existing PR instead of creating a new one. This eliminates the manual workflow of editing generators.yml to set mode: push and branch: <pr-branch> when iterating on a PR.

Changes Made

  • gitUrl.ts: Added isGithubPrUrl() and parseGithubPrUrl() helpers; modified isGitUrl() to exclude PR URLs (both start with https://github.com/)
  • resolveGithubPrBranch.ts (new): Fetches the PR's head branch and head repository via the GitHub REST API using fetch() with GITHUB_TOKEN/GIT_TOKEN. Uses head.repo.full_name for the URI so fork-based PRs resolve to the correct repository.
  • command.ts:
    • Made parseTargetOutput() and getTargets() async to support the GitHub API call
    • When a PR URL is detected, resolves to { mode: "push", branch, uri } output config
    • Forces local generation when --output is a PR URL (same as git URL output)
    • Hoisted parseTargetOutput call out of .map() in getTargets() to avoid redundant API calls
    • Added isRemoteOutput guard so git/PR URLs are not resolved as filesystem paths in checkOutputDirectory or pipeline.run
  • parseOutputArg.ts: Same PR URL handling for the no-config (flags-only) code path
  • Updated --output CLI help text to mention PR URL support
  • Added changelog entry

Human Review Checklist

  • forceLocal propagation: In handleWithWorkspace, validateArgs receives args.local || forceLocal but runGeneration receives original args + separate forceLocal param — verify runGeneration respects the forceLocal flag independently (it does via isLocal on line 250)
  • parseOutputArg.ts usage: Grep shows no imports of this file — confirm whether it is dead code or dynamically referenced
  • outputPath: undefined: When isRemoteOutput is true, pipeline.run receives outputPath: undefined. Verify this doesn't cause issues downstream in resolveTargetOutput — the git output config on target.output.git should be the primary output mechanism in this case
  • No retry/rate-limit handling on the GitHub API call — acceptable for v1?

Testing

  • Unit tests added/updated
  • Lint passes (pnpm run check)
  • Manual testing completed — needs a real PR URL + GITHUB_TOKEN to verify end-to-end

Link to Devin session: https://app.devin.ai/sessions/9ec43fea26df4a57b4357ec778c86d8a
Requested by: @Swimburger


Open with Devin

When a GitHub PR URL (e.g. https://github.com/owner/repo/pull/123) is
passed to --output, the CLI resolves the PR's head branch via the
GitHub API and pushes generated code directly to it, updating the
existing PR instead of creating a new one.

Changes:
- Add isGithubPrUrl() and parseGithubPrUrl() helpers in gitUrl.ts
- Add resolveGithubPrBranch() utility to fetch PR branch from GitHub API
- Update parseTargetOutput() in command.ts to handle PR URLs (async)
- Update getTargets() to be async to support the above
- Force local generation when --output is a PR URL
- Update parseOutputArg.ts for no-config mode
- Update --output CLI description

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

🤖 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 and CI monitoring

Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

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.

When --output is a GitHub PR URL or git URL, don't resolve it as a
local filesystem path in runGeneration. This avoids nonsensical paths
like '/home/user/project/https:/github.com/owner/repo/pull/123' being
passed to checkOutputDirectory and pipeline.run.

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

This comment was marked as resolved.

For fork PRs, the head branch lives on the fork repo, not the base
repo. Use head.repo.full_name from the GitHub API response to get the
correct repository URI instead of deriving it from the PR URL path.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant