grafana/pkg/kindsys/kindcats.cue
sam boyer 07e5f8117f
Reconcile coremodels, entities, objects under new kind framework (#56492)
* Update thema to latest

* Deal with s/Library/*Runtime/

* Commit new, working results of codegen

* We like pointers now

* Always take runtime arg for NewBase()

* Sketchy handwavy pass at entity meta framework

* Little nibbles

* Update pkg/framework/coremodel/entityframework.cue

Co-authored-by: Artur Wierzbicki <wierzbicki.artur.94@gmail.com>

* Move file into new framework location

* Introduce loaders, Go code

* Complete rename to kind

* Flesh out framework, add svg/dashboard examples

* Cruft removal

* Remove generated kind go files from gitignore

* Refine maturity concept, add SlotKind

* Update embed and go deps

* Export PrefixWithGrafanaCUE

* Make the loader actually work, holy crap

* Many small tweaks to type.cue

* Add Apache 2 licensing exceptions for kinds

* Add new kinds dir, start of generator

* Roll back to earlier oapi-codegen

* Introduce new grafana-specific CUE loaders

* Introduce new tidy code generators framework

* Catch up kind framework with tinkering

* Add slices for the generators

* Add write/verify step to main generator

* Many renames

* Split up kind framework cue files

* Use kind.Decl within generated kinds

* Create kind.SomeDecl wrapper type to cache lineages

* Better names again

* Get one generated implemented, hopefully

* Copy dashboard schema into new kind.cue

* Small fixes to make the initial gen work

* Put svg kind in its new home

* Add generated Go dashboard type

* More renames and cleanups

* Add base kind registry and generator

* Stop blacklisting *_gen.go files

This is not the Go best practice, anyway. All we actually want to ignore
for enterprise is generated wire files.

* Change codegen output directories

pkg/kind -> pkg/kinds
pkg/registry/kindreg -> pkg/registry/corekind

* Rename pkg/framework/kind to pkg/kindsys

* Add core structured kind generator

* Add plural and machine names to kind spec

* Copy playlist over to kind system

* Consolidate kindsys files

* Add raw kind generator

* Update CODEOWNERS for kind framework

* Touch up comments a bit

* More docs tweaks

* Remove generated types to reduce noise for review

* Split each generator into its own file

* Rename Slot kind to Composable kind

* Add handwavy types for customkind loading

* Guard against init calls to framework loader

* First pass at doc on extending the kind system

* Improve attribute example in docs

* Fix wire imports

* Add basic TS types generator

* Fix composable kind category def

* No need for a separate file with generate directive

* Catch dashboard schema up

* Rename generator types to something saner and generic

* Make version configurable in ts/go generators

* Add CommonMeta to ease property access

* Add kindsys prop indicating whether lineage is group

* Put all kind categories back in a single file

* Finish with kindsys group props

* Refactor maturity progression per discussion

- Replace "committed" with "merged"
- All kindcats can use all maturity levels, at least for now

* Convert ts veneer index generator to modular system

* Move over to new jennywrites framework

* Strip down old coremodel generator

* Use public version of jennywrites

* Pull latest thema

* Commit generated Go types

* Add header injection postprocessor

* Move sdboyer/jennywrites to grafana/codejen

* Tweak header output

* Remove dashboard and playlist coremodels

* Fix up backend dashboards devenv test

* Fix TS import patterns to new gen filename

* Update internal imports, remove coremodel registry

* Fix compilation errors, wire generation

* Export and replace the prefix dropper

* More Go struct and field name changes

* Last name fixes, hopefully

* Fix lint errors

* Last lint error

Co-authored-by: Artur Wierzbicki <wierzbicki.artur.94@gmail.com>
2022-11-10 12:36:40 -08:00

167 lines
6.0 KiB
CUE

package kindsys
import (
"strings"
"github.com/grafana/thema"
)
// A Kind specifies a type of Grafana resource.
//
// 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.
//
// 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
//
// There are four categories of kinds: Raw, Composable, CoreStructured,
// and CustomStructured.
#Kind: #Raw | #Composable | #CoreStructured | #CustomStructured
// properties shared between all kind categories.
_sharedKind: {
// name is the canonical name of a Kind, as expressed in PascalCase.
//
// To ensure names are generally portable and amenable for consumption
// in various mechanical tasks, name largely follows the relatively
// strict DNS label naming standard as defined in RFC 1123:
// - Contain at most 63 characters
// - Contain only lowercase alphanumeric characters or '-'
// - Start with an uppercase alphabetic character
// - End with an alphanumeric character
name: =~"^([A-Z][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])$"
// machineName is the case-normalized (lowercase) version of [name]. This
// version of the name is preferred for use in most mechanical contexts,
// as case normalization ensures that case-insensitive and case-sensitive
// checks will never disagree on uniqueness.
//
// In addition to lowercase normalization, dashes are transformed to underscores.
machineName: strings.ToLower(strings.Replace(name, "-", "_", -1))
// pluralName is the pluralized form of name. Defaults to name + "s".
pluralName: =~"^([A-Z][a-zA-Z0-9-]{0,61}[a-zA-Z])$" | *(name + "s")
// pluralMachineName is the pluralized form of [machineName]. The same case
// normalization and dash transformation is applied to [pluralName] as [machineName]
// applies to [name].
pluralMachineName: strings.ToLower(strings.Replace(pluralName, "-", "_", -1))
// lineageIsGroup indicates whether the lineage in this kind is "grouped". In a
// grouped lineage, each top-level field in the schema specifies a discrete
// object that is expected to exist in the wild
//
// This field is set at the framework level, and cannot be in the declaration of
// any individual kind.
//
// This is likely to eventually become a first-class property in Thema:
// https://github.com/grafana/thema/issues/62
lineageIsGroup: bool
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={
_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]
lineageIsGroup: false
// known TODOs
// - sanitize function
// - get summary
}
// TODO
#CustomStructured: {
#Structured
lineageIsGroup: false
...
}
// 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
// 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.
//
// Each Composable is an implementation of exactly one Slot, a shared meta-schema
// defined by Grafana itself that constrains the shape of schemas declared in
// that ComposableKind.
#Composable: S={
_sharedKind
form: "structured"
// TODO docs
// TODO unify this with the existing slots decls in pkg/framework/coremodel
slot: "Panel" | "Query" | "DSConfig"
// TODO unify this with the existing slots decls in pkg/framework/coremodel
lineageIsGroup: bool & [
if slot == "Panel" { true },
if slot == "DSConfig" { true },
if slot == "Query" { false },
][0]
// 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 }
}