diff --git a/coderd/templateversions.go b/coderd/templateversions.go index 8222a12295..c389d8098c 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -878,21 +878,39 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht // upload a copy of the template tar as a file in the database hashBytes := sha256.Sum256(tar) hash := hex.EncodeToString(hashBytes[:]) - file, err = api.Database.InsertFile(ctx, database.InsertFileParams{ - ID: uuid.New(), + // Check if the file already exists. + file, err := api.Database.GetFileByHashAndCreator(ctx, database.GetFileByHashAndCreatorParams{ Hash: hash, CreatedBy: apiKey.UserID, - CreatedAt: database.Now(), - Mimetype: tarMimeType, - Data: tar, }) if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error creating file.", - Detail: err.Error(), + if !errors.Is(err, sql.ErrNoRows) { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching file.", + Detail: err.Error(), + }) + return + } + + // If the example tar file doesn't exist, create it. + file, err = api.Database.InsertFile(ctx, database.InsertFileParams{ + ID: uuid.New(), + Hash: hash, + CreatedBy: apiKey.UserID, + CreatedAt: database.Now(), + Mimetype: tarMimeType, + Data: tar, }) - return + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error creating file.", + Detail: err.Error(), + }) + return + } } + + req.FileID = file.ID } if req.FileID != uuid.Nil { diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index 93d2566150..293a3d38d0 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -179,6 +179,15 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) { tar, err := examples.Archive(ls[0].ID) require.NoError(t, err) require.EqualValues(t, tar, fl) + + // ensure we don't get file conflicts on multiple uses of the same example + tv, err = client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{ + Name: "my-example", + StorageMethod: codersdk.ProvisionerStorageMethodFile, + ExampleID: ls[0].ID, + Provisioner: codersdk.ProvisionerTypeEcho, + }) + require.NoError(t, err) }) }