Skip to content

Commit 9db1a3d

Browse files
lkinglandlance
andauthored
feat: remote template repositories (#437)
* feat: remote template repositories * Update cmd/create.go Co-authored-by: Lance Ball <[email protected]> * docs: extensible templates * feat: remote template repositories * Update docs/guides/language-packs.md * Update docs/guides/language-packs.md Co-authored-by: Lance Ball <[email protected]> * Update docs/guides/language-packs.md Co-authored-by: Lance Ball <[email protected]> * Update docs/guides/templates.md Co-authored-by: Lance Ball <[email protected]> Co-authored-by: Lance Ball <[email protected]>
1 parent 0dba677 commit 9db1a3d

32 files changed

+401
-107
lines changed

Diff for: client.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Client struct {
3434
describer Describer
3535
dnsProvider DNSProvider // Provider of DNS services
3636
repositories string // path to extensible template repositories
37+
repository string // URL to Git repo (overrides on-disk and embedded)
3738
registry string // default registry for OCI image tags
3839
progressListener ProgressListener // progress listener
3940
emitter Emitter // Emits CloudEvents to functions
@@ -259,6 +260,15 @@ func WithRepositories(repositories string) Option {
259260
}
260261
}
261262

263+
// WithRepository sets a specific URL to a Git repository from which to pull templates.
264+
// This setting's existence precldes the use of either the inbuilt templates or any
265+
// repositories from the extensible repositories path.
266+
func WithRepository(repository string) Option {
267+
return func(c *Client) {
268+
c.repository = repository
269+
}
270+
}
271+
262272
// WithRegistry sets the default registry which is consulted when an image name/tag
263273
// is not explocitly provided. Can be fully qualified, including the registry
264274
// (ex: 'quay.io/myname') or simply the namespace 'myname' which indicates the
@@ -342,7 +352,8 @@ func (c *Client) Create(cfg Function) (err error) {
342352
return
343353
}
344354

345-
// Create Function of the given root path.
355+
// Create Function about the given root path.
356+
// Loads extant config if it exists. In-memory representation only.
346357
f, err := NewFunction(cfg.Root)
347358
if err != nil {
348359
return
@@ -371,7 +382,7 @@ func (c *Client) Create(cfg Function) (err error) {
371382
}
372383

373384
// Write out a template.
374-
w := templateWriter{templates: c.repositories, verbose: c.verbose}
385+
w := templateWriter{repositories: c.repositories, url: c.repository, verbose: c.verbose}
375386
if err = w.Write(f.Runtime, f.Template, f.Root); err != nil {
376387
return
377388
}

Diff for: cmd/create.go

+35-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"fmt"
5+
"os"
56
"path/filepath"
67

78
"github.com/AlecAivazis/survey/v2"
@@ -27,6 +28,7 @@ func init() {
2728
func newCreateClient(cfg createConfig) *fn.Client {
2829
return fn.New(
2930
fn.WithRepositories(cfg.Repositories),
31+
fn.WithRepository(cfg.Repository),
3032
fn.WithVerbose(cfg.Verbose))
3133
}
3234

@@ -58,13 +60,13 @@ kn func create --runtime quarkus myfunc
5860
kn func create --template events myfunc
5961
`,
6062
SuggestFor: []string{"vreate", "creaet", "craete", "new"},
61-
PreRunE: bindEnv("runtime", "template", "repositories", "confirm"),
63+
PreRunE: bindEnv("runtime", "template", "repository", "confirm"),
6264
}
6365

6466
cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
6567
cmd.Flags().StringP("runtime", "l", fn.DefaultRuntime, "Function runtime language/framework. Available runtimes: "+buildpacks.Runtimes()+" (Env: $FUNC_RUNTIME)")
66-
cmd.Flags().StringP("repositories", "r", filepath.Join(configPath(), "repositories"), "Path to extended template repositories (Env: $FUNC_REPOSITORIES)")
6768
cmd.Flags().StringP("template", "t", fn.DefaultTemplate, "Function template. Available templates: 'http' and 'events' (Env: $FUNC_TEMPLATE)")
69+
cmd.Flags().StringP("repository", "r", "", "URI to a Git repository containing the specified template (Env: $FUNC_REPOSITORY)")
6870

6971
// Register tab-completeion function integration
7072
if err := cmd.RegisterFlagCompletionFunc("runtime", CompleteRuntimeList); err != nil {
@@ -117,11 +119,16 @@ type createConfig struct {
117119
Runtime string
118120

119121
// Repositories is an optional path that, if it exists, will be used as a source
120-
// for additional template repositories not included in the binary. If not provided
121-
// explicitly as a flag (--repositories) or env (FUNC_REPOSITORIES), the default
122-
// location is $XDG_CONFIG_HOME/repositories ($HOME/.config/func/repositories)
122+
// for additional template repositories not included in the binary. provided via
123+
// env (FUNC_REPOSITORIES), the default location is $XDG_CONFIG_HOME/repositories
124+
// ($HOME/.config/func/repositories)
123125
Repositories string
124126

127+
// Repository is the URL of a specific Git repository to use for templates.
128+
// If specified, this takes precidence over both inbuilt templates or
129+
// extensible templates.
130+
Repository string
131+
125132
// Template is the code written into the new Function project, including
126133
// an implementation adhering to one of the supported function signatures.
127134
// May also include additional configuration settings or examples.
@@ -148,15 +155,24 @@ func newCreateConfig(args []string) createConfig {
148155
}
149156

150157
derivedName, derivedPath := deriveNameAndAbsolutePathFromPath(path)
151-
return createConfig{
152-
Name: derivedName,
153-
Path: derivedPath,
154-
Repositories: viper.GetString("repositories"),
155-
Runtime: viper.GetString("runtime"),
156-
Template: viper.GetString("template"),
157-
Confirm: viper.GetBool("confirm"),
158-
Verbose: viper.GetBool("verbose"),
158+
cc := createConfig{
159+
Name: derivedName,
160+
Path: derivedPath,
161+
Repository: viper.GetString("repository"),
162+
Runtime: viper.GetString("runtime"),
163+
Template: viper.GetString("template"),
164+
Confirm: viper.GetBool("confirm"),
165+
Verbose: viper.GetBool("verbose"),
166+
}
167+
168+
// Repositories not exposed as a flag due to potential confusion and
169+
// unlikliness of being needed, but is left available as an env.
170+
cc.Repositories = os.Getenv("FUNC_REPOSITORIES")
171+
if cc.Repositories == "" {
172+
cc.Repositories = filepath.Join(configPath(), "repositories")
159173
}
174+
175+
return cc
160176
}
161177

162178
// Prompt the user with value of config members, allowing for interaractive changes.
@@ -165,10 +181,13 @@ func newCreateConfig(args []string) createConfig {
165181
func (c createConfig) Prompt() (createConfig, error) {
166182
if !interactiveTerminal() || !c.Confirm {
167183
// Just print the basics if not confirming
168-
fmt.Printf("Project path: %v\n", c.Path)
184+
fmt.Printf("Project path: %v\n", c.Path)
169185
fmt.Printf("Function name: %v\n", c.Name)
170-
fmt.Printf("Runtime: %v\n", c.Runtime)
171-
fmt.Printf("Template: %v\n", c.Template)
186+
fmt.Printf("Runtime: %v\n", c.Runtime)
187+
fmt.Printf("Template: %v\n", c.Template)
188+
if c.Repository != "" {
189+
fmt.Printf("Repository: %v\n", c.Repository)
190+
}
172191
return c, nil
173192
}
174193

Diff for: docs/guides/commands.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ Creates a new Function project at _`path`_. If _`path`_ is unspecified, assumes
66

77
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])?').
88

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.
10+
911
Similar `kn` command: none.
1012

1113
```console
12-
func create <path> [-l <runtime> -t <template>]
14+
func create <path> [-l <runtime> -t <template> -r <repository>]
1315
```
1416

1517
When run as a `kn` plugin.
1618

1719
```console
18-
kn func create <path> [-l <runtime> -t <template>]
20+
kn func create <path> [-l <runtime> -t <template> -r <repository>]
1921
```
2022

2123
## `build`

Diff for: docs/guides/language-packs.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Language Packs
2+
3+
A Language Pack is the mechanism by which the Functions binary can be extended to support additional runtimes, function signatures, even operating systems and installed tooling for a function. A Language Pack includes
4+
- a .builders.yaml file containing a reference to a builder OCI image reference, which conforms to the buildpack builder specification, and contains references to buildpacks supporting this Language Pack
5+
- one or more template directories illustrating the Language Pack's recognized function signatures
6+
- tests and documentation for the templates
7+
8+
Built in to the Functions library is a basic language pack for each supported language.
9+
10+
For an example external language pack, see [https://github.com/lance/gcf-kn/tree/main/ruby]

Diff for: docs/guides/templates.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Templates
2+
3+
When a Function is created, an example implementation and a Function metadata file are written into the new Function's working directory. Together, these files are referred to as the Function's Template. Included are the templates 'http' and 'events' for each supported language runtime.
4+
5+
These embedded templates are minimal by design. The Function contains a minimum of external dependencies, and the 'func.yaml' defines a final environment within which the Funciton will execute that is devoid of any extraneous packages or services.
6+
7+
To make use of more complex inital Function implementions, or to define runtime environments with arbitrarily complex requirements, the templates system is fully pluggable.
8+
9+
## External Git Repositories
10+
11+
When creating a new Function, a Git repository can be specified as the source for the template files. For example, the Boson Project maintains a set of example Functions at https://github.com/boson-project/templates which can be used during project creation.
12+
13+
For example, the Boson Project Templates repository contains an example "Hello World" Function implementation in each of the officially supported languages. To use this template via the CLI, use the flags:
14+
15+
func create <name> --template hello-world --repository https://github.com/boson-project/templates
16+
17+
## Locally Installing Repositories
18+
19+
Template Repositories can also be installed locally by placing them in the Functions configuration directory.
20+
21+
To install the Boson Project templates locally, for example, clone the repository and name it `boson` using `git clone https://github.com/boson-project/templats ~/.config/func/repositories/boson`
22+
23+
Once installed, the Boson Hello World template can be specified:
24+
25+
func create <name> --template boson/hello-world
26+
27+
## Language Packs
28+
29+
In addition to example implementations, a template includes a `func.yaml` which includes metadata about the Function. By default this is populated with things like the new Function's name. It also includes a reference to the specific tooling which compiles and packages the Function into its deployable form. This is called the Builder. By customizing this metadata, it is more than just a template; it is referred to as a Language Pack. See [Project Configuration with func.yaml](func_yaml.md).
30+
31+
A Language Pack can support additional function signatures and can fully customize the environment of the final running Function. For more information see the [Language Pack Guide](language-packs.md).
32+
33+
34+
35+
36+
37+
38+
39+
40+

Diff for: go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ require (
1010
github.com/docker/docker v20.10.7+incompatible
1111
github.com/docker/docker-credential-helpers v0.6.4
1212
github.com/docker/go-connections v0.4.0
13+
github.com/go-git/go-billy/v5 v5.3.1
14+
github.com/go-git/go-git/v5 v5.4.2
1315
github.com/google/go-cmp v0.5.6
1416
github.com/google/uuid v1.2.0
1517
github.com/markbates/pkger v0.17.1

0 commit comments

Comments
 (0)