Skip to content

Commit d37c3a1

Browse files
committed
Merge remote-tracking branch 'origin/main' into jjs/presets
2 parents 986a467 + edd982e commit d37c3a1

File tree

29 files changed

+329
-250
lines changed

29 files changed

+329
-250
lines changed

cli/cliui/output.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ func (f *OutputFormatter) Format(ctx context.Context, data any) (string, error)
8383
return "", xerrors.Errorf("unknown output format %q", f.formatID)
8484
}
8585

86+
// FormatID will return the ID of the format selected by `--output`.
87+
// If no flag is present, it returns the 'default' formatter.
88+
func (f *OutputFormatter) FormatID() string {
89+
return f.formatID
90+
}
91+
8692
type tableFormat struct {
8793
defaultColumns []string
8894
allColumns []string

cli/list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func (r *RootCmd) list() *serpent.Command {
112112
return err
113113
}
114114

115-
if len(res) == 0 {
115+
if len(res) == 0 && formatter.FormatID() != cliui.JSONFormat().ID() {
116116
pretty.Fprintf(inv.Stderr, cliui.DefaultStyles.Prompt, "No workspaces found! Create one:\n")
117117
_, _ = fmt.Fprintln(inv.Stderr)
118118
_, _ = fmt.Fprintln(inv.Stderr, " "+pretty.Sprint(cliui.DefaultStyles.Code, "coder create <name>"))

cli/list_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,30 @@ func TestList(t *testing.T) {
7474
require.NoError(t, json.Unmarshal(out.Bytes(), &workspaces))
7575
require.Len(t, workspaces, 1)
7676
})
77+
78+
t.Run("NoWorkspacesJSON", func(t *testing.T) {
79+
t.Parallel()
80+
client := coderdtest.New(t, nil)
81+
owner := coderdtest.CreateFirstUser(t, client)
82+
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
83+
84+
inv, root := clitest.New(t, "list", "--output=json")
85+
clitest.SetupConfig(t, member, root)
86+
87+
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitLong)
88+
defer cancelFunc()
89+
90+
stdout := bytes.NewBuffer(nil)
91+
stderr := bytes.NewBuffer(nil)
92+
inv.Stdout = stdout
93+
inv.Stderr = stderr
94+
err := inv.WithContext(ctx).Run()
95+
require.NoError(t, err)
96+
97+
var workspaces []codersdk.Workspace
98+
require.NoError(t, json.Unmarshal(stdout.Bytes(), &workspaces))
99+
require.Len(t, workspaces, 0)
100+
101+
require.Len(t, stderr.Bytes(), 0)
102+
})
77103
}

