mirror of https://github.com/knative/func.git
feat: templates list command (#1134)
* feat: templates list command * linter placation
This commit is contained in:
parent
849c2cd7a1
commit
2f8d82bec2
|
@ -27,13 +27,13 @@ DESCRIPTION
|
||||||
This includes embedded (included) language runtimes as well as any installed
|
This includes embedded (included) language runtimes as well as any installed
|
||||||
via the 'repositories add' command.
|
via the 'repositories add' command.
|
||||||
|
|
||||||
|
To specify a URI of a single, specific repository for which languages
|
||||||
|
should be displayed, use the --repository flag.
|
||||||
|
|
||||||
Installed repositories are by default located at ~/.func/repositories
|
Installed repositories are by default located at ~/.func/repositories
|
||||||
($XDG_CONFIG_HOME/.func/repositories). This can be overridden with
|
($XDG_CONFIG_HOME/.func/repositories). This can be overridden with
|
||||||
$FUNC_REPOSITORIES_PATH.
|
$FUNC_REPOSITORIES_PATH.
|
||||||
|
|
||||||
To specify a URI of a single, specific repository for which languages
|
|
||||||
should be displayed, use the --repository flag.
|
|
||||||
|
|
||||||
To see templates available for a given language, see the 'templates' command.
|
To see templates available for a given language, see the 'templates' command.
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ EXAMPLES
|
||||||
PreRunE: bindEnv("json", "repository"),
|
PreRunE: bindEnv("json", "repository"),
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolP("json", "", false, "Set output to JSON format: $FUNC_JSON)")
|
cmd.Flags().BoolP("json", "", false, "Set output to JSON format. (Env: $FUNC_JSON)")
|
||||||
cmd.Flags().StringP("repository", "r", "", "URI to a specific repository to consider (Env: $FUNC_REPOSITORY)")
|
cmd.Flags().StringP("repository", "r", "", "URI to a specific repository to consider (Env: $FUNC_REPOSITORY)")
|
||||||
|
|
||||||
cmd.SetHelpFunc(defaultTemplatedHelp)
|
cmd.SetHelpFunc(defaultTemplatedHelp)
|
||||||
|
|
|
@ -99,6 +99,8 @@ EXAMPLES
|
||||||
cmd.AddCommand(NewCompletionCmd())
|
cmd.AddCommand(NewCompletionCmd())
|
||||||
cmd.AddCommand(NewVersionCmd(config.Version))
|
cmd.AddCommand(NewVersionCmd(config.Version))
|
||||||
cmd.AddCommand(NewLanguagesCmd(newClient))
|
cmd.AddCommand(NewLanguagesCmd(newClient))
|
||||||
|
cmd.AddCommand(NewTemplatesCmd(newClient))
|
||||||
|
cmd.AddCommand(NewLanguagesCmd(newClient))
|
||||||
|
|
||||||
// Help
|
// Help
|
||||||
// Overridden to process the help text as a template and have
|
// Overridden to process the help text as a template and have
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
|
"github.com/ory/viper"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
fn "knative.dev/kn-plugin-func"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTemplatesCmd(newClient ClientFactory) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "templates",
|
||||||
|
Short: "Templates",
|
||||||
|
Long: `
|
||||||
|
NAME
|
||||||
|
{{.Name}} templates - list available templates
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
{{.Name}} templates [language] [--json] [-r|--repository]
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
List all templates available, optionally for a specific language runtime.
|
||||||
|
|
||||||
|
To specify a URI of a single, specific repository for which templates
|
||||||
|
should be displayed, use the --repository flag.
|
||||||
|
|
||||||
|
Installed repositories are by default located at ~/.func/repositories
|
||||||
|
($XDG_CONFIG_HOME/.func/repositories). This can be overridden with
|
||||||
|
$FUNC_REPOSITORIES_PATH.
|
||||||
|
|
||||||
|
To see all available language runtimes, see the 'languages' command.
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
|
||||||
|
o Show a list of all available templates grouped by language runtime
|
||||||
|
$ {{.Name}} templates
|
||||||
|
|
||||||
|
o Show a list of all templates for the Go runtime
|
||||||
|
$ {{.Name}} templates go
|
||||||
|
|
||||||
|
o Return a list of all template runtimes in JSON output format
|
||||||
|
$ {{.Name}} templates --json
|
||||||
|
|
||||||
|
o Return Go templates in a specific repository
|
||||||
|
$ {{.Name}} templates go --repository=https://github.com/boson-project/func-templates
|
||||||
|
`,
|
||||||
|
SuggestFor: []string{"template", "templtaes", "templatse", "remplates",
|
||||||
|
"gemplates", "yemplates", "tenplates", "tekplates", "tejplates",
|
||||||
|
"temolates", "temllates", "temppates", "tempmates", "tempkates",
|
||||||
|
"templstes", "templztes", "templqtes", "templares", "templages", //nolint:misspell
|
||||||
|
"templayes", "templatee", "templatea", "templated", "templatew"},
|
||||||
|
PreRunE: bindEnv("json", "repository"),
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Flags().BoolP("json", "", false, "Set output to JSON format. (Env: $FUNC_JSON)")
|
||||||
|
cmd.Flags().StringP("repository", "r", "", "URI to a specific repository to consider (Env: $FUNC_REPOSITORY)")
|
||||||
|
|
||||||
|
cmd.SetHelpFunc(defaultTemplatedHelp)
|
||||||
|
|
||||||
|
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||||
|
return runTemplates(cmd, args, newClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTemplates(cmd *cobra.Command, args []string, newClient ClientFactory) (err error) {
|
||||||
|
// Gather config
|
||||||
|
cfg, err := newTemplatesConfig(newClient)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client which will provide data
|
||||||
|
client, done := newClient(ClientConfig{Verbose: cfg.Verbose},
|
||||||
|
fn.WithRepository(cfg.Repository), // Use exactly this repo OR
|
||||||
|
fn.WithRepositoriesPath(cfg.RepositoriesPath)) // Path on disk to installed repos
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
// For a singl language runtime
|
||||||
|
// -------------------
|
||||||
|
if len(args) == 1 {
|
||||||
|
templates, err := client.Templates().List(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cfg.JSON {
|
||||||
|
s, err := json.MarshalIndent(templates, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintln(cmd.OutOrStdout(), string(s))
|
||||||
|
} else {
|
||||||
|
for _, template := range templates {
|
||||||
|
fmt.Fprintln(cmd.OutOrStdout(), template)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else if len(args) > 1 {
|
||||||
|
return errors.New("unexpected extra arguments.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// All language runtimes
|
||||||
|
// ------------
|
||||||
|
runtimes, err := client.Runtimes()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cfg.JSON {
|
||||||
|
// Gather into a single data structure for printing as json
|
||||||
|
templateMap := make(map[string][]string)
|
||||||
|
for _, runtime := range runtimes {
|
||||||
|
templates, err := client.Templates().List(runtime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
templateMap[runtime] = templates
|
||||||
|
}
|
||||||
|
s, err := json.MarshalIndent(templateMap, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintln(cmd.OutOrStdout(), string(s))
|
||||||
|
} else {
|
||||||
|
// print using a formatted writer (sorted)
|
||||||
|
builder := strings.Builder{}
|
||||||
|
writer := tabwriter.NewWriter(&builder, 0, 0, 3, ' ', 0)
|
||||||
|
fmt.Fprint(writer, "LANGUAGE\tTEMPLATE\n")
|
||||||
|
for _, runtime := range runtimes {
|
||||||
|
templates, err := client.Templates().List(runtime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, template := range templates {
|
||||||
|
fmt.Fprintf(writer, "%v\t%v\n", runtime, template)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.Flush()
|
||||||
|
fmt.Fprint(cmd.OutOrStdout(), builder.String())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type templatesConfig struct {
|
||||||
|
Verbose bool
|
||||||
|
Repository string // Consider only a specific repository (URI)
|
||||||
|
RepositoriesPath string // Override location on disk of "installed" repos
|
||||||
|
JSON bool // output as JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTemplatesConfig(newClient ClientFactory) (cfg templatesConfig, err error) {
|
||||||
|
// Repositories Path
|
||||||
|
// Not exposed as a flag due to potential confusion with the more likely
|
||||||
|
// "repository" flag, but still available as an environment variable
|
||||||
|
repositoriesPath := os.Getenv("FUNC_REPOSITORIES_PATH")
|
||||||
|
if repositoriesPath == "" { // if no env var provided
|
||||||
|
repositoriesPath = fn.New().RepositoriesPath() // default to ~/.config/func/repositories
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg = templatesConfig{
|
||||||
|
Verbose: viper.GetBool("verbose"),
|
||||||
|
Repository: viper.GetString("repository"),
|
||||||
|
RepositoriesPath: repositoriesPath,
|
||||||
|
JSON: viper.GetBool("json"),
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
fn "knative.dev/kn-plugin-func"
|
||||||
|
. "knative.dev/kn-plugin-func/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestTemplates_Default ensures that the default behavior is listing all
|
||||||
|
// templates for all language runtimes.
|
||||||
|
func TestTemplates_Default(t *testing.T) {
|
||||||
|
defer WithEnvVar(t, "XDG_CONFIG_HOME", t.TempDir())() // ignore user-added
|
||||||
|
buf := piped(t) // gather output
|
||||||
|
cmd := NewTemplatesCmd(NewClientFactory(func() *fn.Client {
|
||||||
|
return fn.New()
|
||||||
|
}))
|
||||||
|
if err := cmd.Execute(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `LANGUAGE TEMPLATE
|
||||||
|
go cloudevents
|
||||||
|
go http
|
||||||
|
node cloudevents
|
||||||
|
node http
|
||||||
|
python cloudevents
|
||||||
|
python http
|
||||||
|
quarkus cloudevents
|
||||||
|
quarkus http
|
||||||
|
rust cloudevents
|
||||||
|
rust http
|
||||||
|
springboot cloudevents
|
||||||
|
springboot http
|
||||||
|
typescript cloudevents
|
||||||
|
typescript http`
|
||||||
|
output := buf()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatalf("expected:\n'%v'\n\ngot:\n'%v'\n", expected, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTemplates_JSON ensures that listing templates respects the --json
|
||||||
|
// output format.
|
||||||
|
func TestTemplates_JSON(t *testing.T) {
|
||||||
|
defer WithEnvVar(t, "XDG_CONFIG_HOME", t.TempDir())() // ignore user-added
|
||||||
|
buf := piped(t) // gather output
|
||||||
|
cmd := NewTemplatesCmd(NewClientFactory(func() *fn.Client {
|
||||||
|
return fn.New()
|
||||||
|
}))
|
||||||
|
cmd.SetArgs([]string{"--json"})
|
||||||
|
if err := cmd.Execute(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `{
|
||||||
|
"go": [
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"node": [
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"python": [
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"quarkus": [
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"rust": [
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"springboot": [
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"typescript": [
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
output := buf()
|
||||||
|
for i, c := range expected {
|
||||||
|
if len(output) <= i {
|
||||||
|
t.Fatalf("output missing character(s) '%v', '%s' and later\n", i, string(c))
|
||||||
|
}
|
||||||
|
if rune(output[i]) != c {
|
||||||
|
t.Fatalf("Character at index %v expected '%s', got '%s'\n", i, string(c), string(output[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if output != expected {
|
||||||
|
t.Fatalf("expected:\n%v\ngot:\n%v\n", expected, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTemplates_ByLanguage ensures that the output is correctly filtered
|
||||||
|
// by language runtime when provided.
|
||||||
|
func TestTemplates_ByLanguage(t *testing.T) {
|
||||||
|
defer WithEnvVar(t, "XDG_CONFIG_HOME", t.TempDir())() // ignore user-added
|
||||||
|
cmd := NewTemplatesCmd(NewClientFactory(func() *fn.Client {
|
||||||
|
return fn.New()
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Test plain text
|
||||||
|
buf := piped(t)
|
||||||
|
cmd.SetArgs([]string{"go"})
|
||||||
|
if err := cmd.Execute(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `cloudevents
|
||||||
|
http`
|
||||||
|
|
||||||
|
output := buf()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatalf("expected plain text:\n'%v'\ngot:\n'%v'\n", expected, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test JSON output
|
||||||
|
buf = piped(t)
|
||||||
|
cmd.SetArgs([]string{"go", "--json"})
|
||||||
|
if err := cmd.Execute(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = `[
|
||||||
|
"cloudevents",
|
||||||
|
"http"
|
||||||
|
]`
|
||||||
|
|
||||||
|
output = buf()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatalf("expected JSON:\n'%v'\ngot:\n'%v'\n", expected, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue