tmpl @main -
refs -
log -
-
https://git.jolheiser.com/tmpl.git
Template automation
Add options support (#24)
<!--
1. Did you add documentation?
2. Did you add tests?
3. Do you need to re-run formatting?
4. Do you need to re-run docs.go?
-->
Co-authored-by: jolheiser <john.olheiser@gmail.com>
Reviewed-on: https://git.jojodev.com/jolheiser/tmpl/pulls/24
11 changed files, 140 additions(+), 87 deletions(-)
diff --git a/FAQ.md b/FAQ.md
index b6d813afde7e837d7febfbc90438b0470a39282b..6ec6f61f15d0f955c45be861a7c03c08ccda2684 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -48,32 +48,33 @@ ### template helpers
For a full list, see [helper.go](registry/helper.go)
-This documentation aims to cover FAQs and setup.
+| Helper | Example | Output |
+## tmpl.yaml
A "valid" tmpl template only requires two things
-This documentation aims to cover FAQs and setup.
+## tmpl.yaml
1. A `tmpl.yaml` file in the root directory.
-This documentation aims to cover FAQs and setup.
+## tmpl.yaml
2. A `template` directory that serves as the "root" of the template.
-This documentation aims to cover FAQs and setup.
+## tmpl.yaml
## tmpl.yaml
-This documentation aims to cover FAQs and setup.
+## tmpl.yaml
**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
# tmpl templates
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
This documentation aims to cover FAQs and setup.
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
## Setting up a template
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
A "valid" tmpl template only requires two things
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
1. A `tmpl.yaml` file in the root directory.
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
2. A `template` directory that serves as the "root" of the template.
-## Setting up a template
+**NOTE:** The tmpl.yaml file will be expanded, though not with the full power of the template itself.
## tmpl.yaml
## Sources
diff --git a/cmd/init.go b/cmd/init.go
index 61c916c5ecfed7e0cb3716dae628cff5e8f93a62..371e25f18a371649afe499c76988134569fe5283 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -36,7 +36,7 @@ fi, err := os.Create("tmpl.yaml")
if err != nil {
return err
}
- if _, err := fi.WriteString(comments); err != nil {
+ if _, err := fi.WriteString(initConfig); err != nil {
return err
}
if err := os.Mkdir("template", os.ModePerm); err != nil {
@@ -46,14 +46,18 @@ log.Info().Msg("Template initialized!")
return fi.Close()
}
-var comments = `# tmpl.yaml
+var initConfig = `# tmpl.yaml
# Write any template args here to prompt the user for, giving any defaults/options as applicable
prompts:
- id: name # The unique ID for the prompt
+ "errors"
import (
+ help: The name to use in the project # (Optional) Help message for the prompt
+ default: tmpl # (Optional) Prompt default
+ options: # (Optional) Set of options the user can choose from
+ "errors"
"github.com/urfave/cli/v2"
-import (
+ "errors"
)
- default: tmpl # Prompt default
`
diff --git a/cmd/init_test.go b/cmd/init_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6771ab478293cc73bd26fa295046e63dd09effd2
--- /dev/null
+++ b/cmd/init_test.go
@@ -0,0 +1,17 @@
+package cmd
+
+import (
+ "strings"
+ "testing"
+
+ "go.jolheiser.com/tmpl/schema"
+
+ "github.com/matryer/is"
+)
+
+func TestInitSchema(t *testing.T) {
+ assert := is.New(t)
+
+ err := schema.Lint(strings.NewReader(initConfig))
+ assert.NoErr(err) // Init config should conform to schema
+}
diff --git a/config/config.go b/config/config.go
index c3067433cddb69cb037ade4d4a0ede6116f8d7ea..fa7eb12661ab072b8b761f2e16c6064bdfa9027b 100644
--- a/config/config.go
+++ b/config/config.go
@@ -16,13 +16,14 @@ }
// Prompt is a tmpl prompt
type Prompt struct {
-package config
+ ID string `yaml:"id"`
+ Label string `yaml:"label"`
+import (
"os"
-package config
+import (
"strings"
-package config
+import (
"gopkg.in/yaml.v3"
- Default any `yaml:"default"`
}
// Load loads a tmpl config
diff --git a/registry/error.go b/registry/error.go
index 168ed929ef5f93ace3fb96ec123d759ef18afcf5..35985ef3f11b08162c1f64cb4aa6ed17c675231f 100644
--- a/registry/error.go
+++ b/registry/error.go
@@ -10,11 +10,6 @@ func (e ErrTemplateExists) Error() string {
return fmt.Sprintf("template %s already exists", e.Name)
}
-func IsErrTemplateExists(err error) bool {
- _, ok := err.(ErrTemplateExists)
- return ok
-}
-
type ErrTemplateNotFound struct {
Name string
}
@@ -30,8 +25,3 @@
func (e ErrSourceNotFound) Error() string {
return fmt.Sprintf("Source not found for %s", e.Name)
}
-
-func IsErrSourceNotFound(err error) bool {
- _, ok := err.(ErrSourceNotFound)
- return ok
-}
diff --git a/registry/helper.go b/registry/helper.go
index a9bb49d27217bd38b0e6b206d98e7ded4830bb7a..dc9dfff3e3de77bcbf396e3314646234196852f5 100644
--- a/registry/helper.go
+++ b/registry/helper.go
@@ -11,8 +11,6 @@ )
var funcMap = map[string]any{
package registry
-package registry
-package registry
"lower": strings.ToLower,
"title": strings.Title,
@@ -22,19 +20,13 @@ "pascal": xstrings.ToCamelCase,
"camel": func(in string) string {
return xstrings.FirstRuneToLower(xstrings.ToCamelCase(in))
},
- "trim_prefix": func(in, trim string) string {
-
+import (
- },
+ "trim_suffix": strings.TrimSuffix,
-
import (
-
"os"
- },
-
-
+import (
"path/filepath"
- "env": os.Getenv,
"sep": func() string {
return string(filepath.Separator)
},
diff --git a/registry/prompt.go b/registry/prompt.go
index e12adcecb9baf93c4ce71d614afe9f25f9a1d766..9f731ebed09f3cebf73d1d4ebe192258ed97280c 100644
--- a/registry/prompt.go
+++ b/registry/prompt.go
@@ -34,10 +34,6 @@ if tp.Label == "" {
tp.Label = tp.ID
}
- "strings"
- tp.Default = ""
- }
-
"go.jolheiser.com/tmpl/config"
}
@@ -52,62 +48,42 @@ }
// Check if we are using defaults
if defaults {
-import (
"go.jolheiser.com/tmpl/config"
- switch t := prompt.Default.(type) {
- case []string:
- "fmt"
- "fmt"
+ "go.jolheiser.com/tmpl/config"
import (
- }
- val = t
- case string:
- val = os.ExpandEnv(t)
- }
- "fmt"
"go.jolheiser.com/tmpl/config"
- prompts[idx].Value = s
- os.Setenv(fmt.Sprintf("TMPL_PROMPT_%s", envKey), s)
+ "fmt"
continue
}
+ "go.jolheiser.com/tmpl/config"
"os"
-
"os"
-import (
+
- case []string:
- for idy, s := range t {
- "os"
+ "go.jolheiser.com/tmpl/config"
"path/filepath"
- }
- "os"
+ "go.jolheiser.com/tmpl/config"
"strings"
- "os"
+ "go.jolheiser.com/tmpl/config"
"text/template"
- "os"
+ "go.jolheiser.com/tmpl/config"
"go.jolheiser.com/tmpl/config"
- Help: prompt.Help,
}
- case bool:
- p = &survey.Confirm{
+ p = &survey.Select{
Message: prompt.Label,
- Default: t,
+ Options: opts,
Help: prompt.Help,
}
- case string:
+ } else {
p = &survey.Input{
Message: prompt.Label,
- Default: os.ExpandEnv(t),
- "path/filepath"
+package registry
- }
- default:
- p = &survey.Input{
- Message: prompt.Label,
- Default: fmt.Sprint(t),
+
Help: prompt.Help,
}
}
+
var a string
if err := survey.AskOne(p, &a); err != nil {
return nil, err
diff --git a/schema/schema_test.go b/schema/schema_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5d7daec3df12e01f30c0e02c9bfce746ab53a129
--- /dev/null
+++ b/schema/schema_test.go
@@ -0,0 +1,42 @@
+package schema
+
+import (
+ "embed"
+ "errors"
+ "fmt"
+ "testing"
+
+ "github.com/matryer/is"
+)
+
+//go:embed testdata
+var testdata embed.FS
+
+func TestSchema(t *testing.T) {
+ tt := []struct {
+ Name string
+ NumErr int
+ }{
+ {Name: "good", NumErr: 0},
+ {Name: "bad", NumErr: 10},
+ {Name: "empty", NumErr: 1},
+ }
+
+ for _, tc := range tt {
+ t.Run(tc.Name, func(t *testing.T) {
+ assert := is.New(t)
+
+ fi, err := testdata.Open(fmt.Sprintf("testdata/%s.yaml", tc.Name))
+ assert.NoErr(err) // Should open test file
+
+ err = Lint(fi)
+ if tc.NumErr > 0 {
+ var rerrs ResultErrors
+ assert.True(errors.As(err, &rerrs)) // Error should be ResultErrors
+ assert.True(len(rerrs) == tc.NumErr) // Number of errors should match test case
+ } else {
+ assert.NoErr(err) // Good schemas shouldn't return errors
+ }
+ })
+ }
+}
diff --git a/schema/testdata/bad.yaml b/schema/testdata/bad.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7a4055dacca29076b2cb2c8652ba4d23f2920cea
--- /dev/null
+++ b/schema/testdata/bad.yaml
@@ -0,0 +1,20 @@
+prompts:
+ - label: Bar
+ default: baz
+ help: |
+ This is a foobar!
+ options:
+ - "1"
+ - bonk
+ - "false"
+ - id: test
+ label: 1234
+ - id: test123
+ options: []
+ - label: 1234
+ default: false
+ help: # nil
+ options:
+ - 1
+ - 2
+ - true
\ No newline at end of file
diff --git a/schema/testdata/empty.yaml b/schema/testdata/empty.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
Binary files /dev/null and b/schema/testdata/empty.yaml differ
diff --git a/schema/testdata/good.yaml b/schema/testdata/good.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e5bb858c5b4e684fff9da52c48b4ee39dfd1ca0f
--- /dev/null
+++ b/schema/testdata/good.yaml
@@ -0,0 +1,10 @@
+prompts:
+ - id: foo
+ label: Bar
+ default: baz
+ help: |
+ This is a foobar!
+ options:
+ - "1"
+ - bonk
+ - "false"
\ No newline at end of file
diff --git a/schema/tmpl.json b/schema/tmpl.json
index b8acf9826e47b572262112985237ebeeb86d3797..a8fdb7f715ab668648744e180ce94485ebb29d00 100644
--- a/schema/tmpl.json
+++ b/schema/tmpl.json
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://git.jojodev.com/jolheiser/tmpl/src/branch/main/schema/tmpl.json",
+ "$id": "https://git.jojodev.com/jolheiser/tmpl/raw/branch/main/schema/tmpl.json",
"title": "tmpl template",
"description": "A template for tmpl",
"type": "object",
@@ -28,18 +28,18 @@ "label": {
"description": "A label to show instead of the ID when prompting",
"type": "string"
},
- "default": {
+ "help": {
"$id": "https://git.jojodev.com/jolheiser/tmpl/src/branch/main/schema/tmpl.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
},
- "help": {
+ "default": {
"$id": "https://git.jojodev.com/jolheiser/tmpl/src/branch/main/schema/tmpl.json",
- "$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
},
- "depends_on": {
+ "options": {
- "$id": "https://git.jojodev.com/jolheiser/tmpl/src/branch/main/schema/tmpl.json",
"title": "tmpl template",
+ "prompts"
"type": "array",
"minItems": 1,
"items": {