88 "strings"
99 "time"
1010
11+ "github.com/MakeNowJust/heredoc"
1112 "github.com/cli/cli/v2/api"
1213 "github.com/cli/cli/v2/internal/config"
1314 "github.com/cli/cli/v2/internal/ghinstance"
@@ -25,8 +26,9 @@ type ListOptions struct {
2526 Config func () (config.Config , error )
2627 BaseRepo func () (ghrepo.Interface , error )
2728
28- OrgName string
29- EnvName string
29+ OrgName string
30+ EnvName string
31+ UserSecrets bool
3032}
3133
3234func NewCmdList (f * cmdutil.Factory , runF func (* ListOptions ) error ) * cobra.Command {
@@ -39,13 +41,19 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
3941 cmd := & cobra.Command {
4042 Use : "list" ,
4143 Short : "List secrets" ,
42- Long : "List secrets for a repository, environment, or organization" ,
43- Args : cobra .NoArgs ,
44+ Long : heredoc .Doc (`
45+ List secrets on one of the following levels:
46+ - repository (default): available to Actions runs in a repository
47+ - environment: available to Actions runs for a deployment environment in a repository
48+ - organization: available to Actions runs within an organization
49+ - user: available to Codespaces for your user
50+ ` ),
51+ Args : cobra .NoArgs ,
4452 RunE : func (cmd * cobra.Command , args []string ) error {
4553 // support `-R, --repo` override
4654 opts .BaseRepo = f .BaseRepo
4755
48- if err := cmdutil .MutuallyExclusive ("specify only one of `--org` or `--env `" , opts .OrgName != "" , opts .EnvName != "" ); err != nil {
56+ if err := cmdutil .MutuallyExclusive ("specify only one of `--org`, `--env`, or `--user `" , opts .OrgName != "" , opts .EnvName != "" , opts . UserSecrets ); err != nil {
4957 return err
5058 }
5159
@@ -59,6 +67,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
5967
6068 cmd .Flags ().StringVarP (& opts .OrgName , "org" , "o" , "" , "List secrets for an organization" )
6169 cmd .Flags ().StringVarP (& opts .EnvName , "env" , "e" , "" , "List secrets for an environment" )
70+ cmd .Flags ().BoolVarP (& opts .UserSecrets , "user" , "u" , false , "List a secret for your user" )
6271
6372 return cmd
6473}
@@ -73,15 +82,16 @@ func listRun(opts *ListOptions) error {
7382 envName := opts .EnvName
7483
7584 var baseRepo ghrepo.Interface
76- if orgName == "" {
85+ if orgName == "" && ! opts . UserSecrets {
7786 baseRepo , err = opts .BaseRepo ()
7887 if err != nil {
7988 return fmt .Errorf ("could not determine base repo: %w" , err )
8089 }
8190 }
8291
8392 var secrets []* Secret
84- if orgName == "" {
93+ showSelectedRepoInfo := opts .IO .IsStdoutTTY ()
94+ if orgName == "" && ! opts .UserSecrets {
8595 if envName == "" {
8696 secrets , err = getRepoSecrets (client , baseRepo )
8797 } else {
@@ -101,7 +111,11 @@ func listRun(opts *ListOptions) error {
101111 return err
102112 }
103113
104- secrets , err = getOrgSecrets (client , host , orgName )
114+ if opts .UserSecrets {
115+ secrets , err = getUserSecrets (client , host , showSelectedRepoInfo )
116+ } else {
117+ secrets , err = getOrgSecrets (client , host , orgName , showSelectedRepoInfo )
118+ }
105119 }
106120
107121 if err != nil {
@@ -117,7 +131,7 @@ func listRun(opts *ListOptions) error {
117131 }
118132 tp .AddField (updatedAt , nil , nil )
119133 if secret .Visibility != "" {
120- if opts . IO . IsStdoutTTY () {
134+ if showSelectedRepoInfo {
121135 tp .AddField (fmtVisibility (* secret ), nil , nil )
122136 } else {
123137 tp .AddField (strings .ToUpper (string (secret .Visibility )), nil , nil )
@@ -158,25 +172,32 @@ func fmtVisibility(s Secret) string {
158172 return ""
159173}
160174
161- func getOrgSecrets (client httpClient , host , orgName string ) ([]* Secret , error ) {
175+ func getOrgSecrets (client httpClient , host , orgName string , showSelectedRepoInfo bool ) ([]* Secret , error ) {
162176 secrets , err := getSecrets (client , host , fmt .Sprintf ("orgs/%s/actions/secrets" , orgName ))
163177 if err != nil {
164178 return nil , err
165179 }
166180
167- type responseData struct {
168- TotalCount int `json:"total_count"`
181+ if showSelectedRepoInfo {
182+ err = getSelectedRepositoryInformation (client , secrets )
183+ if err != nil {
184+ return nil , err
185+ }
169186 }
187+ return secrets , nil
188+ }
170189
171- for _ , secret := range secrets {
172- if secret .SelectedReposURL == "" {
173- continue
174- }
175- var result responseData
176- if _ , err := apiGet (client , secret .SelectedReposURL , & result ); err != nil {
177- return nil , fmt .Errorf ("failed determining selected repositories for %s: %w" , secret .Name , err )
190+ func getUserSecrets (client httpClient , host string , showSelectedRepoInfo bool ) ([]* Secret , error ) {
191+ secrets , err := getSecrets (client , host , "user/codespaces/secrets" )
192+ if err != nil {
193+ return nil , err
194+ }
195+
196+ if showSelectedRepoInfo {
197+ err = getSelectedRepositoryInformation (client , secrets )
198+ if err != nil {
199+ return nil , err
178200 }
179- secret .NumSelectedRepos = result .TotalCount
180201 }
181202
182203 return secrets , nil
@@ -256,3 +277,22 @@ func findNextPage(link string) string {
256277 }
257278 return ""
258279}
280+
281+ func getSelectedRepositoryInformation (client httpClient , secrets []* Secret ) error {
282+ type responseData struct {
283+ TotalCount int `json:"total_count"`
284+ }
285+
286+ for _ , secret := range secrets {
287+ if secret .SelectedReposURL == "" {
288+ continue
289+ }
290+ var result responseData
291+ if _ , err := apiGet (client , secret .SelectedReposURL , & result ); err != nil {
292+ return fmt .Errorf ("failed determining selected repositories for %s: %w" , secret .Name , err )
293+ }
294+ secret .NumSelectedRepos = result .TotalCount
295+ }
296+
297+ return nil
298+ }
0 commit comments