Skip to content

Commit

Permalink
feat!: separate out init command (#866)
Browse files Browse the repository at this point in the history
* feat!: separate out init command
  • Loading branch information
alexplischke authored Dec 8, 2023
1 parent b5c3b6f commit 9102c28
Show file tree
Hide file tree
Showing 10 changed files with 793 additions and 574 deletions.
2 changes: 1 addition & 1 deletion cmd/saucectl/saucectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func main() {
cmd.AddCommand(
run.Command(),
configure.Command(),
ini.Command(),
ini.Command(cmd.PersistentPreRun),
signup.Command(),
completion.Command(),
storage.Command(cmd.PersistentPreRun),
Expand Down
149 changes: 66 additions & 83 deletions internal/cmd/ini/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@ import (
"github.com/saucelabs/saucectl/internal/imagerunner"
"github.com/saucelabs/saucectl/internal/msg"
"github.com/saucelabs/saucectl/internal/playwright"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/testcafe"
"github.com/saucelabs/saucectl/internal/xcuitest"

"github.com/AlecAivazis/survey/v2/terminal"
"github.com/fatih/color"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)

Expand All @@ -33,12 +31,13 @@ var (
initExample = "saucectl init"
)

type initConfig struct {
batchMode bool
var noPrompt = false
var regionName = "us-west-1"

type initConfig struct {
frameworkName string
frameworkVersion string
cypressJSON string
cypressConfigFile string
dockerImage string
app string
testApp string
Expand All @@ -55,11 +54,9 @@ type initConfig struct {
emulatorFlag flags.Emulator
simulatorFlag flags.Simulator
concurrency int
username string
accessKey string
workload string
playwrightProject string
testMatch string
testMatch []string
}

var (
Expand All @@ -68,67 +65,50 @@ var (
restoTimeout = 5 * time.Second
)

// Command creates the `init` command
func Command() *cobra.Command {
initCfg := &initConfig{}

func Command(preRun func(cmd *cobra.Command, args []string)) *cobra.Command {
cmd := &cobra.Command{
Use: initUse,
Short: initShort,
Long: initLong,
Example: initExample,
SilenceUsage: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
return preRun()
},
Run: func(cmd *cobra.Command, args []string) {
tracker := segment.DefaultTracker

go func() {
tracker.Collect("Init", nil)
_ = tracker.Close()
}()
Use: initUse,
Short: initShort,
Long: initLong,
Example: initExample,
SilenceUsage: true,
TraverseChildren: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if preRun != nil {
preRun(cmd, args)
}

log.Info().Msg("Start Init Command")
err := Run(cmd, initCfg)
err := http.CheckProxy()
if err != nil {
log.Err(err).Msg("failed to execute init command")
os.Exit(1)
return fmt.Errorf("invalid HTTP_PROXY value")
}
return nil
},
}
cmd.Flags().StringVarP(&initCfg.username, "username", "u", "", "username to use")
cmd.Flags().StringVarP(&initCfg.accessKey, "accessKey", "a", "", "access key for the Sauce Labs account making the request")
cmd.Flags().StringVarP(&initCfg.region, "region", "r", "us-west-1", "region to use")
cmd.Flags().StringVarP(&initCfg.frameworkName, "framework", "f", "", "framework to configure")
cmd.Flags().StringVarP(&initCfg.frameworkVersion, "frameworkVersion", "v", "", "framework version to be used")
cmd.Flags().StringVar(&initCfg.cypressJSON, "cypress.config", "", "path to cypress.json file (cypress only)")
cmd.Flags().StringVar(&initCfg.dockerImage, "dockerImage", "", "docker image to use (imagerunner only)")
cmd.Flags().StringVar(&initCfg.workload, "workload", "", "workload to use (imagerunner only)")
cmd.Flags().StringVar(&initCfg.app, "app", "", "path to application to test (espresso/xcuitest only)")
cmd.Flags().StringVarP(&initCfg.testApp, "testApp", "t", "", "path to test application (espresso/xcuitest only)")
cmd.Flags().StringSliceVarP(&initCfg.otherApps, "otherApps", "o", []string{}, "path to other applications (espresso/xcuitest only)")
cmd.Flags().StringVarP(&initCfg.platformName, "platformName", "p", "", "Specified platform name")
cmd.Flags().StringVarP(&initCfg.browserName, "browserName", "b", "", "Specifies browser name")
cmd.Flags().StringVar(&initCfg.artifactWhenStr, "artifacts.download.when", "fail", "defines when to download artifacts")
cmd.Flags().Var(&initCfg.emulatorFlag, "emulator", "Specifies the Android emulator to use for testing")
cmd.Flags().Var(&initCfg.simulatorFlag, "simulator", "Specifies the iOS simulator to use for testing")
cmd.Flags().Var(&initCfg.deviceFlag, "device", "Specifies the device to use for testing")
return cmd
}

func preRun() error {
err := http.CheckProxy()
if err != nil {
return fmt.Errorf("invalid HTTP_PROXY value")
}
return nil
cmd.AddCommand(
CypressCmd(),
EspressoCmd(),
ImageRunnerCmd(),
PlaywrightCmd(),
TestCafeCmd(),
XCUITestCmd(),
)

flags := cmd.PersistentFlags()

flags.BoolVar(&noPrompt, "no-prompt", false, "Disable interactive prompts.")
flags.StringVarP(&regionName, "region", "r", "", "Sauce Labs region. Options: us-west-1, eu-central-1.")

return cmd
}

// Run runs the command
func Run(cmd *cobra.Command, initCfg *initConfig) error {
if cmd.Flags().Changed("framework") {
return batchMode(cmd, initCfg)
func Run(cmd *cobra.Command, cfg *initConfig) error {
cfg.region = regionName

if noPrompt {
return noPromptMode(cmd, cfg)
}
stdio := terminal.Stdio{In: os.Stdin, Out: os.Stdout, Err: os.Stderr}

Expand All @@ -144,21 +124,25 @@ func Run(cmd *cobra.Command, initCfg *initConfig) error {
}
}

regio, err := askRegion(stdio)
if err != nil {
return err
var err error
if cfg.region == "" {
cfg.region, err = askRegion(stdio)
if err != nil {
return err
}
}

ini := newInitializer(stdio, creds, regio)
err = ini.checkCredentials(regio)
ini := newInitializer(stdio, creds, cfg)

err = ini.checkCredentials(regionName)
if err != nil {
return err
}
initCfg, err = ini.configure()

err = ini.configure()
if err != nil {
return err
}
initCfg.region = regio

ccy, err := ini.userService.Concurrency(context.Background())
if err != nil {
Expand All @@ -168,41 +152,40 @@ func Run(cmd *cobra.Command, initCfg *initConfig) error {
println()
ccy.Org.Allowed.VDC = 1
}
initCfg.concurrency = ccy.Org.Allowed.VDC
cfg.concurrency = ccy.Org.Allowed.VDC

files, err := saveConfigurationFiles(initCfg)
files, err := saveConfigurationFiles(cfg)
if err != nil {
return err
}
displaySummary(files)
displayExtraInfo(initCfg.frameworkName)
displayExtraInfo(cfg.frameworkName)
return nil
}

func batchMode(cmd *cobra.Command, initCfg *initConfig) error {
func noPromptMode(cmd *cobra.Command, cfg *initConfig) error {
stdio := terminal.Stdio{In: os.Stdin, Out: os.Stdout, Err: os.Stderr}
creds := credentials.Get()
if !creds.IsSet() {
return errors.New(msg.EmptyCredentials)
}

ini := newInitializer(stdio, creds, initCfg.region)
initCfg.batchMode = true
ini := newInitializer(stdio, creds, cfg)

var errs []error
switch initCfg.frameworkName {
switch cfg.frameworkName {
case cypress.Kind:
initCfg, errs = ini.initializeBatchCypress(initCfg)
errs = ini.initializeBatchCypress()
case espresso.Kind:
initCfg, errs = ini.initializeBatchEspresso(cmd.Flags(), initCfg)
errs = ini.initializeBatchEspresso(cmd.Flags())
case playwright.Kind:
initCfg, errs = ini.initializeBatchPlaywright(initCfg)
errs = ini.initializeBatchPlaywright()
case testcafe.Kind:
initCfg, errs = ini.initializeBatchTestcafe(initCfg)
errs = ini.initializeBatchTestcafe()
case xcuitest.Kind:
initCfg, errs = ini.initializeBatchXcuitest(cmd.Flags(), initCfg)
errs = ini.initializeBatchXcuitest(cmd.Flags())
case imagerunner.Kind:
initCfg, errs = ini.initializeBatchImageRunner(initCfg)
errs = ini.initializeBatchImageRunner()
default:
println()
color.HiRed("Invalid framework selected")
Expand All @@ -214,7 +197,7 @@ func batchMode(cmd *cobra.Command, initCfg *initConfig) error {
for _, err := range errs {
fmt.Printf("- %v\n", err)
}
return fmt.Errorf("%s: %d errors occured", initCfg.frameworkName, len(errs))
return fmt.Errorf("%s: %d errors occured", cfg.frameworkName, len(errs))
}

ccy, err := ini.userService.Concurrency(context.Background())
Expand All @@ -225,13 +208,13 @@ func batchMode(cmd *cobra.Command, initCfg *initConfig) error {
println()
ccy.Org.Allowed.VDC = 1
}
initCfg.concurrency = ccy.Org.Allowed.VDC
cfg.concurrency = ccy.Org.Allowed.VDC

files, err := saveConfigurationFiles(initCfg)
files, err := saveConfigurationFiles(cfg)
if err != nil {
return err
}
displaySummary(files)
displayExtraInfo(initCfg.frameworkName)
displayExtraInfo(cfg.frameworkName)
return nil
}
50 changes: 47 additions & 3 deletions internal/cmd/ini/cypress.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,65 @@ import (
// imports embed to load .sauceignore
_ "embed"
"fmt"
"os"
"strconv"
"strings"

"github.com/rs/zerolog/log"
cmds "github.com/saucelabs/saucectl/internal/cmd"
"github.com/saucelabs/saucectl/internal/config"
"github.com/saucelabs/saucectl/internal/cypress"
v1 "github.com/saucelabs/saucectl/internal/cypress/v1"
"github.com/saucelabs/saucectl/internal/cypress/v1alpha"
"github.com/saucelabs/saucectl/internal/segment"
"github.com/saucelabs/saucectl/internal/usage"
"github.com/spf13/cobra"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)

func CypressCmd() *cobra.Command {
cfg := &initConfig{
frameworkName: cypress.Kind,
}

cmd := &cobra.Command{
Use: "cypress",
Short: "Bootstrap a Cypress project.",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) {
tracker := segment.DefaultTracker

go func() {
tracker.Collect(
cases.Title(language.English).String(cmds.FullName(cmd)),
usage.Properties{}.SetFlags(cmd.Flags()),
)
_ = tracker.Close()
}()

err := Run(cmd, cfg)
if err != nil {
log.Err(err).Msg("failed to execute init command")
os.Exit(1)
}
},
}

cmd.Flags().StringVar(&cfg.frameworkVersion, "version", "", "Cypress version.")
cmd.Flags().StringVar(&cfg.cypressConfigFile, "cypress-config", "", "Path to the cypress config file.")
cmd.Flags().StringVar(&cfg.platformName, "platform", "", "OS name and version, such as 'Windows 11' or 'macOS 13'.")
cmd.Flags().StringVar(&cfg.browserName, "browser", "", "Browser name.")
cmd.Flags().StringVar(&cfg.artifactWhenStr, "artifacts-when", "fail", "When to download artifacts.")

return cmd
}

func configureCypress(cfg *initConfig) interface{} {
versions := strings.Split(cfg.frameworkVersion, ".")
version, err := strconv.Atoi(versions[0])
if err != nil {
log.Err(err).Msg("failed to parse frameworkVersion")
log.Err(err).Msg("failed to parse framework version")
}
if version < 10 {
return v1alpha.Project{
Expand All @@ -34,7 +78,7 @@ func configureCypress(cfg *initConfig) interface{} {
RootDir: ".",
Cypress: v1alpha.Cypress{
Version: cfg.frameworkVersion,
ConfigFile: cfg.cypressJSON,
ConfigFile: cfg.cypressConfigFile,
},
Suites: []v1alpha.Suite{
{
Expand Down Expand Up @@ -69,7 +113,7 @@ func configureCypress(cfg *initConfig) interface{} {
RootDir: ".",
Cypress: v1.Cypress{
Version: cfg.frameworkVersion,
ConfigFile: cfg.cypressJSON,
ConfigFile: cfg.cypressConfigFile,
},
Suites: []v1.Suite{
{
Expand Down
Loading

0 comments on commit 9102c28

Please sign in to comment.