mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: workspace builds (#7541)
* refactor workspace builds Signed-off-by: Spike Curtis <spike@coder.com> * make gen Signed-off-by: Spike Curtis <spike@coder.com> * Remove ParameterResolver from typescript Signed-off-by: Spike Curtis <spike@coder.com> * rename conversion -> database/db2sdk Signed-off-by: Spike Curtis <spike@coder.com> * tests for db2sdk Signed-off-by: Spike Curtis <spike@coder.com> * Tests for ParameterResolver Signed-off-by: Spike Curtis <spike@coder.com> * wsbuilder tests Signed-off-by: Spike Curtis <spike@coder.com> * Move parameter validation tests to richparameters_test.go Signed-off-by: Spike Curtis <spike@coder.com> * Fix CI generation; rename mock->dbmock Signed-off-by: Spike Curtis <spike@coder.com> * Fix test imports Signed-off-by: Spike Curtis <spike@coder.com> --------- Signed-off-by: Spike Curtis <spike@coder.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
// Package db2sdk provides common conversion routines from database types to codersdk types
|
||||
package db2sdk
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/parameter"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/provisionersdk/proto"
|
||||
)
|
||||
|
||||
func WorkspaceBuildParameters(params []database.WorkspaceBuildParameter) []codersdk.WorkspaceBuildParameter {
|
||||
out := make([]codersdk.WorkspaceBuildParameter, len(params))
|
||||
for i, p := range params {
|
||||
out[i] = WorkspaceBuildParameter(p)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func WorkspaceBuildParameter(p database.WorkspaceBuildParameter) codersdk.WorkspaceBuildParameter {
|
||||
return codersdk.WorkspaceBuildParameter{
|
||||
Name: p.Name,
|
||||
Value: p.Value,
|
||||
}
|
||||
}
|
||||
|
||||
func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk.TemplateVersionParameter, error) {
|
||||
var protoOptions []*proto.RichParameterOption
|
||||
err := json.Unmarshal(param.Options, &protoOptions)
|
||||
if err != nil {
|
||||
return codersdk.TemplateVersionParameter{}, err
|
||||
}
|
||||
options := make([]codersdk.TemplateVersionParameterOption, 0)
|
||||
for _, option := range protoOptions {
|
||||
options = append(options, codersdk.TemplateVersionParameterOption{
|
||||
Name: option.Name,
|
||||
Description: option.Description,
|
||||
Value: option.Value,
|
||||
Icon: option.Icon,
|
||||
})
|
||||
}
|
||||
|
||||
descriptionPlaintext, err := parameter.Plaintext(param.Description)
|
||||
if err != nil {
|
||||
return codersdk.TemplateVersionParameter{}, err
|
||||
}
|
||||
return codersdk.TemplateVersionParameter{
|
||||
Name: param.Name,
|
||||
DisplayName: param.DisplayName,
|
||||
Description: param.Description,
|
||||
DescriptionPlaintext: descriptionPlaintext,
|
||||
Type: param.Type,
|
||||
Mutable: param.Mutable,
|
||||
DefaultValue: param.DefaultValue,
|
||||
Icon: param.Icon,
|
||||
Options: options,
|
||||
ValidationRegex: param.ValidationRegex,
|
||||
ValidationMin: param.ValidationMin,
|
||||
ValidationMax: param.ValidationMax,
|
||||
ValidationError: param.ValidationError,
|
||||
ValidationMonotonic: codersdk.ValidationMonotonicOrder(param.ValidationMonotonic),
|
||||
Required: param.Required,
|
||||
LegacyVariableName: param.LegacyVariableName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func Parameters(params []database.ParameterValue) []codersdk.Parameter {
|
||||
out := make([]codersdk.Parameter, len(params))
|
||||
for i, p := range params {
|
||||
out[i] = Parameter(p)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func Parameter(parameterValue database.ParameterValue) codersdk.Parameter {
|
||||
return codersdk.Parameter{
|
||||
ID: parameterValue.ID,
|
||||
CreatedAt: parameterValue.CreatedAt,
|
||||
UpdatedAt: parameterValue.UpdatedAt,
|
||||
Scope: codersdk.ParameterScope(parameterValue.Scope),
|
||||
ScopeID: parameterValue.ScopeID,
|
||||
Name: parameterValue.Name,
|
||||
SourceScheme: codersdk.ParameterSourceScheme(parameterValue.SourceScheme),
|
||||
DestinationScheme: codersdk.ParameterDestinationScheme(parameterValue.DestinationScheme),
|
||||
SourceValue: parameterValue.SourceValue,
|
||||
}
|
||||
}
|
||||
|
||||
func ProvisionerJobStatus(provisionerJob database.ProvisionerJob) codersdk.ProvisionerJobStatus {
|
||||
switch {
|
||||
case provisionerJob.CanceledAt.Valid:
|
||||
if !provisionerJob.CompletedAt.Valid {
|
||||
return codersdk.ProvisionerJobCanceling
|
||||
}
|
||||
if provisionerJob.Error.String == "" {
|
||||
return codersdk.ProvisionerJobCanceled
|
||||
}
|
||||
return codersdk.ProvisionerJobFailed
|
||||
case !provisionerJob.StartedAt.Valid:
|
||||
return codersdk.ProvisionerJobPending
|
||||
case provisionerJob.CompletedAt.Valid:
|
||||
if provisionerJob.Error.String == "" {
|
||||
return codersdk.ProvisionerJobSucceeded
|
||||
}
|
||||
return codersdk.ProvisionerJobFailed
|
||||
case database.Now().Sub(provisionerJob.UpdatedAt) > 30*time.Second:
|
||||
return codersdk.ProvisionerJobFailed
|
||||
default:
|
||||
return codersdk.ProvisionerJobRunning
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package db2sdk_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/database/db2sdk"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/provisionersdk/proto"
|
||||
)
|
||||
|
||||
func TestProvisionerJobStatus(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
job database.ProvisionerJob
|
||||
status codersdk.ProvisionerJobStatus
|
||||
}{
|
||||
{
|
||||
name: "canceling",
|
||||
job: database.ProvisionerJob{
|
||||
CanceledAt: sql.NullTime{
|
||||
Time: database.Now().Add(-time.Minute),
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
status: codersdk.ProvisionerJobCanceling,
|
||||
},
|
||||
{
|
||||
name: "canceled",
|
||||
job: database.ProvisionerJob{
|
||||
CanceledAt: sql.NullTime{
|
||||
Time: database.Now().Add(-time.Minute),
|
||||
Valid: true,
|
||||
},
|
||||
CompletedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-30 * time.Second),
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
status: codersdk.ProvisionerJobCanceled,
|
||||
},
|
||||
{
|
||||
name: "canceled_failed",
|
||||
job: database.ProvisionerJob{
|
||||
CanceledAt: sql.NullTime{
|
||||
Time: database.Now().Add(-time.Minute),
|
||||
Valid: true,
|
||||
},
|
||||
CompletedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-30 * time.Second),
|
||||
Valid: true,
|
||||
},
|
||||
Error: sql.NullString{String: "badness", Valid: true},
|
||||
},
|
||||
status: codersdk.ProvisionerJobFailed,
|
||||
},
|
||||
{
|
||||
name: "pending",
|
||||
job: database.ProvisionerJob{},
|
||||
status: codersdk.ProvisionerJobPending,
|
||||
},
|
||||
{
|
||||
name: "succeeded",
|
||||
job: database.ProvisionerJob{
|
||||
StartedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-time.Minute),
|
||||
Valid: true,
|
||||
},
|
||||
CompletedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-30 * time.Second),
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
status: codersdk.ProvisionerJobSucceeded,
|
||||
},
|
||||
{
|
||||
name: "completed_failed",
|
||||
job: database.ProvisionerJob{
|
||||
StartedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-time.Minute),
|
||||
Valid: true,
|
||||
},
|
||||
CompletedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-30 * time.Second),
|
||||
Valid: true,
|
||||
},
|
||||
Error: sql.NullString{String: "badness", Valid: true},
|
||||
},
|
||||
status: codersdk.ProvisionerJobFailed,
|
||||
},
|
||||
{
|
||||
name: "not_updated",
|
||||
job: database.ProvisionerJob{
|
||||
StartedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-time.Minute),
|
||||
Valid: true,
|
||||
},
|
||||
UpdatedAt: database.Now().Add(-31 * time.Second),
|
||||
},
|
||||
status: codersdk.ProvisionerJobFailed,
|
||||
},
|
||||
{
|
||||
name: "updated",
|
||||
job: database.ProvisionerJob{
|
||||
StartedAt: sql.NullTime{
|
||||
Time: database.Now().Add(-time.Minute),
|
||||
Valid: true,
|
||||
},
|
||||
UpdatedAt: database.Now(),
|
||||
},
|
||||
status: codersdk.ProvisionerJobRunning,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
actual := db2sdk.ProvisionerJobStatus(tc.job)
|
||||
require.Equal(t, tc.status, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateVersionParameter_OK(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := require.New(t)
|
||||
|
||||
// In this test we're just going to cover the fields that have to get parsed.
|
||||
options := []*proto.RichParameterOption{
|
||||
{
|
||||
Name: "foo",
|
||||
Description: "bar",
|
||||
Value: "baz",
|
||||
Icon: "David Bowie",
|
||||
},
|
||||
}
|
||||
ob, err := json.Marshal(&options)
|
||||
req.NoError(err)
|
||||
|
||||
db := database.TemplateVersionParameter{
|
||||
Options: json.RawMessage(ob),
|
||||
Description: "_The Rise and Fall of **Ziggy Stardust** and the Spiders from Mars_",
|
||||
}
|
||||
sdk, err := db2sdk.TemplateVersionParameter(db)
|
||||
req.NoError(err)
|
||||
req.Len(sdk.Options, 1)
|
||||
req.Equal("foo", sdk.Options[0].Name)
|
||||
req.Equal("bar", sdk.Options[0].Description)
|
||||
req.Equal("baz", sdk.Options[0].Value)
|
||||
req.Equal("David Bowie", sdk.Options[0].Icon)
|
||||
req.Equal("The Rise and Fall of Ziggy Stardust and the Spiders from Mars", sdk.DescriptionPlaintext)
|
||||
}
|
||||
|
||||
func TestTemplateVersionParameter_BadOptions(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := require.New(t)
|
||||
|
||||
db := database.TemplateVersionParameter{
|
||||
Options: json.RawMessage("not really JSON!"),
|
||||
Description: "_The Rise and Fall of **Ziggy Stardust** and the Spiders from Mars_",
|
||||
}
|
||||
_, err := db2sdk.TemplateVersionParameter(db)
|
||||
req.Error(err)
|
||||
}
|
||||
|
||||
func TestTemplateVersionParameter_BadDescription(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := require.New(t)
|
||||
desc := make([]byte, 300)
|
||||
_, err := rand.Read(desc)
|
||||
req.NoError(err)
|
||||
|
||||
db := database.TemplateVersionParameter{
|
||||
Options: json.RawMessage("[]"),
|
||||
Description: string(desc),
|
||||
}
|
||||
sdk, err := db2sdk.TemplateVersionParameter(db)
|
||||
// Although the markdown parser can return an error, the way we use it should not, even
|
||||
// if we feed it garbage data.
|
||||
req.NoError(err)
|
||||
req.NotEmpty(sdk.DescriptionPlaintext, "broke the markdown parser with %v", desc)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// package dbmock contains a mocked implementation of the database.Store interface for use in tests
|
||||
package dbmock
|
||||
|
||||
//go:generate mockgen -destination ./store.go -package dbmock github.com/coder/coder/coderd/database Store
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user