mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: track usage of built-in example templates (#15671)
Addresses https://github.com/coder/nexus/issues/99. Changes: - Save the id of the built-in example template used to create a template version in the database - Include the example id in telemetry
This commit is contained in:
@@ -788,16 +788,17 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers
|
||||
err := db.InTx(func(db database.Store) error {
|
||||
versionID := takeFirst(orig.ID, uuid.New())
|
||||
err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{
|
||||
ID: versionID,
|
||||
TemplateID: takeFirst(orig.TemplateID, uuid.NullUUID{}),
|
||||
OrganizationID: takeFirst(orig.OrganizationID, uuid.New()),
|
||||
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
|
||||
UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()),
|
||||
Name: takeFirst(orig.Name, testutil.GetRandomName(t)),
|
||||
Message: orig.Message,
|
||||
Readme: takeFirst(orig.Readme, testutil.GetRandomName(t)),
|
||||
JobID: takeFirst(orig.JobID, uuid.New()),
|
||||
CreatedBy: takeFirst(orig.CreatedBy, uuid.New()),
|
||||
ID: versionID,
|
||||
TemplateID: takeFirst(orig.TemplateID, uuid.NullUUID{}),
|
||||
OrganizationID: takeFirst(orig.OrganizationID, uuid.New()),
|
||||
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
|
||||
UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()),
|
||||
Name: takeFirst(orig.Name, testutil.GetRandomName(t)),
|
||||
Message: orig.Message,
|
||||
Readme: takeFirst(orig.Readme, testutil.GetRandomName(t)),
|
||||
JobID: takeFirst(orig.JobID, uuid.New()),
|
||||
CreatedBy: takeFirst(orig.CreatedBy, uuid.New()),
|
||||
SourceExampleID: takeFirst(orig.SourceExampleID, sql.NullString{}),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -7699,16 +7699,17 @@ func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.Inse
|
||||
|
||||
//nolint:gosimple
|
||||
version := database.TemplateVersionTable{
|
||||
ID: arg.ID,
|
||||
TemplateID: arg.TemplateID,
|
||||
OrganizationID: arg.OrganizationID,
|
||||
CreatedAt: arg.CreatedAt,
|
||||
UpdatedAt: arg.UpdatedAt,
|
||||
Name: arg.Name,
|
||||
Message: arg.Message,
|
||||
Readme: arg.Readme,
|
||||
JobID: arg.JobID,
|
||||
CreatedBy: arg.CreatedBy,
|
||||
ID: arg.ID,
|
||||
TemplateID: arg.TemplateID,
|
||||
OrganizationID: arg.OrganizationID,
|
||||
CreatedAt: arg.CreatedAt,
|
||||
UpdatedAt: arg.UpdatedAt,
|
||||
Name: arg.Name,
|
||||
Message: arg.Message,
|
||||
Readme: arg.Readme,
|
||||
JobID: arg.JobID,
|
||||
CreatedBy: arg.CreatedBy,
|
||||
SourceExampleID: arg.SourceExampleID,
|
||||
}
|
||||
q.templateVersions = append(q.templateVersions, version)
|
||||
return nil
|
||||
|
||||
Generated
+3
-1
@@ -1217,7 +1217,8 @@ CREATE TABLE template_versions (
|
||||
created_by uuid NOT NULL,
|
||||
external_auth_providers jsonb DEFAULT '[]'::jsonb NOT NULL,
|
||||
message character varying(1048576) DEFAULT ''::character varying NOT NULL,
|
||||
archived boolean DEFAULT false NOT NULL
|
||||
archived boolean DEFAULT false NOT NULL,
|
||||
source_example_id text
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN template_versions.external_auth_providers IS 'IDs of External auth providers for a specific template version';
|
||||
@@ -1245,6 +1246,7 @@ CREATE VIEW template_version_with_user AS
|
||||
template_versions.external_auth_providers,
|
||||
template_versions.message,
|
||||
template_versions.archived,
|
||||
template_versions.source_example_id,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username
|
||||
FROM (template_versions
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
-- We cannot alter the column type while a view depends on it, so we drop it and recreate it.
|
||||
DROP VIEW template_version_with_user;
|
||||
|
||||
ALTER TABLE
|
||||
template_versions
|
||||
DROP COLUMN source_example_id;
|
||||
|
||||
-- Recreate `template_version_with_user` as described in dump.sql
|
||||
CREATE VIEW template_version_with_user AS
|
||||
SELECT
|
||||
template_versions.id,
|
||||
template_versions.template_id,
|
||||
template_versions.organization_id,
|
||||
template_versions.created_at,
|
||||
template_versions.updated_at,
|
||||
template_versions.name,
|
||||
template_versions.readme,
|
||||
template_versions.job_id,
|
||||
template_versions.created_by,
|
||||
template_versions.external_auth_providers,
|
||||
template_versions.message,
|
||||
template_versions.archived,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username
|
||||
FROM (template_versions
|
||||
LEFT JOIN visible_users ON (template_versions.created_by = visible_users.id));
|
||||
|
||||
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
|
||||
@@ -0,0 +1,30 @@
|
||||
-- We cannot alter the column type while a view depends on it, so we drop it and recreate it.
|
||||
DROP VIEW template_version_with_user;
|
||||
|
||||
ALTER TABLE
|
||||
template_versions
|
||||
ADD
|
||||
COLUMN source_example_id TEXT;
|
||||
|
||||
-- Recreate `template_version_with_user` as described in dump.sql
|
||||
CREATE VIEW template_version_with_user AS
|
||||
SELECT
|
||||
template_versions.id,
|
||||
template_versions.template_id,
|
||||
template_versions.organization_id,
|
||||
template_versions.created_at,
|
||||
template_versions.updated_at,
|
||||
template_versions.name,
|
||||
template_versions.readme,
|
||||
template_versions.job_id,
|
||||
template_versions.created_by,
|
||||
template_versions.external_auth_providers,
|
||||
template_versions.message,
|
||||
template_versions.archived,
|
||||
template_versions.source_example_id,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username
|
||||
FROM (template_versions
|
||||
LEFT JOIN visible_users ON (template_versions.created_by = visible_users.id));
|
||||
|
||||
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
|
||||
@@ -2773,6 +2773,7 @@ type TemplateVersion struct {
|
||||
ExternalAuthProviders json.RawMessage `db:"external_auth_providers" json:"external_auth_providers"`
|
||||
Message string `db:"message" json:"message"`
|
||||
Archived bool `db:"archived" json:"archived"`
|
||||
SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"`
|
||||
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
||||
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
||||
}
|
||||
@@ -2826,8 +2827,9 @@ type TemplateVersionTable struct {
|
||||
// IDs of External auth providers for a specific template version
|
||||
ExternalAuthProviders json.RawMessage `db:"external_auth_providers" json:"external_auth_providers"`
|
||||
// Message describing the changes in this version of the template, similar to a Git commit message. Like a commit message, this should be a short, high-level description of the changes in this version of the template. This message is immutable and should not be updated after the fact.
|
||||
Message string `db:"message" json:"message"`
|
||||
Archived bool `db:"archived" json:"archived"`
|
||||
Message string `db:"message" json:"message"`
|
||||
Archived bool `db:"archived" json:"archived"`
|
||||
SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"`
|
||||
}
|
||||
|
||||
type TemplateVersionVariable struct {
|
||||
|
||||
@@ -8996,7 +8996,7 @@ FROM
|
||||
-- Scope an archive to a single template and ignore already archived template versions
|
||||
(
|
||||
SELECT
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id
|
||||
FROM
|
||||
template_versions
|
||||
WHERE
|
||||
@@ -9097,7 +9097,7 @@ func (q *sqlQuerier) ArchiveUnusedTemplateVersions(ctx context.Context, arg Arch
|
||||
|
||||
const getPreviousTemplateVersion = `-- name: GetPreviousTemplateVersion :one
|
||||
SELECT
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, created_by_avatar_url, created_by_username
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
template_version_with_user AS template_versions
|
||||
WHERE
|
||||
@@ -9134,6 +9134,7 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev
|
||||
&i.ExternalAuthProviders,
|
||||
&i.Message,
|
||||
&i.Archived,
|
||||
&i.SourceExampleID,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
@@ -9142,7 +9143,7 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev
|
||||
|
||||
const getTemplateVersionByID = `-- name: GetTemplateVersionByID :one
|
||||
SELECT
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, created_by_avatar_url, created_by_username
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
template_version_with_user AS template_versions
|
||||
WHERE
|
||||
@@ -9165,6 +9166,7 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (
|
||||
&i.ExternalAuthProviders,
|
||||
&i.Message,
|
||||
&i.Archived,
|
||||
&i.SourceExampleID,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
@@ -9173,7 +9175,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, readme, job_id, created_by, external_auth_providers, message, archived, created_by_avatar_url, created_by_username
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
template_version_with_user AS template_versions
|
||||
WHERE
|
||||
@@ -9196,6 +9198,7 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U
|
||||
&i.ExternalAuthProviders,
|
||||
&i.Message,
|
||||
&i.Archived,
|
||||
&i.SourceExampleID,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
@@ -9204,7 +9207,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, readme, job_id, created_by, external_auth_providers, message, archived, created_by_avatar_url, created_by_username
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
template_version_with_user AS template_versions
|
||||
WHERE
|
||||
@@ -9233,6 +9236,7 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context,
|
||||
&i.ExternalAuthProviders,
|
||||
&i.Message,
|
||||
&i.Archived,
|
||||
&i.SourceExampleID,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
@@ -9241,7 +9245,7 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context,
|
||||
|
||||
const getTemplateVersionsByIDs = `-- name: GetTemplateVersionsByIDs :many
|
||||
SELECT
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, created_by_avatar_url, created_by_username
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
template_version_with_user AS template_versions
|
||||
WHERE
|
||||
@@ -9270,6 +9274,7 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU
|
||||
&i.ExternalAuthProviders,
|
||||
&i.Message,
|
||||
&i.Archived,
|
||||
&i.SourceExampleID,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
@@ -9288,7 +9293,7 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU
|
||||
|
||||
const getTemplateVersionsByTemplateID = `-- name: GetTemplateVersionsByTemplateID :many
|
||||
SELECT
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, created_by_avatar_url, created_by_username
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, created_by_avatar_url, created_by_username
|
||||
FROM
|
||||
template_version_with_user AS template_versions
|
||||
WHERE
|
||||
@@ -9364,6 +9369,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge
|
||||
&i.ExternalAuthProviders,
|
||||
&i.Message,
|
||||
&i.Archived,
|
||||
&i.SourceExampleID,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
@@ -9381,7 +9387,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge
|
||||
}
|
||||
|
||||
const getTemplateVersionsCreatedAfter = `-- name: GetTemplateVersionsCreatedAfter :many
|
||||
SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, created_by_avatar_url, created_by_username FROM template_version_with_user AS template_versions WHERE created_at > $1
|
||||
SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, created_by_avatar_url, created_by_username FROM template_version_with_user AS template_versions WHERE created_at > $1
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error) {
|
||||
@@ -9406,6 +9412,7 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create
|
||||
&i.ExternalAuthProviders,
|
||||
&i.Message,
|
||||
&i.Archived,
|
||||
&i.SourceExampleID,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
@@ -9434,23 +9441,25 @@ INSERT INTO
|
||||
message,
|
||||
readme,
|
||||
job_id,
|
||||
created_by
|
||||
created_by,
|
||||
source_example_id
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
`
|
||||
|
||||
type InsertTemplateVersionParams 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"`
|
||||
Message string `db:"message" json:"message"`
|
||||
Readme string `db:"readme" json:"readme"`
|
||||
JobID uuid.UUID `db:"job_id" json:"job_id"`
|
||||
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
|
||||
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"`
|
||||
Message string `db:"message" json:"message"`
|
||||
Readme string `db:"readme" json:"readme"`
|
||||
JobID uuid.UUID `db:"job_id" json:"job_id"`
|
||||
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
|
||||
SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) error {
|
||||
@@ -9465,6 +9474,7 @@ func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTempla
|
||||
arg.Readme,
|
||||
arg.JobID,
|
||||
arg.CreatedBy,
|
||||
arg.SourceExampleID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -87,10 +87,11 @@ INSERT INTO
|
||||
message,
|
||||
readme,
|
||||
job_id,
|
||||
created_by
|
||||
created_by,
|
||||
source_example_id
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);
|
||||
|
||||
-- name: UpdateTemplateVersionByID :exec
|
||||
UPDATE
|
||||
|
||||
@@ -868,6 +868,9 @@ func ConvertTemplateVersion(version database.TemplateVersion) TemplateVersion {
|
||||
if version.TemplateID.Valid {
|
||||
snapVersion.TemplateID = &version.TemplateID.UUID
|
||||
}
|
||||
if version.SourceExampleID.Valid {
|
||||
snapVersion.SourceExampleID = &version.SourceExampleID.String
|
||||
}
|
||||
return snapVersion
|
||||
}
|
||||
|
||||
@@ -1116,11 +1119,12 @@ type Template struct {
|
||||
}
|
||||
|
||||
type TemplateVersion struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
TemplateID *uuid.UUID `json:"template_id,omitempty"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
JobID uuid.UUID `json:"job_id"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
TemplateID *uuid.UUID `json:"template_id,omitempty"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
JobID uuid.UUID `json:"job_id"`
|
||||
SourceExampleID *string `json:"source_example_id,omitempty"`
|
||||
}
|
||||
|
||||
type ProvisionerJob struct {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package telemetry_test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -48,6 +49,10 @@ func TestTelemetry(t *testing.T) {
|
||||
_ = dbgen.Template(t, db, database.Template{
|
||||
Provisioner: database.ProvisionerTypeTerraform,
|
||||
})
|
||||
sourceExampleID := uuid.NewString()
|
||||
_ = dbgen.TemplateVersion(t, db, database.TemplateVersion{
|
||||
SourceExampleID: sql.NullString{String: sourceExampleID, Valid: true},
|
||||
})
|
||||
_ = dbgen.TemplateVersion(t, db, database.TemplateVersion{})
|
||||
user := dbgen.User(t, db, database.User{})
|
||||
_ = dbgen.Workspace(t, db, database.WorkspaceTable{})
|
||||
@@ -93,7 +98,7 @@ func TestTelemetry(t *testing.T) {
|
||||
require.Len(t, snapshot.ProvisionerJobs, 1)
|
||||
require.Len(t, snapshot.Licenses, 1)
|
||||
require.Len(t, snapshot.Templates, 1)
|
||||
require.Len(t, snapshot.TemplateVersions, 1)
|
||||
require.Len(t, snapshot.TemplateVersions, 2)
|
||||
require.Len(t, snapshot.Users, 1)
|
||||
require.Len(t, snapshot.Groups, 2)
|
||||
// 1 member in the everyone group + 1 member in the custom group
|
||||
@@ -111,6 +116,17 @@ func TestTelemetry(t *testing.T) {
|
||||
require.Len(t, wsa.Subsystems, 2)
|
||||
require.Equal(t, string(database.WorkspaceAgentSubsystemEnvbox), wsa.Subsystems[0])
|
||||
require.Equal(t, string(database.WorkspaceAgentSubsystemExectrace), wsa.Subsystems[1])
|
||||
|
||||
tvs := snapshot.TemplateVersions
|
||||
sort.Slice(tvs, func(i, j int) bool {
|
||||
// Sort by SourceExampleID presence (non-nil comes before nil)
|
||||
if (tvs[i].SourceExampleID != nil) != (tvs[j].SourceExampleID != nil) {
|
||||
return tvs[i].SourceExampleID != nil
|
||||
}
|
||||
return false
|
||||
})
|
||||
require.Equal(t, tvs[0].SourceExampleID, &sourceExampleID)
|
||||
require.Nil(t, tvs[1].SourceExampleID)
|
||||
})
|
||||
t.Run("HashedEmail", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1582,6 +1582,10 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
|
||||
Readme: "",
|
||||
JobID: provisionerJob.ID,
|
||||
CreatedBy: apiKey.UserID,
|
||||
SourceExampleID: sql.NullString{
|
||||
String: req.ExampleID,
|
||||
Valid: req.ExampleID != "",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
if database.IsUniqueViolation(err, database.UniqueTemplateVersionsTemplateIDNameKey) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/audit"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
@@ -134,7 +135,7 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
|
||||
t.Run("WithParameters", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
auditor := audit.NewMock()
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
|
||||
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
data, err := echo.Tar(&echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
@@ -160,11 +161,17 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
|
||||
|
||||
require.Len(t, auditor.AuditLogs(), 2)
|
||||
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[1].Action)
|
||||
|
||||
admin, err := client.User(ctx, user.UserID.String())
|
||||
require.NoError(t, err)
|
||||
tvDB, err := db.GetTemplateVersionByID(dbauthz.As(ctx, coderdtest.AuthzUserSubject(admin, user.OrganizationID)), version.ID)
|
||||
require.NoError(t, err)
|
||||
require.False(t, tvDB.SourceExampleID.Valid)
|
||||
})
|
||||
|
||||
t.Run("Example", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
client, db := coderdtest.NewWithDatabase(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
@@ -205,6 +212,12 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "my-example", tv.Name)
|
||||
|
||||
admin, err := client.User(ctx, user.UserID.String())
|
||||
require.NoError(t, err)
|
||||
tvDB, err := db.GetTemplateVersionByID(dbauthz.As(ctx, coderdtest.AuthzUserSubject(admin, user.OrganizationID)), tv.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ls[0].ID, tvDB.SourceExampleID.String)
|
||||
|
||||
// ensure the template tar was uploaded correctly
|
||||
fl, ct, err := client.Download(ctx, tv.Job.FileID)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -24,7 +24,7 @@ We track the following resources:
|
||||
| OAuth2ProviderAppSecret<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>app_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>display_secret</td><td>false</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>secret_prefix</td><td>false</td></tr></tbody></table> |
|
||||
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>theme_preference</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
||||
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||
|
||||
@@ -127,6 +127,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||
"created_by_avatar_url": ActionIgnore,
|
||||
"created_by_username": ActionIgnore,
|
||||
"archived": ActionTrack,
|
||||
"source_example_id": ActionIgnore, // Never changes.
|
||||
},
|
||||
&database.User{}: {
|
||||
"id": ActionTrack,
|
||||
|
||||
Reference in New Issue
Block a user