dev/sg: remove globalConf, extract Config into sgconf (#33882)

This commit is contained in:
Robert Lin 2022-04-14 09:01:54 -07:00 committed by GitHub
parent 9fc21ef9d2
commit 49668a24b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 258 additions and 176 deletions

3
.gitignore vendored
View File

@ -173,3 +173,6 @@ test-reports/
# go workspace files shouldn't be committed
go.work
# binary
/sg

View File

@ -14,6 +14,7 @@ import (
"github.com/jackc/pgx/v4"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/check"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/stdout"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/usershell"
"github.com/sourcegraph/sourcegraph/dev/sg/root"
@ -229,8 +230,8 @@ func checkSourcegraphDatabase(ctx context.Context) error {
// This check runs only in the `sourcegraph/sourcegraph` repository, so
// we try to parse the globalConf and use its `Env` to configure the
// Postgres connection.
ok, _ := parseConf(configFlag, overwriteConfigFlag)
if !ok {
config, _ := sgconf.Get(configFile, configOverwriteFile)
if config == nil {
return errors.New("failed to read sg.config.yaml. This step of `sg setup` needs to be run in the `sourcegraph` repository")
}
@ -242,7 +243,7 @@ func checkSourcegraphDatabase(ctx context.Context) error {
return val
}
// Otherwise check in globalConf.Env
return globalConf.Env[key]
return config.Env[key]
}
dsn := postgresdsn.New("", "", getEnv)

View File

@ -1,4 +1,4 @@
package main
package sgconf
import (
"io"
@ -10,7 +10,7 @@ import (
"github.com/sourcegraph/sourcegraph/lib/errors"
)
func ParseConfigFile(name string) (*Config, error) {
func parseConfigFile(name string) (*Config, error) {
file, err := os.Open(name)
if err != nil {
return nil, errors.Wrapf(err, "cannot open file %q", name)
@ -22,10 +22,10 @@ func ParseConfigFile(name string) (*Config, error) {
return nil, errors.Wrap(err, "reading configuration file")
}
return ParseConfig(data)
return parseConfig(data)
}
func ParseConfig(data []byte) (*Config, error) {
func parseConfig(data []byte) (*Config, error) {
var conf Config
if err := yaml.Unmarshal(data, &conf); err != nil {
return nil, err

View File

@ -1,4 +1,4 @@
package main
package sgconf
import (
"testing"
@ -40,7 +40,7 @@ commandsets:
- gitserver
`
have, err := ParseConfig([]byte(input))
have, err := parseConfig([]byte(input))
if err != nil {
t.Errorf("unexpected error: %s", err)
}
@ -92,7 +92,7 @@ commands:
- enterprise/internal
- enterprise/cmd/frontend
`
config, err := ParseConfig([]byte(a))
config, err := parseConfig([]byte(a))
if err != nil {
t.Errorf("unexpected error: %s", err)
}
@ -104,7 +104,7 @@ commands:
EXTSVC_CONFIG_FILE: ''
`
overwrite, err := ParseConfig([]byte(b))
overwrite, err := parseConfig([]byte(b))
if err != nil {
t.Errorf("unexpected error: %s", err)
}

View File

@ -0,0 +1,82 @@
package sgconf
import (
"os"
"path/filepath"
"sync"
"github.com/sourcegraph/sourcegraph/dev/sg/root"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
const (
DefaultFile = "sg.config.yaml"
DefaultOverwriteFile = "sg.config.overwrite.yaml"
)
var (
globalConfOnce sync.Once
globalConf *Config
globalConfErr error
)
// Get retrieves the global config files and merges them into a single sg config.
//
// It must not be called before flag initalization, i.e. when confFile or overwriteFile is
// not set, or it will panic. This means that it can only be used in (*cli).Action,
// (*cli).Before/(*cli).After, and postInitHooks
func Get(confFile, overwriteFile string) (*Config, error) {
// If unset, Get was called in an illegal context, since sg.Before validates that the
// flags are non-empty.
if confFile == "" || overwriteFile == "" {
panic("sgconf.Get called before flag initialization")
}
globalConfOnce.Do(func() {
globalConf, globalConfErr = parseConf(confFile, overwriteFile)
})
return globalConf, globalConfErr
}
func parseConf(confFile, overwriteFile string) (*Config, error) {
// Try to determine root of repository, so we can look for config there
repoRoot, err := root.RepositoryRoot()
if err != nil {
return nil, errors.Wrap(err, "Failed to determine repository root location")
}
// If the configFlag/overwriteConfigFlag flags have their default value, we
// take the value as relative to the root of the repository.
if confFile == DefaultFile {
confFile = filepath.Join(repoRoot, confFile)
}
if overwriteFile == DefaultOverwriteFile {
overwriteFile = filepath.Join(repoRoot, overwriteFile)
}
conf, err := parseConfigFile(confFile)
if err != nil {
return nil, errors.Wrapf(err, "Failed to parse %q as configuration file", confFile)
}
if ok, _ := fileExists(overwriteFile); ok {
overwriteConf, err := parseConfigFile(overwriteFile)
if err != nil {
return nil, errors.Wrapf(err, "Failed to parse %q as configuration overwrite file", confFile)
}
conf.Merge(overwriteConf)
}
return conf, nil
}
func fileExists(path string) (bool, error) {
_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return true, nil
}

View File

@ -10,9 +10,10 @@ import (
"github.com/urfave/cli/v2"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/secrets"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/stdout"
"github.com/sourcegraph/sourcegraph/dev/sg/root"
"github.com/sourcegraph/sourcegraph/lib/output"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
func main() {
@ -27,24 +28,21 @@ func main() {
}
const (
defaultConfigFile = "sg.config.yaml"
defaultConfigOverwriteFile = "sg.config.overwrite.yaml"
defaultSecretsFile = "sg.secrets.json"
defaultSecretsFile = "sg.secrets.json"
)
var (
BuildCommit = "dev"
// globalConf is the global config. If a command needs to access it, it *must* call
// `parseConf` before.
globalConf *Config
// secretsStore is instantiated when sg gets run.
secretsStore *secrets.Store
// Note that these values are only available after the main sg CLI app has been run.
configFlag string
overwriteConfigFlag string
// configFile is the path to use with sgconf.Get - it must not be used before flag
// initialization.
configFile string
// configOverwriteFile is the path to use with sgconf.Get - it must not be used before
// flag initialization.
configOverwriteFile string
// Global verbose mode
verbose bool
@ -81,19 +79,21 @@ var sg = &cli.App{
},
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "load sg configuration from `file`",
EnvVars: []string{"SG_CONFIG"},
TakesFile: true,
Value: defaultConfigFile,
Destination: &configFlag,
Value: sgconf.DefaultFile,
Destination: &configFile,
},
&cli.StringFlag{
Name: "overwrite",
Aliases: []string{"o"},
Usage: "load sg configuration from `file` that is gitignored and can be used to, for example, add credentials",
EnvVars: []string{"SG_OVERWRITE"},
TakesFile: true,
Value: defaultConfigOverwriteFile,
Destination: &overwriteConfigFlag,
Value: sgconf.DefaultOverwriteFile,
Destination: &configOverwriteFile,
},
&cli.BoolFlag{
Name: "skip-auto-update",
@ -103,16 +103,24 @@ var sg = &cli.App{
},
},
Before: func(cmd *cli.Context) error {
if verbose {
stdout.Out.SetVerbose()
}
if batchCompletionMode {
// All other setup pertains to running commands - to keep completions fast,
// we skip all other setup.
return nil
}
if verbose {
stdout.Out.SetVerbose()
}
// Validate configuration flags, which is required for sgconf.Get to work everywhere else.
if configFile == "" {
return errors.Newf("--config must not be empty")
}
if configOverwriteFile == "" {
return errors.Newf("--overwrite must not be empty")
}
// Set up access to secrets
if err := loadSecrets(); err != nil {
writeWarningLinef("failed to open secrets: %s", err)
@ -188,42 +196,3 @@ func loadSecrets() error {
secretsStore, err = secrets.LoadFile(fp)
return err
}
// parseConf parses the config file and the optional overwrite file.
// Iear the conf has already been parsed it's a noop.
func parseConf(confFile, overwriteFile string) (bool, output.FancyLine) {
if globalConf != nil {
return true, output.FancyLine{}
}
// Try to determine root of repository, so we can look for config there
repoRoot, err := root.RepositoryRoot()
if err != nil {
return false, output.Linef("", output.StyleWarning, "Failed to determine repository root location: %s", err)
}
// If the configFlag/overwriteConfigFlag flags have their default value, we
// take the value as relative to the root of the repository.
if confFile == defaultConfigFile {
confFile = filepath.Join(repoRoot, confFile)
}
if overwriteFile == defaultConfigOverwriteFile {
overwriteFile = filepath.Join(repoRoot, overwriteFile)
}
globalConf, err = ParseConfigFile(confFile)
if err != nil {
return false, output.Linef("", output.StyleWarning, "Failed to parse %s%s%s%s as configuration file:%s\n%s", output.StyleBold, confFile, output.StyleReset, output.StyleWarning, output.StyleReset, err)
}
if ok, _ := fileExists(overwriteFile); ok {
overwriteConf, err := ParseConfigFile(overwriteFile)
if err != nil {
return false, output.Linef("", output.StyleWarning, "Failed to parse %s%s%s%s as overwrites configuration file:%s\n%s", output.StyleBold, overwriteFile, output.StyleReset, output.StyleWarning, output.StyleReset, err)
}
globalConf.Merge(overwriteConf)
}
return true, output.FancyLine{}
}

View File

@ -9,17 +9,31 @@ import (
"github.com/urfave/cli/v2"
)
// testSG creates a copy of the sg app for testing.
func testSG() *cli.App {
tsg := *sg
return &tsg
}
func TestAppRun(t *testing.T) {
// Check app starts up correctly
sg := testSG()
// Capture output
var out, err bytes.Buffer
sg.Writer = &out
sg.ErrWriter = &err
// Check app starts up correctly
assert.NoError(t, sg.Run([]string{"help"}))
assert.Contains(t, out.String(), "The Sourcegraph developer tool!")
// We do not want errors anywhere
assert.NotContains(t, out.String(), "error")
assert.NotContains(t, out.String(), "panic")
assert.Empty(t, err.String())
}
func TestCommandFormatting(t *testing.T) {
sg := testSG()
sg.Setup()
for _, cmd := range sg.Commands {
testCommandFormatting(t, cmd)

View File

@ -1,7 +1,6 @@
package main
import (
"os"
"syscall"
"github.com/sourcegraph/sourcegraph/lib/errors"
@ -29,14 +28,3 @@ func setMaxOpenFiles() error {
return nil
}
func fileExists(path string) (bool, error) {
_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return true, nil
}

View File

@ -19,8 +19,12 @@ func writeFailureLinef(fmtStr string, args ...interface{}) {
stdout.Out.WriteLine(output.Linef(output.EmojiFailure, output.StyleWarning, fmtStr, args...))
}
func newWarningLinef(fmtStr string, args ...interface{}) output.FancyLine {
return output.Linef(output.EmojiWarningSign, output.StyleYellow, fmtStr, args...)
}
func writeWarningLinef(fmtStr string, args ...interface{}) {
stdout.Out.WriteLine(output.Linef(output.EmojiWarningSign, output.StyleYellow, fmtStr, args...))
stdout.Out.WriteLine(newWarningLinef(fmtStr, args...))
}
func writeSkippedLinef(fmtStr string, args ...interface{}) {

View File

@ -12,6 +12,7 @@ import (
"github.com/urfave/cli/v2"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/db"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/internal/database"
connections "github.com/sourcegraph/sourcegraph/internal/database/connections/live"
"github.com/sourcegraph/sourcegraph/internal/database/migration/runner"
@ -78,13 +79,13 @@ func dbAddUserAction(cmd *cli.Context) error {
ctx := cmd.Context
// Read the configuration.
ok, _ := parseConf(configFlag, overwriteConfigFlag)
if !ok {
conf, _ := sgconf.Get(configFile, configOverwriteFile)
if conf == nil {
return errors.New("failed to read sg.config.yaml. This command needs to be run in the `sourcegraph` repository")
}
// Connect to the database.
conn, err := connections.EnsureNewFrontendDB(postgresdsn.New("", "", globalConf.GetEnv), "frontend", &observation.TestContext)
conn, err := connections.EnsureNewFrontendDB(postgresdsn.New("", "", conf.GetEnv), "frontend", &observation.TestContext)
if err != nil {
return err
}
@ -131,13 +132,13 @@ func dbAddUserAction(cmd *cli.Context) error {
func dbResetRedisExec(ctx context.Context, args []string) error {
// Read the configuration.
ok, _ := parseConf(configFlag, overwriteConfigFlag)
if !ok {
config, _ := sgconf.Get(configFile, configOverwriteFile)
if config == nil {
return errors.New("failed to read sg.config.yaml. This command needs to be run in the `sourcegraph` repository")
}
// Connect to the redis database.
endpoint := globalConf.GetEnv("REDIS_ENDPOINT")
endpoint := config.GetEnv("REDIS_ENDPOINT")
conn, err := redis.Dial("tcp", endpoint, redis.DialConnectTimeout(5*time.Second))
if err != nil {
return errors.Wrapf(err, "failed to connect to Redis at %s", endpoint)
@ -154,8 +155,8 @@ func dbResetRedisExec(ctx context.Context, args []string) error {
func dbResetPGExec(ctx context.Context, args []string) error {
// Read the configuration.
ok, _ := parseConf(configFlag, overwriteConfigFlag)
if !ok {
config, _ := sgconf.Get(configFile, configOverwriteFile)
if config == nil {
return errors.New("failed to read sg.config.yaml. This command needs to be run in the `sourcegraph` repository")
}
@ -172,9 +173,9 @@ func dbResetPGExec(ctx context.Context, args []string) error {
for _, name := range schemaNames {
if name == "frontend" {
dsnMap[name] = postgresdsn.New("", "", globalConf.GetEnv)
dsnMap[name] = postgresdsn.New("", "", config.GetEnv)
} else {
dsnMap[name] = postgresdsn.New(strings.ToUpper(name), "", globalConf.GetEnv)
dsnMap[name] = postgresdsn.New(strings.ToUpper(name), "", config.GetEnv)
}
}

View File

@ -31,7 +31,7 @@ func constructLiveCmdLongHelp() string {
fmt.Fprintf(&out, "Prints the Sourcegraph version deployed to the given environment.")
fmt.Fprintf(&out, "\n")
fmt.Fprintf(&out, "\n")
fmt.Fprintf(&out, "AVAILABLE PRESET ENVIRONMENTS\n")
fmt.Fprintf(&out, "AVAILABLE PRESET ENVIRONMENTS:\n")
for _, name := range environmentNames() {
fmt.Fprintf(&out, " %s\n", name)

View File

@ -13,6 +13,7 @@ import (
"github.com/sourcegraph/sourcegraph/dev/sg/internal/db"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/migration"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/stdout"
"github.com/sourcegraph/sourcegraph/dev/sg/root"
connections "github.com/sourcegraph/sourcegraph/internal/database/connections/live"
@ -101,9 +102,9 @@ func makeRunner(ctx context.Context, schemaNames []string) (cliutil.Runner, erro
// Try to read the `sg` configuration so we can read ENV vars from the
// configuration and use process env as fallback.
var getEnv func(string) string
ok, _ := parseConf(configFlag, overwriteConfigFlag)
if ok {
getEnv = globalConf.GetEnv
config, _ := sgconf.Get(configFile, configOverwriteFile)
if config != nil {
getEnv = config.GetEnv
} else {
getEnv = os.Getenv
}

View File

@ -11,6 +11,7 @@ import (
"github.com/urfave/cli/v2"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/run"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/stdout"
"github.com/sourcegraph/sourcegraph/lib/output"
)
@ -23,17 +24,20 @@ func init() {
}
var runCommand = &cli.Command{
Name: "run",
Usage: "Run the given commands",
ArgsUsage: "[command]",
Description: constructRunCmdLongHelp(),
Category: CategoryDev,
Name: "run",
Usage: "Run the given commands",
ArgsUsage: "[command]",
Category: CategoryDev,
Flags: []cli.Flag{
addToMacOSFirewallFlag,
},
Action: execAdapter(runExec),
BashComplete: completeOptions(func() (options []string) {
for name := range globalConf.Commands {
config, _ := sgconf.Get(configFile, configOverwriteFile)
if config == nil {
return
}
for name := range config.Commands {
options = append(options, name)
}
return
@ -41,9 +45,9 @@ var runCommand = &cli.Command{
}
func runExec(ctx context.Context, args []string) error {
ok, errLine := parseConf(configFlag, overwriteConfigFlag)
if !ok {
stdout.Out.WriteLine(errLine)
config, err := sgconf.Get(configFile, configOverwriteFile)
if err != nil {
writeWarningLinef(err.Error())
os.Exit(1)
}
@ -54,7 +58,7 @@ func runExec(ctx context.Context, args []string) error {
var cmds []run.Command
for _, arg := range args {
cmd, ok := globalConf.Commands[arg]
cmd, ok := config.Commands[arg]
if !ok {
stdout.Out.WriteLine(output.Linef("", output.StyleWarning, "ERROR: command %q not found :(", arg))
return flag.ErrHelp
@ -62,28 +66,30 @@ func runExec(ctx context.Context, args []string) error {
cmds = append(cmds, cmd)
}
return run.Commands(ctx, globalConf.Env, addToMacOSFirewall, verbose, cmds...)
return run.Commands(ctx, config.Env, addToMacOSFirewall, verbose, cmds...)
}
func constructRunCmdLongHelp() string {
var out strings.Builder
fmt.Fprintf(&out, " Runs the given command. If given a whitespace-separated list of commands it runs the set of commands.\n")
ok, warning := parseConf(configFlag, overwriteConfigFlag)
if ok {
fmt.Fprintf(&out, "\n")
fmt.Fprintf(&out, "AVAILABLE COMMANDS IN %s%s%s\n", output.StyleBold, configFlag, output.StyleReset)
var names []string
for name := range globalConf.Commands {
names = append(names, name)
}
sort.Strings(names)
fmt.Fprint(&out, strings.Join(names, "\n"))
} else {
config, err := sgconf.Get(configFile, configOverwriteFile)
if err != nil {
out.Write([]byte("\n"))
output.NewOutput(&out, output.OutputOpts{}).WriteLine(warning)
output.NewOutput(&out, output.OutputOpts{}).WriteLine(newWarningLinef(err.Error()))
return out.String()
}
fmt.Fprintf(&out, "\n")
fmt.Fprintf(&out, "AVAILABLE COMMANDS IN %s%s%s:\n", output.StyleBold, configFile, output.StyleReset)
var names []string
for name := range config.Commands {
names = append(names, name)
}
sort.Strings(names)
fmt.Fprint(&out, strings.Join(names, "\n"))
return out.String()
}

View File

@ -12,6 +12,7 @@ import (
"github.com/urfave/cli/v2"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/run"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/stdout"
"github.com/sourcegraph/sourcegraph/dev/sg/root"
"github.com/sourcegraph/sourcegraph/lib/errors"
@ -72,7 +73,11 @@ var (
addToMacOSFirewallFlag,
},
BashComplete: completeOptions(func() (options []string) {
for name := range globalConf.Commandsets {
config, _ := sgconf.Get(configFile, configOverwriteFile)
if config == nil {
return
}
for name := range config.Commandsets {
options = append(options, name)
}
return
@ -91,36 +96,37 @@ If no commandset is specified, it starts the commandset with the name 'default'.
Use this to start your Sourcegraph environment!
`)
ok, warning := parseConf(configFlag, overwriteConfigFlag)
if ok {
fmt.Fprintf(&out, "\n")
fmt.Fprintf(&out, "AVAILABLE COMMANDSETS IN %s%s%s\n", output.StyleBold, configFlag, output.StyleReset)
var names []string
for name := range globalConf.Commandsets {
switch name {
case "enterprise-codeintel":
names = append(names, fmt.Sprintf(" %s 🧠", name))
case "batches":
names = append(names, fmt.Sprintf(" %s 🦡", name))
default:
names = append(names, fmt.Sprintf(" %s", name))
}
}
sort.Strings(names)
fmt.Fprint(&out, strings.Join(names, "\n"))
} else {
config, err := sgconf.Get(configFile, configOverwriteFile)
if err != nil {
out.Write([]byte("\n"))
output.NewOutput(&out, output.OutputOpts{}).WriteLine(warning)
output.NewOutput(&out, output.OutputOpts{}).WriteLine(newWarningLinef(err.Error()))
return out.String()
}
fmt.Fprintf(&out, "\n")
fmt.Fprintf(&out, "AVAILABLE COMMANDSETS IN %s%s%s:\n", output.StyleBold, configFile, output.StyleReset)
var names []string
for name := range config.Commandsets {
switch name {
case "enterprise-codeintel":
names = append(names, fmt.Sprintf(" %s 🧠", name))
case "batches":
names = append(names, fmt.Sprintf(" %s 🦡", name))
default:
names = append(names, fmt.Sprintf(" %s", name))
}
}
sort.Strings(names)
fmt.Fprint(&out, strings.Join(names, "\n"))
return out.String()
}
func startExec(ctx context.Context, args []string) error {
ok, errLine := parseConf(configFlag, overwriteConfigFlag)
if !ok {
stdout.Out.WriteLine(errLine)
config, err := sgconf.Get(configFile, configOverwriteFile)
if err != nil {
writeWarningLinef(err.Error())
os.Exit(1)
}
@ -130,15 +136,15 @@ func startExec(ctx context.Context, args []string) error {
}
if len(args) != 1 {
if globalConf.DefaultCommandset != "" {
args = append(args, globalConf.DefaultCommandset)
if config.DefaultCommandset != "" {
args = append(args, config.DefaultCommandset)
} else {
stdout.Out.WriteLine(output.Linef("", output.StyleWarning, "ERROR: No commandset specified and no 'defaultCommandset' specified in sg.config.yaml\n"))
return flag.ErrHelp
}
}
set, ok := globalConf.Commandsets[args[0]]
set, ok := config.Commandsets[args[0]]
if !ok {
stdout.Out.WriteLine(output.Linef("", output.StyleWarning, "ERROR: commandset %q not found :(", args[0]))
return flag.ErrHelp
@ -179,10 +185,10 @@ func startExec(ctx context.Context, args []string) error {
}
}
return startCommandSet(ctx, set, globalConf, addToMacOSFirewall)
return startCommandSet(ctx, set, config, addToMacOSFirewall)
}
func startCommandSet(ctx context.Context, set *Commandset, conf *Config, addToMacOSFirewall bool) error {
func startCommandSet(ctx context.Context, set *sgconf.Commandset, conf *sgconf.Config, addToMacOSFirewall bool) error {
if err := runChecksWithName(ctx, set.Checks); err != nil {
return err
}

View File

@ -9,6 +9,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/run"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/stdout"
"github.com/sourcegraph/sourcegraph/lib/output"
"github.com/sourcegraph/sourcegraph/lib/output/outputtest"
@ -20,16 +21,16 @@ func TestStartCommandSet(t *testing.T) {
buf := useOutputBuffer(t)
commandSet := &Commandset{Name: "test-set", Commands: []string{"test-cmd-1"}}
commandSet := &sgconf.Commandset{Name: "test-set", Commands: []string{"test-cmd-1"}}
command := run.Command{
Name: "test-cmd-1",
Install: "echo 'booting up horsegraph'",
Cmd: "echo 'horsegraph booted up. mount your horse.' && echo 'quitting. not horsing around anymore.'",
}
testConf := &Config{
testConf := &sgconf.Config{
Commands: map[string]run.Command{"test-cmd-1": command},
Commandsets: map[string]*Commandset{"test-set": commandSet},
Commandsets: map[string]*sgconf.Commandset{"test-set": commandSet},
}
if err := startCommandSet(ctx, commandSet, testConf, false); err != nil {
@ -60,16 +61,16 @@ func TestStartCommandSet_InstallError(t *testing.T) {
buf := useOutputBuffer(t)
commandSet := &Commandset{Name: "test-set", Commands: []string{"test-cmd-1"}}
commandSet := &sgconf.Commandset{Name: "test-set", Commands: []string{"test-cmd-1"}}
command := run.Command{
Name: "test-cmd-1",
Install: "echo 'booting up horsegraph' && exit 1",
Cmd: "echo 'never appears'",
}
testConf := &Config{
testConf := &sgconf.Config{
Commands: map[string]run.Command{"test-cmd-1": command},
Commandsets: map[string]*Commandset{"test-set": commandSet},
Commandsets: map[string]*sgconf.Commandset{"test-set": commandSet},
}
err := startCommandSet(ctx, commandSet, testConf, withPostInstallCallback)

View File

@ -11,6 +11,7 @@ import (
"github.com/urfave/cli/v2"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/run"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/sgconf"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/stdout"
"github.com/sourcegraph/sourcegraph/lib/output"
)
@ -28,7 +29,11 @@ var testCommand = &cli.Command{
Usage: "Run the given test suite",
Category: CategoryDev,
BashComplete: completeOptions(func() (options []string) {
for name := range globalConf.Tests {
config, _ := sgconf.Get(configFile, configOverwriteFile)
if config == nil {
return
}
for name := range config.Tests {
options = append(options, name)
}
return
@ -37,9 +42,9 @@ var testCommand = &cli.Command{
}
func testExec(ctx context.Context, args []string) error {
ok, errLine := parseConf(configFlag, overwriteConfigFlag)
if !ok {
stdout.Out.WriteLine(errLine)
config, err := sgconf.Get(configFile, configOverwriteFile)
if err != nil {
writeWarningLinef(err.Error())
os.Exit(1)
}
@ -48,13 +53,13 @@ func testExec(ctx context.Context, args []string) error {
return flag.ErrHelp
}
cmd, ok := globalConf.Tests[args[0]]
cmd, ok := config.Tests[args[0]]
if !ok {
stdout.Out.WriteLine(output.Linef("", output.StyleWarning, "ERROR: test suite %q not found :(", args[0]))
return flag.ErrHelp
}
return run.Test(ctx, cmd, args[1:], globalConf.Env)
return run.Test(ctx, cmd, args[1:], config.Env)
}
func constructTestCmdLongHelp() string {
@ -64,22 +69,23 @@ func constructTestCmdLongHelp() string {
// Attempt to parse config to list available testsuites, but don't fail on
// error, because we should never error when the user wants --help output.
ok, warning := parseConf(configFlag, overwriteConfigFlag)
if ok {
fmt.Fprintf(&out, "\n\n")
fmt.Fprintf(&out, "AVAILABLE TESTSUITES IN %s%s%s:\n", output.StyleBold, configFlag, output.StyleReset)
fmt.Fprintf(&out, "\n")
var names []string
for name := range globalConf.Tests {
names = append(names, name)
}
sort.Strings(names)
fmt.Fprint(&out, strings.Join(names, "\n"))
} else {
config, err := sgconf.Get(configFile, configOverwriteFile)
if err != nil {
out.Write([]byte("\n"))
output.NewOutput(&out, output.OutputOpts{}).WriteLine(warning)
output.NewOutput(&out, output.OutputOpts{}).WriteLine(newWarningLinef(err.Error()))
return out.String()
}
fmt.Fprintf(&out, "\n\n")
fmt.Fprintf(&out, "AVAILABLE TESTSUITES IN %s%s%s:\n", output.StyleBold, configFile, output.StyleReset)
fmt.Fprintf(&out, "\n")
var names []string
for name := range config.Tests {
names = append(names, name)
}
sort.Strings(names)
fmt.Fprint(&out, strings.Join(names, "\n"))
return out.String()
}