Skip to content

Latest commit

 

History

History
129 lines (82 loc) · 4.68 KB

A003-generator-framework.md

File metadata and controls

129 lines (82 loc) · 4.68 KB

A003: Generator Framework

  • Author(s): @yufeiminds
  • Approver: @yufeiminds
  • Status: Implemented
  • Last updated: 2023-03-06
  • Discussion at: #1

Abstract

This proposal describes a solution to generate artifacts about resources and provide a unified way to do the following things:

  1. Define the template as a CUE package. Declare the definition of the template as a CUE package. Includes the template name, description, parameters, output, etc.
  2. Testing template use snapshot way. Provide a snapshot testing method to test the template.
  3. Create an engine to generate code. Create an engine to generate code from the template and the RMS.

Background

Related Proposals:

Proposal

Template Definition

Template Schema

The core design:

  • The inputs are the RMS package and CLI options collected by OpenRMS CLI.
  • The outputs are the artifacts would be generated by the template.
  • The diagnostic is errors would be raised when the template is rendered. It provides an error-handling mechanism for generating.

The syntax details can be found on CUE Lang.

Template Discovering

Because the template is a CUE package, we can use the CUE package discovery mechanism to discover the template. We recommend hosting the package on GitHub.

More details of CUE package discovery can be found on CUE Package Discovering.

Template Testing

The template testing is snapshot testing. We should provide built-in test inputs (petstore RMS package), implement a test-case discovery and snapshot diff mechanism, and help the template developer to write the test case quickly.

When a template developer creates a new template, the developer should write the test case. When a template snapshot testing is running, the following steps will be executed:

Template Testing

Rationale

  1. Why use CUE as the template language?

Because CUE has a great programmatic API and a powerful type system, it can help us to validate the template, process the data in compile-time, and make the snippet re-useable by the package management tool.

Solutions comparasion:

  • Instead of using a pure-template solution (such as a pure go template), CUE can inject custom data processing logic. We don't need to write the same logic repeatedly in a general-purpose programming language.
  • Instead of using a pure-programming solution (such as pure go code), CUE can provide a unified way to define the template. It can help the template developer focus on the template logic without understanding the input DSL's Abstract Syntax Tree (AST).
  1. Why use snapshot testing?

Because it's easy to write and maintain, snapshot testing is a common way to test the template. Unlike the unit test, snapshot testing can test the template outputs. It's more suitable for template testing. It can also fit the user's expectations.

Implementation

Suppose the resource developer creates a new template, such as Terraform. The template may be like the following:

  1. Declare required properties

Create terraform/manifest.cue as the template package manifest:

package terraform

import (
	template "github.com/GuanceCloud/iacker/pkg/template/v1"
)

inputs: template.#Inputs

diagnostics: [...template.#Diagnostic]

outputs: template.#Outputs

This snippet will import the built-in type annotation from the core package and validate the template's value types. It will help the template developer to write the correct template.

  1. Define the template

Create terraform/template.cue as the template package manifest:

package terraform

import (
	"strings"
	gotemplate "text/template"

	template "github.com/GuanceCloud/iacker/pkg/template/v1"
)

_templates: """
package {{ .lowername }}

// {{ .camelname }} holds the schema definition for the {{ .camelname }} entity.
type {{ .camelname }} struct {
    // some fields
}
"""

for rsname, rs in inputs.resources {
	outputs: files: "\(strings.ToLower(rsname)).go": template.#File & {
		content: gotemplate.Execute(_templates, {
			lowername: strings.ToLower(rsname),
			camelname: rsname,
			v: rs,
		})
	}
}
  1. Define the snapshot

Create terraform/snapshot/petstore as the template snapshot folder. The test engine will diff the template outputs with files in this folder.

More examples can be found on template folder.