chore: join user information to workspace_build and template_version (#8625)

* include minimial user on template version and build
* Add unit test to ensure join is superset
This commit is contained in:
Steven Masley 2023-07-25 09:14:38 -04:00 committed by GitHub
parent fbb2a6a434
commit de1a7a9210
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 819 additions and 717 deletions

View File

@ -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,

View File

@ -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,

22
coderd/apidoc/docs.go generated
View File

@ -8269,6 +8269,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": {
@ -9476,7 +9496,7 @@ const docTemplate = `{
"format": "date-time"
},
"created_by": {
"$ref": "#/definitions/codersdk.User"
"$ref": "#/definitions/codersdk.MinimalUser"
},
"id": {
"type": "string",

View File

@ -7408,6 +7408,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": {
@ -8560,7 +8577,7 @@
"format": "date-time"
},
"created_by": {
"$ref": "#/definitions/codersdk.User"
"$ref": "#/definitions/codersdk.MinimalUser"
},
"id": {
"type": "string",

View File

@ -1839,23 +1839,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
}
}
@ -1954,10 +1954,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
@ -1966,7 +1966,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)
@ -2195,11 +2195,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 {
@ -2207,12 +2207,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)
}
@ -2468,28 +2468,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)
}

View File

@ -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{})
@ -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)

View File

@ -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
}
}
@ -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 history, nil
for _, build := range q.workspaceBuilds {
if build.ID == id {
return q.workspaceBuildWithUserNoLock(build), 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
}
}
@ -475,7 +475,41 @@ 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
}
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
}
@ -484,7 +518,7 @@ func (q *FakeQuerier) getTemplateVersionByIDNoLock(_ context.Context, templateVe
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
@ -2082,7 +2116,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
}
@ -2102,7 +2136,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
}
@ -2149,7 +2183,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
}
}
@ -2173,7 +2207,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
@ -2231,7 +2265,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
@ -2901,7 +2935,7 @@ func (q *FakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUI
for _, build := range q.workspaceBuilds {
if build.JobID == jobID {
return build, nil
return q.workspaceBuildWithUserNoLock(build), nil
}
}
return database.WorkspaceBuild{}, sql.ErrNoRows
@ -2922,7 +2956,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
}
@ -2957,7 +2991,7 @@ func (q *FakeQuerier) GetWorkspaceBuildsByWorkspaceID(_ context.Context,
continue
}
if workspaceBuild.WorkspaceID == params.WorkspaceID {
history = append(history, workspaceBuild)
history = append(history, q.workspaceBuildWithUserNoLock(workspaceBuild))
}
}
@ -3011,7 +3045,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
@ -3686,20 +3720,20 @@ 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()
defer q.mutex.Unlock()
//nolint:gosimple
version := database.TemplateVersion{
version := database.TemplateVersionTable{
ID: arg.ID,
TemplateID: arg.TemplateID,
OrganizationID: arg.OrganizationID,
@ -3712,7 +3746,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) {
@ -4043,15 +4077,15 @@ 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()
defer q.mutex.Unlock()
workspaceBuild := database.WorkspaceBuild{
workspaceBuild := database.WorkspaceBuildTable{
ID: arg.ID,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
@ -4066,7 +4100,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 {
@ -4505,9 +4539,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()
@ -4522,9 +4556,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 {
@ -4968,9 +5002,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()
@ -4985,14 +5019,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()
@ -5004,9 +5038,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 {

View File

@ -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),
})
buildID := takeFirst(orig.ID, uuid.New())
var build database.WorkspaceBuild
err := db.InTx(func(db database.Store) error {
err := db.InsertWorkspaceBuild(genCtx, database.InsertWorkspaceBuildParams{
ID: buildID,
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, buildID)
if err != nil {
return err
}
return nil
}, nil)
require.NoError(t, err, "insert workspace build")
return build
}
@ -474,19 +487,33 @@ 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 {
versionID := takeFirst(orig.ID, uuid.New())
err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{
ID: versionID,
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, versionID)
if err != nil {
return err
}
return nil
}, nil)
require.NoError(t, err, "insert template version")
return version
}

View File

@ -1131,11 +1131,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) {
@ -1215,11 +1215,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 {
@ -1362,11 +1362,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 {
@ -1509,18 +1509,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 {

View File

@ -2377,12 +2377,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.
@ -2555,12 +2554,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.
@ -2875,12 +2873,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.
@ -3179,12 +3176,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.
@ -3194,12 +3190,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.

View File

@ -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,

View File

@ -0,0 +1,6 @@
BEGIN;
DROP VIEW workspace_build_with_user;
DROP VIEW template_version_with_user;
COMMIT;

View File

@ -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;

View File

@ -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
@ -1858,7 +1875,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"`
@ -1875,14 +1920,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"`

View File

@ -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 {

View File

@ -205,7 +205,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)
@ -218,7 +218,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)
@ -243,7 +243,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
@ -264,8 +264,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
UpdateWorkspaceLockedDeletingAt(ctx context.Context, arg UpdateWorkspaceLockedDeletingAtParams) error

