From 9db1a3d902016d59e60b732de43bdf4be198334f Mon Sep 17 00:00:00 2001 From: Luke Kingland <58986931+lkingland@users.noreply.github.com> Date: Tue, 3 Aug 2021 22:28:15 +0900 Subject: [PATCH] feat: remote template repositories (#437) * feat: remote template repositories * Update cmd/create.go Co-authored-by: Lance Ball * docs: extensible templates * feat: remote template repositories * Update docs/guides/language-packs.md * Update docs/guides/language-packs.md Co-authored-by: Lance Ball * Update docs/guides/language-packs.md Co-authored-by: Lance Ball * Update docs/guides/templates.md Co-authored-by: Lance Ball Co-authored-by: Lance Ball --- client.go | 15 +- cmd/create.go | 51 ++-- docs/guides/commands.md | 6 +- docs/guides/language-packs.md | 10 + docs/guides/templates.md | 40 +++ go.mod | 2 + go.sum | 33 +++ templates.go | 254 ++++++++++++------ templates_test.go | 40 ++- testdata/README.md | 23 ++ testdata/repository.git/HEAD | 1 + testdata/repository.git/config | 6 + testdata/repository.git/description | 1 + testdata/repository.git/hooks/post-update | 8 + testdata/repository.git/info/exclude | 6 + testdata/repository.git/info/refs | 5 + .../25/128199189ce87956e5e41fa8113bbf5cb6c39a | Bin 0 -> 83 bytes .../43/0739f6d9930f74a6aef1a410f0f0727d171cef | Bin 0 -> 56 bytes .../67/00ea8078422674e91189c1b513d1ab0696b150 | Bin 0 -> 783 bytes .../8b/57110b1cc8f2019ca4b2ed51a450ee0873eaaf | 3 + .../98/68959b2b456ac7767bf351a84b369f9fbadb3a | Bin 0 -> 790 bytes .../9a/c29c7ad8c06fa6613b794521568fbd7ea007dd | Bin 0 -> 787 bytes .../b7/5832d0a4a4bb0409cca573b2c97b017d088f90 | Bin 0 -> 48 bytes .../c7/e84596af04680b8e7a39b9a527f19ccd75f287 | Bin 0 -> 466 bytes .../ca/1a6296f97eced6c9497d05598ef508852cac5d | Bin 0 -> 83 bytes .../ca/5019f945b1d769d042c5f87d39f5d7a15f290c | Bin 0 -> 60 bytes .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin 0 -> 15 bytes testdata/repository.git/objects/info/packs | 1 + testdata/repository.git/packed-refs | 2 + .../repository.git/refs/heads/.gitinclude | 0 testdata/repository.git/refs/heads/main | 1 + testdata/repository.git/refs/tags/.gitinclude | 0 32 files changed, 401 insertions(+), 107 deletions(-) create mode 100644 docs/guides/language-packs.md create mode 100644 docs/guides/templates.md create mode 100644 testdata/repository.git/HEAD create mode 100644 testdata/repository.git/config create mode 100644 testdata/repository.git/description create mode 100755 testdata/repository.git/hooks/post-update create mode 100644 testdata/repository.git/info/exclude create mode 100644 testdata/repository.git/info/refs create mode 100644 testdata/repository.git/objects/25/128199189ce87956e5e41fa8113bbf5cb6c39a create mode 100644 testdata/repository.git/objects/43/0739f6d9930f74a6aef1a410f0f0727d171cef create mode 100644 testdata/repository.git/objects/67/00ea8078422674e91189c1b513d1ab0696b150 create mode 100644 testdata/repository.git/objects/8b/57110b1cc8f2019ca4b2ed51a450ee0873eaaf create mode 100644 testdata/repository.git/objects/98/68959b2b456ac7767bf351a84b369f9fbadb3a create mode 100644 testdata/repository.git/objects/9a/c29c7ad8c06fa6613b794521568fbd7ea007dd create mode 100644 testdata/repository.git/objects/b7/5832d0a4a4bb0409cca573b2c97b017d088f90 create mode 100644 testdata/repository.git/objects/c7/e84596af04680b8e7a39b9a527f19ccd75f287 create mode 100644 testdata/repository.git/objects/ca/1a6296f97eced6c9497d05598ef508852cac5d create mode 100644 testdata/repository.git/objects/ca/5019f945b1d769d042c5f87d39f5d7a15f290c create mode 100644 testdata/repository.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 create mode 100644 testdata/repository.git/objects/info/packs create mode 100644 testdata/repository.git/packed-refs create mode 100644 testdata/repository.git/refs/heads/.gitinclude create mode 100644 testdata/repository.git/refs/heads/main create mode 100644 testdata/repository.git/refs/tags/.gitinclude diff --git a/client.go b/client.go index 5f640a0060..93ca08dae7 100644 --- a/client.go +++ b/client.go @@ -34,6 +34,7 @@ type Client struct { describer Describer dnsProvider DNSProvider // Provider of DNS services repositories string // path to extensible template repositories + repository string // URL to Git repo (overrides on-disk and embedded) registry string // default registry for OCI image tags progressListener ProgressListener // progress listener emitter Emitter // Emits CloudEvents to functions @@ -259,6 +260,15 @@ func WithRepositories(repositories string) Option { } } +// WithRepository sets a specific URL to a Git repository from which to pull templates. +// This setting's existence precldes the use of either the inbuilt templates or any +// repositories from the extensible repositories path. +func WithRepository(repository string) Option { + return func(c *Client) { + c.repository = repository + } +} + // WithRegistry sets the default registry which is consulted when an image name/tag // is not explocitly provided. Can be fully qualified, including the registry // (ex: 'quay.io/myname') or simply the namespace 'myname' which indicates the @@ -342,7 +352,8 @@ func (c *Client) Create(cfg Function) (err error) { return } - // Create Function of the given root path. + // Create Function about the given root path. + // Loads extant config if it exists. In-memory representation only. f, err := NewFunction(cfg.Root) if err != nil { return @@ -371,7 +382,7 @@ func (c *Client) Create(cfg Function) (err error) { } // Write out a template. - w := templateWriter{templates: c.repositories, verbose: c.verbose} + w := templateWriter{repositories: c.repositories, url: c.repository, verbose: c.verbose} if err = w.Write(f.Runtime, f.Template, f.Root); err != nil { return } diff --git a/cmd/create.go b/cmd/create.go index f523ed7e02..3ae3fa6636 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "os" "path/filepath" "github.com/AlecAivazis/survey/v2" @@ -27,6 +28,7 @@ func init() { func newCreateClient(cfg createConfig) *fn.Client { return fn.New( fn.WithRepositories(cfg.Repositories), + fn.WithRepository(cfg.Repository), fn.WithVerbose(cfg.Verbose)) } @@ -58,13 +60,13 @@ kn func create --runtime quarkus myfunc kn func create --template events myfunc `, SuggestFor: []string{"vreate", "creaet", "craete", "new"}, - PreRunE: bindEnv("runtime", "template", "repositories", "confirm"), + PreRunE: bindEnv("runtime", "template", "repository", "confirm"), } cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)") cmd.Flags().StringP("runtime", "l", fn.DefaultRuntime, "Function runtime language/framework. Available runtimes: "+buildpacks.Runtimes()+" (Env: $FUNC_RUNTIME)") - cmd.Flags().StringP("repositories", "r", filepath.Join(configPath(), "repositories"), "Path to extended template repositories (Env: $FUNC_REPOSITORIES)") cmd.Flags().StringP("template", "t", fn.DefaultTemplate, "Function template. Available templates: 'http' and 'events' (Env: $FUNC_TEMPLATE)") + cmd.Flags().StringP("repository", "r", "", "URI to a Git repository containing the specified template (Env: $FUNC_REPOSITORY)") // Register tab-completeion function integration if err := cmd.RegisterFlagCompletionFunc("runtime", CompleteRuntimeList); err != nil { @@ -117,11 +119,16 @@ type createConfig struct { Runtime string // Repositories is an optional path that, if it exists, will be used as a source - // for additional template repositories not included in the binary. If not provided - // explicitly as a flag (--repositories) or env (FUNC_REPOSITORIES), the default - // location is $XDG_CONFIG_HOME/repositories ($HOME/.config/func/repositories) + // for additional template repositories not included in the binary. provided via + // env (FUNC_REPOSITORIES), the default location is $XDG_CONFIG_HOME/repositories + // ($HOME/.config/func/repositories) Repositories string + // Repository is the URL of a specific Git repository to use for templates. + // If specified, this takes precidence over both inbuilt templates or + // extensible templates. + Repository string + // Template is the code written into the new Function project, including // an implementation adhering to one of the supported function signatures. // May also include additional configuration settings or examples. @@ -148,15 +155,24 @@ func newCreateConfig(args []string) createConfig { } derivedName, derivedPath := deriveNameAndAbsolutePathFromPath(path) - return createConfig{ - Name: derivedName, - Path: derivedPath, - Repositories: viper.GetString("repositories"), - Runtime: viper.GetString("runtime"), - Template: viper.GetString("template"), - Confirm: viper.GetBool("confirm"), - Verbose: viper.GetBool("verbose"), + cc := createConfig{ + Name: derivedName, + Path: derivedPath, + Repository: viper.GetString("repository"), + Runtime: viper.GetString("runtime"), + Template: viper.GetString("template"), + Confirm: viper.GetBool("confirm"), + Verbose: viper.GetBool("verbose"), + } + + // Repositories not exposed as a flag due to potential confusion and + // unlikliness of being needed, but is left available as an env. + cc.Repositories = os.Getenv("FUNC_REPOSITORIES") + if cc.Repositories == "" { + cc.Repositories = filepath.Join(configPath(), "repositories") } + + return cc } // Prompt the user with value of config members, allowing for interaractive changes. @@ -165,10 +181,13 @@ func newCreateConfig(args []string) createConfig { func (c createConfig) Prompt() (createConfig, error) { if !interactiveTerminal() || !c.Confirm { // Just print the basics if not confirming - fmt.Printf("Project path: %v\n", c.Path) + fmt.Printf("Project path: %v\n", c.Path) fmt.Printf("Function name: %v\n", c.Name) - fmt.Printf("Runtime: %v\n", c.Runtime) - fmt.Printf("Template: %v\n", c.Template) + fmt.Printf("Runtime: %v\n", c.Runtime) + fmt.Printf("Template: %v\n", c.Template) + if c.Repository != "" { + fmt.Printf("Repository: %v\n", c.Repository) + } return c, nil } diff --git a/docs/guides/commands.md b/docs/guides/commands.md index 5bcfd1f6c4..457f5a71e2 100644 --- a/docs/guides/commands.md +++ b/docs/guides/commands.md @@ -6,16 +6,18 @@ Creates a new Function project at _`path`_. If _`path`_ is unspecified, assumes Function name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'). +The files written upon create include an example Function of the specified language runtime, example tests, and a metadata file `func.yaml`. Together, these are referred to as a Template. Included are the templates 'http' and 'events' (default is 'http') for each language runtime. A template can be pulled from a specific Git repository by providing the `--repository` flag, or from a locally installed repository using the repository's name as a prefix. See the [Templates Guide](templates.md) for more information. + Similar `kn` command: none. ```console -func create [-l -t