Skip to content

Commit 0d8093f

Browse files
author
Katie Horne
committed
Merge branch 'main' into vs-code
2 parents 309f25d + eab5c15 commit 0d8093f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1682
-1024
lines changed

.github/workflows/coder.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ jobs:
209209
run: gotestsum --junitfile="gotests.xml" --packages="./..." --
210210
-covermode=atomic -coverprofile="gotests.coverage"
211211
-coverpkg=./...,github.com/coder/coder/codersdk
212-
-timeout=3m -count=$GOCOUNT -short -failfast
212+
-timeout=5m -count=$GOCOUNT -short -failfast
213213

214214
- name: Upload DataDog Trace
215215
if: always() && github.actor != 'dependabot[bot]' && !github.event.pull_request.head.repo.fork
@@ -316,7 +316,7 @@ jobs:
316316
deploy:
317317
name: "deploy"
318318
runs-on: ubuntu-latest
319-
timeout-minutes: 20
319+
timeout-minutes: 30
320320
if: github.ref == 'refs/heads/main' && !github.event.pull_request.head.repo.fork
321321
permissions:
322322
contents: read

.goreleaser.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ nfpms:
9393
type: "config|noreplace"
9494
- src: coder.service
9595
dst: /usr/lib/systemd/system/coder.service
96+
scripts:
97+
preinstall: preinstall.sh
9698

9799
# Image templates are empty on snapshots to avoid lengthy builds for development.
98100
dockers:

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ test: test-clean
115115
.PHONY: test-postgres
116116
test-postgres: test-clean
117117
DB=ci gotestsum --junitfile="gotests.xml" --packages="./..." -- \
118-
-covermode=atomic -coverprofile="gotests.coverage" -timeout=5m \
118+
-covermode=atomic -coverprofile="gotests.coverage" -timeout=10m \
119119
-coverpkg=./...,github.com/coder/coder/codersdk \
120120
-count=1 -parallel=1 -race -failfast
121121

