chore: Rename Projects to Templates (#880)

Customer feedback indicated projects was a confusing name.
After querying the team internally, it seemed unanimous
that it is indeed a confusing name.

Here's for a lil less confusion @ashmeer7 🥂
This commit is contained in:
Kyle Carberry
2022-04-06 12:42:40 -05:00
committed by GitHub
parent 584c8b4fc3
commit 02ad3f14f5
109 changed files with 2548 additions and 2547 deletions
+20 -20
View File
@@ -76,11 +76,11 @@ func New(options *Options) (http.Handler, func()) {
)
r.Get("/", api.organization)
r.Get("/provisionerdaemons", api.provisionerDaemonsByOrganization)
r.Post("/projectversions", api.postProjectVersionsByOrganization)
r.Route("/projects", func(r chi.Router) {
r.Post("/", api.postProjectsByOrganization)
r.Get("/", api.projectsByOrganization)
r.Get("/{projectname}", api.projectByOrganizationAndName)
r.Post("/templateversions", api.postTemplateVersionsByOrganization)
r.Route("/templates", func(r chi.Router) {
r.Post("/", api.postTemplatesByOrganization)
r.Get("/", api.templatesByOrganization)
r.Get("/{templatename}", api.templateByOrganizationAndName)
})
})
r.Route("/parameters/{scope}/{id}", func(r chi.Router) {
@@ -91,33 +91,33 @@ func New(options *Options) (http.Handler, func()) {
r.Delete("/", api.deleteParameter)
})
})
r.Route("/projects/{project}", func(r chi.Router) {
r.Route("/templates/{template}", func(r chi.Router) {
r.Use(
httpmw.ExtractAPIKey(options.Database, nil),
httpmw.ExtractProjectParam(options.Database),
httpmw.ExtractTemplateParam(options.Database),
httpmw.ExtractOrganizationParam(options.Database),
)
r.Get("/", api.project)
r.Delete("/", api.deleteProject)
r.Get("/", api.template)
r.Delete("/", api.deleteTemplate)
r.Route("/versions", func(r chi.Router) {
r.Get("/", api.projectVersionsByProject)
r.Patch("/", api.patchActiveProjectVersion)
r.Get("/{projectversionname}", api.projectVersionByName)
r.Get("/", api.templateVersionsByTemplate)
r.Patch("/", api.patchActiveTemplateVersion)
r.Get("/{templateversionname}", api.templateVersionByName)
})
})
r.Route("/projectversions/{projectversion}", func(r chi.Router) {
r.Route("/templateversions/{templateversion}", func(r chi.Router) {
r.Use(
httpmw.ExtractAPIKey(options.Database, nil),
httpmw.ExtractProjectVersionParam(options.Database),
httpmw.ExtractTemplateVersionParam(options.Database),
httpmw.ExtractOrganizationParam(options.Database),
)
r.Get("/", api.projectVersion)
r.Patch("/cancel", api.patchCancelProjectVersion)
r.Get("/schema", api.projectVersionSchema)
r.Get("/parameters", api.projectVersionParameters)
r.Get("/resources", api.projectVersionResources)
r.Get("/logs", api.projectVersionLogs)
r.Get("/", api.templateVersion)
r.Patch("/cancel", api.patchCancelTemplateVersion)
r.Get("/schema", api.templateVersionSchema)
r.Get("/parameters", api.templateVersionParameters)
r.Get("/resources", api.templateVersionResources)
r.Get("/logs", api.templateVersionLogs)
})
r.Route("/provisionerdaemons", func(r chi.Router) {
r.Route("/me", func(r chi.Router) {
+18 -18
View File
@@ -203,44 +203,44 @@ func CreateAnotherUser(t *testing.T, client *codersdk.Client, organizationID uui
return other
}
// CreateProjectVersion creates a project import provisioner job
// CreateTemplateVersion creates a template import provisioner job
// with the responses provided. It uses the "echo" provisioner for compatibility
// with testing.
func CreateProjectVersion(t *testing.T, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses) codersdk.ProjectVersion {
func CreateTemplateVersion(t *testing.T, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses) codersdk.TemplateVersion {
data, err := echo.Tar(res)
require.NoError(t, err)
file, err := client.Upload(context.Background(), codersdk.ContentTypeTar, data)
require.NoError(t, err)
projectVersion, err := client.CreateProjectVersion(context.Background(), organizationID, codersdk.CreateProjectVersionRequest{
templateVersion, err := client.CreateTemplateVersion(context.Background(), organizationID, codersdk.CreateTemplateVersionRequest{
StorageSource: file.Hash,
StorageMethod: database.ProvisionerStorageMethodFile,
Provisioner: database.ProvisionerTypeEcho,
})
require.NoError(t, err)
return projectVersion
return templateVersion
}
// CreateProject creates a project with the "echo" provisioner for
// CreateTemplate creates a template with the "echo" provisioner for
// compatibility with testing. The name assigned is randomly generated.
func CreateProject(t *testing.T, client *codersdk.Client, organization uuid.UUID, version uuid.UUID) codersdk.Project {
project, err := client.CreateProject(context.Background(), organization, codersdk.CreateProjectRequest{
func CreateTemplate(t *testing.T, client *codersdk.Client, organization uuid.UUID, version uuid.UUID) codersdk.Template {
template, err := client.CreateTemplate(context.Background(), organization, codersdk.CreateTemplateRequest{
Name: randomUsername(),
VersionID: version,
})
require.NoError(t, err)
return project
return template
}
// AwaitProjectImportJob awaits for an import job to reach completed status.
func AwaitProjectVersionJob(t *testing.T, client *codersdk.Client, version uuid.UUID) codersdk.ProjectVersion {
var projectVersion codersdk.ProjectVersion
// AwaitTemplateImportJob awaits for an import job to reach completed status.
func AwaitTemplateVersionJob(t *testing.T, client *codersdk.Client, version uuid.UUID) codersdk.TemplateVersion {
var templateVersion codersdk.TemplateVersion
require.Eventually(t, func() bool {
var err error
projectVersion, err = client.ProjectVersion(context.Background(), version)
templateVersion, err = client.TemplateVersion(context.Background(), version)
require.NoError(t, err)
return projectVersion.Job.CompletedAt != nil
return templateVersion.Job.CompletedAt != nil
}, 5*time.Second, 25*time.Millisecond)
return projectVersion
return templateVersion
}
// AwaitWorkspaceBuildJob waits for a workspace provision job to reach completed status.
@@ -275,12 +275,12 @@ func AwaitWorkspaceAgents(t *testing.T, client *codersdk.Client, build uuid.UUID
return resources
}
// CreateWorkspace creates a workspace for the user and project provided.
// CreateWorkspace creates a workspace for the user and template provided.
// A random name is generated for it.
func CreateWorkspace(t *testing.T, client *codersdk.Client, user uuid.UUID, projectID uuid.UUID) codersdk.Workspace {
func CreateWorkspace(t *testing.T, client *codersdk.Client, user uuid.UUID, templateID uuid.UUID) codersdk.Workspace {
workspace, err := client.CreateWorkspace(context.Background(), user, codersdk.CreateWorkspaceRequest{
ProjectID: projectID,
Name: randomUsername(),
TemplateID: templateID,
Name: randomUsername(),
})
require.NoError(t, err)
return workspace
+4 -4
View File
@@ -18,10 +18,10 @@ func TestNew(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
closer := coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID)
_, _ = coderdtest.NewGoogleInstanceIdentity(t, "example", false)
+105 -105
View File
@@ -22,8 +22,8 @@ func New() database.Store {
files: make([]database.File, 0),
parameterValue: make([]database.ParameterValue, 0),
parameterSchema: make([]database.ParameterSchema, 0),
project: make([]database.Project, 0),
projectVersion: make([]database.ProjectVersion, 0),
template: make([]database.Template, 0),
templateVersion: make([]database.TemplateVersion, 0),
provisionerDaemons: make([]database.ProvisionerDaemon, 0),
provisionerJobs: make([]database.ProvisionerJob, 0),
provisionerJobLog: make([]database.ProvisionerJobLog, 0),
@@ -49,8 +49,8 @@ type fakeQuerier struct {
files []database.File
parameterValue []database.ParameterValue
parameterSchema []database.ParameterSchema
project []database.Project
projectVersion []database.ProjectVersion
template []database.Template
templateVersion []database.TemplateVersion
provisionerDaemons []database.ProvisionerDaemon
provisionerJobs []database.ProvisionerJob
provisionerJobAgent []database.WorkspaceAgent
@@ -164,13 +164,13 @@ func (q *fakeQuerier) GetUserCount(_ context.Context) (int64, error) {
return int64(len(q.users)), nil
}
func (q *fakeQuerier) GetWorkspacesByProjectID(_ context.Context, arg database.GetWorkspacesByProjectIDParams) ([]database.Workspace, error) {
func (q *fakeQuerier) GetWorkspacesByTemplateID(_ context.Context, arg database.GetWorkspacesByTemplateIDParams) ([]database.Workspace, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
workspaces := make([]database.Workspace, 0)
for _, workspace := range q.workspace {
if workspace.ProjectID.String() != arg.ProjectID.String() {
if workspace.TemplateID.String() != arg.TemplateID.String() {
continue
}
if workspace.Deleted != arg.Deleted {
@@ -215,38 +215,38 @@ func (q *fakeQuerier) GetWorkspaceByUserIDAndName(_ context.Context, arg databas
return database.Workspace{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetWorkspaceOwnerCountsByProjectIDs(_ context.Context, projectIDs []uuid.UUID) ([]database.GetWorkspaceOwnerCountsByProjectIDsRow, error) {
func (q *fakeQuerier) GetWorkspaceOwnerCountsByTemplateIDs(_ context.Context, templateIDs []uuid.UUID) ([]database.GetWorkspaceOwnerCountsByTemplateIDsRow, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
counts := map[uuid.UUID]map[uuid.UUID]struct{}{}
for _, projectID := range projectIDs {
for _, templateID := range templateIDs {
found := false
for _, workspace := range q.workspace {
if workspace.ProjectID != projectID {
if workspace.TemplateID != templateID {
continue
}
if workspace.Deleted {
continue
}
countByOwnerID, ok := counts[projectID]
countByOwnerID, ok := counts[templateID]
if !ok {
countByOwnerID = map[uuid.UUID]struct{}{}
}
countByOwnerID[workspace.OwnerID] = struct{}{}
counts[projectID] = countByOwnerID
counts[templateID] = countByOwnerID
found = true
break
}
if !found {
counts[projectID] = map[uuid.UUID]struct{}{}
counts[templateID] = map[uuid.UUID]struct{}{}
}
}
res := make([]database.GetWorkspaceOwnerCountsByProjectIDsRow, 0)
res := make([]database.GetWorkspaceOwnerCountsByTemplateIDsRow, 0)
for key, value := range counts {
res = append(res, database.GetWorkspaceOwnerCountsByProjectIDsRow{
ProjectID: key,
Count: int64(len(value)),
res = append(res, database.GetWorkspaceOwnerCountsByTemplateIDsRow{
TemplateID: key,
Count: int64(len(value)),
})
}
if len(res) == 0 {
@@ -431,47 +431,47 @@ func (q *fakeQuerier) GetParameterValuesByScope(_ context.Context, arg database.
return parameterValues, nil
}
func (q *fakeQuerier) GetProjectByID(_ context.Context, id uuid.UUID) (database.Project, error) {
func (q *fakeQuerier) GetTemplateByID(_ context.Context, id uuid.UUID) (database.Template, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
for _, project := range q.project {
if project.ID.String() == id.String() {
return project, nil
for _, template := range q.template {
if template.ID.String() == id.String() {
return template, nil
}
}
return database.Project{}, sql.ErrNoRows
return database.Template{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetProjectByOrganizationAndName(_ context.Context, arg database.GetProjectByOrganizationAndNameParams) (database.Project, error) {
func (q *fakeQuerier) GetTemplateByOrganizationAndName(_ context.Context, arg database.GetTemplateByOrganizationAndNameParams) (database.Template, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
for _, project := range q.project {
if project.OrganizationID != arg.OrganizationID {
for _, template := range q.template {
if template.OrganizationID != arg.OrganizationID {
continue
}
if !strings.EqualFold(project.Name, arg.Name) {
if !strings.EqualFold(template.Name, arg.Name) {
continue
}
if project.Deleted != arg.Deleted {
if template.Deleted != arg.Deleted {
continue
}
return project, nil
return template, nil
}
return database.Project{}, sql.ErrNoRows
return database.Template{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetProjectVersionsByProjectID(_ context.Context, projectID uuid.UUID) ([]database.ProjectVersion, error) {
func (q *fakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, templateID uuid.UUID) ([]database.TemplateVersion, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
version := make([]database.ProjectVersion, 0)
for _, projectVersion := range q.projectVersion {
if projectVersion.ProjectID.UUID.String() != projectID.String() {
version := make([]database.TemplateVersion, 0)
for _, templateVersion := range q.templateVersion {
if templateVersion.TemplateID.UUID.String() != templateID.String() {
continue
}
version = append(version, projectVersion)
version = append(version, templateVersion)
}
if len(version) == 0 {
return nil, sql.ErrNoRows
@@ -479,46 +479,46 @@ func (q *fakeQuerier) GetProjectVersionsByProjectID(_ context.Context, projectID
return version, nil
}
func (q *fakeQuerier) GetProjectVersionByProjectIDAndName(_ context.Context, arg database.GetProjectVersionByProjectIDAndNameParams) (database.ProjectVersion, error) {
func (q *fakeQuerier) GetTemplateVersionByTemplateIDAndName(_ context.Context, arg database.GetTemplateVersionByTemplateIDAndNameParams) (database.TemplateVersion, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
for _, projectVersion := range q.projectVersion {
if projectVersion.ProjectID != arg.ProjectID {
for _, templateVersion := range q.templateVersion {
if templateVersion.TemplateID != arg.TemplateID {
continue
}
if !strings.EqualFold(projectVersion.Name, arg.Name) {
if !strings.EqualFold(templateVersion.Name, arg.Name) {
continue
}
return projectVersion, nil
return templateVersion, nil
}
return database.ProjectVersion{}, sql.ErrNoRows
return database.TemplateVersion{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetProjectVersionByID(_ context.Context, projectVersionID uuid.UUID) (database.ProjectVersion, error) {
func (q *fakeQuerier) GetTemplateVersionByID(_ context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
for _, projectVersion := range q.projectVersion {
if projectVersion.ID.String() != projectVersionID.String() {
for _, templateVersion := range q.templateVersion {
if templateVersion.ID.String() != templateVersionID.String() {
continue
}
return projectVersion, nil
return templateVersion, nil
}
return database.ProjectVersion{}, sql.ErrNoRows
return database.TemplateVersion{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetProjectVersionByJobID(_ context.Context, jobID uuid.UUID) (database.ProjectVersion, error) {
func (q *fakeQuerier) GetTemplateVersionByJobID(_ context.Context, jobID uuid.UUID) (database.TemplateVersion, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
for _, projectVersion := range q.projectVersion {
if projectVersion.JobID.String() != jobID.String() {
for _, templateVersion := range q.templateVersion {
if templateVersion.JobID.String() != jobID.String() {
continue
}
return projectVersion, nil
return templateVersion, nil
}
return database.ProjectVersion{}, sql.ErrNoRows
return database.TemplateVersion{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.UUID) ([]database.ParameterSchema, error) {
@@ -557,43 +557,43 @@ func (q *fakeQuerier) GetParameterValueByScopeAndName(_ context.Context, arg dat
return database.ParameterValue{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetProjectsByOrganization(_ context.Context, arg database.GetProjectsByOrganizationParams) ([]database.Project, error) {
func (q *fakeQuerier) GetTemplatesByOrganization(_ context.Context, arg database.GetTemplatesByOrganizationParams) ([]database.Template, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
projects := make([]database.Project, 0)
for _, project := range q.project {
if project.Deleted != arg.Deleted {
templates := make([]database.Template, 0)
for _, template := range q.template {
if template.Deleted != arg.Deleted {
continue
}
if project.OrganizationID != arg.OrganizationID {
if template.OrganizationID != arg.OrganizationID {
continue
}
projects = append(projects, project)
templates = append(templates, template)
}
if len(projects) == 0 {
if len(templates) == 0 {
return nil, sql.ErrNoRows
}
return projects, nil
return templates, nil
}
func (q *fakeQuerier) GetProjectsByIDs(_ context.Context, ids []uuid.UUID) ([]database.Project, error) {
func (q *fakeQuerier) GetTemplatesByIDs(_ context.Context, ids []uuid.UUID) ([]database.Template, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
projects := make([]database.Project, 0)
for _, project := range q.project {
templates := make([]database.Template, 0)
for _, template := range q.template {
for _, id := range ids {
if project.ID.String() != id.String() {
if template.ID.String() != id.String() {
continue
}
projects = append(projects, project)
templates = append(templates, template)
}
}
if len(projects) == 0 {
if len(templates) == 0 {
return nil, sql.ErrNoRows
}
return projects, nil
return templates, nil
}
func (q *fakeQuerier) GetOrganizationMemberByUserID(_ context.Context, arg database.GetOrganizationMemberByUserIDParams) (database.OrganizationMember, error) {
@@ -850,12 +850,12 @@ func (q *fakeQuerier) InsertParameterValue(_ context.Context, arg database.Inser
return parameterValue, nil
}
func (q *fakeQuerier) InsertProject(_ context.Context, arg database.InsertProjectParams) (database.Project, error) {
func (q *fakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTemplateParams) (database.Template, error) {
q.mutex.Lock()
defer q.mutex.Unlock()
//nolint:gosimple
project := database.Project{
template := database.Template{
ID: arg.ID,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
@@ -864,18 +864,18 @@ func (q *fakeQuerier) InsertProject(_ context.Context, arg database.InsertProjec
Provisioner: arg.Provisioner,
ActiveVersionID: arg.ActiveVersionID,
}
q.project = append(q.project, project)
return project, nil
q.template = append(q.template, template)
return template, nil
}
func (q *fakeQuerier) InsertProjectVersion(_ context.Context, arg database.InsertProjectVersionParams) (database.ProjectVersion, error) {
func (q *fakeQuerier) InsertTemplateVersion(_ context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) {
q.mutex.Lock()
defer q.mutex.Unlock()
//nolint:gosimple
version := database.ProjectVersion{
version := database.TemplateVersion{
ID: arg.ID,
ProjectID: arg.ProjectID,
TemplateID: arg.TemplateID,
OrganizationID: arg.OrganizationID,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
@@ -883,7 +883,7 @@ func (q *fakeQuerier) InsertProjectVersion(_ context.Context, arg database.Inser
Description: arg.Description,
JobID: arg.JobID,
}
q.projectVersion = append(q.projectVersion, version)
q.templateVersion = append(q.templateVersion, version)
return version, nil
}
@@ -1033,12 +1033,12 @@ func (q *fakeQuerier) InsertWorkspace(_ context.Context, arg database.InsertWork
//nolint:gosimple
workspace := database.Workspace{
ID: arg.ID,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
OwnerID: arg.OwnerID,
ProjectID: arg.ProjectID,
Name: arg.Name,
ID: arg.ID,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
OwnerID: arg.OwnerID,
TemplateID: arg.TemplateID,
Name: arg.Name,
}
q.workspace = append(q.workspace, workspace)
return workspace, nil
@@ -1049,17 +1049,17 @@ func (q *fakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.Inser
defer q.mutex.Unlock()
workspaceBuild := database.WorkspaceBuild{
ID: arg.ID,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
WorkspaceID: arg.WorkspaceID,
Name: arg.Name,
ProjectVersionID: arg.ProjectVersionID,
BeforeID: arg.BeforeID,
Transition: arg.Transition,
InitiatorID: arg.InitiatorID,
JobID: arg.JobID,
ProvisionerState: arg.ProvisionerState,
ID: arg.ID,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
WorkspaceID: arg.WorkspaceID,
Name: arg.Name,
TemplateVersionID: arg.TemplateVersionID,
BeforeID: arg.BeforeID,
Transition: arg.Transition,
InitiatorID: arg.InitiatorID,
JobID: arg.JobID,
ProvisionerState: arg.ProvisionerState,
}
q.workspaceBuild = append(q.workspaceBuild, workspaceBuild)
return workspaceBuild, nil
@@ -1084,47 +1084,47 @@ func (q *fakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPI
return sql.ErrNoRows
}
func (q *fakeQuerier) UpdateProjectActiveVersionByID(_ context.Context, arg database.UpdateProjectActiveVersionByIDParams) error {
func (q *fakeQuerier) UpdateTemplateActiveVersionByID(_ context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error {
q.mutex.Lock()
defer q.mutex.Unlock()
for index, project := range q.project {
if project.ID.String() != arg.ID.String() {
for index, template := range q.template {
if template.ID.String() != arg.ID.String() {
continue
}
project.ActiveVersionID = arg.ActiveVersionID
q.project[index] = project
template.ActiveVersionID = arg.ActiveVersionID
q.template[index] = template
return nil
}
return sql.ErrNoRows
}
func (q *fakeQuerier) UpdateProjectDeletedByID(_ context.Context, arg database.UpdateProjectDeletedByIDParams) error {
func (q *fakeQuerier) UpdateTemplateDeletedByID(_ context.Context, arg database.UpdateTemplateDeletedByIDParams) error {
q.mutex.Lock()
defer q.mutex.Unlock()
for index, project := range q.project {
if project.ID.String() != arg.ID.String() {
for index, template := range q.template {
if template.ID.String() != arg.ID.String() {
continue
}
project.Deleted = arg.Deleted
q.project[index] = project
template.Deleted = arg.Deleted
q.template[index] = template
return nil
}
return sql.ErrNoRows
}
func (q *fakeQuerier) UpdateProjectVersionByID(_ context.Context, arg database.UpdateProjectVersionByIDParams) error {
func (q *fakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) error {
q.mutex.Lock()
defer q.mutex.Unlock()
for index, projectVersion := range q.projectVersion {
if projectVersion.ID.String() != arg.ID.String() {
for index, templateVersion := range q.templateVersion {
if templateVersion.ID.String() != arg.ID.String() {
continue
}
projectVersion.ProjectID = arg.ProjectID
projectVersion.UpdatedAt = arg.UpdatedAt
q.projectVersion[index] = projectVersion
templateVersion.TemplateID = arg.TemplateID
templateVersion.UpdatedAt = arg.UpdatedAt
q.templateVersion[index] = templateVersion
return nil
}
return sql.ErrNoRows
+51 -51
View File
@@ -27,7 +27,7 @@ CREATE TYPE parameter_destination_scheme AS ENUM (
CREATE TYPE parameter_scope AS ENUM (
'organization',
'project',
'template',
'import_job',
'user',
'workspace'
@@ -44,7 +44,7 @@ CREATE TYPE parameter_type_system AS ENUM (
);
CREATE TYPE provisioner_job_type AS ENUM (
'project_version_import',
'template_version_import',
'workspace_build'
);
@@ -160,28 +160,6 @@ CREATE TABLE parameter_values (
destination_scheme parameter_destination_scheme NOT NULL
);
CREATE TABLE project_versions (
id uuid NOT NULL,
project_id uuid,
organization_id uuid NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
name character varying(64) NOT NULL,
description character varying(1048576) NOT NULL,
job_id uuid NOT NULL
);
CREATE TABLE projects (
id uuid NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
organization_id uuid NOT NULL,
deleted boolean DEFAULT false NOT NULL,
name character varying(64) NOT NULL,
provisioner provisioner_type NOT NULL,
active_version_id uuid NOT NULL
);
CREATE TABLE provisioner_daemons (
id uuid NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -219,6 +197,28 @@ CREATE TABLE provisioner_jobs (
worker_id uuid
);
CREATE TABLE template_versions (
id uuid NOT NULL,
template_id uuid,
organization_id uuid NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
name character varying(64) NOT NULL,
description character varying(1048576) NOT NULL,
job_id uuid NOT NULL
);
CREATE TABLE templates (
id uuid NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
organization_id uuid NOT NULL,
deleted boolean DEFAULT false NOT NULL,
name character varying(64) NOT NULL,
provisioner provisioner_type NOT NULL,
active_version_id uuid NOT NULL
);
CREATE TABLE users (
id uuid NOT NULL,
email text NOT NULL,
@@ -252,7 +252,7 @@ CREATE TABLE workspace_builds (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
workspace_id uuid NOT NULL,
project_version_id uuid NOT NULL,
template_version_id uuid NOT NULL,
name character varying(64) NOT NULL,
before_id uuid,
after_id uuid,
@@ -278,7 +278,7 @@ CREATE TABLE workspaces (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
owner_id uuid NOT NULL,
project_id uuid NOT NULL,
template_id uuid NOT NULL,
deleted boolean DEFAULT false NOT NULL,
name character varying(64) NOT NULL
);
@@ -315,18 +315,6 @@ ALTER TABLE ONLY parameter_values
ALTER TABLE ONLY parameter_values
ADD CONSTRAINT parameter_values_scope_id_name_key UNIQUE (scope_id, name);
ALTER TABLE ONLY project_versions
ADD CONSTRAINT project_versions_pkey PRIMARY KEY (id);
ALTER TABLE ONLY project_versions
ADD CONSTRAINT project_versions_project_id_name_key UNIQUE (project_id, name);
ALTER TABLE ONLY projects
ADD CONSTRAINT projects_organization_id_name_key UNIQUE (organization_id, name);
ALTER TABLE ONLY projects
ADD CONSTRAINT projects_pkey PRIMARY KEY (id);
ALTER TABLE ONLY provisioner_daemons
ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
@@ -339,6 +327,18 @@ ALTER TABLE ONLY provisioner_job_logs
ALTER TABLE ONLY provisioner_jobs
ADD CONSTRAINT provisioner_jobs_pkey PRIMARY KEY (id);
ALTER TABLE ONLY template_versions
ADD CONSTRAINT template_versions_pkey PRIMARY KEY (id);
ALTER TABLE ONLY template_versions
ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name);
ALTER TABLE ONLY templates
ADD CONSTRAINT templates_organization_id_name_key UNIQUE (organization_id, name);
ALTER TABLE ONLY templates
ADD CONSTRAINT templates_pkey PRIMARY KEY (id);
ALTER TABLE ONLY users
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
@@ -373,7 +373,7 @@ CREATE UNIQUE INDEX idx_organization_name ON organizations USING btree (name);
CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name));
CREATE UNIQUE INDEX idx_projects_name_lower ON projects USING btree (lower((name)::text));
CREATE UNIQUE INDEX idx_templates_name_lower ON templates USING btree (lower((name)::text));
CREATE UNIQUE INDEX idx_users_email ON users USING btree (email);
@@ -381,7 +381,7 @@ CREATE UNIQUE INDEX idx_users_username ON users USING btree (username);
CREATE UNIQUE INDEX idx_workspaces_name_lower ON workspaces USING btree (lower((name)::text));
CREATE UNIQUE INDEX projects_organization_id_name_idx ON projects USING btree (organization_id, name) WHERE (deleted = false);
CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates USING btree (organization_id, name) WHERE (deleted = false);
CREATE UNIQUE INDEX users_username_lower_idx ON users USING btree (lower(username));
@@ -402,21 +402,21 @@ ALTER TABLE ONLY organization_members
ALTER TABLE ONLY parameter_schemas
ADD CONSTRAINT parameter_schemas_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
ALTER TABLE ONLY project_versions
ADD CONSTRAINT project_versions_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE ONLY project_versions
ADD CONSTRAINT project_versions_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY projects
ADD CONSTRAINT projects_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE ONLY provisioner_job_logs
ADD CONSTRAINT provisioner_job_logs_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
ALTER TABLE ONLY provisioner_jobs
ADD CONSTRAINT provisioner_jobs_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE ONLY template_versions
ADD CONSTRAINT template_versions_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE ONLY template_versions
ADD CONSTRAINT template_versions_template_id_fkey FOREIGN KEY (template_id) REFERENCES templates(id) ON DELETE CASCADE;
ALTER TABLE ONLY templates
ADD CONSTRAINT templates_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE ONLY workspace_agents
ADD CONSTRAINT workspace_agents_resource_id_fkey FOREIGN KEY (resource_id) REFERENCES workspace_resources(id) ON DELETE CASCADE;
@@ -424,7 +424,7 @@ ALTER TABLE ONLY workspace_builds
ADD CONSTRAINT workspace_builds_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
ALTER TABLE ONLY workspace_builds
ADD CONSTRAINT workspace_builds_project_version_id_fkey FOREIGN KEY (project_version_id) REFERENCES project_versions(id) ON DELETE CASCADE;
ADD CONSTRAINT workspace_builds_template_version_id_fkey FOREIGN KEY (template_version_id) REFERENCES template_versions(id) ON DELETE CASCADE;
ALTER TABLE ONLY workspace_builds
ADD CONSTRAINT workspace_builds_workspace_id_fkey FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE;
@@ -436,5 +436,5 @@ ALTER TABLE ONLY workspaces
ADD CONSTRAINT workspaces_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT;
ALTER TABLE ONLY workspaces
ADD CONSTRAINT workspaces_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE RESTRICT;
ADD CONSTRAINT workspaces_template_id_fkey FOREIGN KEY (template_id) REFERENCES templates(id) ON DELETE RESTRICT;
@@ -1,6 +0,0 @@
DROP TABLE project_versions;
DROP TABLE projects;
DROP TYPE provisioner_type;
DROP TABLE files;
@@ -0,0 +1,6 @@
DROP TABLE template_versions;
DROP TABLE templates;
DROP TYPE provisioner_type;
DROP TABLE files;
@@ -1,4 +1,4 @@
-- Store arbitrary data like project source code or avatars.
-- Store arbitrary data like template source code or avatars.
CREATE TABLE files (
hash varchar(64) NOT NULL,
created_at timestamptz NOT NULL,
@@ -11,37 +11,37 @@ CREATE TABLE files (
CREATE TYPE provisioner_type AS ENUM ('echo', 'terraform');
-- Project defines infrastructure that your software project
-- Template defines infrastructure that your software template
-- requires for development.
CREATE TABLE projects (
CREATE TABLE templates (
id uuid NOT NULL,
created_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL,
-- Projects must be scoped to an organization.
-- Templates must be scoped to an organization.
organization_id uuid NOT NULL REFERENCES organizations (id) ON DELETE CASCADE,
deleted boolean NOT NULL DEFAULT FALSE,
name varchar(64) NOT NULL,
provisioner provisioner_type NOT NULL,
-- Target's a Project Version to use for Workspaces.
-- Target's a Template Version to use for Workspaces.
-- If a Workspace doesn't match this version, it will be prompted to rebuild.
active_version_id uuid NOT NULL,
PRIMARY KEY (id),
-- Disallow projects to have the same name under
-- Disallow templates to have the same name under
-- the same organization.
UNIQUE(organization_id, name)
);
-- Enforces no active projects have the same name.
CREATE UNIQUE INDEX ON projects (organization_id, name) WHERE deleted = FALSE;
CREATE UNIQUE INDEX idx_projects_name_lower ON projects USING btree (lower(name));
-- Enforces no active templates have the same name.
CREATE UNIQUE INDEX ON templates (organization_id, name) WHERE deleted = FALSE;
CREATE UNIQUE INDEX idx_templates_name_lower ON templates USING btree (lower(name));
-- Project Versions store historical project data. When a Project Version is imported,
-- an "import" job is queued to parse parameters. A Project Version
-- Template Versions store historical template data. When a Template Version is imported,
-- an "import" job is queued to parse parameters. A Template Version
-- can only be used if the import job succeeds.
CREATE TABLE project_versions (
CREATE TABLE template_versions (
id uuid NOT NULL,
-- This should be indexed. It is intentionally nullable.
project_id uuid REFERENCES projects (id) ON DELETE CASCADE,
template_id uuid REFERENCES templates (id) ON DELETE CASCADE,
organization_id uuid NOT NULL REFERENCES organizations (id) ON DELETE CASCADE,
created_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL,
@@ -51,10 +51,10 @@ CREATE TABLE project_versions (
-- Extracted from a README.md on import.
-- Maximum of 1MB.
description varchar(1048576) NOT NULL,
-- The job ID for building the project version.
-- The job ID for building the template version.
job_id uuid NOT NULL,
PRIMARY KEY (id),
-- Disallow projects to have the same build name
-- Disallow templates to have the same build name
-- multiple times.
UNIQUE(project_id, name)
UNIQUE(template_id, name)
);
@@ -5,7 +5,7 @@ CREATE TABLE workspaces (
-- Use ON DELETE RESTRICT so that we can cleanup external workspace
-- resources first.
owner_id uuid NOT NULL REFERENCES users (id) ON DELETE RESTRICT,
project_id uuid NOT NULL REFERENCES projects (id) ON DELETE RESTRICT,
template_id uuid NOT NULL REFERENCES templates (id) ON DELETE RESTRICT,
deleted boolean NOT NULL DEFAULT FALSE,
name varchar(64) NOT NULL,
PRIMARY KEY (id)
@@ -11,7 +11,7 @@ CREATE TABLE IF NOT EXISTS provisioner_daemons (
);
CREATE TYPE provisioner_job_type AS ENUM (
'project_version_import',
'template_version_import',
'workspace_build'
);
@@ -92,7 +92,7 @@ CREATE TABLE workspace_agents (
CREATE TYPE parameter_scope AS ENUM (
'organization',
'project',
'template',
'import_job',
'user',
'workspace'
@@ -107,7 +107,7 @@ CREATE TYPE parameter_source_scheme AS ENUM('none', 'data');
-- Supported schemes for a parameter destination.
CREATE TYPE parameter_destination_scheme AS ENUM('none', 'environment_variable', 'provisioner_variable');
-- Stores project version parameters parsed on import.
-- Stores template version parameters parsed on import.
-- No secrets are stored here.
--
-- All parameter validation occurs server-side to process
@@ -162,7 +162,7 @@ CREATE TABLE workspace_builds (
created_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL,
workspace_id uuid NOT NULL REFERENCES workspaces (id) ON DELETE CASCADE,
project_version_id uuid NOT NULL REFERENCES project_versions (id) ON DELETE CASCADE,
template_version_id uuid NOT NULL REFERENCES template_versions (id) ON DELETE CASCADE,
name varchar(64) NOT NULL,
before_id uuid,
after_id uuid,
+44 -44
View File
@@ -97,7 +97,7 @@ type ParameterScope string
const (
ParameterScopeOrganization ParameterScope = "organization"
ParameterScopeProject ParameterScope = "project"
ParameterScopeTemplate ParameterScope = "template"
ParameterScopeImportJob ParameterScope = "import_job"
ParameterScopeUser ParameterScope = "user"
ParameterScopeWorkspace ParameterScope = "workspace"
@@ -156,8 +156,8 @@ func (e *ParameterTypeSystem) Scan(src interface{}) error {
type ProvisionerJobType string
const (
ProvisionerJobTypeProjectVersionImport ProvisionerJobType = "project_version_import"
ProvisionerJobTypeWorkspaceBuild ProvisionerJobType = "workspace_build"
ProvisionerJobTypeTemplateVersionImport ProvisionerJobType = "template_version_import"
ProvisionerJobTypeWorkspaceBuild ProvisionerJobType = "workspace_build"
)
func (e *ProvisionerJobType) Scan(src interface{}) error {
@@ -316,28 +316,6 @@ type ParameterValue struct {
DestinationScheme ParameterDestinationScheme `db:"destination_scheme" json:"destination_scheme"`
}
type Project 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"`
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
Deleted bool `db:"deleted" json:"deleted"`
Name string `db:"name" json:"name"`
Provisioner ProvisionerType `db:"provisioner" json:"provisioner"`
ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"`
}
type ProjectVersion struct {
ID uuid.UUID `db:"id" json:"id"`
ProjectID uuid.NullUUID `db:"project_id" json:"project_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"`
Description string `db:"description" json:"description"`
JobID uuid.UUID `db:"job_id" json:"job_id"`
}
type ProvisionerDaemon struct {
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
@@ -375,6 +353,28 @@ type ProvisionerJobLog struct {
Output string `db:"output" json:"output"`
}
type Template 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"`
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
Deleted bool `db:"deleted" json:"deleted"`
Name string `db:"name" json:"name"`
Provisioner ProvisionerType `db:"provisioner" json:"provisioner"`
ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"`
}
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"`
Description string `db:"description" json:"description"`
JobID uuid.UUID `db:"job_id" json:"job_id"`
}
type User struct {
ID uuid.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
@@ -388,13 +388,13 @@ type User struct {
}
type Workspace 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"`
OwnerID uuid.UUID `db:"owner_id" json:"owner_id"`
ProjectID uuid.UUID `db:"project_id" json:"project_id"`
Deleted bool `db:"deleted" json:"deleted"`
Name string `db:"name" json:"name"`
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"`
OwnerID uuid.UUID `db:"owner_id" json:"owner_id"`
TemplateID uuid.UUID `db:"template_id" json:"template_id"`
Deleted bool `db:"deleted" json:"deleted"`
Name string `db:"name" json:"name"`
}
type WorkspaceAgent struct {
@@ -414,18 +414,18 @@ type WorkspaceAgent struct {
}
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"`
ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"`
Name string `db:"name" json:"name"`
BeforeID uuid.NullUUID `db:"before_id" json:"before_id"`
AfterID uuid.NullUUID `db:"after_id" json:"after_id"`
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"`
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"`
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
Name string `db:"name" json:"name"`
BeforeID uuid.NullUUID `db:"before_id" json:"before_id"`
AfterID uuid.NullUUID `db:"after_id" json:"after_id"`
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"`
}
type WorkspaceResource struct {
+15 -15
View File
@@ -22,19 +22,19 @@ type querier interface {
GetParameterSchemasByJobID(ctx context.Context, jobID uuid.UUID) ([]ParameterSchema, error)
GetParameterValueByScopeAndName(ctx context.Context, arg GetParameterValueByScopeAndNameParams) (ParameterValue, error)
GetParameterValuesByScope(ctx context.Context, arg GetParameterValuesByScopeParams) ([]ParameterValue, error)
GetProjectByID(ctx context.Context, id uuid.UUID) (Project, error)
GetProjectByOrganizationAndName(ctx context.Context, arg GetProjectByOrganizationAndNameParams) (Project, error)
GetProjectVersionByID(ctx context.Context, id uuid.UUID) (ProjectVersion, error)
GetProjectVersionByJobID(ctx context.Context, jobID uuid.UUID) (ProjectVersion, error)
GetProjectVersionByProjectIDAndName(ctx context.Context, arg GetProjectVersionByProjectIDAndNameParams) (ProjectVersion, error)
GetProjectVersionsByProjectID(ctx context.Context, dollar_1 uuid.UUID) ([]ProjectVersion, error)
GetProjectsByIDs(ctx context.Context, ids []uuid.UUID) ([]Project, error)
GetProjectsByOrganization(ctx context.Context, arg GetProjectsByOrganizationParams) ([]Project, error)
GetProvisionerDaemonByID(ctx context.Context, id uuid.UUID) (ProvisionerDaemon, error)
GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error)
GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (ProvisionerJob, error)
GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UUID) ([]ProvisionerJob, error)
GetProvisionerLogsByIDBetween(ctx context.Context, arg GetProvisionerLogsByIDBetweenParams) ([]ProvisionerJobLog, error)
GetTemplateByID(ctx context.Context, id uuid.UUID) (Template, error)
GetTemplateByOrganizationAndName(ctx context.Context, arg GetTemplateByOrganizationAndNameParams) (Template, error)
GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (TemplateVersion, error)
GetTemplateVersionByJobID(ctx context.Context, jobID uuid.UUID) (TemplateVersion, error)
GetTemplateVersionByTemplateIDAndName(ctx context.Context, arg GetTemplateVersionByTemplateIDAndNameParams) (TemplateVersion, error)
GetTemplateVersionsByTemplateID(ctx context.Context, dollar_1 uuid.UUID) ([]TemplateVersion, error)
GetTemplatesByIDs(ctx context.Context, ids []uuid.UUID) ([]Template, error)
GetTemplatesByOrganization(ctx context.Context, arg GetTemplatesByOrganizationParams) ([]Template, error)
GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error)
GetUserByID(ctx context.Context, id uuid.UUID) (User, error)
GetUserCount(ctx context.Context) (int64, error)
@@ -49,10 +49,10 @@ type querier interface {
GetWorkspaceBuildsByWorkspaceIDsWithoutAfter(ctx context.Context, ids []uuid.UUID) ([]WorkspaceBuild, error)
GetWorkspaceByID(ctx context.Context, id uuid.UUID) (Workspace, error)
GetWorkspaceByUserIDAndName(ctx context.Context, arg GetWorkspaceByUserIDAndNameParams) (Workspace, error)
GetWorkspaceOwnerCountsByProjectIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceOwnerCountsByProjectIDsRow, error)
GetWorkspaceOwnerCountsByTemplateIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceOwnerCountsByTemplateIDsRow, error)
GetWorkspaceResourceByID(ctx context.Context, id uuid.UUID) (WorkspaceResource, error)
GetWorkspaceResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]WorkspaceResource, error)
GetWorkspacesByProjectID(ctx context.Context, arg GetWorkspacesByProjectIDParams) ([]Workspace, error)
GetWorkspacesByTemplateID(ctx context.Context, arg GetWorkspacesByTemplateIDParams) ([]Workspace, error)
GetWorkspacesByUserID(ctx context.Context, arg GetWorkspacesByUserIDParams) ([]Workspace, error)
InsertAPIKey(ctx context.Context, arg InsertAPIKeyParams) (APIKey, error)
InsertFile(ctx context.Context, arg InsertFileParams) (File, error)
@@ -61,11 +61,11 @@ type querier interface {
InsertOrganizationMember(ctx context.Context, arg InsertOrganizationMemberParams) (OrganizationMember, error)
InsertParameterSchema(ctx context.Context, arg InsertParameterSchemaParams) (ParameterSchema, error)
InsertParameterValue(ctx context.Context, arg InsertParameterValueParams) (ParameterValue, error)
InsertProject(ctx context.Context, arg InsertProjectParams) (Project, error)
InsertProjectVersion(ctx context.Context, arg InsertProjectVersionParams) (ProjectVersion, error)
InsertProvisionerDaemon(ctx context.Context, arg InsertProvisionerDaemonParams) (ProvisionerDaemon, error)
InsertProvisionerJob(ctx context.Context, arg InsertProvisionerJobParams) (ProvisionerJob, error)
InsertProvisionerJobLogs(ctx context.Context, arg InsertProvisionerJobLogsParams) ([]ProvisionerJobLog, error)
InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error)
InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) (TemplateVersion, error)
InsertUser(ctx context.Context, arg InsertUserParams) (User, error)
InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (Workspace, error)
InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspaceAgentParams) (WorkspaceAgent, error)
@@ -73,13 +73,13 @@ type querier interface {
InsertWorkspaceResource(ctx context.Context, arg InsertWorkspaceResourceParams) (WorkspaceResource, error)
UpdateAPIKeyByID(ctx context.Context, arg UpdateAPIKeyByIDParams) error
UpdateGitSSHKey(ctx context.Context, arg UpdateGitSSHKeyParams) error
UpdateProjectActiveVersionByID(ctx context.Context, arg UpdateProjectActiveVersionByIDParams) error
UpdateProjectDeletedByID(ctx context.Context, arg UpdateProjectDeletedByIDParams) error
UpdateProjectVersionByID(ctx context.Context, arg UpdateProjectVersionByIDParams) error
UpdateProvisionerDaemonByID(ctx context.Context, arg UpdateProvisionerDaemonByIDParams) error
UpdateProvisionerJobByID(ctx context.Context, arg UpdateProvisionerJobByIDParams) error
UpdateProvisionerJobWithCancelByID(ctx context.Context, arg UpdateProvisionerJobWithCancelByIDParams) error
UpdateProvisionerJobWithCompleteByID(ctx context.Context, arg UpdateProvisionerJobWithCompleteByIDParams) error
UpdateTemplateActiveVersionByID(ctx context.Context, arg UpdateTemplateActiveVersionByIDParams) error
UpdateTemplateDeletedByID(ctx context.Context, arg UpdateTemplateDeletedByIDParams) error
UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) error
UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error
UpdateWorkspaceBuildByID(ctx context.Context, arg UpdateWorkspaceBuildByIDParams) error
UpdateWorkspaceDeletedByID(ctx context.Context, arg UpdateWorkspaceDeletedByIDParams) error
File diff suppressed because it is too large Load Diff
@@ -1,56 +0,0 @@
-- name: GetProjectVersionsByProjectID :many
SELECT
*
FROM
project_versions
WHERE
project_id = $1 :: uuid;
-- name: GetProjectVersionByJobID :one
SELECT
*
FROM
project_versions
WHERE
job_id = $1;
-- name: GetProjectVersionByProjectIDAndName :one
SELECT
*
FROM
project_versions
WHERE
project_id = $1
AND "name" = $2;
-- name: GetProjectVersionByID :one
SELECT
*
FROM
project_versions
WHERE
id = $1;
-- name: InsertProjectVersion :one
INSERT INTO
project_versions (
id,
project_id,
organization_id,
created_at,
updated_at,
"name",
description,
job_id
)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;
-- name: UpdateProjectVersionByID :exec
UPDATE
project_versions
SET
project_id = $2,
updated_at = $3
WHERE
id = $1;
@@ -1,26 +1,26 @@
-- name: GetProjectByID :one
-- name: GetTemplateByID :one
SELECT
*
FROM
projects
templates
WHERE
id = $1
LIMIT
1;
-- name: GetProjectsByIDs :many
-- name: GetTemplatesByIDs :many
SELECT
*
FROM
projects
templates
WHERE
id = ANY(@ids :: uuid [ ]);
-- name: GetProjectByOrganizationAndName :one
-- name: GetTemplateByOrganizationAndName :one
SELECT
*
FROM
projects
templates
WHERE
organization_id = @organization_id
AND deleted = @deleted
@@ -28,18 +28,18 @@ WHERE
LIMIT
1;
-- name: GetProjectsByOrganization :many
-- name: GetTemplatesByOrganization :many
SELECT
*
FROM
projects
templates
WHERE
organization_id = $1
AND deleted = $2;
-- name: InsertProject :one
-- name: InsertTemplate :one
INSERT INTO
projects (
templates (
id,
created_at,
updated_at,
@@ -51,17 +51,17 @@ INSERT INTO
VALUES
($1, $2, $3, $4, $5, $6, $7) RETURNING *;
-- name: UpdateProjectActiveVersionByID :exec
-- name: UpdateTemplateActiveVersionByID :exec
UPDATE
projects
templates
SET
active_version_id = $2
WHERE
id = $1;
-- name: UpdateProjectDeletedByID :exec
-- name: UpdateTemplateDeletedByID :exec
UPDATE
projects
templates
SET
deleted = $2
WHERE
@@ -0,0 +1,56 @@
-- name: GetTemplateVersionsByTemplateID :many
SELECT
*
FROM
template_versions
WHERE
template_id = $1 :: uuid;
-- name: GetTemplateVersionByJobID :one
SELECT
*
FROM
template_versions
WHERE
job_id = $1;
-- name: GetTemplateVersionByTemplateIDAndName :one
SELECT
*
FROM
template_versions
WHERE
template_id = $1
AND "name" = $2;
-- name: GetTemplateVersionByID :one
SELECT
*
FROM
template_versions
WHERE
id = $1;
-- name: InsertTemplateVersion :one
INSERT INTO
template_versions (
id,
template_id,
organization_id,
created_at,
updated_at,
"name",
description,
job_id
)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;
-- name: UpdateTemplateVersionByID :exec
UPDATE
template_versions
SET
template_id = $2,
updated_at = $3
WHERE
id = $1;
+1 -1
View File
@@ -62,7 +62,7 @@ INSERT INTO
created_at,
updated_at,
workspace_id,
project_version_id,
template_version_id,
before_id,
"name",
transition,
+7 -7
View File
@@ -8,13 +8,13 @@ WHERE
LIMIT
1;
-- name: GetWorkspacesByProjectID :many
-- name: GetWorkspacesByTemplateID :many
SELECT
*
FROM
workspaces
WHERE
project_id = $1
template_id = $1
AND deleted = $2;
-- name: GetWorkspacesByUserID :many
@@ -36,16 +36,16 @@ WHERE
AND deleted = @deleted
AND LOWER("name") = LOWER(@name);
-- name: GetWorkspaceOwnerCountsByProjectIDs :many
-- name: GetWorkspaceOwnerCountsByTemplateIDs :many
SELECT
project_id,
template_id,
COUNT(DISTINCT owner_id)
FROM
workspaces
WHERE
project_id = ANY(@ids :: uuid [ ])
template_id = ANY(@ids :: uuid [ ])
GROUP BY
project_id,
template_id,
owner_id;
-- name: InsertWorkspace :one
@@ -55,7 +55,7 @@ INSERT INTO
created_at,
updated_at,
owner_id,
project_id,
template_id,
name
)
VALUES
+3 -3
View File
@@ -86,7 +86,7 @@ func TestAgentGitSSHKey(t *testing.T) {
user := coderdtest.CreateFirstUser(t, client)
daemonCloser := coderdtest.NewProvisionerDaemon(t, client)
authToken := uuid.NewString()
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionDryRun: echo.ProvisionComplete,
Provision: []*proto.Provision_Response{{
@@ -106,8 +106,8 @@ func TestAgentGitSSHKey(t *testing.T) {
},
}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
daemonCloser.Close()
-53
View File
@@ -1,53 +0,0 @@
package httpmw
import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
)
type projectParamContextKey struct{}
// ProjectParam returns the project from the ExtractProjectParam handler.
func ProjectParam(r *http.Request) database.Project {
project, ok := r.Context().Value(projectParamContextKey{}).(database.Project)
if !ok {
panic("developer error: project param middleware not provided")
}
return project
}
// ExtractProjectParam grabs a project from the "project" URL parameter.
func ExtractProjectParam(db database.Store) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
projectID, parsed := parseUUID(rw, r, "project")
if !parsed {
return
}
project, err := db.GetProjectByID(r.Context(), projectID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("project %q does not exist", projectID),
})
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project: %s", err),
})
return
}
ctx := context.WithValue(r.Context(), projectParamContextKey{}, project)
chi.RouteContext(ctx).URLParams.Add("organization", project.OrganizationID.String())
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
}
-54
View File
@@ -1,54 +0,0 @@
package httpmw
import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
)
type projectVersionParamContextKey struct{}
// ProjectVersionParam returns the project version from the ExtractProjectVersionParam handler.
func ProjectVersionParam(r *http.Request) database.ProjectVersion {
projectVersion, ok := r.Context().Value(projectVersionParamContextKey{}).(database.ProjectVersion)
if !ok {
panic("developer error: project version param middleware not provided")
}
return projectVersion
}
// ExtractProjectVersionParam grabs project version from the "projectversion" URL parameter.
func ExtractProjectVersionParam(db database.Store) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
projectVersionID, parsed := parseUUID(rw, r, "projectversion")
if !parsed {
return
}
projectVersion, err := db.GetProjectVersionByID(r.Context(), projectVersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("project version %q does not exist", projectVersionID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version: %s", err.Error()),
})
return
}
ctx := context.WithValue(r.Context(), projectVersionParamContextKey{}, projectVersion)
chi.RouteContext(ctx).URLParams.Add("organization", projectVersion.OrganizationID.String())
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
}
+53
View File
@@ -0,0 +1,53 @@
package httpmw
import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
)
type templateParamContextKey struct{}
// TemplateParam returns the template from the ExtractTemplateParam handler.
func TemplateParam(r *http.Request) database.Template {
template, ok := r.Context().Value(templateParamContextKey{}).(database.Template)
if !ok {
panic("developer error: template param middleware not provided")
}
return template
}
// ExtractTemplateParam grabs a template from the "template" URL parameter.
func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
templateID, parsed := parseUUID(rw, r, "template")
if !parsed {
return
}
template, err := db.GetTemplateByID(r.Context(), templateID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("template %q does not exist", templateID),
})
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get template: %s", err),
})
return
}
ctx := context.WithValue(r.Context(), templateParamContextKey{}, template)
chi.RouteContext(ctx).URLParams.Add("organization", template.OrganizationID.String())
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
}
@@ -19,7 +19,7 @@ import (
"github.com/coder/coder/cryptorand"
)
func TestProjectParam(t *testing.T) {
func TestTemplateParam(t *testing.T) {
t.Parallel()
setupAuthentication := func(db database.Store) (*http.Request, database.Organization) {
@@ -84,7 +84,7 @@ func TestProjectParam(t *testing.T) {
t.Parallel()
db := databasefake.New()
rtr := chi.NewRouter()
rtr.Use(httpmw.ExtractProjectParam(db))
rtr.Use(httpmw.ExtractTemplateParam(db))
rtr.Get("/", nil)
r, _ := setupAuthentication(db)
rw := httptest.NewRecorder()
@@ -99,11 +99,11 @@ func TestProjectParam(t *testing.T) {
t.Parallel()
db := databasefake.New()
rtr := chi.NewRouter()
rtr.Use(httpmw.ExtractProjectParam(db))
rtr.Use(httpmw.ExtractTemplateParam(db))
rtr.Get("/", nil)
r, _ := setupAuthentication(db)
chi.RouteContext(r.Context()).URLParams.Add("project", uuid.NewString())
chi.RouteContext(r.Context()).URLParams.Add("template", uuid.NewString())
rw := httptest.NewRecorder()
rtr.ServeHTTP(rw, r)
@@ -116,11 +116,11 @@ func TestProjectParam(t *testing.T) {
t.Parallel()
db := databasefake.New()
rtr := chi.NewRouter()
rtr.Use(httpmw.ExtractProjectParam(db))
rtr.Use(httpmw.ExtractTemplateParam(db))
rtr.Get("/", nil)
r, _ := setupAuthentication(db)
chi.RouteContext(r.Context()).URLParams.Add("project", "not-a-uuid")
chi.RouteContext(r.Context()).URLParams.Add("template", "not-a-uuid")
rw := httptest.NewRecorder()
rtr.ServeHTTP(rw, r)
@@ -129,28 +129,28 @@ func TestProjectParam(t *testing.T) {
require.Equal(t, http.StatusBadRequest, res.StatusCode)
})
t.Run("Project", func(t *testing.T) {
t.Run("Template", func(t *testing.T) {
t.Parallel()
db := databasefake.New()
rtr := chi.NewRouter()
rtr.Use(
httpmw.ExtractAPIKey(db, nil),
httpmw.ExtractProjectParam(db),
httpmw.ExtractTemplateParam(db),
httpmw.ExtractOrganizationParam(db),
)
rtr.Get("/", func(rw http.ResponseWriter, r *http.Request) {
_ = httpmw.ProjectParam(r)
_ = httpmw.TemplateParam(r)
rw.WriteHeader(http.StatusOK)
})
r, org := setupAuthentication(db)
project, err := db.InsertProject(context.Background(), database.InsertProjectParams{
template, err := db.InsertTemplate(context.Background(), database.InsertTemplateParams{
ID: uuid.New(),
OrganizationID: org.ID,
Name: "moo",
})
require.NoError(t, err)
chi.RouteContext(r.Context()).URLParams.Add("project", project.ID.String())
chi.RouteContext(r.Context()).URLParams.Add("template", template.ID.String())
rw := httptest.NewRecorder()
rtr.ServeHTTP(rw, r)
+54
View File
@@ -0,0 +1,54 @@
package httpmw
import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
)
type templateVersionParamContextKey struct{}
// TemplateVersionParam returns the template version from the ExtractTemplateVersionParam handler.
func TemplateVersionParam(r *http.Request) database.TemplateVersion {
templateVersion, ok := r.Context().Value(templateVersionParamContextKey{}).(database.TemplateVersion)
if !ok {
panic("developer error: template version param middleware not provided")
}
return templateVersion
}
// ExtractTemplateVersionParam grabs template version from the "templateversion" URL parameter.
func ExtractTemplateVersionParam(db database.Store) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
templateVersionID, parsed := parseUUID(rw, r, "templateversion")
if !parsed {
return
}
templateVersion, err := db.GetTemplateVersionByID(r.Context(), templateVersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("template version %q does not exist", templateVersionID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get template version: %s", err.Error()),
})
return
}
ctx := context.WithValue(r.Context(), templateVersionParamContextKey{}, templateVersion)
chi.RouteContext(ctx).URLParams.Add("organization", templateVersion.OrganizationID.String())
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
}
@@ -19,10 +19,10 @@ import (
"github.com/coder/coder/cryptorand"
)
func TestProjectVersionParam(t *testing.T) {
func TestTemplateVersionParam(t *testing.T) {
t.Parallel()
setupAuthentication := func(db database.Store) (*http.Request, database.Project) {
setupAuthentication := func(db database.Store) (*http.Request, database.Template) {
var (
id, secret = randomAPIKeyParts()
hashed = sha256.Sum256([]byte(secret))
@@ -75,7 +75,7 @@ func TestProjectVersionParam(t *testing.T) {
})
require.NoError(t, err)
project, err := db.InsertProject(context.Background(), database.InsertProjectParams{
template, err := db.InsertTemplate(context.Background(), database.InsertTemplateParams{
ID: uuid.New(),
OrganizationID: organization.ID,
Name: "moo",
@@ -84,16 +84,16 @@ func TestProjectVersionParam(t *testing.T) {
ctx := chi.NewRouteContext()
ctx.URLParams.Add("organization", organization.Name)
ctx.URLParams.Add("project", project.Name)
ctx.URLParams.Add("template", template.Name)
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, ctx))
return r, project
return r, template
}
t.Run("None", func(t *testing.T) {
t.Parallel()
db := databasefake.New()
rtr := chi.NewRouter()
rtr.Use(httpmw.ExtractProjectVersionParam(db))
rtr.Use(httpmw.ExtractTemplateVersionParam(db))
rtr.Get("/", nil)
r, _ := setupAuthentication(db)
rw := httptest.NewRecorder()
@@ -108,11 +108,11 @@ func TestProjectVersionParam(t *testing.T) {
t.Parallel()
db := databasefake.New()
rtr := chi.NewRouter()
rtr.Use(httpmw.ExtractProjectVersionParam(db))
rtr.Use(httpmw.ExtractTemplateVersionParam(db))
rtr.Get("/", nil)
r, _ := setupAuthentication(db)
chi.RouteContext(r.Context()).URLParams.Add("projectversion", uuid.NewString())
chi.RouteContext(r.Context()).URLParams.Add("templateversion", uuid.NewString())
rw := httptest.NewRecorder()
rtr.ServeHTTP(rw, r)
@@ -121,28 +121,28 @@ func TestProjectVersionParam(t *testing.T) {
require.Equal(t, http.StatusNotFound, res.StatusCode)
})
t.Run("ProjectVersion", func(t *testing.T) {
t.Run("TemplateVersion", func(t *testing.T) {
t.Parallel()
db := databasefake.New()
rtr := chi.NewRouter()
rtr.Use(
httpmw.ExtractAPIKey(db, nil),
httpmw.ExtractProjectVersionParam(db),
httpmw.ExtractTemplateVersionParam(db),
httpmw.ExtractOrganizationParam(db),
)
rtr.Get("/", func(rw http.ResponseWriter, r *http.Request) {
_ = httpmw.ProjectVersionParam(r)
_ = httpmw.TemplateVersionParam(r)
rw.WriteHeader(http.StatusOK)
})
r, project := setupAuthentication(db)
projectVersion, err := db.InsertProjectVersion(context.Background(), database.InsertProjectVersionParams{
r, template := setupAuthentication(db)
templateVersion, err := db.InsertTemplateVersion(context.Background(), database.InsertTemplateVersionParams{
ID: uuid.New(),
OrganizationID: project.OrganizationID,
OrganizationID: template.OrganizationID,
Name: "moo",
})
require.NoError(t, err)
chi.RouteContext(r.Context()).URLParams.Add("projectversion", projectVersion.ID.String())
chi.RouteContext(r.Context()).URLParams.Add("templateversion", templateVersion.ID.String())
rw := httptest.NewRecorder()
rtr.ServeHTTP(rw, r)
+4 -4
View File
@@ -58,10 +58,10 @@ func TestWorkspaceBuildParam(t *testing.T) {
require.NoError(t, err)
workspace, err := db.InsertWorkspace(context.Background(), database.InsertWorkspaceParams{
ID: uuid.New(),
ProjectID: uuid.New(),
OwnerID: user.ID,
Name: "potato",
ID: uuid.New(),
TemplateID: uuid.New(),
OwnerID: user.ID,
Name: "potato",
})
require.NoError(t, err)
+1 -1
View File
@@ -15,7 +15,7 @@ import (
type workspaceResourceParamContextKey struct{}
// ProvisionerJobParam returns the project from the ExtractProjectParam handler.
// ProvisionerJobParam returns the template from the ExtractTemplateParam handler.
func WorkspaceResourceParam(r *http.Request) database.WorkspaceResource {
resource, ok := r.Context().Value(workspaceResourceParamContextKey{}).(database.WorkspaceResource)
if !ok {
+1 -1
View File
@@ -88,7 +88,7 @@ func TestWorkspaceResourceParam(t *testing.T) {
rw.WriteHeader(http.StatusOK)
})
r, job := setup(db, database.ProvisionerJobTypeProjectVersionImport)
r, job := setup(db, database.ProvisionerJobTypeTemplateVersionImport)
chi.RouteContext(r.Context()).URLParams.Add("workspaceresource", job.ID.String())
rw := httptest.NewRecorder()
rtr.ServeHTTP(rw, r)
+60 -60
View File
@@ -42,25 +42,25 @@ func (api *api) provisionerDaemonsByOrganization(rw http.ResponseWriter, r *http
render.JSON(rw, r, daemons)
}
// Creates a new version of a project. An import job is queued to parse the storage method provided.
func (api *api) postProjectVersionsByOrganization(rw http.ResponseWriter, r *http.Request) {
// Creates a new version of a template. An import job is queued to parse the storage method provided.
func (api *api) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *http.Request) {
apiKey := httpmw.APIKey(r)
organization := httpmw.OrganizationParam(r)
var req codersdk.CreateProjectVersionRequest
var req codersdk.CreateTemplateVersionRequest
if !httpapi.Read(rw, r, &req) {
return
}
if req.ProjectID != uuid.Nil {
_, err := api.Database.GetProjectByID(r.Context(), req.ProjectID)
if req.TemplateID != uuid.Nil {
_, err := api.Database.GetTemplateByID(r.Context(), req.TemplateID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "project does not exist",
Message: "template does not exist",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project: %s", err),
Message: fmt.Sprintf("get template: %s", err),
})
return
}
@@ -80,7 +80,7 @@ func (api *api) postProjectVersionsByOrganization(rw http.ResponseWriter, r *htt
return
}
var projectVersion database.ProjectVersion
var templateVersion database.TemplateVersion
var provisionerJob database.ProvisionerJob
err = api.Database.InTx(func(db database.Store) error {
jobID := uuid.New()
@@ -110,24 +110,24 @@ func (api *api) postProjectVersionsByOrganization(rw http.ResponseWriter, r *htt
Provisioner: req.Provisioner,
StorageMethod: database.ProvisionerStorageMethodFile,
StorageSource: file.Hash,
Type: database.ProvisionerJobTypeProjectVersionImport,
Type: database.ProvisionerJobTypeTemplateVersionImport,
Input: []byte{'{', '}'},
})
if err != nil {
return xerrors.Errorf("insert provisioner job: %w", err)
}
var projectID uuid.NullUUID
if req.ProjectID != uuid.Nil {
projectID = uuid.NullUUID{
UUID: req.ProjectID,
var templateID uuid.NullUUID
if req.TemplateID != uuid.Nil {
templateID = uuid.NullUUID{
UUID: req.TemplateID,
Valid: true,
}
}
projectVersion, err = api.Database.InsertProjectVersion(r.Context(), database.InsertProjectVersionParams{
templateVersion, err = api.Database.InsertTemplateVersion(r.Context(), database.InsertTemplateVersionParams{
ID: uuid.New(),
ProjectID: projectID,
TemplateID: templateID,
OrganizationID: organization.ID,
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
@@ -136,7 +136,7 @@ func (api *api) postProjectVersionsByOrganization(rw http.ResponseWriter, r *htt
JobID: provisionerJob.ID,
})
if err != nil {
return xerrors.Errorf("insert project version: %w", err)
return xerrors.Errorf("insert template version: %w", err)
}
return nil
})
@@ -148,23 +148,23 @@ func (api *api) postProjectVersionsByOrganization(rw http.ResponseWriter, r *htt
}
render.Status(r, http.StatusCreated)
render.JSON(rw, r, convertProjectVersion(projectVersion, convertProvisionerJob(provisionerJob)))
render.JSON(rw, r, convertTemplateVersion(templateVersion, convertProvisionerJob(provisionerJob)))
}
// Create a new project in an organization.
func (api *api) postProjectsByOrganization(rw http.ResponseWriter, r *http.Request) {
var createProject codersdk.CreateProjectRequest
if !httpapi.Read(rw, r, &createProject) {
// Create a new template in an organization.
func (api *api) postTemplatesByOrganization(rw http.ResponseWriter, r *http.Request) {
var createTemplate codersdk.CreateTemplateRequest
if !httpapi.Read(rw, r, &createTemplate) {
return
}
organization := httpmw.OrganizationParam(r)
_, err := api.Database.GetProjectByOrganizationAndName(r.Context(), database.GetProjectByOrganizationAndNameParams{
_, err := api.Database.GetTemplateByOrganizationAndName(r.Context(), database.GetTemplateByOrganizationAndNameParams{
OrganizationID: organization.ID,
Name: createProject.Name,
Name: createTemplate.Name,
})
if err == nil {
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: fmt.Sprintf("project %q already exists", createProject.Name),
Message: fmt.Sprintf("template %q already exists", createTemplate.Name),
Errors: []httpapi.Error{{
Field: "name",
Code: "exists",
@@ -174,23 +174,23 @@ func (api *api) postProjectsByOrganization(rw http.ResponseWriter, r *http.Reque
}
if !errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project by name: %s", err),
Message: fmt.Sprintf("get template by name: %s", err),
})
return
}
projectVersion, err := api.Database.GetProjectVersionByID(r.Context(), createProject.VersionID)
templateVersion, err := api.Database.GetTemplateVersionByID(r.Context(), createTemplate.VersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "project version does not exist",
Message: "template version does not exist",
})
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version by id: %s", err),
Message: fmt.Sprintf("get template version by id: %s", err),
})
return
}
importJob, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
importJob, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get import job by id: %s", err),
@@ -198,41 +198,41 @@ func (api *api) postProjectsByOrganization(rw http.ResponseWriter, r *http.Reque
return
}
var project codersdk.Project
var template codersdk.Template
err = api.Database.InTx(func(db database.Store) error {
now := database.Now()
dbProject, err := db.InsertProject(r.Context(), database.InsertProjectParams{
dbTemplate, err := db.InsertTemplate(r.Context(), database.InsertTemplateParams{
ID: uuid.New(),
CreatedAt: now,
UpdatedAt: now,
OrganizationID: organization.ID,
Name: createProject.Name,
Name: createTemplate.Name,
Provisioner: importJob.Provisioner,
ActiveVersionID: projectVersion.ID,
ActiveVersionID: templateVersion.ID,
})
if err != nil {
return xerrors.Errorf("insert project: %s", err)
return xerrors.Errorf("insert template: %s", err)
}
err = db.UpdateProjectVersionByID(r.Context(), database.UpdateProjectVersionByIDParams{
ID: projectVersion.ID,
ProjectID: uuid.NullUUID{
UUID: dbProject.ID,
err = db.UpdateTemplateVersionByID(r.Context(), database.UpdateTemplateVersionByIDParams{
ID: templateVersion.ID,
TemplateID: uuid.NullUUID{
UUID: dbTemplate.ID,
Valid: true,
},
})
if err != nil {
return xerrors.Errorf("insert project version: %s", err)
return xerrors.Errorf("insert template version: %s", err)
}
for _, parameterValue := range createProject.ParameterValues {
for _, parameterValue := range createTemplate.ParameterValues {
_, err = db.InsertParameterValue(r.Context(), database.InsertParameterValueParams{
ID: uuid.New(),
Name: parameterValue.Name,
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
Scope: database.ParameterScopeProject,
ScopeID: dbProject.ID,
Scope: database.ParameterScopeTemplate,
ScopeID: dbTemplate.ID,
SourceScheme: parameterValue.SourceScheme,
SourceValue: parameterValue.SourceValue,
DestinationScheme: parameterValue.DestinationScheme,
@@ -242,7 +242,7 @@ func (api *api) postProjectsByOrganization(rw http.ResponseWriter, r *http.Reque
}
}
project = convertProject(dbProject, 0)
template = convertTemplate(dbTemplate, 0)
return nil
})
if err != nil {
@@ -253,12 +253,12 @@ func (api *api) postProjectsByOrganization(rw http.ResponseWriter, r *http.Reque
}
render.Status(r, http.StatusCreated)
render.JSON(rw, r, project)
render.JSON(rw, r, template)
}
func (api *api) projectsByOrganization(rw http.ResponseWriter, r *http.Request) {
func (api *api) templatesByOrganization(rw http.ResponseWriter, r *http.Request) {
organization := httpmw.OrganizationParam(r)
projects, err := api.Database.GetProjectsByOrganization(r.Context(), database.GetProjectsByOrganizationParams{
templates, err := api.Database.GetTemplatesByOrganization(r.Context(), database.GetTemplatesByOrganizationParams{
OrganizationID: organization.ID,
})
if errors.Is(err, sql.ErrNoRows) {
@@ -266,15 +266,15 @@ func (api *api) projectsByOrganization(rw http.ResponseWriter, r *http.Request)
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get projects: %s", err.Error()),
Message: fmt.Sprintf("get templates: %s", err.Error()),
})
return
}
projectIDs := make([]uuid.UUID, 0, len(projects))
for _, project := range projects {
projectIDs = append(projectIDs, project.ID)
templateIDs := make([]uuid.UUID, 0, len(templates))
for _, template := range templates {
templateIDs = append(templateIDs, template.ID)
}
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByProjectIDs(r.Context(), projectIDs)
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByTemplateIDs(r.Context(), templateIDs)
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
@@ -285,31 +285,31 @@ func (api *api) projectsByOrganization(rw http.ResponseWriter, r *http.Request)
return
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertProjects(projects, workspaceCounts))
render.JSON(rw, r, convertTemplates(templates, workspaceCounts))
}
func (api *api) projectByOrganizationAndName(rw http.ResponseWriter, r *http.Request) {
func (api *api) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Request) {
organization := httpmw.OrganizationParam(r)
projectName := chi.URLParam(r, "projectname")
project, err := api.Database.GetProjectByOrganizationAndName(r.Context(), database.GetProjectByOrganizationAndNameParams{
templateName := chi.URLParam(r, "templatename")
template, err := api.Database.GetTemplateByOrganizationAndName(r.Context(), database.GetTemplateByOrganizationAndNameParams{
OrganizationID: organization.ID,
Name: projectName,
Name: templateName,
})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("no project found by name %q in the %q organization", projectName, organization.Name),
Message: fmt.Sprintf("no template found by name %q in the %q organization", templateName, organization.Name),
})
return
}
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project by organization and name: %s", err),
Message: fmt.Sprintf("get template by organization and name: %s", err),
})
return
}
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByProjectIDs(r.Context(), []uuid.UUID{project.ID})
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByTemplateIDs(r.Context(), []uuid.UUID{template.ID})
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
@@ -326,7 +326,7 @@ func (api *api) projectByOrganizationAndName(rw http.ResponseWriter, r *http.Req
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertProject(project, count))
render.JSON(rw, r, convertTemplate(template, count))
}
// convertOrganization consumes the database representation and outputs an API friendly representation.
+33 -33
View File
@@ -32,15 +32,15 @@ func TestProvisionerDaemonsByOrganization(t *testing.T) {
})
}
func TestPostProjectVersionsByOrganization(t *testing.T) {
func TestPostTemplateVersionsByOrganization(t *testing.T) {
t.Parallel()
t.Run("InvalidProject", func(t *testing.T) {
t.Run("InvalidTemplate", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
projectID := uuid.New()
_, err := client.CreateProjectVersion(context.Background(), user.OrganizationID, codersdk.CreateProjectVersionRequest{
ProjectID: projectID,
templateID := uuid.New()
_, err := client.CreateTemplateVersion(context.Background(), user.OrganizationID, codersdk.CreateTemplateVersionRequest{
TemplateID: templateID,
StorageMethod: database.ProvisionerStorageMethodFile,
StorageSource: "hash",
Provisioner: database.ProvisionerTypeEcho,
@@ -54,7 +54,7 @@ func TestPostProjectVersionsByOrganization(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_, err := client.CreateProjectVersion(context.Background(), user.OrganizationID, codersdk.CreateProjectVersionRequest{
_, err := client.CreateTemplateVersion(context.Background(), user.OrganizationID, codersdk.CreateTemplateVersionRequest{
StorageMethod: database.ProvisionerStorageMethodFile,
StorageSource: "hash",
Provisioner: database.ProvisionerTypeEcho,
@@ -76,7 +76,7 @@ func TestPostProjectVersionsByOrganization(t *testing.T) {
require.NoError(t, err)
file, err := client.Upload(context.Background(), codersdk.ContentTypeTar, data)
require.NoError(t, err)
_, err = client.CreateProjectVersion(context.Background(), user.OrganizationID, codersdk.CreateProjectVersionRequest{
_, err = client.CreateTemplateVersion(context.Background(), user.OrganizationID, codersdk.CreateTemplateVersionRequest{
StorageMethod: database.ProvisionerStorageMethodFile,
StorageSource: file.Hash,
Provisioner: database.ProvisionerTypeEcho,
@@ -91,24 +91,24 @@ func TestPostProjectVersionsByOrganization(t *testing.T) {
})
}
func TestPostProjectsByOrganization(t *testing.T) {
func TestPostTemplatesByOrganization(t *testing.T) {
t.Parallel()
t.Run("Create", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
_ = coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
})
t.Run("AlreadyExists", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
_, err := client.CreateProject(context.Background(), user.OrganizationID, codersdk.CreateProjectRequest{
Name: project.Name,
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
_, err := client.CreateTemplate(context.Background(), user.OrganizationID, codersdk.CreateTemplateRequest{
Name: template.Name,
VersionID: version.ID,
})
var apiErr *codersdk.Error
@@ -120,7 +120,7 @@ func TestPostProjectsByOrganization(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_, err := client.CreateProject(context.Background(), user.OrganizationID, codersdk.CreateProjectRequest{
_, err := client.CreateTemplate(context.Background(), user.OrganizationID, codersdk.CreateTemplateRequest{
Name: "test",
VersionID: uuid.New(),
})
@@ -130,48 +130,48 @@ func TestPostProjectsByOrganization(t *testing.T) {
})
}
func TestProjectsByOrganization(t *testing.T) {
func TestTemplatesByOrganization(t *testing.T) {
t.Parallel()
t.Run("ListEmpty", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
projects, err := client.ProjectsByOrganization(context.Background(), user.OrganizationID)
templates, err := client.TemplatesByOrganization(context.Background(), user.OrganizationID)
require.NoError(t, err)
require.NotNil(t, projects)
require.Len(t, projects, 0)
require.NotNil(t, templates)
require.Len(t, templates, 0)
})
t.Run("List", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
projects, err := client.ProjectsByOrganization(context.Background(), user.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
templates, err := client.TemplatesByOrganization(context.Background(), user.OrganizationID)
require.NoError(t, err)
require.Len(t, projects, 1)
require.Len(t, templates, 1)
})
t.Run("ListMultiple", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
projects, err := client.ProjectsByOrganization(context.Background(), user.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
templates, err := client.TemplatesByOrganization(context.Background(), user.OrganizationID)
require.NoError(t, err)
require.Len(t, projects, 2)
require.Len(t, templates, 2)
})
}
func TestProjectByOrganizationAndName(t *testing.T) {
func TestTemplateByOrganizationAndName(t *testing.T) {
t.Parallel()
t.Run("NotFound", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_, err := client.ProjectByName(context.Background(), user.OrganizationID, "something")
_, err := client.TemplateByName(context.Background(), user.OrganizationID, "something")
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
@@ -181,9 +181,9 @@ func TestProjectByOrganizationAndName(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
_, err := client.ProjectByName(context.Background(), user.OrganizationID, project.Name)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
_, err := client.TemplateByName(context.Background(), user.OrganizationID, template.Name)
require.NoError(t, err)
})
}
+17 -17
View File
@@ -13,11 +13,11 @@ import (
// ComputeScope targets identifiers to pull parameters from.
type ComputeScope struct {
ProjectImportJobID uuid.UUID
OrganizationID uuid.UUID
UserID uuid.UUID
ProjectID uuid.NullUUID
WorkspaceID uuid.NullUUID
TemplateImportJobID uuid.UUID
OrganizationID uuid.UUID
UserID uuid.UUID
TemplateID uuid.NullUUID
WorkspaceID uuid.NullUUID
}
type ComputeOptions struct {
@@ -48,12 +48,12 @@ func Compute(ctx context.Context, db database.Store, scope ComputeScope, options
}
// All parameters for the import job ID!
parameterSchemas, err := db.GetParameterSchemasByJobID(ctx, scope.ProjectImportJobID)
parameterSchemas, err := db.GetParameterSchemasByJobID(ctx, scope.TemplateImportJobID)
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
return nil, xerrors.Errorf("get project parameters: %w", err)
return nil, xerrors.Errorf("get template parameters: %w", err)
}
for _, parameterSchema := range parameterSchemas {
compute.parameterSchemasByName[parameterSchema.Name] = parameterSchema
@@ -71,13 +71,13 @@ func Compute(ctx context.Context, db database.Store, scope ComputeScope, options
// Job parameters come second!
err = compute.injectScope(ctx, database.GetParameterValuesByScopeParams{
Scope: database.ParameterScopeImportJob,
ScopeID: scope.ProjectImportJobID,
ScopeID: scope.TemplateImportJobID,
})
if err != nil {
return nil, err
}
// Default project parameter values come second!
// Default template parameter values come second!
for _, parameterSchema := range parameterSchemas {
if parameterSchema.DefaultSourceScheme == database.ParameterSourceSchemeNone {
continue
@@ -101,21 +101,21 @@ func Compute(ctx context.Context, db database.Store, scope ComputeScope, options
DestinationScheme: parameterSchema.DefaultDestinationScheme,
SourceValue: parameterSchema.DefaultSourceValue,
Scope: database.ParameterScopeImportJob,
ScopeID: scope.ProjectImportJobID,
ScopeID: scope.TemplateImportJobID,
}, true)
if err != nil {
return nil, xerrors.Errorf("insert default value: %w", err)
}
default:
return nil, xerrors.Errorf("unsupported source scheme for project version parameter %q: %q", parameterSchema.Name, string(parameterSchema.DefaultSourceScheme))
return nil, xerrors.Errorf("unsupported source scheme for template version parameter %q: %q", parameterSchema.Name, string(parameterSchema.DefaultSourceScheme))
}
}
if scope.ProjectID.Valid {
// Project parameters come third!
if scope.TemplateID.Valid {
// Template parameters come third!
err = compute.injectScope(ctx, database.GetParameterValuesByScopeParams{
Scope: database.ParameterScopeProject,
ScopeID: scope.ProjectID.UUID,
Scope: database.ParameterScopeTemplate,
ScopeID: scope.TemplateID.UUID,
})
if err != nil {
return nil, err
@@ -178,14 +178,14 @@ func (c *compute) injectScope(ctx context.Context, scopeParams database.GetParam
func (c *compute) injectSingle(scopedParameter database.ParameterValue, defaultValue bool) error {
parameterSchema, hasParameterSchema := c.parameterSchemasByName[scopedParameter.Name]
if !hasParameterSchema {
// Don't inject parameters that aren't defined by the project.
// Don't inject parameters that aren't defined by the template.
return nil
}
_, hasParameterValue := c.computedParameterByName[scopedParameter.Name]
if hasParameterValue {
if !parameterSchema.AllowOverrideSource &&
// Users and workspaces cannot override anything on a project!
// Users and workspaces cannot override anything on a template!
(scopedParameter.Scope == database.ParameterScopeUser ||
scopedParameter.Scope == database.ParameterScopeWorkspace) {
return nil
+20 -20
View File
@@ -17,9 +17,9 @@ func TestCompute(t *testing.T) {
t.Parallel()
generateScope := func() parameter.ComputeScope {
return parameter.ComputeScope{
ProjectImportJobID: uuid.New(),
OrganizationID: uuid.New(),
ProjectID: uuid.NullUUID{
TemplateImportJobID: uuid.New(),
OrganizationID: uuid.New(),
TemplateID: uuid.NullUUID{
UUID: uuid.New(),
Valid: true,
},
@@ -34,7 +34,7 @@ func TestCompute(t *testing.T) {
AllowOverrideSource bool
AllowOverrideDestination bool
DefaultDestinationScheme database.ParameterDestinationScheme
ProjectImportJobID uuid.UUID
TemplateImportJobID uuid.UUID
}
generateParameter := func(t *testing.T, db database.Store, opts parameterOptions) database.ParameterSchema {
if opts.DefaultDestinationScheme == "" {
@@ -47,7 +47,7 @@ func TestCompute(t *testing.T) {
param, err := db.InsertParameterSchema(context.Background(), database.InsertParameterSchemaParams{
ID: uuid.New(),
Name: name,
JobID: opts.ProjectImportJobID,
JobID: opts.TemplateImportJobID,
DefaultSourceScheme: database.ParameterSourceSchemeData,
DefaultSourceValue: sourceValue,
AllowOverrideSource: opts.AllowOverrideSource,
@@ -64,7 +64,7 @@ func TestCompute(t *testing.T) {
scope := generateScope()
_, err := db.InsertParameterSchema(context.Background(), database.InsertParameterSchemaParams{
ID: uuid.New(),
JobID: scope.ProjectImportJobID,
JobID: scope.TemplateImportJobID,
Name: "hey",
DefaultSourceScheme: database.ParameterSourceSchemeNone,
})
@@ -74,12 +74,12 @@ func TestCompute(t *testing.T) {
require.Len(t, computed, 0)
})
t.Run("UseDefaultProjectValue", func(t *testing.T) {
t.Run("UseDefaultTemplateValue", func(t *testing.T) {
t.Parallel()
db := databasefake.New()
scope := generateScope()
parameterSchema := generateParameter(t, db, parameterOptions{
ProjectImportJobID: scope.ProjectImportJobID,
TemplateImportJobID: scope.TemplateImportJobID,
DefaultDestinationScheme: database.ParameterDestinationSchemeProvisionerVariable,
})
computed, err := parameter.Compute(context.Background(), db, scope, nil)
@@ -88,7 +88,7 @@ func TestCompute(t *testing.T) {
computedValue := computed[0]
require.True(t, computedValue.DefaultSourceValue)
require.Equal(t, database.ParameterScopeImportJob, computedValue.Scope)
require.Equal(t, scope.ProjectImportJobID, computedValue.ScopeID)
require.Equal(t, scope.TemplateImportJobID, computedValue.ScopeID)
require.Equal(t, computedValue.SourceValue, parameterSchema.DefaultSourceValue)
})
@@ -97,7 +97,7 @@ func TestCompute(t *testing.T) {
db := databasefake.New()
scope := generateScope()
parameterSchema := generateParameter(t, db, parameterOptions{
ProjectImportJobID: scope.ProjectImportJobID,
TemplateImportJobID: scope.TemplateImportJobID,
})
_, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{
ID: uuid.New(),
@@ -114,7 +114,7 @@ func TestCompute(t *testing.T) {
ID: uuid.New(),
Name: parameterSchema.Name,
Scope: database.ParameterScopeImportJob,
ScopeID: scope.ProjectImportJobID,
ScopeID: scope.TemplateImportJobID,
SourceScheme: database.ParameterSourceSchemeData,
SourceValue: "secondnop",
DestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable,
@@ -128,18 +128,18 @@ func TestCompute(t *testing.T) {
require.Equal(t, value.SourceValue, computed[0].SourceValue)
})
t.Run("ProjectOverridesProjectDefault", func(t *testing.T) {
t.Run("TemplateOverridesTemplateDefault", func(t *testing.T) {
t.Parallel()
db := databasefake.New()
scope := generateScope()
parameterSchema := generateParameter(t, db, parameterOptions{
ProjectImportJobID: scope.ProjectImportJobID,
TemplateImportJobID: scope.TemplateImportJobID,
})
value, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{
ID: uuid.New(),
Name: parameterSchema.Name,
Scope: database.ParameterScopeProject,
ScopeID: scope.ProjectID.UUID,
Scope: database.ParameterScopeTemplate,
ScopeID: scope.TemplateID.UUID,
SourceScheme: database.ParameterSourceSchemeData,
SourceValue: "nop",
DestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable,
@@ -153,12 +153,12 @@ func TestCompute(t *testing.T) {
require.Equal(t, value.SourceValue, computed[0].SourceValue)
})
t.Run("WorkspaceCannotOverwriteProjectDefault", func(t *testing.T) {
t.Run("WorkspaceCannotOverwriteTemplateDefault", func(t *testing.T) {
t.Parallel()
db := databasefake.New()
scope := generateScope()
parameterSchema := generateParameter(t, db, parameterOptions{
ProjectImportJobID: scope.ProjectImportJobID,
TemplateImportJobID: scope.TemplateImportJobID,
})
_, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{
@@ -178,13 +178,13 @@ func TestCompute(t *testing.T) {
require.Equal(t, true, computed[0].DefaultSourceValue)
})
t.Run("WorkspaceOverwriteProjectDefault", func(t *testing.T) {
t.Run("WorkspaceOverwriteTemplateDefault", func(t *testing.T) {
t.Parallel()
db := databasefake.New()
scope := generateScope()
parameterSchema := generateParameter(t, db, parameterOptions{
AllowOverrideSource: true,
ProjectImportJobID: scope.ProjectImportJobID,
TemplateImportJobID: scope.TemplateImportJobID,
})
_, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{
ID: uuid.New(),
@@ -208,7 +208,7 @@ func TestCompute(t *testing.T) {
db := databasefake.New()
scope := generateScope()
_ = generateParameter(t, db, parameterOptions{
ProjectImportJobID: scope.ProjectImportJobID,
TemplateImportJobID: scope.TemplateImportJobID,
DefaultDestinationScheme: database.ParameterDestinationSchemeProvisionerVariable,
})
computed, err := parameter.Compute(context.Background(), db, scope, &parameter.ComputeOptions{
+2 -2
View File
@@ -143,8 +143,8 @@ func readScopeAndID(rw http.ResponseWriter, r *http.Request) (database.Parameter
switch chi.URLParam(r, "scope") {
case string(codersdk.ParameterOrganization):
scope = database.ParameterScopeOrganization
case string(codersdk.ParameterProject):
scope = database.ParameterScopeProject
case string(codersdk.ParameterTemplate):
scope = database.ParameterScopeTemplate
case string(codersdk.ParameterUser):
scope = database.ParameterScopeUser
case string(codersdk.ParameterWorkspace):
-225
View File
@@ -1,225 +0,0 @@
package coderd
import (
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/google/uuid"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/coderd/httpmw"
"github.com/coder/coder/codersdk"
)
// Returns a single project.
func (api *api) project(rw http.ResponseWriter, r *http.Request) {
project := httpmw.ProjectParam(r)
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByProjectIDs(r.Context(), []uuid.UUID{project.ID})
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace counts: %s", err.Error()),
})
return
}
count := uint32(0)
if len(workspaceCounts) > 0 {
count = uint32(workspaceCounts[0].Count)
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertProject(project, count))
}
func (api *api) deleteProject(rw http.ResponseWriter, r *http.Request) {
project := httpmw.ProjectParam(r)
workspaces, err := api.Database.GetWorkspacesByProjectID(r.Context(), database.GetWorkspacesByProjectIDParams{
ProjectID: project.ID,
})
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspaces by project id: %s", err),
})
return
}
if len(workspaces) > 0 {
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: "All workspaces must be deleted before a project can be removed.",
})
return
}
err = api.Database.UpdateProjectDeletedByID(r.Context(), database.UpdateProjectDeletedByIDParams{
ID: project.ID,
Deleted: true,
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("update project deleted by id: %s", err),
})
return
}
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "Project has been deleted!",
})
}
func (api *api) projectVersionsByProject(rw http.ResponseWriter, r *http.Request) {
project := httpmw.ProjectParam(r)
versions, err := api.Database.GetProjectVersionsByProjectID(r.Context(), project.ID)
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version: %s", err),
})
return
}
jobIDs := make([]uuid.UUID, 0, len(versions))
for _, version := range versions {
jobIDs = append(jobIDs, version.JobID)
}
jobs, err := api.Database.GetProvisionerJobsByIDs(r.Context(), jobIDs)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get jobs: %s", err),
})
return
}
jobByID := map[string]database.ProvisionerJob{}
for _, job := range jobs {
jobByID[job.ID.String()] = job
}
apiVersion := make([]codersdk.ProjectVersion, 0)
for _, version := range versions {
job, exists := jobByID[version.JobID.String()]
if !exists {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("job %q doesn't exist for version %q", version.JobID, version.ID),
})
return
}
apiVersion = append(apiVersion, convertProjectVersion(version, convertProvisionerJob(job)))
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, apiVersion)
}
func (api *api) projectVersionByName(rw http.ResponseWriter, r *http.Request) {
project := httpmw.ProjectParam(r)
projectVersionName := chi.URLParam(r, "projectversionname")
projectVersion, err := api.Database.GetProjectVersionByProjectIDAndName(r.Context(), database.GetProjectVersionByProjectIDAndNameParams{
ProjectID: uuid.NullUUID{
UUID: project.ID,
Valid: true,
},
Name: projectVersionName,
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("no project version found by name %q", projectVersionName),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version by name: %s", err),
})
return
}
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
})
return
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertProjectVersion(projectVersion, convertProvisionerJob(job)))
}
func (api *api) patchActiveProjectVersion(rw http.ResponseWriter, r *http.Request) {
var req codersdk.UpdateActiveProjectVersion
if !httpapi.Read(rw, r, &req) {
return
}
project := httpmw.ProjectParam(r)
version, err := api.Database.GetProjectVersionByID(r.Context(), req.ID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "project version not found",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version: %s", err),
})
return
}
if version.ProjectID.UUID.String() != project.ID.String() {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "The provided project version doesn't belong to the specified project.",
})
return
}
err = api.Database.UpdateProjectActiveVersionByID(r.Context(), database.UpdateProjectActiveVersionByIDParams{
ID: project.ID,
ActiveVersionID: req.ID,
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("update active project version: %s", err),
})
return
}
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "Updated the active project version!",
})
}
func convertProjects(projects []database.Project, workspaceCounts []database.GetWorkspaceOwnerCountsByProjectIDsRow) []codersdk.Project {
apiProjects := make([]codersdk.Project, 0, len(projects))
for _, project := range projects {
found := false
for _, workspaceCount := range workspaceCounts {
if workspaceCount.ProjectID.String() != project.ID.String() {
continue
}
apiProjects = append(apiProjects, convertProject(project, uint32(workspaceCount.Count)))
found = true
break
}
if !found {
apiProjects = append(apiProjects, convertProject(project, uint32(0)))
}
}
return apiProjects
}
func convertProject(project database.Project, workspaceOwnerCount uint32) codersdk.Project {
return codersdk.Project{
ID: project.ID,
CreatedAt: project.CreatedAt,
UpdatedAt: project.UpdatedAt,
OrganizationID: project.OrganizationID,
Name: project.Name,
Provisioner: project.Provisioner,
ActiveVersionID: project.ActiveVersionID,
WorkspaceOwnerCount: workspaceOwnerCount,
}
}
-139
View File
@@ -1,139 +0,0 @@
package coderd_test
import (
"context"
"net/http"
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/codersdk"
)
func TestProject(t *testing.T) {
t.Parallel()
t.Run("Get", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
_, err := client.Project(context.Background(), project.ID)
require.NoError(t, err)
})
}
func TestDeleteProject(t *testing.T) {
t.Parallel()
t.Run("NoWorkspaces", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
err := client.DeleteProject(context.Background(), project.ID)
require.NoError(t, err)
})
t.Run("Workspaces", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
err := client.DeleteProject(context.Background(), project.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
})
}
func TestProjectVersionsByProject(t *testing.T) {
t.Parallel()
t.Run("Get", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
versions, err := client.ProjectVersionsByProject(context.Background(), project.ID)
require.NoError(t, err)
require.Len(t, versions, 1)
})
}
func TestProjectVersionByName(t *testing.T) {
t.Parallel()
t.Run("NotFound", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
_, err := client.ProjectVersionByName(context.Background(), project.ID, "nothing")
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
})
t.Run("Found", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
_, err := client.ProjectVersionByName(context.Background(), project.ID, version.Name)
require.NoError(t, err)
})
}
func TestPatchActiveProjectVersion(t *testing.T) {
t.Parallel()
t.Run("NotFound", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
err := client.UpdateActiveProjectVersion(context.Background(), project.ID, codersdk.UpdateActiveProjectVersion{
ID: uuid.New(),
})
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
})
t.Run("DoesNotBelong", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
version = coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
err := client.UpdateActiveProjectVersion(context.Background(), project.ID, codersdk.UpdateActiveProjectVersion{
ID: version.ID,
})
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode())
})
t.Run("Found", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
err := client.UpdateActiveProjectVersion(context.Background(), project.ID, codersdk.UpdateActiveProjectVersion{
ID: version.ID,
})
require.NoError(t, err)
})
}
+26 -26
View File
@@ -177,13 +177,13 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
if err != nil {
return nil, failJob(fmt.Sprintf("get workspace: %s", err))
}
projectVersion, err := server.Database.GetProjectVersionByID(ctx, workspaceBuild.ProjectVersionID)
templateVersion, err := server.Database.GetTemplateVersionByID(ctx, workspaceBuild.TemplateVersionID)
if err != nil {
return nil, failJob(fmt.Sprintf("get project version: %s", err))
return nil, failJob(fmt.Sprintf("get template version: %s", err))
}
project, err := server.Database.GetProjectByID(ctx, projectVersion.ProjectID.UUID)
template, err := server.Database.GetTemplateByID(ctx, templateVersion.TemplateID.UUID)
if err != nil {
return nil, failJob(fmt.Sprintf("get project: %s", err))
return nil, failJob(fmt.Sprintf("get template: %s", err))
}
owner, err := server.Database.GetUserByID(ctx, workspace.OwnerID)
if err != nil {
@@ -192,10 +192,10 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
// Compute parameters for the workspace to consume.
parameters, err := parameter.Compute(ctx, server.Database, parameter.ComputeScope{
ProjectImportJobID: projectVersion.JobID,
OrganizationID: job.OrganizationID,
ProjectID: uuid.NullUUID{
UUID: project.ID,
TemplateImportJobID: templateVersion.JobID,
OrganizationID: job.OrganizationID,
TemplateID: uuid.NullUUID{
UUID: template.ID,
Valid: true,
},
UserID: user.ID,
@@ -235,9 +235,9 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
},
},
}
case database.ProvisionerJobTypeProjectVersionImport:
protoJob.Type = &proto.AcquiredJob_ProjectImport_{
ProjectImport: &proto.AcquiredJob_ProjectImport{
case database.ProvisionerJobTypeTemplateVersionImport:
protoJob.Type = &proto.AcquiredJob_TemplateImport_{
TemplateImport: &proto.AcquiredJob_TemplateImport{
Metadata: &sdkproto.Provision_Metadata{
CoderUrl: server.AccessURL.String(),
},
@@ -250,7 +250,7 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
if err != nil {
return nil, failJob(fmt.Sprintf("get file by hash: %s", err))
}
protoJob.ProjectSourceArchive = file.Data
protoJob.TemplateSourceArchive = file.Data
default:
return nil, failJob(fmt.Sprintf("unsupported storage method: %s", job.StorageMethod))
}
@@ -366,20 +366,20 @@ func (server *provisionerdServer) UpdateJob(ctx context.Context, request *proto.
}
}
var projectID uuid.NullUUID
if job.Type == database.ProvisionerJobTypeProjectVersionImport {
projectVersion, err := server.Database.GetProjectVersionByJobID(ctx, job.ID)
var templateID uuid.NullUUID
if job.Type == database.ProvisionerJobTypeTemplateVersionImport {
templateVersion, err := server.Database.GetTemplateVersionByJobID(ctx, job.ID)
if err != nil {
return nil, xerrors.Errorf("get project version by job id: %w", err)
return nil, xerrors.Errorf("get template version by job id: %w", err)
}
projectID = projectVersion.ProjectID
templateID = templateVersion.TemplateID
}
parameters, err := parameter.Compute(ctx, server.Database, parameter.ComputeScope{
ProjectImportJobID: job.ID,
ProjectID: projectID,
OrganizationID: job.OrganizationID,
UserID: job.InitiatorID,
TemplateImportJobID: job.ID,
TemplateID: templateID,
OrganizationID: job.OrganizationID,
UserID: job.InitiatorID,
}, nil)
if err != nil {
return nil, xerrors.Errorf("compute parameters: %w", err)
@@ -450,7 +450,7 @@ func (server *provisionerdServer) FailJob(ctx context.Context, failJob *proto.Fa
if err != nil {
return nil, xerrors.Errorf("update workspace build state: %w", err)
}
case *proto.FailedJob_ProjectImport_:
case *proto.FailedJob_TemplateImport_:
}
return &proto.Empty{}, nil
}
@@ -470,17 +470,17 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
}
switch jobType := completed.Type.(type) {
case *proto.CompletedJob_ProjectImport_:
case *proto.CompletedJob_TemplateImport_:
for transition, resources := range map[database.WorkspaceTransition][]*sdkproto.Resource{
database.WorkspaceTransitionStart: jobType.ProjectImport.StartResources,
database.WorkspaceTransitionStop: jobType.ProjectImport.StopResources,
database.WorkspaceTransitionStart: jobType.TemplateImport.StartResources,
database.WorkspaceTransitionStop: jobType.TemplateImport.StopResources,
} {
addresses, err := provisionersdk.ResourceAddresses(resources)
if err != nil {
return nil, xerrors.Errorf("compute resource addresses: %w", err)
}
for index, resource := range resources {
server.Logger.Info(ctx, "inserting project import job resource",
server.Logger.Info(ctx, "inserting template import job resource",
slog.F("job_id", job.ID.String()),
slog.F("resource_name", resource.Name),
slog.F("resource_type", resource.Type),
+12 -12
View File
@@ -21,7 +21,7 @@ func TestProvisionerJobLogs(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
@@ -36,9 +36,9 @@ func TestProvisionerJobLogs(t *testing.T) {
},
}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
before := time.Now().UTC()
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
@@ -59,7 +59,7 @@ func TestProvisionerJobLogs(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
@@ -74,9 +74,9 @@ func TestProvisionerJobLogs(t *testing.T) {
},
}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
before := database.Now()
ctx, cancelFunc := context.WithCancel(context.Background())
t.Cleanup(cancelFunc)
@@ -95,7 +95,7 @@ func TestProvisionerJobLogs(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
@@ -110,9 +110,9 @@ func TestProvisionerJobLogs(t *testing.T) {
},
}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
logs, err := client.WorkspaceBuildLogsBefore(context.Background(), workspace.LatestBuild.ID, time.Now())
require.NoError(t, err)
+225
View File
@@ -0,0 +1,225 @@
package coderd
import (
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/google/uuid"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/coderd/httpmw"
"github.com/coder/coder/codersdk"
)
// Returns a single template.
func (api *api) template(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByTemplateIDs(r.Context(), []uuid.UUID{template.ID})
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace counts: %s", err.Error()),
})
return
}
count := uint32(0)
if len(workspaceCounts) > 0 {
count = uint32(workspaceCounts[0].Count)
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertTemplate(template, count))
}
func (api *api) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
workspaces, err := api.Database.GetWorkspacesByTemplateID(r.Context(), database.GetWorkspacesByTemplateIDParams{
TemplateID: template.ID,
})
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspaces by template id: %s", err),
})
return
}
if len(workspaces) > 0 {
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: "All workspaces must be deleted before a template can be removed.",
})
return
}
err = api.Database.UpdateTemplateDeletedByID(r.Context(), database.UpdateTemplateDeletedByIDParams{
ID: template.ID,
Deleted: true,
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("update template deleted by id: %s", err),
})
return
}
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "Template has been deleted!",
})
}
func (api *api) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
versions, err := api.Database.GetTemplateVersionsByTemplateID(r.Context(), template.ID)
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get template version: %s", err),
})
return
}
jobIDs := make([]uuid.UUID, 0, len(versions))
for _, version := range versions {
jobIDs = append(jobIDs, version.JobID)
}
jobs, err := api.Database.GetProvisionerJobsByIDs(r.Context(), jobIDs)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get jobs: %s", err),
})
return
}
jobByID := map[string]database.ProvisionerJob{}
for _, job := range jobs {
jobByID[job.ID.String()] = job
}
apiVersion := make([]codersdk.TemplateVersion, 0)
for _, version := range versions {
job, exists := jobByID[version.JobID.String()]
if !exists {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("job %q doesn't exist for version %q", version.JobID, version.ID),
})
return
}
apiVersion = append(apiVersion, convertTemplateVersion(version, convertProvisionerJob(job)))
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, apiVersion)
}
func (api *api) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)
templateVersionName := chi.URLParam(r, "templateversionname")
templateVersion, err := api.Database.GetTemplateVersionByTemplateIDAndName(r.Context(), database.GetTemplateVersionByTemplateIDAndNameParams{
TemplateID: uuid.NullUUID{
UUID: template.ID,
Valid: true,
},
Name: templateVersionName,
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("no template version found by name %q", templateVersionName),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get template version by name: %s", err),
})
return
}
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
})
return
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertTemplateVersion(templateVersion, convertProvisionerJob(job)))
}
func (api *api) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Request) {
var req codersdk.UpdateActiveTemplateVersion
if !httpapi.Read(rw, r, &req) {
return
}
template := httpmw.TemplateParam(r)
version, err := api.Database.GetTemplateVersionByID(r.Context(), req.ID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "template version not found",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get template version: %s", err),
})
return
}
if version.TemplateID.UUID.String() != template.ID.String() {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "The provided template version doesn't belong to the specified template.",
})
return
}
err = api.Database.UpdateTemplateActiveVersionByID(r.Context(), database.UpdateTemplateActiveVersionByIDParams{
ID: template.ID,
ActiveVersionID: req.ID,
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("update active template version: %s", err),
})
return
}
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "Updated the active template version!",
})
}
func convertTemplates(templates []database.Template, workspaceCounts []database.GetWorkspaceOwnerCountsByTemplateIDsRow) []codersdk.Template {
apiTemplates := make([]codersdk.Template, 0, len(templates))
for _, template := range templates {
found := false
for _, workspaceCount := range workspaceCounts {
if workspaceCount.TemplateID.String() != template.ID.String() {
continue
}
apiTemplates = append(apiTemplates, convertTemplate(template, uint32(workspaceCount.Count)))
found = true
break
}
if !found {
apiTemplates = append(apiTemplates, convertTemplate(template, uint32(0)))
}
}
return apiTemplates
}
func convertTemplate(template database.Template, workspaceOwnerCount uint32) codersdk.Template {
return codersdk.Template{
ID: template.ID,
CreatedAt: template.CreatedAt,
UpdatedAt: template.UpdatedAt,
OrganizationID: template.OrganizationID,
Name: template.Name,
Provisioner: template.Provisioner,
ActiveVersionID: template.ActiveVersionID,
WorkspaceOwnerCount: workspaceOwnerCount,
}
}
+139
View File
@@ -0,0 +1,139 @@
package coderd_test
import (
"context"
"net/http"
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/codersdk"
)
func TestTemplate(t *testing.T) {
t.Parallel()
t.Run("Get", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
_, err := client.Template(context.Background(), template.ID)
require.NoError(t, err)
})
}
func TestDeleteTemplate(t *testing.T) {
t.Parallel()
t.Run("NoWorkspaces", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
err := client.DeleteTemplate(context.Background(), template.ID)
require.NoError(t, err)
})
t.Run("Workspaces", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
err := client.DeleteTemplate(context.Background(), template.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
})
}
func TestTemplateVersionsByTemplate(t *testing.T) {
t.Parallel()
t.Run("Get", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
versions, err := client.TemplateVersionsByTemplate(context.Background(), template.ID)
require.NoError(t, err)
require.Len(t, versions, 1)
})
}
func TestTemplateVersionByName(t *testing.T) {
t.Parallel()
t.Run("NotFound", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
_, err := client.TemplateVersionByName(context.Background(), template.ID, "nothing")
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
})
t.Run("Found", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
_, err := client.TemplateVersionByName(context.Background(), template.ID, version.Name)
require.NoError(t, err)
})
}
func TestPatchActiveTemplateVersion(t *testing.T) {
t.Parallel()
t.Run("NotFound", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
ID: uuid.New(),
})
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
})
t.Run("DoesNotBelong", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
ID: version.ID,
})
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode())
})
t.Run("Found", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{
ID: version.ID,
})
require.NoError(t, err)
})
}
@@ -15,9 +15,9 @@ import (
"github.com/coder/coder/codersdk"
)
func (api *api) projectVersion(rw http.ResponseWriter, r *http.Request) {
projectVersion := httpmw.ProjectVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
func (api *api) templateVersion(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
@@ -25,12 +25,12 @@ func (api *api) projectVersion(rw http.ResponseWriter, r *http.Request) {
return
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertProjectVersion(projectVersion, convertProvisionerJob(job)))
render.JSON(rw, r, convertTemplateVersion(templateVersion, convertProvisionerJob(job)))
}
func (api *api) patchCancelProjectVersion(rw http.ResponseWriter, r *http.Request) {
projectVersion := httpmw.ProjectVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
func (api *api) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
@@ -67,9 +67,9 @@ func (api *api) patchCancelProjectVersion(rw http.ResponseWriter, r *http.Reques
})
}
func (api *api) projectVersionSchema(rw http.ResponseWriter, r *http.Request) {
projectVersion := httpmw.ProjectVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
func (api *api) templateVersionSchema(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
@@ -78,7 +78,7 @@ func (api *api) projectVersionSchema(rw http.ResponseWriter, r *http.Request) {
}
if !job.CompletedAt.Valid {
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: "Project version job hasn't completed!",
Message: "Template version job hasn't completed!",
})
return
}
@@ -99,10 +99,10 @@ func (api *api) projectVersionSchema(rw http.ResponseWriter, r *http.Request) {
render.JSON(rw, r, schemas)
}
func (api *api) projectVersionParameters(rw http.ResponseWriter, r *http.Request) {
func (api *api) templateVersionParameters(rw http.ResponseWriter, r *http.Request) {
apiKey := httpmw.APIKey(r)
projectVersion := httpmw.ProjectVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
templateVersion := httpmw.TemplateVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
@@ -116,9 +116,9 @@ func (api *api) projectVersionParameters(rw http.ResponseWriter, r *http.Request
return
}
values, err := parameter.Compute(r.Context(), api.Database, parameter.ComputeScope{
ProjectImportJobID: job.ID,
OrganizationID: job.OrganizationID,
UserID: apiKey.UserID,
TemplateImportJobID: job.ID,
OrganizationID: job.OrganizationID,
UserID: apiKey.UserID,
}, &parameter.ComputeOptions{
// We *never* want to send the client secret parameter values.
HideRedisplayValues: true,
@@ -136,9 +136,9 @@ func (api *api) projectVersionParameters(rw http.ResponseWriter, r *http.Request
render.JSON(rw, r, values)
}
func (api *api) projectVersionResources(rw http.ResponseWriter, r *http.Request) {
projectVersion := httpmw.ProjectVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
func (api *api) templateVersionResources(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
@@ -148,9 +148,9 @@ func (api *api) projectVersionResources(rw http.ResponseWriter, r *http.Request)
api.provisionerJobResources(rw, r, job)
}
func (api *api) projectVersionLogs(rw http.ResponseWriter, r *http.Request) {
projectVersion := httpmw.ProjectVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
func (api *api) templateVersionLogs(rw http.ResponseWriter, r *http.Request) {
templateVersion := httpmw.TemplateVersionParam(r)
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
@@ -160,13 +160,13 @@ func (api *api) projectVersionLogs(rw http.ResponseWriter, r *http.Request) {
api.provisionerJobLogs(rw, r, job)
}
func convertProjectVersion(version database.ProjectVersion, job codersdk.ProvisionerJob) codersdk.ProjectVersion {
return codersdk.ProjectVersion{
ID: version.ID,
ProjectID: &version.ProjectID.UUID,
CreatedAt: version.CreatedAt,
UpdatedAt: version.UpdatedAt,
Name: version.Name,
Job: job,
func convertTemplateVersion(version database.TemplateVersion, job codersdk.ProvisionerJob) codersdk.TemplateVersion {
return codersdk.TemplateVersion{
ID: version.ID,
TemplateID: &version.TemplateID.UUID,
CreatedAt: version.CreatedAt,
UpdatedAt: version.UpdatedAt,
Name: version.Name,
Job: job,
}
}
@@ -15,28 +15,28 @@ import (
"github.com/coder/coder/provisionersdk/proto"
)
func TestProjectVersion(t *testing.T) {
func TestTemplateVersion(t *testing.T) {
t.Parallel()
t.Run("Get", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
_, err := client.ProjectVersion(context.Background(), version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_, err := client.TemplateVersion(context.Background(), version.ID)
require.NoError(t, err)
})
}
func TestPatchCancelProjectVersion(t *testing.T) {
func TestPatchCancelTemplateVersion(t *testing.T) {
t.Parallel()
t.Run("AlreadyCompleted", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
err := client.CancelProjectVersion(context.Background(), version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
err := client.CancelTemplateVersion(context.Background(), version.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
@@ -46,7 +46,7 @@ func TestPatchCancelProjectVersion(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
@@ -56,14 +56,14 @@ func TestPatchCancelProjectVersion(t *testing.T) {
})
require.Eventually(t, func() bool {
var err error
version, err = client.ProjectVersion(context.Background(), version.ID)
version, err = client.TemplateVersion(context.Background(), version.ID)
require.NoError(t, err)
t.Logf("Status: %s", version.Job.Status)
return version.Job.Status == codersdk.ProvisionerJobRunning
}, 5*time.Second, 25*time.Millisecond)
err := client.CancelProjectVersion(context.Background(), version.ID)
err := client.CancelTemplateVersion(context.Background(), version.ID)
require.NoError(t, err)
err = client.CancelProjectVersion(context.Background(), version.ID)
err = client.CancelTemplateVersion(context.Background(), version.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
@@ -73,7 +73,7 @@ func TestPatchCancelProjectVersion(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
@@ -83,30 +83,30 @@ func TestPatchCancelProjectVersion(t *testing.T) {
})
require.Eventually(t, func() bool {
var err error
version, err = client.ProjectVersion(context.Background(), version.ID)
version, err = client.TemplateVersion(context.Background(), version.ID)
require.NoError(t, err)
t.Logf("Status: %s", version.Job.Status)
return version.Job.Status == codersdk.ProvisionerJobRunning
}, 5*time.Second, 25*time.Millisecond)
err := client.CancelProjectVersion(context.Background(), version.ID)
err := client.CancelTemplateVersion(context.Background(), version.ID)
require.NoError(t, err)
require.Eventually(t, func() bool {
var err error
version, err = client.ProjectVersion(context.Background(), version.ID)
version, err = client.TemplateVersion(context.Background(), version.ID)
require.NoError(t, err)
return version.Job.Status == codersdk.ProvisionerJobCanceled
}, 5*time.Second, 25*time.Millisecond)
})
}
func TestProjectVersionSchema(t *testing.T) {
func TestTemplateVersionSchema(t *testing.T) {
t.Parallel()
t.Run("ListRunning", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
_, err := client.ProjectVersionSchema(context.Background(), version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_, err := client.TemplateVersionSchema(context.Background(), version.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
@@ -116,7 +116,7 @@ func TestProjectVersionSchema(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: []*proto.Parse_Response{{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
@@ -131,22 +131,22 @@ func TestProjectVersionSchema(t *testing.T) {
}},
Provision: echo.ProvisionComplete,
})
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
schemas, err := client.ProjectVersionSchema(context.Background(), version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
schemas, err := client.TemplateVersionSchema(context.Background(), version.ID)
require.NoError(t, err)
require.NotNil(t, schemas)
require.Len(t, schemas, 1)
})
}
func TestProjectVersionParameters(t *testing.T) {
func TestTemplateVersionParameters(t *testing.T) {
t.Parallel()
t.Run("ListRunning", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
_, err := client.ProjectVersionParameters(context.Background(), version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_, err := client.TemplateVersionParameters(context.Background(), version.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
@@ -156,7 +156,7 @@ func TestProjectVersionParameters(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: []*proto.Parse_Response{{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
@@ -176,8 +176,8 @@ func TestProjectVersionParameters(t *testing.T) {
}},
Provision: echo.ProvisionComplete,
})
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
params, err := client.ProjectVersionParameters(context.Background(), version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
params, err := client.TemplateVersionParameters(context.Background(), version.ID)
require.NoError(t, err)
require.NotNil(t, params)
require.Len(t, params, 1)
@@ -185,14 +185,14 @@ func TestProjectVersionParameters(t *testing.T) {
})
}
func TestProjectVersionResources(t *testing.T) {
func TestTemplateVersionResources(t *testing.T) {
t.Parallel()
t.Run("ListRunning", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
_, err := client.ProjectVersionResources(context.Background(), version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_, err := client.TemplateVersionResources(context.Background(), version.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode())
@@ -202,7 +202,7 @@ func TestProjectVersionResources(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
@@ -222,8 +222,8 @@ func TestProjectVersionResources(t *testing.T) {
},
}},
})
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
resources, err := client.ProjectVersionResources(context.Background(), version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
resources, err := client.TemplateVersionResources(context.Background(), version.ID)
require.NoError(t, err)
require.NotNil(t, resources)
require.Len(t, resources, 4)
@@ -233,13 +233,13 @@ func TestProjectVersionResources(t *testing.T) {
})
}
func TestProjectVersionLogs(t *testing.T) {
func TestTemplateVersionLogs(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
before := time.Now()
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionDryRun: echo.ProvisionComplete,
Provision: []*proto.Provision_Response{{
@@ -271,7 +271,7 @@ func TestProjectVersionLogs(t *testing.T) {
})
ctx, cancelFunc := context.WithCancel(context.Background())
t.Cleanup(cancelFunc)
logs, err := client.ProjectVersionLogsAfter(ctx, version.ID, before)
logs, err := client.TemplateVersionLogsAfter(ctx, version.ID, before)
require.NoError(t, err)
for {
_, ok := <-logs
+1 -1
View File
@@ -23,7 +23,7 @@ const (
// Compare checks the equality of passwords from a hashed pbkdf2 string.
// This uses pbkdf2 to ensure FIPS 140-2 compliance. See:
// https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp2261.pdf
// https://csrc.nist.gov/csrc/media/templates/cryptographic-module-validation-program/documents/security-policies/140sp2261.pdf
func Compare(hashed string, password string) (bool, error) {
if len(hashed) < hashLength {
return false, xerrors.Errorf("hash too short: %d", len(hashed))
+52 -52
View File
@@ -529,12 +529,12 @@ func (api *api) postWorkspacesByUser(rw http.ResponseWriter, r *http.Request) {
return
}
apiKey := httpmw.APIKey(r)
project, err := api.Database.GetProjectByID(r.Context(), createWorkspace.ProjectID)
template, err := api.Database.GetTemplateByID(r.Context(), createWorkspace.TemplateID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("project %q doesn't exist", createWorkspace.ProjectID.String()),
Message: fmt.Sprintf("template %q doesn't exist", createWorkspace.TemplateID.String()),
Errors: []httpapi.Error{{
Field: "project_id",
Field: "template_id",
Code: "not_found",
}},
})
@@ -542,17 +542,17 @@ func (api *api) postWorkspacesByUser(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project: %s", err),
Message: fmt.Sprintf("get template: %s", err),
})
return
}
_, err = api.Database.GetOrganizationMemberByUserID(r.Context(), database.GetOrganizationMemberByUserIDParams{
OrganizationID: project.OrganizationID,
OrganizationID: template.OrganizationID,
UserID: apiKey.UserID,
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "you aren't allowed to access projects in that organization",
Message: "you aren't allowed to access templates in that organization",
})
return
}
@@ -569,16 +569,16 @@ func (api *api) postWorkspacesByUser(rw http.ResponseWriter, r *http.Request) {
})
if err == nil {
// If the workspace already exists, don't allow creation.
project, err := api.Database.GetProjectByID(r.Context(), workspace.ProjectID)
template, err := api.Database.GetTemplateByID(r.Context(), workspace.TemplateID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("find project for conflicting workspace name %q: %s", createWorkspace.Name, err),
Message: fmt.Sprintf("find template for conflicting workspace name %q: %s", createWorkspace.Name, err),
})
return
}
// The project is fetched for clarity to the user on where the conflicting name may be.
// The template is fetched for clarity to the user on where the conflicting name may be.
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: fmt.Sprintf("workspace %q already exists in the %q project", createWorkspace.Name, project.Name),
Message: fmt.Sprintf("workspace %q already exists in the %q template", createWorkspace.Name, template.Name),
Errors: []httpapi.Error{{
Field: "name",
Code: "exists",
@@ -593,35 +593,35 @@ func (api *api) postWorkspacesByUser(rw http.ResponseWriter, r *http.Request) {
return
}
projectVersion, err := api.Database.GetProjectVersionByID(r.Context(), project.ActiveVersionID)
templateVersion, err := api.Database.GetTemplateVersionByID(r.Context(), template.ActiveVersionID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version: %s", err),
Message: fmt.Sprintf("get template version: %s", err),
})
return
}
projectVersionJob, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
templateVersionJob, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version job: %s", err),
Message: fmt.Sprintf("get template version job: %s", err),
})
return
}
projectVersionJobStatus := convertProvisionerJob(projectVersionJob).Status
switch projectVersionJobStatus {
templateVersionJobStatus := convertProvisionerJob(templateVersionJob).Status
switch templateVersionJobStatus {
case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning:
httpapi.Write(rw, http.StatusNotAcceptable, httpapi.Response{
Message: fmt.Sprintf("The provided project version is %s. Wait for it to complete importing!", projectVersionJobStatus),
Message: fmt.Sprintf("The provided template version is %s. Wait for it to complete importing!", templateVersionJobStatus),
})
return
case codersdk.ProvisionerJobFailed:
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: fmt.Sprintf("The provided project version %q has failed to import. You cannot create workspaces using it!", projectVersion.Name),
Message: fmt.Sprintf("The provided template version %q has failed to import. You cannot create workspaces using it!", templateVersion.Name),
})
return
case codersdk.ProvisionerJobCanceled:
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: "The provided project version was canceled during import. You cannot create workspaces using it!",
Message: "The provided template version was canceled during import. You cannot create workspaces using it!",
})
return
}
@@ -632,12 +632,12 @@ func (api *api) postWorkspacesByUser(rw http.ResponseWriter, r *http.Request) {
workspaceBuildID := uuid.New()
// Workspaces are created without any versions.
workspace, err = db.InsertWorkspace(r.Context(), database.InsertWorkspaceParams{
ID: uuid.New(),
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
OwnerID: apiKey.UserID,
ProjectID: project.ID,
Name: createWorkspace.Name,
ID: uuid.New(),
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
OwnerID: apiKey.UserID,
TemplateID: template.ID,
Name: createWorkspace.Name,
})
if err != nil {
return xerrors.Errorf("insert workspace: %w", err)
@@ -670,26 +670,26 @@ func (api *api) postWorkspacesByUser(rw http.ResponseWriter, r *http.Request) {
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
InitiatorID: apiKey.UserID,
OrganizationID: project.OrganizationID,
Provisioner: project.Provisioner,
OrganizationID: template.OrganizationID,
Provisioner: template.Provisioner,
Type: database.ProvisionerJobTypeWorkspaceBuild,
StorageMethod: projectVersionJob.StorageMethod,
StorageSource: projectVersionJob.StorageSource,
StorageMethod: templateVersionJob.StorageMethod,
StorageSource: templateVersionJob.StorageSource,
Input: input,
})
if err != nil {
return xerrors.Errorf("insert provisioner job: %w", err)
}
workspaceBuild, err = db.InsertWorkspaceBuild(r.Context(), database.InsertWorkspaceBuildParams{
ID: workspaceBuildID,
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
WorkspaceID: workspace.ID,
ProjectVersionID: projectVersion.ID,
Name: namesgenerator.GetRandomName(1),
InitiatorID: apiKey.UserID,
Transition: database.WorkspaceTransitionStart,
JobID: provisionerJob.ID,
ID: workspaceBuildID,
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
WorkspaceID: workspace.ID,
TemplateVersionID: templateVersion.ID,
Name: namesgenerator.GetRandomName(1),
InitiatorID: apiKey.UserID,
Transition: database.WorkspaceTransitionStart,
JobID: provisionerJob.ID,
})
if err != nil {
return xerrors.Errorf("insert workspace build: %w", err)
@@ -705,7 +705,7 @@ func (api *api) postWorkspacesByUser(rw http.ResponseWriter, r *http.Request) {
render.Status(r, http.StatusCreated)
render.JSON(rw, r, convertWorkspace(workspace,
convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(projectVersionJob)), project))
convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(templateVersionJob)), template))
}
func (api *api) workspacesByUser(rw http.ResponseWriter, r *http.Request) {
@@ -723,10 +723,10 @@ func (api *api) workspacesByUser(rw http.ResponseWriter, r *http.Request) {
return
}
workspaceIDs := make([]uuid.UUID, 0, len(workspaces))
projectIDs := make([]uuid.UUID, 0, len(workspaces))
templateIDs := make([]uuid.UUID, 0, len(workspaces))
for _, workspace := range workspaces {
workspaceIDs = append(workspaceIDs, workspace.ID)
projectIDs = append(projectIDs, workspace.ProjectID)
templateIDs = append(templateIDs, workspace.TemplateID)
}
workspaceBuilds, err := api.Database.GetWorkspaceBuildsByWorkspaceIDsWithoutAfter(r.Context(), workspaceIDs)
if errors.Is(err, sql.ErrNoRows) {
@@ -738,13 +738,13 @@ func (api *api) workspacesByUser(rw http.ResponseWriter, r *http.Request) {
})
return
}
projects, err := api.Database.GetProjectsByIDs(r.Context(), projectIDs)
templates, err := api.Database.GetTemplatesByIDs(r.Context(), templateIDs)
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get projects: %s", err),
Message: fmt.Sprintf("get templates: %s", err),
})
return
}
@@ -767,9 +767,9 @@ func (api *api) workspacesByUser(rw http.ResponseWriter, r *http.Request) {
for _, workspaceBuild := range workspaceBuilds {
buildByWorkspaceID[workspaceBuild.WorkspaceID] = workspaceBuild
}
projectByID := map[uuid.UUID]database.Project{}
for _, project := range projects {
projectByID[project.ID] = project
templateByID := map[uuid.UUID]database.Template{}
for _, template := range templates {
templateByID[template.ID] = template
}
jobByID := map[uuid.UUID]database.ProvisionerJob{}
for _, job := range jobs {
@@ -784,10 +784,10 @@ func (api *api) workspacesByUser(rw http.ResponseWriter, r *http.Request) {
})
return
}
project, exists := projectByID[workspace.ProjectID]
template, exists := templateByID[workspace.TemplateID]
if !exists {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("project not found for workspace %q", workspace.Name),
Message: fmt.Sprintf("template not found for workspace %q", workspace.Name),
})
return
}
@@ -799,7 +799,7 @@ func (api *api) workspacesByUser(rw http.ResponseWriter, r *http.Request) {
return
}
apiWorkspaces = append(apiWorkspaces,
convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), project))
convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), template))
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, apiWorkspaces)
@@ -838,17 +838,17 @@ func (api *api) workspaceByUserAndName(rw http.ResponseWriter, r *http.Request)
})
return
}
project, err := api.Database.GetProjectByID(r.Context(), workspace.ProjectID)
template, err := api.Database.GetTemplateByID(r.Context(), workspace.TemplateID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project: %s", err),
Message: fmt.Sprintf("get template: %s", err),
})
return
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, convertWorkspace(workspace,
convertWorkspaceBuild(build, convertProvisionerJob(job)), project))
convertWorkspaceBuild(build, convertProvisionerJob(job)), template))
}
// Generates a new ID and secret for an API key.
+26 -26
View File
@@ -310,13 +310,13 @@ func TestPostAPIKey(t *testing.T) {
func TestPostWorkspacesByUser(t *testing.T) {
t.Parallel()
t.Run("InvalidProject", func(t *testing.T) {
t.Run("InvalidTemplate", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
_, err := client.CreateWorkspace(context.Background(), codersdk.Me, codersdk.CreateWorkspaceRequest{
ProjectID: uuid.New(),
Name: "workspace",
TemplateID: uuid.New(),
Name: "workspace",
})
require.Error(t, err)
var apiErr *codersdk.Error
@@ -324,7 +324,7 @@ func TestPostWorkspacesByUser(t *testing.T) {
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
})
t.Run("NoProjectAccess", func(t *testing.T) {
t.Run("NoTemplateAccess", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
first := coderdtest.CreateFirstUser(t, client)
@@ -334,12 +334,12 @@ func TestPostWorkspacesByUser(t *testing.T) {
Name: "another",
})
require.NoError(t, err)
version := coderdtest.CreateProjectVersion(t, other, org.ID, nil)
project := coderdtest.CreateProject(t, other, org.ID, version.ID)
version := coderdtest.CreateTemplateVersion(t, other, org.ID, nil)
template := coderdtest.CreateTemplate(t, other, org.ID, version.ID)
_, err = client.CreateWorkspace(context.Background(), codersdk.Me, codersdk.CreateWorkspaceRequest{
ProjectID: project.ID,
Name: "workspace",
TemplateID: template.ID,
Name: "workspace",
})
require.Error(t, err)
var apiErr *codersdk.Error
@@ -352,13 +352,13 @@ func TestPostWorkspacesByUser(t *testing.T) {
client := coderdtest.New(t, nil)
coderdtest.NewProvisionerDaemon(t, client)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.CreateWorkspace(context.Background(), codersdk.Me, codersdk.CreateWorkspaceRequest{
ProjectID: project.ID,
Name: workspace.Name,
TemplateID: template.ID,
Name: workspace.Name,
})
require.Error(t, err)
var apiErr *codersdk.Error
@@ -371,10 +371,10 @@ func TestPostWorkspacesByUser(t *testing.T) {
client := coderdtest.New(t, nil)
coderdtest.NewProvisionerDaemon(t, client)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
_ = coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
_ = coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
})
}
@@ -392,10 +392,10 @@ func TestWorkspacesByUser(t *testing.T) {
client := coderdtest.New(t, nil)
coderdtest.NewProvisionerDaemon(t, client)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
_ = coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
_ = coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
workspaces, err := client.WorkspacesByUser(context.Background(), codersdk.Me)
require.NoError(t, err)
require.Len(t, workspaces, 1)
@@ -418,10 +418,10 @@ func TestWorkspaceByUserAndName(t *testing.T) {
client := coderdtest.New(t, nil)
coderdtest.NewProvisionerDaemon(t, client)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.WorkspaceByName(context.Background(), codersdk.Me, workspace.Name)
require.NoError(t, err)
})
+11 -11
View File
@@ -92,17 +92,17 @@ func (api *api) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) {
func convertWorkspaceBuild(workspaceBuild database.WorkspaceBuild, job codersdk.ProvisionerJob) codersdk.WorkspaceBuild {
//nolint:unconvert
return codersdk.WorkspaceBuild{
ID: workspaceBuild.ID,
CreatedAt: workspaceBuild.CreatedAt,
UpdatedAt: workspaceBuild.UpdatedAt,
WorkspaceID: workspaceBuild.WorkspaceID,
ProjectVersionID: workspaceBuild.ProjectVersionID,
BeforeID: workspaceBuild.BeforeID.UUID,
AfterID: workspaceBuild.AfterID.UUID,
Name: workspaceBuild.Name,
Transition: workspaceBuild.Transition,
InitiatorID: workspaceBuild.InitiatorID,
Job: job,
ID: workspaceBuild.ID,
CreatedAt: workspaceBuild.CreatedAt,
UpdatedAt: workspaceBuild.UpdatedAt,
WorkspaceID: workspaceBuild.WorkspaceID,
TemplateVersionID: workspaceBuild.TemplateVersionID,
BeforeID: workspaceBuild.BeforeID.UUID,
AfterID: workspaceBuild.AfterID.UUID,
Name: workspaceBuild.Name,
Transition: workspaceBuild.Transition,
InitiatorID: workspaceBuild.InitiatorID,
Job: job,
}
}
+20 -20
View File
@@ -19,10 +19,10 @@ func TestWorkspaceBuild(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.WorkspaceBuild(context.Background(), workspace.LatestBuild.ID)
require.NoError(t, err)
}
@@ -32,7 +32,7 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
@@ -41,9 +41,9 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) {
}},
ProvisionDryRun: echo.ProvisionComplete,
})
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
var build codersdk.WorkspaceBuild
require.Eventually(t, func() bool {
var err error
@@ -68,11 +68,11 @@ func TestWorkspaceBuildResources(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
closeDaemon := coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
closeDaemon.Close()
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.WorkspaceResourcesByBuild(context.Background(), workspace.LatestBuild.ID)
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
@@ -83,7 +83,7 @@ func TestWorkspaceBuildResources(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
@@ -103,9 +103,9 @@ func TestWorkspaceBuildResources(t *testing.T) {
},
}},
})
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
resources, err := client.WorkspaceResourcesByBuild(context.Background(), workspace.LatestBuild.ID)
require.NoError(t, err)
@@ -123,7 +123,7 @@ func TestWorkspaceBuildLogs(t *testing.T) {
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
before := time.Now()
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Log{
@@ -150,9 +150,9 @@ func TestWorkspaceBuildLogs(t *testing.T) {
},
}},
})
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
ctx, cancelFunc := context.WithCancel(context.Background())
t.Cleanup(cancelFunc)
logs, err := client.WorkspaceBuildLogsAfter(ctx, workspace.LatestBuild.ID, before)
+8 -8
View File
@@ -24,7 +24,7 @@ func TestPostWorkspaceAuthAWSInstanceIdentity(t *testing.T) {
})
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
@@ -42,9 +42,9 @@ func TestPostWorkspaceAuthAWSInstanceIdentity(t *testing.T) {
},
}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
client.HTTPClient = metadataClient
@@ -90,7 +90,7 @@ func TestPostWorkspaceAuthGoogleInstanceIdentity(t *testing.T) {
})
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
@@ -108,9 +108,9 @@ func TestPostWorkspaceAuthGoogleInstanceIdentity(t *testing.T) {
},
}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
_, err := client.AuthWorkspaceGoogleInstanceIdentity(context.Background(), "", metadata)
+8 -8
View File
@@ -25,7 +25,7 @@ func TestWorkspaceResource(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Provision: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
@@ -42,9 +42,9 @@ func TestWorkspaceResource(t *testing.T) {
},
}},
})
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
resources, err := client.WorkspaceResourcesByBuild(context.Background(), workspace.LatestBuild.ID)
require.NoError(t, err)
@@ -59,7 +59,7 @@ func TestWorkspaceAgentListen(t *testing.T) {
user := coderdtest.CreateFirstUser(t, client)
daemonCloser := coderdtest.NewProvisionerDaemon(t, client)
authToken := uuid.NewString()
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionDryRun: echo.ProvisionComplete,
Provision: []*proto.Provision_Response{{
@@ -79,9 +79,9 @@ func TestWorkspaceAgentListen(t *testing.T) {
},
}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
daemonCloser.Close()
+42 -42
View File
@@ -37,14 +37,14 @@ func (api *api) workspace(rw http.ResponseWriter, r *http.Request) {
})
return
}
project, err := api.Database.GetProjectByID(r.Context(), workspace.ProjectID)
template, err := api.Database.GetTemplateByID(r.Context(), workspace.TemplateID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project: %s", err),
Message: fmt.Sprintf("get template: %s", err),
})
return
}
render.JSON(rw, r, convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), project))
render.JSON(rw, r, convertWorkspace(workspace, convertWorkspaceBuild(build, convertProvisionerJob(job)), template))
}
func (api *api) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
@@ -102,7 +102,7 @@ func (api *api) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
if !httpapi.Read(rw, r, &createBuild) {
return
}
if createBuild.ProjectVersionID == uuid.Nil {
if createBuild.TemplateVersionID == uuid.Nil {
latestBuild, err := api.Database.GetWorkspaceBuildByWorkspaceIDWithoutAfter(r.Context(), workspace.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
@@ -110,14 +110,14 @@ func (api *api) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
})
return
}
createBuild.ProjectVersionID = latestBuild.ProjectVersionID
createBuild.TemplateVersionID = latestBuild.TemplateVersionID
}
projectVersion, err := api.Database.GetProjectVersionByID(r.Context(), createBuild.ProjectVersionID)
templateVersion, err := api.Database.GetTemplateVersionByID(r.Context(), createBuild.TemplateVersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "project version not found",
Message: "template version not found",
Errors: []httpapi.Error{{
Field: "project_version_id",
Field: "template_version_id",
Code: "exists",
}},
})
@@ -125,40 +125,40 @@ func (api *api) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project version: %s", err),
Message: fmt.Sprintf("get template version: %s", err),
})
return
}
projectVersionJob, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.JobID)
templateVersionJob, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
})
return
}
projectVersionJobStatus := convertProvisionerJob(projectVersionJob).Status
switch projectVersionJobStatus {
templateVersionJobStatus := convertProvisionerJob(templateVersionJob).Status
switch templateVersionJobStatus {
case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning:
httpapi.Write(rw, http.StatusNotAcceptable, httpapi.Response{
Message: fmt.Sprintf("The provided project version is %s. Wait for it to complete importing!", projectVersionJobStatus),
Message: fmt.Sprintf("The provided template version is %s. Wait for it to complete importing!", templateVersionJobStatus),
})
return
case codersdk.ProvisionerJobFailed:
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: fmt.Sprintf("The provided project version %q has failed to import: %q. You cannot build workspaces with it!", projectVersion.Name, projectVersionJob.Error.String),
Message: fmt.Sprintf("The provided template version %q has failed to import: %q. You cannot build workspaces with it!", templateVersion.Name, templateVersionJob.Error.String),
})
return
case codersdk.ProvisionerJobCanceled:
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: "The provided project version was canceled during import. You cannot builds workspaces with it!",
Message: "The provided template version was canceled during import. You cannot builds workspaces with it!",
})
return
}
project, err := api.Database.GetProjectByID(r.Context(), projectVersion.ProjectID.UUID)
template, err := api.Database.GetTemplateByID(r.Context(), templateVersion.TemplateID.UUID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get project: %s", err),
Message: fmt.Sprintf("get template: %s", err),
})
return
}
@@ -203,28 +203,28 @@ func (api *api) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
InitiatorID: apiKey.UserID,
OrganizationID: project.OrganizationID,
Provisioner: project.Provisioner,
OrganizationID: template.OrganizationID,
Provisioner: template.Provisioner,
Type: database.ProvisionerJobTypeWorkspaceBuild,
StorageMethod: projectVersionJob.StorageMethod,
StorageSource: projectVersionJob.StorageSource,
StorageMethod: templateVersionJob.StorageMethod,
StorageSource: templateVersionJob.StorageSource,
Input: input,
})
if err != nil {
return xerrors.Errorf("insert provisioner job: %w", err)
}
workspaceBuild, err = db.InsertWorkspaceBuild(r.Context(), database.InsertWorkspaceBuildParams{
ID: workspaceBuildID,
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
WorkspaceID: workspace.ID,
ProjectVersionID: projectVersion.ID,
BeforeID: priorHistoryID,
Name: namesgenerator.GetRandomName(1),
ProvisionerState: priorHistory.ProvisionerState,
InitiatorID: apiKey.UserID,
Transition: createBuild.Transition,
JobID: provisionerJob.ID,
ID: workspaceBuildID,
CreatedAt: database.Now(),
UpdatedAt: database.Now(),
WorkspaceID: workspace.ID,
TemplateVersionID: templateVersion.ID,
BeforeID: priorHistoryID,
Name: namesgenerator.GetRandomName(1),
ProvisionerState: priorHistory.ProvisionerState,
InitiatorID: apiKey.UserID,
Transition: createBuild.Transition,
JobID: provisionerJob.ID,
})
if err != nil {
return xerrors.Errorf("insert workspace build: %w", err)
@@ -290,16 +290,16 @@ func (api *api) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) {
render.JSON(rw, r, convertWorkspaceBuild(workspaceBuild, convertProvisionerJob(job)))
}
func convertWorkspace(workspace database.Workspace, workspaceBuild codersdk.WorkspaceBuild, project database.Project) codersdk.Workspace {
func convertWorkspace(workspace database.Workspace, workspaceBuild codersdk.WorkspaceBuild, template database.Template) codersdk.Workspace {
return codersdk.Workspace{
ID: workspace.ID,
CreatedAt: workspace.CreatedAt,
UpdatedAt: workspace.UpdatedAt,
OwnerID: workspace.OwnerID,
ProjectID: workspace.ProjectID,
LatestBuild: workspaceBuild,
ProjectName: project.Name,
Outdated: workspaceBuild.ProjectVersionID.String() != project.ActiveVersionID.String(),
Name: workspace.Name,
ID: workspace.ID,
CreatedAt: workspace.CreatedAt,
UpdatedAt: workspace.UpdatedAt,
OwnerID: workspace.OwnerID,
TemplateID: workspace.TemplateID,
LatestBuild: workspaceBuild,
TemplateName: template.Name,
Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(),
Name: workspace.Name,
}
}
+45 -45
View File
@@ -20,10 +20,10 @@ func TestWorkspace(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.Workspace(context.Background(), workspace.ID)
require.NoError(t, err)
}
@@ -35,10 +35,10 @@ func TestWorkspaceBuilds(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.WorkspaceBuilds(context.Background(), workspace.ID)
require.NoError(t, err)
})
@@ -46,18 +46,18 @@ func TestWorkspaceBuilds(t *testing.T) {
func TestPostWorkspaceBuild(t *testing.T) {
t.Parallel()
t.Run("NoProjectVersion", func(t *testing.T) {
t.Run("NoTemplateVersion", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
coderdtest.NewProvisionerDaemon(t, client)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
ProjectVersionID: uuid.New(),
Transition: database.WorkspaceTransitionStart,
TemplateVersionID: uuid.New(),
Transition: database.WorkspaceTransitionStart,
})
require.Error(t, err)
var apiErr *codersdk.Error
@@ -65,19 +65,19 @@ func TestPostWorkspaceBuild(t *testing.T) {
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
})
t.Run("ProjectVersionFailedImport", func(t *testing.T) {
t.Run("TemplateVersionFailedImport", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, &echo.Responses{
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Provision: []*proto.Provision_Response{{}},
})
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
_, err := client.CreateWorkspace(context.Background(), codersdk.Me, codersdk.CreateWorkspaceRequest{
ProjectID: project.ID,
Name: "workspace",
TemplateID: template.ID,
Name: "workspace",
})
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
@@ -89,15 +89,15 @@ func TestPostWorkspaceBuild(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
closeDaemon := coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
// Close here so workspace build doesn't process!
closeDaemon.Close()
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
ProjectVersionID: project.ActiveVersionID,
Transition: database.WorkspaceTransitionStart,
TemplateVersionID: template.ActiveVersionID,
Transition: database.WorkspaceTransitionStart,
})
require.Error(t, err)
var apiErr *codersdk.Error
@@ -110,14 +110,14 @@ func TestPostWorkspaceBuild(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
build, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
ProjectVersionID: project.ActiveVersionID,
Transition: database.WorkspaceTransitionStart,
TemplateVersionID: template.ActiveVersionID,
Transition: database.WorkspaceTransitionStart,
})
require.NoError(t, err)
require.Equal(t, workspace.LatestBuild.ID.String(), build.BeforeID.String())
@@ -132,10 +132,10 @@ func TestPostWorkspaceBuild(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
build, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
Transition: database.WorkspaceTransitionDelete,
@@ -157,10 +157,10 @@ func TestWorkspaceBuildByName(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
_, err := client.WorkspaceBuildByName(context.Background(), workspace.ID, "something")
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
@@ -172,10 +172,10 @@ func TestWorkspaceBuildByName(t *testing.T) {
client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateProjectVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitProjectVersionJob(t, client, version.ID)
project := coderdtest.CreateProject(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, project.ID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
build, err := client.WorkspaceBuild(context.Background(), workspace.LatestBuild.ID)
require.NoError(t, err)
_, err = client.WorkspaceBuildByName(context.Background(), workspace.ID, build.Name)