Skip to content

Commit 5dbe2f1

Browse files
fix: merge main into fix/error-message, resolve processSSHConfig comment conflict
Co-authored-by: richards-ensono <292143884+richards-ensono@users.noreply.github.com>
2 parents 7347d0a + b2506e3 commit 5dbe2f1

44 files changed

Lines changed: 1901 additions & 627 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release_container.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ jobs:
6666
run: test "$(git rev-parse HEAD)" = "$VALIDATED_HEAD_SHA"
6767

6868
- name: Log in to GitHub Container Registry
69-
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
69+
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
7070
with:
7171
registry: ghcr.io
7272
# GITHUB_TOKEN is automatically provided in GitHub Actions

.github/workflows/scorecard.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ jobs:
2727
persist-credentials: false
2828

2929
- name: Run OpenSSF Scorecard
30-
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
30+
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
3131
with:
3232
results_file: results.sarif
3333
results_format: sarif
3434
publish_results: true
3535

3636
- name: Upload Scorecard SARIF
37-
uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
37+
uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
3838
with:
3939
sarif_file: results.sarif
4040

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ bin/
1111

1212
# Random
1313
local/
14-
14+
internal/config/.eirctl-tester
1515

1616
# Generated outputs
1717
.github/workflows/gha__e__infra__e__sample.yml

cmd/eirctl/eirctl.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ var (
2323
Revision = "aaaa1234"
2424
)
2525

