8000 Support `--no-repos-selected` on `gh secret set` by williammartin · Pull Request #11217 · cli/cli · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Support --no-repos-selected on gh secret set #11217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

williammartin
Copy link
Member
@williammartin williammartin commented Jul 3, 2025

Description

Fixes #9808

Acceptance Criteria

Given there is no secret
When I run gh secret set <secret_name> -b <secret_value> -o <org> -v selected --no-repos-selected
Then a secret called <secret_name> is created in with a value of <secret_value> with the selected visibility and no repositories selected.

➜ gh secret list --org williammartin-test-org | cat

➜ gh secret set TEST -b BODY -o williammartin-test-org -v selected --no-repos-selected
✓ Set Actions secret TEST for williammartin-test-org

➜ gh api /orgs/williammartin-test-org/actions/secrets/TEST/repositories | cat
{"total_count":0,"repositories":[]}%

Given there is an existing secret with <secret_name>
When I run gh secret set <secret_name> -b <secret_value> -o <org> -v selected --no-repos-selected
Then that secret is replaced with a value of <secret_value> with the selected visibility and no repositories selected.

➜ ./bin/gh secret set TEST -b BODY -o williammartin-test-org -v selected --repos test-repo                                                                                                                                                                 ✓ Set Actions secret TEST for williammartin-test-org

