99 "github.com/depot/cli/pkg/api"
1010 "github.com/depot/cli/pkg/config"
1111 "github.com/depot/cli/pkg/helpers"
12+ civ2 "github.com/depot/cli/pkg/proto/depot/ci/v2"
1213 "github.com/spf13/cobra"
1314)
1415
@@ -21,6 +22,9 @@ func NewCmdSecrets() *cobra.Command {
2122 depot ci secrets add GITHUB_TOKEN
2223 depot ci secrets add MY_API_KEY --value "secret-value"
2324
25+ # Add multiple secrets at once
26+ depot ci secrets add FOO=bar BAZ=qux
27+
2428 # Add a repo-specific secret
2529 depot ci secrets add MY_API_KEY --repo owner/repo --value "secret-value"
2630
@@ -54,31 +58,35 @@ func NewCmdSecretsAdd() *cobra.Command {
5458 )
5559
5660 cmd := & cobra.Command {
57- Use : "add SECRET_NAME" ,
58- Short : "Add a new CI secret" ,
59- Long : `Add a new secret that can be used in Depot CI workflows.
60- If --value is not provided, you will be prompted to enter the secret value securely.
61- Use --repo to scope the secret to a specific repository. Without --repo, the secret
62- applies to all repositories in the organization.` ,
61+ Use : "add [SECRET_NAME | KEY=VALUE ...]" ,
62+ Short : "Add one or more CI secrets" ,
63+ Long : `Add secrets that can be used in Depot CI workflows.
64+
65+ Supports three modes:
66+ 1. Single secret with --value flag: depot ci secrets add SECRET_NAME --value "val"
67+ 2. Single secret with interactive prompt: depot ci secrets add SECRET_NAME
68+ 3. Bulk KEY=VALUE pairs: depot ci secrets add FOO=bar BAZ=qux
69+
70+ The --value and --description flags cannot be used with KEY=VALUE pairs.
71+ Use --repo to scope secrets to a specific repository. Without --repo, secrets
72+ apply to all repositories in the organization.` ,
6373 Example : ` # Add an org-wide secret with interactive prompt
6474 depot ci secrets add GITHUB_TOKEN
6575
6676 # Add an org-wide secret with value from command line
6777 depot ci secrets add MY_API_KEY --value "secret-value"
6878
79+ # Add multiple secrets at once
80+ depot ci secrets add FOO=bar BAZ=qux
81+
6982 # Add a repo-specific secret
7083 depot ci secrets add DATABASE_URL --repo owner/repo --value "prod-db-url"
7184
7285 # Add a secret with description
7386 depot ci secrets add DATABASE_URL --description "Production database connection string"` ,
74- Args : cobra .ExactArgs (1 ),
87+ Args : cobra .MinimumNArgs (1 ),
7588 RunE : func (cmd * cobra.Command , args []string ) error {
7689 ctx := cmd .Context ()
77- secretName := args [0 ]
78-
79- if secretName == "" {
80- return fmt .Errorf ("secret name cannot be empty" )
81- }
8290
8391 if orgID == "" {
8492 orgID = config .GetCurrentOrganization ()
@@ -93,6 +101,59 @@ applies to all repositories in the organization.`,
93101 return fmt .Errorf ("missing API token, please run `depot login`" )
94102 }
95103
104+ scope := "org-wide"
105+ if repo != "" {
106+ scope = repo
107+ }
108+
109+ // Detect KEY=VALUE pairs
110+ hasKVPairs := false
111+ for _ , arg := range args {
112+ if strings .Contains (arg , "=" ) {
113+ hasKVPairs = true
114+ break
115+ }
116+ }
117+
118+ if hasKVPairs {
119+ // Bulk mode: all args must be KEY=VALUE
120+ if value != "" {
121+ return fmt .Errorf ("cannot use --value with KEY=VALUE arguments" )
122+ }
123+ if description != "" {
124+ return fmt .Errorf ("cannot use --description with KEY=VALUE arguments" )
125+ }
126+
127+ var secrets []* civ2.SecretInput
128+ for _ , arg := range args {
129+ parts := strings .SplitN (arg , "=" , 2 )
130+ if len (parts ) != 2 || parts [0 ] == "" {
131+ return fmt .Errorf ("invalid argument %q — expected KEY=VALUE format" , arg )
132+ }
133+ secrets = append (secrets , & civ2.SecretInput {Name : parts [0 ], Value : parts [1 ]})
134+ }
135+
136+ err := api .CIBatchAddSecrets (ctx , tokenVal , orgID , secrets , repo )
137+ if err != nil {
138+ return fmt .Errorf ("failed to add secrets: %w" , err )
139+ }
140+
141+ for _ , s := range secrets {
142+ fmt .Printf ("Successfully added CI secret '%s' (%s)\n " , s .Name , scope )
143+ }
144+ return nil
145+ }
146+
147+ // Single mode: first arg is secret name
148+ if len (args ) > 1 {
149+ return fmt .Errorf ("too many arguments — did you mean to use KEY=VALUE format?" )
150+ }
151+
152+ secretName := args [0 ]
153+ if secretName == "" {
154+ return fmt .Errorf ("secret name cannot be empty" )
155+ }
156+
96157 secretValue := value
97158 if secretValue == "" {
98159 secretValue , err = helpers .PromptForSecret (fmt .Sprintf ("Enter value for secret '%s': " , secretName ))
@@ -106,10 +167,6 @@ applies to all repositories in the organization.`,
106167 return fmt .Errorf ("failed to add secret: %w" , err )
107168 }
108169
109- scope := "org-wide"
110- if repo != "" {
111- scope = repo
112- }
113170 fmt .Printf ("Successfully added CI secret '%s' (%s)\n " , secretName , scope )
114171 return nil
115172 },
0 commit comments