mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 00:47:38 -06:00
schema: Generate Go and Typescript from Thema coremodels (#49193)
* Add go code generator for coremodels * Just generate the entire coremodel for now Maybe we'll need more flexibility as more coremodels are added, but for now this is fine. * Add note on type comment about stability, grodkit * Remove local replace directive for thema * Generate typescript from coremodel * Update pkg/coremodel/dashboard/addenda.go Co-authored-by: Ryan McKinley <ryantxu@gmail.com> * Update cuetsy to new release * Update thema to latest * Fix enum generation for FieldColorModeId * Put main generated object at the end of the file * Tweaks to generated Go output * Retweak back to var * Add generated coremodel test * Remove local replace statement again * Add Make target and call into cuetsy cmd from gen * Rename and comment linsrc for readability * Move key codegen bits into reusable package * Move body of cuetsifier into codegen pkg Also genericize the diffing output into reusable WriteDiffer. * Refactor coremodel generator to use WriteDiffer * Add gen-cue step to CI * Whip all the codegen automation into shape * Add simplistic coremodel canonicality controls * Remove erroneously committed test * Bump thema version * Remove dead code * Improve wording of non-canonicality comment Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
a641949a05
commit
be06d37a20
50
.drone.yml
50
.drone.yml
@ -254,6 +254,14 @@ steps:
|
||||
- validate-scuemata
|
||||
image: grafana/build-container:1.5.4
|
||||
name: ensure-cuetsified
|
||||
- commands:
|
||||
- '# It is required that code generated from Thema/CUE be committed and in sync
|
||||
with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- CODEGEN_VERIFY=1 make gen-cue
|
||||
image: grafana/build-container:1.5.4
|
||||
name: verify-gen-cue
|
||||
- commands:
|
||||
- . scripts/build/gpg-test-vars.sh && ./bin/grabpl package --jobs 8 --edition oss
|
||||
--build-id ${DRONE_BUILD_NUMBER} --variants linux-amd64,linux-amd64-musl,darwin-amd64,windows-amd64,armv6
|
||||
@ -941,6 +949,14 @@ steps:
|
||||
- validate-scuemata
|
||||
image: grafana/build-container:1.5.4
|
||||
name: ensure-cuetsified
|
||||
- commands:
|
||||
- '# It is required that code generated from Thema/CUE be committed and in sync
|
||||
with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- CODEGEN_VERIFY=1 make gen-cue
|
||||
image: grafana/build-container:1.5.4
|
||||
name: verify-gen-cue
|
||||
- commands:
|
||||
- ./bin/grabpl package --jobs 8 --edition oss --build-id ${DRONE_BUILD_NUMBER} --sign
|
||||
depends_on:
|
||||
@ -1581,6 +1597,14 @@ steps:
|
||||
- validate-scuemata
|
||||
image: grafana/build-container:1.5.4
|
||||
name: ensure-cuetsified
|
||||
- commands:
|
||||
- '# It is required that code generated from Thema/CUE be committed and in sync
|
||||
with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- CODEGEN_VERIFY=1 make gen-cue
|
||||
image: grafana/build-container:1.5.4
|
||||
name: verify-gen-cue
|
||||
- commands:
|
||||
- ./bin/grabpl package --jobs 8 --edition oss --sign ${DRONE_TAG}
|
||||
depends_on:
|
||||
@ -2178,6 +2202,14 @@ steps:
|
||||
- validate-scuemata
|
||||
image: grafana/build-container:1.5.4
|
||||
name: ensure-cuetsified
|
||||
- commands:
|
||||
- '# It is required that code generated from Thema/CUE be committed and in sync
|
||||
with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- CODEGEN_VERIFY=1 make gen-cue
|
||||
image: grafana/build-container:1.5.4
|
||||
name: verify-gen-cue
|
||||
- commands:
|
||||
- ./bin/grabpl build-backend --jobs 8 --edition enterprise2 ${DRONE_TAG}
|
||||
depends_on:
|
||||
@ -3391,6 +3423,14 @@ steps:
|
||||
- validate-scuemata
|
||||
image: grafana/build-container:1.5.4
|
||||
name: ensure-cuetsified
|
||||
- commands:
|
||||
- '# It is required that code generated from Thema/CUE be committed and in sync
|
||||
with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- CODEGEN_VERIFY=1 make gen-cue
|
||||
image: grafana/build-container:1.5.4
|
||||
name: verify-gen-cue
|
||||
- commands:
|
||||
- ./bin/grabpl package --jobs 8 --edition oss --build-id ${DRONE_BUILD_NUMBER} --sign
|
||||
depends_on:
|
||||
@ -3933,6 +3973,14 @@ steps:
|
||||
- validate-scuemata
|
||||
image: grafana/build-container:1.5.4
|
||||
name: ensure-cuetsified
|
||||
- commands:
|
||||
- '# It is required that code generated from Thema/CUE be committed and in sync
|
||||
with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- CODEGEN_VERIFY=1 make gen-cue
|
||||
image: grafana/build-container:1.5.4
|
||||
name: verify-gen-cue
|
||||
- commands:
|
||||
- ./bin/grabpl build-backend --jobs 8 --edition enterprise2 --build-id ${DRONE_BUILD_NUMBER}
|
||||
--variants linux-amd64
|
||||
@ -4667,6 +4715,6 @@ kind: secret
|
||||
name: gcp_upload_artifacts_key
|
||||
---
|
||||
kind: signature
|
||||
hmac: a697f4b02af2da0fc6c0d751e40e59db542541d6024e5f0c2b062c7060d635ab
|
||||
hmac: fb64e50c271012ad1cc9b7ad7e7bd037736d6e3471d24f73774e8fd61472600c
|
||||
|
||||
...
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -158,6 +158,7 @@ compilation-stats.json
|
||||
# auto generated Go files
|
||||
*_gen.go
|
||||
!pkg/services/featuremgmt/toggles_gen.go
|
||||
!pkg/coremodel/**/*_gen.go
|
||||
|
||||
# Auto-generated localisation files
|
||||
public/locales/_build/
|
||||
|
5
Makefile
5
Makefile
@ -83,6 +83,11 @@ clean-api-spec:
|
||||
|
||||
##@ Building
|
||||
|
||||
gen-cue: ## Do all CUE/Thema code generation
|
||||
@echo "generate code from .cue files"
|
||||
go generate ./pkg/framework/coremodel
|
||||
go generate ./public/app/plugins
|
||||
|
||||
gen-go: $(WIRE)
|
||||
@echo "generate go files"
|
||||
$(WIRE) gen -tags $(WIRE_TAGS) ./pkg/server ./pkg/cmd/grafana-cli/runner
|
||||
|
20
go.mod
20
go.mod
@ -50,7 +50,7 @@ require (
|
||||
github.com/google/wire v0.5.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/gosimple/slug v1.9.0
|
||||
github.com/grafana/cuetsy v0.0.1
|
||||
github.com/grafana/cuetsy v0.0.2
|
||||
github.com/grafana/grafana-aws-sdk v0.10.3
|
||||
github.com/grafana/grafana-azure-sdk-go v1.2.0
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.134.0
|
||||
@ -101,12 +101,12 @@ require (
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.0.0
|
||||
go.opentelemetry.io/otel/sdk v1.6.3
|
||||
go.opentelemetry.io/otel/trace v1.6.3
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
||||
golang.org/x/exp v0.0.0-20210220032938-85be41e4509f
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
||||
golang.org/x/tools v0.1.10
|
||||
gonum.org/v1/gonum v0.11.0
|
||||
google.golang.org/api v0.74.0
|
||||
@ -147,7 +147,7 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.10.1
|
||||
github.com/dennwc/varint v1.0.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
|
||||
@ -164,7 +164,7 @@ require (
|
||||
github.com/go-openapi/loads v0.20.2
|
||||
github.com/go-openapi/runtime v0.19.29 // indirect
|
||||
github.com/go-openapi/spec v0.20.4
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-openapi/validate v0.20.2 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/gogo/status v1.1.0 // indirect
|
||||
@ -182,7 +182,7 @@ require (
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.5 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 // indirect
|
||||
@ -245,6 +245,7 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.17
|
||||
github.com/armon/go-radix v1.0.0
|
||||
github.com/blugelabs/bluge v0.1.9
|
||||
github.com/getkin/kin-openapi v0.94.0
|
||||
github.com/golang-migrate/migrate/v4 v4.7.0
|
||||
github.com/grafana/dskit v0.0.0-20211011144203-3a88ec0b675f
|
||||
github.com/grafana/thema v0.0.0-20220523183731-72aebd14e751
|
||||
@ -289,7 +290,6 @@ require (
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20220115173737-adb46da277ac // indirect
|
||||
github.com/getkin/kin-openapi v0.94.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@ -298,15 +298,19 @@ require (
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/klauspost/compress v1.15.1 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/labstack/echo/v4 v4.7.2 // indirect
|
||||
github.com/labstack/gommon v0.3.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.8 // indirect
|
||||
github.com/segmentio/asm v1.1.1 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
github.com/xlab/treeprint v1.1.0 // indirect
|
||||
github.com/yudai/pp v2.0.1+incompatible // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.15.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
k8s.io/api v0.22.5 // indirect
|
||||
k8s.io/apimachinery v0.22.5 // indirect
|
||||
k8s.io/klog/v2 v2.30.0 // indirect
|
||||
|
59
go.sum
59
go.sum
@ -768,9 +768,13 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||
github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=
|
||||
github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU=
|
||||
github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=
|
||||
github.com/deepmap/oapi-codegen v1.10.1 h1:xybuJUR6D8l7P+LAuxOm5SD7nTlFKHWvOPl31q+DDVs=
|
||||
github.com/deepmap/oapi-codegen v1.10.1/go.mod h1:TvVmDQlUkFli9gFij/gtW1o+tFBr4qCHyv2zG+R0YZY=
|
||||
github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
|
||||
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
|
||||
github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
|
||||
@ -881,7 +885,6 @@ github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac/go.mod h1:gNh8
|
||||
github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/proto v1.6.15 h1:XbpwxmuOPrdES97FrSfpyy67SSCV/wBIKXqgJzh6hNw=
|
||||
github.com/emicklei/proto v1.6.15/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/emicklei/proto v1.10.0 h1:pDGyFRVV5RvV+nkBK9iy3q67FBy9Xa7vwrOTE+g5aGw=
|
||||
github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
@ -969,6 +972,7 @@ github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||
github.com/go-chi/chi v4.1.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
|
||||
@ -1121,8 +1125,9 @@ github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72P
|
||||
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
|
||||
github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
@ -1139,8 +1144,11 @@ github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhO
|
||||
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis/v8 v8.0.0-beta.10.0.20200905143926-df7fe4e2ce72/go.mod h1:CJP1ZIHwhosNYwIdaHPZK9vHsM3+roNBaZ7U9Of1DXc=
|
||||
@ -1196,6 +1204,7 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
|
||||
github.com/gocql/gocql v0.0.0-20200121121104-95d072f1b5bb/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY=
|
||||
github.com/gocql/gocql v0.0.0-20200228163523-cd4b606dd2fb/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY=
|
||||
@ -1293,6 +1302,7 @@ github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 h1:utua3L2IbQJmauC5IXdEA547bcoU5dozgQAfc8Onsg4=
|
||||
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
|
||||
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
@ -1438,8 +1448,8 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
|
||||
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
|
||||
github.com/grafana/cuetsy v0.0.1 h1:HEoYBiEb8zRq70kc0WSVG+bZ85W8nQ8BQr4l7f2kl0s=
|
||||
github.com/grafana/cuetsy v0.0.1/go.mod h1:h8fQHb+IHbLjJ6UpaAuRtd8qV6D2JEm+j9rSk3G2Dik=
|
||||
github.com/grafana/cuetsy v0.0.2 h1:0vbU+MNznzxFyaUtbqZ6UGiOrm4HotPQGLyc121xGC8=
|
||||
github.com/grafana/cuetsy v0.0.2/go.mod h1:7OoEYb42s7PbSYtNUTy1DoCeJ3LAOTafsZbndvikTj8=
|
||||
github.com/grafana/dskit v0.0.0-20211011144203-3a88ec0b675f h1:FvvSVEbnGeM2bUivGmsiXTi8URJyBU7TcFEEoRe5wWI=
|
||||
github.com/grafana/dskit v0.0.0-20211011144203-3a88ec0b675f/go.mod h1:uPG2nyK4CtgNDmWv7qyzYcdI+S90kHHRWvHnBtEMBXM=
|
||||
github.com/grafana/go-mssqldb v0.0.0-20210326084033-d0ce3c521036 h1:GplhUk6Xes5JIhUUrggPcPBhOn+eT8+WsHiebvq7GgA=
|
||||
@ -1868,7 +1878,11 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
|
||||
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
|
||||
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/laher/mergefs v0.1.1 h1:nV2bTS57vrmbMxeR6uvJpI8LyGl3QHj4bLBZO3aUV58=
|
||||
github.com/laher/mergefs v0.1.1/go.mod h1:FSY1hYy94on4Tz60waRMGdO1awwS23BacqJlqf9lJ9Q=
|
||||
github.com/lann/builder v0.0.0-20150808151131-f22ce00fd939/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
@ -1878,8 +1892,17 @@ github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkO
|
||||
github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 h1:X/79QL0b4YJVO5+OsPH9rF2u428CIrGL/jLmPsoOQQ4=
|
||||
github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353/go.mod h1:N0SVk0uhy+E1PZ3C9ctsPRlvOPAFPkCNlcPBDkt0N3U=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/leodido/ragel-machinery v0.0.0-20181214104525-299bdde78165/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg=
|
||||
github.com/leoluk/perflib_exporter v0.1.0/go.mod h1:rpV0lYj7lemdTm31t7zpCqYqPnw7xs86f+BaaNBVYFM=
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
|
||||
github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ=
|
||||
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||
github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
|
||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||
github.com/lestrrat-go/jwx v1.2.23/go.mod h1:sAXjRwzSvCN6soO4RLoWWm1bVPpb8iOuv0IYfH8OWd8=
|
||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
@ -1930,6 +1953,7 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||
github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM=
|
||||
@ -2396,7 +2420,6 @@ github.com/prometheus/prometheus v1.8.2-0.20211011171444-354d8d2ecfac/go.mod h1:
|
||||
github.com/prometheus/statsd_exporter v0.20.0/go.mod h1:YL3FWCG8JBBtaUSxAg4Gz2ZYu22bS84XM89ZQXXTWmQ=
|
||||
github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20201118171849-f6a6b3f636fc h1:gSVONBi2HWMFXCa9jFdYvYk7IwW/mTLxWOF7rXS4LO0=
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20201118171849-f6a6b3f636fc/go.mod h1:KbKfKPy2I6ecOIGA9apfheFv14+P3RSmmQvshofQyMY=
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20220428173112-74888fd59c2b h1:zd/2RNzIRkoGGMjE+YIsZ85CnDIz672JK2F3Zl4vux4=
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20220428173112-74888fd59c2b/go.mod h1:KjY0wibdYKc4DYkerHSbguaf3JeIPGhNJBp2BNiFH78=
|
||||
@ -2612,14 +2635,10 @@ github.com/thanos-io/thanos v0.13.1-0.20210224074000-659446cab117/go.mod h1:kdqF
|
||||
github.com/thanos-io/thanos v0.13.1-0.20210226164558-03dace0a1aa1/go.mod h1:gMCy4oCteKTT7VuXVvXLTPGzzjovX1VPE5p+HgL1hyU=
|
||||
github.com/thanos-io/thanos v0.13.1-0.20210401085038-d7dff0c84d17/go.mod h1:zU8KqE+6A+HksK4wiep8e/3UvCZLm+Wrw9AqZGaAm9k=
|
||||
github.com/thanos-io/thanos v0.22.0/go.mod h1:SZDWz3phcUcBr4MYFoPFRvl+Z9Nbi45HlwQlwSZSt+Q=
|
||||
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||
github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
|
||||
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/tinylru v1.0.2/go.mod h1:HDVL7TsWeezQ4g44Um84TOVBMFcq7Xa9giqNc805KJ8=
|
||||
@ -2658,8 +2677,10 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
|
||||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
@ -2674,6 +2695,7 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae h1:oyiy3uBj1F4O3AaFh7hUGBrJjAssJhKyAbwxtkslxqo=
|
||||
@ -2971,8 +2993,11 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@ -3036,6 +3061,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -3132,8 +3158,7 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 h1:yssD99+7tqHWO5Gwh81phT+67hg+KttniBr6UnEXOY8=
|
||||
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -3174,8 +3199,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200930132711-30421366ff76/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -3338,6 +3364,7 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -3352,6 +3379,7 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
@ -3384,8 +3412,9 @@ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -3,4 +3,4 @@
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
export * from './schema/graph.gen';
|
||||
export * from './schema/mudball.gen';
|
||||
|
@ -0,0 +1,222 @@
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from repository root.
|
||||
//
|
||||
// Derived from the Thema lineage at pkg/coremodel/dashboard
|
||||
|
||||
|
||||
// This model is a WIP and not yet canonical. Consequently, its members are
|
||||
// not exported to exclude it from grafana-schema's public API surface.
|
||||
|
||||
interface AnnotationQuery {
|
||||
builtIn: number;
|
||||
datasource: {};
|
||||
enable: boolean;
|
||||
hide?: boolean;
|
||||
iconColor?: string;
|
||||
name?: string;
|
||||
rawQuery?: string;
|
||||
showIn: number;
|
||||
target?: {};
|
||||
type: string;
|
||||
}
|
||||
|
||||
const defaultAnnotationQuery: Partial<AnnotationQuery> = {
|
||||
builtIn: 0,
|
||||
enable: true,
|
||||
hide: false,
|
||||
showIn: 0,
|
||||
type: 'dashboard',
|
||||
};
|
||||
|
||||
interface VariableModel {
|
||||
label?: string;
|
||||
name: string;
|
||||
type: VariableType;
|
||||
}
|
||||
|
||||
interface DashboardLink {
|
||||
asDropdown: boolean;
|
||||
icon?: string;
|
||||
includeVars: boolean;
|
||||
keepTime: boolean;
|
||||
tags: string[];
|
||||
targetBlank: boolean;
|
||||
title: string;
|
||||
tooltip?: string;
|
||||
type: DashboardLinkType;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
const defaultDashboardLink: Partial<DashboardLink> = {
|
||||
asDropdown: false,
|
||||
includeVars: false,
|
||||
keepTime: false,
|
||||
tags: [],
|
||||
targetBlank: false,
|
||||
};
|
||||
|
||||
type DashboardLinkType = 'link' | 'dashboards';
|
||||
|
||||
type VariableType = 'query' | 'adhoc' | 'constant' | 'datasource' | 'interval' | 'textbox' | 'custom' | 'system';
|
||||
|
||||
enum FieldColorModeId {
|
||||
ContinuousGrYlRd = 'continuous-GrYlRd',
|
||||
Fixed = 'fixed',
|
||||
PaletteClassic = 'palette-classic',
|
||||
PaletteSaturated = 'palette-saturated',
|
||||
Thresholds = 'thresholds',
|
||||
}
|
||||
|
||||
type FieldColorSeriesByMode = 'min' | 'max' | 'last';
|
||||
|
||||
interface FieldColor {
|
||||
fixedColor?: string;
|
||||
mode: FieldColorModeId | string;
|
||||
seriesBy?: FieldColorSeriesByMode;
|
||||
}
|
||||
|
||||
interface Threshold {
|
||||
color: string;
|
||||
state?: string;
|
||||
value?: number;
|
||||
}
|
||||
|
||||
enum ThresholdsMode {
|
||||
Absolute = 'absolute',
|
||||
Percentage = 'percentage',
|
||||
}
|
||||
|
||||
interface ThresholdsConfig {
|
||||
mode: ThresholdsMode;
|
||||
steps: Threshold[];
|
||||
}
|
||||
|
||||
const defaultThresholdsConfig: Partial<ThresholdsConfig> = {
|
||||
steps: [],
|
||||
};
|
||||
|
||||
interface Transformation {
|
||||
id: string;
|
||||
options: {};
|
||||
}
|
||||
|
||||
enum DashboardCursorSync {
|
||||
Crosshair = 1,
|
||||
Off = 0,
|
||||
Tooltip = 2,
|
||||
}
|
||||
|
||||
const defaultDashboardCursorSync: DashboardCursorSync = DashboardCursorSync.Off;
|
||||
|
||||
interface Panel {
|
||||
datasource?: {};
|
||||
description?: string;
|
||||
fieldConfig: {
|
||||
defaults: {};
|
||||
overrides: {
|
||||
matcher: {
|
||||
id: string;
|
||||
};
|
||||
properties: {
|
||||
id: string;
|
||||
}[];
|
||||
}[];
|
||||
};
|
||||
gridPos?: {
|
||||
h: number;
|
||||
w: number;
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
id?: number;
|
||||
interval?: string;
|
||||
links?: DashboardLink[];
|
||||
maxDataPoints?: number;
|
||||
options: {};
|
||||
pluginVersion?: string;
|
||||
repeat?: string;
|
||||
repeatDirection: 'h' | 'v';
|
||||
tags?: string[];
|
||||
targets?: {}[];
|
||||
thresholds?: any[];
|
||||
timeFrom?: string;
|
||||
timeRegions?: any[];
|
||||
timeShift?: string;
|
||||
title?: string;
|
||||
transformations: Transformation[];
|
||||
transparent: boolean;
|
||||
type: string;
|
||||
}
|
||||
|
||||
const defaultPanel: Partial<Panel> = {
|
||||
links: [],
|
||||
repeatDirection: 'h',
|
||||
tags: [],
|
||||
targets: [],
|
||||
thresholds: [],
|
||||
timeRegions: [],
|
||||
transformations: [],
|
||||
transparent: false,
|
||||
};
|
||||
|
||||
interface Dashboard {
|
||||
annotations?: {
|
||||
list: AnnotationQuery[];
|
||||
};
|
||||
description?: string;
|
||||
editable: boolean;
|
||||
fiscalYearStartMonth?: number;
|
||||
gnetId?: string;
|
||||
graphTooltip: DashboardCursorSync;
|
||||
id?: number;
|
||||
links?: DashboardLink[];
|
||||
liveNow?: boolean;
|
||||
panels?: Panel | {
|
||||
type: 'graph';
|
||||
} | {
|
||||
type: 'heatmap';
|
||||
} | {
|
||||
type: 'row';
|
||||
collapsed: boolean;
|
||||
id: number;
|
||||
panels: Panel | {
|
||||
type: 'graph';
|
||||
} | {
|
||||
type: 'heatmap';
|
||||
}[];
|
||||
}[];
|
||||
refresh?: string | false;
|
||||
schemaVersion: number;
|
||||
style: 'light' | 'dark';
|
||||
tags?: string[];
|
||||
templating?: {
|
||||
list: VariableModel[];
|
||||
};
|
||||
time?: {
|
||||
from: string;
|
||||
to: string;
|
||||
};
|
||||
timepicker?: {
|
||||
collapse: boolean;
|
||||
enable: boolean;
|
||||
hidden: boolean;
|
||||
refresh_intervals: string[];
|
||||
};
|
||||
timezone?: 'browser' | 'utc' | '';
|
||||
title?: string;
|
||||
uid?: string;
|
||||
version?: number;
|
||||
weekStart?: string;
|
||||
}
|
||||
|
||||
const defaultDashboard: Partial<Dashboard> = {
|
||||
editable: true,
|
||||
graphTooltip: DashboardCursorSync.Off,
|
||||
links: [],
|
||||
panels: [],
|
||||
schemaVersion: 36,
|
||||
style: 'dark',
|
||||
tags: [],
|
||||
timezone: 'browser',
|
||||
};
|
@ -1,89 +0,0 @@
|
||||
package schema
|
||||
|
||||
AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(kind="enum")
|
||||
VisibilityMode: "auto" | "never" | "always" @cuetsy(kind="enum")
|
||||
GraphDrawStyle: "line" | "bars" | "points" @cuetsy(kind="enum")
|
||||
LineInterpolation: "linear" | "smooth" | "stepBefore" | "stepAfter" @cuetsy(kind="enum")
|
||||
ScaleDistribution: "linear" | "log" | "ordinal" @cuetsy(kind="enum")
|
||||
GraphGradientMode: "none" | "opacity" | "hue" | "scheme" @cuetsy(kind="enum")
|
||||
StackingMode: "none" | "normal" | "percent" @cuetsy(kind="enum")
|
||||
GraphTransform: "constant" | "negative-Y" @cuetsy(kind="enum")
|
||||
BarAlignment: -1 | 0 | 1 @cuetsy(kind="enum",memberNames="Before|Center|After")
|
||||
ScaleOrientation: 0 | 1 @cuetsy(kind="enum",memberNames="Horizontal|Vertical")
|
||||
ScaleDirection: 1 | 1 | -1 | -1 @cuetsy(kind="enum",memberNames="Up|Right|Down|Left")
|
||||
LineStyle: {
|
||||
fill?: "solid" | "dash" | "dot" | "square"
|
||||
dash?: [...number]
|
||||
} @cuetsy(kind="interface")
|
||||
LineConfig: {
|
||||
lineColor?: string
|
||||
lineWidth?: number
|
||||
lineInterpolation?: LineInterpolation
|
||||
lineStyle?: LineStyle
|
||||
|
||||
// Indicate if null values should be treated as gaps or connected.
|
||||
// When the value is a number, it represents the maximum delta in the
|
||||
// X axis that should be considered connected. For timeseries, this is milliseconds
|
||||
spanNulls?: bool | number
|
||||
} @cuetsy(kind="interface")
|
||||
BarConfig: {
|
||||
barAlignment?: BarAlignment
|
||||
barWidthFactor?: number
|
||||
barMaxWidth?: number
|
||||
} @cuetsy(kind="interface")
|
||||
FillConfig: {
|
||||
fillColor?: string
|
||||
fillOpacity?: number
|
||||
fillBelowTo?: string
|
||||
} @cuetsy(kind="interface")
|
||||
PointsConfig: {
|
||||
showPoints?: VisibilityMode
|
||||
pointSize?: number
|
||||
pointColor?: string
|
||||
pointSymbol?: string
|
||||
} @cuetsy(kind="interface")
|
||||
ScaleDistributionConfig: {
|
||||
type: ScaleDistribution
|
||||
log?: number
|
||||
} @cuetsy(kind="interface")
|
||||
AxisConfig: {
|
||||
axisPlacement?: AxisPlacement
|
||||
axisLabel?: string
|
||||
axisWidth?: number
|
||||
axisSoftMin?: number
|
||||
axisSoftMax?: number
|
||||
axisGridShow?: bool
|
||||
scaleDistribution?: ScaleDistributionConfig
|
||||
} @cuetsy(kind="interface")
|
||||
HideSeriesConfig: {
|
||||
tooltip: bool
|
||||
legend: bool
|
||||
viz: bool
|
||||
} @cuetsy(kind="interface")
|
||||
StackingConfig: {
|
||||
mode?: StackingMode
|
||||
group?: string
|
||||
} @cuetsy(kind="interface")
|
||||
StackableFieldConfig: {
|
||||
stacking?: StackingConfig
|
||||
} @cuetsy(kind="interface")
|
||||
HideableFieldConfig: {
|
||||
hideFrom?: HideSeriesConfig
|
||||
} @cuetsy(kind="interface")
|
||||
GraphTresholdsStyleMode: "off" | "line" | "area" | "line+area" | "series" @cuetsy(kind="enum",memberNames="Off|Line|Area|LineAndArea|Series")
|
||||
GraphThresholdsStyleConfig: {
|
||||
mode: GraphTresholdsStyleMode
|
||||
} @cuetsy(kind="interface")
|
||||
GraphFieldConfig: {
|
||||
LineConfig
|
||||
FillConfig
|
||||
PointsConfig
|
||||
AxisConfig
|
||||
BarConfig
|
||||
StackableFieldConfig
|
||||
HideableFieldConfig
|
||||
drawStyle?: GraphDrawStyle
|
||||
gradientMode?: GraphGradientMode
|
||||
thresholdsStyle?: GraphThresholdsStyleConfig
|
||||
transform?: GraphTransform
|
||||
} @cuetsy(kind="interface")
|
@ -1,15 +0,0 @@
|
||||
package schema
|
||||
|
||||
LegendPlacement: "bottom" | "right" @cuetsy(kind="type")
|
||||
|
||||
LegendDisplayMode: "list" | "table" | "hidden" @cuetsy(kind="enum")
|
||||
|
||||
VizLegendOptions: {
|
||||
displayMode: LegendDisplayMode
|
||||
placement: LegendPlacement
|
||||
asTable?: bool
|
||||
isVisible?: bool
|
||||
sortBy?: string
|
||||
sortDesc?: bool
|
||||
calcs: [...string]
|
||||
} @cuetsy(kind="interface")
|
@ -1,19 +1,149 @@
|
||||
package schema
|
||||
|
||||
// Use this file as a big TODO list - if it's still in here, it's a TODO to
|
||||
// separate it out into a discrete file.
|
||||
// TODO break this up into individual files. Current limitation on this is codegen logic, imports, dependencies
|
||||
|
||||
// TODO docs
|
||||
AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
VisibilityMode: "auto" | "never" | "always" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
GraphDrawStyle: "line" | "bars" | "points" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
GraphTransform: "constant" | "negative-Y" @cuetsy(kind="enum",memberNames="Constant|NegativeY")
|
||||
|
||||
// TODO docs
|
||||
LineInterpolation: "linear" | "smooth" | "stepBefore" | "stepAfter" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
ScaleDistribution: "linear" | "log" | "ordinal" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
GraphGradientMode: "none" | "opacity" | "hue" | "scheme" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
StackingMode: "none" | "normal" | "percent" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
BarAlignment: -1 | 0 | 1 @cuetsy(kind="enum",memberNames="Before|Center|After")
|
||||
|
||||
// TODO docs
|
||||
ScaleOrientation: 0 | 1 @cuetsy(kind="enum",memberNames="Horizontal|Vertical")
|
||||
|
||||
// TODO docs
|
||||
ScaleDirection: 1 | 1 | -1 | -1 @cuetsy(kind="enum",memberNames="Up|Right|Down|Left")
|
||||
|
||||
// TODO docs
|
||||
LineStyle: {
|
||||
fill?: "solid" | "dash" | "dot" | "square"
|
||||
dash?: [...number]
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
LineConfig: {
|
||||
lineColor?: string
|
||||
lineWidth?: number
|
||||
lineInterpolation?: LineInterpolation
|
||||
lineStyle?: LineStyle
|
||||
|
||||
// Indicate if null values should be treated as gaps or connected.
|
||||
// When the value is a number, it represents the maximum delta in the
|
||||
// X axis that should be considered connected. For timeseries, this is milliseconds
|
||||
spanNulls?: bool | number
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
BarConfig: {
|
||||
barAlignment?: BarAlignment
|
||||
barWidthFactor?: number
|
||||
barMaxWidth?: number
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
FillConfig: {
|
||||
fillColor?: string
|
||||
fillOpacity?: number
|
||||
fillBelowTo?: string
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
PointsConfig: {
|
||||
showPoints?: VisibilityMode
|
||||
pointSize?: number
|
||||
pointColor?: string
|
||||
pointSymbol?: string
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
ScaleDistributionConfig: {
|
||||
type: ScaleDistribution
|
||||
log?: number
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
AxisConfig: {
|
||||
axisPlacement?: AxisPlacement
|
||||
axisLabel?: string
|
||||
axisWidth?: number
|
||||
axisSoftMin?: number
|
||||
axisSoftMax?: number
|
||||
axisGridShow?: bool
|
||||
scaleDistribution?: ScaleDistributionConfig
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
HideSeriesConfig: {
|
||||
tooltip: bool
|
||||
legend: bool
|
||||
viz: bool
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
StackingConfig: {
|
||||
mode?: StackingMode
|
||||
group?: string
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
StackableFieldConfig: {
|
||||
stacking?: StackingConfig
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
HideableFieldConfig: {
|
||||
hideFrom?: HideSeriesConfig
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
GraphTresholdsStyleMode: "off" | "line" | "area" | "line+area" | "series" @cuetsy(kind="enum",memberNames="Off|Line|Area|LineAndArea|Series")
|
||||
|
||||
// TODO docs
|
||||
GraphThresholdsStyleConfig: {
|
||||
mode: GraphTresholdsStyleMode
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
LegendPlacement: "bottom" | "right" @cuetsy(kind="type")
|
||||
|
||||
// TODO docs
|
||||
LegendDisplayMode: "list" | "table" | "hidden" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
TableSortByFieldState: {
|
||||
displayName: string
|
||||
desc?: bool
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
SingleStatBaseOptions: {
|
||||
OptionsWithTextFormatting
|
||||
reduceOptions: ReduceDataOptions
|
||||
orientation: VizOrientation
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
ReduceDataOptions: {
|
||||
// If true show each row value
|
||||
values?: bool
|
||||
@ -24,30 +154,100 @@ ReduceDataOptions: {
|
||||
// Which fields to show. By default this is only numeric fields
|
||||
fields?: string
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
VizOrientation: "auto" | "vertical" | "horizontal" @cuetsy(kind="enum")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
OptionsWithTooltip: {
|
||||
// FIXME this field is non-optional in the corresponding TS type
|
||||
tooltip?: VizTooltipOptions
|
||||
tooltip: VizTooltipOptions
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
OptionsWithLegend: {
|
||||
// FIXME this field is non-optional in the corresponding TS type
|
||||
legend?: VizLegendOptions
|
||||
legend: VizLegendOptions
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
OptionsWithTextFormatting: {
|
||||
text?: VizTextDisplayOptions
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
BigValueColorMode: "value" | "background" | "none" @cuetsy(kind="enum")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
BigValueGraphMode: "none" | "line" | "area" @cuetsy(kind="enum")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO docs
|
||||
BigValueJustifyMode: "auto" | "center" @cuetsy(kind="enum")
|
||||
// TODO copy back to appropriate place
|
||||
// TODO does cuetsy handle underscores the expected way?
|
||||
|
||||
// TODO docs
|
||||
BigValueTextMode: "auto" | "value" | "value_and_name" | "name" | "none" @cuetsy(kind="enum",memberNames="Auto|Value|ValueAndName|Name|None")
|
||||
// TODO copy back to appropriate place
|
||||
|
||||
// TODO -- should not be table specific!
|
||||
// TODO docs
|
||||
FieldTextAlignment: "auto" | "left" | "right" | "center" @cuetsy(kind="type")
|
||||
|
||||
// TODO docs
|
||||
TableCellDisplayMode: "auto" | "color-text" | "color-background" | "color-background-solid" | "gradient-gauge" | "lcd-gauge" | "json-view" | "basic" | "image" @cuetsy(kind="enum",memberNames="Auto|ColorText|ColorBackground|ColorBackgroundSolid|GradientGauge|LcdGauge|JSONView|BasicGauge|Image")
|
||||
|
||||
// TODO docs
|
||||
VizTextDisplayOptions: {
|
||||
// Explicit title text size
|
||||
titleSize?: number
|
||||
// Explicit value text size
|
||||
valueSize?: number
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
TooltipDisplayMode: "single" | "multi" | "none" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
SortOrder: "asc" | "desc" | "none" @cuetsy(kind="enum",memberNames="Ascending|Descending|None")
|
||||
|
||||
// TODO docs
|
||||
GraphFieldConfig: {
|
||||
LineConfig
|
||||
FillConfig
|
||||
PointsConfig
|
||||
AxisConfig
|
||||
BarConfig
|
||||
StackableFieldConfig
|
||||
HideableFieldConfig
|
||||
drawStyle?: GraphDrawStyle
|
||||
gradientMode?: GraphGradientMode
|
||||
thresholdsStyle?: GraphThresholdsStyleConfig
|
||||
transform?: GraphTransform
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
VizLegendOptions: {
|
||||
displayMode: LegendDisplayMode
|
||||
placement: LegendPlacement
|
||||
asTable?: bool
|
||||
isVisible?: bool
|
||||
sortBy?: string
|
||||
sortDesc?: bool
|
||||
calcs: [...string]
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
BarGaugeDisplayMode: "basic" | "lcd" | "gradient" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
TableFieldOptions: {
|
||||
width?: number
|
||||
minWidth?: number
|
||||
align: FieldTextAlignment | *"auto"
|
||||
displayMode: TableCellDisplayMode | *"auto"
|
||||
hidden?: bool // ?? default is missing or false ??
|
||||
inspect: bool | *false
|
||||
filterable?: bool
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
VizTooltipOptions: {
|
||||
mode: TooltipDisplayMode
|
||||
sort: SortOrder
|
||||
} @cuetsy(kind="interface")
|
||||
|
@ -1,8 +1,11 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy from all the files in this directory,
|
||||
// then hand-edited for correctness. It will be fully auto-generated Soon™.
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
export enum AxisPlacement {
|
||||
Auto = 'auto',
|
||||
Bottom = 'bottom',
|
||||
@ -78,6 +81,10 @@ export interface LineStyle {
|
||||
fill?: 'solid' | 'dash' | 'dot' | 'square';
|
||||
}
|
||||
|
||||
export const defaultLineStyle: Partial<LineStyle> = {
|
||||
dash: [],
|
||||
};
|
||||
|
||||
export interface LineConfig {
|
||||
lineColor?: string;
|
||||
lineInterpolation?: LineInterpolation;
|
||||
@ -176,6 +183,10 @@ export interface ReduceDataOptions {
|
||||
values?: boolean;
|
||||
}
|
||||
|
||||
export const defaultReduceDataOptions: Partial<ReduceDataOptions> = {
|
||||
calcs: [],
|
||||
};
|
||||
|
||||
export enum VizOrientation {
|
||||
Auto = 'auto',
|
||||
Horizontal = 'horizontal',
|
||||
@ -250,14 +261,7 @@ export enum SortOrder {
|
||||
None = 'none',
|
||||
}
|
||||
|
||||
export interface GraphFieldConfig
|
||||
extends LineConfig,
|
||||
FillConfig,
|
||||
PointsConfig,
|
||||
AxisConfig,
|
||||
BarConfig,
|
||||
StackableFieldConfig,
|
||||
HideableFieldConfig {
|
||||
export interface GraphFieldConfig extends LineConfig, FillConfig, PointsConfig, AxisConfig, BarConfig, StackableFieldConfig, HideableFieldConfig {
|
||||
drawStyle?: GraphDrawStyle;
|
||||
gradientMode?: GraphGradientMode;
|
||||
thresholdsStyle?: GraphThresholdsStyleConfig;
|
||||
@ -274,6 +278,10 @@ export interface VizLegendOptions {
|
||||
sortDesc?: boolean;
|
||||
}
|
||||
|
||||
export const defaultVizLegendOptions: Partial<VizLegendOptions> = {
|
||||
calcs: [],
|
||||
};
|
||||
|
||||
export enum BarGaugeDisplayMode {
|
||||
Basic = 'basic',
|
||||
Gradient = 'gradient',
|
||||
@ -281,16 +289,16 @@ export enum BarGaugeDisplayMode {
|
||||
}
|
||||
|
||||
export interface TableFieldOptions {
|
||||
align: string;
|
||||
align: FieldTextAlignment;
|
||||
displayMode: TableCellDisplayMode;
|
||||
inspect: boolean;
|
||||
filterable?: boolean;
|
||||
hidden?: boolean;
|
||||
inspect: boolean;
|
||||
minWidth?: number;
|
||||
width?: number;
|
||||
filterable?: boolean;
|
||||
}
|
||||
|
||||
export const defaultTableFieldOptions: TableFieldOptions = {
|
||||
export const defaultTableFieldOptions: Partial<TableFieldOptions> = {
|
||||
align: 'auto',
|
||||
displayMode: TableCellDisplayMode.Auto,
|
||||
inspect: false,
|
@ -1,15 +0,0 @@
|
||||
package schema
|
||||
|
||||
// TODO -- should not be table specific!
|
||||
FieldTextAlignment: "auto" | "left" | "right" | "center" @cuetsy(kind="type")
|
||||
|
||||
TableCellDisplayMode: "auto" | "color-text" | "color-background" | "color-background-solid" | "gradient-gauge" | "lcd-gauge" | "json-view" | "basic" | "image" @cuetsy(kind="enum",memberNames="Auto|ColorText|ColorBackground|ColorBackgroundSolid|GradientGauge|LcdGauge|JSONView|BasicGauge|Image")
|
||||
|
||||
TableFieldOptions: {
|
||||
width?: number
|
||||
minWidth?: number
|
||||
align: FieldTextAlignment | *"auto"
|
||||
displayMode: TableCellDisplayMode | *"auto"
|
||||
hidden?: bool // ?? default is missing or false ??
|
||||
filterable?: bool
|
||||
} @cuetsy(kind="interface")
|
@ -1,8 +0,0 @@
|
||||
package schema
|
||||
|
||||
VizTextDisplayOptions: {
|
||||
// Explicit title text size
|
||||
titleSize?: number
|
||||
// Explicit value text size
|
||||
valueSize?: number
|
||||
} @cuetsy(kind="interface")
|
@ -1,9 +0,0 @@
|
||||
package schema
|
||||
|
||||
TooltipDisplayMode: "single" | "multi" | "none" @cuetsy(kind="enum")
|
||||
SortOrder: "asc" | "desc" | "none" @cuetsy(kind="enum")
|
||||
|
||||
VizTooltipOptions: {
|
||||
mode: TooltipDisplayMode
|
||||
sort: SortOrder
|
||||
} @cuetsy(kind="interface")
|
@ -1,365 +1,30 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
gerrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/ast"
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
"cuelang.org/go/cue/errors"
|
||||
cload "cuelang.org/go/cue/load"
|
||||
"cuelang.org/go/cue/parser"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/grafana/cuetsy"
|
||||
"github.com/grafana/grafana/pkg/cmd/grafana-cli/utils"
|
||||
"github.com/grafana/grafana/pkg/schema/load"
|
||||
"github.com/grafana/grafana/pkg/codegen"
|
||||
)
|
||||
|
||||
// FIXME almost this whole file is a sloppy, one-off hack that just goes around actually making
|
||||
// the API we need. Parts need to be factored out appropriately.
|
||||
|
||||
var ctx = cuecontext.New()
|
||||
|
||||
// The only import statement we currently allow in any models.cue file
|
||||
const allowedImport = "github.com/grafana/grafana/packages/grafana-schema/src/schema"
|
||||
|
||||
var importMap = map[string]string{
|
||||
allowedImport: "@grafana/schema",
|
||||
}
|
||||
|
||||
// Hard-coded list of paths to skip. Remove a particular file as we're ready
|
||||
// to rely on the TypeScript auto-generated by cuetsy for that particular file.
|
||||
var skipPaths = []string{
|
||||
"public/app/plugins/panel/barchart/models.cue",
|
||||
"public/app/plugins/panel/canvas/models.cue",
|
||||
"public/app/plugins/panel/histogram/models.cue",
|
||||
"public/app/plugins/panel/heatmap-new/models.cue",
|
||||
"public/app/plugins/panel/candlestick/models.cue",
|
||||
"public/app/plugins/panel/state-timeline/models.cue",
|
||||
"public/app/plugins/panel/status-history/models.cue",
|
||||
"public/app/plugins/panel/table/models.cue",
|
||||
"public/app/plugins/panel/timeseries/models.cue",
|
||||
// All the cue files in this dir have to be individually excluded, even
|
||||
// though the generator currently smooshes them all together
|
||||
"packages/grafana-schema/src/schema/graph.cue",
|
||||
"packages/grafana-schema/src/schema/legend.cue",
|
||||
"packages/grafana-schema/src/schema/mudball.cue",
|
||||
"packages/grafana-schema/src/schema/table.cue",
|
||||
"packages/grafana-schema/src/schema/text.cue",
|
||||
"packages/grafana-schema/src/schema/tooltip.cue",
|
||||
}
|
||||
|
||||
const prefix = "/"
|
||||
|
||||
//nolint: gocyclo
|
||||
// TODO remove this whole thing
|
||||
func (cmd Command) generateTypescript(c utils.CommandLine) error {
|
||||
root := c.String("grafana-root")
|
||||
if root == "" {
|
||||
return gerrors.New("must provide path to the root of a Grafana repository checkout")
|
||||
}
|
||||
|
||||
var fspaths load.BaseLoadPaths
|
||||
var err error
|
||||
|
||||
fspaths.BaseCueFS, err = populateMapFSFromRoot(paths.BaseCueFS, root, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fspaths.DistPluginCueFS, err = populateMapFSFromRoot(paths.DistPluginCueFS, root, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
overlay, err := defaultOverlay(fspaths)
|
||||
wd, err := codegen.CuetsifyPlugins(ctx, root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Prep the cue load config
|
||||
clcfg := &cload.Config{
|
||||
Overlay: overlay,
|
||||
// FIXME these module paths won't work for things not under our cue.mod - AKA third-party plugins
|
||||
// ModuleRoot: prefix,
|
||||
Module: "github.com/grafana/grafana",
|
||||
if c.Bool("diff") {
|
||||
return wd.Verify()
|
||||
}
|
||||
|
||||
// FIXME hardcoding paths to exclude is not the way to handle this
|
||||
excl := map[string]bool{
|
||||
"cue.mod": true,
|
||||
"cue/scuemata": true,
|
||||
"packages/grafana-schema/src/scuemata/dashboard": true,
|
||||
"packages/grafana-schema/src/scuemata/dashboard/dist": true,
|
||||
}
|
||||
|
||||
exclude := func(path string) bool {
|
||||
dir := filepath.Dir(path)
|
||||
if excl[dir] {
|
||||
return true
|
||||
}
|
||||
for _, p := range skipPaths {
|
||||
if path == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
outfiles := make(map[string][]byte)
|
||||
|
||||
cuetsify := func(in fs.FS) error {
|
||||
seen := make(map[string]bool)
|
||||
return fs.WalkDir(in, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir := filepath.Dir(path)
|
||||
|
||||
if d.IsDir() || filepath.Ext(d.Name()) != ".cue" || seen[dir] || exclude(path) {
|
||||
return nil
|
||||
}
|
||||
seen[dir] = true
|
||||
clcfg.Dir = dir
|
||||
// FIXME Horrible hack to figure out the identifier used for
|
||||
// imported packages - intercept the parser called by the loader to
|
||||
// look at the ast.Files on their way in to building.
|
||||
// Much better if we could work backwards from the cue.Value,
|
||||
// maybe even directly in cuetsy itself, and figure out when a
|
||||
// referenced object is "out of bounds".
|
||||
// var imports sync.Map
|
||||
var imports []*ast.ImportSpec
|
||||
clcfg.ParseFile = func(name string, src interface{}) (*ast.File, error) {
|
||||
f, err := parser.ParseFile(name, src, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imports = append(imports, f.Imports...)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// FIXME loading in this way causes all files in a dir to be loaded
|
||||
// as a single cue.Instance or cue.Value, which makes it quite
|
||||
// difficult to map them _back_ onto the original file and generate
|
||||
// discrete .gen.ts files for each .cue input. However, going one
|
||||
// .cue file at a time and passing it as the first arg to
|
||||
// load.Instances() means that the other files are ignored
|
||||
// completely, causing references between these files to be
|
||||
// unresolved, and thus encounter a different kind of error.
|
||||
insts := cload.Instances(nil, clcfg)
|
||||
if len(insts) > 1 {
|
||||
panic("extra instances")
|
||||
}
|
||||
bi := insts[0]
|
||||
|
||||
v := ctx.BuildInstance(bi)
|
||||
if v.Err() != nil {
|
||||
return v.Err()
|
||||
}
|
||||
|
||||
var b []byte
|
||||
f := &tsFile{}
|
||||
seen := make(map[string]bool)
|
||||
// FIXME explicitly mapping path patterns to conversion patterns
|
||||
// is exactly what we want to avoid
|
||||
switch {
|
||||
// panel plugin models.cue files
|
||||
case strings.Contains(path, "public/app/plugins"):
|
||||
for _, im := range imports {
|
||||
ip := strings.Trim(im.Path.Value, "\"")
|
||||
if ip != allowedImport {
|
||||
// TODO make a specific error type for this
|
||||
return errors.Newf(im.Pos(), "import %q not allowed, panel plugins may only import from %q", ip, allowedImport)
|
||||
}
|
||||
// TODO this approach will silently swallow the unfixable
|
||||
// error case where multiple files in the same dir import
|
||||
// the same package to a different ident
|
||||
if !seen[ip] {
|
||||
seen[ip] = true
|
||||
f.Imports = append(f.Imports, convertImport(im))
|
||||
}
|
||||
}
|
||||
|
||||
// val := v.LookupPath(cue.ParsePath("Panel.lineages[0][0]"))
|
||||
// Extract the latest schema and its version number. (All of this goes away with Thema, whew)
|
||||
f.V = &tsModver{}
|
||||
lins := v.LookupPath(cue.ParsePath("Panel.lineages"))
|
||||
f.V.Lin, _ = lins.Len().Int64()
|
||||
f.V.Lin = f.V.Lin - 1
|
||||
schs := lins.LookupPath(cue.MakePath(cue.Index(int(f.V.Lin))))
|
||||
f.V.Sch, _ = schs.Len().Int64()
|
||||
f.V.Sch = f.V.Sch - 1
|
||||
latest := schs.LookupPath(cue.MakePath(cue.Index(int(f.V.Sch))))
|
||||
|
||||
b, err = cuetsy.Generate(latest, cuetsy.Config{})
|
||||
default:
|
||||
b, err = cuetsy.Generate(v, cuetsy.Config{})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Body = string(b)
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = tsTemplate.Execute(&buf, f)
|
||||
outfiles[strings.Replace(path, ".cue", ".gen.ts", -1)] = buf.Bytes()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
err = cuetsify(fspaths.BaseCueFS)
|
||||
if err != nil {
|
||||
return gerrors.New(errors.Details(err, nil))
|
||||
}
|
||||
err = cuetsify(fspaths.DistPluginCueFS)
|
||||
if err != nil {
|
||||
return gerrors.New(errors.Details(err, nil))
|
||||
}
|
||||
|
||||
diff := c.Bool("diff")
|
||||
var derr bool
|
||||
for of, b := range outfiles {
|
||||
p := filepath.Join(root, of)
|
||||
if diff {
|
||||
if _, err := os.Stat(p); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fmt.Printf("%s: no generated code file to compare against\n", p)
|
||||
derr = true
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("%s: %w", p, err)
|
||||
}
|
||||
|
||||
f, err := os.Open(filepath.Clean(p))
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", p, err)
|
||||
}
|
||||
|
||||
ob, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstr := cmp.Diff(string(ob), string(b))
|
||||
if dstr != "" {
|
||||
derr = true
|
||||
fmt.Printf("%s would have changed:\n%s\n", p, dstr)
|
||||
}
|
||||
} else {
|
||||
err := os.WriteFile(p, b, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if derr {
|
||||
return errors.New("some files changed")
|
||||
}
|
||||
|
||||
return nil
|
||||
return wd.Write()
|
||||
}
|
||||
|
||||
func convertImport(im *ast.ImportSpec) *tsImport {
|
||||
tsim := &tsImport{
|
||||
Pkg: importMap[allowedImport],
|
||||
}
|
||||
if im.Name != nil && im.Name.String() != "" {
|
||||
tsim.Ident = im.Name.String()
|
||||
} else {
|
||||
sl := strings.Split(im.Path.Value, "/")
|
||||
final := sl[len(sl)-1]
|
||||
if idx := strings.Index(final, ":"); idx != -1 {
|
||||
tsim.Pkg = final[idx:]
|
||||
} else {
|
||||
tsim.Pkg = final
|
||||
}
|
||||
}
|
||||
return tsim
|
||||
}
|
||||
|
||||
func defaultOverlay(p load.BaseLoadPaths) (map[string]cload.Source, error) {
|
||||
overlay := make(map[string]cload.Source)
|
||||
|
||||
if err := toOverlay(prefix, p.BaseCueFS, overlay); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := toOverlay(prefix, p.DistPluginCueFS, overlay); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return overlay, nil
|
||||
}
|
||||
|
||||
func toOverlay(prefix string, vfs fs.FS, overlay map[string]cload.Source) error {
|
||||
if !filepath.IsAbs(prefix) {
|
||||
return fmt.Errorf("must provide absolute path prefix when generating cue overlay, got %q", prefix)
|
||||
}
|
||||
err := fs.WalkDir(vfs, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := vfs.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(f fs.File) {
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}(f)
|
||||
|
||||
b, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
overlay[filepath.Join(prefix, path)] = cload.FromBytes(b)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type tsFile struct {
|
||||
V *tsModver
|
||||
Imports []*tsImport
|
||||
Body string
|
||||
}
|
||||
|
||||
type tsModver struct {
|
||||
Lin, Sch int64
|
||||
}
|
||||
|
||||
type tsImport struct {
|
||||
Ident string
|
||||
Pkg string
|
||||
}
|
||||
|
||||
var tsTemplate = template.Must(template.New("cuetsygen").Parse(
|
||||
`//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
{{range .Imports}}
|
||||
import * as {{.Ident}} from '{{.Pkg}}';{{end}}
|
||||
{{if .V}}
|
||||
export const modelVersion = Object.freeze([{{ .V.Lin }}, {{ .V.Sch }}]);
|
||||
{{end}}
|
||||
{{.Body}}`))
|
||||
|
399
pkg/codegen/coremodel.go
Normal file
399
pkg/codegen/coremodel.go
Normal file
@ -0,0 +1,399 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing/fstest"
|
||||
"text/template"
|
||||
|
||||
"cuelang.org/go/pkg/encoding/yaml"
|
||||
"github.com/deepmap/oapi-codegen/pkg/codegen"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/grafana/cuetsy"
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
"github.com/grafana/thema"
|
||||
"github.com/grafana/thema/encoding/openapi"
|
||||
"golang.org/x/tools/imports"
|
||||
)
|
||||
|
||||
// ExtractedLineage contains the results of statically analyzing a Grafana
|
||||
// directory for a Thema lineage.
|
||||
type ExtractedLineage struct {
|
||||
Lineage thema.Lineage
|
||||
// Absolute path to the coremodel's lineage.cue file.
|
||||
LineagePath string
|
||||
// Path to the coremodel's lineage.cue file relative to repo root.
|
||||
RelativePath string
|
||||
// Indicates whether the coremodel is considered canonical or not. Generated
|
||||
// code from not-yet-canonical coremodels should include appropriate caveats in
|
||||
// documentation and possibly be hidden from external public API surface areas.
|
||||
IsCanonical bool
|
||||
}
|
||||
|
||||
// ExtractLineage loads a Grafana Thema lineage from the filesystem.
|
||||
//
|
||||
// The provided path must be the absolute path to the file containing the
|
||||
// lineage to be loaded.
|
||||
//
|
||||
// This loading approach is intended primarily for use with code generators, or
|
||||
// other use cases external to grafana-server backend. For code within
|
||||
// grafana-server, prefer lineage loaders provided in e.g. pkg/coremodel/*.
|
||||
func ExtractLineage(path string, lib thema.Library) (*ExtractedLineage, error) {
|
||||
if !filepath.IsAbs(path) {
|
||||
return nil, fmt.Errorf("must provide an absolute path, got %q", path)
|
||||
}
|
||||
|
||||
ec := &ExtractedLineage{
|
||||
LineagePath: path,
|
||||
}
|
||||
|
||||
var find func(path string) (string, error)
|
||||
find = func(path string) (string, error) {
|
||||
parent := filepath.Dir(path)
|
||||
if parent == path {
|
||||
return "", errors.New("grafana root directory could not be found")
|
||||
}
|
||||
fp := filepath.Join(path, "go.mod")
|
||||
if _, err := os.Stat(fp); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
return find(parent)
|
||||
}
|
||||
groot, err := find(path)
|
||||
if err != nil {
|
||||
return ec, err
|
||||
}
|
||||
|
||||
f, err := os.Open(ec.LineagePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not open lineage file at %s: %w", path, err)
|
||||
}
|
||||
|
||||
byt, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fs := fstest.MapFS{
|
||||
"lineage.cue": &fstest.MapFile{
|
||||
Data: byt,
|
||||
},
|
||||
}
|
||||
|
||||
ec.RelativePath, err = filepath.Rel(groot, filepath.Dir(path))
|
||||
if err != nil {
|
||||
// should be unreachable, since we rootclimbed to find groot above
|
||||
panic(err)
|
||||
}
|
||||
ec.Lineage, err = cuectx.LoadGrafanaInstancesWithThema(ec.RelativePath, fs, lib)
|
||||
if err != nil {
|
||||
return ec, err
|
||||
}
|
||||
ec.IsCanonical = isCanonical(ec.Lineage.Name())
|
||||
return ec, nil
|
||||
}
|
||||
|
||||
func isCanonical(name string) bool {
|
||||
return canonicalCoremodels[name]
|
||||
}
|
||||
|
||||
// FIXME specificying coremodel canonicality DOES NOT belong here - it should be part of the coremodel declaration.
|
||||
var canonicalCoremodels = map[string]bool{
|
||||
"dashboard": false,
|
||||
}
|
||||
|
||||
// GenerateGoCoremodel generates a standard Go coremodel from a Thema lineage.
|
||||
//
|
||||
// The provided path must be a directory. Generated code files will be written
|
||||
// to that path. The final element of the path must match the Lineage.Name().
|
||||
func (ls *ExtractedLineage) GenerateGoCoremodel(path string) (WriteDiffer, error) {
|
||||
lin, lib := ls.Lineage, ls.Lineage.Library()
|
||||
_, name := filepath.Split(path)
|
||||
if name != lin.Name() {
|
||||
return nil, fmt.Errorf("lineage name %q must match final element of path, got %q", lin.Name(), path)
|
||||
}
|
||||
|
||||
sch := thema.SchemaP(lin, thema.LatestVersion(lin))
|
||||
f, err := openapi.GenerateSchema(sch, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("thema openapi generation failed: %w", err)
|
||||
}
|
||||
|
||||
str, err := yaml.Marshal(lib.Context().BuildFile(f))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cue-yaml marshaling failed: %w", err)
|
||||
}
|
||||
|
||||
loader := openapi3.NewLoader()
|
||||
oT, err := loader.LoadFromData([]byte(str))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading generated openapi failed; %w", err)
|
||||
}
|
||||
|
||||
gostr, err := codegen.Generate(oT, lin.Name(), codegen.Options{
|
||||
GenerateTypes: true,
|
||||
SkipPrune: true,
|
||||
SkipFmt: true,
|
||||
UserTemplates: map[string]string{
|
||||
"imports.tmpl": fmt.Sprintf(tmplImports, ls.RelativePath),
|
||||
"typedef.tmpl": tmplTypedef,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("openapi generation failed: %w", err)
|
||||
}
|
||||
|
||||
vars := goPkg{
|
||||
Name: lin.Name(),
|
||||
LineagePath: ls.RelativePath,
|
||||
LatestSeqv: sch.Version()[0],
|
||||
LatestSchv: sch.Version()[1],
|
||||
}
|
||||
var buuf bytes.Buffer
|
||||
err = tmplAddenda.Execute(&buuf, vars)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fset := token.NewFileSet()
|
||||
gf, err := parser.ParseFile(fset, "coremodel_gen.go", gostr+buuf.String(), parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generated go file parsing failed: %w", err)
|
||||
}
|
||||
m := makeReplacer(lin.Name())
|
||||
ast.Walk(m, gf)
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = format.Node(&buf, fset, gf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ast printing failed: %w", err)
|
||||
}
|
||||
|
||||
byt, err := imports.Process("coremodel_gen.go", buf.Bytes(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("goimports processing failed: %w", err)
|
||||
}
|
||||
|
||||
// Generate the assignability test. TODO do this in a framework test instead
|
||||
var buf3 bytes.Buffer
|
||||
err = tmplAssignableTest.Execute(&buf3, vars)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed generating assignability test file: %w", err)
|
||||
}
|
||||
|
||||
wd := NewWriteDiffer()
|
||||
wd[filepath.Join(path, "coremodel_gen.go")] = byt
|
||||
wd[filepath.Join(path, "coremodel_gen_test.go")] = buf3.Bytes()
|
||||
|
||||
return wd, nil
|
||||
}
|
||||
|
||||
type goPkg struct {
|
||||
Name string
|
||||
LineagePath string
|
||||
LatestSeqv, LatestSchv uint
|
||||
IsComposed bool
|
||||
}
|
||||
|
||||
func (ls *ExtractedLineage) GenerateTypescriptCoremodel(path string) (WriteDiffer, error) {
|
||||
_, name := filepath.Split(path)
|
||||
if name != ls.Lineage.Name() {
|
||||
return nil, fmt.Errorf("lineage name %q must match final element of path, got %q", ls.Lineage.Name(), path)
|
||||
}
|
||||
|
||||
schv := thema.SchemaP(ls.Lineage, thema.LatestVersion(ls.Lineage)).UnwrapCUE()
|
||||
|
||||
parts, err := cuetsy.GenerateAST(schv, cuetsy.Config{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cuetsy parts gen failed: %w", err)
|
||||
}
|
||||
|
||||
top, err := cuetsy.GenerateSingleAST(string(makeReplacer(ls.Lineage.Name())), schv, cuetsy.TypeInterface)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cuetsy top gen failed: %w", err)
|
||||
}
|
||||
|
||||
// TODO until cuetsy can toposort its outputs, put the top/parent type at the bottom of the file.
|
||||
parts.Nodes = append(parts.Nodes, top.T, top.D)
|
||||
// parts.Nodes = append([]ts.Decl{top.T, top.D}, parts.Nodes...)
|
||||
|
||||
var strb strings.Builder
|
||||
var str string
|
||||
fpath := ls.Lineage.Name() + ".gen.ts"
|
||||
strb.WriteString(fmt.Sprintf(genHeader, ls.RelativePath))
|
||||
|
||||
if !ls.IsCanonical {
|
||||
fpath = fmt.Sprintf("%s_experimental.gen.ts", ls.Lineage.Name())
|
||||
strb.WriteString(`
|
||||
// This model is a WIP and not yet canonical. Consequently, its members are
|
||||
// not exported to exclude it from grafana-schema's public API surface.
|
||||
|
||||
`)
|
||||
strb.WriteString(fmt.Sprint(parts))
|
||||
// TODO replace this regexp with cuetsy config for whether members are exported
|
||||
re := regexp.MustCompile(`(?m)^export `)
|
||||
str = re.ReplaceAllLiteralString(strb.String(), "")
|
||||
} else {
|
||||
strb.WriteString(fmt.Sprint(parts))
|
||||
str = strb.String()
|
||||
}
|
||||
|
||||
wd := NewWriteDiffer()
|
||||
wd[filepath.Join(path, fpath)] = []byte(str)
|
||||
return wd, nil
|
||||
}
|
||||
|
||||
type modelReplacer string
|
||||
|
||||
func makeReplacer(name string) modelReplacer {
|
||||
return modelReplacer(fmt.Sprintf("%s%s", string(strings.ToUpper(name)[0]), name[1:]))
|
||||
}
|
||||
|
||||
func (m modelReplacer) Visit(n ast.Node) ast.Visitor {
|
||||
switch x := n.(type) {
|
||||
case *ast.Ident:
|
||||
x.Name = m.replacePrefix(x.Name)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (m modelReplacer) replacePrefix(str string) string {
|
||||
if len(str) >= len(m) && str[:len(m)] == string(m) {
|
||||
return strings.Replace(str, string(m), "Model", 1)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
var genHeader = `// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from repository root.
|
||||
//
|
||||
// Derived from the Thema lineage at %s
|
||||
|
||||
`
|
||||
|
||||
var tmplImports = genHeader + `package {{ .PackageName }}
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/runtime"
|
||||
openapi_types "github.com/deepmap/oapi-codegen/pkg/types"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/grafana/thema"
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
)
|
||||
`
|
||||
|
||||
var tmplAddenda = template.Must(template.New("addenda").Parse(`
|
||||
//go:embed lineage.cue
|
||||
var cueFS embed.FS
|
||||
|
||||
// codegen ensures that this is always the latest Thema schema version
|
||||
var currentVersion = thema.SV({{ .LatestSeqv }}, {{ .LatestSchv }})
|
||||
|
||||
// Lineage returns the Thema lineage representing a Grafana {{ .Name }}.
|
||||
//
|
||||
// The lineage is the canonical specification of the current {{ .Name }} schema,
|
||||
// all prior schema versions, and the mappings that allow migration between
|
||||
// schema versions.
|
||||
{{- if .IsComposed }}//
|
||||
// This is the base variant of the schema. It does not include any composed
|
||||
// plugin schemas.{{ end }}
|
||||
func Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "dashboard"), cueFS, lib, opts...)
|
||||
}
|
||||
|
||||
var _ thema.LineageFactory = Lineage
|
||||
|
||||
// Coremodel contains the foundational schema declaration for {{ .Name }}s.
|
||||
type Coremodel struct {
|
||||
lin thema.Lineage
|
||||
}
|
||||
|
||||
// Lineage returns the canonical dashboard Lineage.
|
||||
func (c *Coremodel) Lineage() thema.Lineage {
|
||||
return c.lin
|
||||
}
|
||||
|
||||
// CurrentSchema returns the current (latest) {{ .Name }} 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{}
|
||||
}
|
||||
|
||||
func ProvideCoremodel(lib thema.Library) (*Coremodel, error) {
|
||||
lin, err := Lineage(lib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Coremodel{
|
||||
lin: lin,
|
||||
}, nil
|
||||
}
|
||||
`))
|
||||
|
||||
var tmplAssignableTest = template.Must(template.New("addenda").Parse(fmt.Sprintf(genHeader, "{{ .LineagePath }}") + `package {{ .Name }}
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
func TestSchemaAssignability(t *testing.T) {
|
||||
lin, err := Lineage(cuectx.ProvideThemaLibrary())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sch := thema.SchemaP(lin, currentVersion)
|
||||
|
||||
err = thema.AssignableTo(sch, &Model{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
`))
|
||||
|
||||
var tmplTypedef = `{{range .Types}}
|
||||
{{ with .Schema.Description }}{{ . }}{{ else }}// {{.TypeName}} defines model for {{.JsonName}}.{{ end }}
|
||||
//
|
||||
// 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 {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
|
||||
{{end}}
|
||||
`
|
134
pkg/codegen/diffwrite.go
Normal file
134
pkg/codegen/diffwrite.go
Normal file
@ -0,0 +1,134 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// WriteDiffer is a pseudo-filesystem that supports batch-writing its contents
|
||||
// to the real filesystem, or batch-comparing its contents to the real
|
||||
// filesystem. Its intended use is for idiomatic `go generate`-style code
|
||||
// generators, where it is expected that the results of codegen are committed to
|
||||
// version control.
|
||||
//
|
||||
// In such cases, the normal behavior of a generator is to write files to disk,
|
||||
// but in CI, that behavior should change to verify that what is already on disk
|
||||
// is identical to the results of code generation. This allows CI to ensure that
|
||||
// the results of code generation are always up to date. WriteDiffer supports
|
||||
// these related behaviors through its Write() and Verify() methods, respectively.
|
||||
//
|
||||
// Note that the statelessness of WriteDiffer means that, if a particular input
|
||||
// to the code generator goes away, it will not notice generated files left
|
||||
// behind if their inputs are removed.
|
||||
// TODO introduce a search/match system
|
||||
type WriteDiffer map[string][]byte
|
||||
|
||||
func NewWriteDiffer() WriteDiffer {
|
||||
return WriteDiffer(make(map[string][]byte))
|
||||
}
|
||||
|
||||
type writeSlice []struct {
|
||||
path string
|
||||
contents []byte
|
||||
}
|
||||
|
||||
// Verify checks the contents of each file against the filesystem. It emits an error
|
||||
// if any of its contained files differ.
|
||||
func (wd WriteDiffer) Verify() error {
|
||||
var result error
|
||||
|
||||
for _, item := range wd.toSlice() {
|
||||
if _, err := os.Stat(item.path); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
result = multierror.Append(result, fmt.Errorf("%s: generated file should exist, but does not", item.path))
|
||||
} else {
|
||||
result = multierror.Append(result, fmt.Errorf("%s: could not stat generated file: %w", item.path, err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
f, err := os.Open(filepath.Clean(item.path))
|
||||
if err != nil {
|
||||
result = multierror.Append(result, fmt.Errorf("%s: %w", item.path, err))
|
||||
continue
|
||||
}
|
||||
|
||||
ob, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
result = multierror.Append(result, fmt.Errorf("%s: %w", item.path, err))
|
||||
continue
|
||||
}
|
||||
dstr := cmp.Diff(string(ob), string(item.contents))
|
||||
if dstr != "" {
|
||||
result = multierror.Append(result, fmt.Errorf("%s would have changed:\n\n%s", item.path, dstr))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Write writes all of the files to their indicated paths.
|
||||
func (wd WriteDiffer) Write() error {
|
||||
g, _ := errgroup.WithContext(context.TODO())
|
||||
g.SetLimit(12)
|
||||
|
||||
for _, item := range wd.toSlice() {
|
||||
it := item
|
||||
g.Go(func() error {
|
||||
err := os.MkdirAll(filepath.Dir(it.path), os.ModePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: failed to ensure parent directory exists: %w", it.path, err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(it.path, it.contents, 0644); err != nil {
|
||||
return fmt.Errorf("%s: error while writing file: %w", it.path, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
func (wd WriteDiffer) toSlice() writeSlice {
|
||||
sl := make(writeSlice, 0, len(wd))
|
||||
type ws struct {
|
||||
path string
|
||||
contents []byte
|
||||
}
|
||||
|
||||
for k, v := range wd {
|
||||
sl = append(sl, ws{
|
||||
path: k,
|
||||
contents: v,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(sl, func(i, j int) bool {
|
||||
return sl[i].path < sl[j].path
|
||||
})
|
||||
|
||||
return sl
|
||||
}
|
||||
|
||||
// Merge combines all the entries from the provided WriteDiffer into the callee
|
||||
// WriteDiffer. Duplicate paths result in an error.
|
||||
func (wd WriteDiffer) Merge(wd2 WriteDiffer) error {
|
||||
for k, v := range wd2 {
|
||||
if _, has := wd[k]; has {
|
||||
return fmt.Errorf("path %s already exists in write differ", k)
|
||||
}
|
||||
wd[k] = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
343
pkg/codegen/pluggen.go
Normal file
343
pkg/codegen/pluggen.go
Normal file
@ -0,0 +1,343 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
gerrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing/fstest"
|
||||
"text/template"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/ast"
|
||||
"cuelang.org/go/cue/errors"
|
||||
cload "cuelang.org/go/cue/load"
|
||||
"cuelang.org/go/cue/parser"
|
||||
"github.com/grafana/cuetsy"
|
||||
"github.com/grafana/grafana/pkg/schema/load"
|
||||
)
|
||||
|
||||
// The only import statement we currently allow in any models.cue file
|
||||
const allowedImport = "github.com/grafana/grafana/packages/grafana-schema/src/schema"
|
||||
|
||||
var importMap = map[string]string{
|
||||
allowedImport: "@grafana/schema",
|
||||
}
|
||||
|
||||
// Hard-coded list of paths to skip. Remove a particular file as we're ready
|
||||
// to rely on the TypeScript auto-generated by cuetsy for that particular file.
|
||||
var skipPaths = []string{
|
||||
"public/app/plugins/panel/barchart/models.cue",
|
||||
"public/app/plugins/panel/canvas/models.cue",
|
||||
"public/app/plugins/panel/histogram/models.cue",
|
||||
"public/app/plugins/panel/heatmap-new/models.cue",
|
||||
"public/app/plugins/panel/candlestick/models.cue",
|
||||
"public/app/plugins/panel/state-timeline/models.cue",
|
||||
"public/app/plugins/panel/status-history/models.cue",
|
||||
"public/app/plugins/panel/table/models.cue",
|
||||
"public/app/plugins/panel/timeseries/models.cue",
|
||||
}
|
||||
|
||||
const prefix = "/"
|
||||
|
||||
var paths = load.GetDefaultLoadPaths()
|
||||
|
||||
// CuetsifyPlugins runs cuetsy against plugins' models.cue files.
|
||||
func CuetsifyPlugins(ctx *cue.Context, root string) (WriteDiffer, error) {
|
||||
// TODO this whole func has a lot of old, crufty behavior from the scuemata era; needs TLC
|
||||
var fspaths load.BaseLoadPaths
|
||||
var err error
|
||||
|
||||
fspaths.BaseCueFS, err = populateMapFSFromRoot(paths.BaseCueFS, root, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fspaths.DistPluginCueFS, err = populateMapFSFromRoot(paths.DistPluginCueFS, root, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
overlay, err := defaultOverlay(fspaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prep the cue load config
|
||||
clcfg := &cload.Config{
|
||||
Overlay: overlay,
|
||||
// FIXME these module paths won't work for things not under our cue.mod - AKA third-party plugins
|
||||
ModuleRoot: prefix,
|
||||
Module: "github.com/grafana/grafana",
|
||||
}
|
||||
|
||||
// FIXME hardcoding paths to exclude is not the way to handle this
|
||||
excl := map[string]bool{
|
||||
"cue.mod": true,
|
||||
"cue/scuemata": true,
|
||||
"packages/grafana-schema/src/scuemata/dashboard": true,
|
||||
"packages/grafana-schema/src/scuemata/dashboard/dist": true,
|
||||
}
|
||||
|
||||
exclude := func(path string) bool {
|
||||
dir := filepath.Dir(path)
|
||||
if excl[dir] {
|
||||
return true
|
||||
}
|
||||
for _, p := range skipPaths {
|
||||
if path == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
outfiles := NewWriteDiffer()
|
||||
|
||||
cuetsify := func(in fs.FS) error {
|
||||
seen := make(map[string]bool)
|
||||
return fs.WalkDir(in, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir := filepath.Dir(path)
|
||||
|
||||
if d.IsDir() || filepath.Ext(d.Name()) != ".cue" || seen[dir] || exclude(path) {
|
||||
return nil
|
||||
}
|
||||
seen[dir] = true
|
||||
clcfg.Dir = filepath.Join(root, dir)
|
||||
// FIXME Horrible hack to figure out the identifier used for
|
||||
// imported packages - intercept the parser called by the loader to
|
||||
// look at the ast.Files on their way in to building.
|
||||
// Much better if we could work backwards from the cue.Value,
|
||||
// maybe even directly in cuetsy itself, and figure out when a
|
||||
// referenced object is "out of bounds".
|
||||
// var imports sync.Map
|
||||
var imports []*ast.ImportSpec
|
||||
clcfg.ParseFile = func(name string, src interface{}) (*ast.File, error) {
|
||||
f, err := parser.ParseFile(name, src, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imports = append(imports, f.Imports...)
|
||||
return f, nil
|
||||
}
|
||||
if strings.Contains(path, "public/app/plugins") {
|
||||
clcfg.Package = "grafanaschema"
|
||||
} else {
|
||||
clcfg.Package = ""
|
||||
}
|
||||
|
||||
// FIXME loading in this way causes all files in a dir to be loaded
|
||||
// as a single cue.Instance or cue.Value, which makes it quite
|
||||
// difficult to map them _back_ onto the original file and generate
|
||||
// discrete .gen.ts files for each .cue input. However, going one
|
||||
// .cue file at a time and passing it as the first arg to
|
||||
// load.Instances() means that the other files are ignored
|
||||
// completely, causing references between these files to be
|
||||
// unresolved, and thus encounter a different kind of error.
|
||||
insts := cload.Instances(nil, clcfg)
|
||||
if len(insts) > 1 {
|
||||
panic("extra instances")
|
||||
}
|
||||
bi := insts[0]
|
||||
|
||||
v := ctx.BuildInstance(bi)
|
||||
if v.Err() != nil {
|
||||
return v.Err()
|
||||
}
|
||||
|
||||
var b []byte
|
||||
f := &tsFile{}
|
||||
seen := make(map[string]bool)
|
||||
// FIXME explicitly mapping path patterns to conversion patterns
|
||||
// is exactly what we want to avoid
|
||||
switch {
|
||||
// panel plugin models.cue files
|
||||
case strings.Contains(path, "public/app/plugins"):
|
||||
for _, im := range imports {
|
||||
ip := strings.Trim(im.Path.Value, "\"")
|
||||
if ip != allowedImport {
|
||||
// TODO make a specific error type for this
|
||||
return errors.Newf(im.Pos(), "import %q not allowed, panel plugins may only import from %q", ip, allowedImport)
|
||||
}
|
||||
// TODO this approach will silently swallow the unfixable
|
||||
// error case where multiple files in the same dir import
|
||||
// the same package to a different ident
|
||||
if !seen[ip] {
|
||||
seen[ip] = true
|
||||
f.Imports = append(f.Imports, convertImport(im))
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the latest schema and its version number. (All of this goes away with Thema, whew)
|
||||
f.V = &tsModver{}
|
||||
lins := v.LookupPath(cue.ParsePath("Panel.lineages"))
|
||||
f.V.Lin, _ = lins.Len().Int64()
|
||||
f.V.Lin = f.V.Lin - 1
|
||||
schs := lins.LookupPath(cue.MakePath(cue.Index(int(f.V.Lin))))
|
||||
f.V.Sch, _ = schs.Len().Int64()
|
||||
f.V.Sch = f.V.Sch - 1
|
||||
latest := schs.LookupPath(cue.MakePath(cue.Index(int(f.V.Sch))))
|
||||
|
||||
b, err = cuetsy.Generate(latest, cuetsy.Config{})
|
||||
default:
|
||||
b, err = cuetsy.Generate(v, cuetsy.Config{})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Body = string(b)
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = tsTemplate.Execute(&buf, f)
|
||||
outfiles[filepath.Join(root, strings.Replace(path, ".cue", ".gen.ts", -1))] = buf.Bytes()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
err = cuetsify(fspaths.BaseCueFS)
|
||||
if err != nil {
|
||||
return nil, gerrors.New(errors.Details(err, nil))
|
||||
}
|
||||
err = cuetsify(fspaths.DistPluginCueFS)
|
||||
if err != nil {
|
||||
return nil, gerrors.New(errors.Details(err, nil))
|
||||
}
|
||||
|
||||
return outfiles, nil
|
||||
}
|
||||
|
||||
func convertImport(im *ast.ImportSpec) *tsImport {
|
||||
tsim := &tsImport{
|
||||
Pkg: importMap[allowedImport],
|
||||
}
|
||||
if im.Name != nil && im.Name.String() != "" {
|
||||
tsim.Ident = im.Name.String()
|
||||
} else {
|
||||
sl := strings.Split(im.Path.Value, "/")
|
||||
final := sl[len(sl)-1]
|
||||
if idx := strings.Index(final, ":"); idx != -1 {
|
||||
tsim.Pkg = final[idx:]
|
||||
} else {
|
||||
tsim.Pkg = final
|
||||
}
|
||||
}
|
||||
return tsim
|
||||
}
|
||||
|
||||
func defaultOverlay(p load.BaseLoadPaths) (map[string]cload.Source, error) {
|
||||
overlay := make(map[string]cload.Source)
|
||||
|
||||
if err := toOverlay(prefix, p.BaseCueFS, overlay); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := toOverlay(prefix, p.DistPluginCueFS, overlay); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return overlay, nil
|
||||
}
|
||||
|
||||
func toOverlay(prefix string, vfs fs.FS, overlay map[string]cload.Source) error {
|
||||
if !filepath.IsAbs(prefix) {
|
||||
return fmt.Errorf("must provide absolute path prefix when generating cue overlay, got %q", prefix)
|
||||
}
|
||||
err := fs.WalkDir(vfs, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := vfs.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(f fs.File) {
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}(f)
|
||||
|
||||
b, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
overlay[filepath.Join(prefix, path)] = cload.FromBytes(b)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper function that populates an fs.FS by walking over a virtual filesystem,
|
||||
// and reading files from disk corresponding to each file encountered.
|
||||
func populateMapFSFromRoot(in fs.FS, root, join string) (fs.FS, error) {
|
||||
out := make(fstest.MapFS)
|
||||
err := fs.WalkDir(in, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
// Ignore gosec warning G304. The input set here is necessarily
|
||||
// constrained to files specified in embed.go
|
||||
// nolint:gosec
|
||||
b, err := os.Open(filepath.Join(root, join, path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
byt, err := io.ReadAll(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out[path] = &fstest.MapFile{Data: byt}
|
||||
return nil
|
||||
})
|
||||
return out, err
|
||||
}
|
||||
|
||||
type tsFile struct {
|
||||
V *tsModver
|
||||
Imports []*tsImport
|
||||
Body string
|
||||
}
|
||||
|
||||
type tsModver struct {
|
||||
Lin, Sch int64
|
||||
}
|
||||
|
||||
type tsImport struct {
|
||||
Ident string
|
||||
Pkg string
|
||||
}
|
||||
|
||||
var tsTemplate = template.Must(template.New("cuetsygen").Parse(`//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
{{range .Imports}}
|
||||
import * as {{.Ident}} from '{{.Pkg}}';{{end}}
|
||||
{{if .V}}
|
||||
export const modelVersion = Object.freeze([{{ .V.Lin }}, {{ .V.Sch }}]);
|
||||
{{end}}
|
||||
{{.Body}}`))
|
10
pkg/coremodel/dashboard/addenda.go
Normal file
10
pkg/coremodel/dashboard/addenda.go
Normal file
@ -0,0 +1,10 @@
|
||||
package dashboard
|
||||
|
||||
// HandoffSchemaVersion is the minimum schemaVersion for dashboards at which the
|
||||
// Thema-based dashboard schema is possibly valid
|
||||
//
|
||||
// schemaVersion is the original version numbering system for dashboards. If a
|
||||
// dashboard is below this schemaVersion, it is necessary for the frontend
|
||||
// typescript dashboard migration logic to first run and get it past this
|
||||
// number, after which Thema can take over.
|
||||
const HandoffSchemaVersion = 36
|
@ -1,40 +0,0 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
// Coremodel contains the foundational schema declaration for dashboards.
|
||||
type Coremodel struct {
|
||||
lin thema.Lineage
|
||||
}
|
||||
|
||||
// Lineage returns the canonical dashboard Lineage.
|
||||
func (c *Coremodel) Lineage() thema.Lineage {
|
||||
return c.lin
|
||||
}
|
||||
|
||||
func (c *Coremodel) CurrentSchema() thema.Schema {
|
||||
sch, err := c.lin.Schema(currentVersion)
|
||||
if err != nil {
|
||||
// Only reachable if our own schema currentVersion does not exist, which
|
||||
// can really only happen transitionally during development
|
||||
panic(err)
|
||||
}
|
||||
return sch
|
||||
}
|
||||
|
||||
func (c *Coremodel) GoType() interface{} {
|
||||
return &model{}
|
||||
}
|
||||
|
||||
func ProvideCoremodel(lib thema.Library) (*Coremodel, error) {
|
||||
lin, err := Lineage(lib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Coremodel{
|
||||
lin: lin,
|
||||
}, nil
|
||||
}
|
751
pkg/coremodel/dashboard/coremodel_gen.go
Normal file
751
pkg/coremodel/dashboard/coremodel_gen.go
Normal file
@ -0,0 +1,751 @@
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from repository root.
|
||||
//
|
||||
// Derived from the Thema lineage at pkg/coremodel/dashboard
|
||||
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
// Defines values for DashboardGraphTooltip.
|
||||
const (
|
||||
ModelGraphTooltipN0 ModelGraphTooltip = 0
|
||||
|
||||
ModelGraphTooltipN1 ModelGraphTooltip = 1
|
||||
|
||||
ModelGraphTooltipN2 ModelGraphTooltip = 2
|
||||
)
|
||||
|
||||
// Defines values for DashboardStyle.
|
||||
const (
|
||||
ModelStyleDark ModelStyle = "dark"
|
||||
|
||||
ModelStyleLight ModelStyle = "light"
|
||||
)
|
||||
|
||||
// Defines values for DashboardTimezone.
|
||||
const (
|
||||
ModelTimezoneBrowser ModelTimezone = "browser"
|
||||
|
||||
ModelTimezoneEmpty ModelTimezone = ""
|
||||
|
||||
ModelTimezoneUtc ModelTimezone = "utc"
|
||||
)
|
||||
|
||||
// Defines values for DashboardDashboardCursorSync.
|
||||
const (
|
||||
ModelDashboardCursorSyncN0 ModelDashboardCursorSync = 0
|
||||
|
||||
ModelDashboardCursorSyncN1 ModelDashboardCursorSync = 1
|
||||
|
||||
ModelDashboardCursorSyncN2 ModelDashboardCursorSync = 2
|
||||
)
|
||||
|
||||
// Defines values for DashboardDashboardLinkType.
|
||||
const (
|
||||
ModelDashboardLinkTypeDashboards ModelDashboardLinkType = "dashboards"
|
||||
|
||||
ModelDashboardLinkTypeLink ModelDashboardLinkType = "link"
|
||||
)
|
||||
|
||||
// Defines values for DashboardFieldColorModeId.
|
||||
const (
|
||||
ModelFieldColorModeIdContinuousGrYlRd ModelFieldColorModeId = "continuous-GrYlRd"
|
||||
|
||||
ModelFieldColorModeIdFixed ModelFieldColorModeId = "fixed"
|
||||
|
||||
ModelFieldColorModeIdPaletteClassic ModelFieldColorModeId = "palette-classic"
|
||||
|
||||
ModelFieldColorModeIdPaletteSaturated ModelFieldColorModeId = "palette-saturated"
|
||||
|
||||
ModelFieldColorModeIdThresholds ModelFieldColorModeId = "thresholds"
|
||||
)
|
||||
|
||||
// Defines values for DashboardFieldColorSeriesByMode.
|
||||
const (
|
||||
ModelFieldColorSeriesByModeLast ModelFieldColorSeriesByMode = "last"
|
||||
|
||||
ModelFieldColorSeriesByModeMax ModelFieldColorSeriesByMode = "max"
|
||||
|
||||
ModelFieldColorSeriesByModeMin ModelFieldColorSeriesByMode = "min"
|
||||
)
|
||||
|
||||
// Defines values for DashboardGraphPanelType.
|
||||
const (
|
||||
ModelGraphPanelTypeGraph ModelGraphPanelType = "graph"
|
||||
)
|
||||
|
||||
// Defines values for DashboardHeatmapPanelType.
|
||||
const (
|
||||
ModelHeatmapPanelTypeHeatmap ModelHeatmapPanelType = "heatmap"
|
||||
)
|
||||
|
||||
// Defines values for DashboardPanelRepeatDirection.
|
||||
const (
|
||||
ModelPanelRepeatDirectionH ModelPanelRepeatDirection = "h"
|
||||
|
||||
ModelPanelRepeatDirectionV ModelPanelRepeatDirection = "v"
|
||||
)
|
||||
|
||||
// Defines values for DashboardRowPanelType.
|
||||
const (
|
||||
ModelRowPanelTypeRow ModelRowPanelType = "row"
|
||||
)
|
||||
|
||||
// Defines values for DashboardThresholdsConfigMode.
|
||||
const (
|
||||
ModelThresholdsConfigModeAbsolute ModelThresholdsConfigMode = "absolute"
|
||||
|
||||
ModelThresholdsConfigModePercentage ModelThresholdsConfigMode = "percentage"
|
||||
)
|
||||
|
||||
// Defines values for DashboardThresholdsMode.
|
||||
const (
|
||||
ModelThresholdsModeAbsolute ModelThresholdsMode = "absolute"
|
||||
|
||||
ModelThresholdsModePercentage ModelThresholdsMode = "percentage"
|
||||
)
|
||||
|
||||
// Defines values for DashboardVariableModelType.
|
||||
const (
|
||||
ModelVariableModelTypeAdhoc ModelVariableModelType = "adhoc"
|
||||
|
||||
ModelVariableModelTypeConstant ModelVariableModelType = "constant"
|
||||
|
||||
ModelVariableModelTypeCustom ModelVariableModelType = "custom"
|
||||
|
||||
ModelVariableModelTypeDatasource ModelVariableModelType = "datasource"
|
||||
|
||||
ModelVariableModelTypeInterval ModelVariableModelType = "interval"
|
||||
|
||||
ModelVariableModelTypeQuery ModelVariableModelType = "query"
|
||||
|
||||
ModelVariableModelTypeSystem ModelVariableModelType = "system"
|
||||
|
||||
ModelVariableModelTypeTextbox ModelVariableModelType = "textbox"
|
||||
)
|
||||
|
||||
// Defines values for DashboardVariableType.
|
||||
const (
|
||||
ModelVariableTypeAdhoc ModelVariableType = "adhoc"
|
||||
|
||||
ModelVariableTypeConstant ModelVariableType = "constant"
|
||||
|
||||
ModelVariableTypeCustom ModelVariableType = "custom"
|
||||
|
||||
ModelVariableTypeDatasource ModelVariableType = "datasource"
|
||||
|
||||
ModelVariableTypeInterval ModelVariableType = "interval"
|
||||
|
||||
ModelVariableTypeQuery ModelVariableType = "query"
|
||||
|
||||
ModelVariableTypeSystem ModelVariableType = "system"
|
||||
|
||||
ModelVariableTypeTextbox ModelVariableType = "textbox"
|
||||
)
|
||||
|
||||
// Dashboard defines model for dashboard.
|
||||
//
|
||||
// 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 {
|
||||
Annotations *struct {
|
||||
List []ModelAnnotationQuery `json:"list"`
|
||||
} `json:"annotations,omitempty"`
|
||||
|
||||
// Description of dashboard.
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// Whether a dashboard is editable or not.
|
||||
Editable bool `json:"editable"`
|
||||
|
||||
// TODO docs
|
||||
FiscalYearStartMonth *int `json:"fiscalYearStartMonth,omitempty"`
|
||||
GnetId *string `json:"gnetId,omitempty"`
|
||||
GraphTooltip ModelGraphTooltip `json:"graphTooltip"`
|
||||
|
||||
// Unique numeric identifier for the dashboard.
|
||||
// TODO must isolate or remove identifiers local to a Grafana instance...?
|
||||
Id *int64 `json:"id,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
Links *[]ModelDashboardLink `json:"links,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
LiveNow *bool `json:"liveNow,omitempty"`
|
||||
Panels *[]interface{} `json:"panels,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
Refresh *interface{} `json:"refresh,omitempty"`
|
||||
|
||||
// Version of the JSON schema, incremented each time a Grafana update brings
|
||||
// changes to said schema.
|
||||
// TODO this is the existing schema numbering system. It will be replaced by Thema's themaVersion
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
|
||||
// Theme of dashboard.
|
||||
Style ModelStyle `json:"style"`
|
||||
|
||||
// Tags associated with dashboard.
|
||||
Tags *[]string `json:"tags,omitempty"`
|
||||
Templating *struct {
|
||||
List []ModelVariableModel `json:"list"`
|
||||
} `json:"templating,omitempty"`
|
||||
|
||||
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
Time *struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
} `json:"time,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
// TODO this appears to be spread all over in the frontend. Concepts will likely need tidying in tandem with schema changes
|
||||
Timepicker *struct {
|
||||
// Whether timepicker is collapsed or not.
|
||||
Collapse bool `json:"collapse"`
|
||||
|
||||
// Whether timepicker is enabled or not.
|
||||
Enable bool `json:"enable"`
|
||||
|
||||
// Whether timepicker is visible or not.
|
||||
Hidden bool `json:"hidden"`
|
||||
|
||||
// Selectable intervals for auto-refresh.
|
||||
RefreshIntervals []string `json:"refresh_intervals"`
|
||||
} `json:"timepicker,omitempty"`
|
||||
|
||||
// Timezone of dashboard,
|
||||
Timezone *ModelTimezone `json:"timezone,omitempty"`
|
||||
|
||||
// Title of dashboard.
|
||||
Title *string `json:"title,omitempty"`
|
||||
|
||||
// Unique dashboard identifier that can be generated by anyone. string (8-40)
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
|
||||
// Version of the dashboard, incremented each time the dashboard is updated.
|
||||
Version *int `json:"version,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
WeekStart *string `json:"weekStart,omitempty"`
|
||||
}
|
||||
|
||||
// DashboardGraphTooltip defines model for Dashboard.GraphTooltip.
|
||||
//
|
||||
// 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 ModelGraphTooltip int
|
||||
|
||||
// Theme of dashboard.
|
||||
//
|
||||
// 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 ModelStyle string
|
||||
|
||||
// Timezone of dashboard,
|
||||
//
|
||||
// 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 ModelTimezone string
|
||||
|
||||
// TODO docs
|
||||
// FROM: AnnotationQuery in grafana-data/src/types/annotations.ts
|
||||
//
|
||||
// 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 ModelAnnotationQuery struct {
|
||||
BuiltIn int `json:"builtIn"`
|
||||
|
||||
// Datasource to use for annotation.
|
||||
Datasource struct {
|
||||
Type *string `json:"type,omitempty"`
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
} `json:"datasource"`
|
||||
|
||||
// Whether annotation is enabled.
|
||||
Enable bool `json:"enable"`
|
||||
|
||||
// Whether to hide annotation.
|
||||
Hide *bool `json:"hide,omitempty"`
|
||||
|
||||
// Annotation icon color.
|
||||
IconColor *string `json:"iconColor,omitempty"`
|
||||
|
||||
// Name of annotation.
|
||||
Name *string `json:"name,omitempty"`
|
||||
|
||||
// Query for annotation data.
|
||||
RawQuery *string `json:"rawQuery,omitempty"`
|
||||
ShowIn int `json:"showIn"`
|
||||
|
||||
// Schema for panel targets is specified by datasource
|
||||
// plugins. We use a placeholder definition, which the Go
|
||||
// schema loader either left open/as-is with the Base
|
||||
// variant of the Dashboard and Panel families, or filled
|
||||
// with types derived from plugins in the Instance variant.
|
||||
// When working directly from CUE, importers can extend this
|
||||
// type directly to achieve the same effect.
|
||||
Target *ModelTarget `json:"target,omitempty"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// 0 for no shared crosshair or tooltip (default).
|
||||
// 1 for shared crosshair.
|
||||
// 2 for shared crosshair AND shared tooltip.
|
||||
//
|
||||
// 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 ModelDashboardCursorSync int
|
||||
|
||||
// FROM public/app/features/dashboard/state/DashboardModels.ts - ish
|
||||
// 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 ModelDashboardLink struct {
|
||||
AsDropdown bool `json:"asDropdown"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
IncludeVars bool `json:"includeVars"`
|
||||
KeepTime bool `json:"keepTime"`
|
||||
Tags []string `json:"tags"`
|
||||
TargetBlank bool `json:"targetBlank"`
|
||||
Title string `json:"title"`
|
||||
Tooltip *string `json:"tooltip,omitempty"`
|
||||
Type ModelDashboardLinkType `json:"type"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// DashboardDashboardLinkType defines model for DashboardDashboardLink.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 ModelDashboardLinkType string
|
||||
|
||||
// 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 ModelFieldColor struct {
|
||||
// Stores the fixed color value if mode is fixed
|
||||
FixedColor *string `json:"fixedColor,omitempty"`
|
||||
|
||||
// The main color scheme mode
|
||||
Mode interface{} `json:"mode"`
|
||||
|
||||
// TODO docs
|
||||
SeriesBy *ModelFieldColorSeriesByMode `json:"seriesBy,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 ModelFieldColorModeId string
|
||||
|
||||
// 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 ModelFieldColorSeriesByMode string
|
||||
|
||||
// DashboardGraphPanel defines model for dashboard.GraphPanel.
|
||||
//
|
||||
// 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 ModelGraphPanel struct {
|
||||
// Support for legacy graph and heatmap panels.
|
||||
Type ModelGraphPanelType `json:"type"`
|
||||
}
|
||||
|
||||
// Support for legacy graph and heatmap panels.
|
||||
//
|
||||
// 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 ModelGraphPanelType string
|
||||
|
||||
// DashboardHeatmapPanel defines model for dashboard.HeatmapPanel.
|
||||
//
|
||||
// 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 ModelHeatmapPanel struct {
|
||||
Type ModelHeatmapPanelType `json:"type"`
|
||||
}
|
||||
|
||||
// DashboardHeatmapPanelType defines model for DashboardHeatmapPanel.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 ModelHeatmapPanelType string
|
||||
|
||||
// Dashboard panels. Panels are canonically defined inline
|
||||
// because they share a version timeline with the dashboard
|
||||
// schema; they do not evolve independently.
|
||||
//
|
||||
// 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 ModelPanel struct {
|
||||
// The datasource used in all targets.
|
||||
Datasource *struct {
|
||||
Type *string `json:"type,omitempty"`
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
} `json:"datasource,omitempty"`
|
||||
|
||||
// Description.
|
||||
Description *string `json:"description,omitempty"`
|
||||
FieldConfig struct {
|
||||
Defaults struct {
|
||||
// TODO docs
|
||||
Color *ModelFieldColor `json:"color,omitempty"`
|
||||
|
||||
// custom is specified by the PanelFieldConfig field
|
||||
// in panel plugin schemas.
|
||||
Custom *map[string]interface{} `json:"custom,omitempty"`
|
||||
|
||||
// Significant digits (for display)
|
||||
Decimals *float32 `json:"decimals,omitempty"`
|
||||
|
||||
// Human readable field metadata
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// The display value for this field. This supports template variables blank is auto
|
||||
DisplayName *string `json:"displayName,omitempty"`
|
||||
|
||||
// This can be used by data sources that return and explicit naming structure for values and labels
|
||||
// When this property is configured, this value is used rather than the default naming strategy.
|
||||
DisplayNameFromDS *string `json:"displayNameFromDS,omitempty"`
|
||||
|
||||
// True if data source field supports ad-hoc filters
|
||||
Filterable *bool `json:"filterable,omitempty"`
|
||||
|
||||
// // The behavior when clicking on a result
|
||||
Links *[]interface{} `json:"links,omitempty"`
|
||||
|
||||
// Convert input values into a display string
|
||||
//
|
||||
// TODO this one corresponds to a complex type with
|
||||
// generics on the typescript side. Ouch. Will
|
||||
// either need special care, or we'll just need to
|
||||
// accept a very loosely specified schema. It's very
|
||||
// unlikely we'll be able to translate cue to
|
||||
// typescript generics in the general case, though
|
||||
// this particular one *may* be able to work.
|
||||
Mappings *[]map[string]interface{} `json:"mappings,omitempty"`
|
||||
Max *float32 `json:"max,omitempty"`
|
||||
Min *float32 `json:"min,omitempty"`
|
||||
|
||||
// Alternative to empty string
|
||||
NoValue *string `json:"noValue,omitempty"`
|
||||
|
||||
// An explict path to the field in the datasource. When the frame meta includes a path,
|
||||
// This will default to `${frame.meta.path}/${field.name}
|
||||
//
|
||||
// When defined, this value can be used as an identifier within the datasource scope, and
|
||||
// may be used to update the results
|
||||
Path *string `json:"path,omitempty"`
|
||||
Thresholds *ModelThresholdsConfig `json:"thresholds,omitempty"`
|
||||
|
||||
// Numeric Options
|
||||
Unit *string `json:"unit,omitempty"`
|
||||
|
||||
// True if data source can write a value to the path. Auth/authz are supported separately
|
||||
Writeable *bool `json:"writeable,omitempty"`
|
||||
} `json:"defaults"`
|
||||
Overrides []struct {
|
||||
Matcher struct {
|
||||
Id string `json:"id"`
|
||||
Options *interface{} `json:"options,omitempty"`
|
||||
} `json:"matcher"`
|
||||
Properties []struct {
|
||||
Id string `json:"id"`
|
||||
Value *interface{} `json:"value,omitempty"`
|
||||
} `json:"properties"`
|
||||
} `json:"overrides"`
|
||||
} `json:"fieldConfig"`
|
||||
|
||||
// Grid position.
|
||||
GridPos *struct {
|
||||
// Panel
|
||||
H int `json:"h"`
|
||||
|
||||
// true if fixed
|
||||
Static *bool `json:"static,omitempty"`
|
||||
|
||||
// Panel
|
||||
W int `json:"w"`
|
||||
|
||||
// Panel x
|
||||
X int `json:"x"`
|
||||
|
||||
// Panel y
|
||||
Y int `json:"y"`
|
||||
} `json:"gridPos,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
Id *int `json:"id,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
Interval *string `json:"interval,omitempty"`
|
||||
|
||||
// Panel links.
|
||||
// TODO fill this out - seems there are a couple variants?
|
||||
Links *[]ModelDashboardLink `json:"links,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
MaxDataPoints *float32 `json:"maxDataPoints,omitempty"`
|
||||
|
||||
// options is specified by the PanelOptions field in panel
|
||||
// plugin schemas.
|
||||
Options map[string]interface{} `json:"options"`
|
||||
|
||||
// FIXME this almost certainly has to be changed in favor of scuemata versions
|
||||
PluginVersion *string `json:"pluginVersion,omitempty"`
|
||||
|
||||
// Name of template variable to repeat for.
|
||||
Repeat *string `json:"repeat,omitempty"`
|
||||
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
RepeatDirection ModelPanelRepeatDirection `json:"repeatDirection"`
|
||||
|
||||
// TODO docs
|
||||
Tags *[]string `json:"tags,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
Targets *[]ModelTarget `json:"targets,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
Thresholds *[]interface{} `json:"thresholds,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
TimeFrom *string `json:"timeFrom,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
TimeRegions *[]interface{} `json:"timeRegions,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
TimeShift *string `json:"timeShift,omitempty"`
|
||||
|
||||
// Panel title.
|
||||
Title *string `json:"title,omitempty"`
|
||||
Transformations []struct {
|
||||
Id string `json:"id"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
} `json:"transformations"`
|
||||
|
||||
// Whether to display the panel without a background.
|
||||
Transparent bool `json:"transparent"`
|
||||
|
||||
// The panel plugin type id. May not be empty.
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
//
|
||||
// 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 ModelPanelRepeatDirection string
|
||||
|
||||
// Row panel
|
||||
//
|
||||
// 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 ModelRowPanel struct {
|
||||
Collapsed bool `json:"collapsed"`
|
||||
|
||||
// Name of default datasource.
|
||||
Datasource *struct {
|
||||
Type *string `json:"type,omitempty"`
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
} `json:"datasource,omitempty"`
|
||||
GridPos *struct {
|
||||
// Panel
|
||||
H int `json:"h"`
|
||||
|
||||
// true if fixed
|
||||
Static *bool `json:"static,omitempty"`
|
||||
|
||||
// Panel
|
||||
W int `json:"w"`
|
||||
|
||||
// Panel x
|
||||
X int `json:"x"`
|
||||
|
||||
// Panel y
|
||||
Y int `json:"y"`
|
||||
} `json:"gridPos,omitempty"`
|
||||
Id int `json:"id"`
|
||||
Panels []interface{} `json:"panels"`
|
||||
|
||||
// Name of template variable to repeat for.
|
||||
Repeat *string `json:"repeat,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Type ModelRowPanelType `json:"type"`
|
||||
}
|
||||
|
||||
// DashboardRowPanelType defines model for DashboardRowPanel.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 ModelRowPanelType string
|
||||
|
||||
// Schema for panel targets is specified by datasource
|
||||
// plugins. We use a placeholder definition, which the Go
|
||||
// schema loader either left open/as-is with the Base
|
||||
// variant of the Dashboard and Panel families, or filled
|
||||
// with types derived from plugins in the Instance variant.
|
||||
// When working directly from CUE, importers can extend this
|
||||
// type directly to achieve the same effect.
|
||||
//
|
||||
// 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 ModelTarget map[string]interface{}
|
||||
|
||||
// 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 ModelThreshold struct {
|
||||
// TODO docs
|
||||
Color string `json:"color"`
|
||||
|
||||
// TODO docs
|
||||
// TODO are the values here enumerable into a disjunction?
|
||||
// Some seem to be listed in typescript comment
|
||||
State *string `json:"state,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
// FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON
|
||||
Value *float32 `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// DashboardThresholdsConfig defines model for dashboard.ThresholdsConfig.
|
||||
//
|
||||
// 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 ModelThresholdsConfig struct {
|
||||
Mode ModelThresholdsConfigMode `json:"mode"`
|
||||
|
||||
// Must be sorted by 'value', first value is always -Infinity
|
||||
Steps []struct {
|
||||
// TODO docs
|
||||
Color string `json:"color"`
|
||||
|
||||
// TODO docs
|
||||
// TODO are the values here enumerable into a disjunction?
|
||||
// Some seem to be listed in typescript comment
|
||||
State *string `json:"state,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
// FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON
|
||||
Value *float32 `json:"value,omitempty"`
|
||||
} `json:"steps"`
|
||||
}
|
||||
|
||||
// DashboardThresholdsConfigMode defines model for DashboardThresholdsConfig.Mode.
|
||||
//
|
||||
// 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 ModelThresholdsConfigMode string
|
||||
|
||||
// DashboardThresholdsMode defines model for dashboard.ThresholdsMode.
|
||||
//
|
||||
// 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 ModelThresholdsMode string
|
||||
|
||||
// TODO docs
|
||||
// FIXME this is extremely underspecfied; wasn't obvious which typescript types corresponded to it
|
||||
//
|
||||
// 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 ModelTransformation struct {
|
||||
Id string `json:"id"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
}
|
||||
|
||||
// FROM: packages/grafana-data/src/types/templateVars.ts
|
||||
// TODO docs
|
||||
// TODO what about what's in public/app/features/types.ts?
|
||||
// TODO there appear to be a lot of different kinds of [template] vars here? if so need a disjunction
|
||||
//
|
||||
// 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 ModelVariableModel struct {
|
||||
Label *string `json:"label,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Type ModelVariableModelType `json:"type"`
|
||||
}
|
||||
|
||||
// DashboardVariableModelType defines model for DashboardVariableModel.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 ModelVariableModelType string
|
||||
|
||||
// FROM: packages/grafana-data/src/types/templateVars.ts
|
||||
// TODO docs
|
||||
// TODO this implies some wider pattern/discriminated union, probably?
|
||||
//
|
||||
// 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 ModelVariableType string
|
||||
|
||||
//go:embed lineage.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 dashboard.
|
||||
//
|
||||
// The lineage is the canonical specification of the current dashboard 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", "dashboard"), cueFS, lib, opts...)
|
||||
}
|
||||
|
||||
var _ thema.LineageFactory = Lineage
|
||||
|
||||
// Coremodel contains the foundational schema declaration for dashboards.
|
||||
type Coremodel struct {
|
||||
lin thema.Lineage
|
||||
}
|
||||
|
||||
// Lineage returns the canonical dashboard Lineage.
|
||||
func (c *Coremodel) Lineage() thema.Lineage {
|
||||
return c.lin
|
||||
}
|
||||
|
||||
// CurrentSchema returns the current (latest) dashboard 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{}
|
||||
}
|
||||
|
||||
func ProvideCoremodel(lib thema.Library) (*Coremodel, error) {
|
||||
lin, err := Lineage(lib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Coremodel{
|
||||
lin: lin,
|
||||
}, nil
|
||||
}
|
28
pkg/coremodel/dashboard/coremodel_gen_test.go
Normal file
28
pkg/coremodel/dashboard/coremodel_gen_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from repository root.
|
||||
//
|
||||
// Derived from the Thema lineage at pkg/coremodel/dashboard
|
||||
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
func TestSchemaAssignability(t *testing.T) {
|
||||
lin, err := Lineage(cuectx.ProvideThemaLibrary())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sch := thema.SchemaP(lin, currentVersion)
|
||||
|
||||
err = thema.AssignableTo(sch, &Model{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
@ -136,7 +136,7 @@ seqs: [
|
||||
#VariableType: "query" | "adhoc" | "constant" | "datasource" | "interval" | "textbox" | "custom" | "system" @cuetsy(kind="type")
|
||||
|
||||
// TODO docs
|
||||
#FieldColorModeId: "thresholds" | "palette-classic" | "palette-saturated" | "continuous-GrYlRd" | "fixed" @cuetsy(kind="enum")
|
||||
#FieldColorModeId: "thresholds" | "palette-classic" | "palette-saturated" | "continuous-GrYlRd" | "fixed" @cuetsy(kind="enum",memberNames="Thresholds|PaletteClassic|PaletteSaturated|ContinuousGrYlRd|Fixed")
|
||||
|
||||
// TODO docs
|
||||
#FieldColorSeriesByMode: "min" | "max" | "last" @cuetsy(kind="type")
|
||||
|
@ -1,117 +0,0 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/thema"
|
||||
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed lineage.cue
|
||||
cueFS embed.FS
|
||||
|
||||
// TODO: this should be generated by Thema.
|
||||
currentVersion = thema.SV(0, 0)
|
||||
)
|
||||
|
||||
// HandoffSchemaVersion is the minimum schemaVersion for dashboards at which the
|
||||
// Thema-based dashboard schema is known to be valid.
|
||||
//
|
||||
// schemaVersion is the original version numbering system for dashboards. If a
|
||||
// dashboard is below this schemaVersion, it is necessary for the frontend
|
||||
// typescript dashboard migration logic to first run and get it past this
|
||||
// number, after which Thema can take over.
|
||||
const HandoffSchemaVersion = 36
|
||||
|
||||
// Lineage returns the Thema lineage representing Grafana dashboards. The
|
||||
// lineage is the canonical specification of the current datasource schema, all
|
||||
// prior schema versions, and the mappings that allow migration between schema
|
||||
// versions.
|
||||
//
|
||||
// This is the base variant of the schema, which does not include any composed
|
||||
// plugin schemas.
|
||||
func Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "dashboard"), cueFS, lib, opts...)
|
||||
}
|
||||
|
||||
// Model is a dummy struct stand-in for dashboards.
|
||||
//
|
||||
// It exists solely to trick compgen into accepting the dashboard coremodel as valid.
|
||||
type Model struct{}
|
||||
|
||||
// model is a hacky Go struct representing a dashboard.
|
||||
//
|
||||
// This exists solely because the coremodel framework enforces that there is a Go struct to which
|
||||
// all valid Thema schema instances can be assigned, per Thema's assignability checker. See
|
||||
// https://github.com/grafana/thema/blob/main/docs/invariants.md#go-assignability for rules.
|
||||
//
|
||||
// DO NOT RELY ON THIS FOR ANYTHING REAL. It is unclear whether we will ever attempt to have a correct, complete
|
||||
// Go struct representation of dashboards, let alone compress it into a single struct.
|
||||
type model struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
GnetId string `json:"gnetId"`
|
||||
Tags []string `json:"tags"`
|
||||
Style string `json:"style"`
|
||||
Timezone string `json:"timezone"`
|
||||
Editable bool `json:"editable"`
|
||||
GraphTooltip uint8 `json:"graphTooltip"`
|
||||
Time struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
} `json:"time"`
|
||||
Timepicker struct {
|
||||
Collapse bool `json:"collapse"`
|
||||
Enable bool `json:"enable"`
|
||||
Hidden bool `json:"hidden"`
|
||||
RefreshIntervals []string `json:"refresh_intervals"`
|
||||
} `json:"timepicker"`
|
||||
Templating struct {
|
||||
List []interface{} `json:"list"`
|
||||
} `json:"templating"`
|
||||
Annotations struct {
|
||||
List []struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
BuiltIn uint8 `json:"builtIn"`
|
||||
Datasource struct {
|
||||
Type string `json:"type"`
|
||||
Uid string `json:"uid"`
|
||||
} `json:"datasource"`
|
||||
Enable bool `json:"enable"`
|
||||
Hide bool `json:"hide,omitempty"`
|
||||
IconColor string `json:"iconColor"`
|
||||
RawQuery string `json:"rawQuery,omitempty"`
|
||||
ShowIn int `json:"showIn"`
|
||||
Target interface{} `json:"target"`
|
||||
} `json:"list"`
|
||||
} `json:"annotations"`
|
||||
Refresh interface{} `json:"refresh"` // (bool|string)
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
Links []struct {
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
Tooltip string `json:"tooltip,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Tags []string `json:"tags"`
|
||||
AsDropdown bool `json:"asDropdown"`
|
||||
TargetBlank bool `json:"targetBlank"`
|
||||
IncludeVars bool `json:"includeVars"`
|
||||
KeepTime bool `json:"keepTime"`
|
||||
} `json:"links"`
|
||||
Panels []interface{} `json:"panels"`
|
||||
FiscalYearStartMonth uint8 `json:"fiscalYearStartMonth"`
|
||||
LiveNow bool `json:"liveNow"`
|
||||
WeekStart string `json:"weekStart"`
|
||||
|
||||
// //
|
||||
|
||||
Uid string `json:"uid"`
|
||||
// OrgId int64 `json:"orgId"`
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Version int `json:"version"`
|
||||
}
|
93
pkg/framework/coremodel/gen.go
Normal file
93
pkg/framework/coremodel/gen.go
Normal file
@ -0,0 +1,93 @@
|
||||
// go:build ignore
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
gcgen "github.com/grafana/grafana/pkg/codegen"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
var lib = thema.NewLibrary(cuecontext.New())
|
||||
|
||||
const sep = string(filepath.Separator)
|
||||
|
||||
// Generate Go and Typescript implementations for all coremodels, and populate the
|
||||
// coremodel static registry.
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
fmt.Fprintf(os.Stderr, "coremodel code generator does not currently accept any arguments\n, got %q", os.Args)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not get working directory: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// TODO this binds us to only having coremodels in a single directory. If we need more, compgen is the way
|
||||
grootp := strings.Split(cwd, sep)
|
||||
groot := filepath.Join(sep, filepath.Join(grootp[:len(grootp)-3]...))
|
||||
|
||||
cmroot := filepath.Join(groot, "pkg", "coremodel")
|
||||
tsroot := filepath.Join(groot, "packages", "grafana-schema", "src", "schema")
|
||||
|
||||
items, err := ioutil.ReadDir(cmroot)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not read coremodels parent dir %s: %s\n", cmroot, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var lins []*gcgen.ExtractedLineage
|
||||
for _, item := range items {
|
||||
if item.IsDir() {
|
||||
lin, err := gcgen.ExtractLineage(filepath.Join(cmroot, item.Name(), "lineage.cue"), lib)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not process coremodel dir %s: %s\n", cmroot, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
lins = append(lins, lin)
|
||||
}
|
||||
}
|
||||
|
||||
wd := gcgen.NewWriteDiffer()
|
||||
for _, ls := range lins {
|
||||
wdg, err := ls.GenerateGoCoremodel(filepath.Join(cmroot, ls.Lineage.Name()))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to generate Go for %s: %s\n", ls.Lineage.Name(), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
wd.Merge(wdg)
|
||||
|
||||
wdt, 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(wdt)
|
||||
}
|
||||
|
||||
if _, set := os.LookupEnv("CODEGEN_VERIFY"); set {
|
||||
err = wd.Verify()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "generated code is not up to date:\n%s\nrun `make gen-cue` to regenerate\n\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
err = wd.Write()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error while writing generated code to disk:\n%s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
package coremodel
|
||||
|
||||
// Generates all code derived from coremodel Thema lineages that's used directly
|
||||
// by both the frontend and backend.
|
||||
//go:generate go run gen.go
|
||||
|
||||
import (
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
63
public/app/plugins/gen.go
Normal file
63
public/app/plugins/gen.go
Normal file
@ -0,0 +1,63 @@
|
||||
// go:build ignore
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
"github.com/grafana/grafana/pkg/codegen"
|
||||
)
|
||||
|
||||
// Generate TypeScript for all plugin models.cue
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
fmt.Fprintf(os.Stderr, "plugin thema code generator does not currently accept any arguments\n, got %q", os.Args)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not get working directory: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var find func(path string) (string, error)
|
||||
find = func(path string) (string, error) {
|
||||
parent := filepath.Dir(path)
|
||||
if parent == path {
|
||||
return "", errors.New("grafana root directory could not be found")
|
||||
}
|
||||
fp := filepath.Join(path, "go.mod")
|
||||
if _, err := os.Stat(fp); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
return find(parent)
|
||||
}
|
||||
groot, err := find(cwd)
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
wd, err := codegen.CuetsifyPlugins(cuecontext.New(), groot)
|
||||
|
||||
if _, set := os.LookupEnv("CODEGEN_VERIFY"); set {
|
||||
err = wd.Verify()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "generated code is out of sync with inputs:\n%s\nrun `make gen-cue` to regenerate\n\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
err = wd.Write()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error while writing generated code to disk:\n%s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
3
public/app/plugins/igen.go
Normal file
3
public/app/plugins/igen.go
Normal file
@ -0,0 +1,3 @@
|
||||
package plugins
|
||||
|
||||
//go:generate go run gen.go
|
@ -1,5 +1,7 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
@ -1,5 +1,7 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
@ -1,5 +1,7 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
@ -1,5 +1,7 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file was autogenerated by cuetsy. DO NOT EDIT!
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// To regenerate, run "make gen-cue" from the repository root.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
@ -41,6 +41,7 @@ load(
|
||||
'upload_cdn_step',
|
||||
'validate_scuemata_step',
|
||||
'ensure_cuetsified_step',
|
||||
'verify_gen_cue_step',
|
||||
'test_a11y_frontend_step',
|
||||
'trigger_oss'
|
||||
)
|
||||
@ -136,6 +137,7 @@ def get_steps(edition):
|
||||
build_plugins_step(edition=edition, sign=True),
|
||||
validate_scuemata_step(),
|
||||
ensure_cuetsified_step(),
|
||||
verify_gen_cue_step(),
|
||||
]
|
||||
integration_test_steps = [
|
||||
postgres_integration_tests_step(edition=edition, ver_mode=ver_mode),
|
||||
|
@ -31,6 +31,7 @@ load(
|
||||
'benchmark_ldap_step',
|
||||
'validate_scuemata_step',
|
||||
'ensure_cuetsified_step',
|
||||
'verify_gen_cue_step',
|
||||
'test_a11y_frontend_step',
|
||||
'enterprise_downstream_step',
|
||||
)
|
||||
@ -126,6 +127,7 @@ def pr_pipelines(edition):
|
||||
build_plugins_step(edition=edition),
|
||||
validate_scuemata_step(),
|
||||
ensure_cuetsified_step(),
|
||||
verify_gen_cue_step(),
|
||||
]
|
||||
integration_test_steps = [
|
||||
postgres_integration_tests_step(edition=edition, ver_mode=ver_mode),
|
||||
|
@ -41,6 +41,7 @@ load(
|
||||
'upload_cdn_step',
|
||||
'validate_scuemata_step',
|
||||
'ensure_cuetsified_step',
|
||||
'verify_gen_cue_step',
|
||||
'publish_images_step',
|
||||
'trigger_oss'
|
||||
)
|
||||
@ -183,6 +184,7 @@ def get_steps(edition, ver_mode):
|
||||
build_plugins_step(edition=edition, sign=True),
|
||||
validate_scuemata_step(),
|
||||
ensure_cuetsified_step(),
|
||||
verify_gen_cue_step(),
|
||||
]
|
||||
|
||||
integration_test_steps = [
|
||||
|
@ -1167,6 +1167,16 @@ def ensure_cuetsified_step():
|
||||
],
|
||||
}
|
||||
|
||||
def verify_gen_cue_step():
|
||||
return {
|
||||
'name': 'verify-gen-cue',
|
||||
'image': build_image,
|
||||
'commands': [
|
||||
'# It is required that code generated from Thema/CUE be committed and in sync with its inputs.',
|
||||
'# The following command will fail if running code generators produces any diff in output.',
|
||||
'CODEGEN_VERIFY=1 make gen-cue',
|
||||
],
|
||||
}
|
||||
|
||||
def end_to_end_tests_deps(edition):
|
||||
if disable_tests:
|
||||
|
Loading…
Reference in New Issue
Block a user