Skip to content

Commit 0811bab

Browse files
committed
Merge branch 'main' into clarify-stop-warning
2 parents cc37010 + 3f04e98 commit 0811bab

Some content is hidden

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

44 files changed

+1053
-391
lines changed

.github/workflows/ci.yaml

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ jobs:
131131
echo "LINT_CACHE_DIR=$dir" >> $GITHUB_ENV
132132
133133
- name: golangci-lint cache
134-
uses: buildjet/cache@v3
134+
uses: buildjet/cache@v4
135135
with:
136136
path: |
137137
${{ env.LINT_CACHE_DIR }}
@@ -141,7 +141,7 @@ jobs:
141141
142142
# Check for any typos
143143
- name: Check for typos
144-
uses: crate-ci/typos@v1.17.2
144+
uses: crate-ci/typos@v1.18.0
145145
with:
146146
config: .github/workflows/typos.toml
147147

@@ -305,7 +305,7 @@ jobs:
305305
api-key: ${{ secrets.DATADOG_API_KEY }}
306306

307307
- name: Check code coverage
308-
uses: codecov/codecov-action@v3
308+
uses: codecov/codecov-action@v4
309309
# This action has a tendency to error out unexpectedly, it has
310310
# the `fail_ci_if_error` option that defaults to `false`, but
311311
# that is no guarantee, see:
@@ -353,7 +353,7 @@ jobs:
353353
api-key: ${{ secrets.DATADOG_API_KEY }}
354354

355355
- name: Check code coverage
356-
uses: codecov/codecov-action@v3
356+
uses: codecov/codecov-action@v4
357357
# This action has a tendency to error out unexpectedly, it has
358358
# the `fail_ci_if_error` option that defaults to `false`, but
359359
# that is no guarantee, see:
@@ -412,7 +412,7 @@ jobs:
412412
working-directory: site
413413

414414
- name: Check code coverage
415-
uses: codecov/codecov-action@v3
415+
uses: codecov/codecov-action@v4
416416
# This action has a tendency to error out unexpectedly, it has
417417
# the `fail_ci_if_error` option that defaults to `false`, but
418418
# that is no guarantee, see:
@@ -862,62 +862,6 @@ jobs:
862862
TOKEN_SYDNEY: ${{ secrets.FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN }}
863863
TOKEN_SAO_PAULO: ${{ secrets.FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN }}
864864

865-
deploy-legacy-proxies:
866-
runs-on: ubuntu-latest
867-
timeout-minutes: 30
868-
needs: build
869-
if: github.ref == 'refs/heads/main' && !github.event.pull_request.head.repo.fork
870-
permissions:
871-
contents: read
872-
id-token: write
873-
steps:
874-
- name: Authenticate to Google Cloud
875-
uses: google-github-actions/auth@v2
876-
with:
877-
workload_identity_provider: projects/573722524737/locations/global/workloadIdentityPools/github/providers/github
878-
service_account: coder-ci@coder-dogfood.iam.gserviceaccount.com
879-
880-
- name: Set up Google Cloud SDK
881-
uses: google-github-actions/setup-gcloud@v2
882-
883-
- name: Download build artifacts
884-
uses: actions/download-artifact@v4
885-
with:
886-
name: coder
887-
path: ./build
888-
889-
- name: Install Release
890-
run: |
891-
set -euo pipefail
892-
893-
regions=(
894-
# gcp-region-id instance-name systemd-service-name
895-
"australia-southeast1-b coder-sydney coder-workspace-proxy"
896-
"europe-west3-c coder-europe coder-workspace-proxy"
897-
"southamerica-east1-b coder-brazil coder-workspace-proxy"
898-
)
899-
900-
deb_pkg=$(find ./build -name "coder_*_linux_amd64.deb" -print -quit)
901-
if [ -z "$deb_pkg" ]; then
902-
echo "deb package $deb_pkg not found"
903-
ls -l ./build
904-
exit 1
905-
fi
906-
907-
gcloud config set project coder-dogfood
908-
for region in "${regions[@]}"; do
909-
echo "::group::$region"
910-
set -- $region
911-
912-
set -x
913-
gcloud config set compute/zone "$1"
914-
gcloud compute scp "$deb_pkg" "${2}:/tmp/coder.deb"
915-
gcloud compute ssh "$2" -- /bin/sh -c "set -eux; sudo dpkg -i --force-confdef /tmp/coder.deb; sudo systemctl daemon-reload; sudo service '$3' restart"
916-
set +x
917-
918-
echo "::endgroup::"
919-
done
920-
921865
# sqlc-vet runs a postgres docker container, runs Coder migrations, and then
922866
# runs sqlc-vet to ensure all queries are valid. This catches any mistakes
923867
# in migrations or sqlc queries that makes a query unable to be prepared.