➜ gh api /orgs/williammartin-test-org/actions/secrets/TEST/repositories | cat
{"total_count":1,"repositories":[{"id":902814034,"node_id":"R_kgDONc_ZUg","name":"test-repo","full_name":"williammartin-test-org/test-repo","private":true,"owner":{"login":"williammartin-test-org","id":132901068,"node_id":"O_kgDOB-vozA","avatar_url":"https://avatars.githubusercontent.com/u/132901068?v=4","gravatar_id":"","url":"https://api.github.com/users/williammartin-test-org","html_url":"https://github.com/williammartin-test-org","followers_url":"https://api.github.com/users/williammartin-test-org/followers","following_url":"https://api.github.com/users/williammartin-test-org/following{/other_user}","gists_url":"https://api.github.com/users/williammartin-test-org/gists{/gist_id}","starred_url":"https://api.github.com/users/williammartin-test-org/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/williammartin-test-org/subscriptions","organizations_url":"https://api.github.com/users/williammartin-test-org/orgs","repos_url":"https://api.github.com/users/williammartin-test-org/repos","events_url":"https://api.github.com/users/williammartin-test-org/events{/privacy}","received_events_url":"https://api.github.com/users/williammartin-test-org/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/williammartin-test-org/test-repo","description":null,"fork":false,"url":"https://api.github.com/repos/williammartin-test-org/test-repo","forks_url":"https://api.github.com/repos/williammartin-test-org/test-repo/forks","keys_url":"https://api.github.com/repos/williammartin-test-org/test-repo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/williammartin-test-org/test-repo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/williammartin-test-org/test-repo/teams","hooks_url":"https://api.github.com/repos/williammartin-test-org/test-repo/hooks","issue_events_url":"https://api.github.com/repos/williammartin-test-org/test-repo/issues/events{/number}","events_url":"https://api.github.com/repos/williammartin-test-org/test-repo/events","assignees_url":"https://api.github.com/repos/williammartin-test-org/test-repo/assignees{/user}","branches_url":"https://api.github.com/repos/williammartin-test-org/test-repo/branches{/branch}","tags_url":"https://api.github.com/repos/williammartin-test-org/test-repo/tags","blobs_url":"https://api.github.com/repos/williammartin-test-org/test-repo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/williammartin-test-org/test-repo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/williammartin-test-org/test-repo/git/refs{/sha}","trees_url":"https://api.github.com/repos/williammartin-test-org/test-repo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/williammartin-test-org/test-repo/statuses/{sha}","languages_url":"https://api.github.com/repos/williammartin-test-org/test-repo/languages","stargazers_url":"https://api.github.com/repos/williammartin-test-org/test-repo/stargazers","contributors_url":"https://api.github.com/repos/williammartin-test-org/test-repo/contributors","subscribers_url":"https://api.github.com/repos/williammartin-test-org/test-repo/subscribers","subscription_url":"https://api.github.com/repos/williammartin-test-org/test-repo/subscription","commits_url":"https://api.github.com/repos/williammartin-test-org/test-repo/commits{/sha}","git_commits_url":"https://api.github.com/repos/williammartin-test-org/test-repo/git/commits{/sha}","comments_url":"https://api.github.com/repos/williammartin-test-org/test-repo/comments{/number}","issue_comment_url":"https://api.github.com/repos/williammartin-test-org/test-repo/issues/comments{/number}","contents_url":"https://api.github.com/repos/williammartin-test-org/test-repo/contents/{+path}","compare_url":"https://api.github.com/repos/williammartin-test-org/test-repo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/williammartin-test-org/test-repo/merges","archive_url":"https://api.github.com/repos/williammartin-test-org/test-repo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/williammartin-test-org/test-repo/downloads","issues_url":"https://api.github.com/repos/williammartin-test-org/test-repo/issues{/number}","pulls_url":"https://api.github.com/repos/williammartin-test-org/test-repo/pulls{/number}","milestones_url":"https://api.github.com/repos/williammartin-test-org/test-repo/milestones{/number}","notifications_url":"https://api.github.com/repos/williammartin-test-org/test-repo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/williammartin-test-org/test-repo/labels{/name}","releases_url":"https://api.github.com/repos/williammartin-test-org/test-repo/releases{/id}","deployments_url":"https://api.github.com/repos/williammartin-test-org/test-repo/deployments"}]}%

➜ ./bin/gh secret set TEST -b BODY -o williammartin-test-org -v selected --no-repos-selected
✓ Set Actions secret TEST for williammartin-test-org

➜ gh api /orgs/williammartin-test-org/actions/secrets/TEST/repositories | cat
{"total_count":0,"repositories":[]}%

When I run gh secret set <secret_name> -b <secret_value> -o <org> -v selected --no-repos-selected --repos
Then then I receive an error message indicating the mutual exclusivity of the --no-repos-selected and --repos flags

➜ ./bin/gh secret set TEST -b BODY -o williammartin-test-org -v selected --no-repos-selected --repos cli/cli
specify only one of `--repos` or `--no-repos-selected`

When I run gh secret set <secret_name> -b <secret_value> -o <org> --no-repos-selected
Then then --visibility selected is implied

➜ ./bin/gh secret set TEST -b BODY -o williammartin-test-org --no-repos-selected
✓ Set Actions secret TEST for williammartin-test-org

➜ gh api /orgs/williammartin-test-org/actions/secrets/TEST/repositories | cat                                                                                                             {"total_count":0,"repositories":[]}%

When I run gh secret set <secret_name> -b <secret_value> -o <org> -v <private/all> --no-repos-selected
Then then I receive an error message indicating that --no-repos-selected may only be used with --visibility selected

➜ ./bin/gh secret set TEST -b BODY -o williammartin-test-org -v private --no-repos-selected
`--no-repos-selected` is only supported with `--visibility=selected`

When I run gh secret set <secret_name> -b <secret_value> -o <org> -v selected
Then then I receive an error message indicating that providing either a list of repos with --repos or --no-repo-selected is required.

➜ ./bin/gh secret set TEST -b BODY -o williammartin-test-org -v selected
`--repos` or `--no-repos-selected` required with `--visibility=selected`

When I run gh secret set --help
Then then there is a note about --no-repos-selected that indicates if there are any repos selected on an existing secret, then they will be cleared.A

➜ ./bin/gh secret set --help
Set a value for a secret on one of the following levels:
- repository (default): available to GitHub Actions runs or Dependabot in a repository
- environment: available to GitHub Actions runs for a deployment environment in a repository
- organization: available to GitHub Actions runs, Dependabot, or Codespaces within an organization
- user: available to Codespaces for your user

Organization and user secrets can optionally be restricted to only be available to
specific repositories.

Secret values are locally encrypted before being sent to GitHub.


USAGE
  gh secret set <secret-name> [flags]

FLAGS
  -a, --app string           Set the application for a secret: {actions|codespaces|dependabot}
  -b, --body string          The value for the secret (reads from standard input if not specified)
  -e, --env environment      Set deployment environment secret
  -f, --env-file file        Load secret names and values from a dotenv-formatted file
      --no-repos-selected    No repositories can access the organization or user secret
      --no-store             Print the encrypted, base64-encoded value instead of storing it on GitHub
  -o, --org organization     Set organization secret
  -r, --repos repositories   List of repositories that can access an organization secret
  -u, --user                 Set a secret for your user
  -v, --visibility string    Set visibility for an organization secret: {all|private|selected} (default "private")

INHERITED FLAGS
      --help                     Show help for command
  -R, --repo [HOST/]OWNER/REPO   Select another repository using the [HOST/]OWNER/REPO format

EXAMPLES
  # Paste secret value for the current repository in an interactive prompt
  $ gh secret set MYSECRET

  # Read secret value from an environment variable
  $ gh secret set MYSECRET --body "$ENV_VALUE"

  # Set secret for a specific remote repository
  $ gh secret set MYSECRET --repo origin/repo --body "$ENV_VALUE"

  # Read secret value from a file
  $ gh secret set MYSECRET < myfile.txt

  # Set secret for a deployment environment in the current repository
  $ gh secret set MYSECRET --env myenvironment

  # Set organization-level secret visible to both public and private repositories
  $ gh secret set MYSECRET --org myOrg --visibility all

  # Set organization-level secret visible to specific repositories
  $ gh secret set MYSECRET --org myOrg --repos repo1,repo2,repo3

  # Set organization-level secret visible to no repositories
  $ gh secret set MYSECRET --org myOrg --no-repos-selected

  # Set user-level secret for Codespaces
  $ gh secret set MYSECRET --user

  # Set repository-level secret for Dependabot
  $ gh secret set MYSECRET --app dependabot

  # Set multiple secrets imported from the ".env" file
  $ gh secret set -f .env

  # Set multiple secrets from stdin
  $ gh secret set -f - < myfile.txt

LEARN MORE
  Use `gh <command> <subcommand> --help` for more information about a command.
  Read the manual at https://cli.github.com/manual
  Learn about exit codes using `gh help exit-codes`
  Learn about accessibility experiences using `gh help accessibility`

Acceptance Test

➜ GOMAXPROCS=1 GH_ACCEPTANCE_HOST=github.com GH_ACCEPTANCE_ORG=gh-acceptance-testing GH_ACCEPTANCE_SCRIPT=secret-org-with-selected-visibility.txtar go test -count=1 -tags=acceptance -run ^TestSecrets$ ./acceptance -v
=== RUN   TestSecrets
=== RUN   TestSecrets/secret-org-with-selected-visibility
=== PAUSE TestSecrets/secret-org-with-selected-visibility
=== CONT  TestSecrets/secret-org-with-selected-visibility
    testscript.go:584: WORK=$WORK
        PATH=/var/folders/45/sdnm1hp10nj1s9q57dp3bc5h0000gn/T/testscript-main1133164272/bin:/opt/homebrew/opt/go/libexec/bin:/Users/williammartin/.bun/bin:/Users/williammartin/.bun/bin:/Users/williammartin/.local/bin:/opt/homebrew/opt/go/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/usr/local/MacGPG2/bin:/Applications/Wireshark.app/Contents/MacOS:/Applications/VMware Fusion.app/Contents/Public:/usr/local/go/bin:/Users/williammartin/.cargo/bin:/Applications/Ghostty.app/Contents/MacOS:/Users/williammartin/go/bin/:/opt/homebrew/opt/go/libexec/bin
        GOTRACEBACK=system
        HOME=$WORK
        TMPDIR=$WORK/.tmp
        devnull=/dev/null
        /=/
        :=:
        $=$
        exe=
        SCRIPT_NAME=secret_org_with_selected_visibility
        GH_CONFIG_DIR=$WORK
        GH_HOST=github.com
        ORG=gh-acceptance-testing
        GH_TOKEN=ghp_************************************
        RANDOM_STRING=DWbDxBVpDI

        # Setup environment variables used for testscript (0.000s)
        > env REPO=${SCRIPT_NAME}-${RANDOM_STRING}
        > env2upper SECRET_NAME=${SCRIPT_NAME}_${RANDOM_STRING}
        # Use gh as a credential helper (0.567s)
        > exec gh auth setup-git
        # Create a repository with a file so it has a default branch (1.702s)
        > exec gh repo create ${ORG}/${REPO} --add-readme --private
        [stdout]
        https://github.com/gh-acceptance-testing/secret_org_with_selected_visibility-DWbDxBVpDI
        # Defer repo cleanup (0.000s)
        > defer gh repo delete --yes ${ORG}/${REPO}
        # Confirm organization secret does not exist, will fail admin:org scope missing (0.330s)
        > exec gh secret list --org ${ORG}
        [stdout]
        SECRET_ORG_UZKSOQYGTO   2025-07-03T14:40:27Z    SELECTED
        SECRET_ORG_XYTTEDZKWF   2025-07-03T14:37:13Z    SELECTED
        > ! stdout ${SECRET_NAME}
        # Set an organization secret with no shared visibility, but no repos (0.529s)
        > exec gh secret set ${SECRET_NAME} --org ${ORG} --body 'just an organization secret' --no-repos-selected
        # Defer organization secret cleanup (0.000s)
        > defer gh secret delete ${SECRET_NAME} --org ${ORG}
        # Verify new organization secret exists with shared visibility (0.278s)
        > exec gh api -X GET /orgs/${ORG}/actions/secrets/${SECRET_NAME} --jq '.visibility'
        [stdout]
        selected
        > stdout selected
        # Verify the secret is not shared with any repositories (0.314s)
        > exec gh api -X GET /orgs/${ORG}/actions/secrets/${SECRET_NAME}/repositories --jq '.repositories | length'
        [stdout]
        0
        > stdout 0
        # Set the same organization secret with shared visibility to the previously created repository (0.963s)
        > exec gh secret set ${SECRET_NAME} --org ${ORG} --body 'just an organization secret' --repos ${REPO}
        # Verify the secret is now shared with the repository (0.313s)
        > exec gh api -X GET /orgs/${ORG}/actions/secrets/${SECRET_NAME}/repositories --jq '.repositories[0].name'
        [stdout]
        secret_org_with_selected_visibility-DWbDxBVpDI
        > stdout ${REPO}
        # Set the same organization secret with shared visibility back  to no repositories selected (0.560s)
        > exec gh secret set ${SECRET_NAME} --org ${ORG} --body 'just an organization secret' --no-repos-selected
        # Verify the secret is not shared with any repositories (0.304s)
        > exec gh api -X GET /orgs/${ORG}/actions/secrets/${SECRET_NAME}/repositories --jq '.repositories | length'
        [stdout]
        0
        > stdout 0
        PASS

--- PASS: TestSecrets (0.00s)
    --- PASS: TestSecrets/secret-org-with-selected-visibility (6.71s)
PASS
ok      github.com/cli/cli/v2/acceptance        7.153s

@Copilot Copilot AI review requested due to automatic review settings July 3, 2025 15:04
@williammartin williammartin requested a review from a team as a code owner July 3, 2025 15:04
@williammartin williammartin requested a review from andyfeller July 3, 2025 15:04
@williammartin williammartin requested review from BagToad and removed request for andyfeller July 3, 2025 15:05
@BagToad BagToad changed the title Support --no-repos-selected on secret set Support --no-repos-selected on secret set Jul 3, 2025
@BagToad BagToad changed the title Support --no-repos-selected on secret set Support --no-repos-selected on gh secret set Jul 3, 2025
Copy link
Contributor
@Copilot 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

This PR introduces support for the --no-repos-selected flag when setting organization secrets, enforces mutual-exclusivity rules among --repos, --no-repos-selected, and --user, and updates tests to cover these new behaviors.

  • Adds a noRepositoriesSelected flag and corresponding help text in set.go
  • Implements validation logic for mutual exclusivity and visibility combinations
  • Expands set_test.go with new test cases for --no-repos-selected, implicit selected visibility, and mutual-exclusion errors

Reviewed Changes

Copilot reviewed 2 out of 4 changed files in this pull request and generated 2 comments.

File Description
pkg/cmd/secret/set/set.go Introduce --no-repos-selected flag, add validation in NewCmdSet, update examples
pkg/cmd/secret/set/set_test.go Migrate tests from cli to args, add cases and error‐message checks for the new flag
Files not reviewed (2)
  • acceptance/testdata/secret/secret-org-with-selected-visibility.txtar: Language not supported
  • acceptance/testdata/secret/secret-org.txtar: Language not supported
Comments suppressed due to low confidence (2)

pkg/cmd/secret/set/set_test.go:41

  • [nitpick] The test checks that an error occurs for invalid visibility but doesn't assert the specific error message. Consider adding wantsErrMessage to verify the correct message is emitted.
		},

pkg/cmd/secret/set/set.go:142

  • This mutual-​exclusivity check is nested under if len(args) == 0, so it won't run in the normal code path when a secret name is provided. Move these validation calls before the args length check or use cobra.ExactArgs(1) so they apply on every invocation.
			if err := cmdutil.MutuallyExclusive("specify only one of `--repos` or `--no-repos-selected`", len(opts.RepositoryNames) > 0, noRepositoriesSelected); err != nil {

@williammartin williammartin enabled auto-merge July 3, 2025 15:12
@williammartin williammartin disabled auto-merge July 3, 2025 15:12
@williammartin williammartin merged commit d641722 into trunk Jul 3, 2025
19 checks passed
@williammartin williammartin deleted the 9808-gh-secret-set-using-selected-visibility-requires-a-list-of-repositories-its-optional-in-the-apibrowser branch July 3, 2025 15:24
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.

"gh secret set" using selected visibility requires a list of repositories, its optional in the API/browser
2 participants
0