diff --git a/.vscode/settings.json b/.vscode/settings.json index 6f7ea5c69fce3..a04dc17791f5f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -73,6 +73,10 @@ { "match": "database/queries/*.sql", "cmd": "make gen" + }, + { + "match": "provisionerd/proto/provisionerd.proto", + "cmd": "make provisionerd/proto/provisionerd.pb.go", } ] }, diff --git a/coderd/audit/table.go b/coderd/audit/table.go index 1556d9d3a3909..f7edadbcf21f2 100644 --- a/coderd/audit/table.go +++ b/coderd/audit/table.go @@ -78,7 +78,7 @@ var AuditableResources = auditMap(map[any]map[string]Action{ "created_at": ActionIgnore, // Never changes, but is implicit and not helpful in a diff. "updated_at": ActionIgnore, // Changes, but is implicit and not helpful in a diff. "name": ActionTrack, - "description": ActionTrack, + "readme": ActionTrack, "job_id": ActionIgnore, // Not helpful in a diff because jobs aren't tracked in audit logs. }, &database.User{}: { diff --git a/coderd/coderd.go b/coderd/coderd.go index 6bf4aa8920189..1f91e97ccd889 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -175,8 +175,8 @@ func New(options *Options) (http.Handler, func()) { r.Use( apiKeyMiddleware, httpmw.ExtractTemplateParam(options.Database), - httpmw.ExtractOrganizationParam(options.Database), ) + r.Get("/", api.template) r.Delete("/", api.deleteTemplate) r.Route("/versions", func(r chi.Router) { @@ -189,7 +189,6 @@ func New(options *Options) (http.Handler, func()) { r.Use( apiKeyMiddleware, httpmw.ExtractTemplateVersionParam(options.Database), - httpmw.ExtractOrganizationParam(options.Database), ) r.Get("/", api.templateVersion) diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 8455f522cc605..1e80910d97417 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -6,6 +6,7 @@ import ( "sort" "strings" "sync" + "time" "github.com/google/uuid" "golang.org/x/exp/slices" @@ -1189,7 +1190,7 @@ func (q *fakeQuerier) InsertTemplateVersion(_ context.Context, arg database.Inse CreatedAt: arg.CreatedAt, UpdatedAt: arg.UpdatedAt, Name: arg.Name, - Description: arg.Description, + Readme: arg.Readme, JobID: arg.JobID, } q.templateVersions = append(q.templateVersions, version) @@ -1478,7 +1479,7 @@ func (q *fakeQuerier) UpdateTemplateActiveVersionByID(_ context.Context, arg dat defer q.mutex.Unlock() for index, template := range q.templates { - if template.ID.String() != arg.ID.String() { + if template.ID != arg.ID { continue } template.ActiveVersionID = arg.ActiveVersionID @@ -1493,7 +1494,7 @@ func (q *fakeQuerier) UpdateTemplateDeletedByID(_ context.Context, arg database. defer q.mutex.Unlock() for index, template := range q.templates { - if template.ID.String() != arg.ID.String() { + if template.ID != arg.ID { continue } template.Deleted = arg.Deleted @@ -1508,7 +1509,7 @@ func (q *fakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database. defer q.mutex.Unlock() for index, templateVersion := range q.templateVersions { - if templateVersion.ID.String() != arg.ID.String() { + if templateVersion.ID != arg.ID { continue } templateVersion.TemplateID = arg.TemplateID @@ -1519,12 +1520,28 @@ func (q *fakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database. return sql.ErrNoRows } +func (q *fakeQuerier) UpdateTemplateVersionDescriptionByJobID(_ context.Context, arg database.UpdateTemplateVersionDescriptionByJobIDParams) error { + q.mutex.Lock() + defer q.mutex.Unlock() + + for index, templateVersion := range q.templateVersions { + if templateVersion.JobID != arg.JobID { + continue + } + templateVersion.Readme = arg.Readme + templateVersion.UpdatedAt = time.Now() + q.templateVersions[index] = templateVersion + return nil + } + return sql.ErrNoRows +} + func (q *fakeQuerier) UpdateProvisionerDaemonByID(_ context.Context, arg database.UpdateProvisionerDaemonByIDParams) error { q.mutex.Lock() defer q.mutex.Unlock() for index, daemon := range q.provisionerDaemons { - if arg.ID.String() != daemon.ID.String() { + if arg.ID != daemon.ID { continue } daemon.UpdatedAt = arg.UpdatedAt @@ -1540,7 +1557,7 @@ func (q *fakeQuerier) UpdateWorkspaceAgentConnectionByID(_ context.Context, arg defer q.mutex.Unlock() for index, agent := range q.provisionerJobAgents { - if agent.ID.String() != arg.ID.String() { + if agent.ID != arg.ID { continue } agent.FirstConnectedAt = arg.FirstConnectedAt @@ -1557,7 +1574,7 @@ func (q *fakeQuerier) UpdateProvisionerJobByID(_ context.Context, arg database.U defer q.mutex.Unlock() for index, job := range q.provisionerJobs { - if arg.ID.String() != job.ID.String() { + if arg.ID != job.ID { continue } job.UpdatedAt = arg.UpdatedAt @@ -1572,7 +1589,7 @@ func (q *fakeQuerier) UpdateProvisionerJobWithCancelByID(_ context.Context, arg defer q.mutex.Unlock() for index, job := range q.provisionerJobs { - if arg.ID.String() != job.ID.String() { + if arg.ID != job.ID { continue } job.CanceledAt = arg.CanceledAt @@ -1587,7 +1604,7 @@ func (q *fakeQuerier) UpdateProvisionerJobWithCompleteByID(_ context.Context, ar defer q.mutex.Unlock() for index, job := range q.provisionerJobs { - if arg.ID.String() != job.ID.String() { + if arg.ID != job.ID { continue } job.UpdatedAt = arg.UpdatedAt @@ -1604,7 +1621,7 @@ func (q *fakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.U defer q.mutex.Unlock() for index, workspace := range q.workspaces { - if workspace.ID.String() != arg.ID.String() { + if workspace.ID != arg.ID { continue } workspace.AutostartSchedule = arg.AutostartSchedule @@ -1620,7 +1637,7 @@ func (q *fakeQuerier) UpdateWorkspaceAutostop(_ context.Context, arg database.Up defer q.mutex.Unlock() for index, workspace := range q.workspaces { - if workspace.ID.String() != arg.ID.String() { + if workspace.ID != arg.ID { continue } workspace.AutostopSchedule = arg.AutostopSchedule @@ -1636,7 +1653,7 @@ func (q *fakeQuerier) UpdateWorkspaceBuildByID(_ context.Context, arg database.U defer q.mutex.Unlock() for index, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.ID.String() != arg.ID.String() { + if workspaceBuild.ID != arg.ID { continue } workspaceBuild.UpdatedAt = arg.UpdatedAt @@ -1653,7 +1670,7 @@ func (q *fakeQuerier) UpdateWorkspaceDeletedByID(_ context.Context, arg database defer q.mutex.Unlock() for index, workspace := range q.workspaces { - if workspace.ID.String() != arg.ID.String() { + if workspace.ID != arg.ID { continue } workspace.Deleted = arg.Deleted diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 89ca22acab100..b69ca30566da3 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -234,7 +234,7 @@ CREATE TABLE template_versions ( 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, + readme character varying(1048576) NOT NULL, job_id uuid NOT NULL ); diff --git a/coderd/database/migrations/000012_template_version_readme.down.sql b/coderd/database/migrations/000012_template_version_readme.down.sql new file mode 100644 index 0000000000000..9f090f164993b --- /dev/null +++ b/coderd/database/migrations/000012_template_version_readme.down.sql @@ -0,0 +1 @@ +ALTER TABLE template_versions RENAME README TO description; diff --git a/coderd/database/migrations/000012_template_version_readme.up.sql b/coderd/database/migrations/000012_template_version_readme.up.sql new file mode 100644 index 0000000000000..684b3b90a715e --- /dev/null +++ b/coderd/database/migrations/000012_template_version_readme.up.sql @@ -0,0 +1 @@ +ALTER TABLE template_versions RENAME description TO readme; diff --git a/coderd/database/models.go b/coderd/database/models.go index 1fc101a16ee1a..6ac61e6da14b5 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -446,7 +446,7 @@ type TemplateVersion struct { 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"` + Readme string `db:"readme" json:"readme"` JobID uuid.UUID `db:"job_id" json:"job_id"` } diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 9787aca37e017..faff010d11759 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -103,6 +103,7 @@ type querier interface { UpdateTemplateActiveVersionByID(ctx context.Context, arg UpdateTemplateActiveVersionByIDParams) error UpdateTemplateDeletedByID(ctx context.Context, arg UpdateTemplateDeletedByIDParams) error UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) error + UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg UpdateTemplateVersionDescriptionByJobIDParams) error UpdateUserHashedPassword(ctx context.Context, arg UpdateUserHashedPasswordParams) error UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) (User, error) UpdateUserRoles(ctx context.Context, arg UpdateUserRolesParams) (User, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index d4abbefd040f5..de4ac465660dc 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1830,7 +1830,7 @@ func (q *sqlQuerier) UpdateTemplateDeletedByID(ctx context.Context, arg UpdateTe const getTemplateVersionByID = `-- name: GetTemplateVersionByID :one SELECT - id, template_id, organization_id, created_at, updated_at, name, description, job_id + id, template_id, organization_id, created_at, updated_at, name, readme, job_id FROM template_versions WHERE @@ -1847,7 +1847,7 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) ( &i.CreatedAt, &i.UpdatedAt, &i.Name, - &i.Description, + &i.Readme, &i.JobID, ) return i, err @@ -1855,7 +1855,7 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) ( const getTemplateVersionByJobID = `-- name: GetTemplateVersionByJobID :one SELECT - id, template_id, organization_id, created_at, updated_at, name, description, job_id + id, template_id, organization_id, created_at, updated_at, name, readme, job_id FROM template_versions WHERE @@ -1872,7 +1872,7 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U &i.CreatedAt, &i.UpdatedAt, &i.Name, - &i.Description, + &i.Readme, &i.JobID, ) return i, err @@ -1880,7 +1880,7 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U const getTemplateVersionByTemplateIDAndName = `-- name: GetTemplateVersionByTemplateIDAndName :one SELECT - id, template_id, organization_id, created_at, updated_at, name, description, job_id + id, template_id, organization_id, created_at, updated_at, name, readme, job_id FROM template_versions WHERE @@ -1903,7 +1903,7 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context, &i.CreatedAt, &i.UpdatedAt, &i.Name, - &i.Description, + &i.Readme, &i.JobID, ) return i, err @@ -1911,7 +1911,7 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context, const getTemplateVersionsByTemplateID = `-- name: GetTemplateVersionsByTemplateID :many SELECT - id, template_id, organization_id, created_at, updated_at, name, description, job_id + id, template_id, organization_id, created_at, updated_at, name, readme, job_id FROM template_versions WHERE @@ -1972,7 +1972,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge &i.CreatedAt, &i.UpdatedAt, &i.Name, - &i.Description, + &i.Readme, &i.JobID, ); err != nil { return nil, err @@ -1997,11 +1997,11 @@ INSERT INTO created_at, updated_at, "name", - description, + readme, job_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id, template_id, organization_id, created_at, updated_at, name, description, job_id + ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id, template_id, organization_id, created_at, updated_at, name, readme, job_id ` type InsertTemplateVersionParams struct { @@ -2011,7 +2011,7 @@ type InsertTemplateVersionParams struct { 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"` + Readme string `db:"readme" json:"readme"` JobID uuid.UUID `db:"job_id" json:"job_id"` } @@ -2023,7 +2023,7 @@ func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTempla arg.CreatedAt, arg.UpdatedAt, arg.Name, - arg.Description, + arg.Readme, arg.JobID, ) var i TemplateVersion @@ -2034,7 +2034,7 @@ func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTempla &i.CreatedAt, &i.UpdatedAt, &i.Name, - &i.Description, + &i.Readme, &i.JobID, ) return i, err @@ -2061,6 +2061,26 @@ func (q *sqlQuerier) UpdateTemplateVersionByID(ctx context.Context, arg UpdateTe return err } +const updateTemplateVersionDescriptionByJobID = `-- name: UpdateTemplateVersionDescriptionByJobID :exec +UPDATE + template_versions +SET + readme = $2, + updated_at = now() +WHERE + job_id = $1 +` + +type UpdateTemplateVersionDescriptionByJobIDParams struct { + JobID uuid.UUID `db:"job_id" json:"job_id"` + Readme string `db:"readme" json:"readme"` +} + +func (q *sqlQuerier) UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg UpdateTemplateVersionDescriptionByJobIDParams) error { + _, err := q.db.ExecContext(ctx, updateTemplateVersionDescriptionByJobID, arg.JobID, arg.Readme) + return err +} + const getAllUserRoles = `-- name: GetAllUserRoles :one SELECT -- username is returned just to help for logging purposes diff --git a/coderd/database/queries/templateversions.sql b/coderd/database/queries/templateversions.sql index b6a3550d5f2bd..148c8856deeb0 100644 --- a/coderd/database/queries/templateversions.sql +++ b/coderd/database/queries/templateversions.sql @@ -66,7 +66,7 @@ INSERT INTO created_at, updated_at, "name", - description, + readme, job_id ) VALUES @@ -80,3 +80,12 @@ SET updated_at = $3 WHERE id = $1; + +-- name: UpdateTemplateVersionDescriptionByJobID :exec +UPDATE + template_versions +SET + readme = $2, + updated_at = now() +WHERE + job_id = $1; diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 9a27fbe6e4857..5cdebc1c942f2 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -348,6 +348,16 @@ func (server *provisionerdServer) UpdateJob(ctx context.Context, request *proto. } } + if len(request.Readme) > 0 { + err := server.Database.UpdateTemplateVersionDescriptionByJobID(ctx, database.UpdateTemplateVersionDescriptionByJobIDParams{ + JobID: job.ID, + Readme: string(request.Readme), + }) + if err != nil { + return nil, xerrors.Errorf("update template version description: %w", err) + } + } + if len(request.ParameterSchemas) > 0 { for _, protoParameter := range request.ParameterSchemas { validationTypeSystem, err := convertValidationTypeSystem(protoParameter.ValidationTypeSystem) diff --git a/coderd/templateversions.go b/coderd/templateversions.go index 99c6c62383811..f1d70cb4c9b97 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -357,7 +357,7 @@ func (api *api) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht CreatedAt: database.Now(), UpdatedAt: database.Now(), Name: namesgenerator.GetRandomName(1), - Description: "", + Readme: "", JobID: provisionerJob.ID, }) if err != nil { @@ -407,5 +407,6 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi UpdatedAt: version.UpdatedAt, Name: version.Name, Job: job, + Readme: version.Readme, } } diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index d2a7baeab560d..c7843b4a3d17e 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -216,7 +216,7 @@ func (api *api) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) { if err != nil { return err } - if build.ID.String() != latestBuild.ID.String() { + if build.ID != latestBuild.ID { return xerrors.New("build is outdated") } return nil diff --git a/coderd/workspaceresourceauth.go b/coderd/workspaceresourceauth.go index f9d8f701f8daf..a2784b9553438 100644 --- a/coderd/workspaceresourceauth.go +++ b/coderd/workspaceresourceauth.go @@ -144,7 +144,7 @@ func (api *api) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, in }) return } - if latestHistory.ID.String() != resourceHistory.ID.String() { + if latestHistory.ID != resourceHistory.ID { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ Message: fmt.Sprintf("resource found for id %q, but isn't registered on the latest history", instanceID), }) diff --git a/codersdk/templateversions.go b/codersdk/templateversions.go index 3b8b2e21711d4..64e3934c8732a 100644 --- a/codersdk/templateversions.go +++ b/codersdk/templateversions.go @@ -21,6 +21,7 @@ type TemplateVersion struct { UpdatedAt time.Time `json:"updated_at"` Name string `json:"name"` Job ProvisionerJob `json:"job"` + Readme string `json:"readme"` } // TemplateVersionParameterSchema represents a parameter parsed from template version source. diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index 56428d6a3c0a0..6a9ecab23dee3 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -9,7 +9,6 @@ import ( "path/filepath" "golang.org/x/xerrors" - protobuf "google.golang.org/protobuf/proto" "github.com/coder/coder/provisionersdk" diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index b9cfade26b8da..aec1bfe147bbb 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.20.0 +// protoc v3.19.4 // source: provisionerd/proto/provisionerd.proto package proto @@ -502,6 +502,7 @@ type UpdateJobRequest struct { JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` Logs []*Log `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs,omitempty"` ParameterSchemas []*proto.ParameterSchema `protobuf:"bytes,3,rep,name=parameter_schemas,json=parameterSchemas,proto3" json:"parameter_schemas,omitempty"` + Readme []byte `protobuf:"bytes,4,opt,name=readme,proto3" json:"readme,omitempty"` } func (x *UpdateJobRequest) Reset() { @@ -557,6 +558,13 @@ func (x *UpdateJobRequest) GetParameterSchemas() []*proto.ParameterSchema { return nil } +func (x *UpdateJobRequest) GetReadme() []byte { + if x != nil { + return x.Readme + } + return nil +} + type UpdateJobResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1046,7 +1054,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, + 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0xb3, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, @@ -1056,39 +1064,40 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x73, 0x22, 0x77, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, - 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2a, 0x34, - 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, - 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, 0x4d, 0x4f, - 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, - 0x45, 0x52, 0x10, 0x01, 0x32, 0x98, 0x02, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0a, 0x41, 0x63, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x4a, 0x6f, - 0x62, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, - 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x68, 0x65, 0x6d, 0x61, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x22, 0x77, 0x0a, + 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x46, + 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, + 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, + 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, 0x32, 0x98, 0x02, 0x0a, + 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, + 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0a, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, + 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, + 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, + 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, + 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, + 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index c59d977a16990..b1808c5443e55 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -83,6 +83,7 @@ message UpdateJobRequest { string job_id = 1; repeated Log logs = 2; repeated provisioner.ParameterSchema parameter_schemas = 3; + bytes readme = 4; } message UpdateJobResponse { diff --git a/provisionerd/provisionerd.go b/provisionerd/provisionerd.go index c06a3365da55c..28475455182ed 100644 --- a/provisionerd/provisionerd.go +++ b/provisionerd/provisionerd.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "os" + "path" "path/filepath" "reflect" "strings" @@ -361,8 +362,8 @@ func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) { return } // #nosec - path := filepath.Join(p.opts.WorkDirectory, header.Name) - if !strings.HasPrefix(path, filepath.Clean(p.opts.WorkDirectory)) { + headerPath := filepath.Join(p.opts.WorkDirectory, header.Name) + if !strings.HasPrefix(headerPath, filepath.Clean(p.opts.WorkDirectory)) { p.failActiveJobf("tar attempts to target relative upper directory") return } @@ -372,36 +373,36 @@ func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) { } switch header.Typeflag { case tar.TypeDir: - err = os.MkdirAll(path, mode) + err = os.MkdirAll(headerPath, mode) if err != nil { - p.failActiveJobf("mkdir %q: %s", path, err) + p.failActiveJobf("mkdir %q: %s", headerPath, err) return } - p.opts.Logger.Debug(context.Background(), "extracted directory", slog.F("path", path)) + p.opts.Logger.Debug(context.Background(), "extracted directory", slog.F("path", headerPath)) case tar.TypeReg: - file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, mode) + file, err := os.OpenFile(headerPath, os.O_CREATE|os.O_RDWR, mode) if err != nil { - p.failActiveJobf("create file %q (mode %s): %s", path, mode, err) + p.failActiveJobf("create file %q (mode %s): %s", headerPath, mode, err) return } - // Max file size of 10MB. - size, err := io.CopyN(file, reader, (1<<20)*10) + // Max file size of 10MiB. + size, err := io.CopyN(file, reader, 10<<20) if errors.Is(err, io.EOF) { err = nil } if err != nil { _ = file.Close() - p.failActiveJobf("copy file %q: %s", path, err) + p.failActiveJobf("copy file %q: %s", headerPath, err) return } err = file.Close() if err != nil { - p.failActiveJobf("close file %q: %s", path, err) + p.failActiveJobf("close file %q: %s", headerPath, err) return } p.opts.Logger.Debug(context.Background(), "extracted file", slog.F("size_bytes", size), - slog.F("path", path), + slog.F("path", headerPath), slog.F("mode", mode), ) } @@ -411,6 +412,7 @@ func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) { case *proto.AcquiredJob_TemplateImport_: p.opts.Logger.Debug(context.Background(), "acquired job is template import") + p.runReadmeParse(ctx, job) p.runTemplateImport(ctx, shutdown, provisioner, job) case *proto.AcquiredJob_WorkspaceBuild_: p.opts.Logger.Debug(context.Background(), "acquired job is workspace provision", @@ -450,6 +452,51 @@ func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) { } } +// ReadmeFile is the location we look for to extract documentation from template +// versions. +const ReadmeFile = "README.md" + +func (p *Server) runReadmeParse(ctx context.Context, job *proto.AcquiredJob) { + client, ok := p.client() + if !ok { + p.failActiveJobf("client disconnected") + return + } + + fi, err := os.ReadFile(path.Join(p.opts.WorkDirectory, ReadmeFile)) + if err != nil { + _, err := client.UpdateJob(ctx, &proto.UpdateJobRequest{ + JobId: job.GetJobId(), + Logs: []*proto.Log{{ + Source: proto.LogSource_PROVISIONER_DAEMON, + Level: sdkproto.LogLevel_DEBUG, + Stage: "No README.md provided", + CreatedAt: time.Now().UTC().UnixMilli(), + }}, + }) + if err != nil { + p.failActiveJobf("write log: %s", err) + } + + return + } + + _, err = client.UpdateJob(ctx, &proto.UpdateJobRequest{ + JobId: job.GetJobId(), + Logs: []*proto.Log{{ + Source: proto.LogSource_PROVISIONER_DAEMON, + Level: sdkproto.LogLevel_INFO, + Stage: "Adding README.md...", + CreatedAt: time.Now().UTC().UnixMilli(), + }}, + Readme: fi, + }) + if err != nil { + p.failActiveJobf("write log: %s", err) + return + } +} + func (p *Server) runTemplateImport(ctx, shutdown context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob) { client, ok := p.client() if !ok { diff --git a/provisionerd/provisionerd_test.go b/provisionerd/provisionerd_test.go index c4b82472e0ef5..0b12720ce68d0 100644 --- a/provisionerd/provisionerd_test.go +++ b/provisionerd/provisionerd_test.go @@ -214,6 +214,7 @@ func TestProvisionerd(t *testing.T) { didLog atomic.Bool didAcquireJob atomic.Bool didDryRun atomic.Bool + didReadme atomic.Bool completeChan = make(chan struct{}) completeOnce sync.Once ) @@ -230,7 +231,8 @@ func TestProvisionerd(t *testing.T) { JobId: "test", Provisioner: "someprovisioner", TemplateSourceArchive: createTar(t, map[string]string{ - "test.txt": "content", + "test.txt": "content", + provisionerd.ReadmeFile: "# A cool template 😎\n", }), Type: &proto.AcquiredJob_TemplateImport_{ TemplateImport: &proto.AcquiredJob_TemplateImport{ @@ -240,9 +242,12 @@ func TestProvisionerd(t *testing.T) { }, nil }, updateJob: func(ctx context.Context, update *proto.UpdateJobRequest) (*proto.UpdateJobResponse, error) { - if len(update.Logs) != 0 { + if len(update.Logs) > 0 { didLog.Store(true) } + if len(update.Readme) > 0 { + didReadme.Store(true) + } return &proto.UpdateJobResponse{}, nil }, completeJob: func(ctx context.Context, job *proto.CompletedJob) (*proto.Empty, error) { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index da8c18eee2d2c..6f35a5236e187 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -231,9 +231,10 @@ export interface TemplateVersion { readonly updated_at: string readonly name: string readonly job: ProvisionerJob + readonly readme: string } -// From codersdk/templateversions.go:30:6 +// From codersdk/templateversions.go:31:6 export interface TemplateVersionParameter { // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -242,7 +243,7 @@ export interface TemplateVersionParameter { readonly default_source_value: boolean } -// From codersdk/templateversions.go:27:6 +// From codersdk/templateversions.go:28:6 export interface TemplateVersionParameterSchema { readonly id: string readonly created_at: string