.github/workflows/contrib.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
pull-requests: write
2727
steps:
2828
- name: auto-approve dependabot
29-
uses: hmarr/auto-approve-action@v3
29+
uses: hmarr/auto-approve-action@v4
3030
if: github.actor == 'dependabot[bot]'
3131

3232
cla:

cli/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,10 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
655655
options.OIDCConfig = oc
656656
}
657657

658+
// We'll read from this channel in the select below that tracks shutdown. If it remains
659+
// nil, that case of the select will just never fire, but it's important not to have a
660+
// "bare" read on this channel.
661+
var pubsubWatchdogTimeout <-chan struct{}
658662
if vals.InMemoryDatabase {
659663
// This is only used for testing.
660664
options.Database = dbmem.New()
@@ -683,6 +687,9 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
683687
options.PrometheusRegistry.MustRegister(ps)
684688
}
685689
defer options.Pubsub.Close()
690+
psWatchdog := pubsub.NewWatchdog(ctx, logger.Named("pswatch"), ps)
691+
pubsubWatchdogTimeout = psWatchdog.Timeout()
692+
defer psWatchdog.Close()
686693
}
687694

688695
if options.DeploymentValues.Prometheus.Enable && options.DeploymentValues.Prometheus.CollectDBMetrics {
@@ -1031,6 +1038,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
10311038
_, _ = io.WriteString(inv.Stdout, cliui.Bold("Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit"))
10321039
case <-tunnelDone:
10331040
exitErr = xerrors.New("dev tunnel closed unexpectedly")
1041+
case <-pubsubWatchdogTimeout:
1042+
exitErr = xerrors.New("pubsub Watchdog timed out")
10341043
case exitErr = <-errCh:
10351044
}
10361045
if exitErr != nil && !xerrors.Is(exitErr, context.Canceled) {

cli/templatepull.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
func (r *RootCmd) templatePull() *clibase.Cmd {
1818
var (
1919
tarMode bool
20+
zipMode bool
2021
versionName string
2122
)
2223

@@ -39,6 +40,10 @@ func (r *RootCmd) templatePull() *clibase.Cmd {
3940
dest = inv.Args[1]
4041
}
4142

43+
if tarMode && zipMode {
44+
return xerrors.Errorf("either tar or zip can be selected")
45+
}
46+
4247
organization, err := CurrentOrganization(inv, client)
4348
if err != nil {
4449
return xerrors.Errorf("get current organization: %w", err)
@@ -98,17 +103,25 @@ func (r *RootCmd) templatePull() *clibase.Cmd {
98103

99104
cliui.Info(inv.Stderr, "Pulling template version "+cliui.Bold(templateVersion.Name)+"...")
100105

106+
var fileFormat string // empty = default, so .tar
107+
if zipMode {
108+
fileFormat = codersdk.FormatZip
109+
}
110+
101111
// Download the tar archive.
102-
raw, ctype, err := client.Download(ctx, templateVersion.Job.FileID)
112+
raw, ctype, err := client.DownloadWithFormat(ctx, templateVersion.Job.FileID, fileFormat)
103113
if err != nil {
104114
return xerrors.Errorf("download template: %w", err)
105115
}
106116

107-
if ctype != codersdk.ContentTypeTar {
117+
if fileFormat == "" && ctype != codersdk.ContentTypeTar {
108118
return xerrors.Errorf("unexpected Content-Type %q, expecting %q", ctype, codersdk.ContentTypeTar)
109119
}
120+
if fileFormat == codersdk.FormatZip && ctype != codersdk.ContentTypeZip {
121+
return xerrors.Errorf("unexpected Content-Type %q, expecting %q", ctype, codersdk.ContentTypeZip)
122+
}
110123

111-
if tarMode {
124+
if tarMode || zipMode {
112125
_, err = inv.Stdout.Write(raw)
113126
return err
114127
}
@@ -152,6 +165,12 @@ func (r *RootCmd) templatePull() *clibase.Cmd {
152165

153166
Value: clibase.BoolOf(&tarMode),
154167
},
168+
{
169+
Description: "Output the template as a zip archive to stdout.",
170+
Flag: "zip",
171+
172+
Value: clibase.BoolOf(&zipMode),
173+
},
155174
{
156175
Description: "The name of the template version to pull. Use 'active' to pull the active version, 'latest' to pull the latest version, or the name of the template version to pull.",
157176
Flag: "version",

cli/templatepull_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli_test
22

33
import (
4+
"archive/tar"
45
"bytes"
56
"context"
67
"crypto/sha256"
@@ -15,6 +16,7 @@ import (
1516
"github.com/stretchr/testify/require"
1617

1718
"github.com/coder/coder/v2/cli/clitest"
19+
"github.com/coder/coder/v2/coderd"
1820
"github.com/coder/coder/v2/coderd/coderdtest"
1921
"github.com/coder/coder/v2/coderd/rbac"
2022
"github.com/coder/coder/v2/provisioner/echo"
@@ -81,6 +83,7 @@ func TestTemplatePull_Stdout(t *testing.T) {
8183
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, updatedVersion.ID)
8284
coderdtest.UpdateActiveTemplateVersion(t, client, template.ID, updatedVersion.ID)
8385

86+
// Verify .tar format
8487
inv, root := clitest.New(t, "templates", "pull", "--tar", template.Name)
8588
clitest.SetupConfig(t, templateAdmin, root)
8689

@@ -89,8 +92,21 @@ func TestTemplatePull_Stdout(t *testing.T) {
8992

9093
err = inv.Run()
9194
require.NoError(t, err)
92-
9395
require.True(t, bytes.Equal(expected, buf.Bytes()), "tar files differ")
96+
97+
// Verify .zip format
98+
tarReader := tar.NewReader(bytes.NewReader(expected))
99+
expectedZip, err := coderd.CreateZipFromTar(tarReader)
100+
require.NoError(t, err)
101+
102+
inv, root = clitest.New(t, "templates", "pull", "--zip", template.Name)
103+
clitest.SetupConfig(t, templateAdmin, root)
104+
buf.Reset()
105+
inv.Stdout = &buf
106+
107+
err = inv.Run()
108+
require.NoError(t, err)
109+
require.True(t, bytes.Equal(expectedZip, buf.Bytes()), "zip files differ")
94110
}
95111

96112
// Stdout tests that 'templates pull' pulls down the non-latest active template

cli/testdata/coder_templates_pull_--help.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@ OPTIONS:
1717
-y, --yes bool
1818
Bypass prompts.
1919

20+
--zip bool
21+
Output the template as a zip archive to stdout.
22+
2023
———
2124
Run `coder --help` for a list of global options.

cli/vscodessh.go

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"cdr.dev/slog/sloggers/sloghuman"
2222

2323
"github.com/coder/coder/v2/cli/clibase"
24+
"github.com/coder/coder/v2/cli/cliui"
2425
"github.com/coder/coder/v2/cli/cliutil"
2526
"github.com/coder/coder/v2/codersdk"
2627
)
@@ -38,6 +39,7 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
3839
logDir string
3940
networkInfoDir string
4041
networkInfoInterval time.Duration
42+
waitEnum string
4143
)
4244
cmd := &clibase.Cmd{
4345
// A SSH config entry is added by the VS Code extension that
@@ -99,35 +101,45 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
99101
}
100102
owner := parts[1]
101103
name := parts[2]
104+
if len(parts) > 3 {
105+
name += "." + parts[3]
106+
}
107+
108+
// Set autostart to false because it's assumed the VS Code extension
109+
// will call this command after the workspace is started.
110+
autostart := false
102111

103-
workspace, err := client.WorkspaceByOwnerAndName(ctx, owner, name, codersdk.WorkspaceOptions{})
112+
_, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, autostart, owner, name)
104113
if err != nil {
105-
return xerrors.Errorf("find workspace: %w", err)
114+
return xerrors.Errorf("find workspace and agent: %w", err)
106115
}
107116

108-
var agent codersdk.WorkspaceAgent
109-
var found bool
110-
for _, resource := range workspace.LatestBuild.Resources {
111-
if len(resource.Agents) == 0 {
112-
continue
113-
}
114-
for _, resourceAgent := range resource.Agents {
115-
// If an agent name isn't included we default to
116-
// the first agent!
117-
if len(parts) != 4 {
118-
agent = resourceAgent
119-
found = true
117+
// Select the startup script behavior based on template configuration or flags.
118+
var wait bool
119+
switch waitEnum {
120+
case "yes":
121+
wait = true
122+
case "no":
123+
wait = false
124+
case "auto":
125+
for _, script := range workspaceAgent.Scripts {
126+
if script.StartBlocksLogin {
127+
wait = true
120128
break
121129
}
122-
if resourceAgent.Name != parts[3] {
123-
continue
124-
}
125-
agent = resourceAgent
126-
found = true
127-
break
128130
}
129-
if found {
130-
break
131+
default:
132+
return xerrors.Errorf("unknown wait value %q", waitEnum)
133+
}
134+
135+
err = cliui.Agent(ctx, inv.Stderr, workspaceAgent.ID, cliui.AgentOptions{
136+
Fetch: client.WorkspaceAgent,
137+
FetchLogs: client.WorkspaceAgentLogsAfter,
138+
Wait: wait,
139+
})
140+
if err != nil {
141+
if xerrors.Is(err, context.Canceled) {
142+
return cliui.Canceled
131143
}
132144
}
133145

@@ -152,7 +164,7 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
152164
if r.disableDirect {
153165
logger.Info(ctx, "direct connections disabled")
154166
}
155-
agentConn, err := client.DialWorkspaceAgent(ctx, agent.ID, &codersdk.DialWorkspaceAgentOptions{
167+
agentConn, err := client.DialWorkspaceAgent(ctx, workspaceAgent.ID, &codersdk.DialWorkspaceAgentOptions{
156168
Logger: logger,
157169
BlockEndpoints: r.disableDirect,
158170
})
@@ -249,6 +261,12 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
249261
Default: "5s",
250262
Value: clibase.DurationOf(&networkInfoInterval),
251263
},
264+
{
265+
Flag: "wait",
266+
Description: "Specifies whether or not to wait for the startup script to finish executing. Auto means that the agent startup script behavior configured in the workspace template is used.",
267+
Default: "auto",
268+
Value: clibase.EnumOf(&waitEnum, "yes", "no", "auto"),
269+
},
252270
}
253271
return cmd
254272
}

coderd/coderd.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ func New(options *Options) *API {
472472

473473
api.Auditor.Store(&options.Auditor)
474474
api.TailnetCoordinator.Store(&options.TailnetCoordinator)
475-
api.agentProvider, err = NewServerTailnet(api.ctx,
475+
stn, err := NewServerTailnet(api.ctx,
476476
options.Logger,
477477
options.DERPServer,
478478
api.DERPMap,
@@ -485,6 +485,10 @@ func New(options *Options) *API {
485485
if err != nil {
486486
panic("failed to setup server tailnet: " + err.Error())
487487
}
488+
api.agentProvider = stn
489+
if options.DeploymentValues.Prometheus.Enable {
490+
options.PrometheusRegistry.MustRegister(stn)
491+
}
488492
api.TailnetClientService, err = tailnet.NewClientService(
489493
api.Logger.Named("tailnetclient"),
490494
&api.TailnetCoordinator,

0 commit comments

Comments
 (0)