README.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ To install, run:
4747
curl -fsSL https://coder.com/install.sh | sh
4848
```
4949

50-
Once installed, you can run a temporary deployment in dev mode (all data is in-memory and destroyed on exit):
50+
Once installed, you can start a production deployment with a single command:
5151

5252
```sh
53-
coder server --dev
53+
# Automatically sets up an external access URL on *.try.coder.app
54+
coder server --tunnel
55+
56+
# Requires a PostgreSQL instance and external access URL
57+
coder server --postgres-url <url> --access-url <url>
5458
```
5559

5660
Use `coder --help` to get a complete list of flags and environment variables. Use our [quickstart guide](https://coder.com/docs/coder-oss/latest/quickstart) for a full walkthrough.
@@ -61,7 +65,7 @@ Visit our docs [here](https://coder.com/docs/coder-oss).
6165

6266
## Comparison
6367

64-
Please file [an issue](https://github.com/coder/coder/issues/new) if any information is out of date. Also refer to: [What Coder is not](https://coder.com/docs/coder-oss/latest/about#what-coder-is-not).
68+
Please file [an issue](https://github.com/coder/coder/issues/new) if any information is out of date. Also refer to: [What Coder is not](https://coder.com/docs/coder-oss/latest/index#what-coder-is-not).
6569

6670
| Tool | Type | Delivery Model | Cost | Environments |
6771
| :---------------------------------------------------------- | :------- | :----------------- | :---------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |

cli/cliui/prompt_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions, cmdOpt func(cmd *cob
165165
}
166166

167167
func TestPasswordTerminalState(t *testing.T) {
168+
// TODO: fix this test so that it runs reliably
169+
t.Skip()
170+
168171
if os.Getenv("TEST_SUBPROCESS") == "1" {
169172
passwordHelper()
170173
return
@@ -205,6 +208,7 @@ func TestPasswordTerminalState(t *testing.T) {
205208
require.True(t, echo, "echo is off after reading password")
206209
}
207210

211+
// nolint:unused
208212
func passwordHelper() {
209213
cmd := &cobra.Command{
210214
Run: func(cmd *cobra.Command, args []string) {

cli/config/file.go

+12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ func (r Root) DotfilesURL() File {
2525
return File(filepath.Join(string(r), "dotfilesurl"))
2626
}
2727

28+
func (r Root) PostgresPath() string {
29+
return filepath.Join(string(r), "postgres")
30+
}
31+
32+
func (r Root) PostgresPassword() File {
33+
return File(filepath.Join(r.PostgresPath(), "password"))
34+
}
35+
36+
func (r Root) PostgresPort() File {
37+
return File(filepath.Join(r.PostgresPath(), "port"))
38+
}
39+
2840
// File provides convenience methods for interacting with *os.File.
2941
type File string
3042

cli/login.go

+76-60
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/spf13/cobra"
1818
"golang.org/x/xerrors"
1919

20+
"github.com/coder/coder/cli/cliflag"
2021
"github.com/coder/coder/cli/cliui"
2122
"github.com/coder/coder/codersdk"
2223
)
@@ -37,7 +38,12 @@ func init() {
3738
}
3839

3940
func login() *cobra.Command {
40-
return &cobra.Command{
41+
var (
42+
email string
43+
username string
44+
password string
45+
)
46+
cmd := &cobra.Command{
4147
Use: "login <url>",
4248
Short: "Authenticate with a Coder deployment",
4349
Args: cobra.ExactArgs(1),
@@ -66,71 +72,77 @@ func login() *cobra.Command {
6672
return xerrors.Errorf("has initial user: %w", err)
6773
}
6874
if !hasInitialUser {
69-
if !isTTY(cmd) {
70-
return xerrors.New("the initial user cannot be created in non-interactive mode. use the API")
71-
}
7275
_, _ = fmt.Fprintf(cmd.OutOrStdout(), caret+"Your Coder deployment hasn't been set up!\n")
7376

74-
_, err := cliui.Prompt(cmd, cliui.PromptOptions{
75-
Text: "Would you like to create the first user?",
76-
Default: "yes",
77-
IsConfirm: true,
78-
})
79-
if errors.Is(err, cliui.Canceled) {
80-
return nil
81-
}
82-
if err != nil {
83-
return err
84-
}
85-
currentUser, err := user.Current()
86-
if err != nil {
87-
return xerrors.Errorf("get current user: %w", err)
88-
}
89-
username, err := cliui.Prompt(cmd, cliui.PromptOptions{
90-
Text: "What " + cliui.Styles.Field.Render("username") + " would you like?",
91-
Default: currentUser.Username,
92-
})
93-
if errors.Is(err, cliui.Canceled) {
94-
return nil
95-
}
96-
if err != nil {
97-
return xerrors.Errorf("pick username prompt: %w", err)
98-
}
99-
100-
email, err := cliui.Prompt(cmd, cliui.PromptOptions{
101-
Text: "What's your " + cliui.Styles.Field.Render("email") + "?",
102-
Validate: func(s string) error {
103-
err := validator.New().Var(s, "email")
104-
if err != nil {
105-
return xerrors.New("That's not a valid email address!")
106-
}
77+
if username == "" {
78+
if !isTTY(cmd) {
79+
return xerrors.New("the initial user cannot be created in non-interactive mode. use the API")
80+
}
81+
_, err := cliui.Prompt(cmd, cliui.PromptOptions{
82+
Text: "Would you like to create the first user?",
83+
Default: "yes",
84+
IsConfirm: true,
85+
})
86+
if errors.Is(err, cliui.Canceled) {
87+
return nil
88+
}
89+
if err != nil {
10790
return err
108-
},
109-
})
110-
if err != nil {
111-
return xerrors.Errorf("specify email prompt: %w", err)
91+
}
92+
currentUser, err := user.Current()
93+
if err != nil {
94+
return xerrors.Errorf("get current user: %w", err)
95+
}
96+
username, err = cliui.Prompt(cmd, cliui.PromptOptions{
97+
Text: "What " + cliui.Styles.Field.Render("username") + " would you like?",
98+
Default: currentUser.Username,
99+
})
100+
if errors.Is(err, cliui.Canceled) {
101+
return nil
102+
}
103+
if err != nil {
104+
return xerrors.Errorf("pick username prompt: %w", err)
105+
}
112106
}
113107

114-
password, err := cliui.Prompt(cmd, cliui.PromptOptions{
115-
Text: "Enter a " + cliui.Styles.Field.Render("password") + ":",
116-
Secret: true,
117-
Validate: cliui.ValidateNotEmpty,
118-
})
119-
if err != nil {
120-
return xerrors.Errorf("specify password prompt: %w", err)
108+
if email == "" {
109+
email, err = cliui.Prompt(cmd, cliui.PromptOptions{
110+
Text: "What's your " + cliui.Styles.Field.Render("email") + "?",
111+
Validate: func(s string) error {
112+
err := validator.New().Var(s, "email")
113+
if err != nil {
114+
return xerrors.New("That's not a valid email address!")
115+
}
116+
return err
117+
},
118+
})
119+
if err != nil {
120+
return xerrors.Errorf("specify email prompt: %w", err)
121+
}
121122
}
122-
_, err = cliui.Prompt(cmd, cliui.PromptOptions{
123-
Text: "Confirm " + cliui.Styles.Field.Render("password") + ":",
124-
Secret: true,
125-
Validate: func(s string) error {
126-
if s != password {
127-
return xerrors.Errorf("Passwords do not match")
128-
}
129-
return nil
130-
},
131-
})
132-
if err != nil {
133-
return xerrors.Errorf("confirm password prompt: %w", err)
123+
124+
if password == "" {
125+
password, err = cliui.Prompt(cmd, cliui.PromptOptions{
126+
Text: "Enter a " + cliui.Styles.Field.Render("password") + ":",
127+
Secret: true,
128+
Validate: cliui.ValidateNotEmpty,
129+
})
130+
if err != nil {
131+
return xerrors.Errorf("specify password prompt: %w", err)
132+
}
133+
_, err = cliui.Prompt(cmd, cliui.PromptOptions{
134+
Text: "Confirm " + cliui.Styles.Field.Render("password") + ":",
135+
Secret: true,
136+
Validate: func(s string) error {
137+
if s != password {
138+
return xerrors.Errorf("Passwords do not match")
139+
}
140+
return nil
141+
},
142+
})
143+
if err != nil {
144+
return xerrors.Errorf("confirm password prompt: %w", err)
145+
}
134146
}
135147

136148
_, err = client.CreateFirstUser(cmd.Context(), codersdk.CreateFirstUserRequest{
@@ -219,6 +231,10 @@ func login() *cobra.Command {
219231
return nil
220232
},
221233
}
234+
cliflag.StringVarP(cmd.Flags(), &email, "email", "e", "CODER_EMAIL", "", "Specifies an email address to authenticate with.")
235+
cliflag.StringVarP(cmd.Flags(), &username, "username", "u", "CODER_USERNAME", "", "Specifies a username to authenticate with.")
236+
cliflag.StringVarP(cmd.Flags(), &password, "password", "p", "CODER_PASSWORD", "", "Specifies a password to authenticate with.")
237+
return cmd
222238
}
223239

224240
// isWSL determines if coder-cli is running within Windows Subsystem for Linux

cli/login_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ func TestLogin(t *testing.T) {
5656
<-doneChan
5757
})
5858

59+
t.Run("InitialUserFlags", func(t *testing.T) {
60+
t.Parallel()
61+
client := coderdtest.New(t, nil)
62+
// The --force-tty flag is required on Windows, because the `isatty` library does not
63+
// accurately detect Windows ptys when they are not attached to a process:
64+
// https://github.com/mattn/go-isatty/issues/59
65+
doneChan := make(chan struct{})
66+
root, _ := clitest.New(t, "login", client.URL.String(), "--username", "testuser", "--email", "user@coder.com", "--password", "password")
67+
pty := ptytest.New(t)
68+
root.SetIn(pty.Input())
69+
root.SetOut(pty.Output())
70+
go func() {
71+
defer close(doneChan)
72+
err := root.Execute()
73+
assert.NoError(t, err)
74+
}()
75+
pty.ExpectMatch("Welcome to Coder")
76+
<-doneChan
77+
})
78+
5979
t.Run("InitialUserTTYConfirmPasswordFailAndReprompt", func(t *testing.T) {
6080
t.Parallel()
6181
ctx, cancel := context.WithCancel(context.Background())

cli/parameters.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package cli
2+
3+
import (
4+
"github.com/jedib0t/go-pretty/v6/table"
5+
"github.com/spf13/cobra"
6+
7+
"github.com/coder/coder/cli/cliui"
8+
"github.com/coder/coder/codersdk"
9+
)
10+
11+
func parameters() *cobra.Command {
12+
cmd := &cobra.Command{
13+
Short: "List parameters for a given scope",
14+
Example: "coder parameters list workspace my-workspace",
15+
Use: "parameters",
16+
// Currently hidden as this shows parameter values, not parameter
17+
// schemes. Until we have a good way to distinguish the two, it's better
18+
// not to add confusion or lock ourselves into a certain api.
19+
// This cmd is still valuable debugging tool for devs to avoid
20+
// constructing curl requests.
21+
Hidden: true,
22+
Aliases: []string{"params"},
23+
}
24+
cmd.AddCommand(
25+
parameterList(),
26+
)
27+
return cmd
28+
}
29+
30+
// displayParameters will return a table displaying all parameters passed in.
31+
// filterColumns must be a subset of the parameter fields and will determine which
32+
// columns to display
33+
func displayParameters(filterColumns []string, params ...codersdk.Parameter) string {
34+
tableWriter := cliui.Table()
35+
header := table.Row{"id", "scope", "scope id", "name", "source scheme", "destination scheme", "created at", "updated at"}
36+
tableWriter.AppendHeader(header)
37+
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header, filterColumns))
38+
tableWriter.SortBy([]table.SortBy{{
39+
Name: "name",
40+
}})
41+
for _, param := range params {
42+
tableWriter.AppendRow(table.Row{
43+
param.ID.String(),
44+
param.Scope,
45+
param.ScopeID.String(),
46+
param.Name,
47+
param.SourceScheme,
48+
param.DestinationScheme,
49+
param.CreatedAt,
50+
param.UpdatedAt,
51+
})
52+
}
53+
return tableWriter.Render()
54+
}

0 commit comments

Comments
 (0)