diff --git a/pkg/codegen/coremodel.go b/pkg/codegen/coremodel.go index c6d46a8e069..5266d379d20 100644 --- a/pkg/codegen/coremodel.go +++ b/pkg/codegen/coremodel.go @@ -38,6 +38,10 @@ type ExtractedLineage struct { // code from not-yet-canonical coremodels should include appropriate caveats in // documentation and possibly be hidden from external public API surface areas. IsCanonical bool + + // Indicates whether the coremodel represents an API type, and should therefore + // be included in API client code generation. + IsAPIType bool } // ExtractLineage loads a Grafana Thema lineage from the filesystem. @@ -100,6 +104,7 @@ func ExtractLineage(path string, lib thema.Library) (*ExtractedLineage, error) { return ec, err } ec.IsCanonical = isCanonical(ec.Lineage.Name()) + ec.IsAPIType = isAPIType(ec.Lineage.Name()) return ec, nil } @@ -122,11 +127,20 @@ func isCanonical(name string) bool { return canonicalCoremodels[name] } +func isAPIType(name string) bool { + return !nonAPITypes[name] +} + // FIXME specifying coremodel canonicality DOES NOT belong here - it should be part of the coremodel declaration. var canonicalCoremodels = map[string]bool{ "dashboard": false, } +// FIXME this also needs to be moved into coremodel metadata +var nonAPITypes = map[string]bool{ + "pluginmeta": true, +} + // GenerateGoCoremodel generates a standard Go model struct and coremodel // implementation from a coremodel CUE declaration. // diff --git a/pkg/coremodel/pluginmeta/coremodel.cue b/pkg/coremodel/pluginmeta/coremodel.cue new file mode 100644 index 00000000000..a376f47209c --- /dev/null +++ b/pkg/coremodel/pluginmeta/coremodel.cue @@ -0,0 +1,340 @@ +package pluginmeta + +import "github.com/grafana/thema" + +thema.#Lineage +name: "pluginmeta" +seqs: [ + { + schemas: [ + { + // Unique name of the plugin. If the plugin is published on + // grafana.com, then the plugin id has to follow the naming + // conventions. + id: =~"^[0-9a-z]+\\-([0-9a-z]+\\-)?(app|panel|datasource)$" + + // type indicates which type of Grafana plugin this is, of the defined + // set of Grafana plugin types. + type: #Type + + // Type is a string identifier of the Grafana plugin type. + #Type: "app" | "datasource" | "panel" | "renderer" | "secretsmanager" + + // IncludeType is a string identifier of a plugin include type, which is + // a superset of plugin types. + #IncludeType: #Type | "dashboard" | "page" + + // Human-readable name of the plugin that is shown to the user in + // the UI. + name: string + + // Plugin category used on the Add data source page. + category?: "tsdb" | "logging" | "cloud" | "tracing" | "sql" | "enterprise" | "other" + + // For data source plugins, if the plugin supports annotation + // queries. + annotations?: bool + + // For data source plugins, if the plugin supports alerting. + alerting?: bool + + // If the plugin has a backend component. + backend?: bool + + // The first part of the file name of the backend component + // executable. There can be multiple executables built for + // different operating system and architecture. Grafana will + // check for executables named `_<$GOOS>_<.exe for Windows>`, e.g. `plugin_linux_amd64`. + // Combination of $GOOS and $GOARCH can be found here: + // https://golang.org/doc/install/source#environment. + executable?: string + + // Initialize plugin on startup. By default, the plugin + // initializes on first use. + preload?: bool + + // Marks a plugin as a pre-release. + state?: #ReleaseState + + // ReleaseState indicates release maturity state of a plugin. + #ReleaseState: "alpha" | "beta" | *"stable" + + // Resources to include in plugin. + includes?: [...#Include] + + // A resource to be included in a plugin. + #Include: { + // Unique identifier of the included resource + uid?: string + type: #IncludeType + name?: string + + // (Legacy) The Angular component to use for a page. + component?: string + role?: "Admin" | "Editor" | "Viewer" + + // Used for app plugins. + path?: string + + // Add the include to the side menu. + addToNav?: bool + + // Page or dashboard when user clicks the icon in the side menu. + defaultNav?: bool + + // Icon to use in the side menu. For information on available + // icon, refer to [Icons + // Overview](https://developers.grafana.com/ui/latest/index.html?path=/story/docs-overview-icon--icons-overview). + icon?: string + ... + } + + // For data source plugins, if the plugin supports logs. + logs?: bool + + // For panel plugins. Hides the query editor. + skipDataQuery?: bool + + // For data source plugins, if the plugin supports metric queries. + // Used in Explore. + metrics?: bool + + // For data source plugins, if the plugin supports streaming. + streaming?: bool + + // This is an undocumented feature. + tables?: bool + + // For data source plugins, if the plugin supports tracing. + tracing?: bool + + // For data source plugins, include hidden queries in the data + // request. + hiddenQueries?: bool + + // Set to true for app plugins that should be enabled by default + // in all orgs + autoEnabled?: bool + + // Dependencies needed by the plugin. + dependencies: #Dependencies + + #Dependencies: { + // (Deprecated) Required Grafana version for this plugin, e.g. + // `6.x.x 7.x.x` to denote plugin requires Grafana v6.x.x or + // v7.x.x. + grafanaVersion?: =~"^([0-9]+)(\\.[0-9x]+)?(\\.[0-9x])?$" + + // Required Grafana version for this plugin. Validated using + // https://github.com/npm/node-semver. + grafanaDependency: =~"^(<=|>=|<|>|=|~|\\^)?([0-9]+)(\\.[0-9x\\*]+)(\\.[0-9x\\*])?(\\s(<=|>=|<|=>)?([0-9]+)(\\.[0-9x]+)(\\.[0-9x]))?$" + + // An array of required plugins on which this plugin depends. + plugins?: [...#Dependency] + } + + // Dependency describes another plugin on which a plugin depends. + // The id refers to the plugin package identifier, as given on + // the grafana.com plugin marketplace. + #Dependency: { + id: =~"^[0-9a-z]+\\-([0-9a-z]+\\-)?(app|panel|datasource)$" + type: "app" | "datasource" | "panel" + name: string + version: string + ... + } + + // Metadata about the plugin. + info: #Info + + // Metadata about a Grafana plugin. Some fields are used on the plugins + // page in Grafana and others on grafana.com, if the plugin is published. + #Info: { + // Information about the plugin author. + author?: { + // Author's name. + name?: string + + // Author's name. + email?: string + + // Link to author's website. + url?: string + } + + // Build information + build?: #BuildInfo + + // Description of plugin. Used on the plugins page in Grafana and + // for search on grafana.com. + description?: string + + // Array of plugin keywords. Used for search on grafana.com. + keywords: [...string] + // should be this, but CUE to openapi converter screws this up + // by inserting a non-concrete default. + // keywords: [string, ...string] + + // An array of link objects to be displayed on this plugin's + // project page in the form `{name: 'foo', url: + // 'http://example.com'}` + links?: [...{ + name?: string + url?: string + }] + + // SVG images that are used as plugin icons. + logos: { + // Link to the "small" version of the plugin logo, which must be + // an SVG image. "Large" and "small" logos can be the same image. + small: string + + // Link to the "large" version of the plugin logo, which must be + // an SVG image. "Large" and "small" logos can be the same image. + large: string + } + + // An array of screenshot objects in the form `{name: 'bar', path: + // 'img/screenshot.png'}` + screenshots?: [...{ + name?: string + path?: string + }] + + // Date when this plugin was built. + updated: =~"^(\\d{4}-\\d{2}-\\d{2}|\\%TODAY\\%)$" + + // Project version of this commit, e.g. `6.7.x`. + version: =~"^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*$|\\%VERSION\\%)" + } + + #BuildInfo: { + // Time when the plugin was built, as a Unix timestamp. + time?: int64 + repo?: string + + // Git branch the plugin was built from. + branch?: string + + // Git hash of the commit the plugin was built from + hash?: string + "number"?: int64 + + // GitHub pull request the plugin was built from + pr?: int32 + } + + // For data source plugins. There is a query options section in + // the plugin's query editor and these options can be turned on + // if needed. + queryOptions?: { + // For data source plugins. If the `max data points` option should + // be shown in the query options section in the query editor. + maxDataPoints?: bool + + // For data source plugins. If the `min interval` option should be + // shown in the query options section in the query editor. + minInterval?: bool + + // For data source plugins. If the `cache timeout` option should + // be shown in the query options section in the query editor. + cacheTimeout?: bool + } + + // Routes is a list of proxy routes, if any. For datasource plugins only. + routes?: [...#Route] + + // Header describes an HTTP header that is forwarded with a proxied request for + // a plugin route. + #Header: { + name: string + content: string + } + + // URLParam describes query string parameters for + // a url in a plugin route + #URLParam: { + name: string + content: string + } + + // A proxy route used in datasource plugins for plugin authentication + // and adding headers to HTTP requests made by the plugin. + // For more information, refer to [Authentication for data source + // plugins](https://grafana.com/docs/grafana/latest/developers/plugins/authentication/). + #Route: { + // For data source plugins. The route path that is replaced by the + // route URL field when proxying the call. + path?: string + + // For data source plugins. Route method matches the HTTP verb + // like GET or POST. Multiple methods can be provided as a + // comma-separated list. + method?: string + + // For data source plugins. Route URL is where the request is + // proxied to. + url?: string + + urlParams?: [...#URLParam] + reqSignedIn?: bool + reqRole?: string + + // For data source plugins. Route headers adds HTTP headers to the + // proxied request. + headers?: [...#Header] + + // For data source plugins. Route headers set the body content and + // length to the proxied request. + body?: { + ... + } + + // For data source plugins. Token authentication section used with + // an OAuth API. + tokenAuth?: #TokenAuth + + // For data source plugins. Token authentication section used with + // an JWT OAuth API. + jwtTokenAuth?: #JWTTokenAuth + } + + // TODO docs + #TokenAuth: { + // URL to fetch the authentication token. + url?: string + + // The list of scopes that your application should be granted + // access to. + scopes?: [...string] + + // Parameters for the token authentication request. + params: [string]: string + } + + // TODO docs + // TODO should this really be separate from TokenAuth? + #JWTTokenAuth: { + // URL to fetch the JWT token. + url: string + + // The list of scopes that your application should be granted + // access to. + scopes: [...string] + + // Parameters for the JWT token authentication request. + params: [string]: string + } + + // Grafana Enerprise specific features. + enterpriseFeatures?: { + // Enable/Disable health diagnostics errors. Requires Grafana + // >=7.5.5. + healthDiagnosticsErrors?: bool | *false + ... + } + }, + ] + }, +] diff --git a/pkg/coremodel/pluginmeta/pluginmeta_gen.go b/pkg/coremodel/pluginmeta/pluginmeta_gen.go new file mode 100644 index 00000000000..4e9bfc17c79 --- /dev/null +++ b/pkg/coremodel/pluginmeta/pluginmeta_gen.go @@ -0,0 +1,590 @@ +// This file is autogenerated. DO NOT EDIT. +// +// Run "make gen-cue" from repository root to regenerate. +// +// Derived from the Thema lineage at pkg/coremodel/pluginmeta + +package pluginmeta + +import ( + "embed" + "path/filepath" + + "github.com/grafana/grafana/pkg/cuectx" + "github.com/grafana/grafana/pkg/framework/coremodel" + "github.com/grafana/thema" +) + +// Defines values for PluginmetaCategory. +const ( + CategoryCloud Category = "cloud" + + CategoryEnterprise Category = "enterprise" + + CategoryLogging Category = "logging" + + CategoryOther Category = "other" + + CategorySql Category = "sql" + + CategoryTracing Category = "tracing" + + CategoryTsdb Category = "tsdb" +) + +// Defines values for PluginmetaType. +const ( + TypeApp Type = "app" + + TypeDatasource Type = "datasource" + + TypePanel Type = "panel" + + TypeRenderer Type = "renderer" + + TypeSecretsmanager Type = "secretsmanager" +) + +// Defines values for PluginmetaDependencyType. +const ( + DependencyTypeApp DependencyType = "app" + + DependencyTypeDatasource DependencyType = "datasource" + + DependencyTypePanel DependencyType = "panel" +) + +// Defines values for PluginmetaIncludeRole. +const ( + IncludeRoleAdmin IncludeRole = "Admin" + + IncludeRoleEditor IncludeRole = "Editor" + + IncludeRoleViewer IncludeRole = "Viewer" +) + +// Defines values for PluginmetaIncludeType. +const ( + IncludeTypeApp IncludeType = "app" + + IncludeTypeDashboard IncludeType = "dashboard" + + IncludeTypeDatasource IncludeType = "datasource" + + IncludeTypePage IncludeType = "page" + + IncludeTypePanel IncludeType = "panel" + + IncludeTypeRenderer IncludeType = "renderer" + + IncludeTypeSecretsmanager IncludeType = "secretsmanager" +) + +// Defines values for PluginmetaReleaseState. +const ( + ReleaseStateAlpha ReleaseState = "alpha" + + ReleaseStateBeta ReleaseState = "beta" + + ReleaseStateStable ReleaseState = "stable" +) + +// Pluginmeta defines model for pluginmeta. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Model struct { + // For data source plugins, if the plugin supports alerting. + Alerting *bool `json:"alerting,omitempty"` + + // For data source plugins, if the plugin supports annotation + // queries. + Annotations *bool `json:"annotations,omitempty"` + + // Set to true for app plugins that should be enabled by default + // in all orgs + AutoEnabled *bool `json:"autoEnabled,omitempty"` + + // If the plugin has a backend component. + Backend *bool `json:"backend,omitempty"` + + // Plugin category used on the Add data source page. + Category *Category `json:"category,omitempty"` + + // Dependencies needed by the plugin. + Dependencies struct { + // Required Grafana version for this plugin. Validated using + // https://github.com/npm/node-semver. + GrafanaDependency string `json:"grafanaDependency"` + + // (Deprecated) Required Grafana version for this plugin, e.g. + // `6.x.x 7.x.x` to denote plugin requires Grafana v6.x.x or + // v7.x.x. + GrafanaVersion *string `json:"grafanaVersion,omitempty"` + + // An array of required plugins on which this plugin depends. + Plugins *[]Dependency `json:"plugins,omitempty"` + } `json:"dependencies"` + + // Grafana Enerprise specific features. + EnterpriseFeatures *struct { + // Enable/Disable health diagnostics errors. Requires Grafana + // >=7.5.5. + HealthDiagnosticsErrors *bool `json:"healthDiagnosticsErrors,omitempty"` + } `json:"enterpriseFeatures,omitempty"` + + // The first part of the file name of the backend component + // executable. There can be multiple executables built for + // different operating system and architecture. Grafana will + // check for executables named `_<$GOOS>_<.exe for Windows>`, e.g. `plugin_linux_amd64`. + // Combination of $GOOS and $GOARCH can be found here: + // https://golang.org/doc/install/source#environment. + Executable *string `json:"executable,omitempty"` + + // For data source plugins, include hidden queries in the data + // request. + HiddenQueries *bool `json:"hiddenQueries,omitempty"` + + // Unique name of the plugin. If the plugin is published on + // grafana.com, then the plugin id has to follow the naming + // conventions. + Id string `json:"id"` + + // Resources to include in plugin. + Includes *[]Include `json:"includes,omitempty"` + + // Metadata about the plugin. + Info struct { + // Information about the plugin author. + Author *struct { + // Author's name. + Email *string `json:"email,omitempty"` + + // Author's name. + Name *string `json:"name,omitempty"` + + // Link to author's website. + Url *string `json:"url,omitempty"` + } `json:"author,omitempty"` + Build *BuildInfo `json:"build,omitempty"` + + // Description of plugin. Used on the plugins page in Grafana and + // for search on grafana.com. + Description *string `json:"description,omitempty"` + + // Array of plugin keywords. Used for search on grafana.com. + Keywords []string `json:"keywords"` + + // An array of link objects to be displayed on this plugin's + // project page in the form `{name: 'foo', url: + // 'http://example.com'}` + Links *[]struct { + Name *string `json:"name,omitempty"` + Url *string `json:"url,omitempty"` + } `json:"links,omitempty"` + + // SVG images that are used as plugin icons. + Logos struct { + // Link to the "large" version of the plugin logo, which must be + // an SVG image. "Large" and "small" logos can be the same image. + Large string `json:"large"` + + // Link to the "small" version of the plugin logo, which must be + // an SVG image. "Large" and "small" logos can be the same image. + Small string `json:"small"` + } `json:"logos"` + + // An array of screenshot objects in the form `{name: 'bar', path: + // 'img/screenshot.png'}` + Screenshots *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"screenshots,omitempty"` + + // Date when this plugin was built. + Updated string `json:"updated"` + + // Project version of this commit, e.g. `6.7.x`. + Version string `json:"version"` + } `json:"info"` + + // For data source plugins, if the plugin supports logs. + Logs *bool `json:"logs,omitempty"` + + // For data source plugins, if the plugin supports metric queries. + // Used in Explore. + Metrics *bool `json:"metrics,omitempty"` + + // Human-readable name of the plugin that is shown to the user in + // the UI. + Name string `json:"name"` + + // Initialize plugin on startup. By default, the plugin + // initializes on first use. + Preload *bool `json:"preload,omitempty"` + + // For data source plugins. There is a query options section in + // the plugin's query editor and these options can be turned on + // if needed. + QueryOptions *struct { + // For data source plugins. If the `cache timeout` option should + // be shown in the query options section in the query editor. + CacheTimeout *bool `json:"cacheTimeout,omitempty"` + + // For data source plugins. If the `max data points` option should + // be shown in the query options section in the query editor. + MaxDataPoints *bool `json:"maxDataPoints,omitempty"` + + // For data source plugins. If the `min interval` option should be + // shown in the query options section in the query editor. + MinInterval *bool `json:"minInterval,omitempty"` + } `json:"queryOptions,omitempty"` + + // Routes is a list of proxy routes, if any. For datasource plugins only. + Routes *[]Route `json:"routes,omitempty"` + + // For panel plugins. Hides the query editor. + SkipDataQuery *bool `json:"skipDataQuery,omitempty"` + + // ReleaseState indicates release maturity state of a plugin. + State *ReleaseState `json:"state,omitempty"` + + // For data source plugins, if the plugin supports streaming. + Streaming *bool `json:"streaming,omitempty"` + + // This is an undocumented feature. + Tables *bool `json:"tables,omitempty"` + + // For data source plugins, if the plugin supports tracing. + Tracing *bool `json:"tracing,omitempty"` + + // type indicates which type of Grafana plugin this is, of the defined + // set of Grafana plugin types. + Type Type `json:"type"` +} + +// Plugin category used on the Add data source page. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Category string + +// type indicates which type of Grafana plugin this is, of the defined +// set of Grafana plugin types. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Type string + +// PluginmetaBuildInfo defines model for pluginmeta.BuildInfo. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type BuildInfo struct { + // Git branch the plugin was built from. + Branch *string `json:"branch,omitempty"` + + // Git hash of the commit the plugin was built from + Hash *string `json:"hash,omitempty"` + Number *int64 `json:"number,omitempty"` + + // GitHub pull request the plugin was built from + Pr *int32 `json:"pr,omitempty"` + Repo *string `json:"repo,omitempty"` + + // Time when the plugin was built, as a Unix timestamp. + Time *int64 `json:"time,omitempty"` +} + +// PluginmetaDependencies defines model for pluginmeta.Dependencies. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Dependencies struct { + // Required Grafana version for this plugin. Validated using + // https://github.com/npm/node-semver. + GrafanaDependency string `json:"grafanaDependency"` + + // (Deprecated) Required Grafana version for this plugin, e.g. + // `6.x.x 7.x.x` to denote plugin requires Grafana v6.x.x or + // v7.x.x. + GrafanaVersion *string `json:"grafanaVersion,omitempty"` + + // An array of required plugins on which this plugin depends. + Plugins *[]Dependency `json:"plugins,omitempty"` +} + +// Dependency describes another plugin on which a plugin depends. +// The id refers to the plugin package identifier, as given on +// the grafana.com plugin marketplace. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Dependency struct { + Id string `json:"id"` + Name string `json:"name"` + Type DependencyType `json:"type"` + Version string `json:"version"` +} + +// PluginmetaDependencyType defines model for PluginmetaDependency.Type. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type DependencyType string + +// Header describes an HTTP header that is forwarded with a proxied request for +// a plugin route. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Header struct { + Content string `json:"content"` + Name string `json:"name"` +} + +// A resource to be included in a plugin. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Include struct { + // Add the include to the side menu. + AddToNav *bool `json:"addToNav,omitempty"` + + // (Legacy) The Angular component to use for a page. + Component *string `json:"component,omitempty"` + + // Page or dashboard when user clicks the icon in the side menu. + DefaultNav *bool `json:"defaultNav,omitempty"` + + // Icon to use in the side menu. For information on available + // icon, refer to [Icons + // Overview](https://developers.grafana.com/ui/latest/index.html?path=/story/docs-overview-icon--icons-overview). + Icon *string `json:"icon,omitempty"` + Name *string `json:"name,omitempty"` + + // Used for app plugins. + Path *string `json:"path,omitempty"` + Role *IncludeRole `json:"role,omitempty"` + Type IncludeType `json:"type"` + + // Unique identifier of the included resource + Uid *string `json:"uid,omitempty"` +} + +// PluginmetaIncludeRole defines model for PluginmetaInclude.Role. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type IncludeRole string + +// PluginmetaIncludeType defines model for PluginmetaInclude.Type. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type IncludeType string + +// Metadata about a Grafana plugin. Some fields are used on the plugins +// page in Grafana and others on grafana.com, if the plugin is published. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Info struct { + // Information about the plugin author. + Author *struct { + // Author's name. + Email *string `json:"email,omitempty"` + + // Author's name. + Name *string `json:"name,omitempty"` + + // Link to author's website. + Url *string `json:"url,omitempty"` + } `json:"author,omitempty"` + Build *BuildInfo `json:"build,omitempty"` + + // Description of plugin. Used on the plugins page in Grafana and + // for search on grafana.com. + Description *string `json:"description,omitempty"` + + // Array of plugin keywords. Used for search on grafana.com. + Keywords []string `json:"keywords"` + + // An array of link objects to be displayed on this plugin's + // project page in the form `{name: 'foo', url: + // 'http://example.com'}` + Links *[]struct { + Name *string `json:"name,omitempty"` + Url *string `json:"url,omitempty"` + } `json:"links,omitempty"` + + // SVG images that are used as plugin icons. + Logos struct { + // Link to the "large" version of the plugin logo, which must be + // an SVG image. "Large" and "small" logos can be the same image. + Large string `json:"large"` + + // Link to the "small" version of the plugin logo, which must be + // an SVG image. "Large" and "small" logos can be the same image. + Small string `json:"small"` + } `json:"logos"` + + // An array of screenshot objects in the form `{name: 'bar', path: + // 'img/screenshot.png'}` + Screenshots *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"screenshots,omitempty"` + + // Date when this plugin was built. + Updated string `json:"updated"` + + // Project version of this commit, e.g. `6.7.x`. + Version string `json:"version"` +} + +// TODO docs +// TODO should this really be separate from TokenAuth? +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type JWTTokenAuth struct { + // Parameters for the JWT token authentication request. + Params map[string]interface{} `json:"params"` + + // The list of scopes that your application should be granted + // access to. + Scopes []string `json:"scopes"` + + // URL to fetch the JWT token. + Url string `json:"url"` +} + +// ReleaseState indicates release maturity state of a plugin. +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type ReleaseState string + +// A proxy route used in datasource plugins for plugin authentication +// and adding headers to HTTP requests made by the plugin. +// For more information, refer to [Authentication for data source +// plugins](https://grafana.com/docs/grafana/latest/developers/plugins/authentication/). +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type Route struct { + // For data source plugins. Route headers set the body content and + // length to the proxied request. + Body *map[string]interface{} `json:"body,omitempty"` + + // For data source plugins. Route headers adds HTTP headers to the + // proxied request. + Headers *[]Header `json:"headers,omitempty"` + + // TODO docs + // TODO should this really be separate from TokenAuth? + JwtTokenAuth *JWTTokenAuth `json:"jwtTokenAuth,omitempty"` + + // For data source plugins. Route method matches the HTTP verb + // like GET or POST. Multiple methods can be provided as a + // comma-separated list. + Method *string `json:"method,omitempty"` + + // For data source plugins. The route path that is replaced by the + // route URL field when proxying the call. + Path *string `json:"path,omitempty"` + ReqRole *string `json:"reqRole,omitempty"` + ReqSignedIn *bool `json:"reqSignedIn,omitempty"` + + // TODO docs + TokenAuth *TokenAuth `json:"tokenAuth,omitempty"` + + // For data source plugins. Route URL is where the request is + // proxied to. + Url *string `json:"url,omitempty"` + UrlParams *[]URLParam `json:"urlParams,omitempty"` +} + +// TODO docs +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type TokenAuth struct { + // Parameters for the token authentication request. + Params map[string]interface{} `json:"params"` + + // The list of scopes that your application should be granted + // access to. + Scopes *[]string `json:"scopes,omitempty"` + + // URL to fetch the authentication token. + Url *string `json:"url,omitempty"` +} + +// URLParam describes query string parameters for +// a url in a plugin route +// +// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES. +// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok. +type URLParam struct { + Content string `json:"content"` + Name string `json:"name"` +} + +//go:embed coremodel.cue +var cueFS embed.FS + +// codegen ensures that this is always the latest Thema schema version +var currentVersion = thema.SV(0, 0) + +// Lineage returns the Thema lineage representing a Grafana pluginmeta. +// +// The lineage is the canonical specification of the current pluginmeta schema, +// all prior schema versions, and the mappings that allow migration between +// schema versions. +func Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) { + return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "pluginmeta"), cueFS, lib, opts...) +} + +var _ thema.LineageFactory = Lineage +var _ coremodel.Interface = &Coremodel{} + +// Coremodel contains the foundational schema declaration for pluginmetas. +// It implements coremodel.Interface. +type Coremodel struct { + lin thema.Lineage +} + +// Lineage returns the canonical pluginmeta Lineage. +func (c *Coremodel) Lineage() thema.Lineage { + return c.lin +} + +// CurrentSchema returns the current (latest) pluginmeta Thema schema. +func (c *Coremodel) CurrentSchema() thema.Schema { + return thema.SchemaP(c.lin, currentVersion) +} + +// GoType returns a pointer to an empty Go struct that corresponds to +// the current Thema schema. +func (c *Coremodel) GoType() interface{} { + return &Model{} +} + +// New returns a new instance of the pluginmeta coremodel. +// +// Note that this function does not cache, and initially loading a Thema lineage +// can be expensive. As such, the Grafana backend should prefer to access this +// coremodel through a registry (pkg/framework/coremodel/registry), which does cache. +func New(lib thema.Library) (*Coremodel, error) { + lin, err := Lineage(lib) + if err != nil { + return nil, err + } + + return &Coremodel{ + lin: lin, + }, nil +} diff --git a/pkg/framework/coremodel/gen.go b/pkg/framework/coremodel/gen.go index 2d0796e7ac8..61115cbf850 100644 --- a/pkg/framework/coremodel/gen.go +++ b/pkg/framework/coremodel/gen.go @@ -72,12 +72,15 @@ func main() { } wd.Merge(gofiles) - tsfiles, err := ls.GenerateTypescriptCoremodel(filepath.Join(tsroot, ls.Lineage.Name())) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to generate TypeScript for %s: %s\n", ls.Lineage.Name(), err) - os.Exit(1) + // Only generate TS for API types + if ls.IsAPIType { + tsfiles, err := ls.GenerateTypescriptCoremodel(filepath.Join(tsroot, ls.Lineage.Name())) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to generate TypeScript for %s: %s\n", ls.Lineage.Name(), err) + os.Exit(1) + } + wd.Merge(tsfiles) } - wd.Merge(tsfiles) } regfiles, err := gcgen.GenerateCoremodelRegistry(filepath.Join(groot, "pkg", "framework", "coremodel", "registry", "registry_gen.go"), lins) diff --git a/pkg/framework/coremodel/registry/registry_gen.go b/pkg/framework/coremodel/registry/registry_gen.go index cdca94666c1..d434dfd636b 100644 --- a/pkg/framework/coremodel/registry/registry_gen.go +++ b/pkg/framework/coremodel/registry/registry_gen.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/grafana/grafana/pkg/coremodel/dashboard" + "github.com/grafana/grafana/pkg/coremodel/pluginmeta" "github.com/grafana/grafana/pkg/framework/coremodel" "github.com/grafana/thema" ) @@ -23,13 +24,15 @@ import ( // Prefer All() when performing operations generically across all coremodels. For example, // a validation HTTP middleware for any coremodel-schematized object type. type Base struct { - all []coremodel.Interface - dashboard *dashboard.Coremodel + all []coremodel.Interface + dashboard *dashboard.Coremodel + pluginmeta *pluginmeta.Coremodel } // type guards var ( _ coremodel.Interface = &dashboard.Coremodel{} + _ coremodel.Interface = &pluginmeta.Coremodel{} ) // Dashboard returns the dashboard coremodel. The return value is guaranteed to @@ -38,6 +41,12 @@ func (s *Base) Dashboard() *dashboard.Coremodel { return s.dashboard } +// Pluginmeta returns the pluginmeta coremodel. The return value is guaranteed to +// implement coremodel.Interface. +func (s *Base) Pluginmeta() *pluginmeta.Coremodel { + return s.pluginmeta +} + func doProvideBase(lib thema.Library) *Base { var err error reg := &Base{} @@ -48,5 +57,11 @@ func doProvideBase(lib thema.Library) *Base { } reg.all = append(reg.all, reg.dashboard) + reg.pluginmeta, err = pluginmeta.New(lib) + if err != nil { + panic(fmt.Sprintf("error while initializing pluginmeta coremodel: %s", err)) + } + reg.all = append(reg.all, reg.pluginmeta) + return reg }