mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:31:48 +00:00
Start implementing sg doctor command (#20796)
This adds a `sg doctor` command that executes the checks defined in `sg.config.yaml`.
This commit is contained in:
parent
66433efe17
commit
61a832f77e
@ -35,6 +35,11 @@ func ParseConfigFile(name string) (*Config, error) {
|
||||
conf.Tests[name] = cmd
|
||||
}
|
||||
|
||||
for name, check := range conf.Checks {
|
||||
check.Name = name
|
||||
conf.Checks[name] = check
|
||||
}
|
||||
|
||||
return &conf, nil
|
||||
}
|
||||
|
||||
@ -107,11 +112,18 @@ func equal(a, b []string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type Check struct {
|
||||
Name string `yaml:"-"`
|
||||
Cmd string `yaml:"cmd"`
|
||||
FailMessage string `yaml:"failMessage"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Env map[string]string `yaml:"env"`
|
||||
Commands map[string]Command `yaml:"commands"`
|
||||
Commandsets map[string][]string `yaml:"commandsets"`
|
||||
Tests map[string]Command `yaml:"tests"`
|
||||
Checks map[string]Check `yaml:"checks"`
|
||||
}
|
||||
|
||||
// Merges merges the top-level entries of two Config objects, with the receiver
|
||||
|
||||
@ -22,7 +22,7 @@ var (
|
||||
ShortHelp: "Run the given command.",
|
||||
FlagSet: runFlagSet,
|
||||
Exec: runExec,
|
||||
UsageFunc: runUsage,
|
||||
UsageFunc: printRunUsage,
|
||||
}
|
||||
|
||||
runSetFlagSet = flag.NewFlagSet("sg run-set", flag.ExitOnError)
|
||||
@ -32,7 +32,7 @@ var (
|
||||
ShortHelp: "Run the given command set.",
|
||||
FlagSet: runSetFlagSet,
|
||||
Exec: runSetExec,
|
||||
UsageFunc: runSetUsage,
|
||||
UsageFunc: printRunSetUsage,
|
||||
}
|
||||
|
||||
startFlagSet = flag.NewFlagSet("sg start", flag.ExitOnError)
|
||||
@ -42,7 +42,7 @@ var (
|
||||
ShortHelp: "Runs the commandset with the name 'start'.",
|
||||
FlagSet: startFlagSet,
|
||||
Exec: startExec,
|
||||
UsageFunc: startUsage,
|
||||
UsageFunc: printStartUsage,
|
||||
}
|
||||
|
||||
testFlagSet = flag.NewFlagSet("sg test", flag.ExitOnError)
|
||||
@ -52,7 +52,17 @@ var (
|
||||
ShortHelp: "Run the given test suite.",
|
||||
FlagSet: testFlagSet,
|
||||
Exec: testExec,
|
||||
UsageFunc: testUsage,
|
||||
UsageFunc: printTestUsage,
|
||||
}
|
||||
|
||||
doctorFlagSet = flag.NewFlagSet("sg doctor", flag.ExitOnError)
|
||||
doctorCommand = &ffcli.Command{
|
||||
Name: "doctor",
|
||||
ShortUsage: "sg doctor",
|
||||
ShortHelp: "Run the checks defined in the config file to make sure your system is healthy.",
|
||||
FlagSet: doctorFlagSet,
|
||||
Exec: doctorExec,
|
||||
UsageFunc: printDoctorUsage,
|
||||
}
|
||||
)
|
||||
|
||||
@ -67,9 +77,8 @@ var (
|
||||
overwriteConfigFlag = rootFlagSet.String("overwrite", defaultConfigOverwriteFile, "configuration overwrites file that is gitignored and can be used to, for example, add credentials")
|
||||
|
||||
rootCommand = &ffcli.Command{
|
||||
ShortUsage: "sg [flags] <subcommand>",
|
||||
FlagSet: rootFlagSet,
|
||||
Subcommands: []*ffcli.Command{runCommand, runSetCommand, startCommand, testCommand},
|
||||
ShortUsage: "sg [flags] <subcommand>",
|
||||
FlagSet: rootFlagSet,
|
||||
Exec: func(ctx context.Context, args []string) error {
|
||||
return flag.ErrHelp
|
||||
},
|
||||
@ -91,6 +100,7 @@ var (
|
||||
|
||||
return out.String()
|
||||
},
|
||||
Subcommands: []*ffcli.Command{runCommand, runSetCommand, startCommand, testCommand, doctorCommand},
|
||||
}
|
||||
)
|
||||
|
||||
@ -227,7 +237,11 @@ func runExec(ctx context.Context, args []string) error {
|
||||
return run(ctx, cmd)
|
||||
}
|
||||
|
||||
func runUsage(c *ffcli.Command) string {
|
||||
func doctorExec(ctx context.Context, args []string) error {
|
||||
return runChecks(ctx, conf.Checks)
|
||||
}
|
||||
|
||||
func printRunUsage(c *ffcli.Command) string {
|
||||
var out strings.Builder
|
||||
|
||||
fmt.Fprintf(&out, "USAGE\n")
|
||||
@ -249,7 +263,7 @@ func runUsage(c *ffcli.Command) string {
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func testUsage(c *ffcli.Command) string {
|
||||
func printTestUsage(c *ffcli.Command) string {
|
||||
var out strings.Builder
|
||||
|
||||
fmt.Fprintf(&out, "USAGE\n")
|
||||
@ -271,7 +285,7 @@ func testUsage(c *ffcli.Command) string {
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func runSetUsage(c *ffcli.Command) string {
|
||||
func printRunSetUsage(c *ffcli.Command) string {
|
||||
var out strings.Builder
|
||||
|
||||
fmt.Fprintf(&out, "USAGE\n")
|
||||
@ -292,7 +306,7 @@ func runSetUsage(c *ffcli.Command) string {
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func startUsage(c *ffcli.Command) string {
|
||||
func printStartUsage(c *ffcli.Command) string {
|
||||
var out strings.Builder
|
||||
|
||||
fmt.Fprintf(&out, "USAGE\n")
|
||||
@ -301,6 +315,15 @@ func startUsage(c *ffcli.Command) string {
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func printDoctorUsage(c *ffcli.Command) string {
|
||||
var out strings.Builder
|
||||
|
||||
fmt.Fprintf(&out, "USAGE\n")
|
||||
fmt.Fprintf(&out, " sg doctor\n")
|
||||
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func fileExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
|
||||
@ -382,3 +382,41 @@ func runTest(ctx context.Context, cmd Command, args []string) error {
|
||||
|
||||
return c.Run()
|
||||
}
|
||||
|
||||
func runChecks(ctx context.Context, checks map[string]Check) error {
|
||||
root, err := root.RepositoryRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, check := range checks {
|
||||
commandCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
c := exec.CommandContext(commandCtx, "bash", "-c", check.Cmd)
|
||||
c.Dir = root
|
||||
c.Env = makeEnv(conf.Env)
|
||||
|
||||
p := out.Pending(output.Linef(output.EmojiLightbulb, output.StylePending, "Running check %q...", check.Name))
|
||||
|
||||
if cmdOut, err := c.CombinedOutput(); err != nil {
|
||||
p.Complete(output.Linef(output.EmojiFailure, output.StyleWarning, "Check %q failed: %s", check.Name, err))
|
||||
|
||||
out.WriteLine(output.Linef("", output.StyleWarning, "%s", check.FailMessage))
|
||||
if len(cmdOut) != 0 {
|
||||
out.WriteLine(output.Linef("", output.StyleWarning, "Check produced the following output:"))
|
||||
separator := strings.Repeat("-", 80)
|
||||
line := output.Linef(
|
||||
"", output.StyleWarning,
|
||||
"%s\n%s%s%s%s%s",
|
||||
separator, output.StyleReset, cmdOut, output.StyleWarning, separator, output.StyleReset,
|
||||
)
|
||||
out.WriteLine(line)
|
||||
}
|
||||
} else {
|
||||
p.Complete(output.Linef(output.EmojiSuccess, output.StyleSuccess, "Check %q success!", check.Name))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sourcegraph/src-cli/internal/output"
|
||||
"github.com/sourcegraph/sourcegraph/lib/output"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -315,6 +315,19 @@ commands:
|
||||
GOGC: 50
|
||||
PATH: .bin:$PATH
|
||||
|
||||
checks:
|
||||
docker:
|
||||
cmd: docker -v
|
||||
failMessage: "Failed to run 'docker -v'. Please make sure Docker is running."
|
||||
|
||||
redis:
|
||||
cmd: echo "PING" | nc localhost 6379
|
||||
failMessage: "Failed to connect to Redis on port 6379. Please make sure Redis is running."
|
||||
|
||||
postgres:
|
||||
cmd: psql -c 'SELECT 1;'
|
||||
failMessage: "Failed to connect to Postgres database. Make sure environment variables are setup correctly so that psql can connect."
|
||||
|
||||
commandsets:
|
||||
default:
|
||||
- frontend
|
||||
|
||||
Loading…
Reference in New Issue
Block a user