Skip to content

Commit 1c11dcd

Browse files
committed
semantics update
1 parent 179c121 commit 1c11dcd

File tree

6 files changed

+341
-48
lines changed

6 files changed

+341
-48
lines changed

cmd/src/abc.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package main
33
import (
44
"flag"
55
"fmt"
6+
7+
"github.com/sourcegraph/src-cli/internal/cmderrors"
68
)
79

810
var abcCommands commander
@@ -12,26 +14,43 @@ func init() {
1214
1315
Usage:
1416
15-
src abc command [command options]
17+
src abc <instance-id> command [command options]
1618
1719
The commands are:
1820
1921
variables manage workflow instance variables
2022
21-
Use "src abc [command] -h" for more information about a command.
23+
Use "src abc <instance-id> [command] -h" for more information about a command.
2224
`
2325

2426
flagSet := flag.NewFlagSet("abc", flag.ExitOnError)
27+
usageFunc := func() {
28+
fmt.Println(usage)
29+
}
30+
flagSet.Usage = usageFunc
2531
handler := func(args []string) error {
26-
abcCommands.run(flagSet, "src abc", usage, args)
32+
if err := flagSet.Parse(args); err != nil {
33+
return err
34+
}
35+
36+
if flagSet.NArg() == 0 || flagSet.Arg(0) == "help" {
37+
flagSet.SetOutput(flag.CommandLine.Output())
38+
flagSet.Usage()
39+
return nil
40+
}
41+
42+
if flagSet.NArg() < 2 {
43+
return cmderrors.Usage("must provide an instance ID and subcommand")
44+
}
45+
46+
instanceID := flagSet.Arg(0)
47+
abcCommands.runWithPrefixArgs("src abc <instance-id>", []string{instanceID}, flagSet.Args()[1:])
2748
return nil
2849
}
2950

3051
commands = append(commands, &command{
31-
flagSet: flagSet,
32-
handler: handler,
33-
usageFunc: func() {
34-
fmt.Println(usage)
35-
},
52+
flagSet: flagSet,
53+
handler: handler,
54+
usageFunc: usageFunc,
3655
})
3756
}

cmd/src/abc_variables.go

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,55 @@ package main
33
import (
44
"flag"
55
"fmt"
6+
7+
"github.com/sourcegraph/src-cli/internal/cmderrors"
68
)
79

810
var abcVariablesCommands commander
911

1012
func init() {
11-
usage := `'src abc variables' is a tool that manages workflow instance variables on a Sourcegraph instance.
13+
usage := `'src abc <instance-id> variables' is a tool that manages workflow instance variables on a Sourcegraph instance.
1214
1315
Usage:
1416
15-
src abc variables command [command options]
17+
src abc <instance-id> variables command [command options]
1618
1719
The commands are:
1820
19-
set set or remove a workflow instance variable
21+
set set workflow instance variables
22+
delete delete a workflow instance variable
2023
21-
Use "src abc variables [command] -h" for more information about a command.
24+
Use "src abc <instance-id> variables [command] -h" for more information about a command.
2225
`
2326

2427
flagSet := flag.NewFlagSet("variables", flag.ExitOnError)
28+
usageFunc := func() {
29+
fmt.Println(usage)
30+
}
31+
flagSet.Usage = usageFunc
2532
handler := func(args []string) error {
26-
abcVariablesCommands.run(flagSet, "src abc variables", usage, args)
33+
if len(args) == 0 {
34+
return cmderrors.Usage("must provide an instance ID")
35+
}
36+
37+
instanceID := args[0]
38+
if err := flagSet.Parse(args[1:]); err != nil {
39+
return err
40+
}
41+
42+
if flagSet.NArg() == 0 || flagSet.Arg(0) == "help" {
43+
flagSet.SetOutput(flag.CommandLine.Output())
44+
flagSet.Usage()
45+
return nil
46+
}
47+
48+
abcVariablesCommands.runWithPrefixArgs("src abc <instance-id> variables", []string{instanceID}, flagSet.Args())
2749
return nil
2850
}
2951

3052
abcCommands = append(abcCommands, &command{
31-
flagSet: flagSet,
32-
handler: handler,
33-
usageFunc: func() {
34-
fmt.Println(usage)
35-
},
53+
flagSet: flagSet,
54+
handler: handler,
55+
usageFunc: usageFunc,
3656
})
3757
}

