From 868e96d06a6eac5282f4a895ec84b552c8a73775 Mon Sep 17 00:00:00 2001 From: Marcos Lilljedahl Date: Fri, 8 Apr 2022 12:54:40 -0300 Subject: [PATCH] Allow to specify template when running `dagger project init` Adds the ability to select a template which will create a new file in the CWD with the template name. Templates present in the "cmd/dagger/project/templates" directory are automatically embedded in the dagger binary when building and then listed in the `dagger project init` help output. Usage: dagger project init -t One idea that we had while pairing on this is to eventually try improving this UX by extending the `dagger project` command by adding sub-commands like `dagger project templates [list, new, output, ...]`. Pair: gerhard Signed-off-by: Marcos Lilljedahl --- cmd/dagger/cmd/project/init.go | 16 ++++++- cmd/dagger/cmd/project/template.go | 50 ++++++++++++++++++++++ cmd/dagger/cmd/project/templates/hello.cue | 28 ++++++++++++ tests/package.json | 2 +- tests/project.bats | 26 ++++++++++- 5 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 cmd/dagger/cmd/project/template.go create mode 100644 cmd/dagger/cmd/project/templates/hello.cue diff --git a/cmd/dagger/cmd/project/init.go b/cmd/dagger/cmd/project/init.go index 86ff36b5..ff526126 100644 --- a/cmd/dagger/cmd/project/init.go +++ b/cmd/dagger/cmd/project/init.go @@ -33,8 +33,17 @@ var initCmd = &cobra.Command{ dir = args[0] } - name := viper.GetString("name") + // TODO @gerhard suggested maybe eventually having a + // `dagger project template [list, new]` + t := viper.GetString("template") + if len(t) > 0 { + err := createTemplate(t) + if err != nil { + lg.Fatal().Err(err).Msg("failed to initialize template") + } + } + name := viper.GetString("name") doneCh := common.TrackCommand(ctx, cmd) err := pkg.CueModInit(ctx, dir, name) <-doneCh @@ -46,6 +55,11 @@ var initCmd = &cobra.Command{ func init() { initCmd.Flags().StringP("name", "n", "", "project name") + t, err := getTemplateNames() + if err != nil { + panic(err) + } + initCmd.Flags().StringP("template", "t", "", fmt.Sprintf("Template name %s", t)) if err := viper.BindPFlags(initCmd.Flags()); err != nil { panic(err) } diff --git a/cmd/dagger/cmd/project/template.go b/cmd/dagger/cmd/project/template.go new file mode 100644 index 00000000..4a0b0288 --- /dev/null +++ b/cmd/dagger/cmd/project/template.go @@ -0,0 +1,50 @@ +package project + +import ( + "embed" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +//go:embed templates/*.cue +var templateFS embed.FS + +func createTemplate(name string) error { + filename := fmt.Sprintf("%s.cue", name) + f, err := templateFS.Open(fmt.Sprintf("templates/%s", filename)) + if err != nil { + return err + } + defer f.Close() + + fout, err := os.Create(filename) + if err != nil { + return err + } + + defer fout.Close() + + _, err = io.Copy(fout, f) + if err != nil { + return err + } + + return nil +} + +func getTemplateNames() ([]string, error) { + r := []string{} + e, err := templateFS.ReadDir("templates") + if err != nil { + return nil, err + } + + for _, f := range e { + r = append(r, strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))) + } + + return r, nil +} diff --git a/cmd/dagger/cmd/project/templates/hello.cue b/cmd/dagger/cmd/project/templates/hello.cue new file mode 100644 index 00000000..5d3fdab1 --- /dev/null +++ b/cmd/dagger/cmd/project/templates/hello.cue @@ -0,0 +1,28 @@ +// The first time you run the hello +// action as `dagger do hello --log-format plain`, +// make sure to run `dagger project update` first, +// so that all required dependencies are available. + +package hello + +import ( + "dagger.io/dagger" + "universe.dagger.io/bash" + "universe.dagger.io/alpine" + +) + +dagger.#Plan & { + actions: { + _alpine: alpine.#Build & { + packages: bash: _ + } + + // Hello world + hello: bash.#Run & { + input: _alpine.output + script: contents: "echo Hello World" + always: true + } + } +} diff --git a/tests/package.json b/tests/package.json index b959fad7..ccb5018e 100644 --- a/tests/package.json +++ b/tests/package.json @@ -4,7 +4,7 @@ "test": "bats --jobs 4 --print-output-on-failure --verbose-run ." }, "devDependencies": { - "bats": "https://github.com/bats-core/bats-core#master", + "bats": "https://github.com/bats-core/bats-core#v1.6.0", "bats-assert": "https://github.com/bats-core/bats-assert", "bats-support": "https://github.com/bats-core/bats-support" } diff --git a/tests/project.bats b/tests/project.bats index 45382abc..25a90ebf 100644 --- a/tests/project.bats +++ b/tests/project.bats @@ -8,7 +8,7 @@ setup() { } @test "project init and update and info" { - cd "$TEMPDIR" || exit + cd "$TEMPDIR" || exit 1 "$DAGGER" project init ./ --name "github.com/foo/bar" test -d ./cue.mod/pkg @@ -39,3 +39,27 @@ setup() { assert_failure assert_output --partial "dagger project not found. Run \`dagger project init\`" } + + +@test "project init with template" { + cd "$TEMPDIR" || exit 1 + + if test -f ./hello.cue + then + echo "./hello.cue should not exist" + exit 1 + fi + + run "$DAGGER" project init -t hello + + assert_success + + if test ! -f ./hello.cue + then + echo "./hello.cue file was not created by the template flag" + exit 1 + fi + + cd - + diff --unified "$TEMPDIR/hello.cue" "$TESTDIR/../cmd/dagger/cmd/project/templates/hello.cue" +}