Skip to content

Commit bfbe271

Browse files
committed
Merge branch 'main' into 5574-new-parameter-data-source
2 parents f73c633 + f91a0d8 commit bfbe271

30 files changed

+337
-275
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Generated files
2+
coderd/apidoc/docs.go linguist-generated=true
3+
coderd/apidoc/swagger.json linguist-generated=true
24
coderd/database/dump.sql linguist-generated=true
35
peerbroker/proto/*.go linguist-generated=true
46
provisionerd/proto/*.go linguist-generated=true

.github/workflows/coder.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ jobs:
617617
name: "test/e2e/${{ matrix.os }}"
618618
needs:
619619
- changes
620-
if: needs.changes.outputs.docs-only == 'false'
620+
if: false #needs.changes.outputs.docs-only == 'false'
621621
runs-on: ${{ matrix.os }}
622622
timeout-minutes: 20
623623
strategy:

coderd/coderdtest/swagger_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func TestEndpointsDocumented(t *testing.T) {
1818

1919
swaggerComments, err := coderdtest.ParseSwaggerComments("..")
2020
require.NoError(t, err, "can't parse swagger comments")
21+
require.NotEmpty(t, swaggerComments, "swagger comments must be present")
2122

2223
_, _, api := coderdtest.NewWithAPI(t, nil)
2324
coderdtest.VerifySwaggerDefinitions(t, api.APIHandler, swaggerComments)

coderd/coderdtest/swaggerparser.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func parseSwaggerComment(commentGroup *ast.CommentGroup) SwaggerComment {
149149

150150
func VerifySwaggerDefinitions(t *testing.T, router chi.Router, swaggerComments []SwaggerComment) {
151151
assertUniqueRoutes(t, swaggerComments)
152+
assertSingleAnnotations(t, swaggerComments)
152153

153154
err := chi.Walk(router, func(method, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
154155
method = strings.ToLower(method)
@@ -192,6 +193,36 @@ func assertUniqueRoutes(t *testing.T, comments []SwaggerComment) {
192193
}
193194
}
194195

196+
var uniqueAnnotations = []string{"@ID", "@Summary", "@Tags", "@Router"}
197+
198+
func assertSingleAnnotations(t *testing.T, comments []SwaggerComment) {
199+
for _, comment := range comments {
200+
counters := map[string]int{}
201+
202+
for _, line := range comment.raw {
203+
splitN := strings.SplitN(strings.TrimSpace(line.Text), " ", 3)
204+
if len(splitN) < 2 {
205+
continue // comment prefix without any content
206+
}
207+
208+
if !strings.HasPrefix(splitN[1], "@") {
209+
continue // not a swagger annotation
210+
}
211+
212+
annotation := splitN[1]
213+
if _, ok := counters[annotation]; !ok {
214+
counters[annotation] = 0
215+
}
216+
counters[annotation]++
217+
}
218+
219+
for _, annotation := range uniqueAnnotations {
220+
v := counters[annotation]
221+
assert.Equal(t, 1, v, "%s annotation for route %s must be defined only once", annotation, comment.router)
222+
}
223+
}
224+
}
225+
195226
func findSwaggerCommentByMethodAndRoute(comments []SwaggerComment, method, route string) *SwaggerComment {
196227
for _, c := range comments {
197228
if c.method == method && c.router == route {
@@ -219,6 +250,7 @@ func assertRequiredAnnotations(t *testing.T, comment SwaggerComment) {
219250
assert.NotEmpty(t, comment.id, "@ID must be defined")
220251
assert.NotEmpty(t, comment.summary, "@Summary must be defined")
221252
assert.NotEmpty(t, comment.tags, "@Tags must be defined")
253+
assert.NotEmpty(t, comment.router, "@Router must be defined")
222254
}
223255

224256
func assertGoCommentFirst(t *testing.T, comment SwaggerComment) {
@@ -295,6 +327,8 @@ func assertAccept(t *testing.T, comment SwaggerComment) {
295327
}
296328
}
297329

330+
var allowedProduceTypes = []string{"json", "text/event-stream"}
331+
298332
func assertProduce(t *testing.T, comment SwaggerComment) {
299333
var hasResponseModel bool
300334
for _, r := range comment.successes {
@@ -306,6 +340,7 @@ func assertProduce(t *testing.T, comment SwaggerComment) {
306340

307341
if hasResponseModel {
308342
assert.True(t, comment.produce != "", "Route must have @Produce annotation as it responds with a model structure")
343+
assert.Contains(t, allowedProduceTypes, comment.produce, "@Produce value is limited to specific types: %s", strings.Join(allowedProduceTypes, ","))
309344
} else {
310345
if (comment.router == "/workspaceagents/me/app-health" && comment.method == "post") ||
311346
(comment.router == "/workspaceagents/me/version" && comment.method == "post") ||

coderd/httpmw/oauth2.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func ExtractOAuth2(config OAuth2Config, client *http.Client) func(http.Handler)
5050

5151
// Interfaces can hold a nil value
5252
if config == nil || reflect.ValueOf(config).IsNil() {
53-
httpapi.Write(ctx, rw, http.StatusPreconditionRequired, codersdk.Response{
53+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
5454
Message: "The oauth2 method requested is not configured!",
5555
})
5656
return

coderd/httpmw/oauth2_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestOAuth2(t *testing.T) {
4040
req := httptest.NewRequest("GET", "/", nil)
4141
res := httptest.NewRecorder()
4242
httpmw.ExtractOAuth2(nil, nil)(nil).ServeHTTP(res, req)
43-
require.Equal(t, http.StatusPreconditionRequired, res.Result().StatusCode)
43+
require.Equal(t, http.StatusBadRequest, res.Result().StatusCode)
4444
})
4545
t.Run("RedirectWithoutCode", func(t *testing.T) {
4646
t.Parallel()

coderd/provisionerjobs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job
193193
func (api *API) provisionerJobResources(rw http.ResponseWriter, r *http.Request, job database.ProvisionerJob) {
194194
ctx := r.Context()
195195
if !job.CompletedAt.Valid {
196-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
196+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
197197
Message: "Job hasn't completed!",
198198
})
199199
return

coderd/templates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
110110
return
111111
}
112112
if len(workspaces) > 0 {
113-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
113+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
114114
Message: "All workspaces must be deleted before a template can be removed.",
115115
})
116116
return

coderd/templates_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ func TestDeleteTemplate(t *testing.T) {
501501
err := client.DeleteTemplate(ctx, template.ID)
502502
var apiErr *codersdk.Error
503503
require.ErrorAs(t, err, &apiErr)
504-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
504+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
505505
})
506506
}
507507

coderd/templateversions.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ func (api *API) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Reque
9898
return
9999
}
100100
if job.CompletedAt.Valid {
101-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
101+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
102102
Message: "Job has already completed!",
103103
})
104104
return
105105
}
106106
if job.CanceledAt.Valid {
107-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
107+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
108108
Message: "Job has already been marked as canceled!",
109109
})
110110
return
@@ -162,7 +162,7 @@ func (api *API) templateVersionSchema(rw http.ResponseWriter, r *http.Request) {
162162
return
163163
}
164164
if !job.CompletedAt.Valid {
165-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
165+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
166166
Message: "Template version job hasn't completed!",
167167
})
168168
return
@@ -274,7 +274,7 @@ func (api *API) templateVersionParameters(rw http.ResponseWriter, r *http.Reques
274274
return
275275
}
276276
if !job.CompletedAt.Valid {
277-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
277+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
278278
Message: "Job hasn't completed!",
279279
})
280280
return
@@ -342,7 +342,7 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
342342
return
343343
}
344344
if !job.CompletedAt.Valid {
345-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
345+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
346346
Message: "Template version import job hasn't completed!",
347347
})
348348
return
@@ -486,13 +486,13 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
486486
}
487487

488488
if job.CompletedAt.Valid {
489-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
489+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
490490
Message: "Job has already completed.",
491491
})
492492
return
493493
}
494494
if job.CanceledAt.Valid {
495-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
495+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
496496
Message: "Job has already been marked as canceled.",
497497
})
498498
return

coderd/templateversions_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func TestPatchCancelTemplateVersion(t *testing.T) {
206206
err := client.CancelTemplateVersion(ctx, version.ID)
207207
var apiErr *codersdk.Error
208208
require.ErrorAs(t, err, &apiErr)
209-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
209+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
210210
})
211211
t.Run("AlreadyCanceled", func(t *testing.T) {
212212
t.Parallel()
@@ -238,7 +238,7 @@ func TestPatchCancelTemplateVersion(t *testing.T) {
238238
err = client.CancelTemplateVersion(ctx, version.ID)
239239
var apiErr *codersdk.Error
240240
require.ErrorAs(t, err, &apiErr)
241-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
241+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
242242
require.Eventually(t, func() bool {
243243
var err error
244244
version, err = client.TemplateVersion(ctx, version.ID)
@@ -300,7 +300,7 @@ func TestTemplateVersionSchema(t *testing.T) {
300300
_, err := client.TemplateVersionSchema(ctx, version.ID)
301301
var apiErr *codersdk.Error
302302
require.ErrorAs(t, err, &apiErr)
303-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
303+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
304304
})
305305
t.Run("List", func(t *testing.T) {
306306
t.Parallel()
@@ -380,7 +380,7 @@ func TestTemplateVersionParameters(t *testing.T) {
380380
_, err := client.TemplateVersionParameters(ctx, version.ID)
381381
var apiErr *codersdk.Error
382382
require.ErrorAs(t, err, &apiErr)
383-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
383+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
384384
})
385385
t.Run("List", func(t *testing.T) {
386386
t.Parallel()
@@ -447,7 +447,7 @@ func TestTemplateVersionResources(t *testing.T) {
447447
_, err := client.TemplateVersionResources(ctx, version.ID)
448448
var apiErr *codersdk.Error
449449
require.ErrorAs(t, err, &apiErr)
450-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
450+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
451451
})
452452
t.Run("List", func(t *testing.T) {
453453
t.Parallel()
@@ -749,7 +749,7 @@ func TestTemplateVersionDryRun(t *testing.T) {
749749
})
750750
var apiErr *codersdk.Error
751751
require.ErrorAs(t, err, &apiErr)
752-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
752+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
753753
})
754754

755755
t.Run("Cancel", func(t *testing.T) {
@@ -828,7 +828,7 @@ func TestTemplateVersionDryRun(t *testing.T) {
828828
err = client.CancelTemplateVersionDryRun(ctx, version.ID, job.ID)
829829
var apiErr *codersdk.Error
830830
require.ErrorAs(t, err, &apiErr)
831-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
831+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
832832
})
833833

834834
t.Run("AlreadyCanceled", func(t *testing.T) {
@@ -873,7 +873,7 @@ func TestTemplateVersionDryRun(t *testing.T) {
873873
err = client.CancelTemplateVersionDryRun(ctx, version.ID, job.ID)
874874
var apiErr *codersdk.Error
875875
require.ErrorAs(t, err, &apiErr)
876-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
876+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
877877
})
878878
})
879879
}

coderd/userauth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
161161
}
162162

163163
if verifiedEmail == nil {
164-
httpapi.Write(ctx, rw, http.StatusPreconditionRequired, codersdk.Response{
164+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
165165
Message: "Your primary email must be verified on GitHub!",
166166
})
167167
return

coderd/userauth_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func TestUserOAuth2Github(t *testing.T) {
177177
})
178178
_ = coderdtest.CreateFirstUser(t, client)
179179
resp := oauth2Callback(t, client)
180-
require.Equal(t, http.StatusPreconditionRequired, resp.StatusCode)
180+
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
181181
})
182182
t.Run("BlockSignups", func(t *testing.T) {
183183
t.Parallel()
@@ -686,7 +686,7 @@ func TestUserOIDC(t *testing.T) {
686686
t.Parallel()
687687
client := coderdtest.New(t, nil)
688688
resp := oidcCallback(t, client, "asdf")
689-
require.Equal(t, http.StatusPreconditionRequired, resp.StatusCode)
689+
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
690690
})
691691

692692
t.Run("NoIDToken", func(t *testing.T) {

coderd/workspaceagents.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
237237
return
238238
}
239239
if apiAgent.Status != codersdk.WorkspaceAgentConnected {
240-
httpapi.Write(ctx, rw, http.StatusPreconditionRequired, codersdk.Response{
240+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
241241
Message: fmt.Sprintf("Agent state is %q, it must be in the %q state.", apiAgent.Status, codersdk.WorkspaceAgentConnected),
242242
})
243243
return
@@ -318,7 +318,7 @@ func (api *API) workspaceAgentListeningPorts(rw http.ResponseWriter, r *http.Req
318318
return
319319
}
320320
if apiAgent.Status != codersdk.WorkspaceAgentConnected {
321-
httpapi.Write(ctx, rw, http.StatusPreconditionRequired, codersdk.Response{
321+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
322322
Message: fmt.Sprintf("Agent state is %q, it must be in the %q state.", apiAgent.Status, codersdk.WorkspaceAgentConnected),
323323
})
324324
return
@@ -826,7 +826,7 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin
826826
// @ID submit-workspace-agent-stats
827827
// @Security CoderSessionToken
828828
// @Accept json
829-
// @Produce application/json
829+
// @Produce json
830830
// @Tags Agents
831831
// @Param request body codersdk.AgentStats true "Stats request"
832832
// @Success 200 {object} codersdk.AgentStatsResponse
@@ -904,7 +904,7 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques
904904
// @ID submit-workspace-agent-application-health
905905
// @Security CoderSessionToken
906906
// @Accept json
907-
// @Produce application/json
907+
// @Produce json
908908
// @Tags Agents
909909
// @Param request body codersdk.PostWorkspaceAppHealthsRequest true "Application health request"
910910
// @Success 200

coderd/workspacebuilds.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,12 +411,12 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
411411
})
412412
return
413413
case codersdk.ProvisionerJobFailed:
414-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
414+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
415415
Message: fmt.Sprintf("The provided template version %q has failed to import: %q. You cannot build workspaces with it!", templateVersion.Name, templateVersionJob.Error.String),
416416
})
417417
return
418418
case codersdk.ProvisionerJobCanceled:
419-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
419+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
420420
Message: "The provided template version was canceled during import. You cannot builds workspaces with it!",
421421
})
422422
return
@@ -626,13 +626,13 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques
626626
return
627627
}
628628
if job.CompletedAt.Valid {
629-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
629+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
630630
Message: "Job has already completed!",
631631
})
632632
return
633633
}
634634
if job.CanceledAt.Valid {
635-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
635+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
636636
Message: "Job has already been marked as canceled!",
637637
})
638638
return

coderd/workspaces.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,12 +406,12 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
406406
})
407407
return
408408
case codersdk.ProvisionerJobFailed:
409-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
409+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
410410
Message: fmt.Sprintf("The provided template version %q has failed to import. You cannot create workspaces using it!", templateVersion.Name),
411411
})
412412
return
413413
case codersdk.ProvisionerJobCanceled:
414-
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
414+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
415415
Message: "The provided template version was canceled during import. You cannot create workspaces using it!",
416416
})
417417
return

coderd/workspaces_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ func TestPostWorkspaceBuild(t *testing.T) {
10531053
})
10541054
var apiErr *codersdk.Error
10551055
require.ErrorAs(t, err, &apiErr)
1056-
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
1056+
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
10571057
})
10581058

10591059
t.Run("AlreadyActive", func(t *testing.T) {

docs/admin/high-availability.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ workspace <-> Coder and user <-> Coder connections.
1515

1616
## Setup
1717

18-
> We're stress testing High Availability this week before we enable it by default. To try HA beforehand, set `CODER_EXPERIMENTAL=true` for the Coder server as well as the additional configuration options below.
19-
2018
Coder automatically enters HA mode when multiple instances simultaneously connect
2119
to the same Postgres endpoint.
2220

0 commit comments

Comments
 (0)