Skip to content

Commit cc1a0b6

Browse files
authored
chore(trigger-argo-workflow): use cli/v3 (#1127)
* chore(trigger-argo-workflow): use cli/v3 * Move submit command into proper subcommand This is necessary because otherwise the extraArgs would interfere with the rest of the argument parsing. Despite that, this change should not be breaking since the `submit` command was also necessary in the previous implementation. * Add test for root commandline parsing This should prevent issues with changes down the line with the way that cli/v* deals with arguments and flags on subcommands. * Remove not-used check condition
1 parent e9a3e88 commit cc1a0b6

File tree

5 files changed

+182
-48
lines changed

5 files changed

+182
-48
lines changed

actions/trigger-argo-workflow/cmd/trigger-argo-workflow/argo.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"bufio"
55
"context"
6+
"encoding/json"
67
"fmt"
78
"io"
89
"log/slog"
@@ -33,6 +34,36 @@ type App struct {
3334
retries uint64
3435
}
3536

37+
type FullConfig struct {
38+
ArgoToken string
39+
LogLevel *slog.LevelVar
40+
AddCILabels bool
41+
Command string
42+
ExtraArgs []string
43+
Instance string
44+
Namespace string
45+
Retries uint64
46+
WorkflowTemplate string
47+
GitHubActionsMetadata GitHubActionsMetadata
48+
}
49+
50+
func (a App) PrintConfig(w io.Writer, md GitHubActionsMetadata) error {
51+
cfg := FullConfig{
52+
ArgoToken: a.argoToken,
53+
LogLevel: a.levelVar,
54+
Command: a.command,
55+
WorkflowTemplate: a.workflowTemplate,
56+
Instance: a.instance,
57+
Namespace: a.namespace,
58+
Retries: a.retries,
59+
ExtraArgs: a.extraArgs,
60+
GitHubActionsMetadata: md,
61+
}
62+
enc := json.NewEncoder(w)
63+
enc.SetIndent("", " ")
64+
return enc.Encode(cfg)
65+
}
66+
3667
var instanceToHost = map[string]string{
3768
"dev": "argo-workflows-dev.grafana.net:443",
3869
"ops": "argo-workflows.grafana.net:443",

actions/trigger-argo-workflow/cmd/trigger-argo-workflow/main.go

Lines changed: 83 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
6+
"io"
57
"log/slog"
68
"maps"
79
"os"
810
"slices"
911
"strings"
1012

1113
"github.com/lmittmann/tint"
12-
cli "github.com/urfave/cli/v2"
14+
cli "github.com/urfave/cli/v3"
1315
"github.com/willabides/actionslog"
1416
"github.com/willabides/actionslog/human"
1517
"golang.org/x/term"
@@ -23,6 +25,7 @@ const (
2325
flagNamespace = "namespace"
2426
flagParameter = "parameter"
2527
flagRetries = "retries"
28+
flagPrintConfig = "print-config"
2629
flagWorkflowTemplate = "workflow-template"
2730
)
2831

@@ -42,13 +45,17 @@ func parseLogLevel(level string) (slog.Level, error) {
4245
}
4346

4447
func main() {
48+
runMain(os.Args, os.Stdout, os.Stderr)
49+
}
50+
51+
func runMain(args []string, writer io.Writer, errWriter io.Writer) {
4552
// If we're on a terminal, we use tint, otherwise if we're on GitHub actions
4653
// we use `willabites/actionslog` to log proper Actions messages, otherwise
4754
// we use logfmt.
4855
var lv slog.LevelVar
4956

5057
logger := slog.New(
51-
slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
58+
slog.NewTextHandler(errWriter, &slog.HandlerOptions{
5259
Level: &lv,
5360
}),
5461
)
@@ -69,35 +76,64 @@ func main() {
6976
)
7077
}
7178

72-
app := cli.NewApp()
79+
app := cli.Command{}
80+
app.Writer = writer
81+
app.ErrWriter = errWriter
7382
app.Name = "Runs the Argo CLI"
7483

75-
app.Action = func(c *cli.Context) error { return run(c, &lv, logger) }
84+
app.Action = func(ctx context.Context, c *cli.Command) error {
85+
return fmt.Errorf("please specify a command")
86+
}
87+
88+
app.Commands = []*cli.Command{
89+
{
90+
Name: "submit",
91+
SkipFlagParsing: true,
92+
Writer: writer,
93+
ErrWriter: errWriter,
94+
Action: func(ctx context.Context, c *cli.Command) error {
95+
return run(ctx, c, &lv, logger, "submit")
96+
},
97+
},
98+
}
7699

77100
app.Flags = []cli.Flag{
78101
&cli.BoolFlag{
79-
Name: flagAddCILabels,
80-
EnvVars: []string{"ADD_CI_LABELS"},
81-
Value: false,
82-
Usage: "If true, the `--labels` argument will be added with values from the environment. This is forced for the `submit` command",
102+
Name: flagPrintConfig,
103+
Required: false,
104+
Usage: "If set thie command will only print the gathered configuration and exist",
105+
},
106+
&cli.BoolFlag{
107+
Name: flagAddCILabels,
108+
Sources: cli.NewValueSourceChain(
109+
cli.EnvVar("ADD_CI_LABELS"),
110+
),
111+
Value: false,
112+
Usage: "If true, the `--labels` argument will be added with values from the environment. This is forced for the `submit` command",
83113
},
84114
&cli.StringFlag{
85-
Name: flagNamespace,
86-
EnvVars: []string{"ARGO_NAMESPACE"},
115+
Name: flagNamespace,
116+
Sources: cli.NewValueSourceChain(
117+
cli.EnvVar("ARGO_NAMESPACE"),
118+
),
87119
Required: true,
88120
},
89121
&cli.StringFlag{
90-
Name: flagArgoToken,
91-
EnvVars: []string{"ARGO_TOKEN"},
122+
Name: flagArgoToken,
123+
Sources: cli.NewValueSourceChain(
124+
cli.EnvVar("ARGO_TOKEN"),
125+
),
92126
Usage: "The Argo token to use for authentication",
93127
Required: true,
94128
},
95129
&cli.StringFlag{
96-
Name: flagLogLevel,
97-
EnvVars: []string{"LOG_LEVEL"},
98-
Usage: "Which log level to use",
99-
Value: "info",
100-
Action: func(c *cli.Context, level string) error {
130+
Name: flagLogLevel,
131+
Sources: cli.NewValueSourceChain(
132+
cli.EnvVar("LOG_LEVEL"),
133+
),
134+
Usage: "Which log level to use",
135+
Value: "info",
136+
Action: func(ctx context.Context, c *cli.Command, level string) error {
101137
level = strings.ToLower(level)
102138

103139
lvl, err := parseLogLevel(level)
@@ -111,10 +147,12 @@ func main() {
111147
},
112148
},
113149
&cli.StringFlag{
114-
Name: flagInstance,
115-
EnvVars: []string{"INSTANCE"},
116-
Value: "ops",
117-
Action: func(c *cli.Context, instance string) error {
150+
Name: flagInstance,
151+
Sources: cli.NewValueSourceChain(
152+
cli.EnvVar("INSTANCE"),
153+
),
154+
Value: "ops",
155+
Action: func(ctx context.Context, c *cli.Command, instance string) error {
118156
// Validate it is a known instance
119157
instances := slices.Collect(maps.Keys(instanceToHost))
120158
if !slices.Contains(instances, instance) {
@@ -129,16 +167,20 @@ func main() {
129167
Usage: "Parameters to pass to the workflow template. Given as `key=value`. Specify multiple times for multiple parameters",
130168
},
131169
&cli.UintFlag{
132-
Name: flagRetries,
133-
EnvVars: []string{"RETRIES"},
134-
Value: 3,
135-
Usage: "Number of retries to make if the command fails",
170+
Name: flagRetries,
171+
Sources: cli.NewValueSourceChain(
172+
cli.EnvVar("RETRIES"),
173+
),
174+
Value: 3,
175+
Usage: "Number of retries to make if the command fails",
136176
},
137177
&cli.StringFlag{
138-
Name: flagWorkflowTemplate,
139-
EnvVars: []string{"WORKFLOW_TEMPLATE"},
140-
Usage: "The workflow template to use",
141-
Action: func(c *cli.Context, tpl string) error {
178+
Name: flagWorkflowTemplate,
179+
Sources: cli.NewValueSourceChain(
180+
cli.EnvVar("WORKFLOW_TEMPLATE"),
181+
),
182+
Usage: "The workflow template to use",
183+
Action: func(ctx context.Context, c *cli.Command, tpl string) error {
142184
// Required if command is `submit`
143185
if c.Args().First() == "submit" && tpl == "" {
144186
return fmt.Errorf("required flag: %s", flagWorkflowTemplate)
@@ -148,16 +190,15 @@ func main() {
148190
},
149191
}
150192

151-
if err := app.Run(os.Args); err != nil {
193+
if err := app.Run(context.Background(), args); err != nil {
152194
logger.With("error", err).Error("failed to run")
153195
os.Exit(1)
154196
}
155197
}
156198

157-
func run(c *cli.Context, level *slog.LevelVar, logger *slog.Logger) error {
199+
func run(ctx context.Context, c *cli.Command, level *slog.LevelVar, logger *slog.Logger, command string) error {
158200
addCILabels := c.Bool(flagAddCILabels)
159201
argoToken := c.String(flagArgoToken)
160-
command := c.Args().First()
161202
instance := c.String(flagInstance)
162203
namespace := c.String(flagNamespace)
163204
parameters := c.StringSlice(flagParameter)
@@ -173,7 +214,7 @@ func run(c *cli.Context, level *slog.LevelVar, logger *slog.Logger) error {
173214
extraArgs = append(extraArgs, "--parameter", param)
174215
}
175216

176-
extraArgs = append(extraArgs, c.Args().Tail()...)
217+
extraArgs = append(extraArgs, c.Args().Slice()...)
177218

178219
md, err := NewGitHubActionsMetadata()
179220
if err != nil {
@@ -192,8 +233,6 @@ func run(c *cli.Context, level *slog.LevelVar, logger *slog.Logger) error {
192233
"namespace", namespace,
193234
)
194235

195-
logger.With("extraArgs", extraArgs).Info("running command")
196-
197236
argo := App{
198237
levelVar: level,
199238
logger: logger,
@@ -212,5 +251,13 @@ func run(c *cli.Context, level *slog.LevelVar, logger *slog.Logger) error {
212251
retries: retries,
213252
}
214253

215-
return argo.Run(c.Context, md)
254+
if c.Bool(flagPrintConfig) {
255+
if err := argo.PrintConfig(c.Writer, md); err != nil {
256+
return err
257+
}
258+
return nil
259+
}
260+
261+
logger.With("extraArgs", extraArgs).Info("running command")
262+
return argo.Run(ctx, md)
216263
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"log/slog"
7+
"os"
8+
"testing"
9+
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestMainConfiguration(t *testing.T) {
14+
tests := map[string]struct {
15+
args []string
16+
env map[string]string
17+
check func(t *testing.T, cfg FullConfig)
18+
}{
19+
"with-extras": {
20+
env: map[string]string{
21+
"ARGO_TOKEN": "my-token",
22+
},
23+
args: []string{
24+
"root",
25+
"--print-config",
26+
"--namespace", "my-namespace",
27+
"--log-level", "debug",
28+
"--instance", "ops",
29+
"submit",
30+
"--name", "something", "--param", "whatever",
31+
},
32+
check: func(t *testing.T, cfg FullConfig) {
33+
require.Equal(t, []string{"--name", "something", "--param", "whatever"}, cfg.ExtraArgs)
34+
require.Equal(t, slog.LevelDebug, cfg.LogLevel.Level())
35+
36+
},
37+
},
38+
"argo-token-as-flag": {
39+
args: []string{
40+
"root",
41+
"--print-config",
42+
"--argo-token", "my-token",
43+
"--namespace", "my-namespace",
44+
"--log-level", "warn",
45+
"--instance", "ops",
46+
"submit",
47+
},
48+
check: func(t *testing.T, cfg FullConfig) {
49+
require.Equal(t, "my-token", cfg.ArgoToken)
50+
},
51+
},
52+
}
53+
for testName, test := range tests {
54+
t.Run(testName, func(t *testing.T) {
55+
for envName, envValue := range test.env {
56+
t.Setenv(envName, envValue)
57+
}
58+
writer := &bytes.Buffer{}
59+
runMain(test.args, writer, os.Stderr)
60+
cfg := FullConfig{}
61+
require.NoError(t, json.NewDecoder(writer).Decode(&cfg))
62+
test.check(t, cfg)
63+
})
64+
}
65+
}

actions/trigger-argo-workflow/go.mod

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,18 @@ require (
77
github.com/kelseyhightower/envconfig v1.4.0
88
github.com/lmittmann/tint v1.1.2
99
github.com/stretchr/testify v1.10.0
10-
github.com/urfave/cli/v2 v2.27.7
10+
github.com/urfave/cli/v3 v3.3.8
1111
github.com/willabides/actionslog v0.5.1
1212
golang.org/x/term v0.33.0
1313
)
1414

1515
require (
16-
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
1716
github.com/davecgh/go-spew v1.1.1 // indirect
1817
github.com/fatih/color v1.10.0 // indirect
1918
github.com/goccy/go-yaml v1.11.0 // indirect
2019
github.com/mattn/go-colorable v0.1.8 // indirect
2120
github.com/mattn/go-isatty v0.0.12 // indirect
2221
github.com/pmezard/go-difflib v1.0.0 // indirect
23-
github.com/russross/blackfriday/v2 v2.1.0 // indirect
24-
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
2522
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
2623
golang.org/x/sys v0.34.0 // indirect
2724
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect

actions/trigger-argo-workflow/go.sum

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
22
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
3-
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
4-
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
53
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
64
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
75
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
@@ -28,16 +26,12 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
2826
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
2927
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3028
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
31-
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
32-
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
3329
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
3430
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
35-
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
36-
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
31+
github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E=
32+
github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
3733
github.com/willabides/actionslog v0.5.1 h1:dJ/Cxg8vO1pEohgC2O4CW1tCWFKJrYJXTZDWYJQK0+E=
3834
github.com/willabides/actionslog v0.5.1/go.mod h1:WDufDP3XZUMBOmau2BvfVCGYuUcVRZI6Eqy8ZRw4pJ8=
39-
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
40-
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
4135
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
4236
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
4337
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=

0 commit comments

Comments
 (0)