Skip to content

Add --json and --jq flags to gh pr create#13348

Open
SebTardif wants to merge 3 commits into
cli:trunkfrom
SebTardif:feat/pr-create-json-jq
Open

Add --json and --jq flags to gh pr create#13348
SebTardif wants to merge 3 commits into
cli:trunkfrom
SebTardif:feat/pr-create-json-jq

Conversation

@SebTardif
Copy link
Copy Markdown

Summary

Add --json and --jq flags to gh pr create so callers can get structured output (id, url, number) instead of parsing a plain-text URL.

Fixes #11247

Changes

api/queries_pr.go

  • Add number field to the CreatePullRequest GraphQL mutation response.

pkg/cmdutil/json_flags.go

  • Add AddJSONAndJQFlags helper for commands where --template (or -t) is already taken by another flag. Registers --json and --jq without --template.
  • Add withTemplateFlag parameter to checkJSONFlags so the host command's --template flag is not confused with JSON output templating.
  • Add SetFilter method to jsonExporter for test use.

pkg/cmd/pr/create/create.go

  • Add Exporter field to CreateOptions and createOutputFields variable (id, url, number).
  • Wire AddJSONAndJQFlags into NewCmdCreate.
  • Add --dry-run + --json mutual exclusion.
  • In submitPR, suppress plain URL and write JSON when Exporter is set.

Tests

pkg/cmd/pr/create/create_test.go:

  • TestJSONFields - canary test ensuring registered fields match expectations.
  • tty json output - interactive flow outputs JSON to stdout, status to stderr (AC1).
  • nontty json output - non-interactive flow outputs JSON (AC2).
  • json output with jq filter - --jq .number outputs just the number (AC3).
  • dry-run and json - mutual exclusion error (AC4).
  • json output with pr template - --json + --template coexist (AC5).
  • json output does not print URL - URL suppressed when Exporter active.
  • jq without json - error without --json.
  • web and json - --web + --json conflict.
  • All ~24 existing mock responses updated with Number field.

pkg/cmdutil/json_flags_test.go:

  • TestAddJSONAndJQFlags - 5 cases covering the new helper: basic, jq filter, host template coexistence, jq-without-json error, invalid field error.

Acceptance Criteria Coverage

AC Description Test
AC1 Interactive --json outputs JSON tty json output
AC2 Non-interactive --json outputs JSON nontty json output
AC3 --jq .number filters output json output with jq filter
AC4 --dry-run + --json errors dry-run and json
AC5 --json + --template coexist json output with pr template

SebTardif added 2 commits May 4, 2026 12:51
Add --json and --jq flags to gh pr create so users can get structured
output (id, url, number) instead of parsing the plain-text URL.

- Add AddJSONAndJQFlags helper in cmdutil for commands where --template
  is already taken for a different purpose.
- Make checkJSONFlags template-aware so the host command's --template
  flag is not confused with JSON output templating.
- Add number field to CreatePullRequest GraphQL mutation.
- Wire up flags in pr create with --dry-run mutual exclusion.
- Export JSON at end of submitPR when Exporter is set.

Fixes cli#11247
- Fix mutation closing brace indentation in queries_pr.go
- Add SetFilter method to jsonExporter for test use
- Add tty JSON output test (AC1: interactive flow)
- Add --jq filter end-to-end test (AC3)
- Add --json + --template coexistence test (AC5)
- Add --web + --json mutual exclusion test
Copilot AI review requested due to automatic review settings May 4, 2026 20:11
@SebTardif SebTardif requested a review from a team as a code owner May 4, 2026 20:11
@SebTardif SebTardif requested a review from babakks May 4, 2026 20:11
@github-actions github-actions Bot added external pull request originating outside of the CLI core team needs-triage needs to be reviewed labels May 4, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds structured output support to gh pr create by introducing --json and --jq flags, enabling callers to consume PR metadata (id/url/number) without parsing human-oriented output.

Changes:

  • Extend the CreatePullRequest GraphQL mutation response to include number.
  • Add cmdutil.AddJSONAndJQFlags (no --template) and update JSON flag parsing to avoid colliding with host commands’ existing --template flags.
  • Wire JSON exporting into gh pr create, including --dry-run/--json mutual exclusion and suppression of plain URL output when JSON output is requested.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
