Kindsys: Remove Raw kind category (#60992)

* Remove Raw references

* Remove more raws

* Re-generate files

* Remove raw folder from veneer

* Fix import

* Fix lint

* Bring back raw folder in grafana-schema

* Another lint

* Remove use of "Structured" word in kinds

* Delete unused function and remove some structured words

* Bunch more removals of structured name

Co-authored-by: sam boyer <sdboyer@grafana.com>
pull/61068/head
Selene 3 years ago committed by GitHub
parent db369fc5b2
commit 8f29450594
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      embed.go
  2. 4
      kinds/constraint.cue
  3. 0
      kinds/dashboard/dashboard_kind.cue
  4. 39
      kinds/gen.go
  5. 0
      kinds/playlist/playlist_kind.cue
  6. 4
      kinds/raw/svg/svg_kind.cue
  7. 8
      kinds/structured/constraint.cue
  8. 0
      kinds/team/team_kind.cue
  9. 23
      pkg/codegen/generators.go
  10. 10
      pkg/codegen/jenny_basecorereg.go
  11. 26
      pkg/codegen/jenny_corekind.go
  12. 3
      pkg/codegen/jenny_eachmajor.go
  13. 68
      pkg/codegen/jenny_rawkind.go
  14. 4
      pkg/codegen/jenny_tsveneerindex.go
  15. 3
      pkg/codegen/latest_jenny.go
  16. 8
      pkg/codegen/tmpl.go
  17. 12
      pkg/codegen/tmpl/kind_core.tmpl
  18. 57
      pkg/codegen/tmpl/kind_raw.tmpl
  19. 12
      pkg/codegen/tmpl/kind_registry.tmpl
  20. 14
      pkg/kinds/dashboard/dashboard_kind_gen.go
  21. 14
      pkg/kinds/playlist/playlist_kind_gen.go
  22. 64
      pkg/kinds/svg/svg_kind_gen.go
  23. 14
      pkg/kinds/team/team_kind_gen.go
  24. 3
      pkg/kindsys/EXTENDING.md
  25. 14
      pkg/kindsys/kind.go
  26. 15
      pkg/kindsys/kindcat_custom.cue
  27. 85
      pkg/kindsys/kindcats.cue
  28. 46
      pkg/kindsys/kindmetas.go
  29. 58
      pkg/kindsys/load.go
  30. 14
      pkg/kindsys/report.go
  31. 13
      pkg/kindsys/report.json
  32. 2
      pkg/plugins/manager/testdata/disallowed-cue-import/models.cue
  33. 35
      pkg/registry/corekind/base.go
  34. 34
      pkg/registry/corekind/base_gen.go

@ -6,5 +6,5 @@ import (
// CueSchemaFS embeds all schema-related CUE files in the Grafana project.
//
//go:embed cue.mod/module.cue kinds/*/*.cue kinds/*/*/*.cue packages/grafana-schema/src/schema/*.cue public/app/plugins/*/*/*.cue public/app/plugins/*/*/plugin.json pkg/kindsys/*.cue pkg/plugins/plugindef/*.cue
//go:embed cue.mod/module.cue kinds/*.cue kinds/*/*.cue packages/grafana-schema/src/schema/*.cue public/app/plugins/*/*/*.cue public/app/plugins/*/*/plugin.json pkg/kindsys/*.cue pkg/plugins/plugindef/*.cue
var CueSchemaFS embed.FS

@ -3,5 +3,5 @@ package kind
import "github.com/grafana/grafana/pkg/kindsys"
// In each child directory, the set of .cue files with 'package kind'
// must be an instance of kindsys.#Raw - a declaration of a raw kind.
kindsys.#Raw
// must be an instance of kindsys.#Core - a declaration of a core kind.
kindsys.#Core

@ -28,7 +28,7 @@ func main() {
}
// Core kinds composite code generator. Produces all generated code in
// grafana/grafana that derives from raw and structured core kinds.
// grafana/grafana that derives from core kinds.
coreKindsGen := codejen.JennyListWithNamer(func(decl *codegen.DeclForGen) string {
return decl.Properties.Common().MachineName
})
@ -36,8 +36,7 @@ func main() {
// All the jennies that comprise the core kinds generator pipeline
coreKindsGen.Append(
codegen.LatestJenny(kindsys.GoCoreKindParentPath, codegen.GoTypesJenny{}),
codegen.CoreStructuredKindJenny(kindsys.GoCoreKindParentPath, nil),
codegen.RawKindJenny(kindsys.GoCoreKindParentPath, nil),
codegen.CoreKindJenny(kindsys.GoCoreKindParentPath, nil),
codegen.BaseCoreRegistryJenny(filepath.Join("pkg", "registry", "corekind"), kindsys.GoCoreKindParentPath),
codegen.LatestMajorsOrXJenny(kindsys.TSCoreKindParentPath, codegen.TSTypesJenny{}),
codegen.TSVeneerIndexJenny(filepath.Join("packages", "grafana-schema", "src")),
@ -55,15 +54,14 @@ func main() {
rt := cuectx.GrafanaThemaRuntime()
var all []*codegen.DeclForGen
// structured kinddirs first
f := os.DirFS(filepath.Join(groot, kindsys.CoreStructuredDeclParentPath))
kinddirs := elsedie(fs.ReadDir(f, "."))("error reading structured fs root directory")
f := os.DirFS(filepath.Join(groot, kindsys.CoreDeclParentPath))
kinddirs := elsedie(fs.ReadDir(f, "."))("error reading core kind fs root directory")
for _, ent := range kinddirs {
if !ent.IsDir() {
continue
}
rel := filepath.Join(kindsys.CoreStructuredDeclParentPath, ent.Name())
decl, err := kindsys.LoadCoreKind[kindsys.CoreStructuredProperties](rel, rt.Context(), nil)
rel := filepath.Join(kindsys.CoreDeclParentPath, ent.Name())
decl, err := kindsys.LoadCoreKind(rel, rt.Context(), nil)
if err != nil {
die(fmt.Errorf("%s is not a valid kind: %s", rel, errors.Details(err, nil)))
}
@ -74,25 +72,6 @@ func main() {
all = append(all, elsedie(codegen.ForGen(rt, decl.Some()))(rel))
}
// now raw kinddirs
f = os.DirFS(filepath.Join(groot, kindsys.RawDeclParentPath))
kinddirs = elsedie(fs.ReadDir(f, "."))("error reading raw fs root directory")
for _, ent := range kinddirs {
if !ent.IsDir() {
continue
}
rel := filepath.Join(kindsys.RawDeclParentPath, ent.Name())
decl, err := kindsys.LoadCoreKind[kindsys.RawProperties](rel, rt.Context(), nil)
if err != nil {
die(fmt.Errorf("%s is not a valid kind: %s", rel, errors.Details(err, nil)))
}
if decl.Properties.MachineName != ent.Name() {
die(fmt.Errorf("%s: kind's machine name (%s) must equal parent dir name (%s)", rel, decl.Properties.Name, ent.Name()))
}
dfg, _ := codegen.ForGen(nil, decl.Some())
all = append(all, dfg)
}
sort.Slice(all, func(i, j int) bool {
return nameFor(all[i].Properties) < nameFor(all[j].Properties)
})
@ -113,11 +92,9 @@ func main() {
func nameFor(m kindsys.SomeKindProperties) string {
switch x := m.(type) {
case kindsys.RawProperties:
return x.Name
case kindsys.CoreStructuredProperties:
case kindsys.CoreProperties:
return x.Name
case kindsys.CustomStructuredProperties:
case kindsys.CustomProperties:
return x.Name
case kindsys.ComposableProperties:
return x.Name

@ -1,4 +0,0 @@
package kind
name: "SVG"
extensions: ["svg"]

@ -1,8 +0,0 @@
package kind
import "github.com/grafana/grafana/pkg/kindsys"
// In each child directory, the set of .cue files with 'package kind'
// must be an instance of kindsys.#CoreStructured - a declaration of a
// structured kind.
kindsys.#CoreStructured

@ -29,29 +29,6 @@ func ForGen(rt *thema.Runtime, decl *kindsys.SomeDecl) (*DeclForGen, error) {
}, nil
}
// RawForGen produces a [DeclForGen] from a [kindsys.Raw] kind.
//
// Useful for grafana-external code generators, which depend on the Kind
// representation in registries produced by grafana core (such as
// ["github.com/grafana/grafana/pkg/registry/corekind".NewBase]).
func RawForGen(k kindsys.Raw) *DeclForGen {
return &DeclForGen{
SomeDecl: k.Decl().Some(),
}
}
// StructuredForGen produces a [DeclForGen] from a [kindsys.Structured] kind.
//
// Useful for grafana-external code generators, which depend on the Kind
// representation in registries produced by grafana core (such as
// ["github.com/grafana/grafana/pkg/registry/corekind".NewBase]).
func StructuredForGen(k kindsys.Structured) *DeclForGen {
return &DeclForGen{
SomeDecl: k.Decl().Some(),
lin: k.Lineage(),
}
}
// DeclForGen wraps [kindsys.SomeDecl] to provide trivial caching of
// the lineage declared by the kind (nil for raw kinds).
type DeclForGen struct {

@ -32,17 +32,9 @@ func (gen *genBaseRegistry) JennyName() string {
}
func (gen *genBaseRegistry) Generate(decls ...*DeclForGen) (*codejen.File, error) {
var numRaw int
for _, k := range decls {
if k.IsRaw() {
numRaw++
}
}
buf := new(bytes.Buffer)
if err := tmpls.Lookup("kind_registry.tmpl").Execute(buf, tvars_kind_registry{
NumRaw: numRaw,
NumStructured: len(decls) - numRaw,
NumStructured: len(decls),
PackageName: filepath.Base(gen.path),
KindPackagePrefix: filepath.ToSlash(filepath.Join("github.com/grafana/grafana", gen.kindrelroot)),
Kinds: decls,

@ -8,14 +8,14 @@ import (
"github.com/grafana/codejen"
)
// CoreStructuredKindJenny generates the implementation of
// [kindsys.Structured] for the provided kind declaration.
// CoreKindJenny generates the implementation of [kindsys.Core] for the provided
// kind declaration.
//
// gokindsdir should be the relative path to the parent directory that contains
// all generated kinds.
//
// This generator only has output for core structured kinds.
func CoreStructuredKindJenny(gokindsdir string, cfg *CoreStructuredKindGeneratorConfig) OneToOne {
func CoreKindJenny(gokindsdir string, cfg *CoreStructuredKindGeneratorConfig) OneToOne {
if cfg == nil {
cfg = new(CoreStructuredKindGeneratorConfig)
}
@ -25,39 +25,39 @@ func CoreStructuredKindJenny(gokindsdir string, cfg *CoreStructuredKindGenerator
}
}
return &genCoreStructuredKind{
return &coreKindJenny{
gokindsdir: gokindsdir,
cfg: cfg,
}
}
// CoreStructuredKindGeneratorConfig holds configuration options for [CoreStructuredKindJenny].
// CoreStructuredKindGeneratorConfig holds configuration options for [CoreKindJenny].
type CoreStructuredKindGeneratorConfig struct {
// GenDirName returns the name of the directory in which the file should be
// generated. Defaults to DeclForGen.Lineage().Name() if nil.
GenDirName func(*DeclForGen) string
}
type genCoreStructuredKind struct {
type coreKindJenny struct {
gokindsdir string
cfg *CoreStructuredKindGeneratorConfig
}
var _ OneToOne = &genCoreStructuredKind{}
var _ OneToOne = &coreKindJenny{}
func (gen *genCoreStructuredKind) JennyName() string {
return "CoreStructuredKindJenny"
func (gen *coreKindJenny) JennyName() string {
return "CoreKindJenny"
}
func (gen *genCoreStructuredKind) Generate(decl *DeclForGen) (*codejen.File, error) {
if !decl.IsCoreStructured() {
func (gen *coreKindJenny) Generate(decl *DeclForGen) (*codejen.File, error) {
if !decl.IsCore() {
return nil, nil
}
path := filepath.Join(gen.gokindsdir, gen.cfg.GenDirName(decl), decl.Properties.Common().MachineName+"_kind_gen.go")
buf := new(bytes.Buffer)
if err := tmpls.Lookup("kind_corestructured.tmpl").Execute(buf, decl); err != nil {
return nil, fmt.Errorf("failed executing kind_corestructured template for %s: %w", path, err)
if err := tmpls.Lookup("kind_core.tmpl").Execute(buf, decl); err != nil {
return nil, fmt.Errorf("failed executing kind_core template for %s: %w", path, err)
}
b, err := postprocessGoFile(genGoFile{
path: path,

@ -30,9 +30,6 @@ func (j *lmox) JennyName() string {
}
func (j *lmox) Generate(decl *DeclForGen) (codejen.Files, error) {
if decl.IsRaw() {
return nil, nil
}
comm := decl.Properties.Common()
sfg := SchemaForGen{
Name: comm.Name,

@ -1,68 +0,0 @@
package codegen
import (
"bytes"
"fmt"
"path/filepath"
"github.com/grafana/codejen"
)
// RawKindJenny generates the implementation of [kindsys.Raw] for the
// provided kind declaration.
//
// gokindsdir should be the relative path to the parent directory that contains
// all generated kinds.
//
// This generator only has output for raw kinds.
func RawKindJenny(gokindsdir string, cfg *RawKindGeneratorConfig) OneToOne {
if cfg == nil {
cfg = new(RawKindGeneratorConfig)
}
if cfg.GenDirName == nil {
cfg.GenDirName = func(decl *DeclForGen) string {
return decl.Properties.Common().MachineName
}
}
return &genRawKind{
gokindsdir: gokindsdir,
cfg: cfg,
}
}
type genRawKind struct {
gokindsdir string
cfg *RawKindGeneratorConfig
}
type RawKindGeneratorConfig struct {
// GenDirName returns the name of the directory in which the file should be
// generated. Defaults to DeclForGen.Lineage().Name() if nil.
GenDirName func(*DeclForGen) string
}
func (gen *genRawKind) JennyName() string {
return "RawKindJenny"
}
func (gen *genRawKind) Generate(decl *DeclForGen) (*codejen.File, error) {
if !decl.IsRaw() {
return nil, nil
}
path := filepath.Join(gen.gokindsdir, gen.cfg.GenDirName(decl), decl.Properties.Common().MachineName+"_kind_gen.go")
buf := new(bytes.Buffer)
if err := tmpls.Lookup("kind_raw.tmpl").Execute(buf, decl); err != nil {
return nil, fmt.Errorf("failed executing kind_raw template for %s: %w", path, err)
}
b, err := postprocessGoFile(genGoFile{
path: path,
in: buf.Bytes(),
})
if err != nil {
return nil, err
}
return codejen.NewFile(path, b, gen), nil
}

@ -42,10 +42,6 @@ func (gen *genTSVeneerIndex) JennyName() string {
func (gen *genTSVeneerIndex) Generate(decls ...*DeclForGen) (*codejen.File, error) {
tsf := new(ast.File)
for _, decl := range decls {
if decl.IsRaw() {
continue
}
sch := decl.Lineage().Latest()
f, err := typescript.GenerateTypes(sch, &typescript.TypeConfig{
RootName: decl.Properties.Common().Name,

@ -32,9 +32,6 @@ func (j *latestj) JennyName() string {
}
func (j *latestj) Generate(decl *DeclForGen) (*codejen.File, error) {
if decl.IsRaw() {
return nil, nil
}
comm := decl.Properties.Common()
sfg := SchemaForGen{
Name: comm.Name,

@ -38,10 +38,10 @@ type (
}
tvars_kind_registry struct {
// Header tvars_autogen_header
NumRaw, NumStructured int
PackageName string
KindPackagePrefix string
Kinds []*DeclForGen
NumStructured int
PackageName string
KindPackagePrefix string
Kinds []*DeclForGen
}
tvars_coremodel_imports struct {
PackageName string

@ -10,22 +10,22 @@ import (
// directory containing the .cue files in which this kind is declared. Necessary
// for runtime errors related to the declaration and/or lineage to provide
// a real path to the correct .cue file.
const rootrel string = "kinds/structured/{{ .Properties.MachineName }}"
const rootrel string = "kinds/{{ .Properties.MachineName }}"
// TODO standard generated docs
type Kind struct {
lin thema.ConvergentLineage[*{{ .Properties.Name }}]
jcodec vmux.Codec
valmux vmux.ValueMux[*{{ .Properties.Name }}]
decl kindsys.Decl[kindsys.CoreStructuredProperties]
decl kindsys.Decl[kindsys.CoreProperties]
}
// type guard
var _ kindsys.Structured = &Kind{}
var _ kindsys.Core = &Kind{}
// TODO standard generated docs
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
decl, err := kindsys.LoadCoreKind[kindsys.CoreStructuredProperties](rootrel, rt.Context(), nil)
decl, err := kindsys.LoadCoreKind(rootrel, rt.Context(), nil)
if err != nil {
return nil, err
}
@ -91,12 +91,12 @@ func (k *Kind) Maturity() kindsys.Maturity {
// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the
// {{ .Properties.MachineName }} declaration in .cue files.
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreStructuredProperties] {
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreProperties] {
d := k.decl
return &d
}
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreStructuredProperties],
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreProperties],
// representing the static properties declared in the {{ .Properties.MachineName }} kind.
//
// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface].

@ -1,57 +0,0 @@
package {{ .Properties.MachineName }}
import (
"github.com/grafana/grafana/pkg/kindsys"
"github.com/grafana/thema"
"github.com/grafana/thema/vmux"
)
// TODO standard generated docs
type Kind struct {
decl kindsys.Decl[kindsys.RawProperties]
}
// type guard
var _ kindsys.Raw = &Kind{}
// TODO standard generated docs
func NewKind() (*Kind, error) {
decl, err := kindsys.LoadCoreKind[kindsys.RawProperties]("kinds/raw/{{ .Properties.MachineName }}", nil, nil)
if err != nil {
return nil, err
}
return &Kind{
decl: *decl,
}, nil
}
// TODO standard generated docs
func (k *Kind) Name() string {
return "{{ .Properties.Name }}"
}
// TODO standard generated docs
func (k *Kind) MachineName() string {
return "{{ .Properties.MachineName }}"
}
// TODO standard generated docs
func (k *Kind) Maturity() kindsys.Maturity {
return k.decl.Properties.Maturity
}
// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the
// {{ .Properties.MachineName }} declaration in .cue files.
func (k *Kind) Decl() *kindsys.Decl[kindsys.RawProperties] {
d := k.decl
return &d
}
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.RawProperties],
// representing the static properties declared in the {{ .Properties.MachineName }} kind.
//
// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface].
func (k *Kind) Props() kindsys.SomeKindProperties {
return k.decl.Properties
}

@ -22,8 +22,7 @@ import (
// Prefer All*() methods when performing operations generically across all kinds.
// For example, a validation HTTP middleware for any kind-schematized object type.
type Base struct {
all []kindsys.Interface
numRaw, numStructured int
all []kindsys.Core
{{- range .Kinds }}
{{ .Properties.MachineName }} *{{ .Properties.MachineName }}.Kind{{end}}
}
@ -31,7 +30,7 @@ type Base struct {
// type guards
var (
{{- range .Kinds }}
_ kindsys.{{ if .IsRaw }}Raw{{ else }}Structured{{ end }} = &{{ .Properties.MachineName }}.Kind{}{{end}}
_ kindsys.Core = &{{ .Properties.MachineName }}.Kind{}{{end}}
)
{{range .Kinds }}
@ -43,13 +42,10 @@ func (b *Base) {{ .Properties.Name }}() *{{ .Properties.MachineName }}.Kind {
func doNewBase(rt *thema.Runtime) *Base {
var err error
reg := &Base{
numRaw: {{ .NumRaw }},
numStructured: {{ .NumStructured }},
}
reg := &Base{}
{{range .Kinds }}
reg.{{ .Properties.MachineName }}, err = {{ .Properties.MachineName }}.NewKind({{ if .IsCoreStructured }}rt{{ end }})
reg.{{ .Properties.MachineName }}, err = {{ .Properties.MachineName }}.NewKind(rt)
if err != nil {
panic(fmt.Sprintf("error while initializing the {{ .Properties.MachineName }} Kind: %s", err))
}

@ -3,7 +3,7 @@
// Generated by:
// kinds/gen.go
// Using jennies:
// CoreStructuredKindJenny
// CoreKindJenny
//
// Run 'make gen-cue' from repository root to regenerate.
@ -19,22 +19,22 @@ import (
// directory containing the .cue files in which this kind is declared. Necessary
// for runtime errors related to the declaration and/or lineage to provide
// a real path to the correct .cue file.
const rootrel string = "kinds/structured/dashboard"
const rootrel string = "kinds/dashboard"
// TODO standard generated docs
type Kind struct {
lin thema.ConvergentLineage[*Dashboard]
jcodec vmux.Codec
valmux vmux.ValueMux[*Dashboard]
decl kindsys.Decl[kindsys.CoreStructuredProperties]
decl kindsys.Decl[kindsys.CoreProperties]
}
// type guard
var _ kindsys.Structured = &Kind{}
var _ kindsys.Core = &Kind{}
// TODO standard generated docs
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
decl, err := kindsys.LoadCoreKind[kindsys.CoreStructuredProperties](rootrel, rt.Context(), nil)
decl, err := kindsys.LoadCoreKind(rootrel, rt.Context(), nil)
if err != nil {
return nil, err
}
@ -100,12 +100,12 @@ func (k *Kind) Maturity() kindsys.Maturity {
// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the
// dashboard declaration in .cue files.
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreStructuredProperties] {
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreProperties] {
d := k.decl
return &d
}
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreStructuredProperties],
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreProperties],
// representing the static properties declared in the dashboard kind.
//
// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface].

@ -3,7 +3,7 @@
// Generated by:
// kinds/gen.go
// Using jennies:
// CoreStructuredKindJenny
// CoreKindJenny
//
// Run 'make gen-cue' from repository root to regenerate.
@ -19,22 +19,22 @@ import (
// directory containing the .cue files in which this kind is declared. Necessary
// for runtime errors related to the declaration and/or lineage to provide
// a real path to the correct .cue file.
const rootrel string = "kinds/structured/playlist"
const rootrel string = "kinds/playlist"
// TODO standard generated docs
type Kind struct {
lin thema.ConvergentLineage[*Playlist]
jcodec vmux.Codec
valmux vmux.ValueMux[*Playlist]
decl kindsys.Decl[kindsys.CoreStructuredProperties]
decl kindsys.Decl[kindsys.CoreProperties]
}
// type guard
var _ kindsys.Structured = &Kind{}
var _ kindsys.Core = &Kind{}
// TODO standard generated docs
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
decl, err := kindsys.LoadCoreKind[kindsys.CoreStructuredProperties](rootrel, rt.Context(), nil)
decl, err := kindsys.LoadCoreKind(rootrel, rt.Context(), nil)
if err != nil {
return nil, err
}
@ -100,12 +100,12 @@ func (k *Kind) Maturity() kindsys.Maturity {
// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the
// playlist declaration in .cue files.
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreStructuredProperties] {
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreProperties] {
d := k.decl
return &d
}
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreStructuredProperties],
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreProperties],
// representing the static properties declared in the playlist kind.
//
// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface].

@ -1,64 +0,0 @@
// THIS FILE IS GENERATED. EDITING IS FUTILE.
//
// Generated by:
// kinds/gen.go
// Using jennies:
// RawKindJenny
//
// Run 'make gen-cue' from repository root to regenerate.
package svg
import (
"github.com/grafana/grafana/pkg/kindsys"
)
// TODO standard generated docs
type Kind struct {
decl kindsys.Decl[kindsys.RawProperties]
}
// type guard
var _ kindsys.Raw = &Kind{}
// TODO standard generated docs
func NewKind() (*Kind, error) {
decl, err := kindsys.LoadCoreKind[kindsys.RawProperties]("kinds/raw/svg", nil, nil)
if err != nil {
return nil, err
}
return &Kind{
decl: *decl,
}, nil
}
// TODO standard generated docs
func (k *Kind) Name() string {
return "SVG"
}
// TODO standard generated docs
func (k *Kind) MachineName() string {
return "svg"
}
// TODO standard generated docs
func (k *Kind) Maturity() kindsys.Maturity {
return k.decl.Properties.Maturity
}
// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the
// svg declaration in .cue files.
func (k *Kind) Decl() *kindsys.Decl[kindsys.RawProperties] {
d := k.decl
return &d
}
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.RawProperties],
// representing the static properties declared in the svg kind.
//
// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface].
func (k *Kind) Props() kindsys.SomeKindProperties {
return k.decl.Properties
}

@ -3,7 +3,7 @@
// Generated by:
// kinds/gen.go
// Using jennies:
// CoreStructuredKindJenny
// CoreKindJenny
//
// Run 'make gen-cue' from repository root to regenerate.
@ -19,22 +19,22 @@ import (
// directory containing the .cue files in which this kind is declared. Necessary
// for runtime errors related to the declaration and/or lineage to provide
// a real path to the correct .cue file.
const rootrel string = "kinds/structured/team"
const rootrel string = "kinds/team"
// TODO standard generated docs
type Kind struct {
lin thema.ConvergentLineage[*Team]
jcodec vmux.Codec
valmux vmux.ValueMux[*Team]
decl kindsys.Decl[kindsys.CoreStructuredProperties]
decl kindsys.Decl[kindsys.CoreProperties]
}
// type guard
var _ kindsys.Structured = &Kind{}
var _ kindsys.Core = &Kind{}
// TODO standard generated docs
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
decl, err := kindsys.LoadCoreKind[kindsys.CoreStructuredProperties](rootrel, rt.Context(), nil)
decl, err := kindsys.LoadCoreKind(rootrel, rt.Context(), nil)
if err != nil {
return nil, err
}
@ -100,12 +100,12 @@ func (k *Kind) Maturity() kindsys.Maturity {
// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the
// team declaration in .cue files.
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreStructuredProperties] {
func (k *Kind) Decl() *kindsys.Decl[kindsys.CoreProperties] {
d := k.decl
return &d
}
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreStructuredProperties],
// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreProperties],
// representing the static properties declared in the team kind.
//
// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface].

@ -13,8 +13,7 @@ This document is the guide to extending kindsys. But first, we have to identify
* **Code generators** - written using the `github.com/grafana/codejen` framework, which applies the [single responsibility principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) to code generation, allowing us to compose modular code generators. Each jenny - a modular generator with a single responsibility - is declared as a `pkg/codegen/jenny_*.go` file.
* **Registries** - generated lists of all or a well-defined subset of kinds that can be used in code. `pkg/registries/corekind` is a registry of all core `pkg/kindsys.Interface` implementations; `packages/grafana-schema/src/index.gen.ts` is a registry of all the TypeScript types generated from the current versions of each kind's schema.
* **Kind declarations** - the declarations of individual kinds. By kind category:
* **Core Structured** - each child directory of `kinds/structured`.
* **Raw** - each child directory of `kinds/raw`.
* **Core** - each child directory of `kinds`.
* **Composable** - In Grafana core, `public/app/plugins/*/*/models.cue` files.
* **Custom** - No examples in Grafana core. See [operator-app-sdk](https://github.com/grafana/operator-app-sdk) (TODO that repo is private; make it public, or point to public examples).

@ -67,22 +67,14 @@ type Interface interface {
Maturity() Maturity // TODO unclear if we want maturity for raw kinds
}
// TODO docs
type Raw interface {
Interface
// TODO docs
Decl() *Decl[RawProperties]
}
type Structured interface {
type Core interface {
Interface
// TODO docs
Lineage() thema.Lineage
// TODO docs
Decl() *Decl[CoreStructuredProperties] // TODO figure out how to reconcile this interface with CustomStructuredProperties
Decl() *Decl[CoreProperties] // TODO figure out how to reconcile this interface with CustomProperties
}
// type Composable interface {
@ -92,5 +84,5 @@ type Structured interface {
// Lineage() thema.Lineage
//
// // TODO docs
// Properties() CoreStructuredProperties // TODO figure out how to reconcile this interface with CustomStructuredProperties
// Properties() CoreProperties // TODO figure out how to reconcile this interface with CustomProperties
// }

@ -1,15 +1,16 @@
package kindsys
// CustomStructured specifies the Kind category for plugin-defined arbitrary types.
// Custom kinds have the same purpose as CoreStructured kinds, differing only in
// Custom specifies the kind category for plugin-defined arbitrary types.
// Custom kinds have the same purpose as Core kinds, differing only in
// that they are declared by external plugins rather than in Grafana core. As such,
// this specification is kept closely aligned with the CoreStructured kind.
// this specification is kept closely aligned with the Core kind.
//
// Grafana provides Kubernetes apiserver-shaped APIs for interacting with custom kinds -
// The same API patterns (and clients) used to interact with CustomResources.
#CustomStructured: {
#Structured
// Grafana provides Kubernetes apiserver-shaped HTTP APIs for interacting with custom
// kinds - the same API patterns (and clients) used to interact with k8s CustomResources.
#Custom: S={
_sharedKind
lineage: { name: S.machineName }
lineageIsGroup: false
...
}

@ -6,25 +6,23 @@ import (
"github.com/grafana/thema"
)
// A Kind specifies a type of Grafana resource.
// A Kind is a specification for a type of object that Grafana knows
// how to work with. Each kind definition contains a schema, and some
// declarative metadata and constraints.
//
// An instance of a Kind is called an entity. An entity is a sequence of bytes -
// for example, a JSON file or HTTP request body - that conforms to the
// constraints defined in a Kind, and enforced by Grafana's entity system.
// An instance of a kind is called a resource. Resources are a sequence of
// bytes - for example, a JSON file or HTTP request body - that conforms
// to the schemas and other constraints defined in a Kind.
//
// Once Grafana has determined a given byte sequence to be an
// instance of a known Kind, kind-specific behaviors can be applied,
// requests can be routed, events can be triggered, etc.
//
// Classes and objects in most programming languages are analogous:
// - #Kind is like a `class` keyword
// - Each declaration of #Kind is like a class declaration
// - Byte sequences are like arguments to the class constructor
// - Entities are like objects - what's returned from the constructor
// Grafana's kinds are similar to Kubernetes CustomResourceDefinitions.
// Grafana provides a standard mechanism for representing its kinds as CRDs.
//
// There are four categories of kinds: Raw, Composable, CoreStructured,
// and CustomStructured.
#Kind: #Raw | #Composable | #CoreStructured | #CustomStructured
// There are three categories of kinds: Core, Custom, and Composable.
#Kind: #Composable | #Core | #Custom
// properties shared between all kind categories.
_sharedKind: {
@ -66,69 +64,37 @@ _sharedKind: {
// https://github.com/grafana/thema/issues/62
lineageIsGroup: bool
// lineage is the Thema lineage containing all the schemas that have existed for this kind.
lineage: thema.#Lineage
// currentVersion is computed to be the syntactic version number of the latest
// schema in lineage.
currentVersion: thema.#SyntacticVersion & (thema.#LatestVersion & {lin: lineage}).out
maturity: #Maturity
// The kind system itself is not mature enough yet for any single
// kind to advance beyond "experimental"
// TODO allow more maturity stages once system is ready https://github.com/orgs/grafana/projects/133/views/8
maturity: *"merged" | "experimental"
// form indicates whether the kind has a schema ("structured") or not ("raw")
form: "structured" | "raw"
}
// Maturity indicates the how far a given kind declaration is in its initial
// journey. Mature kinds still evolve, but with guarantees about compatibility.
#Maturity: "merged" | "experimental" | "stable" | "mature"
// Structured encompasses all three of the structured kind categories, in which
// a schema specifies validity rules for the byte sequence. These represent all
// the conventional types and functional resources in Grafana, such as
// dashboards and datasources.
//
// Structured kinds may be defined either by Grafana itself (#CoreStructured),
// or by plugins (#CustomStructured). Plugin-defined kinds have a slightly
// reduced set of capabilities, due to the constraints imposed by them being run
// in separate processes, and the risks arising from executing code from
// potentially untrusted third parties.
#Structured: S={
// Core specifies the kind category for core-defined arbitrary types.
// Familiar types and functional resources in Grafana, such as dashboards and
// and datasources, are represented as core kinds.
#Core: S=close({
_sharedKind
form: "structured"
// lineage is the Thema lineage containing all the schemas that have existed for this kind.
// It is required that lineage.name is the same as the [machineName].
lineage: thema.#Lineage & { name: S.machineName }
currentVersion: thema.#SyntacticVersion & (thema.#LatestVersion & {lin: lineage}).out
}
// Raw is a category of Kind that specifies handling for a raw file,
// like an image, or an svg or parquet file. Grafana mostly acts as asset storage for raw
// kinds: the byte sequence is a black box to Grafana, and type is determined
// through metadata such as file extension.
#Raw: {
_sharedKind
form: "raw"
// TODO docs
extensions?: [...string]
lineage: { name: S.machineName }
lineageIsGroup: false
})
// known TODOs
// - sanitize function
// - get summary
}
// TODO
#CoreStructured: {
#Structured
lineageIsGroup: false
}
// Composable is a category of structured kind that provides schema elements for
// composition into CoreStructured and CustomStructured kinds. Grafana plugins
// Composable is a category of kind that provides schema elements for
// composition into Core and Custom kinds. Grafana plugins
// provide composable kinds; for example, a datasource plugin provides one to
// describe the structure of its queries, which is then composed into dashboards
// and alerting rules.
@ -138,7 +104,6 @@ _sharedKind: {
// that ComposableKind.
#Composable: S={
_sharedKind
form: "structured"
// TODO docs
// TODO unify this with the existing slots decls in pkg/framework/coremodel

@ -12,49 +12,33 @@ type CommonProperties struct {
Maturity Maturity `json:"maturity"`
}
// RawProperties represents the static properties in a #Raw kind declaration that are
// trivially representable with basic Go types.
//
// When a .cue #Raw declaration is loaded through the standard [LoadCoreKind],
// func, it is fully validated and populated according to all rules specified
// in CUE for #Raw kinds.
type RawProperties struct {
CommonProperties
Extensions []string `json:"extensions"`
}
func (m RawProperties) _private() {}
func (m RawProperties) Common() CommonProperties {
return m.CommonProperties
}
// CoreStructuredProperties represents the static properties in the declaration of a
// #CoreStructured kind that are representable with basic Go types. This
// CoreProperties represents the static properties in the declaration of a
// #Core kind that are representable with basic Go types. This
// excludes Thema schemas.
//
// When a .cue #CoreStructured declaration is loaded through the standard [LoadCoreKind],
// When a .cue #Core declaration is loaded through the standard [LoadCoreKind],
// func, it is fully validated and populated according to all rules specified
// in CUE for #CoreStructured kinds.
type CoreStructuredProperties struct {
// in CUE for #Core kinds.
type CoreProperties struct {
CommonProperties
CurrentVersion thema.SyntacticVersion `json:"currentVersion"`
}
func (m CoreStructuredProperties) _private() {}
func (m CoreStructuredProperties) Common() CommonProperties {
func (m CoreProperties) _private() {}
func (m CoreProperties) Common() CommonProperties {
return m.CommonProperties
}
// CustomStructuredProperties represents the static properties in the declaration of a
// #CustomStructured kind that are representable with basic Go types. This
// CustomProperties represents the static properties in the declaration of a
// #Custom kind that are representable with basic Go types. This
// excludes Thema schemas.
type CustomStructuredProperties struct {
type CustomProperties struct {
CommonProperties
CurrentVersion thema.SyntacticVersion `json:"currentVersion"`
}
func (m CustomStructuredProperties) _private() {}
func (m CustomStructuredProperties) Common() CommonProperties {
func (m CustomProperties) _private() {}
func (m CustomProperties) Common() CommonProperties {
return m.CommonProperties
}
@ -72,8 +56,8 @@ func (m ComposableProperties) Common() CommonProperties {
}
// SomeKindProperties is an interface type to abstract over the different kind
// property struct types: [RawProperties], [CoreStructuredProperties],
// [CustomStructuredProperties], [ComposableProperties].
// property struct types: [CoreProperties], [CustomProperties],
// [ComposableProperties].
//
// It is the traditional interface counterpart to the generic type constraint
// KindProperties.
@ -85,5 +69,5 @@ type SomeKindProperties interface {
// KindProperties is a type parameter that comprises the base possible set of
// kind metadata configurations.
type KindProperties interface {
RawProperties | CoreStructuredProperties | CustomStructuredProperties | ComposableProperties
CoreProperties | CustomProperties | ComposableProperties
}

@ -12,19 +12,10 @@ import (
"github.com/grafana/thema"
)
// DeclParentPath is the path, relative to the repository root, where
// each child directory is expected to contain directories with .cue files,
// declaring one kind.
var DeclParentPath = "kinds"
// CoreStructuredDeclParentPath is the path, relative to the repository root, where
// CoreDeclParentPath is the path, relative to the repository root, where
// each child directory is expected to contain .cue files declaring one
// CoreStructured kind.
var CoreStructuredDeclParentPath = filepath.Join(DeclParentPath, "structured")
// RawDeclParentPath is the path, relative to the repository root, where each child
// directory is expected to contain .cue files declaring one Raw kind.
var RawDeclParentPath = filepath.Join(DeclParentPath, "raw")
// Core kind.
var CoreDeclParentPath = "kinds"
// GoCoreKindParentPath is the path, relative to the repository root, to the directory
// containing one directory per kind, full of generated Go kind output: types and bindings.
@ -99,12 +90,10 @@ func ToKindMeta[T KindProperties](v cue.Value) (T, error) {
anyprops := any(*props).(SomeKindProperties)
switch anyprops.(type) {
case RawProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Raw")))
case CoreStructuredProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("CoreStructured")))
case CustomStructuredProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("CustomStructured")))
case CoreProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Core")))
case CustomProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Custom")))
case ComposableProperties:
kdef = fw.LookupPath(cue.MakePath(cue.Def("Composable")))
default:
@ -136,8 +125,7 @@ type SomeDecl struct {
Properties SomeKindProperties
}
// BindKindLineage binds the lineage for the kind declaration. nil, nil is returned
// for raw kinds.
// BindKindLineage binds the lineage for the kind declaration.
//
// For kinds with a corresponding Go type, it is left to the caller to associate
// that Go type with the lineage returned from this function by a call to [thema.BindType].
@ -146,30 +134,22 @@ func (decl *SomeDecl) BindKindLineage(rt *thema.Runtime, opts ...thema.BindOptio
rt = cuectx.GrafanaThemaRuntime()
}
switch decl.Properties.(type) {
case RawProperties:
return nil, nil
case CoreStructuredProperties, CustomStructuredProperties, ComposableProperties:
case CoreProperties, CustomProperties, ComposableProperties:
return thema.BindLineage(decl.V.LookupPath(cue.MakePath(cue.Str("lineage"))), rt, opts...)
default:
panic("unreachable")
}
}
// IsRaw indicates whether the represented kind is a raw kind.
func (decl *SomeDecl) IsRaw() bool {
_, is := decl.Properties.(RawProperties)
return is
}
// IsCoreStructured indicates whether the represented kind is a core structured kind.
func (decl *SomeDecl) IsCoreStructured() bool {
_, is := decl.Properties.(CoreStructuredProperties)
// IsCore indicates whether the represented kind is a core kind.
func (decl *SomeDecl) IsCore() bool {
_, is := decl.Properties.(CoreProperties)
return is
}
// IsCustomStructured indicates whether the represented kind is a custom structured kind.
func (decl *SomeDecl) IsCustomStructured() bool {
_, is := decl.Properties.(CustomStructuredProperties)
// IsCustom indicates whether the represented kind is a custom kind.
func (decl *SomeDecl) IsCustom() bool {
_, is := decl.Properties.(CustomProperties)
return is
}
@ -204,7 +184,7 @@ func (decl *Decl[T]) Some() *SomeDecl {
//
// declpath is the path to the directory containing the core kind declaration,
// relative to the grafana/grafana root. For example, dashboards are in
// "kinds/structured/dashboard".
// "kinds/dashboard".
//
// The .cue file bytes containing the core kind declaration will be retrieved
// from the central embedded FS, [grafana.CueSchemaFS]. If desired (e.g. for
@ -215,15 +195,15 @@ func (decl *Decl[T]) Some() *SomeDecl {
// This is a low-level function, primarily intended for use in code generation.
// For representations of core kinds that are useful in Go programs at runtime,
// see ["github.com/grafana/grafana/pkg/registry/corekind"].
func LoadCoreKind[T RawProperties | CoreStructuredProperties](declpath string, ctx *cue.Context, overlay fs.FS) (*Decl[T], error) {
func LoadCoreKind(declpath string, ctx *cue.Context, overlay fs.FS) (*Decl[CoreProperties], error) {
vk, err := cuectx.BuildGrafanaInstance(ctx, declpath, "kind", overlay)
if err != nil {
return nil, err
}
decl := &Decl[T]{
decl := &Decl[CoreProperties]{
V: vk,
}
decl.Properties, err = ToKindMeta[T](vk)
decl.Properties, err = ToKindMeta[CoreProperties](vk)
if err != nil {
return nil, err
}

@ -54,15 +54,13 @@ var plannedCoreKinds = []string{
}
type KindStateReport struct {
Core []kindsys.CoreStructuredProperties `json:"core"`
Raw []kindsys.RawProperties `json:"raw"`
Composable []kindsys.ComposableProperties `json:"composable"`
Core []kindsys.CoreProperties `json:"core"`
Composable []kindsys.ComposableProperties `json:"composable"`
}
func emptyKindStateReport() KindStateReport {
return KindStateReport{
Core: make([]kindsys.CoreStructuredProperties, 0),
Raw: make([]kindsys.RawProperties, 0),
Core: make([]kindsys.CoreProperties, 0),
Composable: make([]kindsys.ComposableProperties, 0),
}
}
@ -75,10 +73,8 @@ func buildKindStateReport() KindStateReport {
for _, k := range b.All() {
seen[k.Props().Common().Name] = true
switch props := k.Props().(type) {
case kindsys.CoreStructuredProperties:
case kindsys.CoreProperties:
r.Core = append(r.Core, props)
case kindsys.RawProperties:
r.Raw = append(r.Raw, props)
}
}
@ -86,7 +82,7 @@ func buildKindStateReport() KindStateReport {
if seen[kn] {
continue
}
r.Core = append(r.Core, kindsys.CoreStructuredProperties{
r.Core = append(r.Core, kindsys.CoreProperties{
CommonProperties: kindsys.CommonProperties{
Name: kn,
PluralName: kn + "s",

@ -133,19 +133,6 @@
]
}
],
"raw": [
{
"name": "SVG",
"pluralName": "SVGs",
"machineName": "svg",
"pluralMachineName": "svgs",
"lineageIsGroup": false,
"maturity": "merged",
"extensions": [
"svg"
]
}
],
"composable": [
{
"name": "AlertGroups-Panel",

@ -2,7 +2,7 @@ package grafanaplugin
import (
"github.com/grafana/thema"
"github.com/grafana/grafana/kinds/structured/dashboard:kind"
"github.com/grafana/grafana/kinds/dashboard:kind"
)
_dummy: coremodel.slots

@ -37,40 +37,11 @@ func NewBase(rt *thema.Runtime) *Base {
return doNewBase(rt)
}
// All returns a slice of the [kindsys.Interface] instances corresponding to all
// core raw and structured kinds.
// All returns a slice of [kindsys.Core] containing all core Grafana kinds.
//
// The returned slice is sorted lexicographically by kind machine name.
func (b *Base) All() []kindsys.Interface {
ret := make([]kindsys.Interface, len(b.all))
func (b *Base) All() []kindsys.Core {
ret := make([]kindsys.Core, len(b.all))
copy(ret, b.all)
return ret
}
// AllRaw returns a slice of the [kindsys.Raw] instances for all raw kinds.
//
// The returned slice is sorted lexicographically by kind machine name.
func (b *Base) AllRaw() []kindsys.Raw {
ret := make([]kindsys.Raw, 0, b.numRaw)
for _, k := range b.all {
if rk, is := k.(kindsys.Raw); is {
ret = append(ret, rk)
}
}
return ret
}
// AllStructured returns a slice of the [kindsys.Structured] instances for
// all core structured kinds.
//
// The returned slice is sorted lexicographically by kind machine name.
func (b *Base) AllStructured() []kindsys.Structured {
ret := make([]kindsys.Structured, 0, b.numStructured)
for _, k := range b.all {
if rk, is := k.(kindsys.Structured); is {
ret = append(ret, rk)
}
}
return ret
}

@ -14,7 +14,6 @@ import (
"github.com/grafana/grafana/pkg/kinds/dashboard"
"github.com/grafana/grafana/pkg/kinds/playlist"
"github.com/grafana/grafana/pkg/kinds/svg"
"github.com/grafana/grafana/pkg/kinds/team"
"github.com/grafana/grafana/pkg/kindsys"
"github.com/grafana/thema"
@ -31,20 +30,17 @@ import (
// Prefer All*() methods when performing operations generically across all kinds.
// For example, a validation HTTP middleware for any kind-schematized object type.
type Base struct {
all []kindsys.Interface
numRaw, numStructured int
dashboard *dashboard.Kind
playlist *playlist.Kind
svg *svg.Kind
team *team.Kind
all []kindsys.Core
dashboard *dashboard.Kind
playlist *playlist.Kind
team *team.Kind
}
// type guards
var (
_ kindsys.Structured = &dashboard.Kind{}
_ kindsys.Structured = &playlist.Kind{}
_ kindsys.Raw = &svg.Kind{}
_ kindsys.Structured = &team.Kind{}
_ kindsys.Core = &dashboard.Kind{}
_ kindsys.Core = &playlist.Kind{}
_ kindsys.Core = &team.Kind{}
)
// Dashboard returns the [kindsys.Interface] implementation for the dashboard kind.
@ -57,11 +53,6 @@ func (b *Base) Playlist() *playlist.Kind {
return b.playlist
}
// SVG returns the [kindsys.Interface] implementation for the svg kind.
func (b *Base) SVG() *svg.Kind {
return b.svg
}
// Team returns the [kindsys.Interface] implementation for the team kind.
func (b *Base) Team() *team.Kind {
return b.team
@ -69,10 +60,7 @@ func (b *Base) Team() *team.Kind {
func doNewBase(rt *thema.Runtime) *Base {
var err error
reg := &Base{
numRaw: 1,
numStructured: 3,
}
reg := &Base{}
reg.dashboard, err = dashboard.NewKind(rt)
if err != nil {
@ -86,12 +74,6 @@ func doNewBase(rt *thema.Runtime) *Base {
}
reg.all = append(reg.all, reg.playlist)
reg.svg, err = svg.NewKind()
if err != nil {
panic(fmt.Sprintf("error while initializing the svg Kind: %s", err))
}
reg.all = append(reg.all, reg.svg)
reg.team, err = team.NewKind(rt)
if err != nil {
panic(fmt.Sprintf("error while initializing the team Kind: %s", err))

Loading…
Cancel
Save