26+
const noSummaryFlag = "no-summary"
27+
2628
type EirCtlCmd struct {
2729
ctx context.Context
2830
Cmd *cobra.Command
@@ -71,8 +73,8 @@ func NewEirCtlCmd(ctx context.Context, channelOut, channelErr io.Writer) *EirCtl
7173
tc.Cmd.PersistentFlags().BoolVarP(&tc.rootFlags.DryRun, "dry-run", "", false, "dry run")
7274
_ = tc.viperConf.BindPFlag("dry-run", tc.Cmd.PersistentFlags().Lookup("dry-run"))
7375

74-
tc.Cmd.PersistentFlags().BoolVarP(&tc.rootFlags.NoSummary, "no-summary", "", false, "show summary")
75-
_ = tc.viperConf.BindPFlag("no-summary", tc.Cmd.PersistentFlags().Lookup("no-summary"))
76+
tc.Cmd.PersistentFlags().BoolVarP(&tc.rootFlags.NoSummary, noSummaryFlag, "", false, "show summary")
77+
_ = tc.viperConf.BindPFlag(noSummaryFlag, tc.Cmd.PersistentFlags().Lookup(noSummaryFlag))
7678

7779
tc.Cmd.PersistentFlags().BoolVarP(&tc.rootFlags.Quiet, "quiet", "q", false, "quiet mode")
7880
_ = tc.viperConf.BindPFlag("quiet", tc.Cmd.PersistentFlags().Lookup("quiet"))

cmd/eirctl/eirctl_test.go

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -39,54 +39,63 @@ func (o mockOsFsOps) Create(name string) (io.Writer, error) {
3939

4040
func cmdRunTestHelper(t *testing.T, testInput *cmdRunTestInput) {
4141
t.Helper()
42-
ctx := context.TODO()
42+
logOutput, errOutputLength, err := executeCommandTest(t, testInput)
43+
if err != nil {
44+
assertCommandError(t, testInput, err)
45+
return
46+
}
47+
48+
assertCommandOutput(t, testInput, logOutput, errOutputLength)
49+
}
4350

44-
if testInput.ctx != nil {
45-
ctx = testInput.ctx
51+
func executeCommandTest(t *testing.T, testInput *cmdRunTestInput) (string, int, error) {
52+
t.Helper()
53+
ctx := testInput.ctx
54+
if ctx == nil {
55+
ctx = context.TODO()
4656
}
4757

4858
logOut := output.NewSafeWriter(&bytes.Buffer{})
4959
logErr := output.NewSafeWriter(&bytes.Buffer{})
50-
5160
cmd := eirctlCmd.NewEirCtlCmd(ctx, logOut, logErr)
5261
os.Args = append([]string{os.Args[0]}, testInput.args...)
5362

5463
cmd.Cmd.SetArgs(testInput.args)
5564
errOut := output.NewSafeWriter(&bytes.Buffer{})
56-
stdOut := output.NewSafeWriter(&bytes.Buffer{})
5765
cmd.Cmd.SetErr(errOut)
58-
cmd.Cmd.SetOut(stdOut)
66+
cmd.Cmd.SetOut(output.NewSafeWriter(&bytes.Buffer{}))
5967
cmd.OsFsOps = mockOsFsOps{}
60-
6168
if err := cmd.InitCommand(eirctlCmd.WithSubCommands()...); err != nil {
6269
t.Fatal(err)
6370
}
6471

65-
if err := cmd.Execute(); err != nil {
66-
if testInput.errored {
67-
if len(testInput.output) > 0 {
68-
for _, v := range testInput.output {
69-
if !(strings.Contains(err.Error(), v)) {
70-
t.Errorf("\nerror: %s\n\ndoes not contain: %v\n", err.Error(), v)
71-
}
72-
}
73-
}
74-
return
75-
}
72+
err := cmd.Execute()
73+
return logOut.String(), errOut.Len(), err
74+
}
75+
76+
func assertCommandError(t *testing.T, testInput *cmdRunTestInput, err error) {
77+
t.Helper()
78+
if !testInput.errored {
7679
t.Fatalf("\ngot: %v\nwanted <nil>\n", err)
7780
}
81+
for _, expectedOutput := range testInput.output {
82+
if !strings.Contains(err.Error(), expectedOutput) {
83+
t.Errorf("\nerror: %s\n\ndoes not contain: %v\n", err.Error(), expectedOutput)
84+
}
85+
}
86+
}
7887

79-
if testInput.errored && errOut.Len() < 1 {
88+
func assertCommandOutput(t *testing.T, testInput *cmdRunTestInput, logOutput string, errOutputLength int) {
89+
t.Helper()
90+
if testInput.errored && errOutputLength < 1 {
8091
t.Errorf("\ngot: nil\nwanted an error to be thrown")
8192
}
82-
if len(testInput.output) > 0 {
83-
for _, v := range testInput.output {
84-
if !strings.Contains(logOut.String(), v) {
85-
t.Errorf("\ngot: %s\vnot found in: %v", logOut.String(), v)
86-
}
93+
for _, expectedOutput := range testInput.output {
94+
if !strings.Contains(logOutput, expectedOutput) {
95+
t.Errorf("\ngot: %s\vnot found in: %v", logOutput, expectedOutput)
8796
}
8897
}
89-
if testInput.exactOutput != "" && logOut.String() != testInput.exactOutput {
90-
t.Errorf("output mismatch\ngot: %s\n\nwanted: %s", logOut.String(), testInput.exactOutput)
98+
if testInput.exactOutput != "" && logOutput != testInput.exactOutput {
99+
t.Errorf("output mismatch\ngot: %s\n\nwanted: %s", logOutput, testInput.exactOutput)
91100
}
92101
}

cmd/eirctl/init.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ watchers:
3737
task: task1
3838
`
3939

40+
const noPromptFlag = "no-prompt"
41+
4042
type initFlags struct {
4143
initDir string
4244
noPrompt bool
@@ -56,18 +58,18 @@ func newInitCmd(rootCmd *EirCtlCmd) {
5658
Use: "init",
5759
Short: `initializes the directory with a sample config file`,
5860
RunE: func(cmd *cobra.Command, args []string) error {
59-
if rootCmd.viperConf.GetBool("no-prompt") && len(args) == 0 {
61+
if rootCmd.viperConf.GetBool(noPromptFlag) && len(args) == 0 {
6062
return fmt.Errorf("file name must be supplied when running in non-interactive mode")
6163
}
62-
return ri.runInit(args, rootCmd.viperConf.GetString("dir"), rootCmd.viperConf.GetBool("no-prompt"))
64+
return ri.runInit(args, rootCmd.viperConf.GetString("dir"), rootCmd.viperConf.GetBool(noPromptFlag))
6365
},
6466
}
6567

6668
initCmd.PersistentFlags().StringVar(&f.initDir, "dir", "", "directory to initialize")
6769
_ = rootCmd.viperConf.BindPFlag("dir", initCmd.PersistentFlags().Lookup("dir"))
6870

69-
initCmd.PersistentFlags().BoolVar(&f.noPrompt, "no-prompt", false, "do not prompt")
70-
_ = rootCmd.viperConf.BindPFlag("no-prompt", initCmd.PersistentFlags().Lookup("no-prompt"))
71+
initCmd.PersistentFlags().BoolVar(&f.noPrompt, noPromptFlag, false, "do not prompt")
72+
_ = rootCmd.viperConf.BindPFlag(noPromptFlag, initCmd.PersistentFlags().Lookup(noPromptFlag))
7173

7274
rootCmd.Cmd.AddCommand(initCmd)
7375
}

cmd/main_test.go

Lines changed: 66 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -11,103 +11,74 @@ import (
1111
)
1212

1313
func Test_main(t *testing.T) {
14-
t.Run("main sanity check", func(t *testing.T) {
15-
os.Args = []string{"eirctl", "run", "unknown"}
16-
17-
eirctlRootCmd := eirctlcmd.NewEirCtlCmd(context.TODO(), os.Stdout, os.Stderr)
18-
19-
if err := eirctlRootCmd.InitCommand(eirctlcmd.WithSubCommands()...); err != nil {
20-
logrus.Fatal(err)
21-
}
22-
23-
setDefaultCommandIfNonePresent(eirctlRootCmd.Cmd)
24-
25-
if err := eirctlRootCmd.Execute(); err == nil {
26-
t.Error("got nil wanted error")
27-
}
28-
})
29-
30-
t.Run("main sanity check (explicit debug)", func(t *testing.T) {
31-
os.Args = []string{"eirctl", "run", "unknown", "--debug"}
32-
33-
eirctlRootCmd := eirctlcmd.NewEirCtlCmd(context.TODO(), os.Stdout, os.Stderr)
34-
35-
if err := eirctlRootCmd.InitCommand(eirctlcmd.WithSubCommands()...); err != nil {
36-
logrus.Fatal(err)
37-
}
38-
39-
setDefaultCommandIfNonePresent(eirctlRootCmd.Cmd)
40-
41-
if err := eirctlRootCmd.Execute(); err == nil {
42-
t.Error("got nil wanted error")
43-
}
44-
45-
logLevel := logrus.GetLevel()
46-
if logLevel != logrus.DebugLevel {
47-
t.Errorf("Expected Log Level to be '%s', got: '%s'", logrus.DebugLevel, logLevel)
48-
}
49-
})
50-
51-
t.Run("main sanity check (explicit verbose)", func(t *testing.T) {
52-
os.Args = []string{"eirctl", "run", "unknown", "--verbose"}
53-
54-
eirctlRootCmd := eirctlcmd.NewEirCtlCmd(context.TODO(), os.Stdout, os.Stderr)
55-
56-
if err := eirctlRootCmd.InitCommand(eirctlcmd.WithSubCommands()...); err != nil {
57-
logrus.Fatal(err)
58-
}
59-
60-
setDefaultCommandIfNonePresent(eirctlRootCmd.Cmd)
61-
62-
if err := eirctlRootCmd.Execute(); err == nil {
63-
t.Error("got nil wanted error")
64-
}
65-
66-
logLevel := logrus.GetLevel()
67-
if logLevel != logrus.TraceLevel {
68-
t.Errorf("Expected Log Level to be '%s', got: '%s'", logrus.TraceLevel, logLevel)
69-
}
70-
})
71-
t.Run("exit code correctly bubbled up", func(t *testing.T) {
72-
os.Args = []string{"eirctl", "run", "task", "fail_125", "-c", "testdata/eirctl.yaml"}
73-
moutW := &bytes.Buffer{}
74-
merrW := &bytes.Buffer{}
75-
ec := runMain(moutW, merrW)
76-
77-
if ec != 125 {
78-
t.Fatalf("process ran wihout error")
79-
}
80-
81-
if len(moutW.String()) < 1 {
82-
t.Errorf("got empty error, expected a message")
83-
}
84-
})
85-
t.Run("exited at eirctl command not found", func(t *testing.T) {
86-
os.Args = []string{"eirctl", "run", "task", "not-found", "-c", "testdata/eirctl.yaml"}
87-
moutW := &bytes.Buffer{}
88-
merrW := &bytes.Buffer{}
89-
ec := runMain(moutW, merrW)
14+
for _, testCase := range []struct {
15+
name string
16+
args []string
17+
expectedLogLevel *logrus.Level
18+
}{
19+
{name: "main sanity check", args: []string{"eirctl", "run", "unknown"}},
20+
{name: "main sanity check (explicit debug)", args: []string{"eirctl", "run", "unknown", "--debug"}, expectedLogLevel: logLevel(logrus.DebugLevel)},
21+
{name: "main sanity check (explicit verbose)", args: []string{"eirctl", "run", "unknown", "--verbose"}, expectedLogLevel: logLevel(logrus.TraceLevel)},
22+
} {
23+
t.Run(testCase.name, func(t *testing.T) {
24+
assertRootCommandFailure(t, testCase.args, testCase.expectedLogLevel)
25+
})
26+
}
27+
28+
for _, testCase := range []struct {
29+
name string
30+
args []string
31+
expectedCode int
32+
}{
33+
{name: "exit code correctly bubbled up", args: []string{"eirctl", "run", "task", "fail_125", "-c", "testdata/eirctl.yaml"}, expectedCode: 125},
34+
{name: "exited at eirctl command not found", args: []string{"eirctl", "run", "task", "not-found", "-c", "testdata/eirctl.yaml"}, expectedCode: 1},
35+
{name: "exited at eirctl with help", args: []string{"eirctl", "--help"}, expectedCode: 0},
36+
} {
37+
t.Run(testCase.name, func(t *testing.T) {
38+
assertMainExit(t, testCase.args, testCase.expectedCode)
39+
})
40+
}
41+
}
9042

91-
if ec != 1 {
92-
t.Fatalf("process ran wihout error")
93-
}
43+
func logLevel(level logrus.Level) *logrus.Level {
44+
return &level
45+
}
9446

95-
if len(moutW.String()) < 1 {
96-
t.Errorf("got empty error, expected a message")
97-
}
98-
})
99-
t.Run("exited at eirctl with help", func(t *testing.T) {
100-
os.Args = []string{"eirctl", "--help"}
101-
moutW := &bytes.Buffer{}
102-
merrW := &bytes.Buffer{}
103-
ec := runMain(moutW, merrW)
47+
func assertRootCommandFailure(t *testing.T, args []string, expectedLogLevel *logrus.Level) {
48+
t.Helper()
49+
withTestArgs(t, args)
50+
previousLogLevel := logrus.GetLevel()
51+
t.Cleanup(func() { logrus.SetLevel(previousLogLevel) })
52+
53+
eirctlRootCmd := eirctlcmd.NewEirCtlCmd(context.TODO(), os.Stdout, os.Stderr)
54+
if err := eirctlRootCmd.InitCommand(eirctlcmd.WithSubCommands()...); err != nil {
55+
t.Fatal(err)
56+
}
57+
58+
setDefaultCommandIfNonePresent(eirctlRootCmd.Cmd)
59+
if err := eirctlRootCmd.Execute(); err == nil {
60+
t.Error("got nil wanted error")
61+
}
62+
if expectedLogLevel != nil && logrus.GetLevel() != *expectedLogLevel {
63+
t.Errorf("Expected Log Level to be '%s', got: '%s'", *expectedLogLevel, logrus.GetLevel())
64+
}
65+
}
10466

105-
if ec != 0 {
106-
t.Fatalf("process ran wih error")
107-
}
67+
func assertMainExit(t *testing.T, args []string, expectedCode int) {
68+
t.Helper()
69+
withTestArgs(t, args)
70+
stdout := &bytes.Buffer{}
71+
if code := runMain(stdout, &bytes.Buffer{}); code != expectedCode {
72+
t.Fatalf("got exit code %d, wanted %d", code, expectedCode)
73+
}
74+
if stdout.Len() < 1 {
75+
t.Error("got empty error, expected a message")
76+
}
77+
}
10878

109-
if len(moutW.String()) < 1 {
110-
t.Errorf("got empty error, expected a message")
111-
}
112-
})
79+
func withTestArgs(t *testing.T, args []string) {
80+
t.Helper()
81+
previousArgs := os.Args
82+
os.Args = args
83+
t.Cleanup(func() { os.Args = previousArgs })
11384
}

go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ require (
1010
github.com/briandowns/spinner v1.23.2
1111
github.com/charmbracelet/lipgloss v1.1.0
1212
github.com/containerd/errdefs v1.0.0
13-
github.com/docker/go-connections v0.7.0
13+
github.com/docker/go-connections v0.8.1
1414
github.com/fsnotify/fsnotify v1.10.1
15-
github.com/go-git/go-billy/v5 v5.9.0
15+
github.com/go-git/go-billy/v5 v5.9.1
1616
github.com/invopop/jsonschema v0.14.0
1717
github.com/kevinburke/ssh_config v1.6.0
1818
github.com/opencontainers/image-spec v1.1.1
@@ -114,11 +114,11 @@ require (
114114
github.com/charmbracelet/bubbletea v1.3.10
115115
github.com/charmbracelet/huh v1.0.0
116116
github.com/coryb/templatecolor v0.0.0-20230911044230-5d137a83f1e3
117-
github.com/docker/cli v29.6.2+incompatible
117+
github.com/docker/cli v29.7.1+incompatible
118118
github.com/docker/docker v28.5.2+incompatible
119119
github.com/emicklei/dot v1.11.0
120120
github.com/fatih/color v1.19.0 // indirect
121-
github.com/go-git/go-git/v5 v5.19.1
121+
github.com/go-git/go-git/v5 v5.19.2
122122
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213
123123
github.com/mattn/go-colorable v0.1.14 // indirect
124124
github.com/mattn/go-isatty v0.0.22 // indirect

0 commit comments

Comments
 (0)