Skip to content

Commit 0b61269

Browse files
committed
Merge branch 'main' into bq/add-latency-to-terminal
2 parents 16f56e4 + 88dc66a commit 0b61269

Some content is hidden

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

51 files changed

+1098
-1546
lines changed

.github/CODEOWNERS

Lines changed: 0 additions & 3 deletions
This file was deleted.

.github/actions/upload-datadog/action.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ runs:
99
steps:
1010
- shell: bash
1111
run: |
12+
owner=${{ github.repository_owner }}
13+
echo "owner: $owner"
14+
if [[ $owner != "coder" ]]; then
15+
echo "Not a pull request from the main repo, skipping..."
16+
exit 0
17+
fi
18+
if [[ -z "${{ inputs.api-key }}" ]]; then
19+
# This can happen for dependabot.
20+
echo "No API key provided, skipping..."
21+
exit 0
22+
fi
1223
npm install -g @datadog/datadog-ci
1324
datadog-ci junit upload --service coder ./gotests.xml \
1425
--tags os:${{runner.os}} --tags runner_name:${{runner.name}}

.github/dependabot.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ updates:
5858
interval: "monthly"
5959
time: "06:00"
6060
timezone: "America/Chicago"
61+
reviewers:
62+
- "coder/ts"
6163
commit-message:
6264
prefix: "chore"
6365
labels: []

.github/workflows/ci.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737

3838
# Check for any typos!
3939
- name: Check for typos
40-
uses: crate-ci/typos@v1.14.11
40+
uses: crate-ci/typos@v1.14.12
4141
with:
4242
config: .github/workflows/typos.toml
4343
- name: Fix the typos
@@ -49,7 +49,7 @@ jobs:
4949
5050
# Check for Go linting errors!
5151
- name: Lint Go
52-
uses: golangci/golangci-lint-action@v3.3.1
52+
uses: golangci/golangci-lint-action@v3.5.0
5353
with:
5454
version: v1.52.2
5555

.github/workflows/nightly-flake.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: nightly-flake
2+
on:
3+
schedule:
4+
# Every day at midnight
5+
- cron: "0 0 * * *"
6+
workflow_dispatch:
7+
# For testing purposes
8+
# push:
9+
# paths:
10+
# - ".github/workflows/nightly-flake.yaml"
11+
jobs:
12+
test-go-race:
13+
# While GitHub's toaster runners are likelier to flake, we want consistency
14+
# between this environment and the regular test environment for DataDog
15+
# statistics and to only show real workflow threats.
16+
runs-on: "buildjet-8vcpu-ubuntu-2204"
17+
# This runner costs 0.016 USD per minute,
18+
# so 0.016 * 240 = 3.84 USD per run.
19+
timeout-minutes: 240
20+
steps:
21+
- uses: actions/checkout@v3
22+
23+
- uses: ./.github/actions/setup-go
24+
25+
- uses: hashicorp/setup-terraform@v2
26+
with:
27+
terraform_version: 1.1.9
28+
terraform_wrapper: false
29+
30+
- name: Run Tests
31+
run: |
32+
# -race is likeliest to catch flaky tests
33+
# due to correctness detection and its performance
34+
# impact.
35+
gotestsum --junitfile="gotests.xml" -- -timeout=240m -count=10 -race ./...
36+
37+
- uses: ./.github/actions/upload-datadog
38+
if: always()
39+
with:
40+
api-key: ${{ secrets.DATADOG_API_KEY }}

cli/agent.go

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -58,58 +58,64 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
5858
ctx, cancel := context.WithCancel(inv.Context())
5959
defer cancel()
6060

