diff --git a/app/app.go b/app/app.go new file mode 100644 index 0000000000000000000000000000000000000000..4760b59a01aa77bfc31213ee2419f22039ed755a --- /dev/null +++ b/app/app.go @@ -0,0 +1,102 @@ +package app + +import ( + "os" + "path" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + + "gitlab.com/gitlab-org/gitlab-runner/common" + "gitlab.com/gitlab-org/gitlab-runner/log" +) + +var ( + authors = []cli.Author{ + { + Name: "GitLab Inc.", + Email: "support@gitlab.com", + }, + } +) + +type Handler func(cliCtx *cli.Context) error +type Handlers []Handler + +func (a *Handlers) Handle(cliCtx *cli.Context) error { + for _, f := range *a { + err := f(cliCtx) + if err != nil { + return err + } + } + + return nil +} + +type App struct { + app *cli.App + + beforeFunctions Handlers + afterFunctions Handlers +} + +func (a *App) init(usage string) { + app := cli.NewApp() + a.app = app + + app.Name = path.Base(os.Args[0]) + app.Usage = usage + app.Authors = authors + app.Version = common.AppVersion.ShortLine() + cli.VersionPrinter = common.AppVersion.Printer + + app.Commands = common.GetCommands() + app.CommandNotFound = func(cliCtx *cli.Context, command string) { + logrus.Fatalf("Command %s not found", command) + } + + a.beforeFunctions = make(Handlers, 0) + app.Before = a.beforeFunctions.Handle + + a.afterFunctions = make(Handlers, 0) + app.After = a.afterFunctions.Handle +} + +func (a *App) Run() { + if err := a.app.Run(os.Args); err != nil { + logrus.WithError(err).Fatal("Application execution failed") + } +} + +func (a *App) Extend(extension func(*cli.App)) { + extension(a.app) +} + +func (a *App) AppendBeforeFunc(f Handler) { + a.beforeFunctions = append(a.beforeFunctions, f) +} + +func (a *App) AppendAfterFunc(f Handler) { + a.afterFunctions = append(a.afterFunctions, f) +} + +func New(usage string) *App { + app := new(App) + app.init(usage) + app.Extend(log.AddFlags) + app.AppendBeforeFunc(log.ConfigureLogging) + + return app +} + +func Recover() { + r := recover() + if r != nil { + // log panics forces exit + if _, ok := r.(*logrus.Entry); ok { + os.Exit(1) + } + panic(r) + } +} diff --git a/app/cpuprofile.go b/app/cpuprofile.go new file mode 100644 index 0000000000000000000000000000000000000000..94caabb7f643e57657b73ba6b9fb5e0c562e192a --- /dev/null +++ b/app/cpuprofile.go @@ -0,0 +1,33 @@ +package app + +import ( + "os" + "runtime/pprof" + + "github.com/urfave/cli" +) + +func CPUProfileFlags(app *cli.App) { + app.Flags = append(app.Flags, cli.StringFlag{ + Name: "cpuprofile", + Usage: "write cpu profile to file", + EnvVar: "CPU_PROFILE", + }) +} + +func CPUProfileSetup(cliCtx *cli.Context) error { + if cpuProfile := cliCtx.String("cpuprofile"); cpuProfile != "" { + f, err := os.Create(cpuProfile) + if err != nil { + return err + } + pprof.StartCPUProfile(f) + } + + return nil +} + +func CPUProfileTeardown(cliCtx *cli.Context) error { + pprof.StopCPUProfile() + return nil +} diff --git a/app/fix_home.go b/app/fix_home.go new file mode 100644 index 0000000000000000000000000000000000000000..1a468779298b7f02b5aa5e5aaf0f786ca545e60e --- /dev/null +++ b/app/fix_home.go @@ -0,0 +1,22 @@ +package app + +import ( + "fmt" + "os" + + "github.com/docker/docker/pkg/homedir" + "github.com/urfave/cli" +) + +func FixHOME(cliCtx *cli.Context) error { + // Fix home + if key := homedir.Key(); os.Getenv(key) == "" { + value := homedir.Get() + if value == "" { + return fmt.Errorf("the %q is not set", key) + } + os.Setenv(key, value) + } + + return nil +} diff --git a/app/runtime_platform.go b/app/runtime_platform.go new file mode 100644 index 0000000000000000000000000000000000000000..849d6f9c9c09b78a0a88637d13ba32f002ab9c49 --- /dev/null +++ b/app/runtime_platform.go @@ -0,0 +1,25 @@ +package app + +import ( + "os" + "runtime" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + + "gitlab.com/gitlab-org/gitlab-runner/common" +) + +func LogRuntimePlatform(cliCtx *cli.Context) error { + fields := logrus.Fields{ + "os": runtime.GOOS, + "arch": runtime.GOARCH, + "version": common.VERSION, + "revision": common.REVISION, + "pid": os.Getpid(), + } + + logrus.WithFields(fields).Info("Runtime platform") + + return nil +} diff --git a/helpers/cli/warn_on_bool.go b/app/warn_on_bool.go similarity index 97% rename from helpers/cli/warn_on_bool.go rename to app/warn_on_bool.go index 8539e8fe54b141bb7bb0c49bfa0a0ad449143449..c3490d0f8ec31dc8c40c884e40e7578d4479880b 100644 --- a/helpers/cli/warn_on_bool.go +++ b/app/warn_on_bool.go @@ -1,4 +1,4 @@ -package cli_helpers +package app import ( "strings" diff --git a/cmd/gitlab-runner-helper/main.go b/cmd/gitlab-runner-helper/main.go index 40ab16bd98beed749814bc08329d47edcd9e1a8c..02b88c9eb300bba85fa024b13531ce6fa2db99be 100644 --- a/cmd/gitlab-runner-helper/main.go +++ b/cmd/gitlab-runner-helper/main.go @@ -1,49 +1,19 @@ package main import ( - "os" - "path" - "github.com/sirupsen/logrus" - "github.com/urfave/cli" - "gitlab.com/gitlab-org/gitlab-runner/common" + "gitlab.com/gitlab-org/gitlab-runner/app" "gitlab.com/gitlab-org/gitlab-runner/log" _ "gitlab.com/gitlab-org/gitlab-runner/commands/helpers" ) func main() { - defer func() { - if r := recover(); r != nil { - // log panics forces exit - if _, ok := r.(*logrus.Entry); ok { - os.Exit(1) - } - panic(r) - } - }() - - app := cli.NewApp() - app.Name = path.Base(os.Args[0]) - app.Usage = "a GitLab Runner Helper" - app.Version = common.AppVersion.ShortLine() - cli.VersionPrinter = common.AppVersion.Printer - app.Authors = []cli.Author{ - { - Name: "GitLab Inc.", - Email: "support@gitlab.com", - }, - } - app.Commands = common.GetCommands() - app.CommandNotFound = func(context *cli.Context, command string) { - logrus.Fatalln("Command", command, "not found") - } + defer app.Recover() + a := app.New("GitLab Runner Helper") log.AddSecretsCleanupLogHook(logrus.StandardLogger()) - log.ConfigureLogging(app) - if err := app.Run(os.Args); err != nil { - logrus.Fatal(err) - } + a.Run() } diff --git a/cmd/gitlab-runner/main.go b/cmd/gitlab-runner/main.go index 5bffd5bebe7051be1ba5850703f38d6550bdae1d..48dcbe3243af0ebd3788cdfb134bfeb46a3153f7 100644 --- a/cmd/gitlab-runner/main.go +++ b/cmd/gitlab-runner/main.go @@ -2,14 +2,8 @@ package main import ( "os" - "path" - "github.com/sirupsen/logrus" - "github.com/urfave/cli" - - "gitlab.com/gitlab-org/gitlab-runner/common" - "gitlab.com/gitlab-org/gitlab-runner/helpers/cli" - "gitlab.com/gitlab-org/gitlab-runner/log" + "gitlab.com/gitlab-org/gitlab-runner/app" _ "gitlab.com/gitlab-org/gitlab-runner/cache/gcs" _ "gitlab.com/gitlab-org/gitlab-runner/cache/s3" @@ -26,40 +20,15 @@ import ( ) func main() { - defer func() { - if r := recover(); r != nil { - // log panics forces exit - if _, ok := r.(*logrus.Entry); ok { - os.Exit(1) - } - panic(r) - } - }() - - app := cli.NewApp() - app.Name = path.Base(os.Args[0]) - app.Usage = "a GitLab Runner" - app.Version = common.AppVersion.ShortLine() - cli.VersionPrinter = common.AppVersion.Printer - app.Authors = []cli.Author{ - { - Name: "GitLab Inc.", - Email: "support@gitlab.com", - }, - } - app.Commands = common.GetCommands() - app.CommandNotFound = func(context *cli.Context, command string) { - logrus.Fatalln("Command", command, "not found.") - } - - cli_helpers.LogRuntimePlatform(app) - cli_helpers.SetupCPUProfile(app) - cli_helpers.FixHOME(app) - cli_helpers.WarnOnBool(os.Args) + defer app.Recover() - log.ConfigureLogging(app) + a := app.New("GitLab Runner") + a.AppendBeforeFunc(app.LogRuntimePlatform) + a.Extend(app.CPUProfileFlags) + a.AppendBeforeFunc(app.CPUProfileSetup) + a.AppendAfterFunc(app.CPUProfileTeardown) + a.AppendBeforeFunc(app.FixHOME) + app.WarnOnBool(os.Args) - if err := app.Run(os.Args); err != nil { - logrus.Fatal(err) - } + a.Run() } diff --git a/helpers/cli/cpuprofile.go b/helpers/cli/cpuprofile.go deleted file mode 100644 index e10f9c50725af73cb7194874d4c8d4ca7e692b3e..0000000000000000000000000000000000000000 --- a/helpers/cli/cpuprofile.go +++ /dev/null @@ -1,43 +0,0 @@ -package cli_helpers - -import ( - "os" - "runtime/pprof" - - "github.com/urfave/cli" -) - -func SetupCPUProfile(app *cli.App) { - app.Flags = append(app.Flags, cli.StringFlag{ - Name: "cpuprofile", - Usage: "write cpu profile to file", - EnvVar: "CPU_PROFILE", - }) - - appBefore := app.Before - appAfter := app.After - - app.Before = func(c *cli.Context) error { - if cpuProfile := c.String("cpuprofile"); cpuProfile != "" { - f, err := os.Create(cpuProfile) - if err != nil { - return err - } - pprof.StartCPUProfile(f) - } - - if appBefore != nil { - return appBefore(c) - } - return nil - } - - app.After = func(c *cli.Context) error { - pprof.StopCPUProfile() - - if appAfter != nil { - return appAfter(c) - } - return nil - } -} diff --git a/helpers/cli/fix_home.go b/helpers/cli/fix_home.go deleted file mode 100644 index c327e18686e315f49e398cc0efac99e7e208b7b7..0000000000000000000000000000000000000000 --- a/helpers/cli/fix_home.go +++ /dev/null @@ -1,29 +0,0 @@ -package cli_helpers - -import ( - "fmt" - "os" - - "github.com/docker/docker/pkg/homedir" - "github.com/urfave/cli" -) - -func FixHOME(app *cli.App) { - appBefore := app.Before - - app.Before = func(c *cli.Context) error { - // Fix home - if key := homedir.Key(); os.Getenv(key) == "" { - value := homedir.Get() - if value == "" { - return fmt.Errorf("the %q is not set", key) - } - os.Setenv(key, value) - } - - if appBefore != nil { - return appBefore(c) - } - return nil - } -} diff --git a/helpers/cli/runtime_platform.go b/helpers/cli/runtime_platform.go deleted file mode 100644 index c82d13c676411433b02952adaa9b98161c8b3306..0000000000000000000000000000000000000000 --- a/helpers/cli/runtime_platform.go +++ /dev/null @@ -1,32 +0,0 @@ -package cli_helpers - -import ( - "os" - "runtime" - - "github.com/sirupsen/logrus" - "github.com/urfave/cli" - - "gitlab.com/gitlab-org/gitlab-runner/common" -) - -func LogRuntimePlatform(app *cli.App) { - appBefore := app.Before - app.Before = func(c *cli.Context) error { - fields := logrus.Fields{ - "os": runtime.GOOS, - "arch": runtime.GOARCH, - "version": common.VERSION, - "revision": common.REVISION, - "pid": os.Getpid(), - } - - logrus.WithFields(fields).Info("Runtime platform") - - if appBefore != nil { - return appBefore(c) - } - return nil - } - -} diff --git a/log/configuration.go b/log/configuration.go index 03f187751f50c471c559a536eccc82fc294413ab..53e79595ee2bff6f13a488ea727d2d6b86d9f544 100644 --- a/log/configuration.go +++ b/log/configuration.go @@ -162,21 +162,17 @@ func Configuration() *Config { return configuration } -func ConfigureLogging(app *cli.App) { +func AddFlags(app *cli.App) { app.Flags = append(app.Flags, logFlags...) +} - appBefore := app.Before - app.Before = func(cliCtx *cli.Context) error { - Configuration().logger.SetOutput(os.Stderr) - - err := Configuration().handleCliCtx(cliCtx) - if err != nil { - logrus.WithError(err).Fatal("Error while setting up logging configuration") - } +func ConfigureLogging(cliCtx *cli.Context) error { + Configuration().logger.SetOutput(os.Stderr) - if appBefore != nil { - return appBefore(cliCtx) - } - return nil + err := Configuration().handleCliCtx(cliCtx) + if err != nil { + return fmt.Errorf("error while setting up logging configuration: %v", err) } + + return nil } diff --git a/log/configuration_test.go b/log/configuration_test.go index 1a0bf6bd8af4d74bcee834bd32ed55eb88a9d408..ef85d6db40f94a94e9d4dedd3e33774902feded4 100644 --- a/log/configuration_test.go +++ b/log/configuration_test.go @@ -6,10 +6,7 @@ import ( "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/urfave/cli" - - "gitlab.com/gitlab-org/gitlab-runner/helpers" ) func prepareFakeConfiguration(logger *logrus.Logger) func() { @@ -22,7 +19,7 @@ func prepareFakeConfiguration(logger *logrus.Logger) func() { } } -func testCommandRun(args ...string) { +func testCommandRun(t *testing.T, args ...string) error { app := cli.NewApp() app.Commands = []cli.Command{ { @@ -31,12 +28,13 @@ func testCommandRun(args ...string) { }, } - ConfigureLogging(app) + AddFlags(app) + app.Before = ConfigureLogging args = append([]string{"binary"}, args...) args = append(args, "logtest") - app.Run(args) + return app.Run(args) } type handleCliCtxTestCase struct { @@ -96,46 +94,25 @@ func TestHandleCliCtx(t *testing.T) { logger, _ := test.NewNullLogger() defer prepareFakeConfiguration(logger)() - defer helpers.MakeFatalToPanic()() - - testFunc := func() { - testCommandRun(testCase.args...) - if testCase.expectedError == "" { - assert.Equal(t, testCase.expectedLevel, Configuration().level) - assert.Equal(t, testCase.expectedFormatter, Configuration().format) - assert.Equal(t, testCase.expectedLevelSetWithCli, Configuration().IsLevelSetWithCli()) - assert.Equal(t, testCase.expectedFormatSetWithCli, Configuration().IsFormatSetWithCli()) - - if testCase.goroutinesDumpStopChExists { - assert.NotNil(t, Configuration().goroutinesDumpStopCh) - } else { - assert.Nil(t, Configuration().goroutinesDumpStopCh) - } - } - } - - if testCase.expectedError != "" { - var message *logrus.Entry - var ok bool - func() { - defer func() { - message, ok = recover().(*logrus.Entry) - }() + err := testCommandRun(t, testCase.args...) - testFunc() - }() + if testCase.expectedError == "" { + assert.NoError(t, err) - require.True(t, ok) - - panicMessage, err := message.String() - require.NoError(t, err) - - assert.Contains(t, panicMessage, "Error while setting up logging configuration") - assert.Contains(t, panicMessage, testCase.expectedError) + assert.Equal(t, testCase.expectedLevel, Configuration().level) + assert.Equal(t, testCase.expectedFormatter, Configuration().format) + assert.Equal(t, testCase.expectedLevelSetWithCli, Configuration().IsLevelSetWithCli()) + assert.Equal(t, testCase.expectedFormatSetWithCli, Configuration().IsFormatSetWithCli()) + if testCase.goroutinesDumpStopChExists { + assert.NotNil(t, Configuration().goroutinesDumpStopCh) + } else { + assert.Nil(t, Configuration().goroutinesDumpStopCh) + } } else { - assert.NotPanics(t, testFunc) + assert.Error(t, err) + assert.Contains(t, err.Error(), "error while setting up logging configuration") } }) }