From 541f98544185ce82efc96e0c22a957c02fc45568 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 7 Jun 2022 15:33:19 -0500 Subject: [PATCH 1/4] feat: initiator_username joined to workspace_build queries Using views to make models for sqlc --- .../autobuild/executor/lifecycle_executor.go | 2 +- coderd/database/databasefake/databasefake.go | 66 +++++++++++++------ coderd/database/dump.sql | 17 +++++ ...space_builds_with_initiaitor_view.down.sql | 1 + ...rkspace_builds_with_initiaitor_view.up.sql | 7 ++ coderd/database/models.go | 16 +++++ coderd/database/querier.go | 12 ++-- coderd/database/queries.sql.go | 62 +++++++++-------- coderd/database/queries/workspacebuilds.sql | 16 ++--- coderd/httpmw/workspacebuildparam.go | 4 +- coderd/workspacebuilds.go | 14 ++-- coderd/workspaces.go | 16 +++-- codersdk/workspacebuilds.go | 1 + 13 files changed, 159 insertions(+), 75 deletions(-) create mode 100644 coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql create mode 100644 coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql diff --git a/coderd/autobuild/executor/lifecycle_executor.go b/coderd/autobuild/executor/lifecycle_executor.go index 55b8b3228f775..048f30eb2479b 100644 --- a/coderd/autobuild/executor/lifecycle_executor.go +++ b/coderd/autobuild/executor/lifecycle_executor.go @@ -190,7 +190,7 @@ func (e *Executor) runOnce(t time.Time) Stats { // TODO(cian): this function duplicates most of api.postWorkspaceBuilds. Refactor. // See: https://github.com/coder/coder/issues/1401 -func build(ctx context.Context, store database.Store, workspace database.Workspace, trans database.WorkspaceTransition, priorHistory database.WorkspaceBuild, priorJob database.ProvisionerJob) error { +func build(ctx context.Context, store database.Store, workspace database.Workspace, trans database.WorkspaceTransition, priorHistory database.WorkspaceBuildsWithInitiator, priorJob database.ProvisionerJob) error { template, err := store.GetTemplateByID(ctx, workspace.TemplateID) if err != nil { return xerrors.Errorf("get workspace template: %w", err) diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 0176c82ac3a9e..34be00e2a972a 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -476,63 +476,63 @@ func (q *fakeQuerier) GetWorkspaceOwnerCountsByTemplateIDs(_ context.Context, te return res, nil } -func (q *fakeQuerier) GetWorkspaceBuildByID(_ context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { +func (q *fakeQuerier) GetWorkspaceBuildByID(_ context.Context, id uuid.UUID) (database.WorkspaceBuildsWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() for _, history := range q.workspaceBuilds { if history.ID.String() == id.String() { - return history, nil + return q.workspaceBuildWithInitiator(history), nil } } - return database.WorkspaceBuild{}, sql.ErrNoRows + return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows } -func (q *fakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { +func (q *fakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuildsWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() for _, build := range q.workspaceBuilds { if build.JobID.String() == jobID.String() { - return build, nil + return q.workspaceBuildWithInitiator(build), nil } } - return database.WorkspaceBuild{}, sql.ErrNoRows + return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows } -func (q *fakeQuerier) GetLatestWorkspaceBuildByWorkspaceID(_ context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) { +func (q *fakeQuerier) GetLatestWorkspaceBuildByWorkspaceID(_ context.Context, workspaceID uuid.UUID) (database.WorkspaceBuildsWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() - var row database.WorkspaceBuild + var row database.WorkspaceBuildsWithInitiator var buildNum int32 for _, workspaceBuild := range q.workspaceBuilds { if workspaceBuild.WorkspaceID.String() == workspaceID.String() && workspaceBuild.BuildNumber > buildNum { - row = workspaceBuild + row = q.workspaceBuildWithInitiator(workspaceBuild) buildNum = workspaceBuild.BuildNumber } } if buildNum == 0 { - return database.WorkspaceBuild{}, sql.ErrNoRows + return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows } return row, nil } -func (q *fakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceBuild, error) { +func (q *fakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceBuildsWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() - builds := make(map[uuid.UUID]database.WorkspaceBuild) + builds := make(map[uuid.UUID]database.WorkspaceBuildsWithInitiator) buildNumbers := make(map[uuid.UUID]int32) for _, workspaceBuild := range q.workspaceBuilds { for _, id := range ids { if id.String() == workspaceBuild.WorkspaceID.String() && workspaceBuild.BuildNumber > buildNumbers[id] { - builds[id] = workspaceBuild + builds[id] = q.workspaceBuildWithInitiator(workspaceBuild) buildNumbers[id] = workspaceBuild.BuildNumber } } } - var returnBuilds []database.WorkspaceBuild + var returnBuilds []database.WorkspaceBuildsWithInitiator for i, n := range buildNumbers { if n > 0 { b := builds[i] @@ -546,19 +546,19 @@ func (q *fakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, } func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceID(_ context.Context, - params database.GetWorkspaceBuildByWorkspaceIDParams) ([]database.WorkspaceBuild, error) { + params database.GetWorkspaceBuildByWorkspaceIDParams) ([]database.WorkspaceBuildsWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() - history := make([]database.WorkspaceBuild, 0) + history := make([]database.WorkspaceBuildsWithInitiator, 0) for _, workspaceBuild := range q.workspaceBuilds { if workspaceBuild.WorkspaceID.String() == params.WorkspaceID.String() { - history = append(history, workspaceBuild) + history = append(history, q.workspaceBuildWithInitiator(workspaceBuild)) } } // Order by build_number - slices.SortFunc(history, func(a, b database.WorkspaceBuild) bool { + slices.SortFunc(history, func(a, b database.WorkspaceBuildsWithInitiator) bool { // use greater than since we want descending order return a.BuildNumber > b.BuildNumber }) @@ -600,7 +600,7 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceID(_ context.Context, return history, nil } -func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndNameParams) (database.WorkspaceBuild, error) { +func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndNameParams) (database.WorkspaceBuildsWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -611,9 +611,33 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, a if !strings.EqualFold(workspaceBuild.Name, arg.Name) { continue } - return workspaceBuild, nil + + return q.workspaceBuildWithInitiator(workspaceBuild), nil + } + return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows +} + +func (q *fakeQuerier) workspaceBuildWithInitiator(build database.WorkspaceBuild) database.WorkspaceBuildsWithInitiator { + username := "unknown" + usr, err := q.GetUserByID(context.Background(), build.InitiatorID) + if err == nil { + username = usr.Username + } + return database.WorkspaceBuildsWithInitiator{ + ID: build.ID, + CreatedAt: build.CreatedAt, + UpdatedAt: build.UpdatedAt, + WorkspaceID: build.WorkspaceID, + TemplateVersionID: build.TemplateVersionID, + Name: build.Name, + BuildNumber: build.BuildNumber, + Transition: build.Transition, + InitiatorID: build.InitiatorID, + ProvisionerState: build.ProvisionerState, + JobID: build.JobID, + Deadline: build.Deadline, + InitiatorUsername: username, } - return database.WorkspaceBuild{}, sql.ErrNoRows } func (q *fakeQuerier) GetWorkspacesByOrganizationIDs(_ context.Context, req database.GetWorkspacesByOrganizationIDsParams) ([]database.Workspace, error) { diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index eff1e9ea6350c..59ea7a2bfeeb0 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -308,6 +308,23 @@ CREATE TABLE workspace_builds ( deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL ); +CREATE VIEW workspace_builds_with_initiator AS + SELECT workspace_builds.id, + workspace_builds.created_at, + workspace_builds.updated_at, + workspace_builds.workspace_id, + workspace_builds.template_version_id, + workspace_builds.name, + workspace_builds.build_number, + workspace_builds.transition, + workspace_builds.initiator_id, + workspace_builds.provisioner_state, + workspace_builds.job_id, + workspace_builds.deadline, + COALESCE(users.username, 'unknown'::text) AS initiator_username + FROM (public.workspace_builds + LEFT JOIN users ON ((workspace_builds.initiator_id = users.id))); + CREATE TABLE workspace_resources ( id uuid NOT NULL, created_at timestamp with time zone NOT NULL, diff --git a/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql new file mode 100644 index 0000000000000..1b2c020806002 --- /dev/null +++ b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql @@ -0,0 +1 @@ +DROP VIEW IF EXISTS workspace_builds_with_initiator; diff --git a/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql new file mode 100644 index 0000000000000..7db0990e0e8f0 --- /dev/null +++ b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql @@ -0,0 +1,7 @@ +-- This view adds the initiator name to the query for UI purposes. +-- Showing the initiator user ID is not very friendly. +CREATE VIEW workspace_builds_with_initiator AS +-- If the user is nil, just use 'unknown' for now. +SELECT workspace_builds.*, coalesce(users.username, 'unknown') AS initiator_username +FROM workspace_builds + LEFT JOIN users ON workspace_builds.initiator_id = users.id; diff --git a/coderd/database/models.go b/coderd/database/models.go index 22f47053c3955..ef725e0b0dc9f 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -521,6 +521,22 @@ type WorkspaceBuild struct { Deadline time.Time `db:"deadline" json:"deadline"` } +type WorkspaceBuildsWithInitiator struct { + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"` + TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"` + Name string `db:"name" json:"name"` + BuildNumber int32 `db:"build_number" json:"build_number"` + Transition WorkspaceTransition `db:"transition" json:"transition"` + InitiatorID uuid.UUID `db:"initiator_id" json:"initiator_id"` + ProvisionerState []byte `db:"provisioner_state" json:"provisioner_state"` + JobID uuid.UUID `db:"job_id" json:"job_id"` + Deadline time.Time `db:"deadline" json:"deadline"` + InitiatorUsername string `db:"initiator_username" json:"initiator_username"` +} + type WorkspaceResource struct { ID uuid.UUID `db:"id" json:"id"` CreatedAt time.Time `db:"created_at" json:"created_at"` diff --git a/coderd/database/querier.go b/coderd/database/querier.go index bf66df784fc3c..c5fc4a9405430 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -30,8 +30,8 @@ type querier interface { GetAuthorizationUserRoles(ctx context.Context, userID uuid.UUID) (GetAuthorizationUserRolesRow, error) GetFileByHash(ctx context.Context, hash string) (File, error) GetGitSSHKey(ctx context.Context, userID uuid.UUID) (GitSSHKey, error) - GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuild, error) - GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuild, error) + GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuildsWithInitiator, error) + GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuildsWithInitiator, error) GetOrganizationByID(ctx context.Context, id uuid.UUID) (Organization, error) GetOrganizationByName(ctx context.Context, name string) (Organization, error) GetOrganizationIDsByMemberIDs(ctx context.Context, ids []uuid.UUID) ([]GetOrganizationIDsByMemberIDsRow, error) @@ -67,10 +67,10 @@ type querier interface { GetWorkspaceAppByAgentIDAndName(ctx context.Context, arg GetWorkspaceAppByAgentIDAndNameParams) (WorkspaceApp, error) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid.UUID) ([]WorkspaceApp, error) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceApp, error) - GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuild, error) - GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuild, error) - GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuild, error) - GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuild, error) + GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuildsWithInitiator, error) + GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuildsWithInitiator, error) + GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuildsWithInitiator, error) + GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuildsWithInitiator, error) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (Workspace, error) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg GetWorkspaceByOwnerIDAndNameParams) (Workspace, error) GetWorkspaceOwnerCountsByTemplateIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceOwnerCountsByTemplateIDsRow, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 25e9031e2bafb..145c5d8df3385 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -2952,9 +2952,9 @@ func (q *sqlQuerier) InsertWorkspaceApp(ctx context.Context, arg InsertWorkspace const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildByWorkspaceID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline + id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds + workspace_builds_with_initiator WHERE workspace_id = $1 ORDER BY @@ -2963,9 +2963,9 @@ LIMIT 1 ` -func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuild, error) { +func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuildsWithInitiator, error) { row := q.db.QueryRowContext(ctx, getLatestWorkspaceBuildByWorkspaceID, workspaceID) - var i WorkspaceBuild + var i WorkspaceBuildsWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, @@ -2979,36 +2979,37 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, w &i.ProvisionerState, &i.JobID, &i.Deadline, + &i.InitiatorUsername, ) return i, err } const getLatestWorkspaceBuildsByWorkspaceIDs = `-- name: GetLatestWorkspaceBuildsByWorkspaceIDs :many -SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.name, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline +SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.name, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.initiator_username FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds + workspace_builds_with_initiator WHERE workspace_id = ANY($1 :: uuid [ ]) GROUP BY workspace_id ) m JOIN - workspace_builds wb + workspace_builds_with_initiator wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number ` -func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuild, error) { +func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuildsWithInitiator, error) { rows, err := q.db.QueryContext(ctx, getLatestWorkspaceBuildsByWorkspaceIDs, pq.Array(ids)) if err != nil { return nil, err } defer rows.Close() - var items []WorkspaceBuild + var items []WorkspaceBuildsWithInitiator for rows.Next() { - var i WorkspaceBuild + var i WorkspaceBuildsWithInitiator if err := rows.Scan( &i.ID, &i.CreatedAt, @@ -3022,6 +3023,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, &i.ProvisionerState, &i.JobID, &i.Deadline, + &i.InitiatorUsername, ); err != nil { return nil, err } @@ -3038,18 +3040,18 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, const getWorkspaceBuildByID = `-- name: GetWorkspaceBuildByID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline + id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds + workspace_builds_with_initiator WHERE id = $1 LIMIT 1 ` -func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuild, error) { +func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuildsWithInitiator, error) { row := q.db.QueryRowContext(ctx, getWorkspaceBuildByID, id) - var i WorkspaceBuild + var i WorkspaceBuildsWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, @@ -3063,24 +3065,25 @@ func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (W &i.ProvisionerState, &i.JobID, &i.Deadline, + &i.InitiatorUsername, ) return i, err } const getWorkspaceBuildByJobID = `-- name: GetWorkspaceBuildByJobID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline + id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds + workspace_builds_with_initiator WHERE job_id = $1 LIMIT 1 ` -func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuild, error) { +func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuildsWithInitiator, error) { row := q.db.QueryRowContext(ctx, getWorkspaceBuildByJobID, jobID) - var i WorkspaceBuild + var i WorkspaceBuildsWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, @@ -3094,17 +3097,18 @@ func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UU &i.ProvisionerState, &i.JobID, &i.Deadline, + &i.InitiatorUsername, ) return i, err } const getWorkspaceBuildByWorkspaceID = `-- name: GetWorkspaceBuildByWorkspaceID :many SELECT - id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline + id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds + workspace_builds_with_initiator WHERE - workspace_builds.workspace_id = $1 + workspace_builds_with_initiator.workspace_id = $1 AND CASE -- This allows using the last element on a page as effectively a cursor. -- This is an important option for scripts that need to paginate without @@ -3138,7 +3142,7 @@ type GetWorkspaceBuildByWorkspaceIDParams struct { LimitOpt int32 `db:"limit_opt" json:"limit_opt"` } -func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuild, error) { +func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuildsWithInitiator, error) { rows, err := q.db.QueryContext(ctx, getWorkspaceBuildByWorkspaceID, arg.WorkspaceID, arg.AfterID, @@ -3149,9 +3153,9 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg Get return nil, err } defer rows.Close() - var items []WorkspaceBuild + var items []WorkspaceBuildsWithInitiator for rows.Next() { - var i WorkspaceBuild + var i WorkspaceBuildsWithInitiator if err := rows.Scan( &i.ID, &i.CreatedAt, @@ -3165,6 +3169,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg Get &i.ProvisionerState, &i.JobID, &i.Deadline, + &i.InitiatorUsername, ); err != nil { return nil, err } @@ -3181,9 +3186,9 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg Get const getWorkspaceBuildByWorkspaceIDAndName = `-- name: GetWorkspaceBuildByWorkspaceIDAndName :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline + id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds + workspace_builds_with_initiator WHERE workspace_id = $1 AND "name" = $2 @@ -3194,9 +3199,9 @@ type GetWorkspaceBuildByWorkspaceIDAndNameParams struct { Name string `db:"name" json:"name"` } -func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuild, error) { +func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuildsWithInitiator, error) { row := q.db.QueryRowContext(ctx, getWorkspaceBuildByWorkspaceIDAndName, arg.WorkspaceID, arg.Name) - var i WorkspaceBuild + var i WorkspaceBuildsWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, @@ -3210,6 +3215,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, &i.ProvisionerState, &i.JobID, &i.Deadline, + &i.InitiatorUsername, ) return i, err } diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql index 5b53a874060e8..42fe081eae1cc 100644 --- a/coderd/database/queries/workspacebuilds.sql +++ b/coderd/database/queries/workspacebuilds.sql @@ -2,7 +2,7 @@ SELECT * FROM - workspace_builds + workspace_builds_with_initiator WHERE id = $1 LIMIT @@ -12,7 +12,7 @@ LIMIT SELECT * FROM - workspace_builds + workspace_builds_with_initiator WHERE job_id = $1 LIMIT @@ -22,7 +22,7 @@ LIMIT SELECT * FROM - workspace_builds + workspace_builds_with_initiator WHERE workspace_id = $1 AND "name" = $2; @@ -31,9 +31,9 @@ WHERE SELECT * FROM - workspace_builds + workspace_builds_with_initiator WHERE - workspace_builds.workspace_id = $1 + workspace_builds_with_initiator.workspace_id = $1 AND CASE -- This allows using the last element on a page as effectively a cursor. -- This is an important option for scripts that need to paginate without @@ -63,7 +63,7 @@ LIMIT SELECT * FROM - workspace_builds + workspace_builds_with_initiator WHERE workspace_id = $1 ORDER BY @@ -77,14 +77,14 @@ FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds + workspace_builds_with_initiator WHERE workspace_id = ANY(@ids :: uuid [ ]) GROUP BY workspace_id ) m JOIN - workspace_builds wb + workspace_builds_with_initiator wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number; diff --git a/coderd/httpmw/workspacebuildparam.go b/coderd/httpmw/workspacebuildparam.go index 719a2b5c842ba..9b463bc54404f 100644 --- a/coderd/httpmw/workspacebuildparam.go +++ b/coderd/httpmw/workspacebuildparam.go @@ -16,8 +16,8 @@ import ( type workspaceBuildParamContextKey struct{} // WorkspaceBuildParam returns the workspace build from the ExtractWorkspaceBuildParam handler. -func WorkspaceBuildParam(r *http.Request) database.WorkspaceBuild { - workspaceBuild, ok := r.Context().Value(workspaceBuildParamContextKey{}).(database.WorkspaceBuild) +func WorkspaceBuildParam(r *http.Request) database.WorkspaceBuildsWithInitiator { + workspaceBuild, ok := r.Context().Value(workspaceBuildParamContextKey{}).(database.WorkspaceBuildsWithInitiator) if !ok { panic("developer error: workspace build param middleware not provided") } diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 5a2f567572f84..9ac450495e410 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -62,7 +62,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { return } - var builds []database.WorkspaceBuild + var builds []database.WorkspaceBuildsWithInitiator // Ensure all db calls happen in the same tx err := api.Database.InTx(func(store database.Store) error { var err error @@ -309,7 +309,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { return } - var workspaceBuild database.WorkspaceBuild + var workspaceBuild database.WorkspaceBuildsWithInitiator var provisionerJob database.ProvisionerJob // This must happen in a transaction to ensure history can be inserted, and // the prior history can update it's "after" column to point at the new. @@ -341,7 +341,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { state = priorHistory.ProvisionerState } - workspaceBuild, err = db.InsertWorkspaceBuild(r.Context(), database.InsertWorkspaceBuildParams{ + insertedBuild, err := db.InsertWorkspaceBuild(r.Context(), database.InsertWorkspaceBuildParams{ ID: workspaceBuildID, CreatedAt: database.Now(), UpdatedAt: database.Now(), @@ -358,6 +358,11 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { return xerrors.Errorf("insert workspace build: %w", err) } + workspaceBuild, err = db.GetWorkspaceBuildByID(r.Context(), insertedBuild.ID) + if err != nil { + return xerrors.Errorf("fetch inserted workspace build: %w", err) + } + return nil }) if err != nil { @@ -510,7 +515,7 @@ func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) { func convertWorkspaceBuild( workspaceOwner database.User, workspace database.Workspace, - workspaceBuild database.WorkspaceBuild, + workspaceBuild database.WorkspaceBuildsWithInitiator, job database.ProvisionerJob) codersdk.WorkspaceBuild { //nolint:unconvert if workspace.ID != workspaceBuild.WorkspaceID { @@ -529,6 +534,7 @@ func convertWorkspaceBuild( Name: workspaceBuild.Name, Transition: codersdk.WorkspaceTransition(workspaceBuild.Transition), InitiatorID: workspaceBuild.InitiatorID, + InitiatorUsername: workspaceBuild.InitiatorUsername, Job: convertProvisionerJob(job), Deadline: workspaceBuild.Deadline, } diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 25fd67d581cba..a7eb6e975d38b 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -361,7 +361,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req } var provisionerJob database.ProvisionerJob - var workspaceBuild database.WorkspaceBuild + var workspaceBuild database.WorkspaceBuildsWithInitiator err = api.Database.InTx(func(db database.Store) error { now := database.Now() workspaceBuildID := uuid.New() @@ -418,7 +418,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req if err != nil { return xerrors.Errorf("insert provisioner job: %w", err) } - workspaceBuild, err = db.InsertWorkspaceBuild(r.Context(), database.InsertWorkspaceBuildParams{ + insertedBuild, err := db.InsertWorkspaceBuild(r.Context(), database.InsertWorkspaceBuildParams{ ID: workspaceBuildID, CreatedAt: now, UpdatedAt: now, @@ -434,6 +434,11 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req if err != nil { return xerrors.Errorf("insert workspace build: %w", err) } + + workspaceBuild, err = db.GetWorkspaceBuildByID(r.Context(), insertedBuild.ID) + if err != nil { + return xerrors.Errorf("fetch inserted workspace build: %w", err) + } return nil }) if err != nil { @@ -738,9 +743,9 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data return nil, xerrors.Errorf("get provisioner jobs: %w", err) } - buildByWorkspaceID := map[uuid.UUID]database.WorkspaceBuild{} + buildByWorkspaceID := map[uuid.UUID]database.WorkspaceBuildsWithInitiator{} for _, workspaceBuild := range workspaceBuilds { - buildByWorkspaceID[workspaceBuild.WorkspaceID] = database.WorkspaceBuild{ + buildByWorkspaceID[workspaceBuild.WorkspaceID] = database.WorkspaceBuildsWithInitiator{ ID: workspaceBuild.ID, CreatedAt: workspaceBuild.CreatedAt, UpdatedAt: workspaceBuild.UpdatedAt, @@ -753,6 +758,7 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data ProvisionerState: workspaceBuild.ProvisionerState, JobID: workspaceBuild.JobID, Deadline: workspaceBuild.Deadline, + InitiatorUsername: workspaceBuild.InitiatorUsername, } } templateByID := map[uuid.UUID]database.Template{} @@ -791,7 +797,7 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data } func convertWorkspace( workspace database.Workspace, - workspaceBuild database.WorkspaceBuild, + workspaceBuild database.WorkspaceBuildsWithInitiator, job database.ProvisionerJob, template database.Template, owner database.User) codersdk.Workspace { diff --git a/codersdk/workspacebuilds.go b/codersdk/workspacebuilds.go index ccf3e917f5d63..ec5dfcbc63ccd 100644 --- a/codersdk/workspacebuilds.go +++ b/codersdk/workspacebuilds.go @@ -34,6 +34,7 @@ type WorkspaceBuild struct { Name string `json:"name"` Transition WorkspaceTransition `json:"transition"` InitiatorID uuid.UUID `json:"initiator_id"` + InitiatorUsername string `json:"initiator_name"` Job ProvisionerJob `json:"job"` Deadline time.Time `json:"deadline"` } From 8beccfa829be511fa7347583babf19f4f97804ee Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 7 Jun 2022 15:36:18 -0500 Subject: [PATCH 2/4] Rename type --- .../autobuild/executor/lifecycle_executor.go | 2 +- coderd/database/databasefake/databasefake.go | 34 +++++++------- coderd/database/dump.sql | 2 +- ...space_builds_with_initiaitor_view.down.sql | 2 +- ...rkspace_builds_with_initiaitor_view.up.sql | 2 +- coderd/database/models.go | 2 +- coderd/database/querier.go | 12 ++--- coderd/database/queries.sql.go | 44 +++++++++---------- coderd/database/queries/workspacebuilds.sql | 16 +++---- coderd/httpmw/workspacebuildparam.go | 4 +- coderd/workspacebuilds.go | 6 +-- coderd/workspaces.go | 8 ++-- site/src/api/typesGenerated.ts | 1 + 13 files changed, 68 insertions(+), 67 deletions(-) diff --git a/coderd/autobuild/executor/lifecycle_executor.go b/coderd/autobuild/executor/lifecycle_executor.go index 048f30eb2479b..cd4a65c0534fe 100644 --- a/coderd/autobuild/executor/lifecycle_executor.go +++ b/coderd/autobuild/executor/lifecycle_executor.go @@ -190,7 +190,7 @@ func (e *Executor) runOnce(t time.Time) Stats { // TODO(cian): this function duplicates most of api.postWorkspaceBuilds. Refactor. // See: https://github.com/coder/coder/issues/1401 -func build(ctx context.Context, store database.Store, workspace database.Workspace, trans database.WorkspaceTransition, priorHistory database.WorkspaceBuildsWithInitiator, priorJob database.ProvisionerJob) error { +func build(ctx context.Context, store database.Store, workspace database.Workspace, trans database.WorkspaceTransition, priorHistory database.WorkspaceBuildWithInitiator, priorJob database.ProvisionerJob) error { template, err := store.GetTemplateByID(ctx, workspace.TemplateID) if err != nil { return xerrors.Errorf("get workspace template: %w", err) diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 34be00e2a972a..7f18879b0843b 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -476,7 +476,7 @@ func (q *fakeQuerier) GetWorkspaceOwnerCountsByTemplateIDs(_ context.Context, te return res, nil } -func (q *fakeQuerier) GetWorkspaceBuildByID(_ context.Context, id uuid.UUID) (database.WorkspaceBuildsWithInitiator, error) { +func (q *fakeQuerier) GetWorkspaceBuildByID(_ context.Context, id uuid.UUID) (database.WorkspaceBuildWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -485,10 +485,10 @@ func (q *fakeQuerier) GetWorkspaceBuildByID(_ context.Context, id uuid.UUID) (da return q.workspaceBuildWithInitiator(history), nil } } - return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows + return database.WorkspaceBuildWithInitiator{}, sql.ErrNoRows } -func (q *fakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuildsWithInitiator, error) { +func (q *fakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuildWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -497,14 +497,14 @@ func (q *fakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUI return q.workspaceBuildWithInitiator(build), nil } } - return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows + return database.WorkspaceBuildWithInitiator{}, sql.ErrNoRows } -func (q *fakeQuerier) GetLatestWorkspaceBuildByWorkspaceID(_ context.Context, workspaceID uuid.UUID) (database.WorkspaceBuildsWithInitiator, error) { +func (q *fakeQuerier) GetLatestWorkspaceBuildByWorkspaceID(_ context.Context, workspaceID uuid.UUID) (database.WorkspaceBuildWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() - var row database.WorkspaceBuildsWithInitiator + var row database.WorkspaceBuildWithInitiator var buildNum int32 for _, workspaceBuild := range q.workspaceBuilds { if workspaceBuild.WorkspaceID.String() == workspaceID.String() && workspaceBuild.BuildNumber > buildNum { @@ -513,16 +513,16 @@ func (q *fakeQuerier) GetLatestWorkspaceBuildByWorkspaceID(_ context.Context, wo } } if buildNum == 0 { - return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows + return database.WorkspaceBuildWithInitiator{}, sql.ErrNoRows } return row, nil } -func (q *fakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceBuildsWithInitiator, error) { +func (q *fakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceBuildWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() - builds := make(map[uuid.UUID]database.WorkspaceBuildsWithInitiator) + builds := make(map[uuid.UUID]database.WorkspaceBuildWithInitiator) buildNumbers := make(map[uuid.UUID]int32) for _, workspaceBuild := range q.workspaceBuilds { for _, id := range ids { @@ -532,7 +532,7 @@ func (q *fakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, } } } - var returnBuilds []database.WorkspaceBuildsWithInitiator + var returnBuilds []database.WorkspaceBuildWithInitiator for i, n := range buildNumbers { if n > 0 { b := builds[i] @@ -546,11 +546,11 @@ func (q *fakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, } func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceID(_ context.Context, - params database.GetWorkspaceBuildByWorkspaceIDParams) ([]database.WorkspaceBuildsWithInitiator, error) { + params database.GetWorkspaceBuildByWorkspaceIDParams) ([]database.WorkspaceBuildWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() - history := make([]database.WorkspaceBuildsWithInitiator, 0) + history := make([]database.WorkspaceBuildWithInitiator, 0) for _, workspaceBuild := range q.workspaceBuilds { if workspaceBuild.WorkspaceID.String() == params.WorkspaceID.String() { history = append(history, q.workspaceBuildWithInitiator(workspaceBuild)) @@ -558,7 +558,7 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceID(_ context.Context, } // Order by build_number - slices.SortFunc(history, func(a, b database.WorkspaceBuildsWithInitiator) bool { + slices.SortFunc(history, func(a, b database.WorkspaceBuildWithInitiator) bool { // use greater than since we want descending order return a.BuildNumber > b.BuildNumber }) @@ -600,7 +600,7 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceID(_ context.Context, return history, nil } -func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndNameParams) (database.WorkspaceBuildsWithInitiator, error) { +func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndNameParams) (database.WorkspaceBuildWithInitiator, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -614,16 +614,16 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, a return q.workspaceBuildWithInitiator(workspaceBuild), nil } - return database.WorkspaceBuildsWithInitiator{}, sql.ErrNoRows + return database.WorkspaceBuildWithInitiator{}, sql.ErrNoRows } -func (q *fakeQuerier) workspaceBuildWithInitiator(build database.WorkspaceBuild) database.WorkspaceBuildsWithInitiator { +func (q *fakeQuerier) workspaceBuildWithInitiator(build database.WorkspaceBuild) database.WorkspaceBuildWithInitiator { username := "unknown" usr, err := q.GetUserByID(context.Background(), build.InitiatorID) if err == nil { username = usr.Username } - return database.WorkspaceBuildsWithInitiator{ + return database.WorkspaceBuildWithInitiator{ ID: build.ID, CreatedAt: build.CreatedAt, UpdatedAt: build.UpdatedAt, diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 59ea7a2bfeeb0..4f2b8fccc7581 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -308,7 +308,7 @@ CREATE TABLE workspace_builds ( deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL ); -CREATE VIEW workspace_builds_with_initiator AS +CREATE VIEW workspace_build_with_initiator AS SELECT workspace_builds.id, workspace_builds.created_at, workspace_builds.updated_at, diff --git a/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql index 1b2c020806002..ea0132a60cfbe 100644 --- a/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql +++ b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.down.sql @@ -1 +1 @@ -DROP VIEW IF EXISTS workspace_builds_with_initiator; +DROP VIEW IF EXISTS workspace_build_with_initiator; diff --git a/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql index 7db0990e0e8f0..e7079772bbee2 100644 --- a/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql +++ b/coderd/database/migrations/000022_workspace_builds_with_initiaitor_view.up.sql @@ -1,6 +1,6 @@ -- This view adds the initiator name to the query for UI purposes. -- Showing the initiator user ID is not very friendly. -CREATE VIEW workspace_builds_with_initiator AS +CREATE VIEW workspace_build_with_initiator AS -- If the user is nil, just use 'unknown' for now. SELECT workspace_builds.*, coalesce(users.username, 'unknown') AS initiator_username FROM workspace_builds diff --git a/coderd/database/models.go b/coderd/database/models.go index ef725e0b0dc9f..8a3f57d0c0ff4 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -521,7 +521,7 @@ type WorkspaceBuild struct { Deadline time.Time `db:"deadline" json:"deadline"` } -type WorkspaceBuildsWithInitiator struct { +type WorkspaceBuildWithInitiator struct { ID uuid.UUID `db:"id" json:"id"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` diff --git a/coderd/database/querier.go b/coderd/database/querier.go index c5fc4a9405430..35ea1d10a2796 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -30,8 +30,8 @@ type querier interface { GetAuthorizationUserRoles(ctx context.Context, userID uuid.UUID) (GetAuthorizationUserRolesRow, error) GetFileByHash(ctx context.Context, hash string) (File, error) GetGitSSHKey(ctx context.Context, userID uuid.UUID) (GitSSHKey, error) - GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuildsWithInitiator, error) - GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuildsWithInitiator, error) + GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuildWithInitiator, error) + GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuildWithInitiator, error) GetOrganizationByID(ctx context.Context, id uuid.UUID) (Organization, error) GetOrganizationByName(ctx context.Context, name string) (Organization, error) GetOrganizationIDsByMemberIDs(ctx context.Context, ids []uuid.UUID) ([]GetOrganizationIDsByMemberIDsRow, error) @@ -67,10 +67,10 @@ type querier interface { GetWorkspaceAppByAgentIDAndName(ctx context.Context, arg GetWorkspaceAppByAgentIDAndNameParams) (WorkspaceApp, error) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid.UUID) ([]WorkspaceApp, error) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceApp, error) - GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuildsWithInitiator, error) - GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuildsWithInitiator, error) - GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuildsWithInitiator, error) - GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuildsWithInitiator, error) + GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuildWithInitiator, error) + GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuildWithInitiator, error) + GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuildWithInitiator, error) + GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuildWithInitiator, error) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (Workspace, error) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg GetWorkspaceByOwnerIDAndNameParams) (Workspace, error) GetWorkspaceOwnerCountsByTemplateIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceOwnerCountsByTemplateIDsRow, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 145c5d8df3385..a86acca68c245 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -2954,7 +2954,7 @@ const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildBy SELECT id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE workspace_id = $1 ORDER BY @@ -2963,9 +2963,9 @@ LIMIT 1 ` -func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuildsWithInitiator, error) { +func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (WorkspaceBuildWithInitiator, error) { row := q.db.QueryRowContext(ctx, getLatestWorkspaceBuildByWorkspaceID, workspaceID) - var i WorkspaceBuildsWithInitiator + var i WorkspaceBuildWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, @@ -2990,26 +2990,26 @@ FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE workspace_id = ANY($1 :: uuid [ ]) GROUP BY workspace_id ) m JOIN - workspace_builds_with_initiator wb + workspace_build_with_initiator wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number ` -func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuildsWithInitiator, error) { +func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuildWithInitiator, error) { rows, err := q.db.QueryContext(ctx, getLatestWorkspaceBuildsByWorkspaceIDs, pq.Array(ids)) if err != nil { return nil, err } defer rows.Close() - var items []WorkspaceBuildsWithInitiator + var items []WorkspaceBuildWithInitiator for rows.Next() { - var i WorkspaceBuildsWithInitiator + var i WorkspaceBuildWithInitiator if err := rows.Scan( &i.ID, &i.CreatedAt, @@ -3042,16 +3042,16 @@ const getWorkspaceBuildByID = `-- name: GetWorkspaceBuildByID :one SELECT id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE id = $1 LIMIT 1 ` -func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuildsWithInitiator, error) { +func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuildWithInitiator, error) { row := q.db.QueryRowContext(ctx, getWorkspaceBuildByID, id) - var i WorkspaceBuildsWithInitiator + var i WorkspaceBuildWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, @@ -3074,16 +3074,16 @@ const getWorkspaceBuildByJobID = `-- name: GetWorkspaceBuildByJobID :one SELECT id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE job_id = $1 LIMIT 1 ` -func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuildsWithInitiator, error) { +func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuildWithInitiator, error) { row := q.db.QueryRowContext(ctx, getWorkspaceBuildByJobID, jobID) - var i WorkspaceBuildsWithInitiator + var i WorkspaceBuildWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, @@ -3106,9 +3106,9 @@ const getWorkspaceBuildByWorkspaceID = `-- name: GetWorkspaceBuildByWorkspaceID SELECT id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE - workspace_builds_with_initiator.workspace_id = $1 + workspace_build_with_initiator.workspace_id = $1 AND CASE -- This allows using the last element on a page as effectively a cursor. -- This is an important option for scripts that need to paginate without @@ -3142,7 +3142,7 @@ type GetWorkspaceBuildByWorkspaceIDParams struct { LimitOpt int32 `db:"limit_opt" json:"limit_opt"` } -func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuildsWithInitiator, error) { +func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDParams) ([]WorkspaceBuildWithInitiator, error) { rows, err := q.db.QueryContext(ctx, getWorkspaceBuildByWorkspaceID, arg.WorkspaceID, arg.AfterID, @@ -3153,9 +3153,9 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceID(ctx context.Context, arg Get return nil, err } defer rows.Close() - var items []WorkspaceBuildsWithInitiator + var items []WorkspaceBuildWithInitiator for rows.Next() { - var i WorkspaceBuildsWithInitiator + var i WorkspaceBuildWithInitiator if err := rows.Scan( &i.ID, &i.CreatedAt, @@ -3188,7 +3188,7 @@ const getWorkspaceBuildByWorkspaceIDAndName = `-- name: GetWorkspaceBuildByWorks SELECT id, created_at, updated_at, workspace_id, template_version_id, name, build_number, transition, initiator_id, provisioner_state, job_id, deadline, initiator_username FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE workspace_id = $1 AND "name" = $2 @@ -3199,9 +3199,9 @@ type GetWorkspaceBuildByWorkspaceIDAndNameParams struct { Name string `db:"name" json:"name"` } -func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuildsWithInitiator, error) { +func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndNameParams) (WorkspaceBuildWithInitiator, error) { row := q.db.QueryRowContext(ctx, getWorkspaceBuildByWorkspaceIDAndName, arg.WorkspaceID, arg.Name) - var i WorkspaceBuildsWithInitiator + var i WorkspaceBuildWithInitiator err := row.Scan( &i.ID, &i.CreatedAt, diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql index 42fe081eae1cc..85060245fa4a8 100644 --- a/coderd/database/queries/workspacebuilds.sql +++ b/coderd/database/queries/workspacebuilds.sql @@ -2,7 +2,7 @@ SELECT * FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE id = $1 LIMIT @@ -12,7 +12,7 @@ LIMIT SELECT * FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE job_id = $1 LIMIT @@ -22,7 +22,7 @@ LIMIT SELECT * FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE workspace_id = $1 AND "name" = $2; @@ -31,9 +31,9 @@ WHERE SELECT * FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE - workspace_builds_with_initiator.workspace_id = $1 + workspace_build_with_initiator.workspace_id = $1 AND CASE -- This allows using the last element on a page as effectively a cursor. -- This is an important option for scripts that need to paginate without @@ -63,7 +63,7 @@ LIMIT SELECT * FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE workspace_id = $1 ORDER BY @@ -77,14 +77,14 @@ FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds_with_initiator + workspace_build_with_initiator WHERE workspace_id = ANY(@ids :: uuid [ ]) GROUP BY workspace_id ) m JOIN - workspace_builds_with_initiator wb + workspace_build_with_initiator wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number; diff --git a/coderd/httpmw/workspacebuildparam.go b/coderd/httpmw/workspacebuildparam.go index 9b463bc54404f..63f6ecfd727d4 100644 --- a/coderd/httpmw/workspacebuildparam.go +++ b/coderd/httpmw/workspacebuildparam.go @@ -16,8 +16,8 @@ import ( type workspaceBuildParamContextKey struct{} // WorkspaceBuildParam returns the workspace build from the ExtractWorkspaceBuildParam handler. -func WorkspaceBuildParam(r *http.Request) database.WorkspaceBuildsWithInitiator { - workspaceBuild, ok := r.Context().Value(workspaceBuildParamContextKey{}).(database.WorkspaceBuildsWithInitiator) +func WorkspaceBuildParam(r *http.Request) database.WorkspaceBuildWithInitiator { + workspaceBuild, ok := r.Context().Value(workspaceBuildParamContextKey{}).(database.WorkspaceBuildWithInitiator) if !ok { panic("developer error: workspace build param middleware not provided") } diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 9ac450495e410..9943525ae9cc9 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -62,7 +62,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { return } - var builds []database.WorkspaceBuildsWithInitiator + var builds []database.WorkspaceBuildWithInitiator // Ensure all db calls happen in the same tx err := api.Database.InTx(func(store database.Store) error { var err error @@ -309,7 +309,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { return } - var workspaceBuild database.WorkspaceBuildsWithInitiator + var workspaceBuild database.WorkspaceBuildWithInitiator var provisionerJob database.ProvisionerJob // This must happen in a transaction to ensure history can be inserted, and // the prior history can update it's "after" column to point at the new. @@ -515,7 +515,7 @@ func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) { func convertWorkspaceBuild( workspaceOwner database.User, workspace database.Workspace, - workspaceBuild database.WorkspaceBuildsWithInitiator, + workspaceBuild database.WorkspaceBuildWithInitiator, job database.ProvisionerJob) codersdk.WorkspaceBuild { //nolint:unconvert if workspace.ID != workspaceBuild.WorkspaceID { diff --git a/coderd/workspaces.go b/coderd/workspaces.go index a7eb6e975d38b..4af6abd4ee6a3 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -361,7 +361,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req } var provisionerJob database.ProvisionerJob - var workspaceBuild database.WorkspaceBuildsWithInitiator + var workspaceBuild database.WorkspaceBuildWithInitiator err = api.Database.InTx(func(db database.Store) error { now := database.Now() workspaceBuildID := uuid.New() @@ -743,9 +743,9 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data return nil, xerrors.Errorf("get provisioner jobs: %w", err) } - buildByWorkspaceID := map[uuid.UUID]database.WorkspaceBuildsWithInitiator{} + buildByWorkspaceID := map[uuid.UUID]database.WorkspaceBuildWithInitiator{} for _, workspaceBuild := range workspaceBuilds { - buildByWorkspaceID[workspaceBuild.WorkspaceID] = database.WorkspaceBuildsWithInitiator{ + buildByWorkspaceID[workspaceBuild.WorkspaceID] = database.WorkspaceBuildWithInitiator{ ID: workspaceBuild.ID, CreatedAt: workspaceBuild.CreatedAt, UpdatedAt: workspaceBuild.UpdatedAt, @@ -797,7 +797,7 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data } func convertWorkspace( workspace database.Workspace, - workspaceBuild database.WorkspaceBuildsWithInitiator, + workspaceBuild database.WorkspaceBuildWithInitiator, job database.ProvisionerJob, template database.Template, owner database.User) codersdk.Workspace { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index e403fe80fddff..326f7e189f363 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -447,6 +447,7 @@ export interface WorkspaceBuild { readonly name: string readonly transition: WorkspaceTransition readonly initiator_id: string + readonly initiator_name: string readonly job: ProvisionerJob readonly deadline: string } From 6df96ef49514cdd2aa62404b3e1a452742360441 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 7 Jun 2022 15:40:35 -0500 Subject: [PATCH 3/4] Assert username in single workspace build fetch --- coderd/workspacebuilds_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 5b15f54c29d52..1734f52b836f9 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -33,15 +33,18 @@ func TestWorkspaceBuilds(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + first := coderdtest.CreateFirstUser(t, client) + user, err := client.User(context.Background(), codersdk.Me) + require.NoError(t, err, "fetch me") + version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil) + template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) builds, err := client.WorkspaceBuilds(context.Background(), codersdk.WorkspaceBuildsRequest{WorkspaceID: workspace.ID}) require.Len(t, builds, 1) require.Equal(t, int32(1), builds[0].BuildNumber) + require.Equal(t, user.Username, builds[0].InitiatorUsername) require.NoError(t, err) }) From 454aea7f85dcefb736789cb7e47872e62a19401c Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 7 Jun 2022 15:43:47 -0500 Subject: [PATCH 4/4] Add field to ts mock --- site/src/testHelpers/entities.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index c58097d01d9be..d409a5a026d62 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -131,6 +131,7 @@ export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = { created_at: "2022-05-17T17:39:01.382927298Z", id: "1", initiator_id: "", + initiator_name: "unknown", job: MockProvisionerJob, name: "a-workspace-build", template_version_id: "",