61-
ignorePorts := map[int]string{}
61+
var (
62+
ignorePorts = map[int]string{}
63+
isLinux = runtime.GOOS == "linux"
6264

63-
isLinux := runtime.GOOS == "linux"
65+
sinks = []slog.Sink{}
66+
logClosers = []func() error{}
67+
)
68+
defer func() {
69+
for _, closer := range logClosers {
70+
_ = closer()
71+
}
72+
}()
73+
74+
addSinkIfProvided := func(sinkFn func(io.Writer) slog.Sink, loc string) error {
75+
switch loc {
76+
case "":
77+
// Do nothing.
78+
79+
case "/dev/stderr":
80+
sinks = append(sinks, sinkFn(inv.Stderr))
81+
82+
case "/dev/stdout":
83+
sinks = append(sinks, sinkFn(inv.Stdout))
84+
85+
default:
86+
fi, err := os.OpenFile(loc, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
87+
if err != nil {
88+
return xerrors.Errorf("open log file %q: %w", loc, err)
89+
}
90+
sinks = append(sinks, sinkFn(fi))
91+
logClosers = append(logClosers, fi.Close)
92+
}
93+
return nil
94+
}
95+
96+
if err := addSinkIfProvided(sloghuman.Sink, slogHumanPath); err != nil {
97+
return xerrors.Errorf("add human sink: %w", err)
98+
}
99+
if err := addSinkIfProvided(slogjson.Sink, slogJSONPath); err != nil {
100+
return xerrors.Errorf("add json sink: %w", err)
101+
}
102+
if err := addSinkIfProvided(slogstackdriver.Sink, slogStackdriverPath); err != nil {
103+
return xerrors.Errorf("add stackdriver sink: %w", err)
104+
}
64105

65106
// Spawn a reaper so that we don't accumulate a ton
66107
// of zombie processes.
67108
if reaper.IsInitProcess() && !noReap && isLinux {
68109
logWriter := &lumberjack.Logger{
69110
Filename: filepath.Join(logDir, "coder-agent-init.log"),
70111
MaxSize: 5, // MB
112+
// Without this, rotated logs will never be deleted.
113+
MaxBackups: 1,
71114
}
72115
defer logWriter.Close()
73116

74-
sinks := []slog.Sink{sloghuman.Sink(logWriter)}
75-
closers := []func() error{}
76-
addSinkIfProvided := func(sinkFn func(io.Writer) slog.Sink, loc string) error {
77-
switch loc {
78-
case "":
79-
80-
case "/dev/stdout":
81-
sinks = append(sinks, sinkFn(inv.Stdout))
82-
83-
case "/dev/stderr":
84-
sinks = append(sinks, sinkFn(inv.Stderr))
85-
86-
default:
87-
fi, err := os.OpenFile(loc, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
88-
if err != nil {
89-
return xerrors.Errorf("open log file %q: %w", loc, err)
90-
}
91-
closers = append(closers, fi.Close)
92-
sinks = append(sinks, sinkFn(fi))
93-
}
94-
return nil
95-
}
96-
97-
if err := addSinkIfProvided(sloghuman.Sink, slogHumanPath); err != nil {
98-
return xerrors.Errorf("add human sink: %w", err)
99-
}
100-
if err := addSinkIfProvided(slogjson.Sink, slogJSONPath); err != nil {
101-
return xerrors.Errorf("add json sink: %w", err)
102-
}
103-
if err := addSinkIfProvided(slogstackdriver.Sink, slogStackdriverPath); err != nil {
104-
return xerrors.Errorf("add stackdriver sink: %w", err)
105-
}
106-
117+
sinks = append(sinks, sloghuman.Sink(logWriter))
107118
logger := slog.Make(sinks...).Leveled(slog.LevelDebug)
108-
defer func() {
109-
for _, closer := range closers {
110-
_ = closer()
111-
}
112-
}()
113119

114120
logger.Info(ctx, "spawning reaper process")
115121
// Do not start a reaper on the child process. It's important
@@ -146,12 +152,15 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
146152
ljLogger := &lumberjack.Logger{
147153
Filename: filepath.Join(logDir, "coder-agent.log"),
148154
MaxSize: 5, // MB
155+
// Without this, rotated logs will never be deleted.
156+
MaxBackups: 1,
149157
}
150158
defer ljLogger.Close()
151159
logWriter := &closeWriter{w: ljLogger}
152160
defer logWriter.Close()
153161

154-
logger := slog.Make(sloghuman.Sink(inv.Stderr), sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug)
162+
sinks = append(sinks, sloghuman.Sink(logWriter))
163+
logger := slog.Make(sinks...).Leveled(slog.LevelDebug)
155164

156165
version := buildinfo.Version()
157166
logger.Info(ctx, "starting agent",

cli/clitest/clitest.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"github.com/stretchr/testify/assert"
1919
"github.com/stretchr/testify/require"
2020

21+
"cdr.dev/slog"
22+
"cdr.dev/slog/sloggers/slogtest"
2123
"github.com/coder/coder/cli"
2224
"github.com/coder/coder/cli/clibase"
2325
"github.com/coder/coder/cli/config"
@@ -39,16 +41,17 @@ func New(t *testing.T, args ...string) (*clibase.Invocation, config.Root) {
3941

4042
type logWriter struct {
4143
prefix string
42-
t *testing.T
44+
log slog.Logger
4345
}
4446

4547
func (l *logWriter) Write(p []byte) (n int, err error) {
4648
trimmed := strings.TrimSpace(string(p))
4749
if trimmed == "" {
4850
return len(p), nil
4951
}
50-
l.t.Log(
51-
l.prefix + ": " + trimmed,
52+
l.log.Info(
53+
context.Background(),
54+
l.prefix+": "+trimmed,
5255
)
5356
return len(p), nil
5457
}
@@ -57,12 +60,13 @@ func NewWithCommand(
5760
t *testing.T, cmd *clibase.Cmd, args ...string,
5861
) (*clibase.Invocation, config.Root) {
5962
configDir := config.Root(t.TempDir())
63+
logger := slogtest.Make(t, nil)
6064
i := &clibase.Invocation{
6165
Command: cmd,
6266
Args: append([]string{"--global-config", string(configDir)}, args...),
6367
Stdin: io.LimitReader(nil, 0),
64-
Stdout: (&logWriter{prefix: "stdout", t: t}),
65-
Stderr: (&logWriter{prefix: "stderr", t: t}),
68+
Stdout: (&logWriter{prefix: "stdout", log: logger}),
69+
Stderr: (&logWriter{prefix: "stderr", log: logger}),
6670
}
6771
t.Logf("invoking command: %s %s", cmd.Name(), strings.Join(i.Args, " "))
6872

cli/templatepush.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
115115
alwaysPrompt bool
116116
provisionerTags []string
117117
uploadFlags templateUploadFlags
118+
activate bool
118119
)
119120
client := new(codersdk.Client)
120121
cmd := &clibase.Cmd{
@@ -172,11 +173,13 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
172173
return xerrors.Errorf("job failed: %s", job.Job.Status)
173174
}
174175

175-
err = client.UpdateActiveTemplateVersion(inv.Context(), template.ID, codersdk.UpdateActiveTemplateVersion{
176-
ID: job.ID,
177-
})
178-
if err != nil {
179-
return err
176+
if activate {
177+
err = client.UpdateActiveTemplateVersion(inv.Context(), template.ID, codersdk.UpdateActiveTemplateVersion{
178+
ID: job.ID,
179+
})
180+
if err != nil {
181+
return err
182+
}
180183
}
181184

182185
_, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
@@ -226,6 +229,12 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
226229
Description: "Always prompt all parameters. Does not pull parameter values from active template version.",
227230
Value: clibase.BoolOf(&alwaysPrompt),
228231
},
232+
{
233+
Flag: "activate",
234+
Description: "Whether the new template will be marked active.",
235+
Default: "true",
236+
Value: clibase.BoolOf(&activate),
237+
},
229238
cliui.SkipPromptOption(),
230239
uploadFlags.option(),
231240
}

cli/templatepush_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,48 @@ func TestTemplatePush(t *testing.T) {
6969
require.Equal(t, "example", templateVersions[1].Name)
7070
})
7171

72+
t.Run("PushInactiveTemplateVersion", func(t *testing.T) {
73+
t.Parallel()
74+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
75+
user := coderdtest.CreateFirstUser(t, client)
76+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
77+
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
78+
79+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
80+
81+
// Test the cli command.
82+
source := clitest.CreateTemplateVersionSource(t, &echo.Responses{
83+
Parse: echo.ParseComplete,
84+
ProvisionApply: echo.ProvisionComplete,
85+
})
86+
inv, root := clitest.New(t, "templates", "push", template.Name, "--activate=false", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example")
87+
clitest.SetupConfig(t, client, root)
88+
pty := ptytest.New(t).Attach(inv)
89+
w := clitest.StartWithWaiter(t, inv)
90+
91+
matches := []struct {
92+
match string
93+
write string
94+
}{
95+
{match: "Upload", write: "yes"},
96+
}
97+
for _, m := range matches {
98+
pty.ExpectMatch(m.match)
99+
pty.WriteLine(m.write)
100+
}
101+
102+
w.RequireSuccess()
103+
104+
// Assert that the template version didn't change.
105+
templateVersions, err := client.TemplateVersionsByTemplate(context.Background(), codersdk.TemplateVersionsByTemplateRequest{
106+
TemplateID: template.ID,
107+
})
108+
require.NoError(t, err)
109+
assert.Len(t, templateVersions, 2)
110+
assert.Equal(t, template.ActiveVersionID, templateVersions[0].ID)
111+
require.NotEqual(t, "example", templateVersions[0].Name)
112+
})
113+
72114
t.Run("UseWorkingDir", func(t *testing.T) {
73115
t.Parallel()
74116

cli/testdata/coder_templates_push_--help.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ Usage: coder templates push [flags] [template]
33
Push a new template version from the current directory or as specified by flag
44

55
Options
6+
--activate bool (default: true)
7+
Whether the new template will be marked active.
8+
69
--always-prompt bool
710
Always prompt all parameters. Does not pull parameter values from
811
active template version.

0 commit comments

Comments
 (0)