View File

@ -4478,13 +4478,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
@ -4514,15 +4514,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
`
@ -4542,15 +4544,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
`
@ -4570,15 +4574,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
@ -4604,15 +4610,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 [ ])
`
@ -4638,6 +4646,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
}
@ -4654,9 +4664,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
@ -4720,6 +4730,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
}
@ -4735,7 +4747,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) {
@ -4759,6 +4771,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
}
@ -4773,7 +4787,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,
@ -4788,7 +4802,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 {
@ -4804,8 +4818,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,
@ -4817,24 +4831,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
@ -4843,7 +4843,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 {
@ -4854,29 +4854,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
@ -7444,9 +7430,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
@ -7473,22 +7459,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
`
@ -7516,6 +7504,8 @@ func (q *sqlQuerier) GetLatestWorkspaceBuilds(ctx context.Context) ([]WorkspaceB
&i.Reason,
&i.DailyCost,
&i.MaxDeadline,
&i.InitiatorByAvatarUrl,
&i.InitiatorByUsername,
); err != nil {
return nil, err
}
@ -7531,19 +7521,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
`
@ -7571,6 +7561,8 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context,
&i.Reason,
&i.DailyCost,
&i.MaxDeadline,
&i.InitiatorByAvatarUrl,
&i.InitiatorByUsername,
); err != nil {
return nil, err
}
@ -7587,9 +7579,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
@ -7614,15 +7606,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
@ -7647,15 +7641,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
@ -7684,15 +7680,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
@ -7760,6 +7758,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
}
@ -7775,7 +7775,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) {
@ -7802,6 +7802,8 @@ func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, created
&i.Reason,
&i.DailyCost,
&i.MaxDeadline,
&i.InitiatorByAvatarUrl,
&i.InitiatorByUsername,
); err != nil {
return nil, err
}
@ -7816,7 +7818,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,
@ -7834,7 +7836,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 {
@ -7853,8 +7855,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,
@ -7869,27 +7871,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
@ -7898,7 +7883,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 {
@ -7909,41 +7894,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 {
@ -7951,26 +7919,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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)
@ -384,8 +385,8 @@ func TestCache_BuildTime(t *testing.T) {
})
require.NoError(t, err)
_, err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{
TemplateVersionID: templateVersion.ID,
err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{
TemplateVersionID: templateVersionID,
JobID: job.ID,
Transition: tt.args.transition,
Reason: database.BuildReasonInitiator,

View File

@ -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,

View File

@ -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,

View File

@ -558,8 +558,9 @@ func TestUpdateJob(t *testing.T) {
t.Parallel()
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)
@ -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)
@ -749,17 +752,19 @@ func TestFailJob(t *testing.T) {
ID: uuid.New(),
})
require.NoError(t, err)
build, err := srv.Database.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{
ID: uuid.New(),
buildID := uuid.New()
err = srv.Database.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{
ID: buildID,
WorkspaceID: workspace.ID,
Transition: database.WorkspaceTransitionStart,
Reason: database.BuildReasonInitiator,
})
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{
ID: uuid.New(),
Input: input,
@ -778,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)
@ -801,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))
})
@ -851,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,
})

View File

@ -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,

View File

@ -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,
}
}

View File

@ -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,

View File

@ -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()),

View File

@ -884,7 +884,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,

View File

@ -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
}

View File

@ -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)
@ -108,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}
@ -140,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}
@ -173,6 +180,8 @@ func TestBuilder_ActiveVersion(t *testing.T) {
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
asrt.Equal(activeFileID, job.FileID)
}),
withInTx,
expectBuild(func(bld database.InsertWorkspaceBuildParams) {
asrt.Equal(activeVersionID, bld.TemplateVersionID)
// no previous build...
@ -181,6 +190,7 @@ func TestBuilder_ActiveVersion(t *testing.T) {
}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
}),
withBuild,
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
@ -248,6 +258,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))
@ -257,6 +268,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
asrt.Equal(value, params.Value[i])
}
}),
withBuild,
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
@ -289,6 +301,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))
@ -298,6 +311,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
asrt.Equal(value, params.Value[i])
}
}),
withBuild,
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
@ -336,6 +350,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
withInTx,
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
)
@ -370,6 +385,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) {}),
@ -422,6 +438,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))
@ -431,6 +448,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
asrt.Equal(value, params.Value[i])
}
}),
withBuild,
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
@ -480,6 +498,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))
@ -489,6 +508,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
asrt.Equal(value, params.Value[i])
}
}),
withBuild,
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
@ -536,6 +556,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))
@ -545,6 +566,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
asrt.Equal(value, params.Value[i])
}
}),
withBuild,
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
@ -592,6 +614,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 +789,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 +805,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
},
)
}

View File

@ -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"`
}

