-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support command
mod init
(#945)
- Loading branch information
Showing
3 changed files
with
154 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,109 @@ | ||
package mod | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path" | ||
|
||
"github.com/go-git/go-git/v5/plumbing" | ||
"github.com/pulumi/pulumi/sdk/v3/go/common/util/gitutil" | ||
"github.com/spf13/cobra" | ||
"k8s.io/cli-runtime/pkg/genericclioptions" | ||
"k8s.io/kubectl/pkg/util/templates" | ||
|
||
"kusionstack.io/kusion/pkg/cmd/util" | ||
"kusionstack.io/kusion/pkg/util/i18n" | ||
) | ||
|
||
type InitModOptions struct{} | ||
type InitOptions struct { | ||
Name string | ||
Path string | ||
TemplateURL string | ||
} | ||
|
||
var example = i18n.T(`# Create a kusion module template in the current directory | ||
kusion mod init my-app | ||
# Init a kusion module at the specified Path | ||
kusion mod init my-app ./modules | ||
# Init a module from a remote git template repository | ||
kusion mod init my-app --template https://github.com/<user>/<repo>`) | ||
var short = i18n.T("Create a kusion module along with common files and directories in the current directory") | ||
|
||
var ( | ||
initLong = `` | ||
initExample = `` | ||
const ( | ||
defaultTemplateURL = "https://github.com/KusionStack/kusion-module-scaffolding.git" | ||
defaultBranch = "main" | ||
) | ||
|
||
// NewCmdInit returns an initialized Command instance for the 'mod init' sub command | ||
func NewCmdInit(streams genericclioptions.IOStreams) *cobra.Command { | ||
func NewCmdInit() *cobra.Command { | ||
o := &InitOptions{} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "", | ||
DisableFlagsInUseLine: true, | ||
Short: "", | ||
Long: initLong, | ||
Example: initExample, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
Use: "init [MODULE NAME] [PATH]", | ||
Short: short, | ||
Example: templates.Examples(example), | ||
RunE: func(cmd *cobra.Command, args []string) (err error) { | ||
defer util.RecoverErr(&err) | ||
util.CheckErr(o.Validate(args)) | ||
util.CheckErr(o.Run()) | ||
return | ||
}, | ||
} | ||
cmd.Flags().StringVar(&o.TemplateURL, "template", "", i18n.T("Initialize with specified template")) | ||
|
||
return cmd | ||
} | ||
|
||
func (o *InitOptions) Validate(args []string) error { | ||
// get the module Name | ||
if len(args) < 1 { | ||
return fmt.Errorf("module Name is empty") | ||
} | ||
o.Name = args[0] | ||
|
||
// get the Path | ||
if len(args) == 2 { | ||
o.Path = args[1] | ||
} else { | ||
// default to the current directory | ||
o.Path, _ = os.Getwd() | ||
} | ||
|
||
// create the module directory if not exists | ||
fs, err := os.Stat(o.Path) | ||
if err != nil { | ||
return fmt.Errorf("failed to create module directory: %w", err) | ||
} else if !fs.IsDir() { | ||
return fmt.Errorf("path is not a directory") | ||
} else if os.IsNotExist(err) { | ||
if err = os.MkdirAll(o.Path, os.ModePerm); err != nil { | ||
return fmt.Errorf("failed to create module directory: %v", err) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (o *InitOptions) Run() error { | ||
if o.TemplateURL == "" { | ||
o.TemplateURL = defaultTemplateURL | ||
} | ||
|
||
// remove existing directory | ||
dir := path.Join(o.Path, o.Name) | ||
if err := os.RemoveAll(dir); err != nil { | ||
return fmt.Errorf("failed to remove existing directory: %v", err) | ||
} | ||
if err := os.MkdirAll(dir, os.ModePerm); err != nil { | ||
return err | ||
} | ||
|
||
// clone templates repo | ||
branch := plumbing.NewBranchReferenceName(defaultBranch) | ||
err := gitutil.GitCloneOrPull(o.TemplateURL, branch, dir, false) | ||
if err != nil { | ||
return fmt.Errorf("failed to clone git repo:%s, %w", o.TemplateURL, err) | ||
} | ||
fmt.Printf("initialized module %s successfully\n", o.Name) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package mod | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
"github.com/bytedance/mockey" | ||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/pulumi/pulumi/sdk/v3/go/common/util/gitutil" | ||
) | ||
|
||
func TestValidateWithEmptyModuleName(t *testing.T) { | ||
o := &InitOptions{} | ||
err := o.Validate([]string{}) | ||
assert.Error(t, err) | ||
assert.Equal(t, "module Name is empty", err.Error()) | ||
} | ||
|
||
func TestValidateWithNonExistentPath(t *testing.T) { | ||
o := &InitOptions{} | ||
err := o.Validate([]string{"my-app", "/non/existent/Path"}) | ||
assert.Error(t, err) | ||
assert.Contains(t, err.Error(), "failed to create module directory") | ||
} | ||
|
||
func TestValidateWithExistingPath(t *testing.T) { | ||
o := &InitOptions{} | ||
err := o.Validate([]string{"my-app", os.TempDir()}) | ||
assert.NoError(t, err) | ||
} | ||
|
||
func TestRunWithEmptyTemplateURL(t *testing.T) { | ||
o := &InitOptions{} | ||
o.Name = "my-app" | ||
o.Path = os.TempDir() | ||
err := o.Run() | ||
assert.NoError(t, err) | ||
} | ||
|
||
func TestRunWithInvalidTemplateURL(t *testing.T) { | ||
o := &InitOptions{} | ||
o.Name = "my-app" | ||
o.Path = os.TempDir() | ||
o.TemplateURL = "invalid-url" | ||
err := o.Run() | ||
assert.Error(t, err) | ||