cmd/src/abc_variables_delete.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
8+
"github.com/sourcegraph/src-cli/internal/api"
9+
"github.com/sourcegraph/src-cli/internal/cmderrors"
10+
)
11+
12+
func init() {
13+
usage := `
14+
Examples:
15+
16+
Delete a variable from a workflow instance:
17+
18+
$ src abc QWdlbnRpY1dvcmtmbG93SW5zdGFuY2U6MQ== variables delete approval
19+
`
20+
21+
flagSet := flag.NewFlagSet("delete", flag.ExitOnError)
22+
usageFunc := func() {
23+
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src abc <instance-id> variables %s':\n", flagSet.Name())
24+
flagSet.PrintDefaults()
25+
fmt.Println(usage)
26+
}
27+
apiFlags := api.NewFlags(flagSet)
28+
29+
handler := func(args []string) error {
30+
if len(args) == 0 {
31+
return cmderrors.Usage("must provide an instance ID")
32+
}
33+
34+
instanceID := args[0]
35+
if err := flagSet.Parse(args[1:]); err != nil {
36+
return err
37+
}
38+
if flagSet.NArg() != 1 {
39+
return cmderrors.Usage("must provide exactly one variable name")
40+
}
41+
42+
key := flagSet.Arg(0)
43+
client := cfg.apiClient(apiFlags, flagSet.Output())
44+
if err := updateABCWorkflowInstanceVariables(context.Background(), client, instanceID, []map[string]string{{
45+
"key": key,
46+
"value": "null",
47+
}}); err != nil {
48+
return err
49+
}
50+
51+
if apiFlags.GetCurl() {
52+
return nil
53+
}
54+
55+
fmt.Printf("Removed variable %q from workflow instance %q.\n", key, instanceID)
56+
return nil
57+
}
58+
59+
abcVariablesCommands = append(abcVariablesCommands, &command{
60+
flagSet: flagSet,
61+
handler: handler,
62+
usageFunc: usageFunc,
63+
})
64+
}

cmd/src/abc_variables_set.go

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"flag"
88
"fmt"
9+
"strings"
910