api/queries_pr.go Adds number to the PR create mutation response fields.
pkg/cmdutil/json_flags.go Introduces AddJSONAndJQFlags, adjusts JSON flag checking to optionally ignore --template, and adds a test helper setter for jq filtering.
pkg/cmdutil/json_flags_test.go Adds coverage for the new AddJSONAndJQFlags helper across common scenarios and error cases.
pkg/cmd/pr/create/create.go Adds exporter plumbing and output behavior changes for --json/--jq, plus --dry-run conflict handling.
pkg/cmd/pr/create/create_test.go Adds PR create JSON output behavior tests and updates GraphQL mock responses to include Number.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +416 to +443
name: "nontty json output",
httpStubs: func(reg *httpmock.Registry, t *testing.T) {
reg.Register(
httpmock.GraphQL(`mutation PullRequestCreate\b`),
httpmock.GraphQLMutation(`
{ "data": { "createPullRequest": { "pullRequest": {
"Number": 12,
"URL": "https://github.com/OWNER/REPO/pull/12"
} } } }`,
func(input map[string]interface{}) {
assert.Equal(t, "REPOID", input["repositoryId"])
assert.Equal(t, "my title", input["title"])
assert.Equal(t, "my body", input["body"])
}))
},
setup: func(opts *CreateOptions, t *testing.T) func() {
opts.TitleProvided = true
opts.BodyProvided = true
opts.Title = "my title"
opts.Body = "my body"
opts.HeadBranch = "feature"
exporter := cmdutil.NewJSONExporter()
exporter.SetFields(createOutputFields)
opts.Exporter = exporter
return func() {}
},
expectedOut: "{\"id\":\"\",\"number\":12,\"url\":\"https://github.com/OWNER/REPO/pull/12\"}\n",
},
Comment on lines +445 to +470
name: "tty json output",
tty: true,
httpStubs: func(reg *httpmock.Registry, t *testing.T) {
reg.Register(
httpmock.GraphQL(`mutation PullRequestCreate\b`),
httpmock.GraphQLMutation(`
{ "data": { "createPullRequest": { "pullRequest": {
"Number": 12,
"URL": "https://github.com/OWNER/REPO/pull/12"
} } } }`,
func(input map[string]interface{}) {}))
},
setup: func(opts *CreateOptions, t *testing.T) func() {
opts.TitleProvided = true
opts.BodyProvided = true
opts.Title = "my title"
opts.Body = "my body"
opts.HeadBranch = "feature"
exporter := cmdutil.NewJSONExporter()
exporter.SetFields(createOutputFields)
opts.Exporter = exporter
return func() {}
},
expectedOut: "{\"id\":\"\",\"number\":12,\"url\":\"https://github.com/OWNER/REPO/pull/12\"}\n",
expectedErrOut: "\nCreating pull request for feature into master in OWNER/REPO\n\n",
},
Comment on lines +498 to +524
name: "json output with pr template",
httpStubs: func(reg *httpmock.Registry, t *testing.T) {
reg.Register(
httpmock.GraphQL(`mutation PullRequestCreate\b`),
httpmock.GraphQLMutation(`
{ "data": { "createPullRequest": { "pullRequest": {
"Number": 12,
"URL": "https://github.com/OWNER/REPO/pull/12"
} } } }`,
func(input map[string]interface{}) {
assert.Equal(t, "my title", input["title"])
}))
},
setup: func(opts *CreateOptions, t *testing.T) func() {
opts.TitleProvided = true
opts.BodyProvided = true
opts.Title = "my title"
opts.Body = "my body"
opts.HeadBranch = "feature"
opts.Template = "bug_fix.md"
exporter := cmdutil.NewJSONExporter()
exporter.SetFields(createOutputFields)
opts.Exporter = exporter
return func() {}
},
expectedOut: "{\"id\":\"\",\"number\":12,\"url\":\"https://github.com/OWNER/REPO/pull/12\"}\n",
},
Address Copilot review feedback: mock responses for JSON output tests
now include a realistic PR node ID instead of relying on the zero value,
ensuring the id field mapping is validated end-to-end.
@SebTardif
Copy link
Copy Markdown
Author

Hi @babakks -- PR #12622 has been inactive for ~2 months with review feedback unaddressed, so I've opened this PR to cover the same feature. This implementation incorporates all 7 items from your review of #12622 (indentation, godoc, test coverage, createOutputFields variable, simplified template logic, etc.) and has test coverage for all 5 acceptance criteria. Happy to adjust anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external pull request originating outside of the CLI core team needs-triage needs to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add --json and --jq to gh pr create

2 participants