From f64917ea19b89c47f11dfb5833eb68404b6b120d Mon Sep 17 00:00:00 2001 From: Kirk Bater Date: Fri, 14 Jul 2023 19:04:15 -0400 Subject: [PATCH 1/3] Adds ability to use custom add command template This adds the functionality in order to define a custom template per-project in order to allow modifications and expansions to the default cobra CLI functionality. --- tpl/main.go | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/tpl/main.go b/tpl/main.go index 009524c..77f1cd3 100644 --- a/tpl/main.go +++ b/tpl/main.go @@ -13,6 +13,13 @@ package tpl +import ( + "errors" + "fmt" + "io/fs" + "os" +) + func MainTemplate() []byte { return []byte(`/* {{ .Copyright }} @@ -118,8 +125,7 @@ func initConfig() { `) } -func AddCommandTemplate() []byte { - return []byte(`/* +var defaultCommandTemplate = []byte(`/* {{ .Project.Copyright }} {{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} */ @@ -160,4 +166,29 @@ func init() { // {{ .CmdName }}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } `) + +func AddCommandTemplate() []byte { + wd, err := os.Getwd() + if err != nil { + fmt.Println("Could not get current working directory.", "Error:", err) + return defaultCommandTemplate + } + + filename := ".cobra_template.tpl" + + tpl, err := os.ReadFile(fmt.Sprintf("%s/%s", wd, filename)) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return defaultCommandTemplate + } + fmt.Println("Could not read .cobra_template.tpl", "Error:", err) + return defaultCommandTemplate + } + + if len(tpl) < 1 { + fmt.Println("Template file is empty. Using default template.") + return defaultCommandTemplate + } + + return tpl } From f8f94fffc4466eadb2ada396837a0e91b881d618 Mon Sep 17 00:00:00 2001 From: Kirk Bater Date: Fri, 14 Jul 2023 19:33:43 -0400 Subject: [PATCH 2/3] Adds test for custom template and fixes existing tests --- cmd/add_test.go | 60 ++++++++++++++++++++++++++++++ cmd/testdata/main.go.golden | 2 +- cmd/testdata/root.go.golden | 2 +- cmd/testdata/test-custom.go.golden | 45 ++++++++++++++++++++++ cmd/testdata/test.go.golden | 2 +- 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 cmd/testdata/test-custom.go.golden diff --git a/cmd/add_test.go b/cmd/add_test.go index 20bc34f..02208f7 100644 --- a/cmd/add_test.go +++ b/cmd/add_test.go @@ -8,6 +8,38 @@ import ( "github.com/spf13/viper" ) +var customFileTemplate = []byte(`/* +{{ .Project.Copyright }} +{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// {{ .CmdName }}Cmd represents the {{ .CmdName }} command +var {{ .CmdName }}Cmd = &myStruct.Command{ + Use: "{{ .CmdName }}", + Short: "A brief description of your command", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("{{ .CmdName }} called") + }, + CustomParam: "This is a custom parameter to extend the default cobra functionality", +} + +func init() { + {{ .CmdParent }}.AddCommand({{ .CmdName }}Cmd) + + // All commands must indepenently define this flag by default + testCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Thank you for contributing a new command. +} +`) + func TestGoldenAddCmd(t *testing.T) { viper.Set("useViper", true) viper.Set("license", "apache") @@ -29,6 +61,34 @@ func TestGoldenAddCmd(t *testing.T) { } } +func TestGoldenCustomAddCmd(t *testing.T) { + viper.Set("useViper", true) + viper.Set("license", "apache") + command := &Command{ + CmdName: "test", + CmdParent: parentName, + Project: getProject(), + } + defer os.RemoveAll(command.AbsolutePath) + + assertNoErr(t, command.Project.Create()) + + templateFile := fmt.Sprintf("%s/.cobra_template.tpl", command.AbsolutePath) + err := os.WriteFile(templateFile, customFileTemplate, 0644) + if err != nil { + t.Fatal(err) + } + + assertNoErr(t, command.Create()) + + generatedFile := fmt.Sprintf("%s/cmd/%s.go", command.AbsolutePath, command.CmdName) + goldenFile := fmt.Sprintf("testdata/%s.go.golden", command.CmdName) + err = compareFiles(generatedFile, goldenFile) + if err != nil { + t.Fatal(err) + } +} + func TestValidateCmdName(t *testing.T) { testCases := []struct { input string diff --git a/cmd/testdata/main.go.golden b/cmd/testdata/main.go.golden index 714c24f..ee48018 100644 --- a/cmd/testdata/main.go.golden +++ b/cmd/testdata/main.go.golden @@ -1,5 +1,5 @@ /* -Copyright © 2022 NAME HERE +Copyright © 2023 NAME HERE Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/testdata/root.go.golden b/cmd/testdata/root.go.golden index f23bb6d..233ea5b 100644 --- a/cmd/testdata/root.go.golden +++ b/cmd/testdata/root.go.golden @@ -1,5 +1,5 @@ /* -Copyright © 2022 NAME HERE +Copyright © 2023 NAME HERE Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/testdata/test-custom.go.golden b/cmd/testdata/test-custom.go.golden new file mode 100644 index 0000000..acd09d6 --- /dev/null +++ b/cmd/testdata/test-custom.go.golden @@ -0,0 +1,45 @@ +/* +Copyright © 2022 NAME HERE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// testCmd represents the test command +var testCmd = &myStruct.Command{ + Use: "test", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("test called") + }, + CustomParam: "This is a custom parameter to extend the default cobra functionality", +} + +func init() { + rootCmd.AddCommand(testCmd) + + // All commands must indepenently define this flag by default + testCmd.PersistentFlags().String("foo", "", "A help for foo") +} diff --git a/cmd/testdata/test.go.golden b/cmd/testdata/test.go.golden index 1fb39e2..4e7520e 100644 --- a/cmd/testdata/test.go.golden +++ b/cmd/testdata/test.go.golden @@ -1,5 +1,5 @@ /* -Copyright © 2022 NAME HERE +Copyright © 2023 NAME HERE Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 24a1ed4ca0b5c80e5b762565aa17388f3ed4ec65 Mon Sep 17 00:00:00 2001 From: Kirk Bater Date: Fri, 14 Jul 2023 19:40:42 -0400 Subject: [PATCH 3/3] adds docs for template file --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index d2bc51e..efb2df1 100644 --- a/README.md +++ b/README.md @@ -177,3 +177,13 @@ Copyright © 2020 Steve Francia This file is part of CLI application foo. */ ``` + +### Custom "add" Templates + +In some cases advanced Cobra users may have extended their implementations of +their command line application past the defaults. In these cases, the default +`cobra-cli add` template may no longer apply to their repository. Support has +been added to create custom template files for new commands on a per-project +basis by adding a `.cobra_template.tpl` file to the root directory of their +command line application. An example template can be found in the +[cmd/add_test.go](https://www.github.com/spf13/cobra-cli/blob/main/cmd/add_test.go) file.