View File

@ -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"`

View File

@ -17,10 +17,10 @@ We track the following resources:
| GitSSHKey<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>private_key</td><td>true</td></tr><tr><td>public_key</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>active_version_id</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>inactivity_ttl</td><td>true</td></tr><tr><td>locked_ttl</td><td>true</td></tr><tr><td>max_ttl</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>restart_requirement_days_of_week</td><td>true</td></tr><tr><td>restart_requirement_weeks</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>git_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>git_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
| Workspace<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>locked_at</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
<!-- End generated by 'make docs/admin/audit-logs.md'. -->

32
docs/api/schemas.md generated
View File

@ -3117,6 +3117,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
@ -4366,19 +4384,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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@ -4415,7 +4421,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 | | |

240
docs/api/templates.md generated
View File

@ -376,19 +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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@ -458,19 +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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@ -564,19 +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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@ -877,19 +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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@ -932,58 +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 | | |
| `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | 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 |
| ------------ | ----------------------------- |
| `login_type` | `password` |
| `login_type` | `github` |
| `login_type` | `oidc` |
| `login_type` | `token` |
| `login_type` | `none` |
| `status` | `active` |
| `status` | `suspended` |
| `error_code` | `MISSING_TEMPLATE_PARAMETER` |
| `error_code` | `REQUIRED_TEMPLATE_VARIABLES` |
| `status` | `pending` |
@ -1079,19 +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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@ -1134,58 +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 | | |
| `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | 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 |
| ------------ | ----------------------------- |
| `login_type` | `password` |
| `login_type` | `github` |
| `login_type` | `oidc` |
| `login_type` | `token` |
| `login_type` | `none` |
| `status` | `active` |
| `status` | `suspended` |
| `error_code` | `MISSING_TEMPLATE_PARAMETER` |
| `error_code` | `REQUIRED_TEMPLATE_VARIABLES` |
| `status` | `pending` |
@ -1225,19 +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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
@ -1316,19 +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",
"login_type": "password",
"organization_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"],
"roles": [
{
"display_name": "string",
"name": "string"
}
],
"status": "active",
"username": "string"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",

View File

@ -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,
@ -129,20 +131,22 @@ var auditableResourcesTypes = map[any]map[string]Action{
"deleting_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,

View File

@ -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,
})

View File

@ -560,6 +560,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
@ -984,7 +991,7 @@ export interface TemplateVersion {
readonly message: string
readonly job: ProvisionerJob
readonly readme: string
readonly created_by: User
readonly created_by: MinimalUser
readonly warnings?: TemplateVersionWarning[]
}