Skip to content

Commit 5d7027d

Browse files
Ryanmergify[bot]
Ryan
andauthored
feat: add bug-report flag (#1056)
* feat: add bug-report flag * fix: use docker host CPU count * feat: add config files to bug-report Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent a970145 commit 5d7027d

File tree

3 files changed

+123
-10
lines changed

3 files changed

+123
-10
lines changed

cmd/root.go

+94-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"bufio"
55
"context"
6+
"fmt"
67
"os"
78
"path/filepath"
89
"regexp"
@@ -19,6 +20,7 @@ import (
1920

2021
"github.com/nektos/act/pkg/artifacts"
2122
"github.com/nektos/act/pkg/common"
23+
"github.com/nektos/act/pkg/container"
2224
"github.com/nektos/act/pkg/model"
2325
"github.com/nektos/act/pkg/runner"
2426
)
@@ -39,6 +41,8 @@ func Execute(ctx context.Context, version string) {
3941
rootCmd.Flags().BoolP("list", "l", false, "list workflows")
4042
rootCmd.Flags().BoolP("graph", "g", false, "draw workflows")
4143
rootCmd.Flags().StringP("job", "j", "", "run job")
44+
rootCmd.Flags().BoolP("bug-report", "", false, "Display system information for bug report")
45+
4246
rootCmd.Flags().StringArrayVarP(&input.secrets, "secret", "s", []string{}, "secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)")
4347
rootCmd.Flags().StringArrayVarP(&input.envs, "env", "", []string{}, "env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)")
4448
rootCmd.Flags().StringArrayVarP(&input.platforms, "platform", "P", []string{}, "custom image to use per platform (e.g. -P ubuntu-18.04=nektos/act-environments-ubuntu:18.04)")
@@ -105,14 +109,94 @@ func args() []string {
105109

106110
args := make([]string, 0)
107111
for _, f := range actrc {
108-
args = append(args, readArgsFile(f)...)
112+
args = append(args, readArgsFile(f, true)...)
109113
}
110114

111115
args = append(args, os.Args[1:]...)
112116
return args
113117
}
114118

115-
func readArgsFile(file string) []string {
119+
func bugReport(ctx context.Context, version string) error {
120+
var commonSocketPaths = []string{
121+
"/var/run/docker.sock",
122+
"/var/run/podman/podman.sock",
123+
"$HOME/.colima/docker.sock",
124+
"$XDG_RUNTIME_DIR/docker.sock",
125+
`\\.\pipe\docker_engine`,
126+
}
127+
128+
sprintf := func(key, val string) string {
129+
return fmt.Sprintf("%-24s%s\n", key, val)
130+
}
131+
132+
report := sprintf("act version:", version)
133+
report += sprintf("GOOS:", runtime.GOOS)
134+
report += sprintf("GOARCH:", runtime.GOARCH)
135+
report += sprintf("NumCPU:", fmt.Sprint(runtime.NumCPU()))
136+
137+
var dockerHost string
138+
if dockerHost = os.Getenv("DOCKER_HOST"); dockerHost == "" {
139+
dockerHost = "DOCKER_HOST environment variable is unset/empty."
140+
}
141+
142+
report += sprintf("Docker host:", dockerHost)
143+
report += fmt.Sprintln("Sockets found:")
144+
for _, p := range commonSocketPaths {
145+
if strings.HasPrefix(p, `$`) {
146+
v := strings.Split(p, `/`)[0]
147+
p = strings.Replace(p, v, os.Getenv(strings.TrimPrefix(v, `$`)), 1)
148+
}
149+
if _, err := os.Stat(p); err != nil {
150+
continue
151+
} else {
152+
report += fmt.Sprintf("\t%s\n", p)
153+
}
154+
}
155+
156+
info, err := container.GetHostInfo(ctx)
157+
if err != nil {
158+
fmt.Println(report)
159+
return err
160+
}
161+
162+
report += sprintf("Config files:", "")
163+
for _, c := range configLocations() {
164+
args := readArgsFile(c, false)
165+
if len(args) > 0 {
166+
report += fmt.Sprintf("\t%s:\n", c)
167+
for _, l := range args {
168+
report += fmt.Sprintf("\t\t%s\n", l)
169+
}
170+
}
171+
}
172+
173+
report += fmt.Sprintln("Docker Engine:")
174+
175+
report += sprintf("\tEngine version:", info.ServerVersion)
176+
report += sprintf("\tEngine runtime:", info.DefaultRuntime)
177+
report += sprintf("\tCgroup version:", info.CgroupVersion)
178+
report += sprintf("\tCgroup driver:", info.CgroupDriver)
179+
report += sprintf("\tStorage driver:", info.Driver)
180+
report += sprintf("\tRegistry URI:", info.IndexServerAddress)
181+
182+
report += sprintf("\tOS:", info.OperatingSystem)
183+
report += sprintf("\tOS type:", info.OSType)
184+
report += sprintf("\tOS version:", info.OSVersion)
185+
report += sprintf("\tOS arch:", info.Architecture)
186+
report += sprintf("\tOS kernel:", info.KernelVersion)
187+
report += sprintf("\tOS CPU:", fmt.Sprint(info.NCPU))
188+
report += sprintf("\tOS memory:", fmt.Sprintf("%d MB", info.MemTotal/1024/1024))
189+
190+
report += fmt.Sprintln("\tSecurity options:")
191+
for _, secopt := range info.SecurityOptions {
192+
report += fmt.Sprintf("\t\t%s\n", secopt)
193+
}
194+
195+
fmt.Println(report)
196+
return nil
197+
}
198+
199+
func readArgsFile(file string, split bool) []string {
116200
args := make([]string, 0)
117201
f, err := os.Open(file)
118202
if err != nil {
@@ -127,8 +211,10 @@ func readArgsFile(file string) []string {
127211
scanner := bufio.NewScanner(f)
128212
for scanner.Scan() {
129213
arg := strings.TrimSpace(scanner.Text())
130-
if strings.HasPrefix(arg, "-") {
214+
if strings.HasPrefix(arg, "-") && split {
131215
args = append(args, regexp.MustCompile(`\s`).Split(arg, 2)...)
216+
} else if !split {
217+
args = append(args, arg)
132218
}
133219
}
134220
return args
@@ -162,6 +248,10 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
162248
log.SetFormatter(&log.JSONFormatter{})
163249
}
164250

251+
if ok, _ := cmd.Flags().GetBool("bug-report"); ok {
252+
return bugReport(ctx, cmd.Version)
253+
}
254+
165255
if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" && input.containerArchitecture == "" {
166256
l := log.New()
167257
l.SetFormatter(&log.TextFormatter{
@@ -256,7 +346,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
256346
if err := defaultImageSurvey(cfgLocations[0]); err != nil {
257347
log.Fatal(err)
258348
}
259-
input.platforms = readArgsFile(cfgLocations[0])
349+
input.platforms = readArgsFile(cfgLocations[0], true)
260350
}
261351
}
262352

pkg/container/docker_run.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,7 @@ type containerReference struct {
201201
input *NewContainerInput
202202
}
203203

204-
func GetDockerClient(ctx context.Context) (*client.Client, error) {
205-
var err error
206-
var cli *client.Client
207-
204+
func GetDockerClient(ctx context.Context) (cli *client.Client, err error) {
208205
// TODO: this should maybe need to be a global option, not hidden in here?
209206
// though i'm not sure how that works out when there's another Executor :D
210207
// I really would like something that works on OSX native for eg
@@ -232,6 +229,22 @@ func GetDockerClient(ctx context.Context) (*client.Client, error) {
232229
return cli, err
233230
}
234231

232+
func GetHostInfo(ctx context.Context) (info types.Info, err error) {
233+
var cli *client.Client
234+
cli, err = GetDockerClient(ctx)
235+
if err != nil {
236+
return info, err
237+
}
238+
defer cli.Close()
239+
240+
info, err = cli.Info(ctx)
241+
if err != nil {
242+
return info, err
243+
}
244+
245+
return info, nil
246+
}
247+
235248
func (cr *containerReference) connect() common.Executor {
236249
return func(ctx context.Context) error {
237250
if cr.cli != nil {

pkg/runner/runner.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import (
99
"runtime"
1010
"strings"
1111

12+
log "github.com/sirupsen/logrus"
13+
1214
"github.com/nektos/act/pkg/common"
15+
"github.com/nektos/act/pkg/container"
1316
"github.com/nektos/act/pkg/model"
14-
log "github.com/sirupsen/logrus"
1517
)
1618

1719
// Runner provides capabilities to run GitHub actions
@@ -171,7 +173,15 @@ func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
171173
}
172174
pipeline = append(pipeline, common.NewParallelExecutor(maxParallel, stageExecutor...))
173175
}
174-
return common.NewParallelExecutor(runtime.NumCPU(), pipeline...)(ctx)
176+
var ncpu int
177+
info, err := container.GetHostInfo(ctx)
178+
if err != nil {
179+
log.Errorf("failed to obtain container engine info: %s", err)
180+
ncpu = 1 // sane default?
181+
} else {
182+
ncpu = info.NCPU
183+
}
184+
return common.NewParallelExecutor(ncpu, pipeline...)(ctx)
175185
})
176186
}
177187

0 commit comments

Comments
 (0)