1011
"github.com/sourcegraph/src-cli/internal/api"
1112
"github.com/sourcegraph/src-cli/internal/cmderrors"
@@ -26,69 +27,68 @@ Examples:
2627
2728
Set a string variable on a workflow instance:
2829
29-
$ src abc variables set QWdlbnRpY1dvcmtmbG93SW5zdGFuY2U6MQ== prompt "tighten the review criteria"
30+
$ src abc QWdlbnRpY1dvcmtmbG93SW5zdGFuY2U6MQ== variables set prompt="tighten the review criteria"
3031
31-
Remove a variable by setting it to null:
32+
Set multiple variables in one request:
3233
33-
$ src abc variables set QWdlbnRpY1dvcmtmbG93SW5zdGFuY2U6MQ== approval null
34+
$ src abc QWdlbnRpY1dvcmtmbG93SW5zdGFuY2U6MQ== variables set --var prompt="tighten the review criteria" --var checkpoints='[1,2,3]'
3435
3536
Set a structured JSON value:
3637
37-
$ src abc variables set QWdlbnRpY1dvcmtmbG93SW5zdGFuY2U6MQ== checkpoints '[1,2,3]'
38+
$ src abc QWdlbnRpY1dvcmtmbG93SW5zdGFuY2U6MQ== variables set checkpoints='[1,2,3]'
3839
3940
Values are interpreted as JSON literals when valid. Otherwise they are sent as plain strings.
4041
`
4142

4243
flagSet := flag.NewFlagSet("set", flag.ExitOnError)
44+
var variableArgs abcVariableArgs
45+
flagSet.Var(&variableArgs, "var", "Variable assignment in <name>=<value> form. Repeat to set multiple variables.")
4346
usageFunc := func() {
44-
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src abc variables %s':\n", flagSet.Name())
47+
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src abc <instance-id> variables %s':\n", flagSet.Name())
4548
flagSet.PrintDefaults()
4649
fmt.Println(usage)
4750
}
4851
apiFlags := api.NewFlags(flagSet)
4952

5053
handler := func(args []string) error {
51-
if err := flagSet.Parse(args); err != nil {
52-
return err
54+
if len(args) == 0 {
55+
return cmderrors.Usage("must provide an instance ID")
5356
}
5457

55-
if flagSet.NArg() != 3 {
56-
return cmderrors.Usage("must provide an instance ID, variable name, and variable value")
58+
instanceID := args[0]
59+
variableArgs = nil
60+
if err := flagSet.Parse(args[1:]); err != nil {
61+
return err
5762
}
5863

59-
instanceID := flagSet.Arg(0)
60-
key := flagSet.Arg(1)
61-
value, remove, err := marshalABCVariableValue(flagSet.Arg(2))
64+
variables, err := parseABCVariables(flagSet.Args(), variableArgs)
6265
if err != nil {
6366
return err
6467
}
6568

66-
client := cfg.apiClient(apiFlags, flagSet.Output())
67-
var result struct {
68-
UpdateAgenticWorkflowInstanceVariables struct {
69-
ID string `json:"id"`
70-
} `json:"updateAgenticWorkflowInstanceVariables"`
69+
graphqlVariables := make([]map[string]string, 0, len(variables))
70+
for _, variable := range variables {
71+
graphqlVariables = append(graphqlVariables, map[string]string{
72+
"key": variable.Key,
73+
"value": variable.Value,
74+
})
7175
}
72-
if ok, err := client.NewRequest(updateABCWorkflowInstanceVariablesMutation, map[string]any{
73-
"instanceID": instanceID,
74-
"variables": []map[string]string{{
75-
"key": key,
76-
"value": value,
77-
}},
78-
}).Do(context.Background(), &result); err != nil || !ok {
76+
77+
client := cfg.apiClient(apiFlags, flagSet.Output())
78+
if err := updateABCWorkflowInstanceVariables(context.Background(), client, instanceID, graphqlVariables); err != nil {
7979
return err
8080
}
8181

8282
if apiFlags.GetCurl() {
8383
return nil
8484
}
8585

86-
if remove {
87-
fmt.Printf("Removed variable %q from workflow instance %q.\n", key, instanceID)
86+
if len(variables) == 1 {
87+
fmt.Printf("Set variable %q on workflow instance %q.\n", variables[0].Key, instanceID)
8888
return nil
8989
}
9090

91-
fmt.Printf("Set variable %q on workflow instance %q.\n", key, instanceID)
91+
fmt.Printf("Updated %d variables on workflow instance %q.\n", len(variables), instanceID)
9292
return nil
9393
}
9494

@@ -99,9 +99,78 @@ Values are interpreted as JSON literals when valid. Otherwise they are sent as p
9999
})
100100
}
101101

102+
type abcVariableArgs []string
103+
104+
func (a *abcVariableArgs) String() string {
105+
return strings.Join(*a, ",")
106+
}
107+
108+
func (a *abcVariableArgs) Set(value string) error {
109+
*a = append(*a, value)
110+
return nil
111+
}
112+
113+
type abcVariable struct {
114+
Key string
115+
Value string
116+
}
117+
118+
func parseABCVariables(positional []string, flagged abcVariableArgs) ([]abcVariable, error) {
119+
rawVariables := append([]string{}, positional...)
120+
rawVariables = append(rawVariables, flagged...)
121+
if len(rawVariables) == 0 {
122+
return nil, cmderrors.Usage("must provide at least one variable assignment")
123+
}
124+
125+
variables := make([]abcVariable, 0, len(rawVariables))
126+
for _, rawVariable := range rawVariables {
127+
variable, err := parseABCVariable(rawVariable)
128+
if err != nil {
129+
return nil, err
130+
}
131+
variables = append(variables, variable)
132+
}
133+
134+
return variables, nil
135+
}
136+
137+
func parseABCVariable(raw string) (abcVariable, error) {
138+
name, rawValue, ok := strings.Cut(raw, "=")
139+
if !ok || name == "" {
140+
return abcVariable{}, cmderrors.Usagef("invalid variable assignment %q: must be in <name>=<value> form", raw)
141+
}
142+
143+
value, remove, err := marshalABCVariableValue(rawValue)
144+
if err != nil {
145+
return abcVariable{}, err
146+
}
147+
if remove {
148+
return abcVariable{}, cmderrors.Usagef("invalid variable assignment %q: use 'src abc <instance-id> variables delete %s' to remove a variable", raw, name)
149+
}
150+
151+
return abcVariable{Key: name, Value: value}, nil
152+
}
153+
154+
func updateABCWorkflowInstanceVariables(ctx context.Context, client api.Client, instanceID string, variables []map[string]string) error {
155+
var result struct {
156+
UpdateAgenticWorkflowInstanceVariables struct {
157+
ID string `json:"id"`
158+
} `json:"updateAgenticWorkflowInstanceVariables"`
159+
}
160+
if ok, err := client.NewRequest(updateABCWorkflowInstanceVariablesMutation, map[string]any{
161+
"instanceID": instanceID,
162+
"variables": variables,
163+
}).Do(ctx, &result); err != nil || !ok {
164+
return err
165+
}
166+
167+
return nil
168+
}
169+
102170
func marshalABCVariableValue(raw string) (value string, remove bool, err error) {
103-
// Try to compact valid JSON literals first. This allows us to send null to delete values, as well as raw numbers.
104-
// If we that doesn't work for the given value, fall back to string encoding.
171+
// Try to compact valid JSON literals first so numbers, arrays, and objects are sent unchanged.
172+
// A bare null is detected separately so the CLI can require the explicit delete command.
173+
// If compacting doesn't work for the given value, fall back to string encoding.
105174
var compact bytes.Buffer
106175
if err := json.Compact(&compact, []byte(raw)); err == nil {
107176
value := compact.String()

0 commit comments

Comments
 (0)