test: add golden files to enterprise cli (#7924)

* test: Add golden files to enterprise cli
This commit is contained in:
Steven Masley 2023-06-09 11:35:20 -05:00 committed by GitHub
parent 4f9d3155c9
commit 065206345e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 956 additions and 214 deletions

View File

@ -525,13 +525,17 @@ coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen $(FIND_EXCLUSIONS)
./scripts/apidocgen/generate.sh
yarn run --cwd=site format:write:only ../docs/api ../docs/manifest.json ../coderd/apidoc/swagger.json
update-golden-files: cli/testdata/.gen-golden helm/tests/testdata/.gen-golden scripts/ci-report/testdata/.gen-golden
update-golden-files: cli/testdata/.gen-golden helm/tests/testdata/.gen-golden scripts/ci-report/testdata/.gen-golden enterprise/cli/testdata/.gen-golden
.PHONY: update-golden-files
cli/testdata/.gen-golden: $(wildcard cli/testdata/*.golden) $(wildcard cli/*.tpl) $(GO_SRC_FILES)
go test ./cli -run="Test(CommandHelp|ServerYAML)" -update
touch "$@"
enterprise/cli/testdata/.gen-golden: $(wildcard enterprise/cli/testdata/*.golden) $(wildcard cli/*.tpl) $(GO_SRC_FILES)
go test ./enterprise/cli -run="TestEnterpriseCommandHelp" -update
touch "$@"
helm/tests/testdata/.gen-golden: $(wildcard helm/tests/testdata/*.yaml) $(wildcard helm/tests/testdata/*.golden) $(GO_SRC_FILES)
go test ./helm/tests -run=TestUpdateGoldenFiles -update
touch "$@"

222
cli/clitest/golden.go Normal file
View File

@ -0,0 +1,222 @@
package clitest
import (
"bytes"
"context"
"flag"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
"github.com/stretchr/testify/require"
"github.com/coder/coder/cli/clibase"
"github.com/coder/coder/cli/config"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/database/dbtestutil"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/testutil"
)
// UpdateGoldenFiles indicates golden files should be updated.
// To update the golden files:
// make update-golden-files
var UpdateGoldenFiles = flag.Bool("update", false, "update .golden files")
var timestampRegex = regexp.MustCompile(`(?i)\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(.\d+)?Z`)
type CommandHelpCase struct {
Name string
Cmd []string
}
func DefaultCases() []CommandHelpCase {
return []CommandHelpCase{
{
Name: "coder --help",
Cmd: []string{"--help"},
},
{
Name: "coder server --help",
Cmd: []string{"server", "--help"},
},
}
}
// TestCommandHelp will test the help output of the given commands
// using golden files.
//
//nolint:tparallel,paralleltest
func TestCommandHelp(t *testing.T, getRoot func(t *testing.T) *clibase.Cmd, cases []CommandHelpCase) {
ogColorProfile := lipgloss.ColorProfile()
// ANSI256 escape codes are far easier for humans to parse in a diff,
// but TrueColor is probably more popular with modern terminals.
lipgloss.SetColorProfile(termenv.ANSI)
t.Cleanup(func() {
lipgloss.SetColorProfile(ogColorProfile)
})
rootClient, replacements := prepareTestData(t)
root := getRoot(t)
ExtractCommandPathsLoop:
for _, cp := range extractVisibleCommandPaths(nil, root.Children) {
name := fmt.Sprintf("coder %s --help", strings.Join(cp, " "))
cmd := append(cp, "--help")
for _, tt := range cases {
if tt.Name == name {
continue ExtractCommandPathsLoop
}
}
cases = append(cases, CommandHelpCase{Name: name, Cmd: cmd})
}
for _, tt := range cases {
tt := tt
t.Run(tt.Name, func(t *testing.T) {
t.Parallel()
ctx := testutil.Context(t, testutil.WaitLong)
var outBuf bytes.Buffer
caseCmd := getRoot(t)
inv, cfg := NewWithCommand(t, caseCmd, tt.Cmd...)
inv.Stderr = &outBuf
inv.Stdout = &outBuf
inv.Environ.Set("CODER_URL", rootClient.URL.String())
inv.Environ.Set("CODER_SESSION_TOKEN", rootClient.SessionToken())
inv.Environ.Set("CODER_CACHE_DIRECTORY", "~/.cache")
SetupConfig(t, rootClient, cfg)
StartWithWaiter(t, inv.WithContext(ctx)).RequireSuccess()
actual := outBuf.Bytes()
if len(actual) == 0 {
t.Fatal("no output")
}
for k, v := range replacements {
actual = bytes.ReplaceAll(actual, []byte(k), []byte(v))
}
actual = NormalizeGoldenFile(t, actual)
goldenPath := filepath.Join("testdata", strings.Replace(tt.Name, " ", "_", -1)+".golden")
if *UpdateGoldenFiles {
t.Logf("update golden file for: %q: %s", tt.Name, goldenPath)
err := os.WriteFile(goldenPath, actual, 0o600)
require.NoError(t, err, "update golden file")
}
expected, err := os.ReadFile(goldenPath)
require.NoError(t, err, "read golden file, run \"make update-golden-files\" and commit the changes")
expected = NormalizeGoldenFile(t, expected)
require.Equal(
t, string(expected), string(actual),
"golden file mismatch: %s, run \"make update-golden-files\", verify and commit the changes",
goldenPath,
)
})
}
}
// NormalizeGoldenFile replaces any strings that are system or timing dependent
// with a placeholder so that the golden files can be compared with a simple
// equality check.
func NormalizeGoldenFile(t *testing.T, byt []byte) []byte {
// Replace any timestamps with a placeholder.
byt = timestampRegex.ReplaceAll(byt, []byte("[timestamp]"))
homeDir, err := os.UserHomeDir()
require.NoError(t, err)
configDir := config.DefaultDir()
byt = bytes.ReplaceAll(byt, []byte(configDir), []byte("~/.config/coderv2"))
byt = bytes.ReplaceAll(byt, []byte(codersdk.DefaultCacheDir()), []byte("[cache dir]"))
// The home directory changes depending on the test environment.
byt = bytes.ReplaceAll(byt, []byte(homeDir), []byte("~"))
for _, r := range []struct {
old string
new string
}{
{"\r\n", "\n"},
{`~\.cache\coder`, "~/.cache/coder"},
{`C:\Users\RUNNER~1\AppData\Local\Temp`, "/tmp"},
{os.TempDir(), "/tmp"},
} {
byt = bytes.ReplaceAll(byt, []byte(r.old), []byte(r.new))
}
return byt
}
func extractVisibleCommandPaths(cmdPath []string, cmds []*clibase.Cmd) [][]string {
var cmdPaths [][]string
for _, c := range cmds {
if c.Hidden {
continue
}
cmdPath := append(cmdPath, c.Name())
cmdPaths = append(cmdPaths, cmdPath)
cmdPaths = append(cmdPaths, extractVisibleCommandPaths(cmdPath, c.Children)...)
}
return cmdPaths
}
func prepareTestData(t *testing.T) (*codersdk.Client, map[string]string) {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
db, pubsub := dbtestutil.NewDB(t)
rootClient := coderdtest.New(t, &coderdtest.Options{
Database: db,
Pubsub: pubsub,
IncludeProvisionerDaemon: true,
})
firstUser := coderdtest.CreateFirstUser(t, rootClient)
secondUser, err := rootClient.CreateUser(ctx, codersdk.CreateUserRequest{
Email: "testuser2@coder.com",
Username: "testuser2",
Password: coderdtest.FirstUserParams.Password,
OrganizationID: firstUser.OrganizationID,
})
require.NoError(t, err)
version := coderdtest.CreateTemplateVersion(t, rootClient, firstUser.OrganizationID, nil)
version = coderdtest.AwaitTemplateVersionJob(t, rootClient, version.ID)
template := coderdtest.CreateTemplate(t, rootClient, firstUser.OrganizationID, version.ID, func(req *codersdk.CreateTemplateRequest) {
req.Name = "test-template"
})
workspace := coderdtest.CreateWorkspace(t, rootClient, firstUser.OrganizationID, template.ID, func(req *codersdk.CreateWorkspaceRequest) {
req.Name = "test-workspace"
})
workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, rootClient, workspace.LatestBuild.ID)
replacements := map[string]string{
firstUser.UserID.String(): "[first user ID]",
secondUser.ID.String(): "[second user ID]",
firstUser.OrganizationID.String(): "[first org ID]",
version.ID.String(): "[version ID]",
version.Name: "[version name]",
version.Job.ID.String(): "[version job ID]",
version.Job.FileID.String(): "[version file ID]",
version.Job.WorkerID.String(): "[version worker ID]",
template.ID.String(): "[template ID]",
workspace.ID.String(): "[workspace ID]",
workspaceBuild.ID.String(): "[workspace build ID]",
workspaceBuild.Job.ID.String(): "[workspace build job ID]",
workspaceBuild.Job.FileID.String(): "[workspace build file ID]",
workspaceBuild.Job.WorkerID.String(): "[workspace build worker ID]",
}
return rootClient, replacements
}

View File

@ -2,235 +2,47 @@ package cli_test
import (
"bytes"
"context"
"flag"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
"github.com/coder/coder/cli/clibase"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/buildinfo"
"github.com/coder/coder/cli"
"github.com/coder/coder/cli/clibase"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/cli/config"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/database/dbtestutil"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/testutil"
)
// To update the golden files:
// make update-golden-files
var updateGoldenFiles = flag.Bool("update", false, "update .golden files")
var timestampRegex = regexp.MustCompile(`(?i)\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(.\d+)?Z`)
// We need to override the global color profile.
//
//nolint:tparallel,paralleltest
func TestCommandHelp(t *testing.T) {
ogColorProfile := lipgloss.ColorProfile()
// ANSI256 escape codes are far easier for humans to parse in a diff,
// but TrueColor is probably more popular with modern terminals.
lipgloss.SetColorProfile(termenv.ANSI)
t.Cleanup(func() {
lipgloss.SetColorProfile(ogColorProfile)
})
rootClient, replacements := prepareTestData(t)
// Test with AGPL commands
getCmds := func(t *testing.T) *clibase.Cmd {
// Must return a fresh instance of cmds each time.
type testCase struct {
name string
cmd []string
t.Helper()
var root cli.RootCmd
rootCmd, err := root.Command(root.AGPL())
require.NoError(t, err)
return rootCmd
}
tests := []testCase{
{
name: "coder --help",
cmd: []string{"--help"},
clitest.TestCommandHelp(t, getCmds, append(clitest.DefaultCases(),
clitest.CommandHelpCase{
Name: "coder agent --help",
Cmd: []string{"agent", "--help"},
},
{
name: "coder server --help",
cmd: []string{"server", "--help"},
clitest.CommandHelpCase{
Name: "coder list --output json",
Cmd: []string{"list", "--output", "json"},
},
{
name: "coder agent --help",
cmd: []string{"agent", "--help"},
clitest.CommandHelpCase{
Name: "coder users list --output json",
Cmd: []string{"users", "list", "--output", "json"},
},
{
name: "coder list --output json",
cmd: []string{"list", "--output", "json"},
},
{
name: "coder users list --output json",
cmd: []string{"users", "list", "--output", "json"},
},
}
rootCmd := new(cli.RootCmd)
root, err := rootCmd.Command(rootCmd.AGPL())
require.NoError(t, err)
ExtractCommandPathsLoop:
for _, cp := range extractVisibleCommandPaths(nil, root.Children) {
name := fmt.Sprintf("coder %s --help", strings.Join(cp, " "))
cmd := append(cp, "--help")
for _, tt := range tests {
if tt.name == name {
continue ExtractCommandPathsLoop
}
}
tests = append(tests, testCase{name: name, cmd: cmd})
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
ctx := testutil.Context(t, testutil.WaitLong)
var outBuf bytes.Buffer
inv, cfg := clitest.New(t, tt.cmd...)
inv.Stderr = &outBuf
inv.Stdout = &outBuf
inv.Environ.Set("CODER_URL", rootClient.URL.String())
inv.Environ.Set("CODER_SESSION_TOKEN", rootClient.SessionToken())
inv.Environ.Set("CODER_CACHE_DIRECTORY", "~/.cache")
clitest.SetupConfig(t, rootClient, cfg)
clitest.StartWithWaiter(t, inv.WithContext(ctx)).RequireSuccess()
actual := outBuf.Bytes()
if len(actual) == 0 {
t.Fatal("no output")
}
for k, v := range replacements {
actual = bytes.ReplaceAll(actual, []byte(k), []byte(v))
}
actual = normalizeGoldenFile(t, actual)
goldenPath := filepath.Join("testdata", strings.Replace(tt.name, " ", "_", -1)+".golden")
if *updateGoldenFiles {
t.Logf("update golden file for: %q: %s", tt.name, goldenPath)
err = os.WriteFile(goldenPath, actual, 0o600)
require.NoError(t, err, "update golden file")
}
expected, err := os.ReadFile(goldenPath)
require.NoError(t, err, "read golden file, run \"make update-golden-files\" and commit the changes")
expected = normalizeGoldenFile(t, expected)
require.Equal(
t, string(expected), string(actual),
"golden file mismatch: %s, run \"make update-golden-files\", verify and commit the changes",
goldenPath,
)
})
}
}
// normalizeGoldenFiles replaces any strings that are system or timing dependent
// with a placeholder so that the golden files can be compared with a simple
// equality check.
func normalizeGoldenFile(t *testing.T, byt []byte) []byte {
// Replace any timestamps with a placeholder.
byt = timestampRegex.ReplaceAll(byt, []byte("[timestamp]"))
homeDir, err := os.UserHomeDir()
require.NoError(t, err)
configDir := config.DefaultDir()
byt = bytes.ReplaceAll(byt, []byte(configDir), []byte("~/.config/coderv2"))
byt = bytes.ReplaceAll(byt, []byte(codersdk.DefaultCacheDir()), []byte("[cache dir]"))
// The home directory changes depending on the test environment.
byt = bytes.ReplaceAll(byt, []byte(homeDir), []byte("~"))
for _, r := range []struct {
old string
new string
}{
{"\r\n", "\n"},
{`~\.cache\coder`, "~/.cache/coder"},
{`C:\Users\RUNNER~1\AppData\Local\Temp`, "/tmp"},
{os.TempDir(), "/tmp"},
} {
byt = bytes.ReplaceAll(byt, []byte(r.old), []byte(r.new))
}
return byt
}
func extractVisibleCommandPaths(cmdPath []string, cmds []*clibase.Cmd) [][]string {
var cmdPaths [][]string
for _, c := range cmds {
if c.Hidden {
continue
}
cmdPath := append(cmdPath, c.Name())
cmdPaths = append(cmdPaths, cmdPath)
cmdPaths = append(cmdPaths, extractVisibleCommandPaths(cmdPath, c.Children)...)
}
return cmdPaths
}
func prepareTestData(t *testing.T) (*codersdk.Client, map[string]string) {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
db, pubsub := dbtestutil.NewDB(t)
rootClient := coderdtest.New(t, &coderdtest.Options{
Database: db,
Pubsub: pubsub,
IncludeProvisionerDaemon: true,
})
firstUser := coderdtest.CreateFirstUser(t, rootClient)
secondUser, err := rootClient.CreateUser(ctx, codersdk.CreateUserRequest{
Email: "testuser2@coder.com",
Username: "testuser2",
Password: coderdtest.FirstUserParams.Password,
OrganizationID: firstUser.OrganizationID,
})
require.NoError(t, err)
version := coderdtest.CreateTemplateVersion(t, rootClient, firstUser.OrganizationID, nil)
version = coderdtest.AwaitTemplateVersionJob(t, rootClient, version.ID)
template := coderdtest.CreateTemplate(t, rootClient, firstUser.OrganizationID, version.ID, func(req *codersdk.CreateTemplateRequest) {
req.Name = "test-template"
})
workspace := coderdtest.CreateWorkspace(t, rootClient, firstUser.OrganizationID, template.ID, func(req *codersdk.CreateWorkspaceRequest) {
req.Name = "test-workspace"
})
workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, rootClient, workspace.LatestBuild.ID)
replacements := map[string]string{
firstUser.UserID.String(): "[first user ID]",
secondUser.ID.String(): "[second user ID]",
firstUser.OrganizationID.String(): "[first org ID]",
version.ID.String(): "[version ID]",
version.Name: "[version name]",
version.Job.ID.String(): "[version job ID]",
version.Job.FileID.String(): "[version file ID]",
version.Job.WorkerID.String(): "[version worker ID]",
template.ID.String(): "[template ID]",
workspace.ID.String(): "[workspace ID]",
workspaceBuild.ID.String(): "[workspace build ID]",
workspaceBuild.Job.ID.String(): "[workspace build job ID]",
workspaceBuild.Job.FileID.String(): "[workspace build file ID]",
workspaceBuild.Job.WorkerID.String(): "[workspace build worker ID]",
}
return rootClient, replacements
))
}
func TestRoot(t *testing.T) {

View File

@ -1607,15 +1607,15 @@ func TestServerYAMLConfig(t *testing.T) {
goldenPath := filepath.Join("testdata", "server-config.yaml.golden")
wantByt = normalizeGoldenFile(t, wantByt)
if *updateGoldenFiles {
wantByt = clitest.NormalizeGoldenFile(t, wantByt)
if *clitest.UpdateGoldenFiles {
require.NoError(t, os.WriteFile(goldenPath, wantByt, 0o600))
return
}
got, err := os.ReadFile(goldenPath)
require.NoError(t, err)
got = normalizeGoldenFile(t, got)
got = clitest.NormalizeGoldenFile(t, got)
require.Equal(t, string(wantByt), string(got))
}

View File

@ -0,0 +1,27 @@
package cli
import (
"testing"
"github.com/coder/coder/cli"
"github.com/stretchr/testify/require"
"github.com/coder/coder/cli/clibase"
"github.com/coder/coder/cli/clitest"
)
//nolint:tparallel,paralleltest
func TestEnterpriseCommandHelp(t *testing.T) {
// Only test the enterprise commands
getCmds := func(t *testing.T) *clibase.Cmd {
// Must return a fresh instance of cmds each time.
t.Helper()
var root cli.RootCmd
rootCmd, err := root.Command((&RootCmd{}).enterpriseOnly())
require.NoError(t, err)
return rootCmd
}
clitest.TestCommandHelp(t, getCmds, clitest.DefaultCases())
}

View File

@ -0,0 +1,50 @@
Usage: coder [global-flags] <subcommand>
Coder v0.0.0-devel — A tool for provisioning self-hosted development environments with Terraform.
- Start a Coder server:
 $ coder server 
- Get started by creating a template from an example:
 $ coder templates init 
Subcommands
features List Enterprise features
groups Manage groups
licenses Add, delete, and list licenses
provisionerd Manage provisioner daemons
server Start a Coder server
Global Options
Global options are applied to all commands. They can be set using environment
variables or flags.
--debug-options bool
Print all options, how they're set, then exit.
--global-config string, $CODER_CONFIG_DIR (default: ~/.config/coderv2)
Path to the global `coder` config directory.
--header string-array, $CODER_HEADER
Additional HTTP headers added to all requests. Provide as key=value.
Can be specified multiple times.
--no-feature-warning bool, $CODER_NO_FEATURE_WARNING
Suppress warnings about unlicensed features.
--no-version-warning bool, $CODER_NO_VERSION_WARNING
Suppress warning when client and server versions do not match.
--token string, $CODER_SESSION_TOKEN
Specify an authentication token. For security reasons setting
CODER_SESSION_TOKEN is preferred.
--url url, $CODER_URL
URL to a deployment.
-v, --verbose bool, $CODER_VERBOSE
Enable verbose output.
---
Report bugs and request features at https://github.com/coder/coder/issues/new

View File

@ -0,0 +1,11 @@
Usage: coder features
List Enterprise features
Aliases: feature
Subcommands
list
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,14 @@
Usage: coder features list [flags]
Aliases: ls
Options
-c, --column string-array (default: Name,Entitlement,Enabled,Limit,Actual)
Specify a column to filter in the table. Available columns are: Name,
Entitlement, Enabled, Limit, Actual.
-o, --output string (default: table)
Output format. Available formats are: table, json.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,14 @@
Usage: coder groups
Manage groups
Aliases: group
Subcommands
create Create a user group
delete Delete a user group
edit Edit a user group
list List user groups
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,10 @@
Usage: coder groups create [flags] <name>
Create a user group
Options
-u, --avatar-url string, $CODER_AVATAR_URL
Set an avatar for a group.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,8 @@
Usage: coder groups delete <name>
Delete a user group
Aliases: rm
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,19 @@
Usage: coder groups edit [flags] <name>
Edit a user group
Options
-a, --add-users string-array
Add users to the group. Accepts emails or IDs.
-u, --avatar-url string
Update the group avatar.
-n, --name string
Update the group name.
-r, --rm-users string-array
Remove users to the group. Accepts emails or IDs.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,14 @@
Usage: coder groups list [flags]
List user groups
Options
-c, --column string-array (default: name,organization id,members,avatar url)
Columns to display in table output. Available columns: name,
organization id, members, avatar url.
-o, --output string (default: table)
Output format. Available formats: table, json.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,13 @@
Usage: coder licenses
Add, delete, and list licenses
Aliases: license
Subcommands
add Add license to Coder deployment
delete Delete license by ID
list List licenses (including expired)
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,16 @@
Usage: coder licenses add [flags] [-f file | -l license]
Add license to Coder deployment
Options
--debug bool
Output license claims for debugging.
-f, --file string
Load license from file.
-l, --license string
License string.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,8 @@
Usage: coder licenses delete <id>
Delete license by ID
Aliases: del, rm
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,8 @@
Usage: coder licenses list
List licenses (including expired)
Aliases: ls
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,9 @@
Usage: coder provisionerd
Manage provisioner daemons
Subcommands
start Run a provisioner daemon
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,19 @@
Usage: coder provisionerd start [flags]
Run a provisioner daemon
Options
-c, --cache-dir string, $CODER_CACHE_DIRECTORY (default: [cache dir])
Directory to store cached data.
--poll-interval duration, $CODER_PROVISIONERD_POLL_INTERVAL (default: 1s)
How often to poll for provisioner jobs.
--poll-jitter duration, $CODER_PROVISIONERD_POLL_JITTER (default: 100ms)
How much to jitter the poll interval by.
-t, --tag string-array, $CODER_PROVISIONERD_TAGS
Tags to filter provisioner jobs by.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,395 @@
Usage: coder server [flags]
Start a Coder server
Subcommands
create-admin-user Create a new admin user with the given username,
email and password and adds it to every
organization.
postgres-builtin-serve Run the built-in PostgreSQL deployment.
postgres-builtin-url Output the connection URL for the built-in
PostgreSQL deployment.
Options
--cache-dir string, $CODER_CACHE_DIRECTORY (default: [cache dir])
The directory to cache temporary files. If unspecified and
$CACHE_DIRECTORY is set, it will be used for compatibility with
systemd.
--disable-owner-workspace-access bool, $CODER_DISABLE_OWNER_WORKSPACE_ACCESS
Remove the permission for the 'owner' role to have workspace execution
on all workspaces. This prevents the 'owner' from ssh, apps, and
terminal access based on the 'owner' role. They still have their user
permissions to access their own workspaces.
--disable-path-apps bool, $CODER_DISABLE_PATH_APPS
Disable workspace apps that are not served from subdomains. Path-based
apps can make requests to the Coder API and pose a security risk when
the workspace serves malicious JavaScript. This is recommended for
security purposes if a --wildcard-access-url is configured.
--swagger-enable bool, $CODER_SWAGGER_ENABLE
Expose the swagger endpoint via /swagger.
--experiments string-array, $CODER_EXPERIMENTS
Enable one or more experiments. These are not ready for production.
Separate multiple experiments with commas, or enter '*' to opt-in to
all available experiments.
--postgres-url string, $CODER_PG_CONNECTION_URL
URL of a PostgreSQL database. If empty, PostgreSQL binaries will be
downloaded from Maven (https://repo1.maven.org/maven2) and store all
data in the config root. Access the built-in database with "coder
server postgres-builtin-url".
--ssh-keygen-algorithm string, $CODER_SSH_KEYGEN_ALGORITHM (default: ed25519)
The algorithm to use for generating ssh keys. Accepted values are
"ed25519", "ecdsa", or "rsa4096".
--update-check bool, $CODER_UPDATE_CHECK (default: false)
Periodically check for new releases of Coder and inform the owner. The
check is performed once per day.
Client Options
These options change the behavior of how clients interact with the Coder.
Clients include the coder cli, vs code extension, and the web UI.
--ssh-config-options string-array, $CODER_SSH_CONFIG_OPTIONS
These SSH config options will override the default SSH config options.
Provide options in "key=value" or "key value" format separated by
commas.Using this incorrectly can break SSH to your deployment, use
cautiously.
--ssh-hostname-prefix string, $CODER_SSH_HOSTNAME_PREFIX (default: coder.)
The SSH deployment prefix is used in the Host of the ssh config.
Config Options
Use a YAML configuration file when your server launch become unwieldy.
-c, --config yaml-config-path, $CODER_CONFIG_PATH
Specify a YAML file to load configuration from.
--write-config bool
Write out the current server config as YAML to stdout.
Introspection / Logging Options
--log-human string, $CODER_LOGGING_HUMAN (default: /dev/stderr)
Output human-readable logs to a given file.
--log-json string, $CODER_LOGGING_JSON
Output JSON logs to a given file.
--log-stackdriver string, $CODER_LOGGING_STACKDRIVER
Output Stackdriver compatible logs to a given file.
-v, --verbose bool, $CODER_VERBOSE
Output debug-level logs.
Introspection / Prometheus Options
--prometheus-address host:port, $CODER_PROMETHEUS_ADDRESS (default: 127.0.0.1:2112)
The bind address to serve prometheus metrics.
--prometheus-collect-agent-stats bool, $CODER_PROMETHEUS_COLLECT_AGENT_STATS
Collect agent stats (may increase charges for metrics storage).
--prometheus-enable bool, $CODER_PROMETHEUS_ENABLE
Serve prometheus metrics on the address defined by prometheus address.
Introspection / Tracing Options
--trace-logs bool, $CODER_TRACE_LOGS
Enables capturing of logs as events in traces. This is useful for
debugging, but may result in a very large amount of events being sent
to the tracing backend which may incur significant costs. If the
verbose flag was supplied, debug-level logs will be included.
--trace bool, $CODER_TRACE_ENABLE
Whether application tracing data is collected. It exports to a backend
configured by environment variables. See:
https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md.
--trace-honeycomb-api-key string, $CODER_TRACE_HONEYCOMB_API_KEY
Enables trace exporting to Honeycomb.io using the provided API Key.
Introspection / pprof Options
--pprof-address host:port, $CODER_PPROF_ADDRESS (default: 127.0.0.1:6060)
The bind address to serve pprof.
--pprof-enable bool, $CODER_PPROF_ENABLE
Serve pprof metrics on the address defined by pprof address.
Networking Options
--access-url url, $CODER_ACCESS_URL
The URL that users will use to access the Coder deployment.
--proxy-trusted-headers string-array, $CODER_PROXY_TRUSTED_HEADERS
Headers to trust for forwarding IP addresses. e.g. Cf-Connecting-Ip,
True-Client-Ip, X-Forwarded-For.
--proxy-trusted-origins string-array, $CODER_PROXY_TRUSTED_ORIGINS
Origin addresses to respect "proxy-trusted-headers". e.g.
192.168.1.0/24.
--redirect-to-access-url bool, $CODER_REDIRECT_TO_ACCESS_URL
Specifies whether to redirect requests that do not match the access
URL host.
--secure-auth-cookie bool, $CODER_SECURE_AUTH_COOKIE
Controls if the 'Secure' property is set on browser session cookies.
--wildcard-access-url url, $CODER_WILDCARD_ACCESS_URL
Specifies the wildcard hostname to use for workspace applications in
the form "*.example.com".
Networking / DERP Options
Most Coder deployments never have to think about DERP because all connections
between workspaces and users are peer-to-peer. However, when Coder cannot
establish a peer to peer connection, Coder uses a distributed relay network
backed by Tailscale and WireGuard.
--derp-config-path string, $CODER_DERP_CONFIG_PATH
Path to read a DERP mapping from. See:
https://tailscale.com/kb/1118/custom-derp-servers/.
--derp-config-url string, $CODER_DERP_CONFIG_URL
URL to fetch a DERP mapping on startup. See:
https://tailscale.com/kb/1118/custom-derp-servers/.
--derp-server-enable bool, $CODER_DERP_SERVER_ENABLE (default: true)
Whether to enable or disable the embedded DERP relay server.
--derp-server-region-code string, $CODER_DERP_SERVER_REGION_CODE (default: coder)
Region code to use for the embedded DERP server.
--derp-server-region-id int, $CODER_DERP_SERVER_REGION_ID (default: 999)
Region ID to use for the embedded DERP server.
--derp-server-region-name string, $CODER_DERP_SERVER_REGION_NAME (default: Coder Embedded Relay)
Region name that for the embedded DERP server.
--derp-server-stun-addresses string-array, $CODER_DERP_SERVER_STUN_ADDRESSES (default: stun.l.google.com:19302)
Addresses for STUN servers to establish P2P connections. Use special
value 'disable' to turn off STUN.
Networking / HTTP Options
--disable-password-auth bool, $CODER_DISABLE_PASSWORD_AUTH
Disable password authentication. This is recommended for security
purposes in production deployments that rely on an identity provider.
Any user with the owner role will be able to sign in with their
password regardless of this setting to avoid potential lock out. If
you are locked out of your account, you can use the `coder server
create-admin` command to create a new admin user directly in the
database.
--disable-session-expiry-refresh bool, $CODER_DISABLE_SESSION_EXPIRY_REFRESH
Disable automatic session expiry bumping due to activity. This forces
all sessions to become invalid after the session expiry duration has
been reached.
--http-address string, $CODER_HTTP_ADDRESS (default: 127.0.0.1:3000)
HTTP bind address of the server. Unset to disable the HTTP endpoint.
--max-token-lifetime duration, $CODER_MAX_TOKEN_LIFETIME (default: 876600h0m0s)
The maximum lifetime duration users can specify when creating an API
token.
--proxy-health-interval duration, $CODER_PROXY_HEALTH_INTERVAL (default: 1m0s)
The interval in which coderd should be checking the status of
workspace proxies.
--session-duration duration, $CODER_SESSION_DURATION (default: 24h0m0s)
The token expiry duration for browser sessions. Sessions may last
longer if they are actively making requests, but this functionality
can be disabled via --disable-session-expiry-refresh.
Networking / TLS Options
Configure TLS / HTTPS for your Coder deployment. If you're running Coder behind
a TLS-terminating reverse proxy or are accessing Coder over a secure link, you
can safely ignore these settings.
--strict-transport-security int, $CODER_STRICT_TRANSPORT_SECURITY (default: 0)
Controls if the 'Strict-Transport-Security' header is set on all
static file responses. This header should only be set if the server is
accessed via HTTPS. This value is the MaxAge in seconds of the header.
--strict-transport-security-options string-array, $CODER_STRICT_TRANSPORT_SECURITY_OPTIONS
Two optional fields can be set in the Strict-Transport-Security
header; 'includeSubDomains' and 'preload'. The
'strict-transport-security' flag must be set to a non-zero value for
these options to be used.
--tls-address host:port, $CODER_TLS_ADDRESS (default: 127.0.0.1:3443)
HTTPS bind address of the server.
--tls-cert-file string-array, $CODER_TLS_CERT_FILE
Path to each certificate for TLS. It requires a PEM-encoded file. To
configure the listener to use a CA certificate, concatenate the
primary certificate and the CA certificate together. The primary
certificate should appear first in the combined file.
--tls-client-auth string, $CODER_TLS_CLIENT_AUTH (default: none)
Policy the server will follow for TLS Client Authentication. Accepted
values are "none", "request", "require-any", "verify-if-given", or
"require-and-verify".
--tls-client-ca-file string, $CODER_TLS_CLIENT_CA_FILE
PEM-encoded Certificate Authority file used for checking the
authenticity of client.
--tls-client-cert-file string, $CODER_TLS_CLIENT_CERT_FILE
Path to certificate for client TLS authentication. It requires a
PEM-encoded file.
--tls-client-key-file string, $CODER_TLS_CLIENT_KEY_FILE
Path to key for client TLS authentication. It requires a PEM-encoded
file.
--tls-enable bool, $CODER_TLS_ENABLE
Whether TLS will be enabled.
--tls-key-file string-array, $CODER_TLS_KEY_FILE
Paths to the private keys for each of the certificates. It requires a
PEM-encoded file.
--tls-min-version string, $CODER_TLS_MIN_VERSION (default: tls12)
Minimum supported version of TLS. Accepted values are "tls10",
"tls11", "tls12" or "tls13".
OAuth2 / GitHub Options
--oauth2-github-allow-everyone bool, $CODER_OAUTH2_GITHUB_ALLOW_EVERYONE
Allow all logins, setting this option means allowed orgs and teams
must be empty.
--oauth2-github-allow-signups bool, $CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS
Whether new users can sign up with GitHub.
--oauth2-github-allowed-orgs string-array, $CODER_OAUTH2_GITHUB_ALLOWED_ORGS
Organizations the user must be a member of to Login with GitHub.
--oauth2-github-allowed-teams string-array, $CODER_OAUTH2_GITHUB_ALLOWED_TEAMS
Teams inside organizations the user must be a member of to Login with
GitHub. Structured as: <organization-name>/<team-slug>.
--oauth2-github-client-id string, $CODER_OAUTH2_GITHUB_CLIENT_ID
Client ID for Login with GitHub.
--oauth2-github-client-secret string, $CODER_OAUTH2_GITHUB_CLIENT_SECRET
Client secret for Login with GitHub.
--oauth2-github-enterprise-base-url string, $CODER_OAUTH2_GITHUB_ENTERPRISE_BASE_URL
Base URL of a GitHub Enterprise deployment to use for Login with
GitHub.
OIDC Options
--oidc-allow-signups bool, $CODER_OIDC_ALLOW_SIGNUPS (default: true)
Whether new users can sign up with OIDC.
--oidc-auth-url-params struct[map[string]string], $CODER_OIDC_AUTH_URL_PARAMS (default: {"access_type": "offline"})
OIDC auth URL parameters to pass to the upstream provider.
--oidc-client-id string, $CODER_OIDC_CLIENT_ID
Client ID to use for Login with OIDC.
--oidc-client-secret string, $CODER_OIDC_CLIENT_SECRET
Client secret to use for Login with OIDC.
--oidc-email-domain string-array, $CODER_OIDC_EMAIL_DOMAIN
Email domains that clients logging in with OIDC must match.
--oidc-email-field string, $CODER_OIDC_EMAIL_FIELD (default: email)
OIDC claim field to use as the email.
--oidc-group-field string, $CODER_OIDC_GROUP_FIELD
This field must be set if using the group sync feature and the scope
name is not 'groups'. Set to the claim to be used for groups.
--oidc-group-mapping struct[map[string]string], $CODER_OIDC_GROUP_MAPPING (default: {})
A map of OIDC group IDs and the group in Coder it should map to. This
is useful for when OIDC providers only return group IDs.
--oidc-ignore-email-verified bool, $CODER_OIDC_IGNORE_EMAIL_VERIFIED
Ignore the email_verified claim from the upstream provider.
--oidc-ignore-userinfo bool, $CODER_OIDC_IGNORE_USERINFO (default: false)
Ignore the userinfo endpoint and only use the ID token for user
information.
--oidc-issuer-url string, $CODER_OIDC_ISSUER_URL
Issuer URL to use for Login with OIDC.
--oidc-scopes string-array, $CODER_OIDC_SCOPES (default: openid,profile,email)
Scopes to grant when authenticating with OIDC.
--oidc-username-field string, $CODER_OIDC_USERNAME_FIELD (default: preferred_username)
OIDC claim field to use as the username.
--oidc-sign-in-text string, $CODER_OIDC_SIGN_IN_TEXT (default: OpenID Connect)
The text to show on the OpenID Connect sign in button.
--oidc-icon-url url, $CODER_OIDC_ICON_URL
URL pointing to the icon to use on the OepnID Connect login button.
Provisioning Options
Tune the behavior of the provisioner, which is responsible for creating,
updating, and deleting workspace resources.
--provisioner-force-cancel-interval duration, $CODER_PROVISIONER_FORCE_CANCEL_INTERVAL (default: 10m0s)
Time to force cancel provisioning tasks that are stuck.
--provisioner-daemon-poll-interval duration, $CODER_PROVISIONER_DAEMON_POLL_INTERVAL (default: 1s)
Time to wait before polling for a new job.
--provisioner-daemon-poll-jitter duration, $CODER_PROVISIONER_DAEMON_POLL_JITTER (default: 100ms)
Random jitter added to the poll interval.
--provisioner-daemons int, $CODER_PROVISIONER_DAEMONS (default: 3)
Number of provisioner daemons to create on start. If builds are stuck
in queued state for a long time, consider increasing this.
Telemetry Options
Telemetry is critical to our ability to improve Coder. We strip all
personalinformation before sending data to our servers. Please only disable
telemetrywhen required by your organization's security policy.
--telemetry bool, $CODER_TELEMETRY_ENABLE (default: false)
Whether telemetry is enabled or not. Coder collects anonymized usage
data to help improve our product.
--telemetry-trace bool, $CODER_TELEMETRY_TRACE (default: false)
Whether Opentelemetry traces are sent to Coder. Coder collects
anonymized application tracing to help improve our product. Disabling
telemetry also disables this option.
⚠ Dangerous Options
--dangerous-allow-path-app-sharing bool, $CODER_DANGEROUS_ALLOW_PATH_APP_SHARING
Allow workspace apps that are not served from subdomains to be shared.
Path-based app sharing is DISABLED by default for security purposes.
Path-based apps can make requests to the Coder API and pose a security
risk when the workspace serves malicious JavaScript. Path-based apps
can be disabled entirely with --disable-path-apps for further
security.
--dangerous-allow-path-app-site-owner-access bool, $CODER_DANGEROUS_ALLOW_PATH_APP_SITE_OWNER_ACCESS
Allow site-owners to access workspace apps from workspaces they do not
own. Owners cannot access path-based apps they do not own by default.
Path-based apps can make requests to the Coder API and pose a security
risk when the workspace serves malicious JavaScript. Path-based apps
can be disabled entirely with --disable-path-apps for further
security.
Enterprise Options
These options are only available in the Enterprise Edition.
--browser-only bool, $CODER_BROWSER_ONLY
Whether Coder only allows connections to workspaces via the browser.
--derp-server-relay-url url, $CODER_DERP_SERVER_RELAY_URL
An HTTP URL that is accessible by other replicas to relay DERP
traffic. Required for high availability.
--scim-auth-header string, $CODER_SCIM_AUTH_HEADER
Enables SCIM and sets the authentication header for the built-in SCIM
server. New users are automatically created with OIDC authentication.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,32 @@
Usage: coder server create-admin-user [flags]
Create a new admin user with the given username, email and password and adds it
to every organization.
Options
--email string, $CODER_EMAIL
The email of the new user. If not specified, you will be prompted via
stdin.
--password string, $CODER_PASSWORD
The password of the new user. If not specified, you will be prompted
via stdin.
--postgres-url string, $CODER_PG_CONNECTION_URL
URL of a PostgreSQL database. If empty, the built-in PostgreSQL
deployment will be used (Coder must not be already running in this
case).
--raw-url bool
Output the raw connection URL instead of a psql command.
--ssh-keygen-algorithm string, $CODER_SSH_KEYGEN_ALGORITHM (default: ed25519)
The algorithm to use for generating ssh keys. Accepted values are
"ed25519", "ecdsa", or "rsa4096".
--username string, $CODER_USERNAME
The username of the new user. If not specified, you will be prompted
via stdin.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,10 @@
Usage: coder server postgres-builtin-serve [flags]
Run the built-in PostgreSQL deployment.
Options
--raw-url bool
Output the raw connection URL instead of a psql command.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,10 @@
Usage: coder server postgres-builtin-url [flags]
Output the connection URL for the built-in PostgreSQL deployment.
Options
--raw-url bool
Output the raw connection URL instead of a psql command.
---
Run `coder --help` for a list of global options.

View File

@ -0,0 +1,17 @@
Usage: coder workspace-proxy
Manage workspace proxies
Aliases: wsproxy
Subcommands
create Create a workspace proxy
delete Delete a workspace proxy
edit Edit a workspace proxy
ls List all workspace proxies
regenerate-token Regenerate a workspace proxy authentication token. This
will invalidate the existing authentication token.
server Start a workspace proxy server
---
Run `coder --help` for a list of global options.