Merge branch 'trunk' into 10480-enhance-gh-search-docs

This commit is contained in:
Kynan Ware 2025-08-06 10:34:25 -06:00 committed by GitHub
commit b5a6913a17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 423 additions and 182 deletions

View file

@ -7,15 +7,11 @@ on:
- "**.go"
- go.mod
- go.sum
- ".github/licenses.tmpl"
- "script/licenses*"
pull_request:
paths:
- "**.go"
- go.mod
- go.sum
- ".github/licenses.tmpl"
- "script/licenses*"
permissions:
contents: read
jobs:
@ -50,18 +46,6 @@ jobs:
with:
version: v2.1.6
# actions/setup-go does not setup the installed toolchain to be preferred over the system install,
# which causes go-licenses to raise "Package ... does not have module info" errors.
# for more information, https://github.com/google/go-licenses/issues/244#issuecomment-1885098633
#
# go-licenses has been pinned for automation use.
- name: Check licenses
run: |
export GOROOT=$(go env GOROOT)
export PATH=${GOROOT}/bin:$PATH
go install github.com/google/go-licenses@5348b744d0983d85713295ea08a20cca1654a45e
make licenses-check
# Discover vulnerabilities within Go standard libraries used to build GitHub CLI using govulncheck.
govulncheck:
runs-on: ubuntu-latest

View file

@ -56,7 +56,7 @@ for issue_num in $CLOSING_ISSUES; do
fi
# Check if 'help wanted' label exists
if ! echo "$LABELS" | grep -q "help wanted"; then
if ! echo "$LABELS" | grep -qE '^help wanted$'; then
ISSUES_WITHOUT_HELP_WANTED+=("$issue_num")
echo "Issue #$issue_num does not have 'help wanted' label"
else
@ -78,7 +78,7 @@ if [ ${#ISSUES_WITHOUT_HELP_WANTED[@]} -gt 0 ]; then
gh pr comment "$PR_URL" --body-file - <<EOF
Thank you for your pull request! 🎉
This PR appears to fix the following issues that are not labeled with \`help wanted\`:
This PR appears to fix the following issues that are not labeled with https://github.com/cli/cli/labels/help%20wanted:
$ISSUE_LIST
As outlined in our [Contributing Guidelines](https://github.com/cli/cli/blob/trunk/.github/CONTRIBUTING.md), we expect that PRs are only created for issues that have been labeled \`help wanted\`.

View file

@ -10,126 +10,6 @@ evaluators:
string:
equals: "{{expected}}"
testData:
- name: not-spam, staff issue
expected: PASS
input: |
<TITLE>
Automatically update third party licenses during Dependabot PRs
</TITLE>
<BODY>
## Overview
With `cli/cli` lint process erring if 3rd party license information is not updated in https://github.com/cli/cli/pull/11047, Dependabot PRs will require maintainers to manually run `make licenses`.
Recently, @williammartin opened https://github.com/cli/cli/pull/11269 with the [`script/fix-dependabot-licenses.sh`](https://github.com/cli/cli/blob/26d70bfb7bcc0b41dbdd50bfc51f827f1a5ad4c4/script/fix-dependabot-licenses.sh) script for maintainers to run that will find all Dependabot PRs and attempt to fix them where the lint workflow failed. This script is a manual repair effort, however it is possible to [use a GitHub Actions workflow to run the `make license` script for Dependabot PRs](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions):
> ```yaml
> name: Dependabot fetch metadata
> on: pull_request
>
> permissions:
> pull-requests: write
> issues: write
>
> jobs:
> dependabot:
> runs-on: ubuntu-latest
> if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'owner/my_repo'
> steps:
> - name: Dependabot metadata
> id: metadata
> uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7
> with:
> github-token: "${{ secrets.GITHUB_TOKEN }}"
> # The following properties are now available:
> # - steps.metadata.outputs.dependency-names
> # - steps.metadata.outputs.dependency-type
> # - steps.metadata.outputs.update-type
> ```
This issue is aimed at implementing GitHub Actions workflow changes that will automatically update `third-party` license source code and `third-party-*.md` reports, eliminating the need for maintainers to manually repair Dependabot PRs.
> [!NOTE]
> To download the `script/fix-dependabot-licenses.sh` script, run the following command:
> ```shell
> curl -o fix-dependabot-licenses.sh https://raw.githubusercontent.com/cli/cli/26d70bfb7bcc0b41dbdd50bfc51f827f1a5ad4c4/script/fix-dependabot-licenses.sh
> ```
>
> Or checkout the original PR:
>
> ```shell
> gh pr checkout https://github.com/cli/cli/pull/11269
> ```
## Expected outcomes
- When Dependabot PRs are opened, automation attempts to regenerate and commit updated license information via `make licenses`
- When Dependabot PRs are updated, status checks pass without maintainer action outside of reviewing PR
- name: not-spam, template-based
spam: true
title: |
Incorrect check summary with v2.45 and v2.75
body: |
### Describe the bug
I got below confusing reports with v2.45 CLI on Ubuntu 22.04:
```sh
$ gh pr status
Relevant pull requests in micropython/micropython
...
Created by you
#17660 tests/extmod: Close UDP timely. [yf13:pull-udp-close]
✓ Checks passing
#17638 unix/make: Drop i686-linux-gnu path. [yf13:pull-drop-i686-linux-gnu]
× 1/94 checks failing
$ gh pr checks 17638
All checks were successful
0 cancelled, 0 failing, 48 successful, 0 skipped, and 0 pending checks
```
I downloaded latest v2.75 CLI but it is the same.
Meanwhile. from browser UI it seems checks passed.
### Affected version
Please run `gh version` and paste the output below.
```
$ gh version
gh version 2.75.0 (2025-07-09)
https://github.com/cli/cli/releases/tag/v2.75.0
```
### Steps to reproduce the behavior
see above descriptions.
### Expected vs actual behavior
A clear and concise description of what you expected to happen and what actually happened.
### Logs
Paste the activity from your command line. Redact if needed.
<!-- Note: Set `GH_DEBUG=true` for verbose logs or `GH_DEBUG=api` for verbose logs with HTTP traffic details. -->
</BODY>
- name: not-spam, short/focused
expected: PASS
input: |
<TITLE>
Include `isImmutable` in `release list`
</TITLE>
<BODY>
Update the list of available JSON fields in the `release list` command to include `isImmutable` flag.
This boolean flag indicates whether a particular release has been marked as immutable.
</BODY>
- name: spam, two words
expected: FAIL
input: |
@ -295,34 +175,6 @@ testData:
Add any other context like screenshots or mockups are helpful, if applicable.
</BODY>
- name: 'spam, legit but too general #10368 (https://github.com/cli/cli/issues/10368)'
expected: FAIL
input: |-
<TITLE>
Instructions in install_linux.md do not result in installation
</TITLE>
<BODY>
### Describe the bug
Bug: the instructions meant to install gh instead don't install gh.
### Affected version
Latest
### Steps to reproduce the behavior
Follow instructions in install_linux.md
### Expected vs actual behavior
Expect: gh is installed and can be used.
### Logs
A bunch of errors
</BODY>
- name: 'spam, #11304 (https://github.com/cli/cli/issues/11304)'
expected: FAIL
input: |-
@ -820,6 +672,106 @@ testData:
- name: 'spam, #9928 (https://github.com/cli/cli/issues/9928)'
expected: FAIL
input: "<TITLE>\nNote that an earlier version of the instructions used the location `/usr/share/keyrings` instead of `/etc/apt/keyrings` in the `sources.list.d` file, so I had to update that to make it work with the above update instructions, and remove the old keyring file from `/usr/share/keyrings`.\n</TITLE>\n\n<BODY>\n Note that an earlier version of the instructions used the location `/usr/share/keyrings` instead of `/etc/apt/keyrings` in the `sources.list.d` file, so I had to update that to make it work with the above update instructions, and remove the old keyring file from `/usr/share/keyrings`.\r\n\r\nAlternatively, one could of course download the updated key to `/usr/share/keyrings`, but we don't really want to pollute `/usr` with non-packaged files!\r\n\r\n_Originally posted by @rrthomas in https://github.com/cli/cli/issues/9569#issuecomment-2333981674_\r\n \n</BODY>"
- name: 'spam, #10075 (https://github.com/cli/cli/issues/10075)'
expected: FAIL
input: "<TITLE>\nRHEL 9 installation update\n</TITLE>\n\n<BODY>\n### Describe the bug\r\n\r\nsteps to install on RHEL9 \r\n\r\n### Steps to reproduce the behavior\r\n\r\n\r\n### Expected vs actual behavior\r\n\r\n```\r\nsudo dnf install dnf-plugins-core.noarch\r\nsudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo\r\nsudo dnf install gh --repo gh-cli\r\n```\n</BODY>"
- name: not spam, staff issue
expected: PASS
input: |
<TITLE>
Automatically update third party licenses during Dependabot PRs
</TITLE>
<BODY>
## Overview
With `cli/cli` lint process erring if 3rd party license information is not updated in https://github.com/cli/cli/pull/11047, Dependabot PRs will require maintainers to manually run `make licenses`.
Recently, @williammartin opened https://github.com/cli/cli/pull/11269 with the [`script/fix-dependabot-licenses.sh`](https://github.com/cli/cli/blob/26d70bfb7bcc0b41dbdd50bfc51f827f1a5ad4c4/script/fix-dependabot-licenses.sh) script for maintainers to run that will find all Dependabot PRs and attempt to fix them where the lint workflow failed. This script is a manual repair effort, however it is possible to [use a GitHub Actions workflow to run the `make license` script for Dependabot PRs](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions):
> ```yaml
> name: Dependabot fetch metadata
> on: pull_request
>
> permissions:
> pull-requests: write
> issues: write
>
> jobs:
> dependabot:
> runs-on: ubuntu-latest
> if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'owner/my_repo'
> steps:
> - name: Dependabot metadata
> id: metadata
> uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7
> with:
> github-token: "${{ secrets.GITHUB_TOKEN }}"
> # The following properties are now available:
> # - steps.metadata.outputs.dependency-names
> # - steps.metadata.outputs.dependency-type
> # - steps.metadata.outputs.update-type
> ```
This issue is aimed at implementing GitHub Actions workflow changes that will automatically update `third-party` license source code and `third-party-*.md` reports, eliminating the need for maintainers to manually repair Dependabot PRs.
> [!NOTE]
> To download the `script/fix-dependabot-licenses.sh` script, run the following command:
> ```shell
> curl -o fix-dependabot-licenses.sh https://raw.githubusercontent.com/cli/cli/26d70bfb7bcc0b41dbdd50bfc51f827f1a5ad4c4/script/fix-dependabot-licenses.sh
> ```
>
> Or checkout the original PR:
>
> ```shell
> gh pr checkout https://github.com/cli/cli/pull/11269
> ```
## Expected outcomes
- When Dependabot PRs are opened, automation attempts to regenerate and commit updated license information via `make licenses`
- When Dependabot PRs are updated, status checks pass without maintainer action outside of reviewing PR
</BODY>
- name: not spam, short/focused
expected: PASS
input: |
<TITLE>
Include `isImmutable` in `release list`
</TITLE>
<BODY>
Update the list of available JSON fields in the `release list` command to include `isImmutable` flag.
This boolean flag indicates whether a particular release has been marked as immutable.
</BODY>
- name: 'not spam, legit but too general #10368 (https://github.com/cli/cli/issues/10368)'
expected: PASS
input: |-
<TITLE>
Instructions in install_linux.md do not result in installation
</TITLE>
<BODY>
### Describe the bug
Bug: the instructions meant to install gh instead don't install gh.
### Affected version
Latest
### Steps to reproduce the behavior
Follow instructions in install_linux.md
### Expected vs actual behavior
Expect: gh is installed and can be used.
### Logs
A bunch of errors
</BODY>
- name: 'not spam, #11277 (https://github.com/cli/cli/issues/11277)'
expected: PASS
input: |-
@ -4482,9 +4434,6 @@ testData:
- name: 'not spam, #10076 (https://github.com/cli/cli/issues/10076)'
expected: PASS
input: "<TITLE>\n`gh run list` does not work with organization ruleset required workflows\n</TITLE>\n\n<BODY>\n### Describe the bug\r\n\r\nSimilar bug mentioned https://github.com/cli/cli/issues/3437, but gh run view or list all return a 404. The URL returned seems right based on REST api docs but not getting any response. When comparing the ID `gh run list` doesn't seem to be correct based on the ids from `gh workflow list`\r\n\r\n**gh cli version:** `gh version 2.63.2 (2024-12-05)`\r\n**ghe version:** `3.13.4`\r\n\r\n### Steps to reproduce the behavior\r\n\r\n1. Complete login to the enterprise server with Github CLI\r\n2. Go to a repository directory that uses that server as a remote\r\n3. Run gh run list returns 404\r\n\r\n### Expected vs actual behavior\r\n\r\nThe gh run list prints out list of workflow runs for the repo to choose from\r\n\r\n### Logs\r\n\r\n```bash\r\n[git remote -v]\r\n[git config --get-regexp ^remote\\..*\\.gh-resolved$]\r\n* Request at 2024-12-13 00:23:19.723417 -0600 CST m=+0.101249251\r\n* Request to https://{SERVER_URL}/api/graphql\r\n* Request took 281.385ms\r\n⣾* Request at 2024-12-13 00:23:20.040818 -0600 CST m=+0.418510918\r\n* Request to https://{SERVER_URL}/api/v3/repos/{ORG}/{REPO}/actions/runs?per_page=20&exclude_pull_requests=true\r\n⢿* Request took 421.362291ms\r\n⡿* Request at 2024-12-13 00:23:20.534045 -0600 CST m=+0.911535293\r\n* Request to https://{SERVER_URL}/api/v3/repos/{ORG}/{REPO}/actions/workflows?per_page=100&page=1\r\n⣟* Request took 105.218541ms\r\n* Request at 2024-12-13 00:23:20.700194 -0600 CST m=+1.077616418\r\n* Request to https://{SERVER_URL}/api/v3/repos/{ORG}/{REPO}/actions/workflows/63737\r\n⣯* Request took 121.476458ms\r\nfailed to get runs: HTTP 404: Not Found (https://{SERVER_URL}/api/v3/repos/{ORG}/{REPO}/actions/workflows/63737)\r\n```\r\n</BODY>"
- name: 'not spam, #10075 (https://github.com/cli/cli/issues/10075)'
expected: PASS
input: "<TITLE>\nRHEL 9 installation update\n</TITLE>\n\n<BODY>\n### Describe the bug\r\n\r\nsteps to install on RHEL9 \r\n\r\n### Steps to reproduce the behavior\r\n\r\n\r\n### Expected vs actual behavior\r\n\r\n```\r\nsudo dnf install dnf-plugins-core.noarch\r\nsudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo\r\nsudo dnf install gh --repo gh-cli\r\n```\n</BODY>"
- name: 'not spam, #10073 (https://github.com/cli/cli/issues/10073)'
expected: PASS
input: "<TITLE>\n`gh gist delete` does not prompt for a gist to delete or prompt for confirmation before deletion\n</TITLE>\n\n<BODY>\n### Describe the bug\n\n- `gh gist delete` doesn't prompt for a gist to delete. This seems like it might be an oversight when compared to the behavior of other `gh gist` and `gh <some-command> delete` operations.\n- `gh gist delete` should prompt for a gist to delete and confirm the selection to delete.\n- `gh gist delete` also does not currently support `--yes` for non-interactive confirmation - perhaps it should? \n\n### Steps to reproduce the behavior\n\n```\ngh gist delete\n```\n### Expected vs actual behavior\n\n**Expected**\n\n```\n gh gist delete\n? Select a gist to delete [Use arrows to move, type to filter]\n> test.md test gist about 4 days ago\n draft.md about 2 months ago\n? Are you sure you want to delete gist test.md (Y/n)\n```\n\n**Actual**\n```\ngh gist delete\n gh gist delete\ncannot delete: gist argument required\n\nUsage: gh gist delete {<id> | <url>} [flags]\n```\n\n### Notes\n\nDiscovered in #10042 \n</BODY>"

View file

@ -14,8 +14,4 @@ SPAM_DIR="$(dirname "$(realpath "$0")")"
_system_prompt="$($SPAM_DIR/generate-sys-prompt.sh)"
_final_prompt="$(_value="$_system_prompt" yq eval '.messages[0].content = strenv(_value)' $SPAM_DIR/eval-prompts.yml)"
# The following `gh models eval` command will fail after 20 requests due to rate limits.
# We are going to open up an issue in `github/gh-models` to address this.
#
# TODO: break up `eval-prompts.yml` file into smaller batches to avoid hitting the rate limit.
gh models eval <(echo "$_final_prompt")

View file

@ -9,16 +9,17 @@
set -euo pipefail
# Determine absolute path to script directory based on where it is called from.
# This allows the script to be run from any directory.
SPAM_DIR="$(dirname "$(realpath "$0")")"
_issue_url="$1"
if [[ -z "$_issue_url" ]]; then
echo "error: issue URL is empty" >&2
exit 1
fi
_suspected_spam_label="suspected-spam"
_check_issue_script=".github/workflows/scripts/spam-detection/check-issue.sh"
_result="$($_check_issue_script "$_issue_url")"
_result="$("$SPAM_DIR/check-issue.sh" "$_issue_url")"
if [[ "$_result" == "PASS" ]]; then
echo "detected as not-spam: $_issue_url"
@ -27,6 +28,17 @@ fi
echo "detected as spam: $_issue_url"
gh issue edit --add-label "$_suspected_spam_label" "$_issue_url"
cat << EOF | gh issue comment "$_issue_url" --body-file -
Thank you for taking the time to create this issue.
echo "issue labelled as suspected spam"
We've automatically reviewed this issue and suspect it as potentially inauthentic or spam-like content. As a result, we're closing this issue.
**If this was closed by mistake**, please don't hesitate to reach out to us by commenting on this issue with additional context.
We appreciate your understanding and apologize if this action was taken in error. Our automated systems help us manage the large volume of issues we receive, but we know they're not perfect.
EOF
gh issue edit --add-label "suspected-spam" --add-label "invalid" "$_issue_url"
gh issue close --reason 'not planned' "$_issue_url"
echo "issue processed as suspected spam: commented, closed, and labeled"

View file

@ -0,0 +1,52 @@
name: Third Party Licenses
on:
push:
branches:
- trunk
paths:
- .github/licenses.tmpl
- .github/workflows/third-party-licenses.yml
- go.mod
- go.sum
- script/licenses*
jobs:
# This job is responsible for updating the third-party license reports and source code.
# It should be safe to cancel as the latest version of `go.mod` should be checked in.
regenerate-licenses:
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
permissions:
contents: write
steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: trunk
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: Regenerate licenses
run: |
export GOROOT=$(go env GOROOT)
export PATH=${GOROOT}/bin:$PATH
go install github.com/google/go-licenses@5348b744d0983d85713295ea08a20cca1654a45e
make licenses
git diff
- name: Commit and push changes
run: |
if git diff --exit-code; then
echo "No third-party license changes to commit"
else
git config --local user.name "github-actions[bot]"
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add third-party third-party-licenses.*.md
git commit -m "Generate licenses - $GITHUB_SHA"
git pull
git push origin
fi

View file

@ -1655,7 +1655,7 @@ func Test_createRun(t *testing.T) {
expectedOut: "https://github.com/OWNER/REPO/pull/12\n",
},
{
name: "if reviewer contains any team, fetch teams",
name: "fetch org teams non-interactively if reviewer contains any team",
setup: func(opts *CreateOptions, t *testing.T) func() {
opts.TitleProvided = true
opts.BodyProvided = true
@ -1718,7 +1718,7 @@ func Test_createRun(t *testing.T) {
expectedErrOut: "",
},
{
name: "if reviewer does NOT contain any team, do NOT fetch teams",
name: "do not fetch org teams non-interactively if reviewer does not contain any team",
setup: func(opts *CreateOptions, t *testing.T) func() {
opts.TitleProvided = true
opts.BodyProvided = true
@ -1773,6 +1773,130 @@ func Test_createRun(t *testing.T) {
expectedOut: "https://github.com/OWNER/REPO/pull/12\n",
expectedErrOut: "",
},
{
name: "fetch org teams interactively if reviewer metadata selected",
tty: true,
setup: func(opts *CreateOptions, t *testing.T) func() {
// In order to test additional metadata, title and body cannot be provided here.
opts.HeadBranch = "feature"
return func() {}
},
cmdStubs: func(cs *run.CommandStubber) {
// Stub git commits for `initDefaultTitleBody` when initializing PR state.
cs.Register(
"git -c log.ShowSignature=false log --pretty=format:%H%x00%s%x00%b%x00 --cherry origin/master...feature",
0,
"3a9b48085046d156c5acce8f3b3a0532cd706a4a\u0000first commit of pr\u0000first commit description\u0000\n",
)
cs.Register(`git rev-parse --show-toplevel`, 0, "")
},
promptStubs: func(pm *prompter.PrompterMock) {
firstConfirmSubmission := true
pm.InputFunc = func(message, defaultValue string) (string, error) {
switch message {
case "Title (required)":
return "TITLE", nil
default:
return "", fmt.Errorf("unexpected input prompt: %s", message)
}
}
pm.MarkdownEditorFunc = func(message, defaultValue string, allowEmpty bool) (string, error) {
switch message {
case "Body":
return "BODY", nil
default:
return "", fmt.Errorf("unexpected markdown editor prompt: %s", message)
}
}
pm.MultiSelectFunc = func(message string, defaults []string, options []string) ([]int, error) {
switch message {
case "What would you like to add?":
return prompter.IndexesFor(options, "Reviewers")
case "Reviewers":
return prompter.IndexesFor(options, "MonaLisa (Mona Display Name)", "OWNER/core")
default:
return nil, fmt.Errorf("unexpected multi-select prompt: %s", message)
}
}
pm.SelectFunc = func(message, defaultValue string, options []string) (int, error) {
switch message {
case "Where should we push the 'feature' branch?":
return 0, nil
case "What's next?":
if firstConfirmSubmission {
firstConfirmSubmission = false
return prompter.IndexFor(options, "Add metadata")
}
return prompter.IndexFor(options, "Submit")
default:
return 0, fmt.Errorf("unexpected select prompt: %s", message)
}
}
},
httpStubs: func(reg *httpmock.Registry, t *testing.T) {
reg.Register(
httpmock.GraphQL(`query UserCurrent\b`),
httpmock.StringResponse(`{"data": {"viewer": {"login": "OWNER"} } }`))
reg.Register(
httpmock.GraphQL(`query PullRequestTemplates\b`),
httpmock.StringResponse(`{ "data": { "repository": { "pullRequestTemplates": [] } } }`),
)
reg.Register(
httpmock.GraphQL(`query RepositoryAssignableUsers\b`),
httpmock.StringResponse(`
{ "data": { "repository": { "assignableUsers": {
"nodes": [
{ "login": "hubot", "id": "HUBOTID", "name": "" },
{ "login": "MonaLisa", "id": "MONAID", "name": "Mona Display Name" }
],
"pageInfo": { "hasNextPage": false }
} } } }
`))
reg.Register(
httpmock.GraphQL(`query OrganizationTeamList\b`),
httpmock.StringResponse(`
{ "data": { "organization": { "teams": {
"nodes": [
{ "slug": "core", "id": "COREID" },
{ "slug": "robots", "id": "ROBOTID" }
],
"pageInfo": { "hasNextPage": false }
} } } }
`))
reg.Register(
httpmock.GraphQL(`mutation PullRequestCreate\b`),
httpmock.GraphQLMutation(`
{ "data": { "createPullRequest": { "pullRequest": {
"id": "NEWPULLID",
"URL": "https://github.com/OWNER/REPO/pull/12"
} } } }
`,
func(inputs map[string]interface{}) {
assert.Equal(t, "TITLE", inputs["title"])
assert.Equal(t, "BODY", inputs["body"])
if v, ok := inputs["assigneeIds"]; ok {
t.Errorf("did not expect assigneeIds: %v", v)
}
if v, ok := inputs["userIds"]; ok {
t.Errorf("did not expect userIds: %v", v)
}
}))
reg.Register(
httpmock.GraphQL(`mutation PullRequestCreateRequestReviews\b`),
httpmock.GraphQLMutation(`
{ "data": { "requestReviews": {
"clientMutationId": ""
} } }
`, func(inputs map[string]interface{}) {
assert.Equal(t, "NEWPULLID", inputs["pullRequestId"])
assert.Equal(t, []interface{}{"COREID"}, inputs["teamIds"])
assert.Equal(t, []interface{}{"MONAID"}, inputs["userIds"])
assert.Equal(t, true, inputs["union"])
}))
},
expectedOut: "https://github.com/OWNER/REPO/pull/12\n",
expectedErrOut: "\nCreating pull request for feature into master in OWNER/REPO\n\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View file

@ -14,7 +14,10 @@ import (
func RequestableReviewersForCompletion(httpClient *http.Client, repo ghrepo.Interface) ([]string, error) {
client := api.NewClientFromHTTP(api.NewCachedHTTPClient(httpClient, time.Minute*2))
metadata, err := api.RepoMetadata(client, repo, api.RepoMetadataInput{Reviewers: true})
metadata, err := api.RepoMetadata(client, repo, api.RepoMetadataInput{
Reviewers: true,
TeamReviewers: true,
})
if err != nil {
return nil, err
}

View file

@ -0,0 +1,120 @@
package shared
import (
"net/http"
"testing"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/stretchr/testify/require"
)
func TestRequestableReviewersForCompletion(t *testing.T) {
tests := []struct {
name string
expectedReviewers []string
httpStubs func(*httpmock.Registry, *testing.T)
}{
{
name: "when users and teams are both available, both are listed",
expectedReviewers: []string{"MonaLisa\tMona Display Name", "OWNER/core", "OWNER/robots", "hubot"},
httpStubs: func(reg *httpmock.Registry, t *testing.T) {
reg.Register(
httpmock.GraphQL(`query UserCurrent\b`),
httpmock.StringResponse(`{"data": {"viewer": {"login": "OWNER"} } }`))
reg.Register(
httpmock.GraphQL(`query RepositoryAssignableUsers\b`),
httpmock.StringResponse(`
{ "data": { "repository": { "assignableUsers": {
"nodes": [
{ "login": "hubot", "id": "HUBOTID", "name": "" },
{ "login": "MonaLisa", "id": "MONAID", "name": "Mona Display Name" }
],
"pageInfo": { "hasNextPage": false }
} } } }
`))
reg.Register(
httpmock.GraphQL(`query OrganizationTeamList\b`),
httpmock.StringResponse(`
{ "data": { "organization": { "teams": {
"nodes": [
{ "slug": "core", "id": "COREID" },
{ "slug": "robots", "id": "ROBOTID" }
],
"pageInfo": { "hasNextPage": false }
} } } }
`))
},
},
{
name: "when users are available but teams aren't, users are listed",
expectedReviewers: []string{"MonaLisa\tMona Display Name", "hubot"},
httpStubs: func(reg *httpmock.Registry, t *testing.T) {
reg.Register(
httpmock.GraphQL(`query UserCurrent\b`),
httpmock.StringResponse(`{"data": {"viewer": {"login": "OWNER"} } }`))
reg.Register(
httpmock.GraphQL(`query RepositoryAssignableUsers\b`),
httpmock.StringResponse(`
{ "data": { "repository": { "assignableUsers": {
"nodes": [
{ "login": "hubot", "id": "HUBOTID", "name": "" },
{ "login": "MonaLisa", "id": "MONAID", "name": "Mona Display Name" }
],
"pageInfo": { "hasNextPage": false }
} } } }
`))
reg.Register(
httpmock.GraphQL(`query OrganizationTeamList\b`),
httpmock.StringResponse(`
{ "data": { "organization": { "teams": {
"nodes": [],
"pageInfo": { "hasNextPage": false }
} } } }
`))
},
},
{
name: "when teams are available but users aren't, teams are listed",
expectedReviewers: []string{"OWNER/core", "OWNER/robots"},
httpStubs: func(reg *httpmock.Registry, t *testing.T) {
reg.Register(
httpmock.GraphQL(`query UserCurrent\b`),
httpmock.StringResponse(`{"data": {"viewer": {"login": "OWNER"} } }`))
reg.Register(
httpmock.GraphQL(`query RepositoryAssignableUsers\b`),
httpmock.StringResponse(`
{ "data": { "repository": { "assignableUsers": {
"nodes": [],
"pageInfo": { "hasNextPage": false }
} } } }
`))
reg.Register(
httpmock.GraphQL(`query OrganizationTeamList\b`),
httpmock.StringResponse(`
{ "data": { "organization": { "teams": {
"nodes": [
{ "slug": "core", "id": "COREID" },
{ "slug": "robots", "id": "ROBOTID" }
],
"pageInfo": { "hasNextPage": false }
} } } }
`))
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
defer reg.Verify(t)
if tt.httpStubs != nil {
tt.httpStubs(reg, t)
}
reviewers, err := RequestableReviewersForCompletion(&http.Client{Transport: reg}, ghrepo.New("OWNER", "REPO"))
require.NoError(t, err)
require.Equal(t, tt.expectedReviewers, reviewers)
})
}
}

View file

@ -181,6 +181,7 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface
// Retrieve and process data for survey prompts based on the extra fields selected
metadataInput := api.RepoMetadataInput{
Reviewers: isChosen("Reviewers"),
TeamReviewers: isChosen("Reviewers"),
Assignees: isChosen("Assignees"),
ActorAssignees: isChosen("Assignees") && state.ActorAssignees,
Labels: isChosen("Labels"),