coderd/apidoc/docs.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1304,7 +1304,7 @@ func New(options *Options) *API {
13041304
func(next http.Handler) http.Handler {
13051305
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
13061306
if !api.Authorize(r, policy.ActionRead, rbac.ResourceDebugInfo) {
1307-
httpapi.ResourceNotFound(rw)
1307+
httpapi.Forbidden(rw)
13081308
return
13091309
}
13101310

coderd/database/dbmem/dbmem.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4170,6 +4170,9 @@ func (q *FakeQuerier) GetProvisionerJobsByOrganizationAndStatusWithQueuePosition
41704170
if len(arg.IDs) > 0 && !slices.Contains(arg.IDs, job.ID) {
41714171
continue
41724172
}
4173+
if len(arg.Tags) > 0 && !tagsSubset(job.Tags, arg.Tags) {
4174+
continue
4175+
}
41734176

41744177
row := database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow{
41754178
ProvisionerJob: rowQP.ProvisionerJob,

coderd/database/queries.sql.go

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/provisionerjobs.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ WHERE
158158
(sqlc.narg('organization_id')::uuid IS NULL OR pj.organization_id = @organization_id)
159159
AND (COALESCE(array_length(@ids::uuid[], 1), 0) = 0 OR pj.id = ANY(@ids::uuid[]))
160160
AND (COALESCE(array_length(@status::provisioner_job_status[], 1), 0) = 0 OR pj.job_status = ANY(@status::provisioner_job_status[]))
161+
AND (@tags::tagset = 'null'::tagset OR provisioner_tagset_contains(pj.tags::tagset, @tags::tagset))
161162
GROUP BY
162163
pj.id,
163164
qp.queue_position,

coderd/provisionerjobs.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ func (api *API) provisionerJob(rw http.ResponseWriter, r *http.Request) {
7272
// @Tags Organizations
7373
// @Param organization path string true "Organization ID" format(uuid)
7474
// @Param limit query int false "Page limit"
75+
// @Param ids query []string false "Filter results by job IDs" format(uuid)
7576
// @Param status query codersdk.ProvisionerJobStatus false "Filter results by status" enums(pending,running,succeeded,canceling,canceled,failed)
77+
// @Param tags query object false "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})"
7678
// @Success 200 {array} codersdk.ProvisionerJob
7779
// @Router /organizations/{organization}/provisionerjobs [get]
7880
func (api *API) provisionerJobs(rw http.ResponseWriter, r *http.Request) {
@@ -103,6 +105,10 @@ func (api *API) handleAuthAndFetchProvisionerJobs(rw http.ResponseWriter, r *htt
103105
p := httpapi.NewQueryParamParser()
104106
limit := p.PositiveInt32(qp, 50, "limit")
105107
status := p.Strings(qp, nil, "status")
108+
if ids == nil {
109+
ids = p.UUIDs(qp, nil, "ids")
110+
}
111+
tagsRaw := p.String(qp, "", "tags")
106112
p.ErrorExcessParams(qp)
107113
if len(p.Errors) > 0 {
108114
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
@@ -112,11 +118,23 @@ func (api *API) handleAuthAndFetchProvisionerJobs(rw http.ResponseWriter, r *htt
112118
return nil, false
113119
}
114120

121+
tags := database.StringMap{}
122+
if tagsRaw != "" {
123+
if err := tags.Scan([]byte(tagsRaw)); err != nil {
124+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
125+
Message: "Invalid tags query parameter",
126+
Detail: err.Error(),
127+
})
128+
return nil, false
129+
}
130+
}
131+
115132
jobs, err := api.Database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisioner(ctx, database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams{
116133
OrganizationID: uuid.NullUUID{UUID: org.ID, Valid: true},
117134
Status: slice.StringEnums[database.ProvisionerJobStatus](status),
118135
Limit: sql.NullInt32{Int32: limit, Valid: limit > 0},
119136
IDs: ids,
137+
Tags: tags,
120138
})
121139
if err != nil {
122140
if httpapi.Is404Error(err) {

coderd/provisionerjobs_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"database/sql"
66
"encoding/json"
7+
"strconv"
78
"testing"
89
"time"
910

@@ -65,9 +66,10 @@ func TestProvisionerJobs(t *testing.T) {
6566
})
6667

6768
// Add more jobs than the default limit.
68-
for range 60 {
69+
for i := range 60 {
6970
dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
7071
OrganizationID: owner.OrganizationID,
72+
Tags: database.StringMap{"count": strconv.Itoa(i)},
7173
})
7274
}
7375

@@ -132,6 +134,16 @@ func TestProvisionerJobs(t *testing.T) {
132134
require.Len(t, jobs, 50)
133135
})
134136

137+
t.Run("IDs", func(t *testing.T) {
138+
t.Parallel()
139+
ctx := testutil.Context(t, testutil.WaitMedium)
140+
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
141+
IDs: []uuid.UUID{workspace.LatestBuild.Job.ID, version.Job.ID},
142+
})
143+
require.NoError(t, err)
144+
require.Len(t, jobs, 2)
145+
})
146+
135147
t.Run("Status", func(t *testing.T) {
136148
t.Parallel()
137149
ctx := testutil.Context(t, testutil.WaitMedium)
@@ -142,6 +154,16 @@ func TestProvisionerJobs(t *testing.T) {
142154
require.Len(t, jobs, 1)
143155
})
144156

157+
t.Run("Tags", func(t *testing.T) {
158+
t.Parallel()
159+
ctx := testutil.Context(t, testutil.WaitMedium)
160+
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
161+
Tags: map[string]string{"count": "1"},
162+
})
163+
require.NoError(t, err)
164+
require.Len(t, jobs, 1)
165+
})
166+
145167
t.Run("Limit", func(t *testing.T) {
146168
t.Parallel()
147169
ctx := testutil.Context(t, testutil.WaitMedium)

codersdk/organizations.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,9 @@ func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizatio
346346

347347
type OrganizationProvisionerJobsOptions struct {
348348
Limit int
349+
IDs []uuid.UUID
349350
Status []ProvisionerJobStatus
351+
Tags map[string]string
350352
}
351353

352354
func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID uuid.UUID, opts *OrganizationProvisionerJobsOptions) ([]ProvisionerJob, error) {
@@ -355,9 +357,19 @@ func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID
355357
if opts.Limit > 0 {
356358
qp.Add("limit", strconv.Itoa(opts.Limit))
357359
}
360+
if len(opts.IDs) > 0 {
361+
qp.Add("ids", joinSliceStringer(opts.IDs))
362+
}
358363
if len(opts.Status) > 0 {
359364
qp.Add("status", joinSlice(opts.Status))
360365
}
366+
if len(opts.Tags) > 0 {
367+
tagsRaw, err := json.Marshal(opts.Tags)
368+
if err != nil {
369+
return nil, xerrors.Errorf("marshal tags: %w", err)
370+
}
371+
qp.Add("tags", string(tagsRaw))
372+
}
361373
}
362374

363375
res, err := c.Request(ctx, http.MethodGet,
@@ -401,6 +413,14 @@ func joinSlice[T ~string](s []T) string {
401413
return strings.Join(ss, ",")
402414
}
403415

416+
func joinSliceStringer[T fmt.Stringer](s []T) string {
417+
var ss []string
418+
for _, v := range s {
419+
ss = append(ss, v.String())
420+
}
421+
return strings.Join(ss, ",")
422+
}
423+
404424
// CreateTemplateVersion processes source-code and optionally associates the version with a template.
405425
// Executing without a template is useful for validating source-code.
406426
func (c *Client) CreateTemplateVersion(ctx context.Context, organizationID uuid.UUID, req CreateTemplateVersionRequest) (TemplateVersion, error) {

docs/admin/monitoring/notifications/index.md

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,54 @@
33
Notifications are sent by Coder in response to specific internal events, such as
44
a workspace being deleted or a user being created.
55

6+
Available events may differ between versions.
7+
For a list of all events, visit your Coder deployment's
8+
`https://coder.example.com/deployment/notifications`.
9+
610
## Event Types
711

812
Notifications are sent in response to internal events, to alert the affected
9-
user(s) of this event. Currently we support the following list of events:
13+
user(s) of the event.
14+
15+
Coder supports the following list of events:
1016

1117
### Workspace Events
1218

13-
_These notifications are sent to the workspace owner._
19+
These notifications are sent to the workspace owner:
1420

15-
- Workspace Deleted
16-
- Workspace Manual Build Failure
17-
- Workspace Automatic Build Failure
18-
- Workspace Automatically Updated
19-
- Workspace Dormant
20-
- Workspace Marked For Deletion
21+
- Workspace created
22+
- Workspace deleted
23+
- Workspace manual build failure
24+
- Workspace automatic build failure
25+
- Workspace manually updated
26+
- Workspace automatically updated
27+
- Workspace marked as dormant
28+
- Workspace marked for deletion
2129

2230
### User Events
2331

24-
_These notifications are sent to users with **owner** and **user admin** roles._
32+
These notifications sent to users with **owner** and **user admin** roles:
2533

26-
- User Account Created
27-
- User Account Deleted
28-
- User Account Suspended
29-
- User Account Activated
30-
- _(coming soon) User Password Reset_
31-
- _(coming soon) User Email Verification_
34+
- User account created
35+
- User account deleted
36+
- User account suspended
37+
- User account activated
3238

33-
_These notifications are sent to the user themselves._
39+
These notifications sent to users themselves:
3440

35-
- User Account Suspended
36-
- User Account Activated
41+
- User account suspended
42+
- User account activated
43+
- User password reset (One-time passcode)
3744

3845
### Template Events
3946

40-
_These notifications are sent to users with **template admin** roles._
47+
These notifications are sent to users with **template admin** roles:
4148

42-
- Template Deleted
49+
- Template deleted
50+
- Template deprecated
51+
- Report: Workspace builds failed for template
52+
- This notification is delivered as part of a weekly cron job and summarizes
53+
the failed builds for a given template.
4354

4455
## Configuration
4556

0 commit comments

Comments
 (0)