From b273590673133cfc456e1899b324d55e2999105a Mon Sep 17 00:00:00 2001 From: healthjyk Date: Tue, 19 Mar 2024 14:37:54 +0800 Subject: [PATCH] feat: refactor the old usage of workspace and backend --- pkg/cmd/apply/options.go | 80 ++++---- pkg/cmd/apply/options_test.go | 28 ++- pkg/cmd/build/build.go | 4 + pkg/cmd/build/builders/appconfig_builder.go | 6 +- pkg/cmd/build/builders/builder.go | 2 +- pkg/cmd/build/options.go | 15 +- pkg/cmd/build/options_test.go | 38 ++-- pkg/cmd/build/util.go | 19 +- pkg/cmd/build/util_test.go | 26 +-- pkg/cmd/destroy/options.go | 60 +++--- pkg/cmd/destroy/options_test.go | 36 ++-- pkg/cmd/preview/options.go | 66 ++++--- pkg/cmd/preview/options_test.go | 179 +++++++++--------- pkg/engine/operation/apply_test.go | 9 +- pkg/engine/operation/destory_test.go | 14 +- pkg/engine/operation/models/change.go | 12 +- pkg/engine/operation/models/change_test.go | 3 +- .../operation/models/operation_context.go | 9 +- pkg/engine/operation/preview_test.go | 21 +- pkg/scaffold/demo_loader.go | 18 +- pkg/scaffold/demo_loader_test.go | 26 +-- 21 files changed, 342 insertions(+), 329 deletions(-) diff --git a/pkg/cmd/apply/options.go b/pkg/cmd/apply/options.go index 50e0e472..8c18ef55 100644 --- a/pkg/cmd/apply/options.go +++ b/pkg/cmd/apply/options.go @@ -52,18 +52,12 @@ func (o *Options) Validate() error { } func (o *Options) Run() error { - // Set no style + // set no style if o.NoStyle { pterm.DisableStyling() pterm.DisableColor() } - // Parse project and stack of work directory - proj, stack, err := project.DetectProjectAndStack(o.Options.WorkDir) - if err != nil { - return err - } - options := &builders.Options{ IsKclPkg: o.IsKclPkg, WorkDir: o.WorkDir, @@ -73,12 +67,32 @@ func (o *Options) Run() error { NoStyle: o.NoStyle, } - // Generate Intent + // parse project and stack of work directory + proj, stack, err := project.DetectProjectAndStack(o.Options.WorkDir) + if err != nil { + return err + } + + // get workspace configurations + bk, err := backend.NewBackend(o.Backend) + if err != nil { + return err + } + wsStorage, err := bk.WorkspaceStorage() + if err != nil { + return err + } + ws, err := wsStorage.Get(o.Workspace) + if err != nil { + return err + } + + // generate Intent var sp *apiv1.Intent if o.IntentFile != "" { sp, err = build.IntentFromFile(o.IntentFile) } else { - sp, err = build.IntentWithSpinner(options, proj, stack) + sp, err = build.IntentWithSpinner(options, proj, stack, ws) } if err != nil { return err @@ -90,16 +104,9 @@ func (o *Options) Run() error { return nil } - // new state storage - ws := "default" // todo: use default workspace for tmp - bk, err := backend.NewBackend("") // todo: use current backend for tmp - if err != nil { - return err - } - storage := bk.StateStorage(proj.Name, stack.Name, ws) - - // Compute changes for preview - changes, err := preview.Preview(&o.Options, storage, sp, proj, stack, ws) + // compute changes for preview + storage := bk.StateStorage(proj.Name, stack.Name, ws.Name) + changes, err := preview.Preview(&o.Options, storage, sp, proj, stack) if err != nil { return err } @@ -109,10 +116,10 @@ func (o *Options) Run() error { return nil } - // Summary preview table + // summary preview table changes.Summary(os.Stdout) - // Detail detection + // detail detection if o.Detail && o.All { changes.OutputDiff("all") if !o.Yes { @@ -120,7 +127,7 @@ func (o *Options) Run() error { } } - // Prompt + // prompt if !o.Yes { for { input, err := prompt() @@ -147,7 +154,7 @@ func (o *Options) Run() error { return err } - // If dry run, print the hint + // if dry run, print the hint if o.DryRun { fmt.Printf("\nNOTE: Currently running in the --dry-run mode, the above configuration does not really take effect\n") return nil @@ -192,7 +199,7 @@ func Apply( changes *models.Changes, out io.Writer, ) error { - // Construct the apply operation + // construct the apply operation ac := &operation.ApplyOperation{ Operation: models.Operation{ Stack: changes.Stack(), @@ -202,10 +209,10 @@ func Apply( }, } - // Line summary + // line summary var ls lineSummary - // Progress bar, print dag walk detail + // progress bar, print dag walk detail progressbar, err := pterm.DefaultProgressbar. WithMaxWidth(0). // Set to 0, the terminal width will be used WithTotal(len(changes.StepKeys)). @@ -214,9 +221,9 @@ func Apply( if err != nil { return err } - // Wait msgCh close + // wait msgCh close var wg sync.WaitGroup - // Receive msg and print detail + // receive msg and print detail go func() { defer func() { if p := recover(); p != nil { @@ -286,11 +293,10 @@ func Apply( // parse cluster in arguments _, st := ac.Apply(&operation.ApplyRequest{ Request: models.Request{ - Project: changes.Project(), - Stack: changes.Stack(), - Workspace: changes.Workspace(), - Operator: o.Operator, - Intent: planResources, + Project: changes.Project(), + Stack: changes.Stack(), + Operator: o.Operator, + Intent: planResources, }, }) if v1.IsErr(st) { @@ -298,9 +304,9 @@ func Apply( } } - // Wait for msgCh closed + // wait for msgCh closed wg.Wait() - // Print summary + // print summary pterm.Fprintln(out, fmt.Sprintf("Apply complete! Resources: %d created, %d updated, %d deleted.", ls.created, ls.updated, ls.deleted)) return nil } @@ -330,7 +336,7 @@ func Watch( return nil } - // Filter out unchanged resources + // filter out unchanged resources toBeWatched := apiv1.Resources{} for _, res := range planResources.Resources { if changes.ChangeOrder.ChangeSteps[res.ResourceKey()].Action != models.UnChanged { @@ -338,7 +344,7 @@ func Watch( } } - // Watch operation + // watch operation wo := &operation.WatchOperation{} if err := wo.Watch(&operation.WatchRequest{ Request: models.Request{ diff --git a/pkg/cmd/apply/options_test.go b/pkg/cmd/apply/options_test.go index 68ba2e49..960204f5 100644 --- a/pkg/cmd/apply/options_test.go +++ b/pkg/cmd/apply/options_test.go @@ -25,6 +25,7 @@ import ( "kusionstack.io/kusion/pkg/engine/runtime/kubernetes" statestorages "kusionstack.io/kusion/pkg/engine/state/storages" "kusionstack.io/kusion/pkg/project" + workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) func TestApplyOptions_Run(t *testing.T) { @@ -33,6 +34,7 @@ func TestApplyOptions_Run(t *testing.T) { mockPatchBuildIntent() mockPatchNewKubernetesRuntime() mockNewBackend() + mockWorkspaceStorage() mockPatchOperationPreview() o := NewApplyOptions() @@ -48,6 +50,7 @@ func TestApplyOptions_Run(t *testing.T) { mockPatchBuildIntent() mockPatchNewKubernetesRuntime() mockNewBackend() + mockWorkspaceStorage() mockPatchOperationPreview() mockOperationApply(models.Success) @@ -60,28 +63,28 @@ func TestApplyOptions_Run(t *testing.T) { } var ( - p = &apiv1.Project{ + proj = &apiv1.Project{ Name: "testdata", } - s = &apiv1.Stack{ + stack = &apiv1.Stack{ Name: "dev", } - ws = "dev" ) func mockPatchDetectProjectAndStack() *mockey.Mocker { return mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*apiv1.Project, *apiv1.Stack, error) { - p.Path = stackDir - s.Path = stackDir - return p, s, nil + proj.Path = stackDir + stack.Path = stackDir + return proj, stack, nil }).Build() } func mockPatchBuildIntent() *mockey.Mocker { return mockey.Mock(build.Intent).To(func( o *builders.Options, - project *apiv1.Project, + proj *apiv1.Project, stack *apiv1.Stack, + ws *apiv1.Workspace, ) (*apiv1.Intent, error) { return &apiv1.Intent{Resources: []apiv1.Resource{sa1, sa2, sa3}}, nil }).Build() @@ -97,6 +100,11 @@ func mockNewBackend() *mockey.Mocker { return mockey.Mock(backend.NewBackend).Return(&storages.LocalStorage{}, nil).Build() } +func mockWorkspaceStorage() { + mockey.Mock((*storages.LocalStorage).WorkspaceStorage).Return(&workspacestorages.LocalStorage{}, nil).Build() + mockey.Mock((*workspacestorages.LocalStorage).Get).Return(&apiv1.Workspace{}, nil).Build() +} + var _ runtime.Runtime = (*fakerRuntime)(nil) type fakerRuntime struct{} @@ -204,7 +212,7 @@ func Test_apply(t *testing.T) { }, }, } - changes := models.NewChanges(p, s, ws, order) + changes := models.NewChanges(proj, stack, order) o := NewApplyOptions() o.DryRun = true err := Apply(o, stateStorage, planResources, changes, os.Stdout) @@ -229,7 +237,7 @@ func Test_apply(t *testing.T) { }, }, } - changes := models.NewChanges(p, s, ws, order) + changes := models.NewChanges(proj, stack, order) err := Apply(o, stateStorage, planResources, changes, os.Stdout) assert.Nil(t, err) @@ -249,7 +257,7 @@ func Test_apply(t *testing.T) { }, }, } - changes := models.NewChanges(p, s, ws, order) + changes := models.NewChanges(proj, stack, order) err := Apply(o, stateStorage, planResources, changes, os.Stdout) assert.NotNil(t, err) diff --git a/pkg/cmd/build/build.go b/pkg/cmd/build/build.go index 1917f83d..e378cad5 100644 --- a/pkg/cmd/build/build.go +++ b/pkg/cmd/build/build.go @@ -68,4 +68,8 @@ func (o *Options) AddBuildFlags(cmd *cobra.Command) { i18n.T("Specify the command line setting files")) cmd.Flags().StringToStringVarP(&o.Arguments, "argument", "D", map[string]string{}, i18n.T("Specify the top-level argument")) + cmd.Flags().StringVarP(&o.Backend, "backend", "", "", + i18n.T("the backend name")) + cmd.Flags().StringVarP(&o.Backend, "workspace", "", "", + i18n.T("the workspace name")) } diff --git a/pkg/cmd/build/builders/appconfig_builder.go b/pkg/cmd/build/builders/appconfig_builder.go index a9213292..54af9a35 100644 --- a/pkg/cmd/build/builders/appconfig_builder.go +++ b/pkg/cmd/build/builders/appconfig_builder.go @@ -1,7 +1,7 @@ package builders import ( - "kusionstack.io/kusion/pkg/apis/core/v1" + v1 "kusionstack.io/kusion/pkg/apis/core/v1" "kusionstack.io/kusion/pkg/modules" "kusionstack.io/kusion/pkg/modules/generators" ) @@ -13,7 +13,7 @@ type AppsConfigBuilder struct { func (acg *AppsConfigBuilder) Build( _ *Options, - project *v1.Project, + proj *v1.Project, stack *v1.Stack, ) (*v1.Intent, error) { i := &v1.Intent{ @@ -22,7 +22,7 @@ func (acg *AppsConfigBuilder) Build( var gfs []modules.NewGeneratorFunc err := modules.ForeachOrdered(acg.Apps, func(appName string, app v1.AppConfiguration) error { - gfs = append(gfs, generators.NewAppConfigurationGeneratorFunc(project.Name, stack.Name, appName, &app, acg.Workspace)) + gfs = append(gfs, generators.NewAppConfigurationGeneratorFunc(proj.Name, stack.Name, appName, &app, acg.Workspace)) return nil }) if err != nil { diff --git a/pkg/cmd/build/builders/builder.go b/pkg/cmd/build/builders/builder.go index f144ed00..625a3f3a 100644 --- a/pkg/cmd/build/builders/builder.go +++ b/pkg/cmd/build/builders/builder.go @@ -1,7 +1,7 @@ package builders import ( - "kusionstack.io/kusion/pkg/apis/core/v1" + v1 "kusionstack.io/kusion/pkg/apis/core/v1" ) // Builder represents a method to build an Intent. Typically, it is implemented by the AppConfigureBuilder, diff --git a/pkg/cmd/build/options.go b/pkg/cmd/build/options.go index 76ed4d05..fb43bb69 100644 --- a/pkg/cmd/build/options.go +++ b/pkg/cmd/build/options.go @@ -9,6 +9,7 @@ import ( yamlv2 "gopkg.in/yaml.v2" "kcl-lang.io/kpm/pkg/api" + "kusionstack.io/kusion/pkg/backend" "kusionstack.io/kusion/pkg/cmd/build/builders" "kusionstack.io/kusion/pkg/project" ) @@ -29,6 +30,8 @@ type Flags struct { Settings []string Arguments map[string]string NoStyle bool + Backend string + Workspace string } const Stdout = "stdout" @@ -69,7 +72,14 @@ func (o *Options) Run() error { } // Parse project and stack of work directory - project, stack, err := project.DetectProjectAndStack(o.WorkDir) + proj, stack, err := project.DetectProjectAndStack(o.WorkDir) + if err != nil { + return err + } + + // Get workspace from backend + storage, err := backend.NewWorkspaceStorage(o.Backend) + ws, err := storage.Get(o.Workspace) if err != nil { return err } @@ -83,8 +93,9 @@ func (o *Options) Run() error { Arguments: o.Arguments, NoStyle: o.NoStyle, }, - project, + proj, stack, + ws, ) if err != nil { return err diff --git a/pkg/cmd/build/options_test.go b/pkg/cmd/build/options_test.go index 1948f77d..75a8d200 100644 --- a/pkg/cmd/build/options_test.go +++ b/pkg/cmd/build/options_test.go @@ -9,7 +9,7 @@ import ( "github.com/bytedance/mockey" "github.com/stretchr/testify/assert" - apiv1 "kusionstack.io/kusion/pkg/apis/core/v1" + v1 "kusionstack.io/kusion/pkg/apis/core/v1" "kusionstack.io/kusion/pkg/cmd/build/builders" "kusionstack.io/kusion/pkg/engine" "kusionstack.io/kusion/pkg/project" @@ -20,10 +20,10 @@ var ( kind = "ServiceAccount" namespace = "test-ns" - p = &apiv1.Project{ + p = &v1.Project{ Name: "testdata", } - s = &apiv1.Stack{ + s = &v1.Stack{ Name: "dev", } @@ -64,7 +64,7 @@ func TestCompileOptions_preSet(t *testing.T) { o := NewBuildOptions() o.Output = tt.fields.Output - o.PreSet(func(cur string) bool { + _ = o.PreSet(func(cur string) bool { return true }) @@ -78,10 +78,6 @@ func TestCompileOptions_preSet(t *testing.T) { } func TestCompileOptions_Run(t *testing.T) { - defer func() { - os.Remove("kusion_state.json") - }() - t.Run("no style is true", func(t *testing.T) { m1 := mockDetectProjectAndStack() m2 := mockGenerateIntent() @@ -118,8 +114,8 @@ func TestCompileOptions_Run(t *testing.T) { }) } -func newSA(name string) apiv1.Resource { - return apiv1.Resource{ +func newSA(name string) v1.Resource { + return v1.Resource{ ID: engine.BuildID(apiVersion, kind, namespace, name), Type: "Kubernetes", Attributes: map[string]interface{}{ @@ -134,7 +130,7 @@ func newSA(name string) apiv1.Resource { } func mockDetectProjectAndStack() *mockey.Mocker { - return mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*apiv1.Project, *apiv1.Stack, error) { + return mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*v1.Project, *v1.Stack, error) { p.Path = stackDir s.Path = stackDir return p, s, nil @@ -142,7 +138,7 @@ func mockDetectProjectAndStack() *mockey.Mocker { } func mockDetectProjectAndStackFail() *mockey.Mocker { - return mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*apiv1.Project, *apiv1.Stack, error) { + return mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*v1.Project, *v1.Stack, error) { p.Path = stackDir s.Path = stackDir return p, s, errTest @@ -152,20 +148,22 @@ func mockDetectProjectAndStackFail() *mockey.Mocker { func mockGenerateIntent() *mockey.Mocker { return mockey.Mock(IntentWithSpinner).To(func( o *builders.Options, - project *apiv1.Project, - stack *apiv1.Stack, - ) (*apiv1.Intent, error) { - return &apiv1.Intent{Resources: []apiv1.Resource{sa1, sa2, sa3}}, nil + proj *v1.Project, + stack *v1.Stack, + ws *v1.Workspace, + ) (*v1.Intent, error) { + return &v1.Intent{Resources: []v1.Resource{sa1, sa2, sa3}}, nil }).Build() } func mockGenerateIntentFail() *mockey.Mocker { return mockey.Mock(IntentWithSpinner).To(func( o *builders.Options, - project *apiv1.Project, - stack *apiv1.Stack, - ) (*apiv1.Intent, error) { - return &apiv1.Intent{Resources: []apiv1.Resource{sa1, sa2, sa3}}, errTest + proj *v1.Project, + stack *v1.Stack, + ws *v1.Workspace, + ) (*v1.Intent, error) { + return &v1.Intent{Resources: []v1.Resource{sa1, sa2, sa3}}, errTest }).Build() } diff --git a/pkg/cmd/build/util.go b/pkg/cmd/build/util.go index bad9723b..852b36cf 100644 --- a/pkg/cmd/build/util.go +++ b/pkg/cmd/build/util.go @@ -12,15 +12,14 @@ import ( "gopkg.in/yaml.v2" yamlv3 "gopkg.in/yaml.v3" - "kusionstack.io/kusion/pkg/apis/core/v1" + v1 "kusionstack.io/kusion/pkg/apis/core/v1" "kusionstack.io/kusion/pkg/cmd/build/builders" "kusionstack.io/kusion/pkg/cmd/build/builders/kcl" "kusionstack.io/kusion/pkg/log" "kusionstack.io/kusion/pkg/util/pretty" - "kusionstack.io/kusion/pkg/workspace" ) -func IntentWithSpinner(o *builders.Options, project *v1.Project, stack *v1.Stack) (*v1.Intent, error) { +func IntentWithSpinner(o *builders.Options, proj *v1.Project, stack *v1.Stack, ws *v1.Workspace) (*v1.Intent, error) { var sp *pterm.SpinnerPrinter if o.NoStyle { fmt.Printf("Generating Intent in the Stack %s...\n", stack.Name) @@ -32,7 +31,7 @@ func IntentWithSpinner(o *builders.Options, project *v1.Project, stack *v1.Stack // style means color and prompt here. Currently, sp will be nil only when o.NoStyle is true style := !o.NoStyle && sp != nil - i, err := Intent(o, project, stack) + i, err := Intent(o, proj, stack, ws) // failed if err != nil { if style { @@ -53,10 +52,10 @@ func IntentWithSpinner(o *builders.Options, project *v1.Project, stack *v1.Stack return i, nil } -func Intent(o *builders.Options, p *v1.Project, s *v1.Stack) (*v1.Intent, error) { +func Intent(o *builders.Options, proj *v1.Project, stack *v1.Stack, ws *v1.Workspace) (*v1.Intent, error) { // Choose the generator var builder builders.Builder - pg := p.Generator + pg := proj.Generator // default AppsConfigBuilder var bt v1.BuilderType @@ -71,11 +70,7 @@ func Intent(o *builders.Options, p *v1.Project, s *v1.Stack) (*v1.Intent, error) case v1.KCLBuilder: builder = &kcl.Builder{} case v1.AppConfigurationBuilder: - appConfigs, err := buildAppConfigs(o, s) - if err != nil { - return nil, err - } - ws, err := workspace.GetWorkspaceByDefaultOperator(s.Name) + appConfigs, err := buildAppConfigs(o, stack) if err != nil { return nil, err } @@ -87,7 +82,7 @@ func Intent(o *builders.Options, p *v1.Project, s *v1.Stack) (*v1.Intent, error) return nil, fmt.Errorf("unknow generator type:%s", bt) } - i, err := builder.Build(o, p, s) + i, err := builder.Build(o, proj, stack) if err != nil { return nil, errors.New(stripansi.Strip(err.Error())) } diff --git a/pkg/cmd/build/util_test.go b/pkg/cmd/build/util_test.go index c2fa3809..50bb3056 100644 --- a/pkg/cmd/build/util_test.go +++ b/pkg/cmd/build/util_test.go @@ -13,7 +13,6 @@ import ( v1 "kusionstack.io/kusion/pkg/apis/core/v1" "kusionstack.io/kusion/pkg/cmd/build/builders" "kusionstack.io/kusion/pkg/cmd/build/builders/kcl" - "kusionstack.io/kusion/pkg/workspace" ) var ( @@ -180,8 +179,9 @@ func TestBuildIntent(t *testing.T) { type args struct { o *builders.Options - project *v1.Project + proj *v1.Project stack *v1.Stack + ws *v1.Workspace mockers []*mockey.MockBuilder } tests := []struct { @@ -193,20 +193,21 @@ func TestBuildIntent(t *testing.T) { { name: "nil builder", args: struct { o *builders.Options - project *v1.Project + proj *v1.Project stack *v1.Stack + ws *v1.Workspace mockers []*mockey.MockBuilder }{ o: &builders.Options{Arguments: map[string]string{}}, - project: &v1.Project{ + proj: &v1.Project{ Name: "default", }, stack: &v1.Stack{ Name: "default", }, + ws: ws, mockers: []*mockey.MockBuilder{ mockey.Mock(kcl.Run).Return(&kcl.CompileResult{Documents: []kclgo.KCLResult{apcMap}}, nil), - mockey.Mock(workspace.GetWorkspaceByDefaultOperator).Return(ws, nil), mockey.Mock((*builders.AppsConfigBuilder).Build).To(func( o *builders.Options, project *v1.Project, stack *v1.Stack, @@ -222,17 +223,19 @@ func TestBuildIntent(t *testing.T) { { name: "kcl builder", args: struct { o *builders.Options - project *v1.Project + proj *v1.Project stack *v1.Stack + ws *v1.Workspace mockers []*mockey.MockBuilder }{ o: &builders.Options{}, - project: &v1.Project{ + proj: &v1.Project{ Generator: &v1.GeneratorConfig{ Type: v1.KCLBuilder, }, }, stack: &v1.Stack{}, + ws: ws, mockers: []*mockey.MockBuilder{ mockey.Mock((*kcl.Builder).Build).Return(nil, nil), }, @@ -242,12 +245,13 @@ func TestBuildIntent(t *testing.T) { { name: "app builder", args: struct { o *builders.Options - project *v1.Project + proj *v1.Project stack *v1.Stack + ws *v1.Workspace mockers []*mockey.MockBuilder }{ o: &builders.Options{Arguments: map[string]string{}}, - project: &v1.Project{ + proj: &v1.Project{ Name: "default", Generator: &v1.GeneratorConfig{ Type: v1.AppConfigurationBuilder, @@ -256,9 +260,9 @@ func TestBuildIntent(t *testing.T) { stack: &v1.Stack{ Name: "default", }, + ws: ws, mockers: []*mockey.MockBuilder{ mockey.Mock(kcl.Run).Return(&kcl.CompileResult{Documents: []kclgo.KCLResult{apcMap}}, nil), - mockey.Mock(workspace.GetWorkspaceByDefaultOperator).Return(ws, nil), mockey.Mock((*builders.AppsConfigBuilder).Build).To(func( o *builders.Options, project *v1.Project, stack *v1.Stack, @@ -284,7 +288,7 @@ func TestBuildIntent(t *testing.T) { } }() - got, err := Intent(tt.args.o, tt.args.project, tt.args.stack) + got, err := Intent(tt.args.o, tt.args.proj, tt.args.stack, tt.args.ws) if (err != nil) != tt.wantErr { t.Errorf("Build() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/cmd/destroy/options.go b/pkg/cmd/destroy/options.go index 432a93d3..9420a569 100644 --- a/pkg/cmd/destroy/options.go +++ b/pkg/cmd/destroy/options.go @@ -20,6 +20,7 @@ import ( "kusionstack.io/kusion/pkg/log" "kusionstack.io/kusion/pkg/project" "kusionstack.io/kusion/pkg/util/signals" + "kusionstack.io/kusion/pkg/workspace" ) type Options struct { @@ -49,24 +50,34 @@ func (o *Options) Validate() error { func (o *Options) Run() error { // listen for interrupts or the SIGTERM signal signals.HandleInterrupt() - // Parse project and stack of work directory + // parse project and stack of work directory proj, stack, err := project.DetectProjectAndStack(o.Options.WorkDir) if err != nil { return err } - // new state storage - ws := "default" // fixme: use default workspace for tmp - bk, err := backend.NewBackend("") // fixme: use current backend for tmp + // complete workspace name + bk, err := backend.NewBackend(o.Backend) if err != nil { return err } - storage := bk.StateStorage(proj.Name, stack.Name, ws) + if o.Workspace == "" { + var wsStorage workspace.Storage + wsStorage, err = bk.WorkspaceStorage() + if err != nil { + return err + } + o.Workspace, err = wsStorage.GetCurrent() + if err != nil { + return err + } + } // only destroy resources we managed + storage := bk.StateStorage(proj.Name, stack.Name, o.Workspace) priorState, err := storage.Get() if err != nil || priorState == nil { - log.Infof("can't find state with project: %s, stack: %s, workspace: %s", proj.Name, stack.Name, ws) + log.Infof("can't find state with project: %s, stack: %s, workspace: %s", proj.Name, stack.Name, o.Workspace) return fmt.Errorf("can not find State in this stack") } destroyResources := priorState.Resources @@ -76,22 +87,22 @@ func (o *Options) Run() error { return nil } - // Compute changes for preview + // compute changes for preview i := &apiv1.Intent{Resources: destroyResources} - changes, err := o.preview(i, proj, stack, ws, storage) + changes, err := o.preview(i, proj, stack, storage) if err != nil { return err } - // Preview + // preview changes.Summary(os.Stdout) - // Detail detection + // detail detection if o.Detail { changes.OutputDiff("all") return nil } - // Prompt + // prompt if !o.Yes { for { var input string @@ -116,7 +127,7 @@ func (o *Options) Run() error { } } - // Destroy + // destroy fmt.Println("Start destroying resources......") if err = o.destroy(i, changes, storage); err != nil { return err @@ -128,12 +139,11 @@ func (o *Options) preview( planResources *apiv1.Intent, proj *apiv1.Project, stack *apiv1.Stack, - ws string, stateStorage state.Storage, ) (*models.Changes, error) { log.Info("Start compute preview changes ...") - // Check and install terraform executable binary for + // check and install terraform executable binary for // resources with the type of Terraform. tfInstaller := terraform.CLIInstaller{ Intent: planResources, @@ -155,18 +165,17 @@ func (o *Options) preview( rsp, s := pc.Preview(&operation.PreviewRequest{ Request: models.Request{ - Project: proj, - Stack: stack, - Workspace: ws, - Operator: o.Operator, - Intent: planResources, + Project: proj, + Stack: stack, + Operator: o.Operator, + Intent: planResources, }, }) if v1.IsErr(s) { return nil, fmt.Errorf("preview failed, status: %v", s) } - return models.NewChanges(proj, stack, ws, rsp.Order), nil + return models.NewChanges(proj, stack, rsp.Order), nil } func (o *Options) destroy(planResources *apiv1.Intent, changes *models.Changes, stateStorage state.Storage) error { @@ -247,11 +256,10 @@ func (o *Options) destroy(planResources *apiv1.Intent, changes *models.Changes, st := do.Destroy(&operation.DestroyRequest{ Request: models.Request{ - Project: changes.Project(), - Stack: changes.Stack(), - Workspace: changes.Workspace(), - Operator: o.Operator, - Intent: planResources, + Project: changes.Project(), + Stack: changes.Stack(), + Operator: o.Operator, + Intent: planResources, }, }) if v1.IsErr(st) { @@ -260,7 +268,7 @@ func (o *Options) destroy(planResources *apiv1.Intent, changes *models.Changes, // wait for msgCh closed wg.Wait() - // Print summary + // print summary pterm.Println() pterm.Printf("Destroy complete! Resources: %d deleted.\n", deleted) return nil diff --git a/pkg/cmd/destroy/options_test.go b/pkg/cmd/destroy/options_test.go index 56f4165e..acbf0adb 100644 --- a/pkg/cmd/destroy/options_test.go +++ b/pkg/cmd/destroy/options_test.go @@ -22,13 +22,15 @@ import ( "kusionstack.io/kusion/pkg/engine/runtime/kubernetes" statestorages "kusionstack.io/kusion/pkg/engine/state/storages" "kusionstack.io/kusion/pkg/project" + workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) func TestDestroyOptions_Run(t *testing.T) { mockey.PatchConvey("Detail is true", t, func() { mockDetectProjectAndStack() mockGetState() - mockNewBackend() + mockBackend() + mockWorkspaceStorage() mockNewKubernetesRuntime() mockOperationPreview() @@ -41,7 +43,8 @@ func TestDestroyOptions_Run(t *testing.T) { mockey.PatchConvey("prompt no", t, func() { mockDetectProjectAndStack() mockGetState() - mockNewBackend() + mockBackend() + mockWorkspaceStorage() mockNewKubernetesRuntime() mockOperationPreview() @@ -54,7 +57,8 @@ func TestDestroyOptions_Run(t *testing.T) { mockey.PatchConvey("prompt yes", t, func() { mockDetectProjectAndStack() mockGetState() - mockNewBackend() + mockBackend() + mockWorkspaceStorage() mockNewKubernetesRuntime() mockOperationPreview() mockOperationDestroy(models.Success) @@ -67,20 +71,19 @@ func TestDestroyOptions_Run(t *testing.T) { } var ( - p = &apiv1.Project{ + proj = &apiv1.Project{ Name: "testdata", } - s = &apiv1.Stack{ + stack = &apiv1.Stack{ Name: "dev", } - ws = "dev" ) func mockDetectProjectAndStack() { mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*apiv1.Project, *apiv1.Stack, error) { - p.Path = stackDir - s.Path = stackDir - return p, s, nil + proj.Path = stackDir + stack.Path = stackDir + return proj, stack, nil }).Build() } @@ -95,7 +98,7 @@ func Test_preview(t *testing.T) { o := NewDestroyOptions() stateStorage := statestorages.NewLocalStorage(filepath.Join(o.WorkDir, "state.yaml")) - _, err := o.preview(&apiv1.Intent{Resources: []apiv1.Resource{sa1}}, p, s, ws, stateStorage) + _, err := o.preview(&apiv1.Intent{Resources: []apiv1.Resource{sa1}}, proj, stack, stateStorage) assert.Nil(t, err) }) } @@ -209,7 +212,7 @@ func Test_destroy(t *testing.T) { }, }, } - changes := models.NewChanges(p, s, ws, order) + changes := models.NewChanges(proj, stack, order) stateStorage := statestorages.NewLocalStorage(filepath.Join(o.WorkDir, "state.yaml")) @@ -232,7 +235,7 @@ func Test_destroy(t *testing.T) { }, }, } - changes := models.NewChanges(p, s, ws, order) + changes := models.NewChanges(proj, stack, order) stateStorage := statestorages.NewLocalStorage(filepath.Join(o.WorkDir, "state.yaml")) err := o.destroy(planResources, changes, stateStorage) @@ -268,8 +271,13 @@ func mockOperationDestroy(res models.OpResult) { }).Build() } -func mockNewBackend() *mockey.Mocker { - return mockey.Mock(backend.NewBackend).Return(&storages.LocalStorage{}, nil).Build() +func mockBackend() { + mockey.Mock(backend.NewBackend).Return(&storages.LocalStorage{}, nil).Build() +} + +func mockWorkspaceStorage() { + mockey.Mock((*storages.LocalStorage).WorkspaceStorage).Return(&workspacestorages.LocalStorage{}, nil).Build() + mockey.Mock((*workspacestorages.LocalStorage).GetCurrent).Return("default", nil).Build() } func Test_prompt(t *testing.T) { diff --git a/pkg/cmd/preview/options.go b/pkg/cmd/preview/options.go index 078c7c6c..acf05836 100644 --- a/pkg/cmd/preview/options.go +++ b/pkg/cmd/preview/options.go @@ -109,16 +109,11 @@ func (o *Options) ValidateIntentFile() error { } func (o *Options) Run() error { - // Set no style + // set no style if o.NoStyle || o.Output == jsonOutput { pterm.DisableStyling() pterm.DisableColor() } - // Parse project and stack of work directory - proj, stack, err := project.DetectProjectAndStack(o.WorkDir) - if err != nil { - return err - } options := &builders.Options{ IsKclPkg: o.IsKclPkg, @@ -129,14 +124,34 @@ func (o *Options) Run() error { NoStyle: o.NoStyle, } - // Generate Intent + // parse project and stack of work directory + proj, stack, err := project.DetectProjectAndStack(o.WorkDir) + if err != nil { + return err + } + + // get workspace configurations + bk, err := backend.NewBackend(o.Backend) + if err != nil { + return err + } + wsStorage, err := bk.WorkspaceStorage() + if err != nil { + return err + } + ws, err := wsStorage.Get(o.Workspace) + if err != nil { + return err + } + + // generate Intent var sp *apiv1.Intent if o.IntentFile != "" { sp, err = build.IntentFromFile(o.IntentFile) } else if o.Output == jsonOutput { - sp, err = build.Intent(options, proj, stack) + sp, err = build.Intent(options, proj, stack, ws) } else { - sp, err = build.IntentWithSpinner(options, proj, stack) + sp, err = build.IntentWithSpinner(options, proj, stack, ws) } if err != nil { return err @@ -151,16 +166,9 @@ func (o *Options) Run() error { return nil } - // new state storage - ws := "default" // todo: use default workspace for tmp - bk, err := backend.NewBackend("") // todo: use current backend for tmp - if err != nil { - return err - } - storage := bk.StateStorage(proj.Name, stack.Name, ws) - - // Compute changes for preview - changes, err := Preview(o, storage, sp, proj, stack, ws) + // compute changes for preview + storage := bk.StateStorage(proj.Name, stack.Name, ws.Name) + changes, err := Preview(o, storage, sp, proj, stack) if err != nil { return err } @@ -180,10 +188,10 @@ func (o *Options) Run() error { return nil } - // Summary preview table + // summary preview table changes.Summary(os.Stdout) - // Detail detection + // detail detection if o.Detail { for { var target string @@ -228,11 +236,10 @@ func Preview( planResources *apiv1.Intent, proj *apiv1.Project, stack *apiv1.Stack, - ws string, ) (*models.Changes, error) { log.Info("Start compute preview changes ...") - // Check and install terraform executable binary for + // check and install terraform executable binary for // resources with the type of Terraform. tfInstaller := terraform.CLIInstaller{ Intent: planResources, @@ -241,7 +248,7 @@ func Preview( return nil, err } - // Construct the preview operation + // construct the preview operation pc := &operation.PreviewOperation{ Operation: models.Operation{ OperationType: models.ApplyPreview, @@ -257,16 +264,15 @@ func Preview( // parse cluster in arguments rsp, s := pc.Preview(&operation.PreviewRequest{ Request: models.Request{ - Project: proj, - Stack: stack, - Workspace: ws, - Operator: o.Operator, - Intent: planResources, + Project: proj, + Stack: stack, + Operator: o.Operator, + Intent: planResources, }, }) if v1.IsErr(s) { return nil, fmt.Errorf("preview failed.\n%s", s.String()) } - return models.NewChanges(proj, stack, ws, rsp.Order), nil + return models.NewChanges(proj, stack, rsp.Order), nil } diff --git a/pkg/cmd/preview/options_test.go b/pkg/cmd/preview/options_test.go index de5ffc54..c3607f9d 100644 --- a/pkg/cmd/preview/options_test.go +++ b/pkg/cmd/preview/options_test.go @@ -23,6 +23,7 @@ import ( "kusionstack.io/kusion/pkg/engine/runtime/kubernetes" statestorages "kusionstack.io/kusion/pkg/engine/state/storages" "kusionstack.io/kusion/pkg/project" + workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) var ( @@ -30,13 +31,12 @@ var ( kind = "ServiceAccount" namespace = "test-ns" - p = &apiv1.Project{ + proj = &apiv1.Project{ Name: "testdata", } - s = &apiv1.Stack{ + stack = &apiv1.Stack{ Name: "dev", } - ws = "dev" sa1 = newSA("sa1") sa2 = newSA("sa2") @@ -50,7 +50,7 @@ func Test_preview(t *testing.T) { defer m.UnPatch() o := NewPreviewOptions() - _, err := Preview(o, stateStorage, &apiv1.Intent{Resources: []apiv1.Resource{sa1, sa2, sa3}}, p, s, ws) + _, err := Preview(o, stateStorage, &apiv1.Intent{Resources: []apiv1.Resource{sa1, sa2, sa3}}, proj, stack) assert.Nil(t, err) }) } @@ -64,89 +64,79 @@ func TestPreviewOptions_Run(t *testing.T) { }) t.Run("compile failed", func(t *testing.T) { - m := mockDetectProjectAndStack() - defer m.UnPatch() + mockey.PatchConvey("mock engine operation", t, func() { + mockDetectProjectAndStack() - o := NewPreviewOptions() - o.Detail = true - err := o.Run() - assert.NotNil(t, err) + o := NewPreviewOptions() + o.Detail = true + err := o.Run() + assert.NotNil(t, err) + }) }) t.Run("no changes", func(t *testing.T) { - m1 := mockDetectProjectAndStack() - m2 := mockPatchBuildIntentWithSpinner() - m3 := mockNewKubernetesRuntime() - m4 := mockNewBackend() - defer m1.UnPatch() - defer m2.UnPatch() - defer m3.UnPatch() - defer m4.UnPatch() - - o := NewPreviewOptions() - o.Detail = true - err := o.Run() - assert.Nil(t, err) + mockey.PatchConvey("mock engine operation", t, func() { + mockDetectProjectAndStack() + mockPatchBuildIntentWithSpinner() + mockNewKubernetesRuntime() + mockNewBackend() + mockWorkspaceStorage() + o := NewPreviewOptions() + o.Detail = true + err := o.Run() + assert.Nil(t, err) + }) }) t.Run("detail is true", func(t *testing.T) { - m1 := mockDetectProjectAndStack() - m2 := mockPatchBuildIntentWithSpinner() - m3 := mockNewKubernetesRuntime() - m4 := mockOperationPreview() - m5 := mockPromptDetail("") - m6 := mockNewBackend() - defer m1.UnPatch() - defer m2.UnPatch() - defer m3.UnPatch() - defer m4.UnPatch() - defer m5.UnPatch() - defer m6.UnPatch() - - o := NewPreviewOptions() - o.Detail = true - err := o.Run() - assert.Nil(t, err) + mockey.PatchConvey("mock engine operation", t, func() { + mockDetectProjectAndStack() + mockPatchBuildIntentWithSpinner() + mockNewKubernetesRuntime() + mockOperationPreview() + mockPromptDetail("") + mockNewBackend() + mockWorkspaceStorage() + + o := NewPreviewOptions() + o.Detail = true + err := o.Run() + assert.Nil(t, err) + }) }) t.Run("json output is true", func(t *testing.T) { - m1 := mockDetectProjectAndStack() - m2 := mockBuildIntent() - m3 := mockNewKubernetesRuntime() - m4 := mockOperationPreview() - m5 := mockPromptDetail("") - m6 := mockNewBackend() - defer m1.UnPatch() - defer m2.UnPatch() - defer m3.UnPatch() - defer m4.UnPatch() - defer m5.UnPatch() - defer m6.UnPatch() - - o := NewPreviewOptions() - o.Output = jsonOutput - err := o.Run() - assert.Nil(t, err) + mockey.PatchConvey("mock engine operation", t, func() { + mockDetectProjectAndStack() + mockBuildIntent() + mockNewKubernetesRuntime() + mockOperationPreview() + mockPromptDetail("") + mockNewBackend() + mockWorkspaceStorage() + + o := NewPreviewOptions() + o.Output = jsonOutput + err := o.Run() + assert.Nil(t, err) + }) }) t.Run("no style is true", func(t *testing.T) { - m1 := mockDetectProjectAndStack() - m2 := mockPatchBuildIntentWithSpinner() - m3 := mockNewKubernetesRuntime() - m4 := mockOperationPreview() - m5 := mockPromptDetail("") - m6 := mockNewBackend() - defer m1.UnPatch() - defer m2.UnPatch() - defer m3.UnPatch() - defer m4.UnPatch() - defer m5.UnPatch() - defer m6.UnPatch() - - o := NewPreviewOptions() - o.NoStyle = true - err := o.Run() - assert.Nil(t, err) + mockey.PatchConvey("mock engine operation", t, func() { + mockDetectProjectAndStack() + mockPatchBuildIntentWithSpinner() + mockNewKubernetesRuntime() + mockOperationPreview() + mockPromptDetail("") + mockNewBackend() + mockWorkspaceStorage() + + o := NewPreviewOptions() + o.NoStyle = true + err := o.Run() + assert.Nil(t, err) + }) }) } @@ -229,48 +219,55 @@ func newSA(name string) apiv1.Resource { } } -func mockDetectProjectAndStack() *mockey.Mocker { - return mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*apiv1.Project, *apiv1.Stack, error) { - p.Path = stackDir - s.Path = stackDir - return p, s, nil +func mockDetectProjectAndStack() { + mockey.Mock(project.DetectProjectAndStack).To(func(stackDir string) (*apiv1.Project, *apiv1.Stack, error) { + proj.Path = stackDir + stack.Path = stackDir + return proj, stack, nil }).Build() } -func mockBuildIntent() *mockey.Mocker { - return mockey.Mock(build.Intent).To(func( +func mockBuildIntent() { + mockey.Mock(build.Intent).To(func( o *builders.Options, - project *apiv1.Project, + proj *apiv1.Project, stack *apiv1.Stack, + ws *apiv1.Workspace, ) (*apiv1.Intent, error) { return &apiv1.Intent{Resources: []apiv1.Resource{sa1, sa2, sa3}}, nil }).Build() } -func mockPatchBuildIntentWithSpinner() *mockey.Mocker { - return mockey.Mock(build.IntentWithSpinner).To(func( +func mockPatchBuildIntentWithSpinner() { + mockey.Mock(build.IntentWithSpinner).To(func( o *builders.Options, - project *apiv1.Project, + proj *apiv1.Project, stack *apiv1.Stack, + ws *apiv1.Workspace, ) (*apiv1.Intent, error) { return &apiv1.Intent{Resources: []apiv1.Resource{sa1, sa2, sa3}}, nil }).Build() } -func mockNewKubernetesRuntime() *mockey.Mocker { - return mockey.Mock(kubernetes.NewKubernetesRuntime).To(func() (runtime.Runtime, error) { +func mockNewKubernetesRuntime() { + mockey.Mock(kubernetes.NewKubernetesRuntime).To(func() (runtime.Runtime, error) { return &fooRuntime{}, nil }).Build() } -func mockPromptDetail(input string) *mockey.Mocker { - return mockey.Mock((*models.ChangeOrder).PromptDetails).To(func(co *models.ChangeOrder) (string, error) { +func mockPromptDetail(input string) { + mockey.Mock((*models.ChangeOrder).PromptDetails).To(func(co *models.ChangeOrder) (string, error) { return input, nil }).Build() } -func mockNewBackend() *mockey.Mocker { - return mockey.Mock(backend.NewBackend).Return(&storages.LocalStorage{}, nil).Build() +func mockNewBackend() { + mockey.Mock(backend.NewBackend).Return(&storages.LocalStorage{}, nil).Build() +} + +func mockWorkspaceStorage() { + mockey.Mock((*storages.LocalStorage).WorkspaceStorage).Return(&workspacestorages.LocalStorage{}, nil).Build() + mockey.Mock((*workspacestorages.LocalStorage).Get).Return(&apiv1.Workspace{}, nil).Build() } func TestPreviewOptions_ValidateIntentFile(t *testing.T) { diff --git a/pkg/engine/operation/apply_test.go b/pkg/engine/operation/apply_test.go index 1470f489..1e90c07f 100644 --- a/pkg/engine/operation/apply_test.go +++ b/pkg/engine/operation/apply_test.go @@ -134,11 +134,10 @@ func TestOperation_Apply(t *testing.T) { MsgCh: make(chan models.Message, 5), }, args: args{applyRequest: &ApplyRequest{models.Request{ - Stack: s, - Project: p, - Workspace: "fake-workspace", - Operator: "fake-operator", - Intent: mf, + Stack: s, + Project: p, + Operator: "fake-operator", + Intent: mf, }}}, wantRsp: &ApplyResponse{rs}, wantSt: nil, diff --git a/pkg/engine/operation/destory_test.go b/pkg/engine/operation/destory_test.go index 9dcbabb9..86176143 100644 --- a/pkg/engine/operation/destory_test.go +++ b/pkg/engine/operation/destory_test.go @@ -20,10 +20,7 @@ import ( ) func TestOperation_Destroy(t *testing.T) { - var ( - workspace = "fake-workspace" - operator = "foo-user" - ) + operator := "foo-user" s := &apiv1.Stack{ Name: "fake-name", @@ -53,11 +50,10 @@ func TestOperation_Destroy(t *testing.T) { } r := &DestroyRequest{ models.Request{ - Stack: s, - Project: p, - Workspace: workspace, - Operator: operator, - Intent: mf, + Stack: s, + Project: p, + Operator: operator, + Intent: mf, }, } diff --git a/pkg/engine/operation/models/change.go b/pkg/engine/operation/models/change.go index 7d86e43c..92c4efc4 100644 --- a/pkg/engine/operation/models/change.go +++ b/pkg/engine/operation/models/change.go @@ -83,9 +83,8 @@ var ( type Changes struct { *ChangeOrder `json:",inline" yaml:",inline"` - project *v1.Project // the project of current changes - stack *v1.Stack // the stack of current changes - workspace string // the workspace name of current changes + project *v1.Project // the project of current changes + stack *v1.Stack // the stack of current changes } type ChangeOrder struct { @@ -93,12 +92,11 @@ type ChangeOrder struct { ChangeSteps map[string]*ChangeStep `json:"changeSteps,omitempty" yaml:"changeSteps,omitempty"` } -func NewChanges(p *v1.Project, s *v1.Stack, ws string, order *ChangeOrder) *Changes { +func NewChanges(p *v1.Project, s *v1.Stack, order *ChangeOrder) *Changes { return &Changes{ ChangeOrder: order, project: p, stack: s, - workspace: ws, } } @@ -137,10 +135,6 @@ func (p *Changes) Project() *v1.Project { return p.project } -func (p *Changes) Workspace() string { - return p.workspace -} - func (o *ChangeOrder) Diffs() string { buf := bytes.NewBufferString("") diff --git a/pkg/engine/operation/models/change_test.go b/pkg/engine/operation/models/change_test.go index 8827c673..1ced1645 100644 --- a/pkg/engine/operation/models/change_test.go +++ b/pkg/engine/operation/models/change_test.go @@ -317,7 +317,6 @@ func TestChanges_Project(t *testing.T) { order *ChangeOrder project *apiv1.Project stack *apiv1.Stack - ws string } tests := []struct { name string @@ -340,7 +339,7 @@ func TestChanges_Project(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - p := NewChanges(tt.fields.project, tt.fields.stack, tt.fields.ws, tt.fields.order) + p := NewChanges(tt.fields.project, tt.fields.stack, tt.fields.order) if got := p.Project(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Changes.Project() = %v, want %v", got, tt.want) } diff --git a/pkg/engine/operation/models/operation_context.go b/pkg/engine/operation/models/operation_context.go index c73b0b73..459123a8 100644 --- a/pkg/engine/operation/models/operation_context.go +++ b/pkg/engine/operation/models/operation_context.go @@ -62,11 +62,10 @@ type Message struct { } type Request struct { - Project *v1.Project `json:"project"` - Stack *v1.Stack `json:"stack"` - Workspace string `json:"workspace"` - Operator string `json:"operator"` - Intent *v1.Intent `json:"intent"` + Project *v1.Project `json:"project"` + Stack *v1.Stack `json:"stack"` + Operator string `json:"operator"` + Intent *v1.Intent `json:"intent"` } type OpResult string diff --git a/pkg/engine/operation/preview_test.go b/pkg/engine/operation/preview_test.go index 8b040ffc..b82dbde6 100644 --- a/pkg/engine/operation/preview_test.go +++ b/pkg/engine/operation/preview_test.go @@ -129,10 +129,9 @@ func TestOperation_Preview(t *testing.T) { args: args{ request: &PreviewRequest{ Request: models.Request{ - Stack: s, - Project: p, - Workspace: "fake-workspace", - Operator: "fake-operator", + Stack: s, + Project: p, + Operator: "fake-operator", Intent: &apiv1.Intent{ Resources: []apiv1.Resource{ FakeResourceState, @@ -167,10 +166,9 @@ func TestOperation_Preview(t *testing.T) { args: args{ request: &PreviewRequest{ Request: models.Request{ - Stack: s, - Project: p, - Workspace: "fake-workspace", - Operator: "fake-operator", + Stack: s, + Project: p, + Operator: "fake-operator", Intent: &apiv1.Intent{ Resources: []apiv1.Resource{ FakeResourceState2, @@ -223,10 +221,9 @@ func TestOperation_Preview(t *testing.T) { args: args{ request: &PreviewRequest{ Request: models.Request{ - Stack: s, - Project: p, - Workspace: "fake-workspace", - Operator: "fake-operator", + Stack: s, + Project: p, + Operator: "fake-operator", Intent: &apiv1.Intent{ Resources: []apiv1.Resource{ { diff --git a/pkg/scaffold/demo_loader.go b/pkg/scaffold/demo_loader.go index f4e9462c..4210c45a 100644 --- a/pkg/scaffold/demo_loader.go +++ b/pkg/scaffold/demo_loader.go @@ -2,14 +2,12 @@ package scaffold import ( "embed" - "errors" "io/fs" "os" "path/filepath" "text/template" - v1 "kusionstack.io/kusion/pkg/apis/core/v1" - "kusionstack.io/kusion/pkg/workspace" + "kusionstack.io/kusion/pkg/backend" ) const demoTmplDir = "quickstart" @@ -19,18 +17,10 @@ var demoFS embed.FS // GenDemoProject creates the demo project with a specified name in the specified directory. func GenDemoProject(dir, name string) error { - // Create the default workspace for the initialized demo project if not exists. - _, err := workspace.GetWorkspaceByDefaultOperator("default") + // Init default workspace for the initialized demo project if not exists. + _, err := backend.NewWorkspaceStorage("") if err != nil { - ws := &v1.Workspace{ - Name: "default", - } - - if err = workspace.CreateWorkspaceByDefaultOperator(ws); err != nil { - if !errors.Is(err, workspace.ErrWorkspaceAlreadyExist) { - return err - } - } + return err } // Define the embeded template parameter data. diff --git a/pkg/scaffold/demo_loader_test.go b/pkg/scaffold/demo_loader_test.go index 94ba9b76..99fca8e5 100644 --- a/pkg/scaffold/demo_loader_test.go +++ b/pkg/scaffold/demo_loader_test.go @@ -8,8 +8,9 @@ import ( "github.com/bytedance/mockey" "github.com/stretchr/testify/assert" - v1 "kusionstack.io/kusion/pkg/apis/core/v1" - "kusionstack.io/kusion/pkg/workspace" + + "kusionstack.io/kusion/pkg/backend" + workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) func TestGenDemoProject(t *testing.T) { @@ -20,33 +21,26 @@ func TestGenDemoProject(t *testing.T) { } defer os.RemoveAll(tmpProjectDir) - t.Run("failed to create default workspace", func(t *testing.T) { + t.Run("failed to init default workspace", func(t *testing.T) { mockey.PatchConvey("mock workspace related functions", t, func() { - mockey.Mock(workspace.GetWorkspaceByDefaultOperator). - To(func(name string) (*v1.Workspace, error) { - return &v1.Workspace{}, workspace.ErrWorkspaceNotExist - }).Build() - mockey.Mock(workspace.CreateWorkspaceByDefaultOperator). - To(func(ws *v1.Workspace) error { - return errors.New("failed to create default workspace") - }).Build() - - err := GenDemoProject("/dir/to/quickstart", "quickstart") + mockey.Mock(backend.NewWorkspaceStorage).Return(nil, errors.New("failed to create default workspace")).Build() + + err = GenDemoProject("/dir/to/quickstart", "quickstart") assert.ErrorContains(t, err, "failed to create default workspace") }) }) t.Run("failed to create destination directory or file path", func(t *testing.T) { mockey.PatchConvey("mock workspace related function", t, func() { - mockey.Mock(workspace.GetWorkspaceByDefaultOperator).Return(nil, nil).Build() + mockey.Mock(backend.NewWorkspaceStorage).Return(&workspacestorages.LocalStorage{}, nil).Build() - err := GenDemoProject("/dir/to/kusion-project/not-exists", "not-exists") + err = GenDemoProject("/dir/to/kusion-project/not-exists", "not-exists") assert.NotNil(t, err) }) }) t.Run("successfully creates the demo project", func(t *testing.T) { - err := GenDemoProject(tmpProjectDir, filepath.Base(tmpProjectDir)) + err = GenDemoProject(tmpProjectDir, filepath.Base(tmpProjectDir)) assert.Nil(t, err) }) }