mirror of https://github.com/grafana/grafana.git
Add a CI step for checking app SDK codegen status (#111528)
* Add a CI step for checking app SDK codegen status What This commit adds a CI step for checking the status of code generated with Grafana App SDK. The step fails if there is a git diff as a result of the codegen step. It also updates generated code to make sure we're starting from a correct state. Why This ensures that when the schemas or the SDK version are updated, the codegen mismatch is caught early at the PR stage. Signed-off-by: Igor Suleymanov <igor.suleymanov@grafana.com> * Format generated code Signed-off-by: Igor Suleymanov <igor.suleymanov@grafana.com> --------- Signed-off-by: Igor Suleymanov <igor.suleymanov@grafana.com>
This commit is contained in:
parent
6c8ca56651
commit
7aed0da22c
|
@ -58,6 +58,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
CODEGEN_VERIFY=1 make gen-cue
|
CODEGEN_VERIFY=1 make gen-cue
|
||||||
CODEGEN_VERIFY=1 make gen-jsonnet
|
CODEGEN_VERIFY=1 make gen-jsonnet
|
||||||
|
CODEGEN_VERIFY=1 make gen-apps
|
||||||
|
|
||||||
- name: Validate go.mod
|
- name: Validate go.mod
|
||||||
run: go run scripts/modowners/modowners.go check go.mod
|
run: go run scripts/modowners/modowners.go check go.mod
|
||||||
|
|
16
Makefile
16
Makefile
|
@ -173,7 +173,19 @@ gen-cuev2: ## Do all CUE code generation
|
||||||
APPS_DIRS := ./apps/dashboard ./apps/folder ./apps/alerting/notifications
|
APPS_DIRS := ./apps/dashboard ./apps/folder ./apps/alerting/notifications
|
||||||
|
|
||||||
.PHONY: gen-apps
|
.PHONY: gen-apps
|
||||||
gen-apps: ## Generate code for Grafana App SDK apps
|
gen-apps: do-gen-apps gofmt ## Generate code for Grafana App SDK apps and run gofmt
|
||||||
|
@if [ -n "$$CODEGEN_VERIFY" ]; then \
|
||||||
|
echo "Verifying generated code is up to date..."; \
|
||||||
|
if ! git diff --quiet; then \
|
||||||
|
echo "Error: Generated apps code is not up to date. Please run 'make gen-apps' to regenerate."; \
|
||||||
|
git diff --name-only; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
echo "Generated apps code is up to date."; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
.PHONY: do-gen-apps
|
||||||
|
do-gen-apps: ## Generate code for Grafana App SDK apps
|
||||||
for dir in $(APPS_DIRS); do \
|
for dir in $(APPS_DIRS); do \
|
||||||
$(MAKE) -C $$dir generate; \
|
$(MAKE) -C $$dir generate; \
|
||||||
done
|
done
|
||||||
|
@ -388,7 +400,7 @@ lint-go-diff:
|
||||||
|
|
||||||
.PHONY: gofmt
|
.PHONY: gofmt
|
||||||
gofmt: ## Run gofmt for all Go files.
|
gofmt: ## Run gofmt for all Go files.
|
||||||
gofmt -s -w .
|
@go list -m -f '{{.Dir}}' | xargs -I{} sh -c 'test ! -f {}/.nolint && echo {}' | xargs gofmt -s -w 2>&1 | grep -v '/pkg/build/' || true
|
||||||
|
|
||||||
# with disabled SC1071 we are ignored some TCL,Expect `/usr/bin/env expect` scripts
|
# with disabled SC1071 we are ignored some TCL,Expect `/usr/bin/env expect` scripts
|
||||||
.PHONY: shellcheck
|
.PHONY: shellcheck
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (c *DashboardClient) Patch(ctx context.Context, identifier resource.Identif
|
||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
func (c *DashboardClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
||||||
return c.client.Update(ctx, &Dashboard{
|
return c.client.Update(ctx, &Dashboard{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: DashboardKind().Kind(),
|
Kind: DashboardKind().Kind(),
|
||||||
|
@ -84,6 +84,8 @@ func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardS
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
ResourceVersion: opts.ResourceVersion,
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Namespace: identifier.Namespace,
|
||||||
|
Name: identifier.Name,
|
||||||
},
|
},
|
||||||
Status: newStatus,
|
Status: newStatus,
|
||||||
}, resource.UpdateOptions{
|
}, resource.UpdateOptions{
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (c *DashboardClient) Patch(ctx context.Context, identifier resource.Identif
|
||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
func (c *DashboardClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
||||||
return c.client.Update(ctx, &Dashboard{
|
return c.client.Update(ctx, &Dashboard{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: DashboardKind().Kind(),
|
Kind: DashboardKind().Kind(),
|
||||||
|
@ -84,6 +84,8 @@ func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardS
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
ResourceVersion: opts.ResourceVersion,
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Namespace: identifier.Namespace,
|
||||||
|
Name: identifier.Name,
|
||||||
},
|
},
|
||||||
Status: newStatus,
|
Status: newStatus,
|
||||||
}, resource.UpdateOptions{
|
}, resource.UpdateOptions{
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (c *DashboardClient) Patch(ctx context.Context, identifier resource.Identif
|
||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
func (c *DashboardClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
||||||
return c.client.Update(ctx, &Dashboard{
|
return c.client.Update(ctx, &Dashboard{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: DashboardKind().Kind(),
|
Kind: DashboardKind().Kind(),
|
||||||
|
@ -84,6 +84,8 @@ func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardS
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
ResourceVersion: opts.ResourceVersion,
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Namespace: identifier.Namespace,
|
||||||
|
Name: identifier.Name,
|
||||||
},
|
},
|
||||||
Status: newStatus,
|
Status: newStatus,
|
||||||
}, resource.UpdateOptions{
|
}, resource.UpdateOptions{
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (c *DashboardClient) Patch(ctx context.Context, identifier resource.Identif
|
||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
func (c *DashboardClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus DashboardStatus, opts resource.UpdateOptions) (*Dashboard, error) {
|
||||||
return c.client.Update(ctx, &Dashboard{
|
return c.client.Update(ctx, &Dashboard{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: DashboardKind().Kind(),
|
Kind: DashboardKind().Kind(),
|
||||||
|
@ -84,6 +84,8 @@ func (c *DashboardClient) UpdateStatus(ctx context.Context, newStatus DashboardS
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
ResourceVersion: opts.ResourceVersion,
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Namespace: identifier.Namespace,
|
||||||
|
Name: identifier.Name,
|
||||||
},
|
},
|
||||||
Status: newStatus,
|
Status: newStatus,
|
||||||
}, resource.UpdateOptions{
|
}, resource.UpdateOptions{
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/grafana/grafana-app-sdk/app"
|
"github.com/grafana/grafana-app-sdk/app"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/kube-openapi/pkg/spec3"
|
||||||
|
|
||||||
v0alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
v0alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||||
v1beta1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
v1beta1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||||
|
@ -34,6 +35,10 @@ var appManifestData = app.ManifestData{
|
||||||
Conversion: false,
|
Conversion: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Routes: app.ManifestVersionRoutes{
|
||||||
|
Namespaced: map[string]spec3.PathProps{},
|
||||||
|
Cluster: map[string]spec3.PathProps{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -47,6 +52,10 @@ var appManifestData = app.ManifestData{
|
||||||
Conversion: false,
|
Conversion: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Routes: app.ManifestVersionRoutes{
|
||||||
|
Namespaced: map[string]spec3.PathProps{},
|
||||||
|
Cluster: map[string]spec3.PathProps{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -60,6 +69,10 @@ var appManifestData = app.ManifestData{
|
||||||
Conversion: false,
|
Conversion: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Routes: app.ManifestVersionRoutes{
|
||||||
|
Namespaced: map[string]spec3.PathProps{},
|
||||||
|
Cluster: map[string]spec3.PathProps{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -73,6 +86,10 @@ var appManifestData = app.ManifestData{
|
||||||
Conversion: false,
|
Conversion: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Routes: app.ManifestVersionRoutes{
|
||||||
|
Namespaced: map[string]spec3.PathProps{},
|
||||||
|
Cluster: map[string]spec3.PathProps{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -104,6 +121,7 @@ var customRouteToGoResponseType = map[string]any{}
|
||||||
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
||||||
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
||||||
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
||||||
|
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
|
||||||
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
if len(path) > 0 && path[0] == '/' {
|
if len(path) > 0 && path[0] == '/' {
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
|
@ -122,8 +140,22 @@ func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goTyp
|
||||||
return goType, exists
|
return goType, exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var customRouteToGoRequestBodyType = map[string]any{}
|
||||||
|
|
||||||
|
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
|
if len(path) > 0 && path[0] == '/' {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
||||||
|
return goType, exists
|
||||||
|
}
|
||||||
|
|
||||||
type GoTypeAssociator struct{}
|
type GoTypeAssociator struct{}
|
||||||
|
|
||||||
|
func NewGoTypeAssociator() *GoTypeAssociator {
|
||||||
|
return &GoTypeAssociator{}
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
|
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
|
||||||
return ManifestGoTypeAssociator(kind, version)
|
return ManifestGoTypeAssociator(kind, version)
|
||||||
}
|
}
|
||||||
|
@ -133,3 +165,6 @@ func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb str
|
||||||
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
||||||
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
|
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
|
||||||
}
|
}
|
||||||
|
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
|
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
|
||||||
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (c *FolderClient) Patch(ctx context.Context, identifier resource.Identifier
|
||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FolderClient) UpdateStatus(ctx context.Context, newStatus FolderStatus, opts resource.UpdateOptions) (*Folder, error) {
|
func (c *FolderClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus FolderStatus, opts resource.UpdateOptions) (*Folder, error) {
|
||||||
return c.client.Update(ctx, &Folder{
|
return c.client.Update(ctx, &Folder{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: FolderKind().Kind(),
|
Kind: FolderKind().Kind(),
|
||||||
|
@ -84,6 +84,8 @@ func (c *FolderClient) UpdateStatus(ctx context.Context, newStatus FolderStatus,
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
ResourceVersion: opts.ResourceVersion,
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Namespace: identifier.Namespace,
|
||||||
|
Name: identifier.Name,
|
||||||
},
|
},
|
||||||
Status: newStatus,
|
Status: newStatus,
|
||||||
}, resource.UpdateOptions{
|
}, resource.UpdateOptions{
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/grafana/grafana-app-sdk/app"
|
"github.com/grafana/grafana-app-sdk/app"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/kube-openapi/pkg/spec3"
|
||||||
|
|
||||||
v1beta1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
v1beta1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||||
)
|
)
|
||||||
|
@ -31,6 +32,10 @@ var appManifestData = app.ManifestData{
|
||||||
Conversion: false,
|
Conversion: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Routes: app.ManifestVersionRoutes{
|
||||||
|
Namespaced: map[string]spec3.PathProps{},
|
||||||
|
Cluster: map[string]spec3.PathProps{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -59,6 +64,7 @@ var customRouteToGoResponseType = map[string]any{}
|
||||||
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
||||||
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
||||||
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
||||||
|
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
|
||||||
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
if len(path) > 0 && path[0] == '/' {
|
if len(path) > 0 && path[0] == '/' {
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
|
@ -77,8 +83,22 @@ func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goTyp
|
||||||
return goType, exists
|
return goType, exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var customRouteToGoRequestBodyType = map[string]any{}
|
||||||
|
|
||||||
|
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
|
if len(path) > 0 && path[0] == '/' {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
||||||
|
return goType, exists
|
||||||
|
}
|
||||||
|
|
||||||
type GoTypeAssociator struct{}
|
type GoTypeAssociator struct{}
|
||||||
|
|
||||||
|
func NewGoTypeAssociator() *GoTypeAssociator {
|
||||||
|
return &GoTypeAssociator{}
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
|
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
|
||||||
return ManifestGoTypeAssociator(kind, version)
|
return ManifestGoTypeAssociator(kind, version)
|
||||||
}
|
}
|
||||||
|
@ -88,3 +108,6 @@ func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb str
|
||||||
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
||||||
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
|
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
|
||||||
}
|
}
|
||||||
|
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
|
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue