knative/func

Proposal: use Golang templating to write `func.yaml`

zroubalik opened this issue · 1 comments

Currently yaml.Marshal() & os.WriteFile() is used to write a Function configuration to disk. It is a convenient way to handle Golang structures, but it has one major drawback - we are unable to write comments to the file. Comments are useful as we can explain the fields, add examples, defaults etc. We can even write the whole configuration to the file, just comment the fields that are not used and users can easily uncomment them if they want to use them (for example the whole options part would benefit from this).

// Write Function struct (metadata) to Disk at f.Root
func (f Function) Write() (err error) {
// Skip writing (and dirtying the work tree) if there were no modifications.
f1, _ := NewFunction(f.Root)
if reflect.DeepEqual(f, f1) {
return
}
// Do not write invalid functions
if err = f.Validate(); err != nil {
return
}
// Write
var bb []byte
if bb, err = yaml.Marshal(&f); err != nil {
return
}
// TODO: open existing file for writing, such that existing permissions
// are preserved?
return os.WriteFile(filepath.Join(f.Root, FunctionFile), bb, 0644)
}

I have been thinking how to solve this for some time and there's option that could be potentially used - Golang built in templating from text/template package. Something like this:

type funcTemplateData struct {
	FunctionName   string
	FunctionRuntime  string
	FunctionRegistry  string
	FunctionImage  string
	FunctionType  string
        ...
}

func (f Function) Write() (err error) { 

funcYamlTemplate :=`
specVersion: 0.35.0
name: {{.FunctionName}}
runtime: {{.FunctionRuntime}}
registry: {{.FunctionRegistry}}
image: {{.FunctionImage}}

# my comment
invoke: {{.FunctionType}}

# another Comment
...
`

var funcData funcTemplateData

// this would set all the values that are set in the Function struct and fill defaults for the rest
funcData = f.GetValuesOrDefaults()

tmpl, err := template.New("func.yaml").Parse(funcYamlTemplate)
file, err := os.Create(projectRoot+"func.yaml")

return tmpl.Execute(file, funcData)
}

The same approach is used for Tekton Pipeline templates:
https://github.com/knative/func/blob/main/pkg/pipelines/tekton/templates_pack.go
https://github.com/knative/func/blob/main/pkg/pipelines/tekton/templates.go#L165

To read the function config, we can use the same apporach we have now, we just need to change the write function. This solution is obviously much harder to implement (dealing with yamls this way is a pain). But it could give us the benefit of adding some comments&examples on the file. Obviously this apporach still doesn't allow users to write their own comments, but at least something. Or maybe it is now worth the work 🤷‍♂️