From eddc78233edb72a248640c96a302f79c75f3a3ab Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 20 Jul 2023 11:33:36 -0400 Subject: [PATCH 01/14] include minimial user on template version and build --- coderd/activitybump.go | 2 +- coderd/activitybump_test.go | 2 +- coderd/database/dbauthz/dbauthz.go | 34 +-- coderd/database/dbauthz/dbauthz_test.go | 2 +- coderd/database/dbfake/dbfake.go | 40 ++-- coderd/database/dbgen/dbgen.go | 78 ++++--- coderd/database/dbmetrics/dbmetrics.go | 30 +-- coderd/database/dbmock/dbmock.go | 35 ++- coderd/database/dump.sql | 93 +++++--- .../000140_join_users_build_version.down.sql | 6 + .../000140_join_users_build_version.up.sql | 38 +++ coderd/database/models.go | 81 +++++-- coderd/database/querier.go | 10 +- coderd/database/queries.sql.go | 221 +++++++----------- coderd/database/queries/templateversions.sql | 24 +- coderd/database/queries/workspacebuilds.sql | 32 +-- coderd/database/sqlc.yaml | 7 +- coderd/metricscache/metricscache_test.go | 2 +- .../prometheusmetrics_test.go | 2 +- .../provisionerdserver/provisionerdserver.go | 4 +- .../provisionerdserver_test.go | 5 +- coderd/templates.go | 2 +- coderd/templateversions.go | 113 +++------ coderd/unhanger/detector.go | 2 +- coderd/workspaces.go | 2 +- coderd/wsbuilder/wsbuilder.go | 66 +++--- codersdk/templateversions.go | 2 +- codersdk/users.go | 8 + enterprise/audit/table.go | 54 +++-- enterprise/coderd/workspacequota.go | 2 +- site/src/api/typesGenerated.ts | 9 +- 31 files changed, 541 insertions(+), 467 deletions(-) create mode 100644 coderd/database/migrations/000140_join_users_build_version.down.sql create mode 100644 coderd/database/migrations/000140_join_users_build_version.up.sql diff --git a/coderd/activitybump.go b/coderd/activitybump.go index 4682f19ceb72d..972d59a31f93b 100644 --- a/coderd/activitybump.go +++ b/coderd/activitybump.go @@ -74,7 +74,7 @@ func activityBumpWorkspace(ctx context.Context, log slog.Logger, db database.Sto newDeadline = build.MaxDeadline } - if _, err := s.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ + if err := s.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ ID: build.ID, UpdatedAt: database.Now(), ProvisionerState: build.ProvisionerState, diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 46cb261b3501b..b9c757e98986e 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -92,7 +92,7 @@ func TestWorkspaceActivityBump(t *testing.T) { dbBuild, err := db.GetWorkspaceBuildByID(ctx, workspace.LatestBuild.ID) require.NoError(t, err) - _, err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ + err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ ID: workspace.LatestBuild.ID, UpdatedAt: database.Now(), ProvisionerState: dbBuild.ProvisionerState, diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 57bcd12c96354..31d23a370d072 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1816,23 +1816,23 @@ func (q *querier) InsertTemplate(ctx context.Context, arg database.InsertTemplat return q.db.InsertTemplate(ctx, arg) } -func (q *querier) InsertTemplateVersion(ctx context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) { +func (q *querier) InsertTemplateVersion(ctx context.Context, arg database.InsertTemplateVersionParams) error { if !arg.TemplateID.Valid { // Making a new template version is the same permission as creating a new template. err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceTemplate.InOrg(arg.OrganizationID)) if err != nil { - return database.TemplateVersion{}, err + return err } } else { // Must do an authorized fetch to prevent leaking template ids this way. tpl, err := q.GetTemplateByID(ctx, arg.TemplateID.UUID) if err != nil { - return database.TemplateVersion{}, err + return err } // Check the create permission on the template. err = q.authorizeContext(ctx, rbac.ActionCreate, tpl) if err != nil { - return database.TemplateVersion{}, err + return err } } @@ -1931,10 +1931,10 @@ func (q *querier) InsertWorkspaceApp(ctx context.Context, arg database.InsertWor return q.db.InsertWorkspaceApp(ctx, arg) } -func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) { +func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) error { w, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID) if err != nil { - return database.WorkspaceBuild{}, err + return err } var action rbac.Action = rbac.ActionUpdate @@ -1943,7 +1943,7 @@ func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertW } if err = q.authorizeContext(ctx, action, w.WorkspaceBuildRBAC(arg.Transition)); err != nil { - return database.WorkspaceBuild{}, err + return err } return q.db.InsertWorkspaceBuild(ctx, arg) @@ -2172,11 +2172,11 @@ func (q *querier) UpdateTemplateScheduleByID(ctx context.Context, arg database.U return update(q.log, q.auth, fetch, q.db.UpdateTemplateScheduleByID)(ctx, arg) } -func (q *querier) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) { +func (q *querier) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) error { // An actor is allowed to update the template version if they are authorized to update the template. tv, err := q.db.GetTemplateVersionByID(ctx, arg.ID) if err != nil { - return database.TemplateVersion{}, err + return err } var obj rbac.Objecter if !tv.TemplateID.Valid { @@ -2184,12 +2184,12 @@ func (q *querier) UpdateTemplateVersionByID(ctx context.Context, arg database.Up } else { tpl, err := q.db.GetTemplateByID(ctx, tv.TemplateID.UUID) if err != nil { - return database.TemplateVersion{}, err + return err } obj = tpl } if err := q.authorizeContext(ctx, rbac.ActionUpdate, obj); err != nil { - return database.TemplateVersion{}, err + return err } return q.db.UpdateTemplateVersionByID(ctx, arg) } @@ -2445,28 +2445,28 @@ func (q *querier) UpdateWorkspaceAutostart(ctx context.Context, arg database.Upd return update(q.log, q.auth, fetch, q.db.UpdateWorkspaceAutostart)(ctx, arg) } -func (q *querier) UpdateWorkspaceBuildByID(ctx context.Context, arg database.UpdateWorkspaceBuildByIDParams) (database.WorkspaceBuild, error) { +func (q *querier) UpdateWorkspaceBuildByID(ctx context.Context, arg database.UpdateWorkspaceBuildByIDParams) error { build, err := q.db.GetWorkspaceBuildByID(ctx, arg.ID) if err != nil { - return database.WorkspaceBuild{}, err + return err } workspace, err := q.db.GetWorkspaceByID(ctx, build.WorkspaceID) if err != nil { - return database.WorkspaceBuild{}, err + return err } err = q.authorizeContext(ctx, rbac.ActionUpdate, workspace.RBACObject()) if err != nil { - return database.WorkspaceBuild{}, err + return err } return q.db.UpdateWorkspaceBuildByID(ctx, arg) } // UpdateWorkspaceBuildCostByID is used by the provisioning system to update the cost of a workspace build. -func (q *querier) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) (database.WorkspaceBuild, error) { +func (q *querier) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { if err := q.authorizeContext(ctx, rbac.ActionUpdate, rbac.ResourceSystem); err != nil { - return database.WorkspaceBuild{}, err + return err } return q.db.UpdateWorkspaceBuildCostByID(ctx, arg) } diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 6a4f09260b7ab..aff10510e20bb 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1377,7 +1377,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(database.UpdateWorkspaceBuildCostByIDParams{ ID: b.ID, DailyCost: 10, - }).Asserts(rbac.ResourceSystem, rbac.ActionUpdate).Returns(o) + }).Asserts(rbac.ResourceSystem, rbac.ActionUpdate) })) s.Run("UpsertLastUpdateCheck", s.Subtest(func(db database.Store, check *expects) { check.Args("value").Asserts(rbac.ResourceSystem, rbac.ActionUpdate) diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index b1ae1e05b4cb4..d378b4cf67c5b 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -473,7 +473,7 @@ func (q *FakeQuerier) templateWithUserNoLock(tpl database.TemplateTable) databas d, _ := json.Marshal(tpl) _ = json.Unmarshal(d, &withUser) withUser.CreatedByUsername = user.Username - withUser.CreatedByAvatarURL = user.AvatarURL.String + withUser.CreatedByAvatarURL = user.AvatarURL return withUser } @@ -3489,13 +3489,13 @@ func (q *FakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl return nil } -func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) { +func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.InsertTemplateVersionParams) error { if err := validateDatabaseType(arg); err != nil { - return database.TemplateVersion{}, err + return err } if len(arg.Message) > 1048576 { - return database.TemplateVersion{}, xerrors.New("message too long") + return xerrors.New("message too long") } q.mutex.Lock() @@ -3515,7 +3515,7 @@ func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.Inse CreatedBy: arg.CreatedBy, } q.templateVersions = append(q.templateVersions, version) - return version, nil + return nil } func (q *FakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg database.InsertTemplateVersionParameterParams) (database.TemplateVersionParameter, error) { @@ -3846,9 +3846,9 @@ func (q *FakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertW return workspaceApp, nil } -func (q *FakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) { +func (q *FakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.InsertWorkspaceBuildParams) error { if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceBuild{}, err + return err } q.mutex.Lock() @@ -3869,7 +3869,7 @@ func (q *FakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.Inser Reason: arg.Reason, } q.workspaceBuilds = append(q.workspaceBuilds, workspaceBuild) - return workspaceBuild, nil + return nil } func (q *FakeQuerier) InsertWorkspaceBuildParameters(_ context.Context, arg database.InsertWorkspaceBuildParametersParams) error { @@ -4308,9 +4308,9 @@ func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database return sql.ErrNoRows } -func (q *FakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) { +func (q *FakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) error { if err := validateDatabaseType(arg); err != nil { - return database.TemplateVersion{}, err + return err } q.mutex.Lock() @@ -4325,9 +4325,9 @@ func (q *FakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database. templateVersion.Name = arg.Name templateVersion.Message = arg.Message q.templateVersions[index] = templateVersion - return templateVersion, nil + return nil } - return database.TemplateVersion{}, sql.ErrNoRows + return sql.ErrNoRows } func (q *FakeQuerier) UpdateTemplateVersionDescriptionByJobID(_ context.Context, arg database.UpdateTemplateVersionDescriptionByJobIDParams) error { @@ -4771,9 +4771,9 @@ func (q *FakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.U return sql.ErrNoRows } -func (q *FakeQuerier) UpdateWorkspaceBuildByID(_ context.Context, arg database.UpdateWorkspaceBuildByIDParams) (database.WorkspaceBuild, error) { +func (q *FakeQuerier) UpdateWorkspaceBuildByID(_ context.Context, arg database.UpdateWorkspaceBuildByIDParams) error { if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceBuild{}, err + return err } q.mutex.Lock() @@ -4788,14 +4788,14 @@ func (q *FakeQuerier) UpdateWorkspaceBuildByID(_ context.Context, arg database.U workspaceBuild.Deadline = arg.Deadline workspaceBuild.MaxDeadline = arg.MaxDeadline q.workspaceBuilds[index] = workspaceBuild - return workspaceBuild, nil + return nil } - return database.WorkspaceBuild{}, sql.ErrNoRows + return sql.ErrNoRows } -func (q *FakeQuerier) UpdateWorkspaceBuildCostByID(_ context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) (database.WorkspaceBuild, error) { +func (q *FakeQuerier) UpdateWorkspaceBuildCostByID(_ context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceBuild{}, err + return err } q.mutex.Lock() @@ -4807,9 +4807,9 @@ func (q *FakeQuerier) UpdateWorkspaceBuildCostByID(_ context.Context, arg databa } workspaceBuild.DailyCost = arg.DailyCost q.workspaceBuilds[index] = workspaceBuild - return workspaceBuild, nil + return nil } - return database.WorkspaceBuild{}, sql.ErrNoRows + return sql.ErrNoRows } func (q *FakeQuerier) UpdateWorkspaceDeletedByID(_ context.Context, arg database.UpdateWorkspaceDeletedByIDParams) error { diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 383e4b2fe5c19..ebe76f9f8891a 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -180,21 +180,34 @@ func Workspace(t testing.TB, db database.Store, orig database.Workspace) databas } func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuild) database.WorkspaceBuild { - build, err := db.InsertWorkspaceBuild(genCtx, database.InsertWorkspaceBuildParams{ - ID: takeFirst(orig.ID, uuid.New()), - CreatedAt: takeFirst(orig.CreatedAt, database.Now()), - UpdatedAt: takeFirst(orig.UpdatedAt, database.Now()), - WorkspaceID: takeFirst(orig.WorkspaceID, uuid.New()), - TemplateVersionID: takeFirst(orig.TemplateVersionID, uuid.New()), - BuildNumber: takeFirst(orig.BuildNumber, 1), - Transition: takeFirst(orig.Transition, database.WorkspaceTransitionStart), - InitiatorID: takeFirst(orig.InitiatorID, uuid.New()), - JobID: takeFirst(orig.JobID, uuid.New()), - ProvisionerState: takeFirstSlice(orig.ProvisionerState, []byte{}), - Deadline: takeFirst(orig.Deadline, database.Now().Add(time.Hour)), - Reason: takeFirst(orig.Reason, database.BuildReasonInitiator), - }) + id := takeFirst(orig.ID, uuid.New()) + var build database.WorkspaceBuild + err := db.InTx(func(store database.Store) error { + err := db.InsertWorkspaceBuild(genCtx, database.InsertWorkspaceBuildParams{ + ID: takeFirst(orig.ID, uuid.New()), + CreatedAt: takeFirst(orig.CreatedAt, database.Now()), + UpdatedAt: takeFirst(orig.UpdatedAt, database.Now()), + WorkspaceID: takeFirst(orig.WorkspaceID, uuid.New()), + TemplateVersionID: takeFirst(orig.TemplateVersionID, uuid.New()), + BuildNumber: takeFirst(orig.BuildNumber, 1), + Transition: takeFirst(orig.Transition, database.WorkspaceTransitionStart), + InitiatorID: takeFirst(orig.InitiatorID, uuid.New()), + JobID: takeFirst(orig.JobID, uuid.New()), + ProvisionerState: takeFirstSlice(orig.ProvisionerState, []byte{}), + Deadline: takeFirst(orig.Deadline, database.Now().Add(time.Hour)), + Reason: takeFirst(orig.Reason, database.BuildReasonInitiator), + }) + if err != nil { + return err + } + build, err = db.GetWorkspaceBuildByID(genCtx, id) + if err != nil { + return err + } + return nil + }, nil) require.NoError(t, err, "insert workspace build") + return build } @@ -474,19 +487,32 @@ func GitAuthLink(t testing.TB, db database.Store, orig database.GitAuthLink) dat } func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVersion) database.TemplateVersion { - version, err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{ - ID: takeFirst(orig.ID, uuid.New()), - TemplateID: orig.TemplateID, - OrganizationID: takeFirst(orig.OrganizationID, uuid.New()), - CreatedAt: takeFirst(orig.CreatedAt, database.Now()), - UpdatedAt: takeFirst(orig.UpdatedAt, database.Now()), - Name: takeFirst(orig.Name, namesgenerator.GetRandomName(1)), - Message: orig.Message, - Readme: takeFirst(orig.Readme, namesgenerator.GetRandomName(1)), - JobID: takeFirst(orig.JobID, uuid.New()), - CreatedBy: takeFirst(orig.CreatedBy, uuid.New()), - }) + var version database.TemplateVersion + err := db.InTx(func(db database.Store) error { + err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{ + ID: takeFirst(orig.ID, uuid.New()), + TemplateID: orig.TemplateID, + OrganizationID: takeFirst(orig.OrganizationID, uuid.New()), + CreatedAt: takeFirst(orig.CreatedAt, database.Now()), + UpdatedAt: takeFirst(orig.UpdatedAt, database.Now()), + Name: takeFirst(orig.Name, namesgenerator.GetRandomName(1)), + Message: orig.Message, + Readme: takeFirst(orig.Readme, namesgenerator.GetRandomName(1)), + JobID: takeFirst(orig.JobID, uuid.New()), + CreatedBy: takeFirst(orig.CreatedBy, uuid.New()), + }) + if err != nil { + return err + } + + version, err = db.GetTemplateVersionByID(genCtx, version.ID) + if err != nil { + return err + } + return nil + }, nil) require.NoError(t, err, "insert template version") + return version } diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index e202f7bbc2992..a27b59b9118a4 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -1110,11 +1110,11 @@ func (m metricsStore) InsertTemplate(ctx context.Context, arg database.InsertTem return err } -func (m metricsStore) InsertTemplateVersion(ctx context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) { +func (m metricsStore) InsertTemplateVersion(ctx context.Context, arg database.InsertTemplateVersionParams) error { start := time.Now() - version, err := m.s.InsertTemplateVersion(ctx, arg) + err := m.s.InsertTemplateVersion(ctx, arg) m.queryLatencies.WithLabelValues("InsertTemplateVersion").Observe(time.Since(start).Seconds()) - return version, err + return err } func (m metricsStore) InsertTemplateVersionParameter(ctx context.Context, arg database.InsertTemplateVersionParameterParams) (database.TemplateVersionParameter, error) { @@ -1194,11 +1194,11 @@ func (m metricsStore) InsertWorkspaceApp(ctx context.Context, arg database.Inser return app, err } -func (m metricsStore) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) { +func (m metricsStore) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) error { start := time.Now() - build, err := m.s.InsertWorkspaceBuild(ctx, arg) + err := m.s.InsertWorkspaceBuild(ctx, arg) m.queryLatencies.WithLabelValues("InsertWorkspaceBuild").Observe(time.Since(start).Seconds()) - return build, err + return err } func (m metricsStore) InsertWorkspaceBuildParameters(ctx context.Context, arg database.InsertWorkspaceBuildParametersParams) error { @@ -1341,11 +1341,11 @@ func (m metricsStore) UpdateTemplateScheduleByID(ctx context.Context, arg databa return err } -func (m metricsStore) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) { +func (m metricsStore) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) error { start := time.Now() - version, err := m.s.UpdateTemplateVersionByID(ctx, arg) + err := m.s.UpdateTemplateVersionByID(ctx, arg) m.queryLatencies.WithLabelValues("UpdateTemplateVersionByID").Observe(time.Since(start).Seconds()) - return version, err + return err } func (m metricsStore) UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg database.UpdateTemplateVersionDescriptionByJobIDParams) error { @@ -1488,18 +1488,18 @@ func (m metricsStore) UpdateWorkspaceAutostart(ctx context.Context, arg database return err } -func (m metricsStore) UpdateWorkspaceBuildByID(ctx context.Context, arg database.UpdateWorkspaceBuildByIDParams) (database.WorkspaceBuild, error) { +func (m metricsStore) UpdateWorkspaceBuildByID(ctx context.Context, arg database.UpdateWorkspaceBuildByIDParams) error { start := time.Now() - build, err := m.s.UpdateWorkspaceBuildByID(ctx, arg) + err := m.s.UpdateWorkspaceBuildByID(ctx, arg) m.queryLatencies.WithLabelValues("UpdateWorkspaceBuildByID").Observe(time.Since(start).Seconds()) - return build, err + return err } -func (m metricsStore) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) (database.WorkspaceBuild, error) { +func (m metricsStore) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { start := time.Now() - build, err := m.s.UpdateWorkspaceBuildCostByID(ctx, arg) + err := m.s.UpdateWorkspaceBuildCostByID(ctx, arg) m.queryLatencies.WithLabelValues("UpdateWorkspaceBuildCostByID").Observe(time.Since(start).Seconds()) - return build, err + return err } func (m metricsStore) UpdateWorkspaceDeletedByID(ctx context.Context, arg database.UpdateWorkspaceDeletedByIDParams) error { diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 2a63a4c83f2c4..03dc3113c7c08 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -2332,12 +2332,11 @@ func (mr *MockStoreMockRecorder) InsertTemplate(arg0, arg1 interface{}) *gomock. } // InsertTemplateVersion mocks base method. -func (m *MockStore) InsertTemplateVersion(arg0 context.Context, arg1 database.InsertTemplateVersionParams) (database.TemplateVersion, error) { +func (m *MockStore) InsertTemplateVersion(arg0 context.Context, arg1 database.InsertTemplateVersionParams) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "InsertTemplateVersion", arg0, arg1) - ret0, _ := ret[0].(database.TemplateVersion) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // InsertTemplateVersion indicates an expected call of InsertTemplateVersion. @@ -2510,12 +2509,11 @@ func (mr *MockStoreMockRecorder) InsertWorkspaceApp(arg0, arg1 interface{}) *gom } // InsertWorkspaceBuild mocks base method. -func (m *MockStore) InsertWorkspaceBuild(arg0 context.Context, arg1 database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) { +func (m *MockStore) InsertWorkspaceBuild(arg0 context.Context, arg1 database.InsertWorkspaceBuildParams) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "InsertWorkspaceBuild", arg0, arg1) - ret0, _ := ret[0].(database.WorkspaceBuild) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // InsertWorkspaceBuild indicates an expected call of InsertWorkspaceBuild. @@ -2830,12 +2828,11 @@ func (mr *MockStoreMockRecorder) UpdateTemplateScheduleByID(arg0, arg1 interface } // UpdateTemplateVersionByID mocks base method. -func (m *MockStore) UpdateTemplateVersionByID(arg0 context.Context, arg1 database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) { +func (m *MockStore) UpdateTemplateVersionByID(arg0 context.Context, arg1 database.UpdateTemplateVersionByIDParams) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateTemplateVersionByID", arg0, arg1) - ret0, _ := ret[0].(database.TemplateVersion) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // UpdateTemplateVersionByID indicates an expected call of UpdateTemplateVersionByID. @@ -3134,12 +3131,11 @@ func (mr *MockStoreMockRecorder) UpdateWorkspaceAutostart(arg0, arg1 interface{} } // UpdateWorkspaceBuildByID mocks base method. -func (m *MockStore) UpdateWorkspaceBuildByID(arg0 context.Context, arg1 database.UpdateWorkspaceBuildByIDParams) (database.WorkspaceBuild, error) { +func (m *MockStore) UpdateWorkspaceBuildByID(arg0 context.Context, arg1 database.UpdateWorkspaceBuildByIDParams) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateWorkspaceBuildByID", arg0, arg1) - ret0, _ := ret[0].(database.WorkspaceBuild) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // UpdateWorkspaceBuildByID indicates an expected call of UpdateWorkspaceBuildByID. @@ -3149,12 +3145,11 @@ func (mr *MockStoreMockRecorder) UpdateWorkspaceBuildByID(arg0, arg1 interface{} } // UpdateWorkspaceBuildCostByID mocks base method. -func (m *MockStore) UpdateWorkspaceBuildCostByID(arg0 context.Context, arg1 database.UpdateWorkspaceBuildCostByIDParams) (database.WorkspaceBuild, error) { +func (m *MockStore) UpdateWorkspaceBuildCostByID(arg0 context.Context, arg1 database.UpdateWorkspaceBuildCostByIDParams) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateWorkspaceBuildCostByID", arg0, arg1) - ret0, _ := ret[0].(database.WorkspaceBuild) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // UpdateWorkspaceBuildCostByID indicates an expected call of UpdateWorkspaceBuildCostByID. diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index f486d162e15c4..637c48eb7b694 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -544,6 +544,51 @@ COMMENT ON COLUMN template_versions.git_auth_providers IS 'IDs of Git auth provi COMMENT ON COLUMN template_versions.message IS 'Message describing the changes in this version of the template, similar to a Git commit message. Like a commit message, this should be a short, high-level description of the changes in this version of the template. This message is immutable and should not be updated after the fact.'; +CREATE TABLE users ( + id uuid NOT NULL, + email text NOT NULL, + username text DEFAULT ''::text NOT NULL, + hashed_password bytea NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + status user_status DEFAULT 'active'::user_status NOT NULL, + rbac_roles text[] DEFAULT '{}'::text[] NOT NULL, + login_type login_type DEFAULT 'password'::login_type NOT NULL, + avatar_url text, + deleted boolean DEFAULT false NOT NULL, + last_seen_at timestamp without time zone DEFAULT '0001-01-01 00:00:00'::timestamp without time zone NOT NULL, + quiet_hours_schedule text DEFAULT ''::text NOT NULL +); + +COMMENT ON COLUMN users.quiet_hours_schedule IS 'Daily (!) cron schedule (with optional CRON_TZ) signifying the start of the user''s quiet hours. If empty, the default quiet hours on the instance is used instead.'; + +CREATE VIEW visible_users AS + SELECT users.id, + users.username, + users.avatar_url + FROM users; + +COMMENT ON VIEW visible_users IS 'Visible fields of users are allowed to be joined with other tables for including context of other resources.'; + +CREATE VIEW template_version_with_user AS + SELECT template_versions.id, + template_versions.template_id, + template_versions.organization_id, + template_versions.created_at, + template_versions.updated_at, + template_versions.name, + template_versions.readme, + template_versions.job_id, + template_versions.created_by, + template_versions.git_auth_providers, + template_versions.message, + COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url, + COALESCE(visible_users.username, ''::text) AS created_by_username + FROM (public.template_versions + LEFT JOIN visible_users ON ((template_versions.created_by = visible_users.id))); + +COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.'; + CREATE TABLE templates ( id uuid NOT NULL, created_at timestamp with time zone NOT NULL, @@ -585,32 +630,6 @@ COMMENT ON COLUMN templates.restart_requirement_days_of_week IS 'A bitmap of day COMMENT ON COLUMN templates.restart_requirement_weeks IS 'The number of weeks between restarts. 0 or 1 weeks means "every week", 2 week means "every second week", etc. Weeks are counted from January 2, 2023, which is the first Monday of 2023. This is to ensure workspaces are started consistently for all customers on the same n-week cycles.'; -CREATE TABLE users ( - id uuid NOT NULL, - email text NOT NULL, - username text DEFAULT ''::text NOT NULL, - hashed_password bytea NOT NULL, - created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL, - status user_status DEFAULT 'active'::user_status NOT NULL, - rbac_roles text[] DEFAULT '{}'::text[] NOT NULL, - login_type login_type DEFAULT 'password'::login_type NOT NULL, - avatar_url text, - deleted boolean DEFAULT false NOT NULL, - last_seen_at timestamp without time zone DEFAULT '0001-01-01 00:00:00'::timestamp without time zone NOT NULL, - quiet_hours_schedule text DEFAULT ''::text NOT NULL -); - -COMMENT ON COLUMN users.quiet_hours_schedule IS 'Daily (!) cron schedule (with optional CRON_TZ) signifying the start of the user''s quiet hours. If empty, the default quiet hours on the instance is used instead.'; - -CREATE VIEW visible_users AS - SELECT users.id, - users.username, - users.avatar_url - FROM users; - -COMMENT ON VIEW visible_users IS 'Visible fields of users are allowed to be joined with other tables for including context of other resources.'; - CREATE VIEW template_with_users AS SELECT templates.id, templates.created_at, @@ -811,6 +830,28 @@ CREATE TABLE workspace_builds ( max_deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL ); +CREATE VIEW workspace_build_with_user AS + SELECT workspace_builds.id, + workspace_builds.created_at, + workspace_builds.updated_at, + workspace_builds.workspace_id, + workspace_builds.template_version_id, + workspace_builds.build_number, + workspace_builds.transition, + workspace_builds.initiator_id, + workspace_builds.provisioner_state, + workspace_builds.job_id, + workspace_builds.deadline, + workspace_builds.reason, + workspace_builds.daily_cost, + workspace_builds.max_deadline, + COALESCE(visible_users.avatar_url, ''::text) AS initiator_by_avatar_url, + COALESCE(visible_users.username, ''::text) AS initiator_by_username + FROM (public.workspace_builds + LEFT JOIN visible_users ON ((workspace_builds.initiator_id = visible_users.id))); + +COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; + CREATE TABLE workspace_proxies ( id uuid NOT NULL, name text NOT NULL, diff --git a/coderd/database/migrations/000140_join_users_build_version.down.sql b/coderd/database/migrations/000140_join_users_build_version.down.sql new file mode 100644 index 0000000000000..0c27698e8c1e9 --- /dev/null +++ b/coderd/database/migrations/000140_join_users_build_version.down.sql @@ -0,0 +1,6 @@ +BEGIN; + +DROP VIEW workspace_build_with_user; +DROP VIEW template_version_with_user; + +COMMIT; diff --git a/coderd/database/migrations/000140_join_users_build_version.up.sql b/coderd/database/migrations/000140_join_users_build_version.up.sql new file mode 100644 index 0000000000000..eed74c09b03ce --- /dev/null +++ b/coderd/database/migrations/000140_join_users_build_version.up.sql @@ -0,0 +1,38 @@ +BEGIN; + +-- If you need to update this view, put 'DROP VIEW workspace_build_with_user;' before this. +CREATE VIEW + workspace_build_with_user +AS +SELECT + workspace_builds.*, + coalesce(visible_users.avatar_url, '') AS initiator_by_avatar_url, + coalesce(visible_users.username, '') AS initiator_by_username +FROM + workspace_builds + LEFT JOIN + visible_users + ON + workspace_builds.initiator_id = visible_users.id; + +COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; + + +-- If you need to update this view, put 'DROP VIEW template_version_with_user;' before this. +CREATE VIEW + template_version_with_user +AS +SELECT + template_versions.*, + coalesce(visible_users.avatar_url, '') AS created_by_avatar_url, + coalesce(visible_users.username, '') AS created_by_username +FROM + template_versions + LEFT JOIN + visible_users + ON + template_versions.created_by = visible_users.id; + +COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.'; + +COMMIT; diff --git a/coderd/database/models.go b/coderd/database/models.go index 2fb9fbb244abd..62d3bfcfd00a4 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1593,7 +1593,7 @@ type Template struct { LockedTTL int64 `db:"locked_ttl" json:"locked_ttl"` RestartRequirementDaysOfWeek int16 `db:"restart_requirement_days_of_week" json:"restart_requirement_days_of_week"` RestartRequirementWeeks int64 `db:"restart_requirement_weeks" json:"restart_requirement_weeks"` - CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"` + CreatedByAvatarURL sql.NullString `db:"created_by_avatar_url" json:"created_by_avatar_url"` CreatedByUsername string `db:"created_by_username" json:"created_by_username"` } @@ -1631,20 +1631,21 @@ type TemplateTable struct { RestartRequirementWeeks int64 `db:"restart_requirement_weeks" json:"restart_requirement_weeks"` } +// Joins in the username + avatar url of the created by user. type TemplateVersion struct { - ID uuid.UUID `db:"id" json:"id"` - TemplateID uuid.NullUUID `db:"template_id" json:"template_id"` - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - Name string `db:"name" json:"name"` - Readme string `db:"readme" json:"readme"` - JobID uuid.UUID `db:"job_id" json:"job_id"` - CreatedBy uuid.UUID `db:"created_by" json:"created_by"` - // IDs of Git auth providers for a specific template version - GitAuthProviders []string `db:"git_auth_providers" json:"git_auth_providers"` - // Message describing the changes in this version of the template, similar to a Git commit message. Like a commit message, this should be a short, high-level description of the changes in this version of the template. This message is immutable and should not be updated after the fact. - Message string `db:"message" json:"message"` + ID uuid.UUID `db:"id" json:"id"` + TemplateID uuid.NullUUID `db:"template_id" json:"template_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + Name string `db:"name" json:"name"` + Readme string `db:"readme" json:"readme"` + JobID uuid.UUID `db:"job_id" json:"job_id"` + CreatedBy uuid.UUID `db:"created_by" json:"created_by"` + GitAuthProviders []string `db:"git_auth_providers" json:"git_auth_providers"` + Message string `db:"message" json:"message"` + CreatedByAvatarURL sql.NullString `db:"created_by_avatar_url" json:"created_by_avatar_url"` + CreatedByUsername string `db:"created_by_username" json:"created_by_username"` } type TemplateVersionParameter struct { @@ -1683,6 +1684,22 @@ type TemplateVersionParameter struct { Ephemeral bool `db:"ephemeral" json:"ephemeral"` } +type TemplateVersionTable struct { + ID uuid.UUID `db:"id" json:"id"` + TemplateID uuid.NullUUID `db:"template_id" json:"template_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + Name string `db:"name" json:"name"` + Readme string `db:"readme" json:"readme"` + JobID uuid.UUID `db:"job_id" json:"job_id"` + CreatedBy uuid.UUID `db:"created_by" json:"created_by"` + // IDs of Git auth providers for a specific template version + GitAuthProviders []string `db:"git_auth_providers" json:"git_auth_providers"` + // Message describing the changes in this version of the template, similar to a Git commit message. Like a commit message, this should be a short, high-level description of the changes in this version of the template. This message is immutable and should not be updated after the fact. + Message string `db:"message" json:"message"` +} + type TemplateVersionVariable struct { TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"` // Variable name @@ -1857,7 +1874,35 @@ type WorkspaceApp struct { External bool `db:"external" json:"external"` } +// Joins in the username + avatar url of the initiated by user. type WorkspaceBuild 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"` + 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"` + Reason BuildReason `db:"reason" json:"reason"` + DailyCost int32 `db:"daily_cost" json:"daily_cost"` + MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` + InitiatorByAvatarUrl sql.NullString `db:"initiator_by_avatar_url" json:"initiator_by_avatar_url"` + InitiatorByUsername string `db:"initiator_by_username" json:"initiator_by_username"` +} + +type WorkspaceBuildParameter struct { + WorkspaceBuildID uuid.UUID `db:"workspace_build_id" json:"workspace_build_id"` + // Parameter name + Name string `db:"name" json:"name"` + // Parameter value + Value string `db:"value" json:"value"` +} + +type WorkspaceBuildTable 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"` @@ -1874,14 +1919,6 @@ type WorkspaceBuild struct { MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` } -type WorkspaceBuildParameter struct { - WorkspaceBuildID uuid.UUID `db:"workspace_build_id" json:"workspace_build_id"` - // Parameter name - Name string `db:"name" json:"name"` - // Parameter value - Value string `db:"value" json:"value"` -} - type WorkspaceProxy struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 05b5a07acdf32..950ea9c2c79db 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -192,7 +192,7 @@ type sqlcQuerier interface { InsertProvisionerJobLogs(ctx context.Context, arg InsertProvisionerJobLogsParams) ([]ProvisionerJobLog, error) InsertReplica(ctx context.Context, arg InsertReplicaParams) (Replica, error) InsertTemplate(ctx context.Context, arg InsertTemplateParams) error - InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) (TemplateVersion, error) + InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) error InsertTemplateVersionParameter(ctx context.Context, arg InsertTemplateVersionParameterParams) (TemplateVersionParameter, error) InsertTemplateVersionVariable(ctx context.Context, arg InsertTemplateVersionVariableParams) (TemplateVersionVariable, error) InsertUser(ctx context.Context, arg InsertUserParams) (User, error) @@ -205,7 +205,7 @@ type sqlcQuerier interface { InsertWorkspaceAgentStartupLogs(ctx context.Context, arg InsertWorkspaceAgentStartupLogsParams) ([]WorkspaceAgentStartupLog, error) InsertWorkspaceAgentStat(ctx context.Context, arg InsertWorkspaceAgentStatParams) (WorkspaceAgentStat, error) InsertWorkspaceApp(ctx context.Context, arg InsertWorkspaceAppParams) (WorkspaceApp, error) - InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) (WorkspaceBuild, error) + InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) error InsertWorkspaceBuildParameters(ctx context.Context, arg InsertWorkspaceBuildParametersParams) error InsertWorkspaceProxy(ctx context.Context, arg InsertWorkspaceProxyParams) (WorkspaceProxy, error) InsertWorkspaceResource(ctx context.Context, arg InsertWorkspaceResourceParams) (WorkspaceResource, error) @@ -230,7 +230,7 @@ type sqlcQuerier interface { UpdateTemplateDeletedByID(ctx context.Context, arg UpdateTemplateDeletedByIDParams) error UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) error - UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) (TemplateVersion, error) + UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) error UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg UpdateTemplateVersionDescriptionByJobIDParams) error UpdateTemplateVersionGitAuthProvidersByJobID(ctx context.Context, arg UpdateTemplateVersionGitAuthProvidersByJobIDParams) error UpdateUserDeletedByID(ctx context.Context, arg UpdateUserDeletedByIDParams) error @@ -251,8 +251,8 @@ type sqlcQuerier interface { UpdateWorkspaceAgentStartupLogOverflowByID(ctx context.Context, arg UpdateWorkspaceAgentStartupLogOverflowByIDParams) error UpdateWorkspaceAppHealthByID(ctx context.Context, arg UpdateWorkspaceAppHealthByIDParams) error UpdateWorkspaceAutostart(ctx context.Context, arg UpdateWorkspaceAutostartParams) error - UpdateWorkspaceBuildByID(ctx context.Context, arg UpdateWorkspaceBuildByIDParams) (WorkspaceBuild, error) - UpdateWorkspaceBuildCostByID(ctx context.Context, arg UpdateWorkspaceBuildCostByIDParams) (WorkspaceBuild, error) + UpdateWorkspaceBuildByID(ctx context.Context, arg UpdateWorkspaceBuildByIDParams) error + UpdateWorkspaceBuildCostByID(ctx context.Context, arg UpdateWorkspaceBuildCostByIDParams) error UpdateWorkspaceDeletedByID(ctx context.Context, arg UpdateWorkspaceDeletedByIDParams) error UpdateWorkspaceLastUsedAt(ctx context.Context, arg UpdateWorkspaceLastUsedAtParams) error UpdateWorkspaceLockedAt(ctx context.Context, arg UpdateWorkspaceLockedAtParams) error diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index e5786aad31a63..ccc4171681126 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -4243,13 +4243,13 @@ func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg Ins const getPreviousTemplateVersion = `-- name: GetPreviousTemplateVersion :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message, created_by_avatar_url, created_by_username FROM - template_versions + template_version_with_user AS template_versions WHERE created_at < ( SELECT created_at - FROM template_versions AS tv + FROM template_version_with_user AS tv WHERE tv.organization_id = $1 AND tv.name = $2 AND tv.template_id = $3 ) AND organization_id = $1 @@ -4279,15 +4279,17 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev &i.CreatedBy, pq.Array(&i.GitAuthProviders), &i.Message, + &i.CreatedByAvatarURL, + &i.CreatedByUsername, ) return i, err } const getTemplateVersionByID = `-- name: GetTemplateVersionByID :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message, created_by_avatar_url, created_by_username FROM - template_versions + template_version_with_user AS template_versions WHERE id = $1 ` @@ -4307,15 +4309,17 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) ( &i.CreatedBy, pq.Array(&i.GitAuthProviders), &i.Message, + &i.CreatedByAvatarURL, + &i.CreatedByUsername, ) return i, err } const getTemplateVersionByJobID = `-- name: GetTemplateVersionByJobID :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message, created_by_avatar_url, created_by_username FROM - template_versions + template_version_with_user AS template_versions WHERE job_id = $1 ` @@ -4335,15 +4339,17 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U &i.CreatedBy, pq.Array(&i.GitAuthProviders), &i.Message, + &i.CreatedByAvatarURL, + &i.CreatedByUsername, ) return i, err } const getTemplateVersionByTemplateIDAndName = `-- name: GetTemplateVersionByTemplateIDAndName :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message, created_by_avatar_url, created_by_username FROM - template_versions + template_version_with_user AS template_versions WHERE template_id = $1 AND "name" = $2 @@ -4369,15 +4375,17 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context, &i.CreatedBy, pq.Array(&i.GitAuthProviders), &i.Message, + &i.CreatedByAvatarURL, + &i.CreatedByUsername, ) return i, err } const getTemplateVersionsByIDs = `-- name: GetTemplateVersionsByIDs :many SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message, created_by_avatar_url, created_by_username FROM - template_versions + template_version_with_user AS template_versions WHERE id = ANY($1 :: uuid [ ]) ` @@ -4403,6 +4411,8 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU &i.CreatedBy, pq.Array(&i.GitAuthProviders), &i.Message, + &i.CreatedByAvatarURL, + &i.CreatedByUsername, ); err != nil { return nil, err } @@ -4419,9 +4429,9 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU const getTemplateVersionsByTemplateID = `-- name: GetTemplateVersionsByTemplateID :many SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message, created_by_avatar_url, created_by_username FROM - template_versions + template_version_with_user AS template_versions WHERE template_id = $1 :: uuid AND CASE @@ -4485,6 +4495,8 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge &i.CreatedBy, pq.Array(&i.GitAuthProviders), &i.Message, + &i.CreatedByAvatarURL, + &i.CreatedByUsername, ); err != nil { return nil, err } @@ -4500,7 +4512,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge } const getTemplateVersionsCreatedAfter = `-- name: GetTemplateVersionsCreatedAfter :many -SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message FROM template_versions WHERE created_at > $1 +SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message, created_by_avatar_url, created_by_username FROM template_version_with_user AS template_versions WHERE created_at > $1 ` func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error) { @@ -4524,6 +4536,8 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create &i.CreatedBy, pq.Array(&i.GitAuthProviders), &i.Message, + &i.CreatedByAvatarURL, + &i.CreatedByUsername, ); err != nil { return nil, err } @@ -4538,7 +4552,7 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create return items, nil } -const insertTemplateVersion = `-- name: InsertTemplateVersion :one +const insertTemplateVersion = `-- name: InsertTemplateVersion :exec INSERT INTO template_versions ( id, @@ -4553,7 +4567,7 @@ INSERT INTO created_by ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ` type InsertTemplateVersionParams struct { @@ -4569,8 +4583,8 @@ type InsertTemplateVersionParams struct { CreatedBy uuid.UUID `db:"created_by" json:"created_by"` } -func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) (TemplateVersion, error) { - row := q.db.QueryRowContext(ctx, insertTemplateVersion, +func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) error { + _, err := q.db.ExecContext(ctx, insertTemplateVersion, arg.ID, arg.TemplateID, arg.OrganizationID, @@ -4582,24 +4596,10 @@ func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTempla arg.JobID, arg.CreatedBy, ) - var i TemplateVersion - err := row.Scan( - &i.ID, - &i.TemplateID, - &i.OrganizationID, - &i.CreatedAt, - &i.UpdatedAt, - &i.Name, - &i.Readme, - &i.JobID, - &i.CreatedBy, - pq.Array(&i.GitAuthProviders), - &i.Message, - ) - return i, err + return err } -const updateTemplateVersionByID = `-- name: UpdateTemplateVersionByID :one +const updateTemplateVersionByID = `-- name: UpdateTemplateVersionByID :exec UPDATE template_versions SET @@ -4608,7 +4608,7 @@ SET name = $4, message = $5 WHERE - id = $1 RETURNING id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, git_auth_providers, message + id = $1 ` type UpdateTemplateVersionByIDParams struct { @@ -4619,29 +4619,15 @@ type UpdateTemplateVersionByIDParams struct { Message string `db:"message" json:"message"` } -func (q *sqlQuerier) UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) (TemplateVersion, error) { - row := q.db.QueryRowContext(ctx, updateTemplateVersionByID, +func (q *sqlQuerier) UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) error { + _, err := q.db.ExecContext(ctx, updateTemplateVersionByID, arg.ID, arg.TemplateID, arg.UpdatedAt, arg.Name, arg.Message, ) - var i TemplateVersion - err := row.Scan( - &i.ID, - &i.TemplateID, - &i.OrganizationID, - &i.CreatedAt, - &i.UpdatedAt, - &i.Name, - &i.Readme, - &i.JobID, - &i.CreatedBy, - pq.Array(&i.GitAuthProviders), - &i.Message, - ) - return i, err + return err } const updateTemplateVersionDescriptionByJobID = `-- name: UpdateTemplateVersionDescriptionByJobID :exec @@ -7209,9 +7195,9 @@ func (q *sqlQuerier) InsertWorkspaceBuildParameters(ctx context.Context, arg Ins const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildByWorkspaceID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_id = $1 ORDER BY @@ -7238,22 +7224,24 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, w &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ) return i, err } const getLatestWorkspaceBuilds = `-- name: GetLatestWorkspaceBuilds :many -SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline +SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.initiator_by_avatar_url, wb.initiator_by_username FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds + workspace_build_with_user AS workspace_builds GROUP BY workspace_id ) m JOIN - workspace_builds wb + workspace_build_with_user AS wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number ` @@ -7281,6 +7269,8 @@ func (q *sqlQuerier) GetLatestWorkspaceBuilds(ctx context.Context) ([]WorkspaceB &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ); err != nil { return nil, err } @@ -7296,19 +7286,19 @@ func (q *sqlQuerier) GetLatestWorkspaceBuilds(ctx context.Context) ([]WorkspaceB } const getLatestWorkspaceBuildsByWorkspaceIDs = `-- name: GetLatestWorkspaceBuildsByWorkspaceIDs :many -SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline +SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.initiator_by_avatar_url, wb.initiator_by_username FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_id = ANY($1 :: uuid [ ]) GROUP BY workspace_id ) m JOIN - workspace_builds wb + workspace_build_with_user AS wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number ` @@ -7336,6 +7326,8 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ); err != nil { return nil, err } @@ -7352,9 +7344,9 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, const getWorkspaceBuildByID = `-- name: GetWorkspaceBuildByID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE id = $1 LIMIT @@ -7379,15 +7371,17 @@ func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (W &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ) return i, err } const getWorkspaceBuildByJobID = `-- name: GetWorkspaceBuildByJobID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE job_id = $1 LIMIT @@ -7412,15 +7406,17 @@ func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UU &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ) return i, err } const getWorkspaceBuildByWorkspaceIDAndBuildNumber = `-- name: GetWorkspaceBuildByWorkspaceIDAndBuildNumber :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_id = $1 AND build_number = $2 @@ -7449,15 +7445,17 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx context.Co &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ) return i, err } const getWorkspaceBuildsByWorkspaceID = `-- name: GetWorkspaceBuildsByWorkspaceID :many SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_builds.workspace_id = $1 AND workspace_builds.created_at > $2 @@ -7525,6 +7523,8 @@ func (q *sqlQuerier) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg Ge &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ); err != nil { return nil, err } @@ -7540,7 +7540,7 @@ func (q *sqlQuerier) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg Ge } const getWorkspaceBuildsCreatedAfter = `-- name: GetWorkspaceBuildsCreatedAfter :many -SELECT id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline FROM workspace_builds WHERE created_at > $1 +SELECT id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username FROM workspace_build_with_user WHERE created_at > $1 ` func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceBuild, error) { @@ -7567,6 +7567,8 @@ func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, created &i.Reason, &i.DailyCost, &i.MaxDeadline, + &i.InitiatorByAvatarUrl, + &i.InitiatorByUsername, ); err != nil { return nil, err } @@ -7581,7 +7583,7 @@ func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, created return items, nil } -const insertWorkspaceBuild = `-- name: InsertWorkspaceBuild :one +const insertWorkspaceBuild = `-- name: InsertWorkspaceBuild :exec INSERT INTO workspace_builds ( id, @@ -7599,7 +7601,7 @@ INSERT INTO reason ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) ` type InsertWorkspaceBuildParams struct { @@ -7618,8 +7620,8 @@ type InsertWorkspaceBuildParams struct { Reason BuildReason `db:"reason" json:"reason"` } -func (q *sqlQuerier) InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) (WorkspaceBuild, error) { - row := q.db.QueryRowContext(ctx, insertWorkspaceBuild, +func (q *sqlQuerier) InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) error { + _, err := q.db.ExecContext(ctx, insertWorkspaceBuild, arg.ID, arg.CreatedAt, arg.UpdatedAt, @@ -7634,27 +7636,10 @@ func (q *sqlQuerier) InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspa arg.MaxDeadline, arg.Reason, ) - var i WorkspaceBuild - err := row.Scan( - &i.ID, - &i.CreatedAt, - &i.UpdatedAt, - &i.WorkspaceID, - &i.TemplateVersionID, - &i.BuildNumber, - &i.Transition, - &i.InitiatorID, - &i.ProvisionerState, - &i.JobID, - &i.Deadline, - &i.Reason, - &i.DailyCost, - &i.MaxDeadline, - ) - return i, err + return err } -const updateWorkspaceBuildByID = `-- name: UpdateWorkspaceBuildByID :one +const updateWorkspaceBuildByID = `-- name: UpdateWorkspaceBuildByID :exec UPDATE workspace_builds SET @@ -7663,7 +7648,7 @@ SET deadline = $4, max_deadline = $5 WHERE - id = $1 RETURNING id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + id = $1 ` type UpdateWorkspaceBuildByIDParams struct { @@ -7674,41 +7659,24 @@ type UpdateWorkspaceBuildByIDParams struct { MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` } -func (q *sqlQuerier) UpdateWorkspaceBuildByID(ctx context.Context, arg UpdateWorkspaceBuildByIDParams) (WorkspaceBuild, error) { - row := q.db.QueryRowContext(ctx, updateWorkspaceBuildByID, +func (q *sqlQuerier) UpdateWorkspaceBuildByID(ctx context.Context, arg UpdateWorkspaceBuildByIDParams) error { + _, err := q.db.ExecContext(ctx, updateWorkspaceBuildByID, arg.ID, arg.UpdatedAt, arg.ProvisionerState, arg.Deadline, arg.MaxDeadline, ) - var i WorkspaceBuild - err := row.Scan( - &i.ID, - &i.CreatedAt, - &i.UpdatedAt, - &i.WorkspaceID, - &i.TemplateVersionID, - &i.BuildNumber, - &i.Transition, - &i.InitiatorID, - &i.ProvisionerState, - &i.JobID, - &i.Deadline, - &i.Reason, - &i.DailyCost, - &i.MaxDeadline, - ) - return i, err + return err } -const updateWorkspaceBuildCostByID = `-- name: UpdateWorkspaceBuildCostByID :one +const updateWorkspaceBuildCostByID = `-- name: UpdateWorkspaceBuildCostByID :exec UPDATE workspace_builds SET daily_cost = $2 WHERE - id = $1 RETURNING id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline + id = $1 ` type UpdateWorkspaceBuildCostByIDParams struct { @@ -7716,26 +7684,9 @@ type UpdateWorkspaceBuildCostByIDParams struct { DailyCost int32 `db:"daily_cost" json:"daily_cost"` } -func (q *sqlQuerier) UpdateWorkspaceBuildCostByID(ctx context.Context, arg UpdateWorkspaceBuildCostByIDParams) (WorkspaceBuild, error) { - row := q.db.QueryRowContext(ctx, updateWorkspaceBuildCostByID, arg.ID, arg.DailyCost) - var i WorkspaceBuild - err := row.Scan( - &i.ID, - &i.CreatedAt, - &i.UpdatedAt, - &i.WorkspaceID, - &i.TemplateVersionID, - &i.BuildNumber, - &i.Transition, - &i.InitiatorID, - &i.ProvisionerState, - &i.JobID, - &i.Deadline, - &i.Reason, - &i.DailyCost, - &i.MaxDeadline, - ) - return i, err +func (q *sqlQuerier) UpdateWorkspaceBuildCostByID(ctx context.Context, arg UpdateWorkspaceBuildCostByIDParams) error { + _, err := q.db.ExecContext(ctx, updateWorkspaceBuildCostByID, arg.ID, arg.DailyCost) + return err } const getWorkspaceResourceByID = `-- name: GetWorkspaceResourceByID :one diff --git a/coderd/database/queries/templateversions.sql b/coderd/database/queries/templateversions.sql index e60fe42604ec6..b1f83d8e91c8b 100644 --- a/coderd/database/queries/templateversions.sql +++ b/coderd/database/queries/templateversions.sql @@ -2,7 +2,7 @@ SELECT * FROM - template_versions + template_version_with_user AS template_versions WHERE template_id = @template_id :: uuid AND CASE @@ -36,18 +36,18 @@ LIMIT SELECT * FROM - template_versions + template_version_with_user AS template_versions WHERE job_id = $1; -- name: GetTemplateVersionsCreatedAfter :many -SELECT * FROM template_versions WHERE created_at > $1; +SELECT * FROM template_version_with_user AS template_versions WHERE created_at > $1; -- name: GetTemplateVersionByTemplateIDAndName :one SELECT * FROM - template_versions + template_version_with_user AS template_versions WHERE template_id = $1 AND "name" = $2; @@ -56,7 +56,7 @@ WHERE SELECT * FROM - template_versions + template_version_with_user AS template_versions WHERE id = $1; @@ -64,11 +64,11 @@ WHERE SELECT * FROM - template_versions + template_version_with_user AS template_versions WHERE id = ANY(@ids :: uuid [ ]); --- name: InsertTemplateVersion :one +-- name: InsertTemplateVersion :exec INSERT INTO template_versions ( id, @@ -83,9 +83,9 @@ INSERT INTO created_by ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING *; + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10); --- name: UpdateTemplateVersionByID :one +-- name: UpdateTemplateVersionByID :exec UPDATE template_versions SET @@ -94,7 +94,7 @@ SET name = $4, message = $5 WHERE - id = $1 RETURNING *; + id = $1; -- name: UpdateTemplateVersionDescriptionByJobID :exec UPDATE @@ -118,11 +118,11 @@ WHERE SELECT * FROM - template_versions + template_version_with_user AS template_versions WHERE created_at < ( SELECT created_at - FROM template_versions AS tv + FROM template_version_with_user AS tv WHERE tv.organization_id = $1 AND tv.name = $2 AND tv.template_id = $3 ) AND organization_id = $1 diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql index b56be8f1d1de5..ea2ccdb8d08ce 100644 --- a/coderd/database/queries/workspacebuilds.sql +++ b/coderd/database/queries/workspacebuilds.sql @@ -2,7 +2,7 @@ SELECT * FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE id = $1 LIMIT @@ -12,20 +12,20 @@ LIMIT SELECT * FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE job_id = $1 LIMIT 1; -- name: GetWorkspaceBuildsCreatedAfter :many -SELECT * FROM workspace_builds WHERE created_at > $1; +SELECT * FROM workspace_build_with_user WHERE created_at > $1; -- name: GetWorkspaceBuildByWorkspaceIDAndBuildNumber :one SELECT * FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_id = $1 AND build_number = $2; @@ -34,7 +34,7 @@ WHERE SELECT * FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_builds.workspace_id = $1 AND workspace_builds.created_at > @since @@ -67,7 +67,7 @@ LIMIT SELECT * FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_id = $1 ORDER BY @@ -81,14 +81,14 @@ FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds + workspace_build_with_user AS workspace_builds WHERE workspace_id = ANY(@ids :: uuid [ ]) GROUP BY workspace_id ) m JOIN - workspace_builds wb + workspace_build_with_user AS wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number; -- name: GetLatestWorkspaceBuilds :many @@ -97,15 +97,15 @@ FROM ( SELECT workspace_id, MAX(build_number) as max_build_number FROM - workspace_builds + workspace_build_with_user AS workspace_builds GROUP BY workspace_id ) m JOIN - workspace_builds wb + workspace_build_with_user AS wb ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number; --- name: InsertWorkspaceBuild :one +-- name: InsertWorkspaceBuild :exec INSERT INTO workspace_builds ( id, @@ -123,9 +123,9 @@ INSERT INTO reason ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING *; + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13); --- name: UpdateWorkspaceBuildByID :one +-- name: UpdateWorkspaceBuildByID :exec UPDATE workspace_builds SET @@ -134,13 +134,13 @@ SET deadline = $4, max_deadline = $5 WHERE - id = $1 RETURNING *; + id = $1; --- name: UpdateWorkspaceBuildCostByID :one +-- name: UpdateWorkspaceBuildCostByID :exec UPDATE workspace_builds SET daily_cost = $2 WHERE - id = $1 RETURNING *; + id = $1; diff --git a/coderd/database/sqlc.yaml b/coderd/database/sqlc.yaml index 2bb3adea0980d..2a3513d768a67 100644 --- a/coderd/database/sqlc.yaml +++ b/coderd/database/sqlc.yaml @@ -27,12 +27,13 @@ overrides: - column: "template_with_users.group_acl" go_type: type: "TemplateACL" - - column: "template_with_users.created_by_avatar_url" - go_type: - type: "string" rename: template: TemplateTable template_with_user: Template + workspace_build: WorkspaceBuildTable + workspace_build_with_user: WorkspaceBuild + template_version: TemplateVersionTable + template_version_with_user: TemplateVersion api_key: APIKey api_key_scope: APIKeyScope api_key_scope_all: APIKeyScopeAll diff --git a/coderd/metricscache/metricscache_test.go b/coderd/metricscache/metricscache_test.go index d2a1a2a25f4ef..ba4fc498efe90 100644 --- a/coderd/metricscache/metricscache_test.go +++ b/coderd/metricscache/metricscache_test.go @@ -384,7 +384,7 @@ func TestCache_BuildTime(t *testing.T) { }) require.NoError(t, err) - _, err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ + err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ TemplateVersionID: templateVersion.ID, JobID: job.ID, Transition: tt.args.transition, diff --git a/coderd/prometheusmetrics/prometheusmetrics_test.go b/coderd/prometheusmetrics/prometheusmetrics_test.go index 2ece768671280..e6170422aa78b 100644 --- a/coderd/prometheusmetrics/prometheusmetrics_test.go +++ b/coderd/prometheusmetrics/prometheusmetrics_test.go @@ -118,7 +118,7 @@ func TestWorkspaces(t *testing.T) { Type: database.ProvisionerJobTypeWorkspaceBuild, }) require.NoError(t, err) - _, err = db.InsertWorkspaceBuild(context.Background(), database.InsertWorkspaceBuildParams{ + err = db.InsertWorkspaceBuild(context.Background(), database.InsertWorkspaceBuildParams{ ID: uuid.New(), WorkspaceID: uuid.New(), JobID: job.ID, diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 2f92e28e1a9fb..ad0d5b6b4c86f 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -657,7 +657,7 @@ func (server *Server) FailJob(ctx context.Context, failJob *proto.FailedJob) (*p } if jobType.WorkspaceBuild.State != nil { - _, err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ + err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ ID: input.WorkspaceBuildID, UpdatedAt: database.Now(), ProvisionerState: jobType.WorkspaceBuild.State, @@ -941,7 +941,7 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete if err != nil { return xerrors.Errorf("update provisioner job: %w", err) } - _, err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ + err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ ID: workspaceBuild.ID, Deadline: autoStop.Deadline, MaxDeadline: autoStop.MaxDeadline, diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 8a1beddc0b1d4..bb34410957cf2 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -749,7 +749,8 @@ func TestFailJob(t *testing.T) { ID: uuid.New(), }) require.NoError(t, err) - build, err := srv.Database.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ + buildID := uuid.New() + err = srv.Database.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ ID: uuid.New(), WorkspaceID: workspace.ID, Transition: database.WorkspaceTransitionStart, @@ -757,7 +758,7 @@ func TestFailJob(t *testing.T) { }) require.NoError(t, err) input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{ - WorkspaceBuildID: build.ID, + WorkspaceBuildID: buildID, }) require.NoError(t, err) job, err := srv.Database.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ diff --git a/coderd/templates.go b/coderd/templates.go index b53d2a65041e4..4f3d3cf8ce674 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -350,7 +350,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque templateAudit.New = dbTemplate - _, err = tx.UpdateTemplateVersionByID(ctx, database.UpdateTemplateVersionByIDParams{ + err = tx.UpdateTemplateVersionByID(ctx, database.UpdateTemplateVersionByIDParams{ ID: templateVersion.ID, TemplateID: uuid.NullUUID{ UUID: dbTemplate.ID, diff --git a/coderd/templateversions.go b/coderd/templateversions.go index 13fc4420fc7e9..80ad85a3ecc12 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -53,15 +53,6 @@ func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) { return } - user, err := api.Database.GetUserByID(ctx, templateVersion.CreatedBy) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error on fetching user.", - Detail: err.Error(), - }) - return - } - schemas, err := api.Database.GetParameterSchemasByJobID(ctx, jobs[0].ProvisionerJob.ID) if errors.Is(err, sql.ErrNoRows) { err = nil @@ -79,7 +70,7 @@ func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) { warnings = append(warnings, codersdk.TemplateVersionWarningUnsupportedWorkspaces) } - httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), user, warnings)) + httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), warnings)) } // @Summary Patch template version by ID @@ -138,10 +129,16 @@ func (api *API) patchTemplateVersion(rw http.ResponseWriter, r *http.Request) { // It is not allowed to "patch" the template ID, and reassign it. var err error - updatedTemplateVersion, err = tx.UpdateTemplateVersionByID(ctx, updateParams) + err = tx.UpdateTemplateVersionByID(ctx, updateParams) if err != nil { return xerrors.Errorf("error on patching template version: %v", err) } + + updatedTemplateVersion, err = tx.GetTemplateVersionByID(ctx, updateParams.ID) + if err != nil { + return xerrors.Errorf("error on fetching patched template version: %v", err) + } + return nil }, nil) if errors.Is(err, errTemplateVersionNameConflict) { @@ -169,16 +166,7 @@ func (api *API) patchTemplateVersion(rw http.ResponseWriter, r *http.Request) { return } - user, err := api.Database.GetUserByID(ctx, templateVersion.CreatedBy) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error on fetching user.", - Detail: err.Error(), - }) - return - } - - httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(updatedTemplateVersion, convertProvisionerJob(jobs[0]), user, nil)) + httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(updatedTemplateVersion, convertProvisionerJob(jobs[0]), nil)) } // @Summary Cancel template version by ID @@ -784,15 +772,8 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque }) return err } - user, err := store.GetUserByID(ctx, version.CreatedBy) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error on fetching user.", - Detail: err.Error(), - }) - return err - } - apiVersions = append(apiVersions, convertTemplateVersion(version, convertProvisionerJob(job), user, nil)) + + apiVersions = append(apiVersions, convertTemplateVersion(version, convertProvisionerJob(job), nil)) } return nil @@ -847,16 +828,7 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) { return } - user, err := api.Database.GetUserByID(ctx, templateVersion.CreatedBy) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error on fetching user.", - Detail: err.Error(), - }) - return - } - - httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), user, nil)) + httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), nil)) } // @Summary Get template version by organization, template, and name @@ -921,16 +893,7 @@ func (api *API) templateVersionByOrganizationTemplateAndName(rw http.ResponseWri return } - user, err := api.Database.GetUserByID(ctx, templateVersion.CreatedBy) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error on fetching user.", - Detail: err.Error(), - }) - return - } - - httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), user, nil)) + httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), nil)) } // @Summary Get previous template version by organization, template, and name @@ -1016,16 +979,7 @@ func (api *API) previousTemplateVersionByOrganizationTemplateAndName(rw http.Res return } - user, err := api.Database.GetUserByID(ctx, templateVersion.CreatedBy) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error on fetching user.", - Detail: err.Error(), - }) - return - } - - httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(previousTemplateVersion, convertProvisionerJob(jobs[0]), user, nil)) + httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(previousTemplateVersion, convertProvisionerJob(jobs[0]), nil)) } // @Summary Update active template version by template ID @@ -1304,7 +1258,7 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht req.Name = namesgenerator.GetRandomName(1) } - templateVersion, err = tx.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ + err = tx.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ ID: templateVersionID, TemplateID: templateID, OrganizationID: organization.ID, @@ -1319,6 +1273,12 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht if err != nil { return xerrors.Errorf("insert template version: %w", err) } + + templateVersion, err = tx.GetTemplateVersionByID(ctx, templateVersionID) + if err != nil { + return xerrors.Errorf("fetched inserted template version: %w", err) + } + return nil }, nil) if err != nil { @@ -1329,19 +1289,10 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht } aReq.New = templateVersion - user, err := api.Database.GetUserByID(ctx, templateVersion.CreatedBy) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error on fetching user.", - Detail: err.Error(), - }) - return - } - httpapi.Write(ctx, rw, http.StatusCreated, convertTemplateVersion(templateVersion, convertProvisionerJob(database.GetProvisionerJobsByIDsWithQueuePositionRow{ ProvisionerJob: provisionerJob, QueuePosition: 0, - }), user, nil)) + }), nil)) } // templateVersionResources returns the workspace agent resources associated @@ -1408,17 +1359,7 @@ func (api *API) templateVersionLogs(rw http.ResponseWriter, r *http.Request) { api.provisionerJobLogs(rw, r, job) } -func convertTemplateVersion(version database.TemplateVersion, job codersdk.ProvisionerJob, user database.User, warnings []codersdk.TemplateVersionWarning) codersdk.TemplateVersion { - createdBy := codersdk.User{ - ID: user.ID, - Username: user.Username, - Email: user.Email, - CreatedAt: user.CreatedAt, - Status: codersdk.UserStatus(user.Status), - Roles: []codersdk.Role{}, - AvatarURL: user.AvatarURL.String, - } - +func convertTemplateVersion(version database.TemplateVersion, job codersdk.ProvisionerJob, warnings []codersdk.TemplateVersionWarning) codersdk.TemplateVersion { return codersdk.TemplateVersion{ ID: version.ID, TemplateID: &version.TemplateID.UUID, @@ -1429,8 +1370,12 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi Message: version.Message, Job: job, Readme: version.Readme, - CreatedBy: createdBy, - Warnings: warnings, + CreatedBy: codersdk.MinimalUser{ + ID: version.CreatedBy, + Username: version.CreatedByUsername, + AvatarURL: version.CreatedByAvatarURL.String, + }, + Warnings: warnings, } } diff --git a/coderd/unhanger/detector.go b/coderd/unhanger/detector.go index fb81311664984..7622251ce44d3 100644 --- a/coderd/unhanger/detector.go +++ b/coderd/unhanger/detector.go @@ -332,7 +332,7 @@ func unhangJob(ctx context.Context, log slog.Logger, db database.Store, pub pubs return xerrors.Errorf("get previous workspace build: %w", err) } if err == nil { - _, err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ + err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ ID: build.ID, UpdatedAt: database.Now(), ProvisionerState: prevBuild.ProvisionerState, diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 8ac07b5ddd51e..62fe8b01cc72e 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -885,7 +885,7 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) { return xerrors.New("Cannot extend workspace: deadline is beyond max deadline imposed by template") } - if _, err := s.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ + if err := s.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{ ID: build.ID, UpdatedAt: build.UpdatedAt, ProvisionerState: build.ProvisionerState, diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 7f6d840f9db6d..06b4d8c167cf9 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -334,36 +334,50 @@ func (b *Builder) buildTx(authFunc func(action rbac.Action, object rbac.Objecter if err != nil { return nil, nil, BuildError{http.StatusInternalServerError, "compute build state", err} } - workspaceBuild, err := b.store.InsertWorkspaceBuild(b.ctx, database.InsertWorkspaceBuildParams{ - ID: workspaceBuildID, - CreatedAt: now, - UpdatedAt: now, - WorkspaceID: b.workspace.ID, - TemplateVersionID: templateVersionID, - BuildNumber: buildNum, - ProvisionerState: state, - InitiatorID: b.initiator, - Transition: b.trans, - JobID: provisionerJob.ID, - Reason: b.reason, - }) - if err != nil { - return nil, nil, BuildError{http.StatusInternalServerError, "insert workspace build", err} - } - names, values, err := b.getParameters() + var workspaceBuild database.WorkspaceBuild + err = b.store.InTx(func(store database.Store) error { + err = store.InsertWorkspaceBuild(b.ctx, database.InsertWorkspaceBuildParams{ + ID: workspaceBuildID, + CreatedAt: now, + UpdatedAt: now, + WorkspaceID: b.workspace.ID, + TemplateVersionID: templateVersionID, + BuildNumber: buildNum, + ProvisionerState: state, + InitiatorID: b.initiator, + Transition: b.trans, + JobID: provisionerJob.ID, + Reason: b.reason, + }) + if err != nil { + return BuildError{http.StatusInternalServerError, "insert workspace build", err} + } + + names, values, err := b.getParameters() + if err != nil { + // getParameters already wraps errors in BuildError + return err + } + err = store.InsertWorkspaceBuildParameters(b.ctx, database.InsertWorkspaceBuildParametersParams{ + WorkspaceBuildID: workspaceBuildID, + Name: names, + Value: values, + }) + if err != nil { + return BuildError{http.StatusInternalServerError, "insert workspace build parameters: %w", err} + } + + workspaceBuild, err = store.GetWorkspaceBuildByID(b.ctx, workspaceBuildID) + if err != nil { + return BuildError{http.StatusInternalServerError, "get workspace build", err} + } + + return nil + }, nil) if err != nil { - // getParameters already wraps errors in BuildError return nil, nil, err } - err = b.store.InsertWorkspaceBuildParameters(b.ctx, database.InsertWorkspaceBuildParametersParams{ - WorkspaceBuildID: workspaceBuildID, - Name: names, - Value: values, - }) - if err != nil { - return nil, nil, BuildError{http.StatusInternalServerError, "insert workspace build parameters: %w", err} - } return &workspaceBuild, &provisionerJob, nil } diff --git a/codersdk/templateversions.go b/codersdk/templateversions.go index 86a62541550ef..18f81731aa03a 100644 --- a/codersdk/templateversions.go +++ b/codersdk/templateversions.go @@ -28,7 +28,7 @@ type TemplateVersion struct { Message string `json:"message"` Job ProvisionerJob `json:"job"` Readme string `json:"readme"` - CreatedBy User `json:"created_by"` + CreatedBy MinimalUser `json:"created_by"` Warnings []TemplateVersionWarning `json:"warnings,omitempty" enums:"DEPRECATED_PARAMETERS"` } diff --git a/codersdk/users.go b/codersdk/users.go index 1536635a2106b..3b9e28af49603 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -33,6 +33,14 @@ type UsersRequest struct { Pagination } +// MinimalUser is the minimal information needed to identify a user and show +// them on the UI. +type MinimalUser struct { + ID uuid.UUID `json:"id" validate:"required" table:"id" format:"uuid"` + Username string `json:"username" validate:"required" table:"username,default_sort"` + AvatarURL string `json:"avatar_url" format:"uri"` +} + // User represents a user in Coder. type User struct { ID uuid.UUID `json:"id" validate:"required" table:"id" format:"uuid"` diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index 1ae7648456eef..6751d76dff5b2 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -86,17 +86,19 @@ var auditableResourcesTypes = map[any]map[string]Action{ "locked_ttl": ActionTrack, }, &database.TemplateVersion{}: { - "id": ActionTrack, - "template_id": ActionTrack, - "organization_id": ActionIgnore, // Never changes. - "created_at": ActionIgnore, // Never changes, but is implicit and not helpful in a diff. - "updated_at": ActionIgnore, // Changes, but is implicit and not helpful in a diff. - "name": ActionTrack, - "message": ActionIgnore, // Never changes after creation. - "readme": ActionTrack, - "job_id": ActionIgnore, // Not helpful in a diff because jobs aren't tracked in audit logs. - "created_by": ActionTrack, - "git_auth_providers": ActionIgnore, // Not helpful because this can only change when new versions are added. + "id": ActionTrack, + "template_id": ActionTrack, + "organization_id": ActionIgnore, // Never changes. + "created_at": ActionIgnore, // Never changes, but is implicit and not helpful in a diff. + "updated_at": ActionIgnore, // Changes, but is implicit and not helpful in a diff. + "name": ActionTrack, + "message": ActionIgnore, // Never changes after creation. + "readme": ActionTrack, + "job_id": ActionIgnore, // Not helpful in a diff because jobs aren't tracked in audit logs. + "created_by": ActionTrack, + "git_auth_providers": ActionIgnore, // Not helpful because this can only change when new versions are added. + "created_by_avatar_url": ActionIgnore, + "created_by_username": ActionIgnore, }, &database.User{}: { "id": ActionTrack, @@ -128,20 +130,22 @@ var auditableResourcesTypes = map[any]map[string]Action{ "locked_at": ActionTrack, }, &database.WorkspaceBuild{}: { - "id": ActionIgnore, - "created_at": ActionIgnore, - "updated_at": ActionIgnore, - "workspace_id": ActionIgnore, - "template_version_id": ActionTrack, - "build_number": ActionIgnore, - "transition": ActionIgnore, - "initiator_id": ActionIgnore, - "provisioner_state": ActionIgnore, - "job_id": ActionIgnore, - "deadline": ActionIgnore, - "reason": ActionIgnore, - "daily_cost": ActionIgnore, - "max_deadline": ActionIgnore, + "id": ActionIgnore, + "created_at": ActionIgnore, + "updated_at": ActionIgnore, + "workspace_id": ActionIgnore, + "template_version_id": ActionTrack, + "build_number": ActionIgnore, + "transition": ActionIgnore, + "initiator_id": ActionIgnore, + "provisioner_state": ActionIgnore, + "job_id": ActionIgnore, + "deadline": ActionIgnore, + "reason": ActionIgnore, + "daily_cost": ActionIgnore, + "max_deadline": ActionIgnore, + "initiator_by_avatar_url": ActionIgnore, + "initiator_by_username": ActionIgnore, }, &database.AuditableGroup{}: { "id": ActionTrack, diff --git a/enterprise/coderd/workspacequota.go b/enterprise/coderd/workspacequota.go index 22d63c2ece2fb..28198ca9a3570 100644 --- a/enterprise/coderd/workspacequota.go +++ b/enterprise/coderd/workspacequota.go @@ -75,7 +75,7 @@ func (c *committer) CommitQuota( return nil } - _, err = s.UpdateWorkspaceBuildCostByID(ctx, database.UpdateWorkspaceBuildCostByIDParams{ + err = s.UpdateWorkspaceBuildCostByID(ctx, database.UpdateWorkspaceBuildCostByIDParams{ ID: build.ID, DailyCost: request.DailyCost, }) diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 707dcfcf57b2b..0d1a604515a8a 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -554,6 +554,13 @@ export interface LoginWithPasswordResponse { readonly session_token: string } +// From codersdk/users.go +export interface MinimalUser { + readonly id: string + readonly username: string + readonly avatar_url: string +} + // From codersdk/deployment.go export interface OAuth2Config { readonly github: OAuth2GithubConfig @@ -930,7 +937,7 @@ export interface TemplateVersion { readonly message: string readonly job: ProvisionerJob readonly readme: string - readonly created_by: User + readonly created_by: MinimalUser readonly warnings?: TemplateVersionWarning[] } From e7a4034fa1c8f66fed3ead3579e9bc4e8e4fe22a Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 20 Jul 2023 11:37:27 -0400 Subject: [PATCH 02/14] make gen --- coderd/apidoc/docs.go | 22 +++- coderd/apidoc/swagger.json | 19 +++- coderd/workspacebuilds.go | 6 +- docs/admin/audit-logs.md | 4 +- docs/api/schemas.md | 31 ++++-- docs/api/templates.md | 221 +++++++++++-------------------------- 6 files changed, 123 insertions(+), 180 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 4fcc4c035949e..16419ba569c08 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -8199,6 +8199,26 @@ const docTemplate = `{ } } }, + "codersdk.MinimalUser": { + "type": "object", + "required": [ + "id", + "username" + ], + "properties": { + "avatar_url": { + "type": "string", + "format": "uri" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "username": { + "type": "string" + } + } + }, "codersdk.OAuth2Config": { "type": "object", "properties": { @@ -9276,7 +9296,7 @@ const docTemplate = `{ "format": "date-time" }, "created_by": { - "$ref": "#/definitions/codersdk.User" + "$ref": "#/definitions/codersdk.MinimalUser" }, "id": { "type": "string", diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 2b0140f1004fe..34e67a5e5a997 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -7350,6 +7350,23 @@ } } }, + "codersdk.MinimalUser": { + "type": "object", + "required": ["id", "username"], + "properties": { + "avatar_url": { + "type": "string", + "format": "uri" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "username": { + "type": "string" + } + } + }, "codersdk.OAuth2Config": { "type": "object", "properties": { @@ -8376,7 +8393,7 @@ "format": "date-time" }, "created_by": { - "$ref": "#/definitions/codersdk.User" + "$ref": "#/definitions/codersdk.MinimalUser" }, "id": { "type": "string", diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 18075b3d87cf7..726e07d8a88a9 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -826,10 +826,6 @@ func (api *API) convertWorkspaceBuild( if !exists { return codersdk.WorkspaceBuild{}, xerrors.Errorf("owner not found for workspace: %q", workspace.Name) } - initiator, exists := userByID[build.InitiatorID] - if !exists { - return codersdk.WorkspaceBuild{}, xerrors.Errorf("build initiator not found for workspace: %q", workspace.Name) - } resources := resourcesByJobID[job.ProvisionerJob.ID] apiResources := make([]codersdk.WorkspaceResource, 0) @@ -865,7 +861,7 @@ func (api *API) convertWorkspaceBuild( BuildNumber: build.BuildNumber, Transition: transition, InitiatorID: build.InitiatorID, - InitiatorUsername: initiator.Username, + InitiatorUsername: build.InitiatorByUsername, Job: apiJob, Deadline: codersdk.NewNullTime(build.Deadline, !build.Deadline.IsZero()), MaxDeadline: codersdk.NewNullTime(build.MaxDeadline, !build.MaxDeadline.IsZero()), diff --git a/docs/admin/audit-logs.md b/docs/admin/audit-logs.md index 0f23bed248839..44dce11c8f69e 100644 --- a/docs/admin/audit-logs.md +++ b/docs/admin/audit-logs.md @@ -17,10 +17,10 @@ We track the following resources: | GitSSHKey
create |
FieldTracked
created_atfalse
private_keytrue
public_keytrue
updated_atfalse
user_idtrue
| | License
create, delete |
FieldTracked
exptrue
idfalse
jwtfalse
uploaded_attrue
uuidtrue
| | Template
write, delete |
FieldTracked
active_version_idtrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
default_ttltrue
deletedfalse
descriptiontrue
display_nametrue
failure_ttltrue
group_acltrue
icontrue
idtrue
inactivity_ttltrue
locked_ttltrue
max_ttltrue
nametrue
organization_idfalse
provisionertrue
restart_requirement_days_of_weektrue
restart_requirement_weekstrue
updated_atfalse
user_acltrue
| -| TemplateVersion
create, write |
FieldTracked
created_atfalse
created_bytrue
git_auth_providersfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
template_idtrue
updated_atfalse
| +| TemplateVersion
create, write |
FieldTracked
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
git_auth_providersfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
template_idtrue
updated_atfalse
| | User
create, write, delete |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
hashed_passwordtrue
idtrue
last_seen_atfalse
login_typetrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
updated_atfalse
usernametrue
| | Workspace
create, write, delete |
FieldTracked
autostart_scheduletrue
created_atfalse
deletedfalse
idtrue
last_used_atfalse
locked_attrue
nametrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| -| WorkspaceBuild
start, stop |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
idfalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
transitionfalse
updated_atfalse
workspace_idfalse
| +| WorkspaceBuild
start, stop |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
transitionfalse
updated_atfalse
workspace_idfalse
| | WorkspaceProxy
|
FieldTracked
created_attrue
deletedfalse
display_nametrue
icontrue
idtrue
nametrue
token_hashed_secrettrue
updated_atfalse
urltrue
wildcard_hostnametrue
| diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 7af780fc5bbf9..3a5bdade1fa4c 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -3078,6 +3078,24 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | --------------- | ------ | -------- | ------------ | ----------- | | `session_token` | string | true | | | +## codersdk.MinimalUser + +```json +{ + "avatar_url": "http://example.com", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "username": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| ------------ | ------ | -------- | ------------ | ----------- | +| `avatar_url` | string | false | | | +| `id` | string | true | | | +| `username` | string | true | | | + ## codersdk.OAuth2Config ```json @@ -4189,18 +4207,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", @@ -4237,7 +4244,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | Name | Type | Required | Restrictions | Description | | ----------------- | --------------------------------------------------------------------------- | -------- | ------------ | ----------- | | `created_at` | string | false | | | -| `created_by` | [codersdk.User](#codersdkuser) | false | | | +| `created_by` | [codersdk.MinimalUser](#codersdkminimaluser) | false | | | | `id` | string | false | | | | `job` | [codersdk.ProvisionerJob](#codersdkprovisionerjob) | false | | | | `message` | string | false | | | diff --git a/docs/api/templates.md b/docs/api/templates.md index 06b11216727ae..b77d2dcce62bf 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -376,18 +376,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", @@ -457,18 +446,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", @@ -562,18 +540,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", @@ -874,18 +841,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \ "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", @@ -928,52 +884,42 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \ Status Code **200** -| Name | Type | Required | Restrictions | Description | -| --------------------- | ------------------------------------------------------------------------ | -------- | ------------ | ----------- | -| `[array item]` | array | false | | | -| `» created_at` | string(date-time) | false | | | -| `» created_by` | [codersdk.User](schemas.md#codersdkuser) | false | | | -| `»» avatar_url` | string(uri) | false | | | -| `»» created_at` | string(date-time) | true | | | -| `»» email` | string(email) | true | | | -| `»» id` | string(uuid) | true | | | -| `»» last_seen_at` | string(date-time) | false | | | -| `»» organization_ids` | array | false | | | -| `»» roles` | array | false | | | -| `»»» display_name` | string | false | | | -| `»»» name` | string | false | | | -| `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | -| `»» username` | string | true | | | -| `» id` | string(uuid) | false | | | -| `» job` | [codersdk.ProvisionerJob](schemas.md#codersdkprovisionerjob) | false | | | -| `»» canceled_at` | string(date-time) | false | | | -| `»» completed_at` | string(date-time) | false | | | -| `»» created_at` | string(date-time) | false | | | -| `»» error` | string | false | | | -| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | | -| `»» file_id` | string(uuid) | false | | | -| `»» id` | string(uuid) | false | | | -| `»» queue_position` | integer | false | | | -| `»» queue_size` | integer | false | | | -| `»» started_at` | string(date-time) | false | | | -| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | | -| `»» tags` | object | false | | | -| `»»» [any property]` | string | false | | | -| `»» worker_id` | string(uuid) | false | | | -| `» message` | string | false | | | -| `» name` | string | false | | | -| `» organization_id` | string(uuid) | false | | | -| `» readme` | string | false | | | -| `» template_id` | string(uuid) | false | | | -| `» updated_at` | string(date-time) | false | | | -| `» warnings` | array | false | | | +| Name | Type | Required | Restrictions | Description | +| -------------------- | ------------------------------------------------------------------------ | -------- | ------------ | ----------- | +| `[array item]` | array | false | | | +| `» created_at` | string(date-time) | false | | | +| `» created_by` | [codersdk.MinimalUser](schemas.md#codersdkminimaluser) | false | | | +| `»» avatar_url` | string(uri) | false | | | +| `»» id` | string(uuid) | true | | | +| `»» username` | string | true | | | +| `» id` | string(uuid) | false | | | +| `» job` | [codersdk.ProvisionerJob](schemas.md#codersdkprovisionerjob) | false | | | +| `»» canceled_at` | string(date-time) | false | | | +| `»» completed_at` | string(date-time) | false | | | +| `»» created_at` | string(date-time) | false | | | +| `»» error` | string | false | | | +| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | | +| `»» file_id` | string(uuid) | false | | | +| `»» id` | string(uuid) | false | | | +| `»» queue_position` | integer | false | | | +| `»» queue_size` | integer | false | | | +| `»» started_at` | string(date-time) | false | | | +| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | | +| `»» tags` | object | false | | | +| `»»» [any property]` | string | false | | | +| `»» worker_id` | string(uuid) | false | | | +| `» message` | string | false | | | +| `» name` | string | false | | | +| `» organization_id` | string(uuid) | false | | | +| `» readme` | string | false | | | +| `» template_id` | string(uuid) | false | | | +| `» updated_at` | string(date-time) | false | | | +| `» warnings` | array | false | | | #### Enumerated Values | Property | Value | | ------------ | ----------------------------- | -| `status` | `active` | -| `status` | `suspended` | | `error_code` | `MISSING_TEMPLATE_PARAMETER` | | `error_code` | `REQUIRED_TEMPLATE_VARIABLES` | | `status` | `pending` | @@ -1069,18 +1015,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templ "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", @@ -1123,52 +1058,42 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templ Status Code **200** -| Name | Type | Required | Restrictions | Description | -| --------------------- | ------------------------------------------------------------------------ | -------- | ------------ | ----------- | -| `[array item]` | array | false | | | -| `» created_at` | string(date-time) | false | | | -| `» created_by` | [codersdk.User](schemas.md#codersdkuser) | false | | | -| `»» avatar_url` | string(uri) | false | | | -| `»» created_at` | string(date-time) | true | | | -| `»» email` | string(email) | true | | | -| `»» id` | string(uuid) | true | | | -| `»» last_seen_at` | string(date-time) | false | | | -| `»» organization_ids` | array | false | | | -| `»» roles` | array | false | | | -| `»»» display_name` | string | false | | | -| `»»» name` | string | false | | | -| `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | -| `»» username` | string | true | | | -| `» id` | string(uuid) | false | | | -| `» job` | [codersdk.ProvisionerJob](schemas.md#codersdkprovisionerjob) | false | | | -| `»» canceled_at` | string(date-time) | false | | | -| `»» completed_at` | string(date-time) | false | | | -| `»» created_at` | string(date-time) | false | | | -| `»» error` | string | false | | | -| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | | -| `»» file_id` | string(uuid) | false | | | -| `»» id` | string(uuid) | false | | | -| `»» queue_position` | integer | false | | | -| `»» queue_size` | integer | false | | | -| `»» started_at` | string(date-time) | false | | | -| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | | -| `»» tags` | object | false | | | -| `»»» [any property]` | string | false | | | -| `»» worker_id` | string(uuid) | false | | | -| `» message` | string | false | | | -| `» name` | string | false | | | -| `» organization_id` | string(uuid) | false | | | -| `» readme` | string | false | | | -| `» template_id` | string(uuid) | false | | | -| `» updated_at` | string(date-time) | false | | | -| `» warnings` | array | false | | | +| Name | Type | Required | Restrictions | Description | +| -------------------- | ------------------------------------------------------------------------ | -------- | ------------ | ----------- | +| `[array item]` | array | false | | | +| `» created_at` | string(date-time) | false | | | +| `» created_by` | [codersdk.MinimalUser](schemas.md#codersdkminimaluser) | false | | | +| `»» avatar_url` | string(uri) | false | | | +| `»» id` | string(uuid) | true | | | +| `»» username` | string | true | | | +| `» id` | string(uuid) | false | | | +| `» job` | [codersdk.ProvisionerJob](schemas.md#codersdkprovisionerjob) | false | | | +| `»» canceled_at` | string(date-time) | false | | | +| `»» completed_at` | string(date-time) | false | | | +| `»» created_at` | string(date-time) | false | | | +| `»» error` | string | false | | | +| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | | +| `»» file_id` | string(uuid) | false | | | +| `»» id` | string(uuid) | false | | | +| `»» queue_position` | integer | false | | | +| `»» queue_size` | integer | false | | | +| `»» started_at` | string(date-time) | false | | | +| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | | +| `»» tags` | object | false | | | +| `»»» [any property]` | string | false | | | +| `»» worker_id` | string(uuid) | false | | | +| `» message` | string | false | | | +| `» name` | string | false | | | +| `» organization_id` | string(uuid) | false | | | +| `» readme` | string | false | | | +| `» template_id` | string(uuid) | false | | | +| `» updated_at` | string(date-time) | false | | | +| `» warnings` | array | false | | | #### Enumerated Values | Property | Value | | ------------ | ----------------------------- | -| `status` | `active` | -| `status` | `suspended` | | `error_code` | `MISSING_TEMPLATE_PARAMETER` | | `error_code` | `REQUIRED_TEMPLATE_VARIABLES` | | `status` | `pending` | @@ -1208,18 +1133,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion} \ "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", @@ -1298,18 +1212,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion} "created_at": "2019-08-24T14:15:22Z", "created_by": { "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], - "roles": [ - { - "display_name": "string", - "name": "string" - } - ], - "status": "active", "username": "string" }, "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", From 3aad7afebd2b64adb5a235ba7ac3ef028c30601e Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 20 Jul 2023 13:23:03 -0400 Subject: [PATCH 03/14] Fix unit tests --- .../provisionerdserver_test.go | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index bb34410957cf2..466451fabc8f3 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -558,7 +558,8 @@ func TestUpdateJob(t *testing.T) { t.Parallel() srv := setup(t, false) job := setupJob(t, srv) - version, err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ + versionID := uuid.New() + err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ ID: uuid.New(), JobID: job, }) @@ -569,7 +570,7 @@ func TestUpdateJob(t *testing.T) { }) require.NoError(t, err) - version, err = srv.Database.GetTemplateVersionByID(ctx, version.ID) + version, err := srv.Database.GetTemplateVersionByID(ctx, versionID) require.NoError(t, err) require.Equal(t, "# hello world", version.Readme) }) @@ -583,8 +584,9 @@ func TestUpdateJob(t *testing.T) { srv := setup(t, false) job := setupJob(t, srv) - version, err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ - ID: uuid.New(), + versionID := uuid.New() + err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ + ID: versionID, JobID: job, }) require.NoError(t, err) @@ -616,7 +618,7 @@ func TestUpdateJob(t *testing.T) { require.NoError(t, err) require.Len(t, response.VariableValues, 2) - templateVariables, err := srv.Database.GetTemplateVersionVariables(ctx, version.ID) + templateVariables, err := srv.Database.GetTemplateVersionVariables(ctx, versionID) require.NoError(t, err) require.Len(t, templateVariables, 2) require.Equal(t, templateVariables[0].Value, firstTemplateVariable.DefaultValue) @@ -629,8 +631,9 @@ func TestUpdateJob(t *testing.T) { srv := setup(t, false) job := setupJob(t, srv) - version, err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ - ID: uuid.New(), + versionID := uuid.New() + err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ + ID: versionID, JobID: job, }) require.NoError(t, err) @@ -658,7 +661,7 @@ func TestUpdateJob(t *testing.T) { // Even though there is an error returned, variables are stored in the database // to show the schema in the site UI. - templateVariables, err := srv.Database.GetTemplateVersionVariables(ctx, version.ID) + templateVariables, err := srv.Database.GetTemplateVersionVariables(ctx, versionID) require.NoError(t, err) require.Len(t, templateVariables, 2) require.Equal(t, templateVariables[0].Value, firstTemplateVariable.DefaultValue) @@ -761,6 +764,7 @@ func TestFailJob(t *testing.T) { WorkspaceBuildID: buildID, }) require.NoError(t, err) + job, err := srv.Database.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ ID: uuid.New(), Input: input, @@ -779,7 +783,7 @@ func TestFailJob(t *testing.T) { require.NoError(t, err) publishedWorkspace := make(chan struct{}) - closeWorkspaceSubscribe, err := srv.Pubsub.Subscribe(codersdk.WorkspaceNotifyChannel(build.WorkspaceID), func(_ context.Context, _ []byte) { + closeWorkspaceSubscribe, err := srv.Pubsub.Subscribe(codersdk.WorkspaceNotifyChannel(workspace.ID), func(_ context.Context, _ []byte) { close(publishedWorkspace) }) require.NoError(t, err) @@ -802,7 +806,7 @@ func TestFailJob(t *testing.T) { require.NoError(t, err) <-publishedWorkspace <-publishedLogs - build, err = srv.Database.GetWorkspaceBuildByID(ctx, build.ID) + build, err := srv.Database.GetWorkspaceBuildByID(ctx, buildID) require.NoError(t, err) require.Equal(t, "some state", string(build.ProvisionerState)) }) @@ -852,15 +856,16 @@ func TestCompleteJob(t *testing.T) { t.Parallel() srv := setup(t, false) jobID := uuid.New() - version, err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ - ID: uuid.New(), + versionID := uuid.New() + err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ + ID: versionID JobID: jobID, }) require.NoError(t, err) job, err := srv.Database.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ ID: jobID, Provisioner: database.ProvisionerTypeEcho, - Input: []byte(`{"template_version_id": "` + version.ID.String() + `"}`), + Input: []byte(`{"template_version_id": "` + versionID.String() + `"}`), StorageMethod: database.ProvisionerStorageMethodFile, Type: database.ProvisionerJobTypeWorkspaceBuild, }) From 4623a5607c5b3ef867cef659bb7ebd56d5db36b4 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 20 Jul 2023 13:24:12 -0400 Subject: [PATCH 04/14] fixup! Fix unit tests --- coderd/provisionerdserver/provisionerdserver_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 466451fabc8f3..c6a23284d403f 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -858,7 +858,7 @@ func TestCompleteJob(t *testing.T) { jobID := uuid.New() versionID := uuid.New() err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ - ID: versionID + ID: versionID, JobID: jobID, }) require.NoError(t, err) From ba7cf914e85a1f617a287ea9584186f492ab4283 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 08:47:35 -0400 Subject: [PATCH 05/14] Fix unit test --- coderd/metricscache/metricscache_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/coderd/metricscache/metricscache_test.go b/coderd/metricscache/metricscache_test.go index ba4fc498efe90..52c0df8a3ebd8 100644 --- a/coderd/metricscache/metricscache_test.go +++ b/coderd/metricscache/metricscache_test.go @@ -358,8 +358,9 @@ func TestCache_BuildTime(t *testing.T) { template, err := db.GetTemplateByID(ctx, id) require.NoError(t, err) - templateVersion, err := db.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ - ID: uuid.New(), + templateVersionID := uuid.New() + err = db.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ + ID: templateVersionID, TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, }) require.NoError(t, err) @@ -385,7 +386,7 @@ func TestCache_BuildTime(t *testing.T) { require.NoError(t, err) err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ - TemplateVersionID: templateVersion.ID, + TemplateVersionID: templateVersionID, JobID: job.ID, Transition: tt.args.transition, Reason: database.BuildReasonInitiator, From d5bbd8510d03a2d4c76b1e25c39f74b56ac57b6c Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 09:13:18 -0400 Subject: [PATCH 06/14] update db mocks --- coderd/database/dbgen/dbgen.go | 11 ++++++----- coderd/wsbuilder/wsbuilder_test.go | 26 ++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index ebe76f9f8891a..3b83970135760 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -180,11 +180,11 @@ func Workspace(t testing.TB, db database.Store, orig database.Workspace) databas } func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuild) database.WorkspaceBuild { - id := takeFirst(orig.ID, uuid.New()) + buildID := takeFirst(orig.ID, uuid.New()) var build database.WorkspaceBuild err := db.InTx(func(store database.Store) error { err := db.InsertWorkspaceBuild(genCtx, database.InsertWorkspaceBuildParams{ - ID: takeFirst(orig.ID, uuid.New()), + ID: buildID, CreatedAt: takeFirst(orig.CreatedAt, database.Now()), UpdatedAt: takeFirst(orig.UpdatedAt, database.Now()), WorkspaceID: takeFirst(orig.WorkspaceID, uuid.New()), @@ -200,7 +200,7 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil if err != nil { return err } - build, err = db.GetWorkspaceBuildByID(genCtx, id) + build, err = db.GetWorkspaceBuildByID(genCtx, buildID) if err != nil { return err } @@ -489,8 +489,9 @@ func GitAuthLink(t testing.TB, db database.Store, orig database.GitAuthLink) dat func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVersion) database.TemplateVersion { var version database.TemplateVersion err := db.InTx(func(db database.Store) error { + versionID := takeFirst(orig.ID, uuid.New()) err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{ - ID: takeFirst(orig.ID, uuid.New()), + ID: versionID, TemplateID: orig.TemplateID, OrganizationID: takeFirst(orig.OrganizationID, uuid.New()), CreatedAt: takeFirst(orig.CreatedAt, database.Now()), @@ -505,7 +506,7 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers return err } - version, err = db.GetTemplateVersionByID(genCtx, version.ID) + version, err = db.GetTemplateVersionByID(genCtx, versionID) if err != nil { return err } diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go index 414841e80b7f0..467c7f8b56dfe 100644 --- a/coderd/wsbuilder/wsbuilder_test.go +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -65,6 +65,8 @@ func TestBuilder_NoOptions(t *testing.T) { // store build ID for later buildID = input.WorkspaceBuildID }), + + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) { asrt.Equal(inactiveVersionID, bld.TemplateVersionID) asrt.Equal(workspaceID, bld.WorkspaceID) @@ -75,6 +77,7 @@ func TestBuilder_NoOptions(t *testing.T) { asrt.Equal(database.BuildReasonInitiator, bld.Reason) asrt.Equal(buildID, bld.ID) }), + withBuild, expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { asrt.Equal(buildID, params.WorkspaceBuildID) asrt.Empty(params.Name) @@ -173,6 +176,7 @@ func TestBuilder_ActiveVersion(t *testing.T) { expectProvisionerJob(func(job database.InsertProvisionerJobParams) { asrt.Equal(activeFileID, job.FileID) }), + expectBuild(func(bld database.InsertWorkspaceBuildParams) { asrt.Equal(activeVersionID, bld.TemplateVersionID) // no previous build... @@ -592,6 +596,15 @@ func withTemplate(mTx *dbmock.MockStore) { }, nil) } +// withInTx runs the given functions on the same db mock. +func withInTx(mTx *dbmock.MockStore) { + mTx.EXPECT().InTx(gomock.Any(), gomock.Any()).Times(1).DoAndReturn( + func(f func(store database.Store) error, _ *sql.TxOptions) error { + return f(mTx) + }, + ) +} + func withActiveVersion(params []database.TemplateVersionParameter) func(mTx *dbmock.MockStore) { return func(mTx *dbmock.MockStore) { mTx.EXPECT().GetTemplateVersionByID(gomock.Any(), activeVersionID). @@ -758,6 +771,13 @@ func expectProvisionerJob( } } +func withBuild(mTx *dbmock.MockStore) { + mTx.EXPECT().GetWorkspaceBuildByID(gomock.Any(), gomock.Any()).Times(1). + DoAndReturn(func(ctx context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { + return database.WorkspaceBuild{ID: id}, nil + }) +} + // expectBuild captures a call to InsertWorkspaceBuild and runs the provided assertions // against it. func expectBuild( @@ -767,11 +787,9 @@ func expectBuild( mTx.EXPECT().InsertWorkspaceBuild(gomock.Any(), gomock.Any()). Times(1). DoAndReturn( - func(ctx context.Context, params database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) { + func(ctx context.Context, params database.InsertWorkspaceBuildParams) error { assertions(params) - // there is no point copying anything other than the ID, since this object is just - // returned to our test code, and we've already asserted what we care about. - return database.WorkspaceBuild{ID: params.ID}, nil + return nil }, ) } From 55ff364b812b5942984cfa00ecc84cc70ffff2fd Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 09:44:01 -0400 Subject: [PATCH 07/14] Fix dbfake with joins --- coderd/database/dbfake/dbfake.go | 89 +++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 30 deletions(-) diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index 86b74a7f8ec86..ecd0cd8f05f0e 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -57,11 +57,11 @@ func New() database.Store { workspaceResources: make([]database.WorkspaceResource, 0), workspaceResourceMetadata: make([]database.WorkspaceResourceMetadatum, 0), provisionerJobs: make([]database.ProvisionerJob, 0), - templateVersions: make([]database.TemplateVersion, 0), + templateVersions: make([]database.TemplateVersionTable, 0), templates: make([]database.TemplateTable, 0), workspaceAgentStats: make([]database.WorkspaceAgentStat, 0), workspaceAgentLogs: make([]database.WorkspaceAgentStartupLog, 0), - workspaceBuilds: make([]database.WorkspaceBuild, 0), + workspaceBuilds: make([]database.WorkspaceBuildTable, 0), workspaceApps: make([]database.WorkspaceApp, 0), workspaces: make([]database.Workspace, 0), licenses: make([]database.License, 0), @@ -127,7 +127,7 @@ type data struct { provisionerJobLogs []database.ProvisionerJobLog provisionerJobs []database.ProvisionerJob replicas []database.Replica - templateVersions []database.TemplateVersion + templateVersions []database.TemplateVersionTable templateVersionParameters []database.TemplateVersionParameter templateVersionVariables []database.TemplateVersionVariable templates []database.TemplateTable @@ -135,7 +135,7 @@ type data struct { workspaceAgentMetadata []database.WorkspaceAgentMetadatum workspaceAgentLogs []database.WorkspaceAgentStartupLog workspaceApps []database.WorkspaceApp - workspaceBuilds []database.WorkspaceBuild + workspaceBuilds []database.WorkspaceBuildTable workspaceBuildParameters []database.WorkspaceBuildParameter workspaceResourceMetadata []database.WorkspaceResourceMetadatum workspaceResources []database.WorkspaceResource @@ -404,7 +404,7 @@ func (q *FakeQuerier) getWorkspaceByAgentIDNoLock(_ context.Context, agentID uui var build database.WorkspaceBuild for _, _build := range q.workspaceBuilds { if _build.JobID == resource.JobID { - build = _build + build = q.workspaceBuildWithUserNoLock(_build) break } } @@ -424,7 +424,7 @@ func (q *FakeQuerier) getWorkspaceByAgentIDNoLock(_ context.Context, agentID uui func (q *FakeQuerier) getWorkspaceBuildByIDNoLock(_ context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { for _, history := range q.workspaceBuilds { if history.ID == id { - return history, nil + return q.workspaceBuildWithUserNoLock(history), nil } } return database.WorkspaceBuild{}, sql.ErrNoRows @@ -435,7 +435,7 @@ func (q *FakeQuerier) getLatestWorkspaceBuildByWorkspaceIDNoLock(_ context.Conte var buildNum int32 = -1 for _, workspaceBuild := range q.workspaceBuilds { if workspaceBuild.WorkspaceID == workspaceID && workspaceBuild.BuildNumber > buildNum { - row = workspaceBuild + row = q.workspaceBuildWithUserNoLock(workspaceBuild) buildNum = workspaceBuild.BuildNumber } } @@ -479,12 +479,46 @@ func (q *FakeQuerier) templateWithUserNoLock(tpl database.TemplateTable) databas return withUser } +func (q *FakeQuerier) templateVersionWithUserNoLock(tpl database.TemplateVersionTable) database.TemplateVersion { + var user database.User + for _, _user := range q.users { + if _user.ID == tpl.CreatedBy { + user = _user + break + } + } + var withUser database.TemplateVersion + // This is a cheeky way to copy the fields over without explicitly listing them all. + d, _ := json.Marshal(tpl) + _ = json.Unmarshal(d, &withUser) + withUser.CreatedByUsername = user.Username + withUser.CreatedByAvatarURL = user.AvatarURL + return withUser +} + +func (q *FakeQuerier) workspaceBuildWithUserNoLock(tpl database.WorkspaceBuildTable) database.WorkspaceBuild { + var user database.User + for _, _user := range q.users { + if _user.ID == tpl.InitiatorID { + user = _user + break + } + } + var withUser database.WorkspaceBuild + // This is a cheeky way to copy the fields over without explicitly listing them all. + d, _ := json.Marshal(tpl) + _ = json.Unmarshal(d, &withUser) + withUser.InitiatorByUsername = user.Username + withUser.InitiatorByAvatarUrl = user.AvatarURL + return withUser +} + func (q *FakeQuerier) getTemplateVersionByIDNoLock(_ context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) { for _, templateVersion := range q.templateVersions { if templateVersion.ID != templateVersionID { continue } - return templateVersion, nil + return q.templateVersionWithUserNoLock(templateVersion), nil } return database.TemplateVersion{}, sql.ErrNoRows } @@ -1370,7 +1404,7 @@ func (q *FakeQuerier) GetLatestWorkspaceBuilds(_ context.Context) ([]database.Wo for _, workspaceBuild := range q.workspaceBuilds { id := workspaceBuild.WorkspaceID if workspaceBuild.BuildNumber > buildNumbers[id] { - builds[id] = workspaceBuild + builds[id] = q.workspaceBuildWithUserNoLock(workspaceBuild) buildNumbers[id] = workspaceBuild.BuildNumber } } @@ -1396,7 +1430,7 @@ func (q *FakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, for _, workspaceBuild := range q.workspaceBuilds { for _, id := range ids { if id == workspaceBuild.WorkspaceID && workspaceBuild.BuildNumber > buildNumbers[id] { - builds[id] = workspaceBuild + builds[id] = q.workspaceBuildWithUserNoLock(workspaceBuild) buildNumbers[id] = workspaceBuild.BuildNumber } } @@ -1606,7 +1640,7 @@ func (q *FakeQuerier) GetPreviousTemplateVersion(_ context.Context, arg database if templateVersion.OrganizationID != arg.OrganizationID { continue } - currentTemplateVersion = templateVersion + currentTemplateVersion = q.templateVersionWithUserNoLock(templateVersion) break } @@ -1623,7 +1657,7 @@ func (q *FakeQuerier) GetPreviousTemplateVersion(_ context.Context, arg database } if templateVersion.CreatedAt.Before(currentTemplateVersion.CreatedAt) { - previousTemplateVersions = append(previousTemplateVersions, templateVersion) + previousTemplateVersions = append(previousTemplateVersions, q.templateVersionWithUserNoLock(templateVersion)) } } @@ -1772,7 +1806,7 @@ func (q *FakeQuerier) GetQuotaConsumedForUser(_ context.Context, userID uuid.UUI continue } - var lastBuild database.WorkspaceBuild + var lastBuild database.WorkspaceBuildTable for _, build := range q.workspaceBuilds { if build.WorkspaceID != workspace.ID { continue @@ -1959,7 +1993,7 @@ func (q *FakeQuerier) GetTemplateVersionByJobID(_ context.Context, jobID uuid.UU if templateVersion.JobID != jobID { continue } - return templateVersion, nil + return q.templateVersionWithUserNoLock(templateVersion), nil } return database.TemplateVersion{}, sql.ErrNoRows } @@ -1979,7 +2013,7 @@ func (q *FakeQuerier) GetTemplateVersionByTemplateIDAndName(_ context.Context, a if !strings.EqualFold(templateVersion.Name, arg.Name) { continue } - return templateVersion, nil + return q.templateVersionWithUserNoLock(templateVersion), nil } return database.TemplateVersion{}, sql.ErrNoRows } @@ -2026,7 +2060,7 @@ func (q *FakeQuerier) GetTemplateVersionsByIDs(_ context.Context, ids []uuid.UUI for _, version := range q.templateVersions { for _, id := range ids { if id == version.ID { - versions = append(versions, version) + versions = append(versions, q.templateVersionWithUserNoLock(version)) break } } @@ -2050,7 +2084,7 @@ func (q *FakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, arg dat if templateVersion.TemplateID.UUID != arg.TemplateID { continue } - version = append(version, templateVersion) + version = append(version, q.templateVersionWithUserNoLock(templateVersion)) } // Database orders by created_at @@ -2108,7 +2142,7 @@ func (q *FakeQuerier) GetTemplateVersionsCreatedAfter(_ context.Context, after t versions := make([]database.TemplateVersion, 0) for _, version := range q.templateVersions { if version.CreatedAt.After(after) { - versions = append(versions, version) + versions = append(versions, q.templateVersionWithUserNoLock(version)) } } return versions, nil @@ -2700,16 +2734,11 @@ func (q *FakeQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) ( return q.getWorkspaceBuildByIDNoLock(ctx, id) } -func (q *FakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { +func (q *FakeQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { q.mutex.RLock() defer q.mutex.RUnlock() - for _, build := range q.workspaceBuilds { - if build.JobID == jobID { - return build, nil - } - } - return database.WorkspaceBuild{}, sql.ErrNoRows + return q.getWorkspaceBuildByIDNoLock(ctx, jobID) } func (q *FakeQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams) (database.WorkspaceBuild, error) { @@ -2727,7 +2756,7 @@ func (q *FakeQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(_ context.Con if workspaceBuild.BuildNumber != arg.BuildNumber { continue } - return workspaceBuild, nil + return q.workspaceBuildWithUserNoLock(workspaceBuild), nil } return database.WorkspaceBuild{}, sql.ErrNoRows } @@ -2762,7 +2791,7 @@ func (q *FakeQuerier) GetWorkspaceBuildsByWorkspaceID(_ context.Context, continue } if workspaceBuild.WorkspaceID == params.WorkspaceID { - history = append(history, workspaceBuild) + history = append(history, q.workspaceBuildWithUserNoLock(workspaceBuild)) } } @@ -2816,7 +2845,7 @@ func (q *FakeQuerier) GetWorkspaceBuildsCreatedAfter(_ context.Context, after ti workspaceBuilds := make([]database.WorkspaceBuild, 0) for _, workspaceBuild := range q.workspaceBuilds { if workspaceBuild.CreatedAt.After(after) { - workspaceBuilds = append(workspaceBuilds, workspaceBuild) + workspaceBuilds = append(workspaceBuilds, q.workspaceBuildWithUserNoLock(workspaceBuild)) } } return workspaceBuilds, nil @@ -3504,7 +3533,7 @@ func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.Inse defer q.mutex.Unlock() //nolint:gosimple - version := database.TemplateVersion{ + version := database.TemplateVersionTable{ ID: arg.ID, TemplateID: arg.TemplateID, OrganizationID: arg.OrganizationID, @@ -3856,7 +3885,7 @@ func (q *FakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.Inser q.mutex.Lock() defer q.mutex.Unlock() - workspaceBuild := database.WorkspaceBuild{ + workspaceBuild := database.WorkspaceBuildTable{ ID: arg.ID, CreatedAt: arg.CreatedAt, UpdatedAt: arg.UpdatedAt, From c8e96ed1c89a5b390cc1a08aa3cf83d97b7227e4 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 10:15:39 -0400 Subject: [PATCH 08/14] Fix tx --- coderd/database/dbgen/dbgen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 3b83970135760..6b123cf4f3677 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -182,7 +182,7 @@ func Workspace(t testing.TB, db database.Store, orig database.Workspace) databas func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuild) database.WorkspaceBuild { buildID := takeFirst(orig.ID, uuid.New()) var build database.WorkspaceBuild - err := db.InTx(func(store database.Store) error { + err := db.InTx(func(db database.Store) error { err := db.InsertWorkspaceBuild(genCtx, database.InsertWorkspaceBuildParams{ ID: buildID, CreatedAt: takeFirst(orig.CreatedAt, database.Now()), From 589c15b759315ea59c0487658fcf3043ffeb6481 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 10:25:18 -0400 Subject: [PATCH 09/14] Fix mock expects --- coderd/wsbuilder/wsbuilder_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go index 467c7f8b56dfe..d0249f800ebd6 100644 --- a/coderd/wsbuilder/wsbuilder_test.go +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -252,6 +252,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) {}), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { asrt.Len(params.Name, len(expectedParams)) @@ -261,6 +262,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { asrt.Equal(value, params.Value[i]) } }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} @@ -293,6 +295,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) {}), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { asrt.Len(params.Name, len(expectedParams)) @@ -302,6 +305,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { asrt.Equal(value, params.Value[i]) } }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} @@ -340,6 +344,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) {}), ) @@ -374,6 +379,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) {}), // no build parameters, since we hit an error validating. // expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {}), @@ -426,6 +432,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) {}), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { asrt.Len(params.Name, len(expectedParams)) @@ -435,6 +442,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { asrt.Equal(value, params.Value[i]) } }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} @@ -484,6 +492,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) {}), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { asrt.Len(params.Name, len(expectedParams)) @@ -493,6 +502,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { asrt.Equal(value, params.Value[i]) } }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} @@ -540,6 +550,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) {}), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { asrt.Len(params.Name, len(expectedParams)) @@ -549,6 +560,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { asrt.Equal(value, params.Value[i]) } }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} From 1898c595bc7b023a9cdba73bc4d2eeab3029befe Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 10:38:24 -0400 Subject: [PATCH 10/14] Fix dbfake, replaced the wrong function --- coderd/database/dbauthz/dbauthz_test.go | 4 ++-- coderd/database/dbfake/dbfake.go | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index aff10510e20bb..2e03611538195 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -810,7 +810,7 @@ func (s *MethodTestSuite) TestTemplate() { TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, Name: tv.Name, UpdatedAt: tv.UpdatedAt, - }).Asserts(t1, rbac.ActionUpdate).Returns(tv) + }).Asserts(t1, rbac.ActionUpdate) })) s.Run("UpdateTemplateVersionDescriptionByJobID", s.Subtest(func(db database.Store, check *expects) { jobID := uuid.New() @@ -1242,7 +1242,7 @@ func (s *MethodTestSuite) TestWorkspace() { UpdatedAt: build.UpdatedAt, Deadline: build.Deadline, ProvisionerState: []byte{}, - }).Asserts(ws, rbac.ActionUpdate).Returns(build) + }).Asserts(ws, rbac.ActionUpdate) })) s.Run("SoftDeleteWorkspaceByID", s.Subtest(func(db database.Store, check *expects) { ws := dbgen.Workspace(s.T(), db, database.Workspace{}) diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index ecd0cd8f05f0e..dfdecdb9cea49 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -422,9 +422,9 @@ func (q *FakeQuerier) getWorkspaceByAgentIDNoLock(_ context.Context, agentID uui } func (q *FakeQuerier) getWorkspaceBuildByIDNoLock(_ context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { - for _, history := range q.workspaceBuilds { - if history.ID == id { - return q.workspaceBuildWithUserNoLock(history), nil + for _, build := range q.workspaceBuilds { + if build.ID == id { + return q.workspaceBuildWithUserNoLock(build), nil } } return database.WorkspaceBuild{}, sql.ErrNoRows @@ -2738,7 +2738,12 @@ func (q *FakeQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.U q.mutex.RLock() defer q.mutex.RUnlock() - return q.getWorkspaceBuildByIDNoLock(ctx, jobID) + for _, build := range q.workspaceBuilds { + if build.JobID == jobID { + return q.workspaceBuildWithUserNoLock(build), nil + } + } + return database.WorkspaceBuild{}, sql.ErrNoRows } func (q *FakeQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams) (database.WorkspaceBuild, error) { From 5b7d9555de39699b48856280870fe06142f77820 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 10:49:57 -0400 Subject: [PATCH 11/14] More missed mocks --- coderd/provisionerdserver/provisionerdserver_test.go | 2 +- coderd/wsbuilder/wsbuilder_test.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index c6a23284d403f..1af0c87f7a425 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -754,7 +754,7 @@ func TestFailJob(t *testing.T) { require.NoError(t, err) buildID := uuid.New() err = srv.Database.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ - ID: uuid.New(), + ID: buildID, WorkspaceID: workspace.ID, Transition: database.WorkspaceTransitionStart, Reason: database.BuildReasonInitiator, diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go index d0249f800ebd6..afb7c5af75579 100644 --- a/coderd/wsbuilder/wsbuilder_test.go +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -111,11 +111,13 @@ func TestBuilder_Initiator(t *testing.T) { expectProvisionerJob(func(job database.InsertProvisionerJobParams) { asrt.Equal(otherUserID, job.InitiatorID) }), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) { asrt.Equal(otherUserID, bld.InitiatorID) }), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} @@ -143,11 +145,13 @@ func TestBuilder_Reason(t *testing.T) { // Outputs expectProvisionerJob(func(job database.InsertProvisionerJobParams) { }), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) { asrt.Equal(database.BuildReasonAutostart, bld.Reason) }), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} @@ -177,6 +181,7 @@ func TestBuilder_ActiveVersion(t *testing.T) { asrt.Equal(activeFileID, job.FileID) }), + withInTx, expectBuild(func(bld database.InsertWorkspaceBuildParams) { asrt.Equal(activeVersionID, bld.TemplateVersionID) // no previous build... @@ -185,6 +190,7 @@ func TestBuilder_ActiveVersion(t *testing.T) { }), expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { }), + withBuild, ) ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} From 9bf32c5d79915ca0c2c19fd26f90f2491787cbbe Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 10:56:02 -0400 Subject: [PATCH 12/14] use correct id in fetch --- coderd/provisionerdserver/provisionerdserver_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 1af0c87f7a425..ee0faca6d2e84 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -560,7 +560,7 @@ func TestUpdateJob(t *testing.T) { job := setupJob(t, srv) versionID := uuid.New() err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ - ID: uuid.New(), + ID: versionID, JobID: job, }) require.NoError(t, err) From 262edb067290503327432fa7a61fa49a4632b649 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 11:01:31 -0400 Subject: [PATCH 13/14] linting, remove unused ctx in dbfake --- coderd/database/dbfake/dbfake.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index dfdecdb9cea49..e6e304bca01da 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -2734,7 +2734,7 @@ func (q *FakeQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) ( return q.getWorkspaceBuildByIDNoLock(ctx, id) } -func (q *FakeQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { +func (q *FakeQuerier) GetWorkspaceBuildByJobID(_g context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { q.mutex.RLock() defer q.mutex.RUnlock() From aa6bb77ec4a34b53d1b68b02a7b504d721da0763 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 21 Jul 2023 11:06:10 -0400 Subject: [PATCH 14/14] Add unit test to ensure join is superset --- coderd/database/dbfake/dbfake.go | 2 +- ... => 000140_workspace_deleting_at.down.sql} | 0 ...ql => 000140_workspace_deleting_at.up.sql} | 0 ... 000141_join_users_build_version.down.sql} | 0 ...=> 000141_join_users_build_version.up.sql} | 0 coderd/database/models_test.go | 28 +++++++++++++++++++ 6 files changed, 29 insertions(+), 1 deletion(-) rename coderd/database/migrations/{000141_workspace_deleting_at.down.sql => 000140_workspace_deleting_at.down.sql} (100%) rename coderd/database/migrations/{000141_workspace_deleting_at.up.sql => 000140_workspace_deleting_at.up.sql} (100%) rename coderd/database/migrations/{000140_join_users_build_version.down.sql => 000141_join_users_build_version.down.sql} (100%) rename coderd/database/migrations/{000140_join_users_build_version.up.sql => 000141_join_users_build_version.up.sql} (100%) diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index e6e304bca01da..b0da87af662e9 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -2734,7 +2734,7 @@ func (q *FakeQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) ( return q.getWorkspaceBuildByIDNoLock(ctx, id) } -func (q *FakeQuerier) GetWorkspaceBuildByJobID(_g context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { +func (q *FakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { q.mutex.RLock() defer q.mutex.RUnlock() diff --git a/coderd/database/migrations/000141_workspace_deleting_at.down.sql b/coderd/database/migrations/000140_workspace_deleting_at.down.sql similarity index 100% rename from coderd/database/migrations/000141_workspace_deleting_at.down.sql rename to coderd/database/migrations/000140_workspace_deleting_at.down.sql diff --git a/coderd/database/migrations/000141_workspace_deleting_at.up.sql b/coderd/database/migrations/000140_workspace_deleting_at.up.sql similarity index 100% rename from coderd/database/migrations/000141_workspace_deleting_at.up.sql rename to coderd/database/migrations/000140_workspace_deleting_at.up.sql diff --git a/coderd/database/migrations/000140_join_users_build_version.down.sql b/coderd/database/migrations/000141_join_users_build_version.down.sql similarity index 100% rename from coderd/database/migrations/000140_join_users_build_version.down.sql rename to coderd/database/migrations/000141_join_users_build_version.down.sql diff --git a/coderd/database/migrations/000140_join_users_build_version.up.sql b/coderd/database/migrations/000141_join_users_build_version.up.sql similarity index 100% rename from coderd/database/migrations/000140_join_users_build_version.up.sql rename to coderd/database/migrations/000141_join_users_build_version.up.sql diff --git a/coderd/database/models_test.go b/coderd/database/models_test.go index 0171433dae5aa..1ebb40ae2ff26 100644 --- a/coderd/database/models_test.go +++ b/coderd/database/models_test.go @@ -23,6 +23,34 @@ func TestViewSubsetTemplate(t *testing.T) { } } +// TestViewSubsetTemplateVersion ensures TemplateVersionTable is a subset TemplateVersion +func TestViewSubsetTemplateVersion(t *testing.T) { + t.Parallel() + table := reflect.TypeOf(database.TemplateVersionTable{}) + joined := reflect.TypeOf(database.TemplateVersion{}) + + tableFields := allFields(table) + joinedFields := allFields(joined) + if !assert.Subset(t, fieldNames(joinedFields), fieldNames(tableFields), "table is not subset") { + t.Log("Some fields were added to the TemplateVersion Table without updating the 'template_version_with_user' view.") + t.Log("See migration 000141_join_users_build_version.up.sql to create the view.") + } +} + +// TestViewSubsetWorkspaceBuild ensures WorkspaceBuildTable is a subset of WorkspaceBuild +func TestViewSubsetWorkspaceBuild(t *testing.T) { + t.Parallel() + table := reflect.TypeOf(database.WorkspaceBuildTable{}) + joined := reflect.TypeOf(database.WorkspaceBuild{}) + + tableFields := allFields(table) + joinedFields := allFields(joined) + if !assert.Subset(t, fieldNames(joinedFields), fieldNames(tableFields), "table is not subset") { + t.Log("Some fields were added to the WorkspaceBuild Table without updating the 'workspace_build_with_user' view.") + t.Log("See migration 000141_join_users_build_version.up.sql to create the view.") + } +} + func fieldNames(fields []reflect.StructField) []string { names := make([]string, len(fields)) for i, field := range fields {