diff --git a/ci/README.md b/ci/README.md index ae2370a1..1daee639 100644 --- a/ci/README.md +++ b/ci/README.md @@ -1,5 +1,13 @@ # ci +## checks + +- `steps/build.sh` builds release assets with the appropriate tag injected. Required to pass for merging. +- `steps/fmt.sh` formats all Go source files. +- `steps/gendocs.sh` generates CLI documentation into `/docs` from the command specifications. +- `steps/lint.sh` lints all Go source files based on the rules set fourth in `/.golangci.yml`. + + ## integration tests ### `tcli` @@ -8,7 +16,7 @@ Package `tcli` provides a framework for writing end-to-end CLI tests. Each test group can have its own container for executing commands in a consistent and isolated filesystem. -### prerequisites +### running Assign the following environment variables to run the integration tests against an existing Enterprise deployment instance. @@ -22,5 +30,5 @@ export CODER_PASSWORD=... Then, simply run the test command from the project root ```sh -go test -v ./ci/integration +./ci/steps/integration.sh ``` diff --git a/ci/integration/integration_test.go b/ci/integration/integration_test.go index 52527839..8475de4f 100644 --- a/ci/integration/integration_test.go +++ b/ci/integration/integration_test.go @@ -14,7 +14,7 @@ func run(t *testing.T, container string, execute func(t *testing.T, ctx context. t.Run(container, func(t *testing.T) { t.Parallel() - ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{ diff --git a/internal/cmd/auth.go b/internal/cmd/auth.go index f514ba89..1860298d 100644 --- a/internal/cmd/auth.go +++ b/internal/cmd/auth.go @@ -19,8 +19,7 @@ var errNeedLogin = clog.Fatal( clog.Hintf(`did you run "coder login [https://coder.domain.com]"?`), ) -func newClient() (*coder.Client, error) { - ctx := context.Background() +func newClient(ctx context.Context) (*coder.Client, error) { sessionToken, err := config.Session.Read() if err != nil { return nil, errNeedLogin diff --git a/internal/cmd/configssh.go b/internal/cmd/configssh.go index 38d20fdf..afa6b6b4 100644 --- a/internal/cmd/configssh.go +++ b/internal/cmd/configssh.go @@ -49,9 +49,7 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st endToken := "# ------------END-CODER-ENTERPRISE------------" return func(cmd *cobra.Command, _ []string) error { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - + ctx := cmd.Context() usr, err := user.Current() if err != nil { return xerrors.Errorf("get user home directory: %w", err) @@ -88,22 +86,21 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st return nil } - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } - sshAvailable := isSSHAvailable(ctx) - if !sshAvailable { + if !isSSHAvailable(ctx) { return xerrors.New("SSH is disabled or not available for your Coder Enterprise deployment.") } - user, err := client.Me(cmd.Context()) + user, err := client.Me(ctx) if err != nil { return xerrors.Errorf("fetch username: %w", err) } - envs, err := getEnvs(cmd.Context(), client, coder.Me) + envs, err := getEnvs(ctx, client, coder.Me) if err != nil { return err } diff --git a/internal/cmd/envs.go b/internal/cmd/envs.go index 1ddf9309..8805e208 100644 --- a/internal/cmd/envs.go +++ b/internal/cmd/envs.go @@ -46,11 +46,12 @@ func lsEnvsCommand(user *string) *cobra.Command { Short: "list all environments owned by the active user", Long: "List all Coder environments owned by the active user.", RunE: func(cmd *cobra.Command, args []string) error { - client, err := newClient() + ctx := cmd.Context() + client, err := newClient(ctx) if err != nil { return err } - envs, err := getEnvs(cmd.Context(), client, *user) + envs, err := getEnvs(ctx, client, *user) if err != nil { return err } @@ -101,7 +102,8 @@ coder envs --user charlie@coder.com ls -o json \ | xargs coder envs --user charlie@coder.com stop`, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client, err := newClient() + ctx := cmd.Context() + client, err := newClient(ctx) if err != nil { return xerrors.Errorf("new client: %w", err) } @@ -110,12 +112,12 @@ coder envs --user charlie@coder.com ls -o json \ for _, envName := range args { envName := envName egroup.Go(func() error { - env, err := findEnv(cmd.Context(), client, envName, *user) + env, err := findEnv(ctx, client, envName, *user) if err != nil { return err } - if err = client.StopEnvironment(cmd.Context(), env.ID); err != nil { + if err = client.StopEnvironment(ctx, env.ID); err != nil { return clog.Error(fmt.Sprintf("stop environment %q", env.Name), clog.Causef(err.Error()), clog.BlankLine, clog.Hintf("current environment status is %q", env.LatestStat.ContainerStatus), @@ -152,16 +154,17 @@ coder envs create --image 5f443b16-30652892427b955601330fa5 my-env-name # create a new environment using custom resource amounts coder envs create --cpu 4 --disk 100 --memory 8 --image 5f443b16-30652892427b955601330fa5 my-env-name`, RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() if img == "" { return xerrors.New("image unset") } - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } - multiOrgMember, err := isMultiOrgMember(cmd.Context(), client, *user) + multiOrgMember, err := isMultiOrgMember(ctx, client, *user) if err != nil { return err } @@ -170,7 +173,7 @@ coder envs create --cpu 4 --disk 100 --memory 8 --image 5f443b16-30652892427b955 return xerrors.New("org is required for multi-org members") } - importedImg, err := findImg(cmd.Context(), + importedImg, err := findImg(ctx, findImgConf{ client: client, email: *user, @@ -207,14 +210,14 @@ coder envs create --cpu 4 --disk 100 --memory 8 --image 5f443b16-30652892427b955 createReq.DiskGB = importedImg.DefaultDiskGB } - env, err := client.CreateEnvironment(cmd.Context(), importedImg.OrganizationID, *createReq) + env, err := client.CreateEnvironment(ctx, importedImg.OrganizationID, *createReq) if err != nil { return xerrors.Errorf("create environment: %w", err) } if follow { clog.LogSuccess("creating environment...") - if err := trailBuildLogs(cmd.Context(), client, env.ID); err != nil { + if err := trailBuildLogs(ctx, client, env.ID); err != nil { return err } return nil @@ -261,19 +264,20 @@ func editEnvCmd(user *string) *cobra.Command { coder envs edit back-end-env --disk 20`, RunE: func(cmd *cobra.Command, args []string) error { - client, err := newClient() + ctx := cmd.Context() + client, err := newClient(ctx) if err != nil { return err } envName := args[0] - env, err := findEnv(cmd.Context(), client, envName, *user) + env, err := findEnv(ctx, client, envName, *user) if err != nil { return err } - multiOrgMember, err := isMultiOrgMember(cmd.Context(), client, *user) + multiOrgMember, err := isMultiOrgMember(ctx, client, *user) if err != nil { return err } @@ -288,7 +292,7 @@ coder envs edit back-end-env --disk 20`, diskGB, _ = cmd.Flags().GetInt("disk") gpus, _ = cmd.Flags().GetInt("gpus") - req, err := buildUpdateReq(cmd.Context(), + req, err := buildUpdateReq(ctx, updateConf{ cpu: cpuCores, memGB: memGB, @@ -306,13 +310,13 @@ coder envs edit back-end-env --disk 20`, return err } - if err := client.EditEnvironment(cmd.Context(), env.ID, *req); err != nil { + if err := client.EditEnvironment(ctx, env.ID, *req); err != nil { return xerrors.Errorf("failed to apply changes to environment %q: %w", envName, err) } if follow { clog.LogSuccess("applied changes to the environment, rebuilding...") - if err := trailBuildLogs(cmd.Context(), client, env.ID); err != nil { + if err := trailBuildLogs(ctx, client, env.ID); err != nil { return err } return nil @@ -344,7 +348,7 @@ func rmEnvsCmd(user *string) *cobra.Command { Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } @@ -369,7 +373,7 @@ func rmEnvsCmd(user *string) *cobra.Command { if err != nil { return err } - if err = client.DeleteEnvironment(cmd.Context(), env.ID); err != nil { + if err = client.DeleteEnvironment(ctx, env.ID); err != nil { return clog.Error( fmt.Sprintf(`failed to delete environment "%s"`, env.Name), clog.Causef(err.Error()), diff --git a/internal/cmd/rebuild.go b/internal/cmd/rebuild.go index 958af18f..687e132c 100644 --- a/internal/cmd/rebuild.go +++ b/internal/cmd/rebuild.go @@ -28,7 +28,7 @@ func rebuildEnvCommand(user *string) *cobra.Command { coder envs rebuild backend-env --force`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } @@ -144,7 +144,7 @@ func watchBuildLogCommand(user *string) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } diff --git a/internal/cmd/resourcemanager.go b/internal/cmd/resourcemanager.go index 515318fc..1fbc210d 100644 --- a/internal/cmd/resourcemanager.go +++ b/internal/cmd/resourcemanager.go @@ -55,7 +55,7 @@ coder resources top --sort-by memory --show-empty`, func runResourceTop(options *resourceTopOptions) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } diff --git a/internal/cmd/secrets.go b/internal/cmd/secrets.go index baa8ad25..7c8dfdf6 100644 --- a/internal/cmd/secrets.go +++ b/internal/cmd/secrets.go @@ -82,8 +82,9 @@ coder secrets create aws-credentials --from-file ./credentials.json`, name = args[0] value string err error + ctx = cmd.Context() ) - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } @@ -112,11 +113,11 @@ coder secrets create aws-credentials --from-file ./credentials.json`, } } - user, err := client.UserByEmail(cmd.Context(), *userEmail) + user, err := client.UserByEmail(ctx, *userEmail) if err != nil { return xerrors.Errorf("get user %q by email: %w", *userEmail, err) } - err = client.InsertSecret(cmd.Context(), user, coder.InsertSecretReq{ + err = client.InsertSecret(ctx, user, coder.InsertSecretReq{ Name: name, Value: value, Description: description, @@ -138,16 +139,17 @@ coder secrets create aws-credentials --from-file ./credentials.json`, func listSecretsCmd(userEmail *string) func(cmd *cobra.Command, _ []string) error { return func(cmd *cobra.Command, _ []string) error { - client, err := newClient() + ctx := cmd.Context() + client, err := newClient(ctx) if err != nil { return err } - user, err := client.UserByEmail(cmd.Context(), *userEmail) + user, err := client.UserByEmail(ctx, *userEmail) if err != nil { return xerrors.Errorf("get user %q by email: %w", *userEmail, err) } - secrets, err := client.Secrets(cmd.Context(), user.ID) + secrets, err := client.Secrets(ctx, user.ID) if err != nil { return xerrors.Errorf("get secrets: %w", err) } @@ -173,17 +175,18 @@ func viewSecretCmd(userEmail *string) func(cmd *cobra.Command, args []string) er return func(cmd *cobra.Command, args []string) error { var ( name = args[0] + ctx = cmd.Context() ) - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } - user, err := client.UserByEmail(cmd.Context(), *userEmail) + user, err := client.UserByEmail(ctx, *userEmail) if err != nil { return xerrors.Errorf("get user %q by email: %w", *userEmail, err) } - secret, err := client.SecretWithValueByName(cmd.Context(), name, user.ID) + secret, err := client.SecretWithValueByName(ctx, name, user.ID) if err != nil { return xerrors.Errorf("get secret by name: %w", err) } @@ -198,18 +201,19 @@ func viewSecretCmd(userEmail *string) func(cmd *cobra.Command, args []string) er func removeSecretsCmd(userEmail *string) func(c *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - client, err := newClient() + ctx := cmd.Context() + client, err := newClient(ctx) if err != nil { return err } - user, err := client.UserByEmail(cmd.Context(), *userEmail) + user, err := client.UserByEmail(ctx, *userEmail) if err != nil { return xerrors.Errorf("get user %q by email: %w", *userEmail, err) } errorSeen := false for _, n := range args { - err := client.DeleteSecretByName(cmd.Context(), n, user.ID) + err := client.DeleteSecretByName(ctx, n, user.ID) if err != nil { clog.Log(clog.Error( fmt.Sprintf("failed to delete secret %q: %v", n, err), diff --git a/internal/cmd/shell.go b/internal/cmd/shell.go index 9d4b9b10..7a79a2b7 100644 --- a/internal/cmd/shell.go +++ b/internal/cmd/shell.go @@ -24,7 +24,7 @@ import ( func getEnvsForCompletion(user string) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { ctx := cmd.Context() - client, err := newClient() + client, err := newClient(ctx) if err != nil { return nil, cobra.ShellCompDirectiveDefault } @@ -98,7 +98,7 @@ func sendResizeEvents(ctx context.Context, termFD uintptr, process wsep.Process) } func runCommand(ctx context.Context, envName, command string, args []string) error { - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } diff --git a/internal/cmd/sync.go b/internal/cmd/sync.go index 7247d883..9f162b1b 100644 --- a/internal/cmd/sync.go +++ b/internal/cmd/sync.go @@ -52,7 +52,7 @@ func makeRunSync(init *bool) func(cmd *cobra.Command, args []string) error { remote = args[1] ) - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } @@ -66,7 +66,7 @@ func makeRunSync(init *bool) func(cmd *cobra.Command, args []string) error { remoteDir = remoteTokens[1] ) - env, err := findEnv(cmd.Context(), client, envName, coder.Me) + env, err := findEnv(ctx, client, envName, coder.Me) if err != nil { return err } diff --git a/internal/cmd/urls.go b/internal/cmd/urls.go index 1faa1328..fa4ebd0f 100644 --- a/internal/cmd/urls.go +++ b/internal/cmd/urls.go @@ -91,8 +91,9 @@ func accessLevelIsValid(level string) bool { // specified environment and outputs info to stdout. func listDevURLsCmd(outputFmt *string) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() envName := args[0] - devURLs, err := urlList(cmd.Context(), envName) + devURLs, err := urlList(ctx, envName) if err != nil { return err } @@ -135,6 +136,7 @@ func createDevURLCmd() *cobra.Command { var ( envName = args[0] port = args[1] + ctx = cmd.Context() ) portNum, err := validatePort(port) @@ -150,17 +152,17 @@ func createDevURLCmd() *cobra.Command { if urlname != "" && !devURLNameValidRx.MatchString(urlname) { return xerrors.New("update devurl: name must be < 64 chars in length, begin with a letter and only contain letters or digits.") } - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } - env, err := findEnv(cmd.Context(), client, envName, coder.Me) + env, err := findEnv(ctx, client, envName, coder.Me) if err != nil { return err } - urls, err := urlList(cmd.Context(), envName) + urls, err := urlList(ctx, envName) if err != nil { return err } @@ -168,13 +170,13 @@ func createDevURLCmd() *cobra.Command { urlID, found := devURLID(portNum, urls) if found { clog.LogInfo(fmt.Sprintf("updating devurl for port %v", port)) - err := client.UpdateDevURL(cmd.Context(), env.ID, urlID, portNum, urlname, access) + err := client.UpdateDevURL(ctx, env.ID, urlID, portNum, urlname, access) if err != nil { return xerrors.Errorf("update DevURL: %w", err) } } else { clog.LogInfo(fmt.Sprintf("Adding devurl for port %v", port)) - err := client.InsertDevURL(cmd.Context(), env.ID, portNum, urlname, access) + err := client.InsertDevURL(ctx, env.ID, portNum, urlname, access) if err != nil { return xerrors.Errorf("insert DevURL: %w", err) } @@ -212,6 +214,7 @@ func removeDevURL(cmd *cobra.Command, args []string) error { var ( envName = args[0] port = args[1] + ctx = cmd.Context() ) portNum, err := validatePort(port) @@ -219,16 +222,16 @@ func removeDevURL(cmd *cobra.Command, args []string) error { return xerrors.Errorf("validate port: %w", err) } - client, err := newClient() + client, err := newClient(ctx) if err != nil { return err } - env, err := findEnv(cmd.Context(), client, envName, coder.Me) + env, err := findEnv(ctx, client, envName, coder.Me) if err != nil { return err } - urls, err := urlList(cmd.Context(), envName) + urls, err := urlList(ctx, envName) if err != nil { return err } @@ -240,7 +243,7 @@ func removeDevURL(cmd *cobra.Command, args []string) error { return xerrors.Errorf("No devurl found for port %v", port) } - if err := client.DelDevURL(cmd.Context(), env.ID, urlID); err != nil { + if err := client.DelDevURL(ctx, env.ID, urlID); err != nil { return xerrors.Errorf("delete DevURL: %w", err) } return nil @@ -248,7 +251,7 @@ func removeDevURL(cmd *cobra.Command, args []string) error { // urlList returns the list of active devURLs from the cemanager. func urlList(ctx context.Context, envName string) ([]DevURL, error) { - client, err := newClient() + client, err := newClient(ctx) if err != nil { return nil, err } diff --git a/internal/cmd/users.go b/internal/cmd/users.go index 15dfbf78..87f40fa4 100644 --- a/internal/cmd/users.go +++ b/internal/cmd/users.go @@ -32,12 +32,13 @@ coder users ls -o json | jq .[] | jq -r .email`, func listUsers(outputFmt *string) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - client, err := newClient() + ctx := cmd.Context() + client, err := newClient(ctx) if err != nil { return err } - users, err := client.Users(cmd.Context()) + users, err := client.Users(ctx) if err != nil { return xerrors.Errorf("get users: %w", err) }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: