Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18f7f95c3b |
@@ -21,8 +21,8 @@ require (
|
|||||||
github.com/spf13/afero v1.14.0 // indirect
|
github.com/spf13/afero v1.14.0 // indirect
|
||||||
github.com/spf13/cast v1.8.0 // indirect
|
github.com/spf13/cast v1.8.0 // indirect
|
||||||
github.com/tdewolff/parse/v2 v2.8.1 // indirect
|
github.com/tdewolff/parse/v2 v2.8.1 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/net v0.45.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.29.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.6 // indirect
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
+12
-12
@@ -167,19 +167,19 @@ golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjG
|
|||||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ require (
|
|||||||
github.com/unknwon/com v1.0.1 // indirect
|
github.com/unknwon/com v1.0.1 // indirect
|
||||||
github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect
|
github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect
|
||||||
github.com/urfave/cli v1.22.16 // indirect
|
github.com/urfave/cli v1.22.16 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
github.com/yalue/merged_fs v1.3.0 // indirect
|
github.com/yalue/merged_fs v1.3.0 // indirect
|
||||||
golang.org/x/mod v0.29.0 // indirect
|
golang.org/x/mod v0.27.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/net v0.45.0 // indirect
|
||||||
golang.org/x/oauth2 v0.30.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/sync v0.18.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.29.0 // indirect
|
||||||
golang.org/x/tools v0.38.0 // indirect
|
golang.org/x/tools v0.36.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
+12
-12
@@ -85,20 +85,20 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d
|
|||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/yalue/merged_fs v1.3.0 h1:qCeh9tMPNy/i8cwDsQTJ5bLr6IRxbs6meakNE5O+wyY=
|
github.com/yalue/merged_fs v1.3.0 h1:qCeh9tMPNy/i8cwDsQTJ5bLr6IRxbs6meakNE5O+wyY=
|
||||||
github.com/yalue/merged_fs v1.3.0/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M=
|
github.com/yalue/merged_fs v1.3.0/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
github.com/stretchr/testify v1.10.0 // indirect
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
github.com/tetratelabs/wazero v1.6.0 // indirect
|
github.com/tetratelabs/wazero v1.6.0 // indirect
|
||||||
golang.org/x/mod v0.29.0 // indirect
|
golang.org/x/mod v0.27.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/net v0.45.0 // indirect
|
||||||
golang.org/x/oauth2 v0.30.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/sync v0.18.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.29.0 // indirect
|
||||||
golang.org/x/tools v0.38.0 // indirect
|
golang.org/x/tools v0.36.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
+12
-12
@@ -53,20 +53,20 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
|||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
||||||
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|||||||
@@ -198,12 +198,12 @@ require (
|
|||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 // indirect
|
golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 // indirect
|
||||||
golang.org/x/mod v0.29.0 // indirect
|
golang.org/x/mod v0.28.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/net v0.45.0 // indirect
|
||||||
golang.org/x/sync v0.18.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.29.0 // indirect
|
||||||
golang.org/x/tools v0.38.0 // indirect
|
golang.org/x/tools v0.37.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.6 // indirect
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
honnef.co/go/tools v0.6.1 // indirect
|
honnef.co/go/tools v0.6.1 // indirect
|
||||||
|
|||||||
@@ -481,8 +481,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
|
|||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@@ -496,8 +496,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -507,8 +507,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -529,8 +529,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
@@ -545,8 +545,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
@@ -559,8 +559,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||||
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
|
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
|
||||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
|
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ require (
|
|||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/stretchr/testify v1.10.0 // indirect
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ require (
|
|||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/term v0.37.0 // indirect
|
golang.org/x/term v0.35.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.29.0 // indirect
|
||||||
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61 // indirect
|
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|||||||
@@ -91,14 +91,14 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
|
|||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61 h1:8ajkpB4hXVftY5ko905id+dOnmorcS2CHNxxHLLDcFM=
|
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61 h1:8ajkpB4hXVftY5ko905id+dOnmorcS2CHNxxHLLDcFM=
|
||||||
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61/go.mod h1:IfMagxm39Ys4ybJrDb7W3Ob8RwxftP0Yy+or/NVz1O8=
|
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61/go.mod h1:IfMagxm39Ys4ybJrDb7W3Ob8RwxftP0Yy+or/NVz1O8=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -51,12 +51,12 @@ require (
|
|||||||
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.16.1 // indirect
|
go.mongodb.org/mongo-driver v1.16.1 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/crypto v0.45.0 // indirect
|
golang.org/x/crypto v0.42.0 // indirect
|
||||||
golang.org/x/mod v0.29.0 // indirect
|
golang.org/x/mod v0.27.0 // indirect
|
||||||
golang.org/x/sync v0.18.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.29.0 // indirect
|
||||||
golang.org/x/tools v0.38.0 // indirect
|
golang.org/x/tools v0.36.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
+12
-12
@@ -101,19 +101,19 @@ go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4
|
|||||||
go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
|
go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|||||||
@@ -1,11 +1 @@
|
|||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
*.gen.ts linguist-generated
|
|
||||||
*_gen.ts linguist-generated
|
|
||||||
*_gen.go linguist-generated
|
|
||||||
*_gen.csv linguist-generated
|
|
||||||
*_gen.json linguist-generated
|
|
||||||
**/openapi_snapshots/*.json linguist-generated
|
|
||||||
apps/**/pkg/apis/*_manifest.go linguist-generated
|
|
||||||
public/openapi3.json linguist-generated
|
|
||||||
public/api-merged.json linguist-generated
|
|
||||||
public/api-enterprise-spec.json linguist-generated
|
|
||||||
|
|||||||
+26
-39
@@ -41,8 +41,6 @@
|
|||||||
/docs/sources/ @irenerl24
|
/docs/sources/ @irenerl24
|
||||||
|
|
||||||
/docs/sources/alerting/ @JohnnyK-Grafana
|
/docs/sources/alerting/ @JohnnyK-Grafana
|
||||||
/docs/sources/as-code/ @urbiz-grafana
|
|
||||||
/docs/sources/developer-resources/ @urbiz-grafana
|
|
||||||
/docs/sources/datasources/ @lwandz13
|
/docs/sources/datasources/ @lwandz13
|
||||||
/docs/sources/upgrade-guide/ @jtvdez
|
/docs/sources/upgrade-guide/ @jtvdez
|
||||||
/docs/sources/whatsnew/ @jtvdez
|
/docs/sources/whatsnew/ @jtvdez
|
||||||
@@ -89,7 +87,6 @@
|
|||||||
/apps/folder/ @grafana/grafana-app-platform-squad
|
/apps/folder/ @grafana/grafana-app-platform-squad
|
||||||
/apps/playlist/ @grafana/grafana-app-platform-squad
|
/apps/playlist/ @grafana/grafana-app-platform-squad
|
||||||
/apps/plugins/ @grafana/plugins-platform-backend
|
/apps/plugins/ @grafana/plugins-platform-backend
|
||||||
/apps/collections/ @grafana/grafana-app-platform-squad @grafana/grafana-frontend-platform
|
|
||||||
/apps/preferences/ @grafana/grafana-app-platform-squad @grafana/grafana-frontend-platform
|
/apps/preferences/ @grafana/grafana-app-platform-squad @grafana/grafana-frontend-platform
|
||||||
/apps/shorturl/ @grafana/sharing-squad
|
/apps/shorturl/ @grafana/sharing-squad
|
||||||
/apps/secret/ @grafana/grafana-operator-experience-squad
|
/apps/secret/ @grafana/grafana-operator-experience-squad
|
||||||
@@ -99,9 +96,6 @@
|
|||||||
/apps/iam/ @grafana/access-squad
|
/apps/iam/ @grafana/access-squad
|
||||||
/apps/sdk.mk @grafana/grafana-app-platform-squad
|
/apps/sdk.mk @grafana/grafana-app-platform-squad
|
||||||
/apps/correlations @grafana/datapro
|
/apps/correlations @grafana/datapro
|
||||||
/apps/example/ @grafana/grafana-app-platform-squad
|
|
||||||
/apps/logsdrilldown/ @grafana/observability-logs
|
|
||||||
/apps/annotation/ @grafana/grafana-backend-services-squad
|
|
||||||
/pkg/api/ @grafana/grafana-backend-group
|
/pkg/api/ @grafana/grafana-backend-group
|
||||||
/pkg/apis/ @grafana/grafana-app-platform-squad
|
/pkg/apis/ @grafana/grafana-app-platform-squad
|
||||||
/pkg/apis/query @grafana/grafana-datasources-core-services
|
/pkg/apis/query @grafana/grafana-datasources-core-services
|
||||||
@@ -155,7 +149,7 @@
|
|||||||
/pkg/promlib @grafana/oss-big-tent
|
/pkg/promlib @grafana/oss-big-tent
|
||||||
/pkg/storage/ @grafana/grafana-search-and-storage
|
/pkg/storage/ @grafana/grafana-search-and-storage
|
||||||
/pkg/storage/secret/ @grafana/grafana-operator-experience-squad
|
/pkg/storage/secret/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/annotations/ @grafana/grafana-backend-services-squad
|
/pkg/services/annotations/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/apikey/ @grafana/identity-squad
|
/pkg/services/apikey/ @grafana/identity-squad
|
||||||
/pkg/services/cleanup/ @grafana/grafana-backend-group
|
/pkg/services/cleanup/ @grafana/grafana-backend-group
|
||||||
/pkg/services/contexthandler/ @grafana/grafana-backend-group @grafana/grafana-app-platform-squad
|
/pkg/services/contexthandler/ @grafana/grafana-backend-group @grafana/grafana-app-platform-squad
|
||||||
@@ -171,7 +165,7 @@
|
|||||||
/pkg/services/kmsproviders/ @grafana/grafana-operator-experience-squad
|
/pkg/services/kmsproviders/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/licensing/ @grafana/grafana-operator-experience-squad
|
/pkg/services/licensing/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/dsquerierclient/ @grafana/grafana-datasources-core-services
|
/pkg/services/dsquerierclient/ @grafana/grafana-datasources-core-services
|
||||||
/pkg/services/navtree/ @grafana/grafana-backend-group @grafana/grafana-search-navigate-organise
|
/pkg/services/navtree/ @grafana/grafana-backend-group
|
||||||
/pkg/services/notifications/ @grafana/grafana-backend-group
|
/pkg/services/notifications/ @grafana/grafana-backend-group
|
||||||
/pkg/services/org/ @grafana/grafana-backend-group
|
/pkg/services/org/ @grafana/grafana-backend-group
|
||||||
/pkg/services/playlist/ @grafana/grafana-app-platform-squad
|
/pkg/services/playlist/ @grafana/grafana-app-platform-squad
|
||||||
@@ -185,8 +179,7 @@
|
|||||||
/pkg/services/search/ @grafana/grafana-search-and-storage
|
/pkg/services/search/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/searchusers/ @grafana/grafana-search-and-storage
|
/pkg/services/searchusers/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/secrets/ @grafana/grafana-operator-experience-squad
|
/pkg/services/secrets/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/setting/ @grafana/grafana-backend-services-squad
|
/pkg/services/shorturls/ @grafana/grafana-backend-group
|
||||||
/pkg/services/shorturls/ @grafana/sharing-squad
|
|
||||||
/pkg/services/sqlstore/ @grafana/grafana-search-and-storage
|
/pkg/services/sqlstore/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/ssosettings/ @grafana/identity-squad
|
/pkg/services/ssosettings/ @grafana/identity-squad
|
||||||
/pkg/services/star/ @grafana/grafana-search-and-storage
|
/pkg/services/star/ @grafana/grafana-search-and-storage
|
||||||
@@ -204,7 +197,6 @@
|
|||||||
/pkg/tests/apis/features @grafana/grafana-backend-services-squad
|
/pkg/tests/apis/features @grafana/grafana-backend-services-squad
|
||||||
/pkg/tests/apis/folder @grafana/grafana-search-and-storage
|
/pkg/tests/apis/folder @grafana/grafana-search-and-storage
|
||||||
/pkg/tests/apis/iam @grafana/identity-access-team
|
/pkg/tests/apis/iam @grafana/identity-access-team
|
||||||
/pkg/tests/apis/shorturl @grafana/sharing-squad
|
|
||||||
/pkg/tests/api/correlations/ @grafana/datapro
|
/pkg/tests/api/correlations/ @grafana/datapro
|
||||||
/pkg/tsdb/grafanads/ @grafana/grafana-backend-group
|
/pkg/tsdb/grafanads/ @grafana/grafana-backend-group
|
||||||
/pkg/tsdb/opentsdb/ @grafana/partner-datasources
|
/pkg/tsdb/opentsdb/ @grafana/partner-datasources
|
||||||
@@ -231,7 +223,6 @@
|
|||||||
/devenv/datasources.yaml @grafana/grafana-backend-group
|
/devenv/datasources.yaml @grafana/grafana-backend-group
|
||||||
/devenv/datasources_docker.yaml @grafana/grafana-backend-group
|
/devenv/datasources_docker.yaml @grafana/grafana-backend-group
|
||||||
/devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad
|
/devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad
|
||||||
/devenv/scopes/ @grafana/grafana-operator-experience-squad
|
|
||||||
|
|
||||||
/devenv/dev-dashboards/annotations @grafana/dataviz-squad
|
/devenv/dev-dashboards/annotations @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/migrations @grafana/dataviz-squad
|
/devenv/dev-dashboards/migrations @grafana/dataviz-squad
|
||||||
@@ -248,7 +239,6 @@
|
|||||||
/devenv/dev-dashboards/panel-library @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-library @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-piechart @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-piechart @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-stat @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-stat @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-status-history @grafana/dataviz-squad
|
|
||||||
/devenv/dev-dashboards/panel-table @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-table @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-timeline @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-timeline @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-timeseries @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-timeseries @grafana/dataviz-squad
|
||||||
@@ -258,6 +248,7 @@
|
|||||||
/devenv/dev-dashboards/all-panels.json @grafana/dataviz-squad
|
/devenv/dev-dashboards/all-panels.json @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/dashboards.go @grafana/dataviz-squad
|
/devenv/dev-dashboards/dashboards.go @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/home.json @grafana/dataviz-squad
|
/devenv/dev-dashboards/home.json @grafana/dataviz-squad
|
||||||
|
|
||||||
/devenv/dev-dashboards/datasource-elasticsearch/ @grafana/partner-datasources
|
/devenv/dev-dashboards/datasource-elasticsearch/ @grafana/partner-datasources
|
||||||
/devenv/dev-dashboards/datasource-opentsdb/ @grafana/partner-datasources
|
/devenv/dev-dashboards/datasource-opentsdb/ @grafana/partner-datasources
|
||||||
/devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources
|
/devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources
|
||||||
@@ -421,8 +412,8 @@
|
|||||||
|
|
||||||
/crowdin.yml @grafana/grafana-frontend-platform
|
/crowdin.yml @grafana/grafana-frontend-platform
|
||||||
/public/locales/ @grafanabot
|
/public/locales/ @grafanabot
|
||||||
i18next.config.ts @grafana/grafana-frontend-platform
|
/public/locales/i18next-parser.config.cjs @grafana/grafana-frontend-platform
|
||||||
/public/locales/enterprise/i18next.config.ts @grafana/grafana-frontend-platform
|
/public/locales/i18next-parser-enterprise.config.cjs @grafana/grafana-frontend-platform
|
||||||
/public/app/core/internationalization/ @grafana/grafana-frontend-platform
|
/public/app/core/internationalization/ @grafana/grafana-frontend-platform
|
||||||
/e2e/ @grafana/grafana-frontend-platform
|
/e2e/ @grafana/grafana-frontend-platform
|
||||||
/e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources
|
/e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources
|
||||||
@@ -479,12 +470,22 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
|||||||
/e2e-playwright/fixtures/long-trace-response.json @grafana/observability-traces-and-profiling
|
/e2e-playwright/fixtures/long-trace-response.json @grafana/observability-traces-and-profiling
|
||||||
/e2e-playwright/fixtures/tempo-response.json @grafana/oss-big-tent
|
/e2e-playwright/fixtures/tempo-response.json @grafana/oss-big-tent
|
||||||
/e2e-playwright/fixtures/prometheus-response.json @grafana/datapro
|
/e2e-playwright/fixtures/prometheus-response.json @grafana/datapro
|
||||||
/e2e-playwright/panels-suite/ @grafana/dataviz-squad
|
/e2e-playwright/panels-suite/canvas-scene.spec.ts @grafana/dataviz-squad
|
||||||
/e2e-playwright/panels-suite/dashlist.spec.ts @grafana/grafana-search-navigate-organise
|
/e2e-playwright/panels-suite/dashlist.spec.ts @grafana/grafana-search-navigate-organise
|
||||||
|
/e2e-playwright/panels-suite/datagrid-data-change.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/panels-suite/datagrid-editing-features.spec.ts @grafana/dataviz-squad
|
||||||
/e2e-playwright/panels-suite/frontend-sandbox-panel.spec.ts @grafana/plugins-platform-frontend
|
/e2e-playwright/panels-suite/frontend-sandbox-panel.spec.ts @grafana/plugins-platform-frontend
|
||||||
|
/e2e-playwright/panels-suite/geomap-layer-types.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/panels-suite/geomap-map-controls.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/panels-suite/geomap-spatial-operations-transform.spec.ts @grafana/dataviz-squad
|
||||||
/e2e-playwright/panels-suite/panelEdit_base.spec.ts @grafana/dashboards-squad
|
/e2e-playwright/panels-suite/panelEdit_base.spec.ts @grafana/dashboards-squad
|
||||||
/e2e-playwright/panels-suite/panelEdit_queries.spec.ts @grafana/dashboards-squad
|
/e2e-playwright/panels-suite/panelEdit_queries.spec.ts @grafana/dashboards-squad
|
||||||
/e2e-playwright/panels-suite/panelEdit_transforms.spec.ts @grafana/datapro
|
/e2e-playwright/panels-suite/panelEdit_transforms.spec.ts @grafana/datapro
|
||||||
|
/e2e-playwright/panels-suite/table-footer.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/panels-suite/table-kitchenSink.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/panels-suite/table-markdown.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/panels-suite/table-sparkline.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/panels-suite/table-utils.ts @grafana/dataviz-squad
|
||||||
/e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources
|
/e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources
|
||||||
/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
|
/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
|
||||||
/e2e-playwright/smoke-tests-suite/ @grafana/grafana-frontend-platform
|
/e2e-playwright/smoke-tests-suite/ @grafana/grafana-frontend-platform
|
||||||
@@ -501,7 +502,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
|||||||
/e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend
|
/e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend
|
||||||
/e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend
|
/e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend
|
||||||
/e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad
|
/e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad
|
||||||
/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts @grafana/grafana-frontend-platform
|
|
||||||
/e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad
|
/e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad
|
||||||
/e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad
|
/e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad
|
||||||
/e2e-playwright/various-suite/keybinds.spec.ts @grafana/grafana-frontend-platform
|
/e2e-playwright/various-suite/keybinds.spec.ts @grafana/grafana-frontend-platform
|
||||||
@@ -553,7 +553,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
|||||||
/packages/grafana-data/src/geo/ @grafana/dataviz-squad
|
/packages/grafana-data/src/geo/ @grafana/dataviz-squad
|
||||||
/packages/grafana-data/src/monaco/ @grafana/partner-datasources
|
/packages/grafana-data/src/monaco/ @grafana/partner-datasources
|
||||||
/packages/grafana-data/src/panel/ @grafana/dashboards-squad
|
/packages/grafana-data/src/panel/ @grafana/dashboards-squad
|
||||||
/packages/grafana-data/src/panel/suggestions/ @grafana/dataviz-squad
|
|
||||||
/packages/grafana-data/src/query/ @grafana/grafana-datasources-core-services
|
/packages/grafana-data/src/query/ @grafana/grafana-datasources-core-services
|
||||||
/packages/grafana-data/src/rbac/ @grafana/access-squad
|
/packages/grafana-data/src/rbac/ @grafana/access-squad
|
||||||
/packages/grafana-data/src/table/ @grafana/dataviz-squad
|
/packages/grafana-data/src/table/ @grafana/dataviz-squad
|
||||||
@@ -561,8 +560,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
|||||||
/packages/grafana-data/src/themes/ @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/themes/ @grafana/grafana-frontend-platform
|
||||||
/packages/grafana-data/src/transformations/ @grafana/datapro
|
/packages/grafana-data/src/transformations/ @grafana/datapro
|
||||||
/packages/grafana-data/src/types/ @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/types/ @grafana/grafana-frontend-platform
|
||||||
/packages/grafana-data/src/types/scopes.ts @grafana/grafana-operator-experience-squad
|
|
||||||
/packages/grafana-data/src/types/suggestions.ts @grafana/dataviz-squad
|
|
||||||
/packages/grafana-data/src/utils/__snapshots__/ @grafanabot
|
/packages/grafana-data/src/utils/__snapshots__/ @grafanabot
|
||||||
/packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform
|
||||||
/packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform
|
||||||
@@ -720,11 +717,10 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
|||||||
/packages/grafana-ui/src/components/BarGauge/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/BarGauge/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/DataLinks/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/DataLinks/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/Gauge/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/Gauge/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/RadialGauge/ @grafana/dataviz-squad
|
|
||||||
/packages/grafana-ui/src/components/PluginSignatureBadge/ @grafana/plugins-platform-frontend
|
/packages/grafana-ui/src/components/PluginSignatureBadge/ @grafana/plugins-platform-frontend
|
||||||
/packages/grafana-ui/src/components/Sparkline/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/Sparkline/ @grafana/grafana-frontend-platform @grafana/app-o11y-visualizations
|
||||||
/packages/grafana-ui/src/components/Table/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/Table/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/Table/Cells/SparklineCell.tsx @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/Table/Cells/SparklineCell.tsx @grafana/dataviz-squad @grafana/app-o11y-visualizations
|
||||||
/packages/grafana-ui/src/components/uPlot/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/uPlot/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/ValuePicker/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/ValuePicker/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/VizLayout/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/VizLayout/ @grafana/dataviz-squad
|
||||||
@@ -743,17 +739,6 @@ i18next.config.ts @grafana/grafana-frontend-platform
|
|||||||
# @grafana/test-utils
|
# @grafana/test-utils
|
||||||
/packages/grafana-test-utils @grafana/grafana-frontend-platform
|
/packages/grafana-test-utils @grafana/grafana-frontend-platform
|
||||||
|
|
||||||
# @grafana/api-clients
|
|
||||||
/packages/grafana-api-clients/ @grafana/grafana-frontend-platform @grafana/grafana-search-navigate-organise
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/advisor/ @grafana/plugins-platform-frontend
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/correlations/ @grafana/datapro
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/dashboard/ @grafana/dashboards-squad
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/folder/ @grafana/grafana-search-navigate-organise
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/iam/ @grafana/access-squad @grafana/identity-squad
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/preferences/ @grafana/plugins-platform-frontend
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/provisioning/ @grafana/grafana-git-ui-sync-team
|
|
||||||
/packages/grafana-api-clients/src/clients/rtkq/shorturl/ @grafana/sharing-squad
|
|
||||||
|
|
||||||
# root files, mostly frontend
|
# root files, mostly frontend
|
||||||
/.browserslistrc @grafana/frontend-ops
|
/.browserslistrc @grafana/frontend-ops
|
||||||
/package.json @grafana/frontend-ops
|
/package.json @grafana/frontend-ops
|
||||||
@@ -804,7 +789,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/public/app/core/components/ColorScale/ @grafana/dataviz-squad
|
/public/app/core/components/ColorScale/ @grafana/dataviz-squad
|
||||||
/public/app/core/components/DynamicImports/ @grafana/grafana-search-navigate-organise
|
/public/app/core/components/DynamicImports/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/core/components/EmptyListCTA/ @grafana/grafana-frontend-platform
|
/public/app/core/components/EmptyListCTA/ @grafana/grafana-frontend-platform
|
||||||
/public/app/core/components/FolderFilter/ @grafana/grafana-search-navigate-organise
|
/public/app/core/components/FolderFilter/ @grafana/sharing-squad
|
||||||
/public/app/core/components/Footer/ @grafana/grafana-search-navigate-organise
|
/public/app/core/components/Footer/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/core/components/ForgottenPassword/ @grafana/grafana-search-navigate-organise
|
/public/app/core/components/ForgottenPassword/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/core/components/Form/ @grafana/grafana-frontend-platform
|
/public/app/core/components/Form/ @grafana/grafana-frontend-platform
|
||||||
@@ -846,6 +831,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/public/app/core/constants.ts @grafana/grafana-frontend-platform
|
/public/app/core/constants.ts @grafana/grafana-frontend-platform
|
||||||
/public/app/core/context/ @grafana/grafana-frontend-platform
|
/public/app/core/context/ @grafana/grafana-frontend-platform
|
||||||
/public/app/core/copy/appNotification.ts @grafana/grafana-search-navigate-organise
|
/public/app/core/copy/appNotification.ts @grafana/grafana-search-navigate-organise
|
||||||
|
/public/app/core/core.ts @grafana/grafana-frontend-platform
|
||||||
/public/app/core/crash/ @grafana/observability-traces-and-profiling
|
/public/app/core/crash/ @grafana/observability-traces-and-profiling
|
||||||
/public/app/core/history/ @grafana/observability-traces-and-profiling
|
/public/app/core/history/ @grafana/observability-traces-and-profiling
|
||||||
/public/app/core/hooks/useBusEvent.ts @grafana/grafana-frontend-platform
|
/public/app/core/hooks/useBusEvent.ts @grafana/grafana-frontend-platform
|
||||||
@@ -954,7 +940,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/public/app/features/notifications/ @grafana/grafana-search-navigate-organise
|
/public/app/features/notifications/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/features/org/ @grafana/grafana-search-navigate-organise
|
/public/app/features/org/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/features/panel/ @grafana/dashboards-squad
|
/public/app/features/panel/ @grafana/dashboards-squad
|
||||||
/public/app/features/panel/suggestions/ @grafana/dataviz-squad
|
|
||||||
/public/app/features/playlist/ @grafana/dashboards-squad
|
/public/app/features/playlist/ @grafana/dashboards-squad
|
||||||
/public/app/features/plugins/ @grafana/plugins-platform-frontend
|
/public/app/features/plugins/ @grafana/plugins-platform-frontend
|
||||||
/public/app/features/profile/ @grafana/grafana-frontend-platform
|
/public/app/features/profile/ @grafana/grafana-frontend-platform
|
||||||
@@ -972,6 +957,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/public/app/features/transformers/timeSeriesTable/ @grafana/dataviz-squad @grafana/app-o11y-visualizations
|
/public/app/features/transformers/timeSeriesTable/ @grafana/dataviz-squad @grafana/app-o11y-visualizations
|
||||||
/public/app/features/users/ @grafana/access-squad
|
/public/app/features/users/ @grafana/access-squad
|
||||||
/public/app/features/variables/ @grafana/dashboards-squad
|
/public/app/features/variables/ @grafana/dashboards-squad
|
||||||
|
/public/app/features/preferences/ @grafana/grafana-frontend-platform
|
||||||
/public/app/features/bookmarks/ @grafana/grafana-search-navigate-organise
|
/public/app/features/bookmarks/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/plugins/panel/* @grafana/dataviz-squad
|
/public/app/plugins/panel/* @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/alertlist/ @grafana/alerting-frontend
|
/public/app/plugins/panel/alertlist/ @grafana/alerting-frontend
|
||||||
@@ -993,7 +979,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/public/app/plugins/panel/state-timeline/ @grafana/dataviz-squad
|
/public/app/plugins/panel/state-timeline/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/status-history/ @grafana/dataviz-squad
|
/public/app/plugins/panel/status-history/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/table/ @grafana/dataviz-squad
|
/public/app/plugins/panel/table/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/table/cells/SparklineCellOptionsEditor.tsx @grafana/dataviz-squad
|
/public/app/plugins/panel/table/cells/SparklineCellOptionsEditor.tsx @grafana/dataviz-squad @grafana/app-o11y-visualizations
|
||||||
/public/app/plugins/panel/timeseries/ @grafana/dataviz-squad
|
/public/app/plugins/panel/timeseries/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/trend/ @grafana/dataviz-squad
|
/public/app/plugins/panel/trend/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/geomap/ @grafana/dataviz-squad
|
/public/app/plugins/panel/geomap/ @grafana/dataviz-squad
|
||||||
@@ -1067,10 +1053,13 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/scripts/trigger_windows_build.sh @grafana/grafana-developer-enablement-squad
|
/scripts/trigger_windows_build.sh @grafana/grafana-developer-enablement-squad
|
||||||
/scripts/cleanup-husky.sh @grafana/frontend-ops
|
/scripts/cleanup-husky.sh @grafana/frontend-ops
|
||||||
/scripts/verify-repo-update/ @grafana/grafana-developer-enablement-squad
|
/scripts/verify-repo-update/ @grafana/grafana-developer-enablement-squad
|
||||||
|
/scripts/generate-rtk-apis.ts @grafana/grafana-frontend-platform
|
||||||
|
/scripts/process-specs.ts @grafana/grafana-frontend-platform
|
||||||
/scripts/generate-alerting-rtk-apis.ts @grafana/alerting-frontend
|
/scripts/generate-alerting-rtk-apis.ts @grafana/alerting-frontend
|
||||||
/scripts/levitate-parse-json-report.js @grafana/plugins-platform-frontend
|
/scripts/levitate-parse-json-report.js @grafana/plugins-platform-frontend
|
||||||
/scripts/levitate-show-affected-plugins.js @grafana/plugins-platform-frontend
|
/scripts/levitate-show-affected-plugins.js @grafana/plugins-platform-frontend
|
||||||
/scripts/codemods/explicit-barrel-imports.cjs @grafana/frontend-ops
|
/scripts/codemods/explicit-barrel-imports.cjs @grafana/frontend-ops
|
||||||
|
/scripts/rtk-client-generator/ @grafana/grafana-search-navigate-organise
|
||||||
|
|
||||||
/scripts/codeowners-manifest/ @grafana/dataviz-squad
|
/scripts/codeowners-manifest/ @grafana/dataviz-squad
|
||||||
/scripts/test-coverage-by-codeowner.js @grafana/dataviz-squad
|
/scripts/test-coverage-by-codeowner.js @grafana/dataviz-squad
|
||||||
@@ -1111,7 +1100,6 @@ eslint-suppressions.json @grafanabot
|
|||||||
# Grafana Sharing Squad
|
# Grafana Sharing Squad
|
||||||
/public/app/features/dashboard-scene/sharing/ @grafana/sharing-squad
|
/public/app/features/dashboard-scene/sharing/ @grafana/sharing-squad
|
||||||
/public/app/features/dashboard/components/ShareModal/ @grafana/sharing-squad
|
/public/app/features/dashboard/components/ShareModal/ @grafana/sharing-squad
|
||||||
/public/app/features/dashboard/dashgrid/DashboardLibrary/ @grafana/sharing-squad
|
|
||||||
/public/app/features/manage-dashboards/components/SnapshotListTable.tsx @grafana/sharing-squad
|
/public/app/features/manage-dashboards/components/SnapshotListTable.tsx @grafana/sharing-squad
|
||||||
/pkg/services/dashboardsnapshots/ @grafana/sharing-squad
|
/pkg/services/dashboardsnapshots/ @grafana/sharing-squad
|
||||||
/public/app/features/explore/QueryLibrary/ @grafana/sharing-squad
|
/public/app/features/explore/QueryLibrary/ @grafana/sharing-squad
|
||||||
@@ -1182,7 +1170,6 @@ embed.go @grafana/grafana-as-code
|
|||||||
/pkg/registry/ @grafana/grafana-as-code
|
/pkg/registry/ @grafana/grafana-as-code
|
||||||
/pkg/registry/apis/ @grafana/grafana-app-platform-squad
|
/pkg/registry/apis/ @grafana/grafana-app-platform-squad
|
||||||
/pkg/registry/apis/folders @grafana/grafana-search-and-storage
|
/pkg/registry/apis/folders @grafana/grafana-search-and-storage
|
||||||
/pkg/registry/apis/datasource @grafana/grafana-datasources-core-services
|
|
||||||
/pkg/registry/apis/query @grafana/grafana-datasources-core-services
|
/pkg/registry/apis/query @grafana/grafana-datasources-core-services
|
||||||
/pkg/registry/apis/secret @grafana/grafana-operator-experience-squad
|
/pkg/registry/apis/secret @grafana/grafana-operator-experience-squad
|
||||||
/pkg/registry/apis/userstorage @grafana/grafana-app-platform-squad @grafana/plugins-platform-backend
|
/pkg/registry/apis/userstorage @grafana/grafana-app-platform-squad @grafana/plugins-platform-backend
|
||||||
|
|||||||
@@ -31,9 +31,6 @@ outputs:
|
|||||||
dockerfile:
|
dockerfile:
|
||||||
description: Whether the dockerfile or self have changed in any way
|
description: Whether the dockerfile or self have changed in any way
|
||||||
value: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}
|
value: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}
|
||||||
devenv:
|
|
||||||
description: Whether the devenv or self have changed in any way
|
|
||||||
value: ${{ steps.changed-files.outputs.devenv_any_changed || 'true' }}
|
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
@@ -139,9 +136,6 @@ runs:
|
|||||||
- '.vale.ini'
|
- '.vale.ini'
|
||||||
- '.github/actions/change-detection/**'
|
- '.github/actions/change-detection/**'
|
||||||
- '${{ inputs.self }}'
|
- '${{ inputs.self }}'
|
||||||
devenv:
|
|
||||||
- 'devenv/**'
|
|
||||||
- '${{ inputs.self }}'
|
|
||||||
- name: Print all change groups
|
- name: Print all change groups
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
@@ -163,5 +157,3 @@ runs:
|
|||||||
echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}"
|
echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}"
|
||||||
echo "Dockerfile: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}"
|
echo "Dockerfile: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}"
|
||||||
echo " --> ${{ steps.changed-files.outputs.dockerfile_all_changed_files }}"
|
echo " --> ${{ steps.changed-files.outputs.dockerfile_all_changed_files }}"
|
||||||
echo "devenv: ${{ steps.changed-files.outputs.devenv_any_changed || 'true' }}"
|
|
||||||
echo " --> ${{ steps.changed-files.outputs.devenv_all_changed_files }}"
|
|
||||||
|
|||||||
@@ -33,48 +33,16 @@ runs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
|
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||||
run: |
|
run: |
|
||||||
RETRIES="5"
|
git clone https://x-access-token:${GH_TOKEN}@github.com/grafana/grafana-enterprise.git ../grafana-enterprise;
|
||||||
|
|
||||||
for i in $(seq 1 $RETRIES); do
|
|
||||||
echo "Attempt $i to clone..."
|
|
||||||
|
|
||||||
if git clone https://x-access-token:${GH_TOKEN}@github.com/grafana/grafana-enterprise.git ../grafana-enterprise; then
|
|
||||||
echo "Clone succeeded on attempt $i"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $i -eq $RETRIES ]; then
|
|
||||||
echo "Clone failed after $RETRIES attempts, failing pipeline."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sleep "$i"
|
|
||||||
done
|
|
||||||
|
|
||||||
cd ../grafana-enterprise
|
cd ../grafana-enterprise
|
||||||
|
|
||||||
for i in $(seq 1 $RETRIES); do
|
if git checkout ${GITHUB_HEAD_REF}; then
|
||||||
echo "Attempt $i to checkout..."
|
echo "checked out ${GITHUB_HEAD_REF}"
|
||||||
|
elif git checkout ${GITHUB_BASE_REF}; then
|
||||||
if git checkout ${GITHUB_HEAD_REF}; then
|
echo "checked out ${GITHUB_BASE_REF}"
|
||||||
echo "checked out ${GITHUB_HEAD_REF}"
|
else
|
||||||
elif git checkout ${GITHUB_BASE_REF}; then
|
git checkout main
|
||||||
echo "checked out ${GITHUB_BASE_REF}"
|
fi
|
||||||
else
|
|
||||||
git checkout main
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "Checkout succeeded, breaking retry loop"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $i -eq $RETRIES ]; then
|
|
||||||
echo "Checkout failed after $RETRIES attempts, failing pipeline."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sleep "$i"
|
|
||||||
done
|
|
||||||
|
|
||||||
QUIET=1 ./build.sh
|
QUIET=1 ./build.sh
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
extends: ["config:recommended"],
|
extends: ["config:recommended"],
|
||||||
enabledManagers: ["npm", "docker-compose"],
|
enabledManagers: ["npm"],
|
||||||
ignorePresets: [
|
ignorePresets: [
|
||||||
"github>grafana/grafana-renovate-config//presets/labels",
|
"github>grafana/grafana-renovate-config//presets/labels",
|
||||||
],
|
],
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"@types/slate-react", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
"@types/slate-react", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
||||||
"@types/slate", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
"@types/slate", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
||||||
],
|
],
|
||||||
includePaths: ["package.json", "packages/**", "public/app/plugins/**", "devenv/frontend-service/docker-compose.yaml"],
|
includePaths: ["package.json", "packages/**", "public/app/plugins/**"],
|
||||||
ignorePaths: ["emails/**", "**/mocks/**"],
|
ignorePaths: ["emails/**", "**/mocks/**"],
|
||||||
labels: ["area/frontend", "dependencies", "no-changelog"],
|
labels: ["area/frontend", "dependencies", "no-changelog"],
|
||||||
postUpdateOptions: ["yarnDedupeHighest"],
|
postUpdateOptions: ["yarnDedupeHighest"],
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
- name: Upload to GitHub security events
|
- name: Upload to GitHub security events
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
# If there are security problems, GitHub will automatically comment on the PR for us.
|
# If there are security problems, GitHub will automatically comment on the PR for us.
|
||||||
uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
|
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
category: actionlint
|
category: actionlint
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Build swagger
|
- name: Build swagger
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # 6.0.0
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # 5.5.0
|
||||||
with:
|
with:
|
||||||
"go-version-file": "go.mod"
|
"go-version-file": "go.mod"
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
@@ -46,9 +46,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
# Explicitly set Go version to 1.24.1 to ensure consistent OpenAPI spec generation
|
||||||
|
# The crypto/x509 package has additional fields in Go 1.24.1 that affect the generated specs
|
||||||
|
# This ensures the GHAs environment matches what we use in the Drone pipeline
|
||||||
|
go-version: 1.24.1
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Verify code generation
|
- name: Verify code generation
|
||||||
@@ -79,7 +82,7 @@ jobs:
|
|||||||
make swagger-clean && make openapi3-gen
|
make swagger-clean && make openapi3-gen
|
||||||
|
|
||||||
# Check if the generated specs differ from what's in the repository
|
# Check if the generated specs differ from what's in the repository
|
||||||
for f in public/api-merged.json public/openapi3.json public/api-enterprise-spec.json; do git add $f; done
|
for f in public/api-merged.json public/openapi3.json; do git add $f; done
|
||||||
if [ -z "$(git diff --name-only --cached)" ]; then
|
if [ -z "$(git diff --name-only --cached)" ]; then
|
||||||
echo "OpenAPI specs are up to date!"
|
echo "OpenAPI specs are up to date!"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
@@ -94,7 +94,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Setup Enterprise
|
- name: Setup Enterprise
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ jobs:
|
|||||||
}' "$GITHUB_EVENT_PATH" > /tmp/pr_info.json
|
}' "$GITHUB_EVENT_PATH" > /tmp/pr_info.json
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: pr_info
|
name: pr_info
|
||||||
path: /tmp/pr_info.json
|
path: /tmp/pr_info.json
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }}
|
private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }}
|
||||||
|
|
||||||
- name: Download PR info artifact
|
- name: Download PR info artifact
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v4
|
||||||
id: download-pr-info
|
id: download-pr-info
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
- name: Setup nodejs environment
|
- name: Setup nodejs environment
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
- name: "Configure git user"
|
- name: "Configure git user"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
pull-requests: read
|
pull-requests: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v0.2.1
|
- uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v1.0.0
|
||||||
with:
|
with:
|
||||||
dry-run: true
|
dry-run: true
|
||||||
max-date: "1 month ago"
|
max-date: "1 month ago"
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ name: "CodeQL checks"
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches: ['**'] # run on all branches
|
||||||
- main
|
|
||||||
- release-*.*.*
|
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**/*.cue'
|
- '**/*.cue'
|
||||||
- '**/*.json'
|
- '**/*.json'
|
||||||
@@ -74,15 +72,14 @@ jobs:
|
|||||||
|
|
||||||
- if: matrix.language == 'go' && needs.detect-changes.outputs.go == 'true'
|
- if: matrix.language == 'go' && needs.detect-changes.outputs.go == 'true'
|
||||||
name: Set go version
|
name: Set go version
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||||
with:
|
with:
|
||||||
cache: false
|
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
if: needs.detect-changes.outputs[matrix.language] == 'true'
|
if: needs.detect-changes.outputs[matrix.language] == 'true'
|
||||||
uses: github/codeql-action/init@v4
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -97,4 +94,4 @@ jobs:
|
|||||||
make build-go
|
make build-go
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v4
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
- name: 'Set up Cloud SDK'
|
- name: 'Set up Cloud SDK'
|
||||||
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
|
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
|
||||||
- name: Setup nodejs environment
|
- name: Setup nodejs environment
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -101,7 +101,7 @@ jobs:
|
|||||||
echo "has_backend=false" >> "$GITHUB_OUTPUT"
|
echo "has_backend=false" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
- name: Setup golang environment
|
- name: Setup golang environment
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||||
if: steps.check_backend.outputs.has_backend == 'true'
|
if: steps.check_backend.outputs.has_backend == 'true'
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
@@ -193,7 +193,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
- name: store build artifacts
|
- name: store build artifacts
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
path: ${{ steps.get_dir.outputs.dir }}/ci/packages/*.zip
|
path: ${{ steps.get_dir.outputs.dir }}/ci/packages/*.zip
|
||||||
|
|||||||
@@ -25,5 +25,4 @@ jobs:
|
|||||||
patch_ref: "${{ github.base_ref }}" # this is the target branch name, Ex: "main"
|
patch_ref: "${{ github.base_ref }}" # this is the target branch name, Ex: "main"
|
||||||
patch_repo: "grafana/grafana-security-patches"
|
patch_repo: "grafana/grafana-security-patches"
|
||||||
patch_prefix: "${{ github.event.pull_request.number }}"
|
patch_prefix: "${{ github.event.pull_request.number }}"
|
||||||
sender: "${{ github.event.pull_request.user.login }}"
|
|
||||||
secrets: inherit # zizmor: ignore[secrets-inherit]
|
secrets: inherit # zizmor: ignore[secrets-inherit]
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
path: './pr'
|
path: './pr'
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './pr/.nvmrc'
|
node-version-file: './pr/.nvmrc'
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
run: zip -r ./pr_built_packages.zip ./packages/**/*.tgz
|
run: zip -r ./pr_built_packages.zip ./packages/**/*.tgz
|
||||||
|
|
||||||
- name: Upload build output as artifact
|
- name: Upload build output as artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: buildPr
|
name: buildPr
|
||||||
path: './pr/pr_built_packages.zip'
|
path: './pr/pr_built_packages.zip'
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.base.ref }}
|
ref: ${{ github.event.pull_request.base.ref }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: './base/.nvmrc'
|
node-version-file: './base/.nvmrc'
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ jobs:
|
|||||||
run: zip -r ./base_built_packages.zip ./packages/**/*.tgz
|
run: zip -r ./base_built_packages.zip ./packages/**/*.tgz
|
||||||
|
|
||||||
- name: Upload build output as artifact
|
- name: Upload build output as artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: buildBase
|
name: buildBase
|
||||||
path: './base/base_built_packages.zip'
|
path: './base/base_built_packages.zip'
|
||||||
@@ -136,17 +136,17 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Get built packages from pr
|
- name: Get built packages from pr
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: buildPr
|
name: buildPr
|
||||||
|
|
||||||
- name: Get built packages from base
|
- name: Get built packages from base
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: buildBase
|
name: buildBase
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ jobs:
|
|||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
|
||||||
- name: Upload check output as artifact
|
- name: Upload check output as artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: levitate
|
name: levitate
|
||||||
path: levitate/
|
path: levitate/
|
||||||
@@ -225,7 +225,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: 'Download artifact'
|
- name: 'Download artifact'
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: levitate
|
name: levitate
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
cache: true
|
cache: true
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -109,7 +109,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -133,7 +133,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -164,7 +164,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-go@v6.0.0
|
- uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
- name: Run gofmt
|
- name: Run gofmt
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-go@v6.0.0
|
- uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
- name: "Get vault secrets"
|
- name: "Get vault secrets"
|
||||||
id: vault-secrets
|
id: vault-secrets
|
||||||
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses]
|
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
|
||||||
with:
|
with:
|
||||||
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault
|
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault
|
||||||
repo_secrets: |
|
repo_secrets: |
|
||||||
@@ -71,7 +71,7 @@ jobs:
|
|||||||
|
|
||||||
- name: "Get vault secrets"
|
- name: "Get vault secrets"
|
||||||
id: vault-secrets
|
id: vault-secrets
|
||||||
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses]
|
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
|
||||||
with:
|
with:
|
||||||
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
||||||
repo_secrets: |
|
repo_secrets: |
|
||||||
@@ -139,7 +139,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: "Get vault secrets"
|
- name: "Get vault secrets"
|
||||||
id: vault-secrets
|
id: vault-secrets
|
||||||
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses]
|
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
|
||||||
with:
|
with:
|
||||||
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
||||||
repo_secrets: |
|
repo_secrets: |
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v4
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: "javascript"
|
languages: "javascript"
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v4
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ jobs:
|
|||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
if: steps.check-python.outputs.skip != 'true'
|
if: steps.check-python.outputs.skip != 'true'
|
||||||
uses: github/codeql-action/init@v4
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: "python"
|
languages: "python"
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
if: steps.check-python.outputs.skip != 'true'
|
if: steps.check-python.outputs.skip != 'true'
|
||||||
uses: github/codeql-action/analyze@v4
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
@@ -94,14 +94,14 @@ jobs:
|
|||||||
id: artifact
|
id: artifact
|
||||||
|
|
||||||
- name: Upload grafana.tar.gz
|
- name: Upload grafana.tar.gz
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
path: build-dir/grafana.tar.gz
|
path: build-dir/grafana.tar.gz
|
||||||
|
|
||||||
- name: Upload grafana docker tarball
|
- name: Upload grafana docker tarball
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
name: grafana-docker-tar-gz
|
name: grafana-docker-tar-gz
|
||||||
@@ -122,7 +122,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: ${{ !github.event.pull_request.head.repo.fork }}
|
cache: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
@@ -133,7 +133,7 @@ jobs:
|
|||||||
# We want a static binary, so we need to set CGO_ENABLED=0
|
# We want a static binary, so we need to set CGO_ENABLED=0
|
||||||
CGO_ENABLED=0 go build -o ./e2e-runner ./e2e/
|
CGO_ENABLED=0 go build -o ./e2e-runner ./e2e/
|
||||||
echo "artifact=e2e-runner-${{github.run_number}}" >> "$GITHUB_OUTPUT"
|
echo "artifact=e2e-runner-${{github.run_number}}" >> "$GITHUB_OUTPUT"
|
||||||
- uses: actions/upload-artifact@v5
|
- uses: actions/upload-artifact@v4
|
||||||
id: upload
|
id: upload
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
@@ -159,7 +159,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
registry: 'us-docker.pkg.dev'
|
registry: 'us-docker.pkg.dev'
|
||||||
environment: 'dev'
|
environment: 'dev'
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: grafana-docker-tar-gz
|
name: grafana-docker-tar-gz
|
||||||
path: .
|
path: .
|
||||||
@@ -221,10 +221,10 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/download-artifact@v6
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
- uses: actions/download-artifact@v6
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.build-e2e-runner.outputs.artifact }}
|
name: ${{ needs.build-e2e-runner.outputs.artifact }}
|
||||||
- name: chmod +x
|
- name: chmod +x
|
||||||
@@ -245,7 +245,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
echo "suite=$(echo "$SUITE" | sed 's/\//-/g')" >> "$GITHUB_OUTPUT"
|
echo "suite=$(echo "$SUITE" | sed 's/\//-/g')" >> "$GITHUB_OUTPUT"
|
||||||
- uses: actions/upload-artifact@v5
|
- uses: actions/upload-artifact@v4
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.set-suite-name.outputs.suite }}-${{ github.run_number }}
|
name: ${{ steps.set-suite-name.outputs.suite }}-${{ github.run_number }}
|
||||||
@@ -267,7 +267,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/download-artifact@v6
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
- name: Run E2E tests
|
- name: Run E2E tests
|
||||||
@@ -307,7 +307,7 @@ jobs:
|
|||||||
version: 0.18.8
|
version: 0.18.8
|
||||||
verb: run
|
verb: run
|
||||||
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report
|
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report
|
||||||
- uses: actions/upload-artifact@v5
|
- uses: actions/upload-artifact@v4
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
with:
|
with:
|
||||||
name: playwright-blob-${{ github.run_number }}-${{ matrix.shard }}
|
name: playwright-blob-${{ github.run_number }}-${{ matrix.shard }}
|
||||||
@@ -360,7 +360,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json
|
docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json
|
||||||
|
|
||||||
- uses: actions/download-artifact@v6
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
|
|
||||||
@@ -395,12 +395,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Download blob reports from GitHub Actions Artifacts
|
- name: Download blob reports from GitHub Actions Artifacts
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: blobs
|
path: blobs
|
||||||
pattern: playwright-blob-*
|
pattern: playwright-blob-*
|
||||||
@@ -439,7 +439,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload HTML report
|
- name: Upload HTML report
|
||||||
id: upload-html
|
id: upload-html
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: playwright-html-${{ github.run_number }}
|
name: playwright-html-${{ github.run_number }}
|
||||||
path: playwright-report
|
path: playwright-report
|
||||||
@@ -479,7 +479,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/download-artifact@v6
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
- name: Run PR a11y test
|
- name: Run PR a11y test
|
||||||
@@ -498,7 +498,7 @@ jobs:
|
|||||||
args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail --results=./pa11y-ci-results.json
|
args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail --results=./pa11y-ci-results.json
|
||||||
- name: Upload pa11y results
|
- name: Upload pa11y results
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
name: pa11y-ci-results
|
name: pa11y-ci-results
|
||||||
@@ -525,13 +525,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --immutable
|
run: yarn install --immutable
|
||||||
- name: Get pa11y results
|
- name: Get pa11y results
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: pa11y-ci-results
|
name: pa11y-ci-results
|
||||||
- name: Extract and publish metrics
|
- name: Extract and publish metrics
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
outputs:
|
outputs:
|
||||||
changed: ${{ steps.detect-changes.outputs.frontend }}
|
changed: ${{ steps.detect-changes.outputs.frontend }}
|
||||||
devenv-changed: ${{ steps.detect-changes.outputs.devenv }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
@@ -170,26 +169,3 @@ jobs:
|
|||||||
needs: ${{ toJson(needs) }}
|
needs: ${{ toJson(needs) }}
|
||||||
failure-message: "One or more unit test jobs have failed"
|
failure-message: "One or more unit test jobs have failed"
|
||||||
success-message: "All unit tests completed successfully"
|
success-message: "All unit tests completed successfully"
|
||||||
|
|
||||||
devenv:
|
|
||||||
needs:
|
|
||||||
- detect-changes
|
|
||||||
if: needs.detect-changes.outputs.devenv-changed == 'true'
|
|
||||||
runs-on: ubuntu-x64-large
|
|
||||||
name: "Devenv frontend-service build"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Setup Docker
|
|
||||||
uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: ./.github/actions/setup-node
|
|
||||||
- name: Install Tilt
|
|
||||||
run: curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
|
|
||||||
- name: Create empty config files # TODO: the tiltfile should conditionally mount these only if they exist, like the enterprise license
|
|
||||||
run: |
|
|
||||||
touch devenv/frontend-service/configs/grafana-api.local.ini
|
|
||||||
touch devenv/frontend-service/configs/frontend-service.local.ini
|
|
||||||
- name: Test frontend-service Tiltfile
|
|
||||||
run: tilt ci --file devenv/frontend-service/Tiltfile
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||||
with:
|
with:
|
||||||
cache: false
|
cache: false
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||||
with:
|
with:
|
||||||
cache: false
|
cache: false
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
@@ -107,7 +107,6 @@ jobs:
|
|||||||
CURRENT_OSS_WIRE_CHECKSUM=$(sha256sum pkg/server/wire_gen.go | cut -d' ' -f1)
|
CURRENT_OSS_WIRE_CHECKSUM=$(sha256sum pkg/server/wire_gen.go | cut -d' ' -f1)
|
||||||
if [ "$CURRENT_OSS_WIRE_CHECKSUM" != "${{ steps.pre_gen_oss.outputs.wire_checksum }}" ]; then
|
if [ "$CURRENT_OSS_WIRE_CHECKSUM" != "${{ steps.pre_gen_oss.outputs.wire_checksum }}" ]; then
|
||||||
OSS_WIRE_CHANGED=true
|
OSS_WIRE_CHANGED=true
|
||||||
OSS_DIFF=$(git diff pkg/server/wire_gen.go)
|
|
||||||
echo "Uncomitted changes detected in pkg/server/wire_gen.go"
|
echo "Uncomitted changes detected in pkg/server/wire_gen.go"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -116,7 +115,6 @@ jobs:
|
|||||||
CURRENT_ENTERPRISE_WIRE_CHECKSUM=$(sha256sum pkg/server/enterprise_wire_gen.go | cut -d' ' -f1)
|
CURRENT_ENTERPRISE_WIRE_CHECKSUM=$(sha256sum pkg/server/enterprise_wire_gen.go | cut -d' ' -f1)
|
||||||
if [ "$CURRENT_ENTERPRISE_WIRE_CHECKSUM" != "${{ steps.pre_gen_enterprise.outputs.wire_checksum }}" ]; then
|
if [ "$CURRENT_ENTERPRISE_WIRE_CHECKSUM" != "${{ steps.pre_gen_enterprise.outputs.wire_checksum }}" ]; then
|
||||||
ENTERPRISE_WIRE_CHANGED=true
|
ENTERPRISE_WIRE_CHANGED=true
|
||||||
ENTERPRISE_DIFF=$(git diff pkg/server/enterprise_wire_gen.go)
|
|
||||||
echo "Uncomitted changes detected in pkg/server/enterprise_wire_gen.go"
|
echo "Uncomitted changes detected in pkg/server/enterprise_wire_gen.go"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -126,14 +124,6 @@ jobs:
|
|||||||
else
|
else
|
||||||
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "false" ]]; then
|
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "false" ]]; then
|
||||||
echo "> !!! Please synchronize the grafana OSS and grafana enterprise code bases as defined in the enterprise readme, then run 'make gen-go' in the OSS folder and commit the changes to both repositories."
|
echo "> !!! Please synchronize the grafana OSS and grafana enterprise code bases as defined in the enterprise readme, then run 'make gen-go' in the OSS folder and commit the changes to both repositories."
|
||||||
if [[ "$OSS_WIRE_CHANGED" == "true" ]]; then
|
|
||||||
echo "OSS changes:"
|
|
||||||
echo "$OSS_DIFF"
|
|
||||||
fi
|
|
||||||
if [[ "$ENTERPRISE_WIRE_CHANGED" == "true" ]]; then
|
|
||||||
echo "Enterprise changes:"
|
|
||||||
echo "$ENTERPRISE_DIFF"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
echo "> !!! Please run 'make gen-go' and commit the changes."
|
echo "> !!! Please run 'make gen-go' and commit the changes."
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
id: detect-changes
|
id: detect-changes
|
||||||
uses: ./.github/actions/change-detection
|
uses: ./.github/actions/change-detection
|
||||||
with:
|
with:
|
||||||
self: .github/workflows/pr-test-docker.yml
|
self: .github/workflows/pr-test-integration.yml
|
||||||
|
|
||||||
build-dockerfile:
|
build-dockerfile:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
@@ -34,6 +34,6 @@ jobs:
|
|||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4
|
- uses: docker/setup-docker-action@b60f85385d03ac8acfca6d9996982511d8620a19 # v4
|
||||||
- name: Build Dockerfile
|
- name: Build Dockerfile
|
||||||
run: make build-docker-full
|
run: make build-docker-full
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
@@ -78,7 +78,6 @@ jobs:
|
|||||||
# We don't need more than this since it has to wait for the other tests.
|
# We don't need more than this since it has to wait for the other tests.
|
||||||
shard: [
|
shard: [
|
||||||
1/4, 2/4, 3/4, 4/4,
|
1/4, 2/4, 3/4, 4/4,
|
||||||
profiled,
|
|
||||||
]
|
]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
@@ -92,79 +91,17 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
if: matrix.shard != 'profiled'
|
|
||||||
env:
|
env:
|
||||||
SHARD: ${{ matrix.shard }}
|
SHARD: ${{ matrix.shard }}
|
||||||
CGO_ENABLED: 0
|
|
||||||
SKIP_PACKAGES: |-
|
|
||||||
pkg/tests/apis/folder
|
|
||||||
pkg/tests/apis/dashboard
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# Build regex pattern like: pkg1$|pkg2$|pkg3$
|
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)"
|
||||||
SKIP_PATTERN=$(echo "$SKIP_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -)
|
CGO_ENABLED=0 go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N "$SHARD" -d - | grep -Ev "($SKIP_PATTERN)")"
|
|
||||||
go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
|
||||||
- name: Run profiled tests
|
|
||||||
id: run-profiled-tests
|
|
||||||
if: matrix.shard == 'profiled'
|
|
||||||
env:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
PROFILED_PACKAGES: |-
|
|
||||||
pkg/tests/apis/folder
|
|
||||||
pkg/tests/apis/dashboard
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
# Build regex pattern line: pkg1$|pkg2$|pkg3$
|
|
||||||
PROFILE_PATTERN=$(echo "$PROFILED_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -)
|
|
||||||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | grep -E "($PROFILE_PATTERN)")"
|
|
||||||
if [ ${#PACKAGES[@]} -eq 0 ]; then
|
|
||||||
echo "⚠️ No profiled packages found"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
mkdir -p profiles
|
|
||||||
EXIT_CODE=0
|
|
||||||
# Run each profiled package sequentially
|
|
||||||
for full_pkg in "${PACKAGES[@]}"; do
|
|
||||||
# Build valid file name
|
|
||||||
pkg_name=$(basename "$full_pkg" | tr '/' '_' | tr '.' '_')
|
|
||||||
echo "📦 Running $full_pkg"
|
|
||||||
set +e
|
|
||||||
go test -tags=sqlite -timeout=8m -run '^TestIntegration' \
|
|
||||||
-outputdir=profiles \
|
|
||||||
-cpuprofile="cpu_${pkg_name}.prof" \
|
|
||||||
-memprofile="mem_${pkg_name}.prof" \
|
|
||||||
-trace="trace_${pkg_name}.out" \
|
|
||||||
"$full_pkg" 2>&1 | tee "profiles/test_${pkg_name}.log"
|
|
||||||
TEST_EXIT=$?
|
|
||||||
set -e
|
|
||||||
if [ $TEST_EXIT -ne 0 ]; then
|
|
||||||
echo "❌ $full_pkg failed with exit code $TEST_EXIT"
|
|
||||||
EXIT_CODE=1
|
|
||||||
else
|
|
||||||
echo "✅ $full_pkg passed"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
# Set output for artifact upload
|
|
||||||
if [ $EXIT_CODE -ne 0 ]; then
|
|
||||||
echo "upload_artifacts=true" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "upload_artifacts=false" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
exit $EXIT_CODE
|
|
||||||
- name: Output test profiles and traces
|
|
||||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4
|
|
||||||
if: matrix.shard == 'profiled' && !cancelled() && steps.run-profiled-tests.outputs.upload_artifacts == 'true'
|
|
||||||
with:
|
|
||||||
name: integration-test-profiles-sqlite-nocgo-${{ github.run_number }}
|
|
||||||
path: profiles/
|
|
||||||
retention-days: 7
|
|
||||||
if-no-files-found: ignore
|
|
||||||
mysql:
|
mysql:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.changed == 'true'
|
if: needs.detect-changes.outputs.changed == 'true'
|
||||||
@@ -202,7 +139,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
@@ -251,7 +188,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: ${{ inputs.name }}
|
name: ${{ inputs.name }}
|
||||||
pattern: ${{ inputs.pattern }}
|
pattern: ${{ inputs.pattern }}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Setup Go"
|
- name: "Setup Go"
|
||||||
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
|
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Setup Go"
|
- name: "Setup Go"
|
||||||
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
|
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
@@ -156,16 +156,16 @@ jobs:
|
|||||||
artifacts: targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6
|
artifacts: targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6
|
||||||
verify: true
|
verify: true
|
||||||
- name: windows-amd64
|
- name: windows-amd64
|
||||||
artifacts: targz:grafana:windows/amd64:nocgo,zip:grafana:windows/amd64:nocgo,msi:grafana:windows/amd64:nocgo
|
artifacts: targz:grafana:windows/amd64,zip:grafana:windows/amd64,msi:grafana:windows/amd64
|
||||||
verify: true
|
verify: true
|
||||||
- name: windows-arm64
|
- name: windows-arm64
|
||||||
artifacts: targz:grafana:windows/arm64:nocgo,zip:grafana:windows/arm64:nocgo
|
artifacts: targz:grafana:windows/arm64,zip:grafana:windows/arm64
|
||||||
verify: true
|
verify: true
|
||||||
- name: darwin-amd64
|
- name: darwin-amd64
|
||||||
artifacts: targz:grafana:darwin/amd64:nocgo
|
artifacts: targz:grafana:darwin/amd64
|
||||||
verify: true
|
verify: true
|
||||||
- name: darwin-arm64
|
- name: darwin-arm64
|
||||||
artifacts: targz:grafana:darwin/arm64:nocgo
|
artifacts: targz:grafana:darwin/arm64
|
||||||
verify: true
|
verify: true
|
||||||
steps:
|
steps:
|
||||||
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
||||||
@@ -187,12 +187,12 @@ jobs:
|
|||||||
output: artifacts-${{ matrix.name }}.txt
|
output: artifacts-${{ matrix.name }}.txt
|
||||||
verify: ${{ matrix.verify }}
|
verify: ${{ matrix.verify }}
|
||||||
build-id: ${{ github.run_id }}
|
build-id: ${{ github.run_id }}
|
||||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-${{ matrix.name }}
|
name: artifacts-list-${{ matrix.name }}
|
||||||
path: ${{ steps.build.outputs.file }}
|
path: ${{ steps.build.outputs.file }}
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||||
with:
|
with:
|
||||||
name: artifacts-${{ matrix.name }}
|
name: artifacts-${{ matrix.name }}
|
||||||
path: ${{ steps.build.outputs.dist-dir }}
|
path: ${{ steps.build.outputs.dist-dir }}
|
||||||
@@ -212,7 +212,6 @@ jobs:
|
|||||||
run-id: ${{ github.run_id }}
|
run-id: ${{ github.run_id }}
|
||||||
bucket-path: ${{ needs.setup.outputs.version }}_${{ github.run_id }}
|
bucket-path: ${{ needs.setup.outputs.version }}_${{ github.run_id }}
|
||||||
environment: prod
|
environment: prod
|
||||||
runs-on: ubuntu-x64-small
|
|
||||||
|
|
||||||
publish-dockerhub:
|
publish-dockerhub:
|
||||||
if: github.ref_name == 'main'
|
if: github.ref_name == 'main'
|
||||||
@@ -225,27 +224,27 @@ jobs:
|
|||||||
- build
|
- build
|
||||||
steps:
|
steps:
|
||||||
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-linux-amd64
|
name: artifacts-list-linux-amd64
|
||||||
path: .
|
path: .
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-linux-arm64
|
name: artifacts-list-linux-arm64
|
||||||
path: .
|
path: .
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-linux-armv7
|
name: artifacts-list-linux-armv7
|
||||||
path: .
|
path: .
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: artifacts-linux-amd64
|
name: artifacts-linux-amd64
|
||||||
path: dist
|
path: dist
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: artifacts-linux-arm64
|
name: artifacts-linux-arm64
|
||||||
path: dist
|
path: dist
|
||||||
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||||
with:
|
with:
|
||||||
name: artifacts-linux-armv7
|
name: artifacts-linux-armv7
|
||||||
path: dist
|
path: dist
|
||||||
@@ -321,29 +320,20 @@ jobs:
|
|||||||
repositories: '["grafana"]'
|
repositories: '["grafana"]'
|
||||||
permissions: '{"issues": "write", "pull_requests": "write", "contents": "read"}'
|
permissions: '{"issues": "write", "pull_requests": "write", "contents": "read"}'
|
||||||
- name: Find PR
|
- name: Find PR
|
||||||
continue-on-error: true
|
|
||||||
id: find-pr
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
|
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||||
GRAFANA_COMMIT: ${{ needs.setup.outputs.grafana-commit }}
|
GRAFANA_COMMIT: ${{ needs.setup.outputs.grafana-commit }}
|
||||||
REPO: ${{ github.repository }}
|
run: echo "ISSUE_NUMBER=$(gh api "/repos/grafana/grafana/commits/${GRAFANA_COMMIT}/pulls" | jq -r '.[0].number')" >> "$GITHUB_ENV"
|
||||||
run: |
|
|
||||||
set -eo pipefail
|
|
||||||
gh api "/repos/${REPO}/commits/${GRAFANA_COMMIT}/pulls" | jq -r '.[0].number' | tee issue_number.txt
|
|
||||||
echo "ISSUE_NUMBER=$(cat issue_number.txt)" >> "$GITHUB_ENV"
|
|
||||||
- name: Find Comment
|
- name: Find Comment
|
||||||
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
|
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
|
||||||
if: ${{ steps.find-pr.outcome == 'success' }}
|
|
||||||
id: fc
|
id: fc
|
||||||
continue-on-error: true
|
|
||||||
with:
|
with:
|
||||||
issue-number: ${{ env.ISSUE_NUMBER }}
|
issue-number: ${{ env.ISSUE_NUMBER }}
|
||||||
comment-author: 'grafana-delivery-bot[bot]'
|
comment-author: 'grafana-delivery-bot[bot]'
|
||||||
body-includes: GitHub Actions Build
|
body-includes: GitHub Actions Build
|
||||||
token: ${{ steps.generate_token.outputs.token }}
|
token: ${{ steps.generate_token.outputs.token }}
|
||||||
- name: Create or update comment
|
- name: Create or update comment
|
||||||
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v4
|
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||||
if: ${{ steps.find-pr.outcome == 'success' }} # Run even if comment wasn't found
|
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.generate_token.outputs.token }}
|
token: ${{ steps.generate_token.outputs.token }}
|
||||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
echo "github.ref: $GITHUB_REF"
|
echo "github.ref: $GITHUB_REF"
|
||||||
|
|
||||||
- name: Checkout workflow ref
|
- name: Checkout workflow ref
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-depth: 100
|
fetch-depth: 100
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Checkout build commit
|
- name: Checkout build commit
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
ref: ${{ inputs.grafana_commit }}
|
ref: ${{ inputs.grafana_commit }}
|
||||||
@@ -123,6 +123,11 @@ jobs:
|
|||||||
- name: Validate packages
|
- name: Validate packages
|
||||||
run: ./scripts/validate-npm-packages.sh
|
run: ./scripts/validate-npm-packages.sh
|
||||||
|
|
||||||
|
- name: Debug OIDC Claims
|
||||||
|
uses: github/actions-oidc-debugger@2e9ba5d3f4bebaad1f91a2cede055115738b7ae8
|
||||||
|
with:
|
||||||
|
audience: '${{ github.server_url }}/${{ github.repository_owner }}'
|
||||||
|
|
||||||
- name: Publish packages
|
- name: Publish packages
|
||||||
env:
|
env:
|
||||||
NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }}
|
NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }}
|
||||||
|
|||||||
@@ -133,10 +133,10 @@ jobs:
|
|||||||
path: .grafana-main
|
path: .grafana-main
|
||||||
|
|
||||||
- name: Setup nodejs environment
|
- name: Setup nodejs environment
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
- uses: actions/setup-go@v6.0.0
|
- uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Configure git user
|
- name: Configure git user
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Pin Go version to mod file
|
- name: Pin Go version to mod file
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
cache: true
|
cache: true
|
||||||
- run: go version
|
- run: go version
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Pin Go version to mod file
|
- name: Pin Go version to mod file
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
- run: go version
|
- run: go version
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v10
|
- uses: actions/stale@v9
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
operations-per-run: 750
|
operations-per-run: 750
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.changed == 'true'
|
if: needs.detect-changes.outputs.changed == 'true'
|
||||||
name: "Run Storybook a11y tests (light theme)"
|
name: "Run Storybook a11y tests"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
package-manager-cache: false # too large for GH's cache limits :-(
|
package-manager-cache: false # too large for GH's cache limits :-(
|
||||||
@@ -64,12 +64,12 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.changed == 'true'
|
if: needs.detect-changes.outputs.changed == 'true'
|
||||||
name: "Run Storybook a11y tests (dark theme)"
|
name: "Run Storybook a11y tests"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
package-manager-cache: false # too large for GH's cache limits :-(
|
package-manager-cache: false # too large for GH's cache limits :-(
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6.0.0
|
uses: actions/setup-go@v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Setup Enterprise
|
- name: Setup Enterprise
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install Trivy
|
- name: Install Trivy
|
||||||
uses: aquasecurity/setup-trivy@e6c2c5e321ed9123bda567646e2f96565e34abe1
|
uses: aquasecurity/setup-trivy@9ea583eb67910444b1f64abf338bd2e105a0a93d
|
||||||
with:
|
with:
|
||||||
version: v0.56.2
|
version: v0.56.2
|
||||||
cache: true
|
cache: true
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
.
|
.
|
||||||
if: always() && github.repository == 'grafana/grafana'
|
if: always() && github.repository == 'grafana/grafana'
|
||||||
- name: Upload Trivy scan results to GitHub Security tab
|
- name: Upload Trivy scan results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@v4
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
with:
|
with:
|
||||||
sarif_file: 'trivy-results.sarif'
|
sarif_file: 'trivy-results.sarif'
|
||||||
if: always() && github.repository == 'grafana/grafana'
|
if: always() && github.repository == 'grafana/grafana'
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }}
|
fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }}
|
||||||
- name: Trufflehog
|
- name: Trufflehog
|
||||||
uses: trufflesecurity/trufflehog@b84c3d14d189e16da175e2c27fa8136603783ffc # v3.90.12
|
uses: trufflesecurity/trufflehog@e88e7d019eb84ca64f6b768c82eb6bf1a6271401 # v3.90.9
|
||||||
with:
|
with:
|
||||||
extra_args: --results=verified
|
extra_args: --results=verified
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ jobs:
|
|||||||
bundle-schema-types:
|
bundle-schema-types:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: grafana/plugin-actions/bundle-schema-types@main
|
- uses: grafana/plugin-actions/bundle-schema-types@main
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Setup Go"
|
- name: "Setup Go"
|
||||||
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
|
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
+1
-6
@@ -71,7 +71,6 @@ public/css/*.min.css
|
|||||||
.vs/
|
.vs/
|
||||||
.cursor/
|
.cursor/
|
||||||
.devcontainer/
|
.devcontainer/
|
||||||
.claude/
|
|
||||||
|
|
||||||
.eslintcache
|
.eslintcache
|
||||||
.stylelintcache
|
.stylelintcache
|
||||||
@@ -166,7 +165,6 @@ pkg/services/quota/quotaimpl/storage/storage.json
|
|||||||
/packages/grafana-ui/.yarn/.cache
|
/packages/grafana-ui/.yarn/.cache
|
||||||
/packages/grafana-ui/.storybook/static
|
/packages/grafana-ui/.storybook/static
|
||||||
/packages/grafana-ui/unstable
|
/packages/grafana-ui/unstable
|
||||||
/packages/grafana-flamegraph/.storybook/static
|
|
||||||
/packages/**/dist
|
/packages/**/dist
|
||||||
/packages/**/compiled
|
/packages/**/compiled
|
||||||
/packages/**/.rpt2_cache
|
/packages/**/.rpt2_cache
|
||||||
@@ -252,12 +250,9 @@ public/mockServiceWorker.js
|
|||||||
/e2e-playwright/test-plugins/*/dist
|
/e2e-playwright/test-plugins/*/dist
|
||||||
/apps/provisioning/cmd/job-controller/bin/
|
/apps/provisioning/cmd/job-controller/bin/
|
||||||
|
|
||||||
|
|
||||||
# Ignore unified storage kv store files
|
# Ignore unified storage kv store files
|
||||||
/grafana-kv-data
|
/grafana-kv-data
|
||||||
|
|
||||||
# Ignore debug output from test library
|
|
||||||
/pkg/storage/secret/metadata/testdata/rapid/TestStateMachine/
|
|
||||||
|
|
||||||
/codeowners-manifest/
|
/codeowners-manifest/
|
||||||
|
|
||||||
# Ignore grafana/hippocampus local cache folder
|
# Ignore grafana/hippocampus local cache folder
|
||||||
|
|||||||
+2
-6
@@ -83,7 +83,7 @@ linters:
|
|||||||
deny:
|
deny:
|
||||||
- pkg: github.com/grafana/grafana/pkg
|
- pkg: github.com/grafana/grafana/pkg
|
||||||
desc: apps/playlist is not allowed to import grafana core
|
desc: apps/playlist is not allowed to import grafana core
|
||||||
apps-secret:
|
apps-secret:
|
||||||
list-mode: lax
|
list-mode: lax
|
||||||
files:
|
files:
|
||||||
- ./apps/secret/*
|
- ./apps/secret/*
|
||||||
@@ -105,8 +105,6 @@ linters:
|
|||||||
- '**/pkg/tsdb/graphite/**/*'
|
- '**/pkg/tsdb/graphite/**/*'
|
||||||
- '**/pkg/tsdb/mysql/*'
|
- '**/pkg/tsdb/mysql/*'
|
||||||
- '**/pkg/tsdb/mysql/**/*'
|
- '**/pkg/tsdb/mysql/**/*'
|
||||||
- '**/pkg/tsdb/opentsdb/*'
|
|
||||||
- '**/pkg/tsdb/opentsdb/**/*'
|
|
||||||
- '**/pkg/tsdb/parca/*'
|
- '**/pkg/tsdb/parca/*'
|
||||||
- '**/pkg/tsdb/parca/**/*'
|
- '**/pkg/tsdb/parca/**/*'
|
||||||
- '**/pkg/tsdb/tempo/*'
|
- '**/pkg/tsdb/tempo/*'
|
||||||
@@ -181,9 +179,7 @@ linters:
|
|||||||
- pkg: io/ioutil
|
- pkg: io/ioutil
|
||||||
desc: 'Deprecated: As of Go 1.16, the same functionality is now provided by package io or package os, and those implementations should be preferred in new code. See the specific function documentation for details.'
|
desc: 'Deprecated: As of Go 1.16, the same functionality is now provided by package io or package os, and those implementations should be preferred in new code. See the specific function documentation for details.'
|
||||||
- pkg: gopkg.in/yaml.v2
|
- pkg: gopkg.in/yaml.v2
|
||||||
desc: use go.yaml.in/yaml/v3 instead
|
desc: Grafana packages are not allowed to depend on gopkg.in/yaml.v2 as gopkg.in/yaml.v3 is now available
|
||||||
- pkg: gopkg.in/yaml.v3
|
|
||||||
desc: use go.yaml.in/yaml/v3 instead
|
|
||||||
- pkg: github.com/pkg/errors
|
- pkg: github.com/pkg/errors
|
||||||
desc: 'Deprecated: Go 1.13 supports the functionality provided by pkg/errors in the standard library.'
|
desc: 'Deprecated: Go 1.13 supports the functionality provided by pkg/errors in the standard library.'
|
||||||
- pkg: github.com/xorcare/pointer
|
- pkg: github.com/xorcare/pointer
|
||||||
|
|||||||
+328
-328
File diff suppressed because one or more lines are too long
+1
-1
@@ -25,6 +25,6 @@ plugins:
|
|||||||
path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs
|
path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs
|
||||||
spec: "https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.15.0/bundles/@yarnpkg/plugin-licenses.js"
|
spec: "https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.15.0/bundles/@yarnpkg/plugin-licenses.js"
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.11.0.cjs
|
yarnPath: .yarn/releases/yarn-4.9.4.cjs
|
||||||
|
|
||||||
enableScripts: false
|
enableScripts: false
|
||||||
|
|||||||
-337
@@ -1,340 +1,3 @@
|
|||||||
<!-- 12.3.0 START -->
|
|
||||||
|
|
||||||
# 12.3.0 (2025-11-19)
|
|
||||||
|
|
||||||
### Features and enhancements
|
|
||||||
|
|
||||||
- **API Clients:** Add lazy hooks to clients [#113226](https://github.com/grafana/grafana/pull/113226), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **API clients:** Automatically set PATCH headers [#111879](https://github.com/grafana/grafana/pull/111879), [@Clarity-89](https://github.com/Clarity-89)
|
|
||||||
- **API clients:** Extract into a package [#111810](https://github.com/grafana/grafana/pull/111810), [@Clarity-89](https://github.com/Clarity-89)
|
|
||||||
- **API clients:** Extract into a package (Enterprise)
|
|
||||||
- **API clients:** Update API clients to include all endpoints & add hooks [#113061](https://github.com/grafana/grafana/pull/113061), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **AccessControl:** Include hidden roles in service account role display [#112924](https://github.com/grafana/grafana/pull/112924), [@Jguer](https://github.com/Jguer)
|
|
||||||
- **AccessControl:** Increase limit of LBAC for Datasources rules [#111560](https://github.com/grafana/grafana/pull/111560), [@Jguer](https://github.com/Jguer)
|
|
||||||
- **Accessibility:** Wrap data source info onto 2 lines at small viewports [#113033](https://github.com/grafana/grafana/pull/113033), [@ashharrison90](https://github.com/ashharrison90)
|
|
||||||
- **Alert Enrichment:** Add mutator to insert rule UID labels to allow for efficient use of labelSelector (Enterprise)
|
|
||||||
- **Alerting:** Add enrichment components to rule view page (Enterprise)
|
|
||||||
- **Alerting:** Add enrichment section to rule view page (Enterprise)
|
|
||||||
- **Alerting:** Add jitter support for periodic alert state storage to reduce database load spikes [#111357](https://github.com/grafana/grafana/pull/111357), [@softho0n](https://github.com/softho0n)
|
|
||||||
- **Alerting:** Add position-based matching for identical alert rules [#112407](https://github.com/grafana/grafana/pull/112407), [@konrad147](https://github.com/konrad147)
|
|
||||||
- **Alerting:** Create alertingAlertRuleFormSchema in restrictedGrafanaApis [#112794](https://github.com/grafana/grafana/pull/112794), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
|
|
||||||
- **Alerting:** Display error message in central state history view [#111445](https://github.com/grafana/grafana/pull/111445), [@laurenashleigh](https://github.com/laurenashleigh)
|
|
||||||
- **Alerting:** Enrichment per rule wip-2 (Enterprise)
|
|
||||||
- **Alerting:** Hide metadata if grouping by folder [#113216](https://github.com/grafana/grafana/pull/113216), [@laurenashleigh](https://github.com/laurenashleigh)
|
|
||||||
- **Alerting:** Improve template ai helper prompt and add some examples (Enterprise)
|
|
||||||
- **Alerting:** Move enrichment tab between details and versions [#110886](https://github.com/grafana/grafana/pull/110886), [@laurenashleigh](https://github.com/laurenashleigh)
|
|
||||||
- **Alerting:** Remove ai feedback button from alert form [#112713](https://github.com/grafana/grafana/pull/112713), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
|
|
||||||
- **Alerting:** Remove unused components [#111320](https://github.com/grafana/grafana/pull/111320), [@laurenashleigh](https://github.com/laurenashleigh)
|
|
||||||
- **Alerting:** Remove useRulesSourcesWithRuler for SmartAlertTypeDetector [#111623](https://github.com/grafana/grafana/pull/111623), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
|
|
||||||
- **Alerting:** Surface remote AM silence creation errors properly [#112757](https://github.com/grafana/grafana/pull/112757), [@moustafab](https://github.com/moustafab)
|
|
||||||
- **Alerting:** Triage [#110339](https://github.com/grafana/grafana/pull/110339), [@gillesdemey](https://github.com/gillesdemey)
|
|
||||||
- **Alerting:** Triage rule details drawer [#112055](https://github.com/grafana/grafana/pull/112055), [@konrad147](https://github.com/konrad147)
|
|
||||||
- **Alerting:** Update prompt examples for template AI Helper (Enterprise)
|
|
||||||
- **Alerting:** Update width to instance details drawer in Triage page [#113209](https://github.com/grafana/grafana/pull/113209), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
|
|
||||||
- **Alerting:** Use new enrichment endpoints in FE (Enterprise)
|
|
||||||
- **Alerting:** Use ruleUid as a prop instead of extracting it from the rule context (Enterprise)
|
|
||||||
- **Analytics:** Aggregate daily summary in datasources analytics (Enterprise)
|
|
||||||
- **Analytics:** Apply proper batching to Loki exports and add configurable settings (Enterprise)
|
|
||||||
- **Annotations:** Exclude internal dashboard id when saved via UID [#111535](https://github.com/grafana/grafana/pull/111535), [@ryantxu](https://github.com/ryantxu)
|
|
||||||
- **Azure:** Use SSO settings in plugin context [#112058](https://github.com/grafana/grafana/pull/112058), [@aangelisc](https://github.com/aangelisc)
|
|
||||||
- **Buttons:** Active style for buttons [#111235](https://github.com/grafana/grafana/pull/111235), [@gtk-grafana](https://github.com/gtk-grafana)
|
|
||||||
- **Caching:** Disable cache if datasource has oauthPassThru=true (Enterprise)
|
|
||||||
- **Canvas:** Allow non-icon bg image fields [#112308](https://github.com/grafana/grafana/pull/112308), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Chore:** Add logsdrilldown replace to apps/iam/go.mod [#112581](https://github.com/grafana/grafana/pull/112581), [@njvrzm](https://github.com/njvrzm)
|
|
||||||
- **CloudWatch Logs:** Don't add console link to every field in the logs response [#112230](https://github.com/grafana/grafana/pull/112230), [@idastambuk](https://github.com/idastambuk)
|
|
||||||
- **CloudWatch Logs:** Support Log Anomalies query type [#113067](https://github.com/grafana/grafana/pull/113067), [@idastambuk](https://github.com/idastambuk)
|
|
||||||
- **CloudWatch:** Add syntax highlighting and autocomplete for logs diff command [#111207](https://github.com/grafana/grafana/pull/111207), [@kevinwcyu](https://github.com/kevinwcyu)
|
|
||||||
- **CloudWatch:** Add tracking for logs anomalies [#113181](https://github.com/grafana/grafana/pull/113181), [@idastambuk](https://github.com/idastambuk)
|
|
||||||
- **Dashboard Controls:** Add annotations to the dashboard controls menu [#112816](https://github.com/grafana/grafana/pull/112816), [@leventebalogh](https://github.com/leventebalogh)
|
|
||||||
- **Dashboard Picker:** Update to use correct search + dashboards APIs [#112341](https://github.com/grafana/grafana/pull/112341), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **Dashboard:** Backend always set `metricEditorMode: 0` regardless `metricQueryType` and `expression` [#111613](https://github.com/grafana/grafana/pull/111613), [@ivanortegaalba](https://github.com/ivanortegaalba)
|
|
||||||
- **Dashboards:** Add a new variable type called "Switch" [#111366](https://github.com/grafana/grafana/pull/111366), [@leventebalogh](https://github.com/leventebalogh)
|
|
||||||
- **Dashboards:** Hide error notifications in kiosk mode on dashboards [#112390](https://github.com/grafana/grafana/pull/112390), [@ivanortegaalba](https://github.com/ivanortegaalba)
|
|
||||||
- **Dynamic Dashboards:** Expand dashboards_init_dashboard_completed tracking info [#111102](https://github.com/grafana/grafana/pull/111102), [@idastambuk](https://github.com/idastambuk)
|
|
||||||
- **ErrorBoundary:** Report specific boundary type to Faro [#112071](https://github.com/grafana/grafana/pull/112071), [@tskarhed](https://github.com/tskarhed)
|
|
||||||
- **Explore:** Use compact mode only when targeting Tempo [#113037](https://github.com/grafana/grafana/pull/113037), [@ifrost](https://github.com/ifrost)
|
|
||||||
- **FeatureToggles:** Remove deprecated experimental apiserver [#111617](https://github.com/grafana/grafana/pull/111617), [@ryantxu](https://github.com/ryantxu)
|
|
||||||
- **Fields Selector:** Add component and integrate with Logs and Logs table visualization [#112534](https://github.com/grafana/grafana/pull/112534), [@matyax](https://github.com/matyax)
|
|
||||||
- **Flame Graph:** Anchor exact match when clicking a table symbol in search [#111101](https://github.com/grafana/grafana/pull/111101), [@samarthbagga-meesho](https://github.com/samarthbagga-meesho)
|
|
||||||
- **FlameGraph:** Improve prompt for open assistant to analyze flamegraph [#113071](https://github.com/grafana/grafana/pull/113071), [@simonswine](https://github.com/simonswine)
|
|
||||||
- **FolderPicker:** Don't show expand button for empty folders and move search icon [#111872](https://github.com/grafana/grafana/pull/111872), [@aocenas](https://github.com/aocenas)
|
|
||||||
- **FolderPicker:** Show parent folder when searching [#111026](https://github.com/grafana/grafana/pull/111026), [@aocenas](https://github.com/aocenas)
|
|
||||||
- **Geomap:** Add a MapLibre style base layer [#109841](https://github.com/grafana/grafana/pull/109841), [@remogeissbuehler](https://github.com/remogeissbuehler)
|
|
||||||
- **Geomap:** Move beta layers to GA [#113186](https://github.com/grafana/grafana/pull/113186), [@drew08t](https://github.com/drew08t)
|
|
||||||
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112149](https://github.com/grafana/grafana/pull/112149), [@macabu](https://github.com/macabu)
|
|
||||||
- **Go:** Update to 1.25.3 [#112359](https://github.com/grafana/grafana/pull/112359), [@macabu](https://github.com/macabu)
|
|
||||||
- **Grafana Advisor:** Prometheus Type Migration check [#110853](https://github.com/grafana/grafana/pull/110853), [@bossinc](https://github.com/bossinc)
|
|
||||||
- **Grafana Data Source:** Add random walk configuration options [#113009](https://github.com/grafana/grafana/pull/113009), [@nmarrs](https://github.com/nmarrs)
|
|
||||||
- **IAM:** Add uid column in team_member DB table [#112439](https://github.com/grafana/grafana/pull/112439), [@dmihai](https://github.com/dmihai)
|
|
||||||
- **Jaeger:** Migrate API calls to gRPC endpoint [#113297](https://github.com/grafana/grafana/pull/113297), [@jcolladokuri](https://github.com/jcolladokuri)
|
|
||||||
- **LBAC for data sources:** Provide user feedback of potential performance loss from LBAC rules (Enterprise)
|
|
||||||
- **Library Panels:** Remove direct use of legacy search [#112231](https://github.com/grafana/grafana/pull/112231), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **Logs panel:** Respect selected fields for downloading logs [#111753](https://github.com/grafana/grafana/pull/111753), [@matyax](https://github.com/matyax)
|
|
||||||
- **Nav:** Render menu items as `p` tags so truncation logic can work [#113248](https://github.com/grafana/grafana/pull/113248), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **Navigation:** Move Cost management and billing plugin to root [#111739](https://github.com/grafana/grafana/pull/111739), [@gubjanos](https://github.com/gubjanos)
|
|
||||||
- **PanelTimeCompare:** Support saving time compare window [#113150](https://github.com/grafana/grafana/pull/113150), [@torkelo](https://github.com/torkelo)
|
|
||||||
- **PanelTimeSettings:** Support panel time range settings changes from dashboard in view mode [#113027](https://github.com/grafana/grafana/pull/113027), [@torkelo](https://github.com/torkelo)
|
|
||||||
- **Plugins:** Install Grafana Pathfinder behind a feature flag [#109909](https://github.com/grafana/grafana/pull/109909), [@Jayclifford345](https://github.com/Jayclifford345)
|
|
||||||
- **PostgreSQL:** Support PGPASSFILE by making password optional [#108856](https://github.com/grafana/grafana/pull/108856), [@taraspos](https://github.com/taraspos)
|
|
||||||
- **Provisioning:** Watch file system for changes [#112184](https://github.com/grafana/grafana/pull/112184), [@ryantxu](https://github.com/ryantxu)
|
|
||||||
- **Reporting:** Add support for schema v2 dashboards (Enterprise)
|
|
||||||
- **Reporting:** Wait for streaming to end before exporting CSVs (Enterprise)
|
|
||||||
- **SQL Expressions:** Add Functions to Allow list [#113291](https://github.com/grafana/grafana/pull/113291), [@kylebrandt](https://github.com/kylebrandt)
|
|
||||||
- **Snapshots:** Use appSubUrl for View all snapshots [#111652](https://github.com/grafana/grafana/pull/111652), [@Clarity-89](https://github.com/Clarity-89)
|
|
||||||
- **Span Details:** Bring back span id to span details [#112411](https://github.com/grafana/grafana/pull/112411), [@ifrost](https://github.com/ifrost)
|
|
||||||
- **Span Details:** Wrap label values [#112413](https://github.com/grafana/grafana/pull/112413), [@ifrost](https://github.com/ifrost)
|
|
||||||
- **Stars:** Refactor StarsToolbarButton and unify nav update logic [#112582](https://github.com/grafana/grafana/pull/112582), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **Stat/BarGauge:** Border radius tweak [#112562](https://github.com/grafana/grafana/pull/112562), [@torkelo](https://github.com/torkelo)
|
|
||||||
- **Table:** Add some error-case handling to ImageCell [#110461](https://github.com/grafana/grafana/pull/110461), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Table:** Allow FieldType.other containing arrays to use Pills [#111205](https://github.com/grafana/grafana/pull/111205), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Table:** Disable virtualization, hover overflow, and scrollbar width resizing on Safari 26 [#111834](https://github.com/grafana/grafana/pull/111834), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Table:** Pill and JSON Cells should allow formatting [#111951](https://github.com/grafana/grafana/pull/111951), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Table:** Support DataLinks and Actions in SparklineCell [#112244](https://github.com/grafana/grafana/pull/112244), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Table:** Update ad-hoc filter to use name instead of displayName [#112815](https://github.com/grafana/grafana/pull/112815), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Tempo:** Migrates tags and tag values to datasource backend CallResource requests (Enterprise)
|
|
||||||
- **Theme:** Changes light theme canvas color a more white shade [#111318](https://github.com/grafana/grafana/pull/111318), [@torkelo](https://github.com/torkelo)
|
|
||||||
- **Themes:** Update themes border radius [#111478](https://github.com/grafana/grafana/pull/111478), [@torkelo](https://github.com/torkelo)
|
|
||||||
- **TimeComparison:** Automatically show/hide menu on hover [#112750](https://github.com/grafana/grafana/pull/112750), [@jesdavpet](https://github.com/jesdavpet)
|
|
||||||
- **TimeSeries:** Allow custom time units on x-axis [#112913](https://github.com/grafana/grafana/pull/112913), [@leeoniya](https://github.com/leeoniya)
|
|
||||||
- **Timeseries:** Numeric duration values could render as NaN (#73795) [#112076](https://github.com/grafana/grafana/pull/112076), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Transformations:** Hide "Match all/any" conditions for less than two filters [#109754](https://github.com/grafana/grafana/pull/109754), [@sudoice](https://github.com/sudoice)
|
|
||||||
- **UI Extensions:** Remove path validation from link extensions [#112259](https://github.com/grafana/grafana/pull/112259), [@leventebalogh](https://github.com/leventebalogh)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Access Control:** Fix the permission checks for saving/updating/deleting annotations [#112953](https://github.com/grafana/grafana/pull/112953), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
|
|
||||||
- **Accessibility:** Improve no-unreduced-motion rule and fix violations [#110304](https://github.com/grafana/grafana/pull/110304), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **Alerting Provisioning:** Don't error on recording rules without conditions [#109410](https://github.com/grafana/grafana/pull/109410), [@djpnicholls](https://github.com/djpnicholls)
|
|
||||||
- **Alerting:** Clear outdated settings when switching contact point type [#111869](https://github.com/grafana/grafana/pull/111869), [@konrad147](https://github.com/konrad147)
|
|
||||||
- **Alerting:** Fix enrichment tab to be rendered only for grafana alerting rules [#113030](https://github.com/grafana/grafana/pull/113030), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
|
|
||||||
- **Alerting:** Fix instances matching in notification policies [#112326](https://github.com/grafana/grafana/pull/112326), [@konrad147](https://github.com/konrad147)
|
|
||||||
- **Alerting:** Fix threshold params [#111645](https://github.com/grafana/grafana/pull/111645), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
|
|
||||||
- **Alerting:** Fix unmarshalling of GettableStatus to include time intervals [#112602](https://github.com/grafana/grafana/pull/112602), [@yuri-tceretian](https://github.com/yuri-tceretian)
|
|
||||||
- **Alerting:** Migrate `spec.title` and `spec.name` fieldSelectors [#111993](https://github.com/grafana/grafana/pull/111993), [@gillesdemey](https://github.com/gillesdemey)
|
|
||||||
- **Alerting:** Normalize health when filtering rules [#113087](https://github.com/grafana/grafana/pull/113087), [@gillesdemey](https://github.com/gillesdemey)
|
|
||||||
- **Alerting:** Prohibit receivers with empty name [#113064](https://github.com/grafana/grafana/pull/113064), [@yuri-tceretian](https://github.com/yuri-tceretian)
|
|
||||||
- **Alerting:** Provisioning to fix contact point type on save [#112246](https://github.com/grafana/grafana/pull/112246), [@yuri-tceretian](https://github.com/yuri-tceretian)
|
|
||||||
- **Alerting:** Remove \_\_grafana_origin when duplicating rule [#112396](https://github.com/grafana/grafana/pull/112396), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
|
|
||||||
- **AnnoList:** Fix annotations not loading when in a repeated row [#111540](https://github.com/grafana/grafana/pull/111540), [@joshhunt](https://github.com/joshhunt)
|
|
||||||
- **Annotations:** Fix issue with transformation logic in scenes [#112288](https://github.com/grafana/grafana/pull/112288), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Auth:** Fix render user OAuth passthrough [#111636](https://github.com/grafana/grafana/pull/111636), [@charandas](https://github.com/charandas)
|
|
||||||
- **ComboBox:** Add loading state to dropdown and prefixIcon [#112967](https://github.com/grafana/grafana/pull/112967), [@tomratcliffe](https://github.com/tomratcliffe)
|
|
||||||
- **Connections:** Fix connections home page on enterprise [#111751](https://github.com/grafana/grafana/pull/111751), [@oshirohugo](https://github.com/oshirohugo)
|
|
||||||
- **Dashboard:** Fix editor specific permissions in /api [#113292](https://github.com/grafana/grafana/pull/113292), [@stephaniehingtgen](https://github.com/stephaniehingtgen)
|
|
||||||
- **Dashboards:** Fix bug with anon users with editor permissions creating dashboards [#113260](https://github.com/grafana/grafana/pull/113260), [@stephaniehingtgen](https://github.com/stephaniehingtgen)
|
|
||||||
- **Dashboards:** Fix missing Ctrl+O keyboard shortcut for crosshair toggle [#111310](https://github.com/grafana/grafana/pull/111310), [@ivanortegaalba](https://github.com/ivanortegaalba)
|
|
||||||
- **Dashboards:** Fix moving to root folder [#111515](https://github.com/grafana/grafana/pull/111515), [@stephaniehingtgen](https://github.com/stephaniehingtgen)
|
|
||||||
- **Dashboards:** Fix preload field not being persisted via /v1beta1 [#112475](https://github.com/grafana/grafana/pull/112475), [@ivanortegaalba](https://github.com/ivanortegaalba)
|
|
||||||
- **Flame Graph:** Use suffix for values formatted with a short formatter [#110999](https://github.com/grafana/grafana/pull/110999), [@ifrost](https://github.com/ifrost)
|
|
||||||
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111548](https://github.com/grafana/grafana/pull/111548), [@simonswine](https://github.com/simonswine)
|
|
||||||
- **FolderPermissions:** Return 404 error when folder does not exist instead of 500 [#112919](https://github.com/grafana/grafana/pull/112919), [@Jguer](https://github.com/Jguer)
|
|
||||||
- **FolderPicker:** Fix expand toggle also selecting folder [#111755](https://github.com/grafana/grafana/pull/111755), [@aocenas](https://github.com/aocenas)
|
|
||||||
- **Graphite:** Fix legacy response unmarshalling [#112968](https://github.com/grafana/grafana/pull/112968), [@aangelisc](https://github.com/aangelisc)
|
|
||||||
- **Histogram:** Properly handle sparse heatmap-cells frames [#112907](https://github.com/grafana/grafana/pull/112907), [@leeoniya](https://github.com/leeoniya)
|
|
||||||
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111723](https://github.com/grafana/grafana/pull/111723), [@bradleypettit](https://github.com/bradleypettit)
|
|
||||||
- **Node graph:** Fix context menu position after scrolling [#112374](https://github.com/grafana/grafana/pull/112374), [@adrapereira](https://github.com/adrapereira)
|
|
||||||
- **Playlist:** Fix navigation issues with emoji-titled dashboards during dual-write migration [#111659](https://github.com/grafana/grafana/pull/111659), [@axelavargas](https://github.com/axelavargas)
|
|
||||||
- **Plugin Details Page:** Fix tabs not loading on hard refresh [#112915](https://github.com/grafana/grafana/pull/112915), [@sunker](https://github.com/sunker)
|
|
||||||
- **Plugin navigation:** Fix active nav item selection when there are more than 10 items in a group [#112886](https://github.com/grafana/grafana/pull/112886), [@aocenas](https://github.com/aocenas)
|
|
||||||
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111762](https://github.com/grafana/grafana/pull/111762), [@wbrowne](https://github.com/wbrowne)
|
|
||||||
- **Plugins:** Set isProvisioned for local plugins without remote counterpart [#111268](https://github.com/grafana/grafana/pull/111268), [@oshirohugo](https://github.com/oshirohugo)
|
|
||||||
- **Prometheus:** Fix incremental querying logic for public dashboards [#111642](https://github.com/grafana/grafana/pull/111642), [@jcolladokuri](https://github.com/jcolladokuri)
|
|
||||||
- **Prometheus:** Fix parsing logic of prometheus expressions to honor the order of binary operations [#112220](https://github.com/grafana/grafana/pull/112220), [@jcolladokuri](https://github.com/jcolladokuri)
|
|
||||||
- **Security:** fix for CVE-2025-41115 in SCIM (System for Cross-domain Identity Management) (Enterprise)
|
|
||||||
- **SoloPanel:** Fixes issue with solo route and scopes variable [#112769](https://github.com/grafana/grafana/pull/112769), [@torkelo](https://github.com/torkelo)
|
|
||||||
- **Stars:** Fix starred state not being updated [#111936](https://github.com/grafana/grafana/pull/111936), [@Clarity-89](https://github.com/Clarity-89)
|
|
||||||
- **Stat:** Fix math for percent change value heights when sparkline is not rendered [#112599](https://github.com/grafana/grafana/pull/112599), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **StateTimeline:** Fix color display in tooltip [#112878](https://github.com/grafana/grafana/pull/112878), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **Table:** Fix cell inspect for Sparkline and inferred JSON cells [#113059](https://github.com/grafana/grafana/pull/113059), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
- **TextPanel:** Fix `CodeEditor` not appearing properly [#111937](https://github.com/grafana/grafana/pull/111937), [@ashharrison90](https://github.com/ashharrison90)
|
|
||||||
- **UnitPicker/Cascader:** Fixes type to search for unit feature [#112614](https://github.com/grafana/grafana/pull/112614), [@torkelo](https://github.com/torkelo)
|
|
||||||
- **VizTooltip:** Better overflow handling on long series names [#112240](https://github.com/grafana/grafana/pull/112240), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
|
|
||||||
### Breaking changes
|
|
||||||
|
|
||||||
- **Faro:** Update configuration with best practices [#112108](https://github.com/grafana/grafana/pull/112108), [@joshhunt](https://github.com/joshhunt)
|
|
||||||
- **LibraryPanels:** Remove unique name constraints [#113077](https://github.com/grafana/grafana/pull/113077), [@ryantxu](https://github.com/ryantxu)
|
|
||||||
- **RBAC:** Only write action sets [#112429](https://github.com/grafana/grafana/pull/112429), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
|
|
||||||
|
|
||||||
### Plugin development fixes & changes
|
|
||||||
|
|
||||||
- **Checkbox:** Improve accessibility of the `indeterminate` state [#112388](https://github.com/grafana/grafana/pull/112388), [@ashharrison90](https://github.com/ashharrison90)
|
|
||||||
- **Collapse:** Improve layout and deprecate `collapsible` prop [#113164](https://github.com/grafana/grafana/pull/113164), [@ashharrison90](https://github.com/ashharrison90)
|
|
||||||
- **Docs:** Add storybook links to components [#113102](https://github.com/grafana/grafana/pull/113102), [@samsch](https://github.com/samsch)
|
|
||||||
- **Modal:** Fix button focus being clipped [#112867](https://github.com/grafana/grafana/pull/112867), [@ashharrison90](https://github.com/ashharrison90)
|
|
||||||
- **Slider:** Expose prop to control visibility of input [#113084](https://github.com/grafana/grafana/pull/113084), [@ashharrison90](https://github.com/ashharrison90)
|
|
||||||
- **Slider:** Make `inputId` a required param and fix minor a11y violations [#112006](https://github.com/grafana/grafana/pull/112006), [@ashharrison90](https://github.com/ashharrison90)
|
|
||||||
|
|
||||||
<!-- 12.3.0 END -->
|
|
||||||
<!-- 12.1.4 START -->
|
|
||||||
|
|
||||||
# 12.1.4 (2025-11-19)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Alerting:** Fix unmarshalling of GettableStatus to include time intervals [#112733](https://github.com/grafana/grafana/pull/112733), [@yuri-tceretian](https://github.com/yuri-tceretian)
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup not resetting "last X days" metrics to zero (Enterprise)
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup totals resetting incorrectly (Enterprise)
|
|
||||||
- **Security:** fix for CVE-2025-41115 in SCIM (System for Cross-domain Identity Management) (Enterprise)
|
|
||||||
|
|
||||||
<!-- 12.1.4 END -->
|
|
||||||
<!-- 12.0.7 START -->
|
|
||||||
|
|
||||||
# 12.0.7 (2025-11-19)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Alerting:** Fix unmarshalling of GettableStatus to include time intervals [#112732](https://github.com/grafana/grafana/pull/112732), [@yuri-tceretian](https://github.com/yuri-tceretian)
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup not resetting "last X days" metrics to zero (Enterprise)
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup totals resetting incorrectly (Enterprise)
|
|
||||||
- **Security:** fix for CVE-2025-41115 in SCIM (System for Cross-domain Identity Management) (Enterprise)
|
|
||||||
|
|
||||||
<!-- 12.0.7 END -->
|
|
||||||
<!-- 12.2.2 START -->
|
|
||||||
|
|
||||||
# 12.2.2 (2025-11-19)
|
|
||||||
|
|
||||||
### Features and enhancements
|
|
||||||
|
|
||||||
- **Access control:** Reduce memory usage when fetching user's permissions [#113414](https://github.com/grafana/grafana/pull/113414), [@hairyhenderson](https://github.com/hairyhenderson)
|
|
||||||
- **Table:** Pill and JSON Cells should allow formatting [#113130](https://github.com/grafana/grafana/pull/113130), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup not resetting "last X days" metrics to zero (Enterprise)
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup totals resetting incorrectly (Enterprise)
|
|
||||||
- **Security:** fix for CVE-2025-41115 in SCIM (System for Cross-domain Identity Management) (Enterprise)
|
|
||||||
|
|
||||||
<!-- 12.2.2 END -->
|
|
||||||
<!-- 11.6.8 START -->
|
|
||||||
|
|
||||||
# 11.6.8 (2025-11-19)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Alerting:** Fix unmarshalling of GettableStatus to include time intervals [#112731](https://github.com/grafana/grafana/pull/112731), [@yuri-tceretian](https://github.com/yuri-tceretian)
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup not resetting "last X days" metrics to zero (Enterprise)
|
|
||||||
- **AnalyticsSummaries:** Fix dashboard rollup totals resetting incorrectly (Enterprise)
|
|
||||||
- **Seeder:** Add check in `filterRemovedPermissions` for already existing new permissions before seeding (Enterprise)
|
|
||||||
|
|
||||||
<!-- 11.6.8 END -->
|
|
||||||
<!-- 12.2.1+security-01 START -->
|
|
||||||
|
|
||||||
# 12.2.1+security-01 (2025-11-19)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Security:** fix for CVE-2025-41115 in SCIM (System for Cross-domain Identity Management) (Enterprise)
|
|
||||||
|
|
||||||
<!-- 12.2.1+security-01 END -->
|
|
||||||
<!-- 12.1.3+security-01 START -->
|
|
||||||
|
|
||||||
# 12.1.3+security-01 (2025-11-19)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Security:** fix for CVE-2025-41115 in SCIM (System for Cross-domain Identity Management) (Enterprise)
|
|
||||||
|
|
||||||
<!-- 12.1.3+security-01 END -->
|
|
||||||
|
|
||||||
<!-- 12.0.6+security-01 START -->
|
|
||||||
|
|
||||||
# 12.0.6+security-01 (2025-11-19)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Security:** fix for CVE-2025-41115 in SCIM (System for Cross-domain Identity Management) (Enterprise)
|
|
||||||
|
|
||||||
<!-- 12.0.6+security-01 END -->
|
|
||||||
<!-- 12.2.1 START -->
|
|
||||||
|
|
||||||
# 12.2.1 (2025-10-21)
|
|
||||||
|
|
||||||
### Features and enhancements
|
|
||||||
|
|
||||||
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112156](https://github.com/grafana/grafana/pull/112156), [@macabu](https://github.com/macabu)
|
|
||||||
- **Go:** Update to 1.25.3 [#112361](https://github.com/grafana/grafana/pull/112361), [@macabu](https://github.com/macabu)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Auth:** Fix render user OAuth passthrough [#112092](https://github.com/grafana/grafana/pull/112092), [@mgyongyosi](https://github.com/mgyongyosi)
|
|
||||||
- **Dashboards:** Fix missing Ctrl+O keyboard shortcut for crosshair toggle [#111402](https://github.com/grafana/grafana/pull/111402), [@ivanortegaalba](https://github.com/ivanortegaalba)
|
|
||||||
- **Fix:** Fix redirection after login when Grafana is served from subpath [#111069](https://github.com/grafana/grafana/pull/111069), [@mgyongyosi](https://github.com/mgyongyosi)
|
|
||||||
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111606](https://github.com/grafana/grafana/pull/111606), [@simonswine](https://github.com/simonswine)
|
|
||||||
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111849](https://github.com/grafana/grafana/pull/111849), [@bradleypettit](https://github.com/bradleypettit)
|
|
||||||
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111769](https://github.com/grafana/grafana/pull/111769), [@wbrowne](https://github.com/wbrowne)
|
|
||||||
- **Table:** Backport the Safari 26 fixes to 12.2.1 [#111906](https://github.com/grafana/grafana/pull/111906), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
|
|
||||||
<!-- 12.2.1 END -->
|
|
||||||
<!-- 12.1.3 START -->
|
|
||||||
|
|
||||||
# 12.1.3 (2025-10-21)
|
|
||||||
|
|
||||||
### Features and enhancements
|
|
||||||
|
|
||||||
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112159](https://github.com/grafana/grafana/pull/112159), [@macabu](https://github.com/macabu)
|
|
||||||
- **Go:** Update to 1.25.3 [#112362](https://github.com/grafana/grafana/pull/112362), [@macabu](https://github.com/macabu)
|
|
||||||
- **Table:** Avoid thrown error due to internal React issue [#111945](https://github.com/grafana/grafana/pull/111945), [@fastfrwrd](https://github.com/fastfrwrd)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Auth:** Fix render user OAuth passthrough [#112097](https://github.com/grafana/grafana/pull/112097), [@mgyongyosi](https://github.com/mgyongyosi)
|
|
||||||
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111605](https://github.com/grafana/grafana/pull/111605), [@simonswine](https://github.com/simonswine)
|
|
||||||
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111848](https://github.com/grafana/grafana/pull/111848), [@bradleypettit](https://github.com/bradleypettit)
|
|
||||||
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111767](https://github.com/grafana/grafana/pull/111767), [@wbrowne](https://github.com/wbrowne)
|
|
||||||
|
|
||||||
<!-- 12.1.3 END -->
|
|
||||||
<!-- 12.0.6 START -->
|
|
||||||
|
|
||||||
# 12.0.6 (2025-10-21)
|
|
||||||
|
|
||||||
### Features and enhancements
|
|
||||||
|
|
||||||
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112161](https://github.com/grafana/grafana/pull/112161), [@macabu](https://github.com/macabu)
|
|
||||||
- **Go:** Update to 1.25.3 [#112364](https://github.com/grafana/grafana/pull/112364), [@macabu](https://github.com/macabu)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Auth:** Fix render user OAuth passthrough [#112096](https://github.com/grafana/grafana/pull/112096), [@mgyongyosi](https://github.com/mgyongyosi)
|
|
||||||
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111604](https://github.com/grafana/grafana/pull/111604), [@simonswine](https://github.com/simonswine)
|
|
||||||
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111847](https://github.com/grafana/grafana/pull/111847), [@bradleypettit](https://github.com/bradleypettit)
|
|
||||||
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111766](https://github.com/grafana/grafana/pull/111766), [@wbrowne](https://github.com/wbrowne)
|
|
||||||
|
|
||||||
<!-- 12.0.6 END -->
|
|
||||||
<!-- 11.6.7 START -->
|
|
||||||
|
|
||||||
# 11.6.7 (2025-10-21)
|
|
||||||
|
|
||||||
### Features and enhancements
|
|
||||||
|
|
||||||
- **Analytics:** Apply proper batching to Loki exports and add configurable settings (Enterprise)
|
|
||||||
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112162](https://github.com/grafana/grafana/pull/112162), [@grambbledook](https://github.com/grambbledook)
|
|
||||||
- **Go:** Update to 1.25.3 [#112365](https://github.com/grafana/grafana/pull/112365), [@macabu](https://github.com/macabu)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Auth:** Fix render user OAuth passthrough [#112094](https://github.com/grafana/grafana/pull/112094), [@mgyongyosi](https://github.com/mgyongyosi)
|
|
||||||
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111846](https://github.com/grafana/grafana/pull/111846), [@bradleypettit](https://github.com/bradleypettit)
|
|
||||||
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111801](https://github.com/grafana/grafana/pull/111801), [@wbrowne](https://github.com/wbrowne)
|
|
||||||
- **URLParams:** Stringify true values as key=true always (fixes issues with variables with true value) [#112045](https://github.com/grafana/grafana/pull/112045), [@torkelo](https://github.com/torkelo)
|
|
||||||
|
|
||||||
<!-- 11.6.7 END -->
|
|
||||||
<!-- 11.5.10 START -->
|
|
||||||
|
|
||||||
# 11.5.10 (2025-10-21)
|
|
||||||
|
|
||||||
### Features and enhancements
|
|
||||||
|
|
||||||
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112163](https://github.com/grafana/grafana/pull/112163), [@macabu](https://github.com/macabu)
|
|
||||||
- **Go:** Update to 1.25.3 [#112366](https://github.com/grafana/grafana/pull/112366), [@macabu](https://github.com/macabu)
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- **Auth:** Fix render user OAuth passthrough [#112093](https://github.com/grafana/grafana/pull/112093), [@mgyongyosi](https://github.com/mgyongyosi)
|
|
||||||
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111845](https://github.com/grafana/grafana/pull/111845), [@bradleypettit](https://github.com/bradleypettit)
|
|
||||||
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111802](https://github.com/grafana/grafana/pull/111802), [@wbrowne](https://github.com/wbrowne)
|
|
||||||
|
|
||||||
<!-- 11.5.10 END -->
|
|
||||||
<!-- 12.2.0 START -->
|
<!-- 12.2.0 START -->
|
||||||
|
|
||||||
# 12.2.0 (2025-09-23)
|
# 12.2.0 (2025-09-23)
|
||||||
|
|||||||
+34
-67
@@ -2,84 +2,51 @@
|
|||||||
|
|
||||||
Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md).
|
Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||||
|
|
||||||
This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute. It's designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem.
|
This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute- it’s designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem.
|
||||||
|
|
||||||
> **Help us improve!** We'd love to hear about your contributor experience. Take a moment to share your feedback in our [Open Source Contributor Experience Survey](https://gra.fan/ome). Your input helps us make contributing to Grafana better for everyone.
|
Whether you're a new contributer or a seasoned veteran we hope these resources help you connect with the community:
|
||||||
|
|
||||||
Whether you're a new contributor or a seasoned veteran, we hope these resources help you connect with the community.
|
Interact and be heard:
|
||||||
|
|
||||||
#### Interact and be heard
|
- Forums: Do you have a problem, question, or curiosity? Visit our [forums](https://gra.fan/fromgithubtoforums) for a reservoir of knowledge- submit your own questions and answers!
|
||||||
|
- Meetups: Craving in-person connections without the long journeys? [Join your local Grafana & Friends meetup group](https://gra.fan/githubtomeetup)!
|
||||||
- **Forums:** Do you have a problem, question, or curiosity? Visit our [forums](https://gra.fan/fromgithubtoforums) for a reservoir of knowledge, submit your own questions and answers!
|
- Community Slack: Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
|
||||||
- **Meetups:** Craving in-person connections without the long journeys? [Join your local Grafana & Friends meetup group](https://gra.fan/githubtomeetup)!
|
Learn:
|
||||||
- **Community Slack:** Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
|
- YouTube: From getting started to exploring newer projects like Pyroscope and Beyla, the [Grafana YouTube channel](https://gra.fan/githubtoyoutube) has what you need to get started!
|
||||||
|
- Meetups: Join a [group near you](https://gra.fan/githubtomeetup) to learn from local experts and ask questions in real time.
|
||||||
#### Learn
|
Share your story:
|
||||||
|
- Meetups and blogs: We’d love to feature your OSS Grafana Labs use case or story at an upcoming Grafana & Friends meetup or on the Grafana blog! Submit your idea [here](https://gra.fan/githubtocca) and we’ll connect with you on next steps if accepted.
|
||||||
- **YouTube:** From getting started to exploring newer projects like Pyroscope and Beyla, the [Grafana YouTube channel](https://gra.fan/githubtoyoutube) has what you need to get started!
|
|
||||||
- **Meetups:** Join a [group near you](https://gra.fan/githubtomeetup) to learn from local experts and ask questions in real time.
|
|
||||||
|
|
||||||
#### Make technical contributions
|
|
||||||
|
|
||||||
- You can make technical contributions with or without code. Scroll down to see how!
|
|
||||||
|
|
||||||
#### Share your story
|
|
||||||
|
|
||||||
- **Meetups and blogs:** We’d love to feature your OSS Grafana Labs use case or story at an upcoming Grafana & Friends meetup or on the Grafana blog! Submit your idea [here](https://gra.fan/githubtocca), and we’ll connect with you on next steps if accepted.
|
|
||||||
|
|
||||||
## Choose the right channel
|
|
||||||
|
|
||||||
Use the right place to ask questions, report problems, and propose changes.
|
|
||||||
|
|
||||||
- **[GitHub issues](https://github.com/grafana/grafana/issues) and [pull requests](https://github.com/grafana/grafana/pulls)**: Use for reproducible bugs in core Grafana and maintained plugins, small and actionable feature requests, and code or docs changes via pull requests. Avoid general “how do I” questions. For security issues, follow the [security policy](https://github.com/grafana/grafana/security/policy).
|
|
||||||
- **Grafana community forums**: Use for questions, troubleshooting, best practices, plugin development Q&A, and early idea discussion. Forums create a searchable public knowledge base that helps others with the same problems and questions. Start here if you are unsure: [Grafana community forums](https://community.grafana.com/).
|
|
||||||
- **Grafana Community Slack**: Use for quick, time-sensitive chats and networking. Do not rely on Slack for complex troubleshooting or decisions. Share outcomes back to a forum topic or GitHub issue/PR to keep a public record: [Grafana Community Slack](https://slack.grafana.com).
|
|
||||||
- **Not sure where to start?** Start with a forum topic. Maintainers and community members will redirect you if a GitHub issue or pull request is more appropriate.
|
|
||||||
|
|
||||||
## Make technical contributions
|
## Make technical contributions
|
||||||
|
|
||||||
We welcome your technical contributions! You can contribute in several ways:
|
We welcome your technical contributions! Here are some examples:
|
||||||
|
|
||||||
### Contribute Code to Grafana
|
- Contribute to the Grafana codebase- check out these [help-wanted issues](<(https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)>)
|
||||||
|
- Develop community [plugins](https://grafana.com/developers/plugin-tools)
|
||||||
|
- Report [bugs](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml)
|
||||||
|
- [Triage issues](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/triage-issues.md)
|
||||||
|
- Report [security vulnerabilities](https://github.com/grafana/grafana/security/policy)
|
||||||
|
- Submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md)
|
||||||
|
- Write [technical documentation](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/documentation/README.md)
|
||||||
|
|
||||||
**What you will need:**
|
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating grafana.json files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
|
||||||
|
|
||||||
- Follow our [developer guide](contribute/developer-guide.md) to set up your environment.
|
### Your first contribution
|
||||||
- Adhere to our [frontend](contribute/style-guides/frontend.md) and [backend](contribute/backend/style-guide.md) style guides.
|
|
||||||
- Write or update tests ([testing guide](contribute/style-guides/testing.md)).
|
|
||||||
|
|
||||||
**Step-by-step:**
|
Unsure where to begin contributing to Grafana? Start by browsing issues labeled `beginner friendly` or `help wanted`.
|
||||||
|
|
||||||
1. Browse all [issues](https://github.com/grafana/grafana/issues) to find something to work on. You can also filter by [help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
|
- [Beginner-friendly](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22) issues are generally straightforward to complete.
|
||||||
1. Prepare a clear, descriptive pull request ([how-to guide](contribute/create-pull-request.md)).
|
- [Help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) issues are problems we would like the community to help us with regardless of complexity.
|
||||||
1. Ensure you include and run the appropriate tests as part of your pull request.
|
|
||||||
1. Commit and push your changes. If you encounter merge conflicts, you may rebase your branch onto the main branch.
|
|
||||||
|
|
||||||
### Develop a Plugin
|
If you're looking to make a code change, see how to set up your environment for [local development](contribute/developer-guide.md).
|
||||||
|
|
||||||
Grafana plugins let you extend the platform with new data sources, panels, and more. This is a great way to share your ideas and make a real impact on the Grafana ecosystem.
|
When you're ready to contribute, it's time to [create a pull request](/contribute/create-pull-request.md).
|
||||||
|
|
||||||
**Step-by-step:**
|
### Develop a plugin
|
||||||
|
|
||||||
1. Read the [plugin development guide](https://grafana.com/developers/plugin-tools) to choose your plugin type and set up your environment.
|
Developing a Grafana plugin is a fantastic way to share your unique ideas with the community, extend the platform’s capabilities, and make a real impact on how people visualize and understand their data. Check out our guide to creating [plugins](https://grafana.com/developers/plugin-tools)
|
||||||
2. Scaffold your plugin using the recommended tools.
|
|
||||||
3. Develop and test your plugin locally.
|
|
||||||
4. Follow best practices for code style, testing, and documentation.
|
|
||||||
5. Publish your plugin or submit it for review as described in the guide.
|
|
||||||
|
|
||||||
### Contribute without code
|
### Report bugs
|
||||||
|
|
||||||
You can help even if you don't write code:
|
|
||||||
|
|
||||||
- Report a bug with the [bug report template](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml) and include steps to reproduce.
|
|
||||||
- Submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md) to propose improvements.
|
|
||||||
- Improve our docs with the [documentation contribution guide](https://github.com/grafana/grafana/blob/main/contribute/documentation).
|
|
||||||
- Help with [issue triage](https://github.com/grafana/grafana/blob/main/contribute/triage-issues.md) by reviewing, labeling, and clarifying open issues.
|
|
||||||
- Report security vulnerabilities following our [security policy](https://github.com/grafana/grafana/security/policy).
|
|
||||||
|
|
||||||
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating `grafana.json` files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
|
|
||||||
|
|
||||||
#### Reporting issues
|
|
||||||
|
|
||||||
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
|
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
|
||||||
|
|
||||||
@@ -92,11 +59,11 @@ For data visualization issues:
|
|||||||
- Query results from the inspect drawer (data tab & query inspector)
|
- Query results from the inspect drawer (data tab & query inspector)
|
||||||
- Panel settings can be extracted in the panel inspect drawer JSON tab
|
- Panel settings can be extracted in the panel inspect drawer JSON tab
|
||||||
|
|
||||||
For dashboard related issues:
|
For a dashboard related issues:
|
||||||
|
|
||||||
- Dashboard JSON can be found in the dashboard settings JSON model view. You can [send the panel JSON model](https://grafana.com/docs/grafana/latest/troubleshooting/send-panel-to-grafana-support/) to Grafana Labs Technical Support and request help with troubleshooting your issue.
|
- Dashboard JSON can be found in the dashboard settings JSON model view
|
||||||
|
|
||||||
For authentication and alerting, Grafana server logs are useful.
|
For authentication and alerting Grafana server logs are useful.
|
||||||
|
|
||||||
### Triage issues
|
### Triage issues
|
||||||
|
|
||||||
@@ -108,9 +75,9 @@ Read more about the ways you can [Triage issues](/contribute/triage-issues.md).
|
|||||||
|
|
||||||
If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details on reporting.
|
If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details on reporting.
|
||||||
|
|
||||||
### Suggest features
|
### Suggest enhancements
|
||||||
|
|
||||||
If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md). To learn how to write an effective feature request, refer to [Create a feature request](contribute/create-feature-request.md).
|
If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md).
|
||||||
|
|
||||||
We want to make Grafana accessible to even more people. Submit an [accessibility issue](https://github.com/grafana/grafana/issues/new?template=2-accessibility.md) to help us understand what we can improve.
|
We want to make Grafana accessible to even more people. Submit an [accessibility issue](https://github.com/grafana/grafana/issues/new?template=2-accessibility.md) to help us understand what we can improve.
|
||||||
|
|
||||||
|
|||||||
+2
-6
@@ -17,7 +17,7 @@ ARG JS_SRC=js-builder
|
|||||||
FROM alpine:3.22.2 AS alpine-base
|
FROM alpine:3.22.2 AS alpine-base
|
||||||
FROM ubuntu:22.04 AS ubuntu-base
|
FROM ubuntu:22.04 AS ubuntu-base
|
||||||
FROM golang:1.25.3-alpine AS go-builder-base
|
FROM golang:1.25.3-alpine AS go-builder-base
|
||||||
FROM --platform=${JS_PLATFORM} node:24-alpine AS js-builder-base
|
FROM --platform=${JS_PLATFORM} node:22-alpine AS js-builder-base
|
||||||
# Javascript build stage
|
# Javascript build stage
|
||||||
FROM --platform=${JS_PLATFORM} ${JS_IMAGE} AS js-builder
|
FROM --platform=${JS_PLATFORM} ${JS_IMAGE} AS js-builder
|
||||||
ARG JS_NODE_ENV=production
|
ARG JS_NODE_ENV=production
|
||||||
@@ -95,28 +95,24 @@ COPY pkg/aggregator pkg/aggregator
|
|||||||
COPY apps/playlist apps/playlist
|
COPY apps/playlist apps/playlist
|
||||||
COPY apps/plugins apps/plugins
|
COPY apps/plugins apps/plugins
|
||||||
COPY apps/shorturl apps/shorturl
|
COPY apps/shorturl apps/shorturl
|
||||||
COPY apps/annotation apps/annotation
|
|
||||||
COPY apps/correlations apps/correlations
|
COPY apps/correlations apps/correlations
|
||||||
COPY apps/preferences apps/preferences
|
COPY apps/preferences apps/preferences
|
||||||
COPY apps/collections apps/collections
|
|
||||||
COPY apps/provisioning apps/provisioning
|
COPY apps/provisioning apps/provisioning
|
||||||
COPY apps/secret apps/secret
|
COPY apps/secret apps/secret
|
||||||
COPY apps/scope apps/scope
|
COPY apps/scope apps/scope
|
||||||
COPY apps/investigations apps/investigations
|
COPY apps/investigations apps/investigations
|
||||||
COPY apps/logsdrilldown apps/logsdrilldown
|
|
||||||
COPY apps/advisor apps/advisor
|
COPY apps/advisor apps/advisor
|
||||||
COPY apps/dashboard apps/dashboard
|
COPY apps/dashboard apps/dashboard
|
||||||
COPY apps/folder apps/folder
|
COPY apps/folder apps/folder
|
||||||
|
COPY apps/preferences apps/preferences
|
||||||
COPY apps/iam apps/iam
|
COPY apps/iam apps/iam
|
||||||
COPY apps apps
|
COPY apps apps
|
||||||
COPY kindsv2 kindsv2
|
COPY kindsv2 kindsv2
|
||||||
COPY apps/alerting/alertenrichment apps/alerting/alertenrichment
|
COPY apps/alerting/alertenrichment apps/alerting/alertenrichment
|
||||||
COPY apps/alerting/historian apps/alerting/historian
|
|
||||||
COPY apps/alerting/notifications apps/alerting/notifications
|
COPY apps/alerting/notifications apps/alerting/notifications
|
||||||
COPY apps/alerting/rules apps/alerting/rules
|
COPY apps/alerting/rules apps/alerting/rules
|
||||||
COPY pkg/codegen pkg/codegen
|
COPY pkg/codegen pkg/codegen
|
||||||
COPY pkg/plugins/codegen pkg/plugins/codegen
|
COPY pkg/plugins/codegen pkg/plugins/codegen
|
||||||
COPY apps/example apps/example
|
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
|
|||||||
@@ -135,14 +135,14 @@ i18n-extract-enterprise:
|
|||||||
@echo "Skipping i18n extract for Enterprise: not enabled"
|
@echo "Skipping i18n extract for Enterprise: not enabled"
|
||||||
else
|
else
|
||||||
i18n-extract-enterprise:
|
i18n-extract-enterprise:
|
||||||
@echo "Extracting i18n strings for Enterprise"
|
@echo "Extracting i18n strings for Enterprise"
|
||||||
cd public/locales/enterprise && yarn run i18next-cli extract --sync-primary
|
yarn run i18next --config public/locales/i18next-parser-enterprise.config.cjs
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: i18n-extract
|
.PHONY: i18n-extract
|
||||||
i18n-extract: i18n-extract-enterprise
|
i18n-extract: i18n-extract-enterprise
|
||||||
@echo "Extracting i18n strings for OSS"
|
@echo "Extracting i18n strings for OSS"
|
||||||
yarn run i18next-cli extract --sync-primary
|
yarn run i18next --config public/locales/i18next-parser.config.cjs
|
||||||
@echo "Extracting i18n strings for packages"
|
@echo "Extracting i18n strings for packages"
|
||||||
yarn run packages:i18n-extract
|
yarn run packages:i18n-extract
|
||||||
@echo "Extracting i18n strings for plugins"
|
@echo "Extracting i18n strings for plugins"
|
||||||
@@ -178,7 +178,7 @@ gen-apps: do-gen-apps gofmt ## Generate code for Grafana App SDK apps and run go
|
|||||||
@if [ -n "$$CODEGEN_VERIFY" ]; then \
|
@if [ -n "$$CODEGEN_VERIFY" ]; then \
|
||||||
echo "Verifying generated code is up to date..."; \
|
echo "Verifying generated code is up to date..."; \
|
||||||
if ! git diff --quiet; then \
|
if ! git diff --quiet; then \
|
||||||
echo "Error: Generated code is not up to date. Please run 'make gen-apps', 'make gen-cue', and 'make gen-jsonnet' to regenerate."; \
|
echo "Error: Generated apps code is not up to date. Please run 'make gen-apps' to regenerate."; \
|
||||||
git diff --name-only; \
|
git diff --name-only; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi; \
|
fi; \
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
The open-source platform for monitoring and observability
|
The open-source platform for monitoring and observability
|
||||||
|
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
|
[](https://drone.grafana.net/grafana/grafana)
|
||||||
[](https://goreportcard.com/report/github.com/grafana/grafana)
|
[](https://goreportcard.com/report/github.com/grafana/grafana)
|
||||||
|
|
||||||
Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data-driven culture:
|
Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data-driven culture:
|
||||||
@@ -35,8 +36,6 @@ If you're interested in contributing to the Grafana project:
|
|||||||
- Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22).
|
- Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22).
|
||||||
- Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html).
|
- Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html).
|
||||||
|
|
||||||
> Share your contributor experience in our [feedback survey](https://gra.fan/ome) to help us improve.
|
|
||||||
|
|
||||||
## Get involved
|
## Get involved
|
||||||
|
|
||||||
- Follow [@grafana on X (formerly Twitter)](https://x.com/grafana/).
|
- Follow [@grafana on X (formerly Twitter)](https://x.com/grafana/).
|
||||||
|
|||||||
+2
-31
@@ -1,34 +1,5 @@
|
|||||||
include ../sdk.mk
|
include ../sdk.mk
|
||||||
|
|
||||||
.PHONY: etcd
|
.PHONY: generate
|
||||||
etcd:
|
|
||||||
@docker run -d --name etcd --env ALLOW_NONE_AUTHENTICATION=yes -p 22379:2379 bitnamilegacy/etcd:latest
|
|
||||||
|
|
||||||
.PHONY: generate # Run Grafana App SDK code generation
|
|
||||||
generate: install-app-sdk update-app-sdk
|
generate: install-app-sdk update-app-sdk
|
||||||
@$(APP_SDK_BIN) generate \
|
@$(APP_SDK_BIN) generate -g ./pkg/apis --grouping=group --postprocess --defencoding=none --useoldmanifestkinds
|
||||||
--source=./kinds/ \
|
|
||||||
--gogenpath=./pkg/apis \
|
|
||||||
--grouping=group \
|
|
||||||
--defencoding=none
|
|
||||||
|
|
||||||
.PHONY: run
|
|
||||||
run:
|
|
||||||
@go run ./pkg/standalone/server.go --etcd-servers=http://127.0.0.1:22379 --secure-port 7445
|
|
||||||
|
|
||||||
.PHONY: create-checks
|
|
||||||
create-checks:
|
|
||||||
@echo "Creating plugin check..."
|
|
||||||
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"plugin"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
|
|
||||||
&& echo "Plugin check created successfully"
|
|
||||||
@echo "Creating datasource check..."
|
|
||||||
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"datasource"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
|
|
||||||
&& echo "Datasource check created successfully"
|
|
||||||
|
|
||||||
delete-checks:
|
|
||||||
@curl -k -X DELETE https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
|
||||||
&& echo "All checks deleted successfully"
|
|
||||||
|
|||||||
+119
-140
@@ -4,53 +4,34 @@ go 1.25.3
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver/v3 v3.4.0
|
github.com/Masterminds/semver/v3 v3.4.0
|
||||||
github.com/google/go-cmp v0.7.0
|
|
||||||
github.com/google/go-github/v70 v70.0.0
|
github.com/google/go-github/v70 v70.0.0
|
||||||
github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4
|
github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43
|
||||||
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
|
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
|
||||||
github.com/grafana/grafana-app-sdk v0.48.4
|
github.com/grafana/grafana-app-sdk v0.40.2
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.48.3
|
github.com/grafana/grafana-app-sdk/logging v0.40.2
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.284.0
|
github.com/grafana/grafana-plugin-sdk-go v0.278.0
|
||||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0
|
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.10.0
|
||||||
k8s.io/apimachinery v0.34.2
|
k8s.io/apimachinery v0.33.3
|
||||||
k8s.io/apiserver v0.34.2
|
k8s.io/apiserver v0.33.3
|
||||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
|
||||||
)
|
)
|
||||||
|
|
||||||
// transitive dependencies that need replaced
|
// transitive dependencies that need replaced
|
||||||
// TODO: stop depending on grafana core
|
// TODO: stop depending on grafana core
|
||||||
replace github.com/grafana/grafana => ../..
|
replace github.com/grafana/grafana => ../..
|
||||||
|
|
||||||
replace github.com/grafana/grafana/apps/provisioning => ../provisioning
|
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6
|
||||||
|
|
||||||
replace github.com/grafana/grafana/pkg/apimachinery => ../../pkg/apimachinery
|
|
||||||
|
|
||||||
replace github.com/grafana/grafana/pkg/apiserver => ../../pkg/apiserver
|
|
||||||
|
|
||||||
replace github.com/grafana/grafana/apps/dashboard => ../dashboard
|
|
||||||
|
|
||||||
replace github.com/grafana/grafana/pkg/aggregator => ../../pkg/aggregator
|
|
||||||
|
|
||||||
replace github.com/grafana/grafana/apps/folder => ../folder
|
|
||||||
|
|
||||||
replace github.com/grafana/grafana/apps/secret => ../secret
|
|
||||||
|
|
||||||
replace github.com/grafana/grafana/apps/iam => ../iam
|
|
||||||
|
|
||||||
replace github.com/grafana/grafana/apps/plugins => ../plugins
|
|
||||||
|
|
||||||
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||||
dario.cat/mergo v1.0.2 // indirect
|
dario.cat/mergo v1.0.2 // indirect
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
@@ -59,19 +40,19 @@ require (
|
|||||||
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect
|
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
|
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
github.com/apache/arrow-go/v18 v18.4.1 // indirect
|
github.com/apache/arrow-go/v18 v18.3.0 // indirect
|
||||||
github.com/armon/go-metrics v0.4.1 // indirect
|
github.com/armon/go-metrics v0.4.1 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/at-wat/mqtt-go v0.19.6 // indirect
|
github.com/at-wat/mqtt-go v0.19.4 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.55.7 // indirect
|
github.com/aws/aws-sdk-go v1.55.7 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.1 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.14 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||||
github.com/aws/smithy-go v1.23.1 // indirect
|
github.com/aws/smithy-go v1.22.4 // indirect
|
||||||
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect
|
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect
|
||||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
@@ -81,11 +62,13 @@ require (
|
|||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
||||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cheekybits/genny v1.0.0 // indirect
|
github.com/cheekybits/genny v1.0.0 // indirect
|
||||||
|
github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 // indirect
|
||||||
github.com/cloudflare/circl v1.6.1 // indirect
|
github.com/cloudflare/circl v1.6.1 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect
|
github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect
|
||||||
@@ -95,106 +78,102 @@ require (
|
|||||||
github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect
|
github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect
|
||||||
github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect
|
github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect
|
||||||
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect
|
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect
|
||||||
github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // indirect
|
github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
github.com/elazarl/goproxy v1.7.2 // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||||
|
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
github.com/gchaincl/sqlhooks v1.3.0 // indirect
|
github.com/gchaincl/sqlhooks v1.3.0 // indirect
|
||||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
github.com/getkin/kin-openapi v0.132.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
||||||
github.com/go-kit/log v0.2.1 // indirect
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
github.com/go-ldap/ldap/v3 v3.4.4 // indirect
|
github.com/go-ldap/ldap/v3 v3.4.4 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/analysis v0.24.0 // indirect
|
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||||
github.com/go-openapi/errors v0.22.3 // indirect
|
github.com/go-openapi/errors v0.22.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.22.1 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.2 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
github.com/go-openapi/loads v0.23.1 // indirect
|
github.com/go-openapi/loads v0.22.0 // indirect
|
||||||
github.com/go-openapi/runtime v0.28.0 // indirect
|
github.com/go-openapi/runtime v0.28.0 // indirect
|
||||||
github.com/go-openapi/spec v0.22.0 // indirect
|
github.com/go-openapi/spec v0.21.0 // indirect
|
||||||
github.com/go-openapi/strfmt v0.24.0 // indirect
|
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||||
github.com/go-openapi/swag v0.23.0 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/go-openapi/swag/conv v0.25.1 // indirect
|
github.com/go-openapi/validate v0.24.0 // indirect
|
||||||
github.com/go-openapi/swag/fileutils v0.25.1 // indirect
|
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||||
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
|
|
||||||
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
|
|
||||||
github.com/go-openapi/swag/loading v0.25.1 // indirect
|
|
||||||
github.com/go-openapi/swag/mangling v0.25.1 // indirect
|
|
||||||
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
|
|
||||||
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
|
|
||||||
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
|
|
||||||
github.com/go-openapi/validate v0.25.0 // indirect
|
|
||||||
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
||||||
github.com/go-stack/stack v1.8.1 // indirect
|
github.com/go-stack/stack v1.8.1 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/gogo/googleapis v1.4.1 // indirect
|
github.com/gogo/googleapis v1.4.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
|
||||||
github.com/golang-migrate/migrate/v4 v4.7.0 // indirect
|
github.com/golang-migrate/migrate/v4 v4.7.0 // indirect
|
||||||
|
github.com/golang/mock v1.7.0-rc.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/btree v1.1.3 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
github.com/google/flatbuffers v25.2.10+incompatible // indirect
|
github.com/google/flatbuffers v25.2.10+incompatible // indirect
|
||||||
github.com/google/gnostic-models v0.7.0 // indirect
|
github.com/google/gnostic-models v0.6.9 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/google/wire v0.7.0 // indirect
|
github.com/google/wire v0.6.0 // indirect
|
||||||
github.com/grafana/alerting v0.0.0-20251119204204-77fa75125181 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
github.com/grafana/alerting v0.0.0-20250729175202-b4b881b7b263 // indirect
|
||||||
|
github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 // indirect
|
||||||
github.com/grafana/dataplane/sdata v0.0.9 // indirect
|
github.com/grafana/dataplane/sdata v0.0.9 // indirect
|
||||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect
|
||||||
github.com/grafana/grafana-aws-sdk v1.3.0 // indirect
|
github.com/grafana/grafana-aws-sdk v1.1.0 // indirect
|
||||||
github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // indirect
|
github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 // indirect
|
||||||
github.com/grafana/grafana/apps/plugins v0.0.0 // indirect
|
github.com/grafana/grafana/apps/provisioning v0.0.0-20250804150913-990f1c69ecc2 // indirect
|
||||||
github.com/grafana/grafana/apps/provisioning v0.0.0 // indirect
|
github.com/grafana/grafana/pkg/apiserver v0.0.0-20250804150913-990f1c69ecc2 // indirect
|
||||||
github.com/grafana/grafana/pkg/apiserver v0.0.0 // indirect
|
|
||||||
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
||||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect
|
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
||||||
github.com/grafana/sqlds/v4 v4.2.7 // indirect
|
github.com/grafana/sqlds/v4 v4.2.4 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/hashicorp/go-metrics v0.5.4 // indirect
|
github.com/hashicorp/go-metrics v0.5.4 // indirect
|
||||||
github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect
|
github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-plugin v1.7.0 // indirect
|
github.com/hashicorp/go-plugin v1.6.3 // indirect
|
||||||
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
|
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
|
||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/memberlist v0.5.2 // indirect
|
github.com/hashicorp/memberlist v0.5.2 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||||
github.com/huandu/xstrings v1.5.0 // indirect
|
github.com/huandu/xstrings v1.5.0 // indirect
|
||||||
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
|
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
|
||||||
github.com/jessevdk/go-flags v1.6.1 // indirect
|
github.com/jessevdk/go-flags v1.6.1 // indirect
|
||||||
github.com/jmespath-community/go-jmespath v1.1.1 // indirect
|
github.com/jmespath-community/go-jmespath v1.1.1 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/jmoiron/sqlx v1.4.0 // indirect
|
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/jpillora/backoff v1.0.0 // indirect
|
github.com/jpillora/backoff v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
|
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/lestrrat-go/strftime v1.0.4 // indirect
|
github.com/lestrrat-go/strftime v1.0.4 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
|
github.com/magefile/mage v1.15.0 // indirect
|
||||||
github.com/mailru/easyjson v0.9.0 // indirect
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
github.com/mattetti/filebuffer v1.0.1 // indirect
|
github.com/mattetti/filebuffer v1.0.1 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.32 // indirect
|
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/mdlayher/socket v0.4.1 // indirect
|
github.com/mdlayher/socket v0.4.1 // indirect
|
||||||
github.com/mdlayher/vsock v1.2.1 // indirect
|
github.com/mdlayher/vsock v1.2.1 // indirect
|
||||||
@@ -209,7 +188,7 @@ require (
|
|||||||
github.com/mithrandie/go-text v1.6.0 // indirect
|
github.com/mithrandie/go-text v1.6.0 // indirect
|
||||||
github.com/mithrandie/ternary v1.1.1 // indirect
|
github.com/mithrandie/ternary v1.1.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||||
@@ -220,9 +199,9 @@ require (
|
|||||||
github.com/oklog/run v1.1.0 // indirect
|
github.com/oklog/run v1.1.0 // indirect
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/open-feature/go-sdk v1.16.0 // indirect
|
github.com/open-feature/go-sdk v1.14.1 // indirect
|
||||||
github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.6 // indirect
|
github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 // indirect
|
||||||
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6 // indirect
|
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||||
@@ -230,38 +209,41 @@ require (
|
|||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/prometheus/alertmanager v0.28.0 // indirect
|
github.com/prometheus/alertmanager v0.28.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/common v0.67.3 // indirect
|
github.com/prometheus/common v0.65.0 // indirect
|
||||||
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
||||||
github.com/prometheus/exporter-toolkit v0.14.0 // indirect
|
github.com/prometheus/exporter-toolkit v0.14.0 // indirect
|
||||||
github.com/prometheus/procfs v0.16.1 // indirect
|
github.com/prometheus/procfs v0.16.1 // indirect
|
||||||
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.14.0 // indirect
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rs/cors v1.11.1 // indirect
|
github.com/rs/cors v1.11.1 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
||||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
|
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/spf13/cast v1.10.0 // indirect
|
github.com/spf13/cast v1.7.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.7 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/tetratelabs/wazero v1.8.2 // indirect
|
github.com/tetratelabs/wazero v1.8.2 // indirect
|
||||||
github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect
|
github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect
|
||||||
github.com/tjhop/slog-gokit v0.1.5 // indirect
|
github.com/tjhop/slog-gokit v0.1.3 // indirect
|
||||||
github.com/woodsbury/decimal128 v1.3.0 // indirect
|
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
|
||||||
|
github.com/unknwon/com v1.0.1 // indirect
|
||||||
|
github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect
|
||||||
|
github.com/urfave/cli v1.22.16 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/zeebo/xxh3 v1.0.2 // indirect
|
github.com/zeebo/xxh3 v1.0.2 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.17.4 // indirect
|
go.mongodb.org/mongo-driver v1.17.3 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
||||||
go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 // indirect
|
go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 // indirect
|
||||||
go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 // indirect
|
go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||||
@@ -270,51 +252,48 @@ require (
|
|||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/mock v0.6.0 // indirect
|
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
golang.org/x/crypto v0.40.0 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
|
||||||
golang.org/x/crypto v0.45.0 // indirect
|
golang.org/x/mod v0.26.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect
|
golang.org/x/net v0.42.0 // indirect
|
||||||
golang.org/x/mod v0.30.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/sync v0.16.0 // indirect
|
||||||
golang.org/x/oauth2 v0.33.0 // indirect
|
golang.org/x/sys v0.34.0 // indirect
|
||||||
golang.org/x/sync v0.18.0 // indirect
|
golang.org/x/term v0.33.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/text v0.27.0 // indirect
|
||||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect
|
golang.org/x/time v0.11.0 // indirect
|
||||||
golang.org/x/term v0.37.0 // indirect
|
golang.org/x/tools v0.35.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
|
||||||
golang.org/x/time v0.14.0 // indirect
|
|
||||||
golang.org/x/tools v0.39.0 // indirect
|
|
||||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||||
gonum.org/v1/gonum v0.16.0 // indirect
|
gonum.org/v1/gonum v0.16.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||||
google.golang.org/grpc v1.77.0 // indirect
|
google.golang.org/grpc v1.74.2 // indirect
|
||||||
google.golang.org/protobuf v1.36.10 // indirect
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
|
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/mail.v2 v2.3.1 // indirect
|
gopkg.in/mail.v2 v2.3.1 // indirect
|
||||||
gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect
|
gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect
|
||||||
gopkg.in/telebot.v3 v3.3.8 // indirect
|
gopkg.in/telebot.v3 v3.2.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/api v0.34.2 // indirect
|
k8s.io/api v0.33.3 // indirect
|
||||||
k8s.io/apiextensions-apiserver v0.34.2 // indirect
|
k8s.io/apiextensions-apiserver v0.33.3 // indirect
|
||||||
k8s.io/client-go v0.34.2 // indirect
|
k8s.io/client-go v0.33.3 // indirect
|
||||||
k8s.io/component-base v0.34.2 // indirect
|
k8s.io/component-base v0.33.3 // indirect
|
||||||
k8s.io/klog/v2 v2.130.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||||
modernc.org/libc v1.66.10 // indirect
|
modernc.org/libc v1.65.0 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.11.0 // indirect
|
modernc.org/memory v1.10.0 // indirect
|
||||||
modernc.org/sqlite v1.39.1 // indirect
|
modernc.org/sqlite v1.38.0 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect
|
sigs.k8s.io/yaml v1.5.0 // indirect
|
||||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
xorm.io/builder v0.3.6 // indirect
|
||||||
xorm.io/builder v0.3.13 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
+488
-400
File diff suppressed because it is too large
Load Diff
@@ -1,49 +1,57 @@
|
|||||||
package advisor
|
package advisor
|
||||||
|
|
||||||
checkv0alpha1: {
|
check: {
|
||||||
kind: "Check"
|
kind: "Check"
|
||||||
plural: "checks"
|
pluralName: "Checks"
|
||||||
scope: "Namespaced"
|
current: "v0alpha1"
|
||||||
validation: {
|
validation: {
|
||||||
operations: [
|
operations: [
|
||||||
"CREATE",
|
"CREATE",
|
||||||
"UPDATE",
|
"UPDATE",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
schema: {
|
versions: {
|
||||||
#Data: {
|
"v0alpha1": {
|
||||||
// Generic data input that a check can receive
|
codegen: {
|
||||||
data?: [string]: string
|
ts: {enabled: false}
|
||||||
}
|
go: {enabled: true}
|
||||||
#ErrorLink: {
|
}
|
||||||
// URL to a page with more information about the error
|
schema: {
|
||||||
url: string
|
#Data: {
|
||||||
// Human readable error message
|
// Generic data input that a check can receive
|
||||||
message: string
|
data?: [string]: string
|
||||||
}
|
}
|
||||||
#ReportFailure: {
|
#ErrorLink: {
|
||||||
// Severity of the failure
|
// URL to a page with more information about the error
|
||||||
severity: "high" | "low"
|
url: string
|
||||||
// Step ID that the failure is associated with
|
// Human readable error message
|
||||||
stepID: string
|
message: string
|
||||||
// Human readable identifier of the item that failed
|
}
|
||||||
item: string
|
#ReportFailure: {
|
||||||
// ID of the item that failed
|
// Severity of the failure
|
||||||
itemID: string
|
severity: "high" | "low"
|
||||||
// Links to actions that can be taken to resolve the failure
|
// Step ID that the failure is associated with
|
||||||
links: [...#ErrorLink]
|
stepID: string
|
||||||
// More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.
|
// Human readable identifier of the item that failed
|
||||||
moreInfo?: string
|
item: string
|
||||||
}
|
// ID of the item that failed
|
||||||
#Report: {
|
itemID: string
|
||||||
// Number of elements analyzed
|
// Links to actions that can be taken to resolve the failure
|
||||||
count: int
|
links: [...#ErrorLink]
|
||||||
// List of failures
|
// More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.
|
||||||
failures: [...#ReportFailure]
|
moreInfo?: string
|
||||||
}
|
}
|
||||||
spec: #Data
|
#Report: {
|
||||||
status: {
|
// Number of elements analyzed
|
||||||
report: #Report
|
count: int
|
||||||
|
// List of failures
|
||||||
|
failures: [...#ReportFailure]
|
||||||
|
}
|
||||||
|
spec: #Data
|
||||||
|
status: {
|
||||||
|
report: #Report
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
package advisor
|
package advisor
|
||||||
|
|
||||||
checktypev0alpha1: {
|
checktype: {
|
||||||
kind: "CheckType"
|
kind: "CheckType"
|
||||||
plural: "checktypes"
|
pluralName: "CheckTypes"
|
||||||
scope: "Namespaced"
|
current: "v0alpha1"
|
||||||
schema: {
|
versions: {
|
||||||
#Step: {
|
"v0alpha1": {
|
||||||
title: string
|
codegen: {
|
||||||
description: string
|
ts: {enabled: false}
|
||||||
stepID: string
|
go: {enabled: true}
|
||||||
resolution: string
|
}
|
||||||
}
|
schema: {
|
||||||
spec: {
|
#Step: {
|
||||||
name: string
|
title: string
|
||||||
steps: [...#Step]
|
description: string
|
||||||
|
stepID: string
|
||||||
|
resolution: string
|
||||||
|
}
|
||||||
|
spec: {
|
||||||
|
name: string
|
||||||
|
steps: [...#Step]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,10 @@
|
|||||||
package advisor
|
package advisor
|
||||||
|
|
||||||
manifest: {
|
manifest: {
|
||||||
appName: "advisor"
|
appName: "advisor"
|
||||||
groupOverride: "advisor.grafana.app"
|
groupOverride: "advisor.grafana.app"
|
||||||
versions: {
|
kinds: [
|
||||||
"v0alpha1": {
|
check,
|
||||||
codegen: {
|
checktype,
|
||||||
ts: {enabled: false}
|
]
|
||||||
go: {enabled: true}
|
|
||||||
}
|
|
||||||
kinds: [
|
|
||||||
checkv0alpha1,
|
|
||||||
checktypev0alpha1,
|
|
||||||
]
|
|
||||||
routes: {
|
|
||||||
namespaced: {
|
|
||||||
"/register": {
|
|
||||||
"POST": {
|
|
||||||
response: {
|
|
||||||
message: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
package v0alpha1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CheckClient struct {
|
|
||||||
client *resource.TypedClient[*Check, *CheckList]
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCheckClient(client resource.Client) *CheckClient {
|
|
||||||
return &CheckClient{
|
|
||||||
client: resource.NewTypedClient[*Check, *CheckList](client, CheckKind()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCheckClientFromGenerator(generator resource.ClientGenerator) (*CheckClient, error) {
|
|
||||||
c, err := generator.ClientFor(CheckKind())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewCheckClient(c), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) Get(ctx context.Context, identifier resource.Identifier) (*Check, error) {
|
|
||||||
return c.client.Get(ctx, identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) {
|
|
||||||
return c.client.List(ctx, namespace, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) {
|
|
||||||
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Limit: opts.Limit,
|
|
||||||
LabelFilters: opts.LabelFilters,
|
|
||||||
FieldSelectors: opts.FieldSelectors,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for resp.GetContinue() != "" {
|
|
||||||
page, err := c.client.List(ctx, namespace, resource.ListOptions{
|
|
||||||
Continue: resp.GetContinue(),
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Limit: opts.Limit,
|
|
||||||
LabelFilters: opts.LabelFilters,
|
|
||||||
FieldSelectors: opts.FieldSelectors,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp.SetContinue(page.GetContinue())
|
|
||||||
resp.SetResourceVersion(page.GetResourceVersion())
|
|
||||||
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) Create(ctx context.Context, obj *Check, opts resource.CreateOptions) (*Check, error) {
|
|
||||||
// Make sure apiVersion and kind are set
|
|
||||||
obj.APIVersion = GroupVersion.Identifier()
|
|
||||||
obj.Kind = CheckKind().Kind()
|
|
||||||
return c.client.Create(ctx, obj, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) Update(ctx context.Context, obj *Check, opts resource.UpdateOptions) (*Check, error) {
|
|
||||||
return c.client.Update(ctx, obj, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Check, error) {
|
|
||||||
return c.client.Patch(ctx, identifier, req, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckStatus, opts resource.UpdateOptions) (*Check, error) {
|
|
||||||
return c.client.Update(ctx, &Check{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: CheckKind().Kind(),
|
|
||||||
APIVersion: GroupVersion.Identifier(),
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Namespace: identifier.Namespace,
|
|
||||||
Name: identifier.Name,
|
|
||||||
},
|
|
||||||
Status: newStatus,
|
|
||||||
}, resource.UpdateOptions{
|
|
||||||
Subresource: "status",
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
|
||||||
return c.client.Delete(ctx, identifier, opts)
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
package v0alpha1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CheckTypeClient struct {
|
|
||||||
client *resource.TypedClient[*CheckType, *CheckTypeList]
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCheckTypeClient(client resource.Client) *CheckTypeClient {
|
|
||||||
return &CheckTypeClient{
|
|
||||||
client: resource.NewTypedClient[*CheckType, *CheckTypeList](client, CheckTypeKind()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCheckTypeClientFromGenerator(generator resource.ClientGenerator) (*CheckTypeClient, error) {
|
|
||||||
c, err := generator.ClientFor(CheckTypeKind())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewCheckTypeClient(c), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) Get(ctx context.Context, identifier resource.Identifier) (*CheckType, error) {
|
|
||||||
return c.client.Get(ctx, identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) {
|
|
||||||
return c.client.List(ctx, namespace, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) {
|
|
||||||
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Limit: opts.Limit,
|
|
||||||
LabelFilters: opts.LabelFilters,
|
|
||||||
FieldSelectors: opts.FieldSelectors,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for resp.GetContinue() != "" {
|
|
||||||
page, err := c.client.List(ctx, namespace, resource.ListOptions{
|
|
||||||
Continue: resp.GetContinue(),
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Limit: opts.Limit,
|
|
||||||
LabelFilters: opts.LabelFilters,
|
|
||||||
FieldSelectors: opts.FieldSelectors,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp.SetContinue(page.GetContinue())
|
|
||||||
resp.SetResourceVersion(page.GetResourceVersion())
|
|
||||||
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) Create(ctx context.Context, obj *CheckType, opts resource.CreateOptions) (*CheckType, error) {
|
|
||||||
// Make sure apiVersion and kind are set
|
|
||||||
obj.APIVersion = GroupVersion.Identifier()
|
|
||||||
obj.Kind = CheckTypeKind().Kind()
|
|
||||||
return c.client.Create(ctx, obj, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) Update(ctx context.Context, obj *CheckType, opts resource.UpdateOptions) (*CheckType, error) {
|
|
||||||
return c.client.Update(ctx, obj, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*CheckType, error) {
|
|
||||||
return c.client.Patch(ctx, identifier, req, opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckTypeStatus, opts resource.UpdateOptions) (*CheckType, error) {
|
|
||||||
return c.client.Update(ctx, &CheckType{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: CheckTypeKind().Kind(),
|
|
||||||
APIVersion: GroupVersion.Identifier(),
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Namespace: identifier.Namespace,
|
|
||||||
Name: identifier.Name,
|
|
||||||
},
|
|
||||||
Status: newStatus,
|
|
||||||
}, resource.UpdateOptions{
|
|
||||||
Subresource: "status",
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CheckTypeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
|
||||||
return c.client.Delete(ctx, identifier, opts)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
|
|
||||||
package v0alpha1
|
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
|
||||||
type CreateRegisterBody struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCreateRegisterBody creates a new CreateRegisterBody object.
|
|
||||||
func NewCreateRegisterBody() *CreateRegisterBody {
|
|
||||||
return &CreateRegisterBody{}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
|
|
||||||
package v0alpha1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
|
||||||
type CreateRegister struct {
|
|
||||||
metav1.TypeMeta `json:",inline"`
|
|
||||||
CreateRegisterBody `json:",inline"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCreateRegister() *CreateRegister {
|
|
||||||
return &CreateRegister{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *CreateRegisterBody) DeepCopyInto(dst *CreateRegisterBody) {
|
|
||||||
_ = resource.CopyObjectInto(dst, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *CreateRegister) DeepCopyObject() runtime.Object {
|
|
||||||
dst := NewCreateRegister()
|
|
||||||
o.DeepCopyInto(dst)
|
|
||||||
return dst
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *CreateRegister) DeepCopyInto(dst *CreateRegister) {
|
|
||||||
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
|
|
||||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
|
||||||
o.CreateRegisterBody.DeepCopyInto(&dst.CreateRegisterBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ runtime.Object = NewCreateRegister()
|
|
||||||
@@ -12,26 +12,22 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/app"
|
"github.com/grafana/grafana-app-sdk/app"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/kube-openapi/pkg/spec3"
|
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
|
||||||
|
|
||||||
v0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
v0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
rawSchemaCheckv0alpha1 = []byte(`{"Check":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"ErrorLink":{"additionalProperties":false,"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Report":{"additionalProperties":false,"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"$ref":"#/components/schemas/ReportFailure"},"type":"array"}},"required":["count","failures"],"type":"object"},"ReportFailure":{"additionalProperties":false,"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"$ref":"#/components/schemas/ErrorLink"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"$ref":"#/components/schemas/Report"}},"required":["report"],"type":"object"}}`)
|
rawSchemaCheckv0alpha1 = []byte(`{"spec":{"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"type":"array"}},"required":["count","failures"],"type":"object"}},"required":["report"],"type":"object"}}`)
|
||||||
versionSchemaCheckv0alpha1 app.VersionSchema
|
versionSchemaCheckv0alpha1 app.VersionSchema
|
||||||
_ = json.Unmarshal(rawSchemaCheckv0alpha1, &versionSchemaCheckv0alpha1)
|
_ = json.Unmarshal(rawSchemaCheckv0alpha1, &versionSchemaCheckv0alpha1)
|
||||||
rawSchemaCheckTypev0alpha1 = []byte(`{"CheckType":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Step":{"additionalProperties":false,"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"name":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/Step"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
|
rawSchemaCheckTypev0alpha1 = []byte(`{"spec":{"properties":{"name":{"type":"string"},"steps":{"items":{"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
|
||||||
versionSchemaCheckTypev0alpha1 app.VersionSchema
|
versionSchemaCheckTypev0alpha1 app.VersionSchema
|
||||||
_ = json.Unmarshal(rawSchemaCheckTypev0alpha1, &versionSchemaCheckTypev0alpha1)
|
_ = json.Unmarshal(rawSchemaCheckTypev0alpha1, &versionSchemaCheckTypev0alpha1)
|
||||||
)
|
)
|
||||||
|
|
||||||
var appManifestData = app.ManifestData{
|
var appManifestData = app.ManifestData{
|
||||||
AppName: "advisor",
|
AppName: "advisor",
|
||||||
Group: "advisor.grafana.app",
|
Group: "advisor.grafana.app",
|
||||||
PreferredVersion: "v0alpha1",
|
|
||||||
Versions: []app.ManifestVersion{
|
Versions: []app.ManifestVersion{
|
||||||
{
|
{
|
||||||
Name: "v0alpha1",
|
Name: "v0alpha1",
|
||||||
@@ -61,62 +57,6 @@ var appManifestData = app.ManifestData{
|
|||||||
Schema: &versionSchemaCheckTypev0alpha1,
|
Schema: &versionSchemaCheckTypev0alpha1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Routes: app.ManifestVersionRoutes{
|
|
||||||
Namespaced: map[string]spec3.PathProps{
|
|
||||||
"/register": {
|
|
||||||
Post: &spec3.Operation{
|
|
||||||
OperationProps: spec3.OperationProps{
|
|
||||||
|
|
||||||
OperationId: "createRegister",
|
|
||||||
|
|
||||||
Responses: &spec3.Responses{
|
|
||||||
ResponsesProps: spec3.ResponsesProps{
|
|
||||||
Default: &spec3.Response{
|
|
||||||
ResponseProps: spec3.ResponseProps{
|
|
||||||
Description: "Default OK response",
|
|
||||||
Content: map[string]*spec3.MediaType{
|
|
||||||
"application/json": {
|
|
||||||
MediaTypeProps: spec3.MediaTypeProps{
|
|
||||||
Schema: &spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Type: []string{"object"},
|
|
||||||
Properties: map[string]spec.Schema{
|
|
||||||
"apiVersion": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Type: []string{"string"},
|
|
||||||
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"kind": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Type: []string{"string"},
|
|
||||||
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Type: []string{"string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Required: []string{
|
|
||||||
"message",
|
|
||||||
"apiVersion",
|
|
||||||
"kind",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Cluster: map[string]spec3.PathProps{},
|
|
||||||
Schemas: map[string]spec.Schema{},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -141,14 +81,11 @@ func ManifestGoTypeAssociator(kind, version string) (goType resource.Kind, exist
|
|||||||
return goType, exists
|
return goType, exists
|
||||||
}
|
}
|
||||||
|
|
||||||
var customRouteToGoResponseType = map[string]any{
|
var customRouteToGoResponseType = map[string]any{}
|
||||||
"v0alpha1||<namespace>/register|POST": v0alpha1.CreateRegister{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
||||||
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
||||||
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
||||||
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
|
|
||||||
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
if len(path) > 0 && path[0] == '/' {
|
if len(path) > 0 && path[0] == '/' {
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
@@ -156,42 +93,3 @@ func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (g
|
|||||||
goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
||||||
return goType, exists
|
return goType, exists
|
||||||
}
|
}
|
||||||
|
|
||||||
var customRouteToGoParamsType = map[string]runtime.Object{}
|
|
||||||
|
|
||||||
func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
|
||||||
if len(path) > 0 && path[0] == '/' {
|
|
||||||
path = path[1:]
|
|
||||||
}
|
|
||||||
goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
|
||||||
return goType, exists
|
|
||||||
}
|
|
||||||
|
|
||||||
var customRouteToGoRequestBodyType = map[string]any{}
|
|
||||||
|
|
||||||
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
|
||||||
if len(path) > 0 && path[0] == '/' {
|
|
||||||
path = path[1:]
|
|
||||||
}
|
|
||||||
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
|
||||||
return goType, exists
|
|
||||||
}
|
|
||||||
|
|
||||||
type GoTypeAssociator struct{}
|
|
||||||
|
|
||||||
func NewGoTypeAssociator() *GoTypeAssociator {
|
|
||||||
return &GoTypeAssociator{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
|
|
||||||
return ManifestGoTypeAssociator(kind, version)
|
|
||||||
}
|
|
||||||
func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) {
|
|
||||||
return ManifestCustomRouteResponsesAssociator(kind, version, path, verb)
|
|
||||||
}
|
|
||||||
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
|
||||||
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
|
|
||||||
}
|
|
||||||
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
|
|
||||||
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
|
|
||||||
}
|
|
||||||
|
|||||||
+14
-54
@@ -2,9 +2,7 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/app"
|
"github.com/grafana/grafana-app-sdk/app"
|
||||||
"github.com/grafana/grafana-app-sdk/k8s"
|
"github.com/grafana/grafana-app-sdk/k8s"
|
||||||
@@ -18,15 +16,10 @@ import (
|
|||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkscheduler"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkscheduler"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checktyperegisterer"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checktyperegisterer"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(cfg app.Config) (app.App, error) {
|
func New(cfg app.Config) (app.App, error) {
|
||||||
// Needed until https://github.com/grafana/grafana-app-sdk/pull/1077
|
|
||||||
if cfg.KubeConfig.APIPath == "" {
|
|
||||||
cfg.KubeConfig.APIPath = "apis"
|
|
||||||
}
|
|
||||||
// Read config
|
// Read config
|
||||||
specificConfig, ok := cfg.SpecificConfig.(checkregistry.AdvisorAppConfig)
|
specificConfig, ok := cfg.SpecificConfig.(checkregistry.AdvisorAppConfig)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -52,16 +45,6 @@ func New(cfg app.Config) (app.App, error) {
|
|||||||
checkMap[c.ID()] = c
|
checkMap[c.ID()] = c
|
||||||
}
|
}
|
||||||
|
|
||||||
ctr, err := checktyperegisterer.New(cfg, log)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
csch, err := checkscheduler.New(cfg, log)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
simpleConfig := simple.AppConfig{
|
simpleConfig := simple.AppConfig{
|
||||||
Name: "advisor",
|
Name: "advisor",
|
||||||
KubeConfig: cfg.KubeConfig,
|
KubeConfig: cfg.KubeConfig,
|
||||||
@@ -86,12 +69,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||||||
go func() {
|
go func() {
|
||||||
logger := log.WithContext(ctx).With("check", check.ID())
|
logger := log.WithContext(ctx).With("check", check.ID())
|
||||||
logger.Debug("Processing check", "namespace", req.Object.GetNamespace())
|
logger.Debug("Processing check", "namespace", req.Object.GetNamespace())
|
||||||
orgID, err := getOrgIDFromNamespace(req.Object.GetNamespace())
|
requester, err := identity.GetRequester(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error getting org ID from namespace", "error", err)
|
logger.Error("Error getting requester", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), orgID)
|
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), requester.GetOrgID())
|
||||||
err = processCheck(ctx, logger, client, typesClient, req.Object, check)
|
err = processCheck(ctx, logger, client, typesClient, req.Object, check)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error processing check", "error", err)
|
logger.Error("Error processing check", "error", err)
|
||||||
@@ -102,12 +85,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||||||
go func() {
|
go func() {
|
||||||
logger := log.WithContext(ctx).With("check", check.ID())
|
logger := log.WithContext(ctx).With("check", check.ID())
|
||||||
logger.Debug("Updating check", "namespace", req.Object.GetNamespace(), "name", req.Object.GetName())
|
logger.Debug("Updating check", "namespace", req.Object.GetNamespace(), "name", req.Object.GetName())
|
||||||
orgID, err := getOrgIDFromNamespace(req.Object.GetNamespace())
|
requester, err := identity.GetRequester(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error getting org ID from namespace", "error", err)
|
logger.Error("Error getting requester", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), orgID)
|
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), requester.GetOrgID())
|
||||||
err = processCheckRetry(ctx, logger, client, typesClient, req.Object, check)
|
err = processCheckRetry(ctx, logger, client, typesClient, req.Object, check)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error processing check retry", "error", err)
|
logger.Error("Error processing check retry", "error", err)
|
||||||
@@ -123,37 +106,6 @@ func New(cfg app.Config) (app.App, error) {
|
|||||||
Kind: advisorv0alpha1.CheckTypeKind(),
|
Kind: advisorv0alpha1.CheckTypeKind(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
VersionedCustomRoutes: map[string]simple.AppVersionRouteHandlers{
|
|
||||||
"v0alpha1": {
|
|
||||||
{
|
|
||||||
Namespaced: true,
|
|
||||||
Path: "register",
|
|
||||||
Method: "POST",
|
|
||||||
}: func(ctx context.Context, w app.CustomRouteResponseWriter, req *app.CustomRouteRequest) error {
|
|
||||||
logger := log.WithContext(ctx)
|
|
||||||
namespace := req.ResourceIdentifier.Namespace
|
|
||||||
|
|
||||||
// Register check types for the namespace
|
|
||||||
err := ctr.RegisterCheckTypesInNamespace(ctx, logger, namespace)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to register check types", "namespace", namespace, "error", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return typed response matching the manifest
|
|
||||||
return json.NewEncoder(w).Encode(advisorv0alpha1.CreateRegister{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
APIVersion: fmt.Sprintf("%s/%s", advisorv0alpha1.APIGroup, advisorv0alpha1.APIVersion),
|
|
||||||
},
|
|
||||||
CreateRegisterBody: advisorv0alpha1.CreateRegisterBody{
|
|
||||||
Message: "Check types registered successfully",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := simple.NewApp(simpleConfig)
|
a, err := simple.NewApp(simpleConfig)
|
||||||
@@ -167,9 +119,17 @@ func New(cfg app.Config) (app.App, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save check types as resources
|
// Save check types as resources
|
||||||
|
ctr, err := checktyperegisterer.New(cfg, log)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
a.AddRunnable(ctr)
|
a.AddRunnable(ctr)
|
||||||
|
|
||||||
// Start scheduler
|
// Start scheduler
|
||||||
|
csch, err := checkscheduler.New(cfg, log)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
a.AddRunnable(csch)
|
a.AddRunnable(csch)
|
||||||
|
|
||||||
return a, nil
|
return a, nil
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package app
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
claims "github.com/grafana/authlib/types"
|
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
)
|
)
|
||||||
@@ -16,22 +15,7 @@ func GetAuthorizer() authorizer.Authorizer {
|
|||||||
return authorizer.DecisionNoOpinion, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for service identity
|
// require a user
|
||||||
if identity.IsServiceIdentity(ctx) {
|
|
||||||
return authorizer.DecisionAllow, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for access policy identity
|
|
||||||
info, ok := claims.AuthInfoFrom(ctx)
|
|
||||||
if ok && claims.IsIdentityType(info.GetIdentityType(), claims.TypeAccessPolicy) {
|
|
||||||
// For access policy identities, we need to use ResourceAuthorizer
|
|
||||||
// This requires an AccessClient, which should be provided by the API server
|
|
||||||
// For now, we'll use the default ResourceAuthorizer from the API server
|
|
||||||
// This will be set up by the API server's authorization chain
|
|
||||||
return authorizer.DecisionNoOpinion, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// For regular Grafana users, check if they are admin
|
|
||||||
u, err := identity.GetRequester(ctx)
|
u, err := identity.GetRequester(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authorizer.DecisionDeny, "valid user is required", err
|
return authorizer.DecisionDeny, "valid user is required", err
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
claims "github.com/grafana/authlib/types"
|
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
@@ -80,12 +79,4 @@ func (m *mockUser) HasRole(role identity.RoleType) bool {
|
|||||||
return role == identity.RoleAdmin && m.isGrafanaAdmin
|
return role == identity.RoleAdmin && m.isGrafanaAdmin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockUser) GetUID() string {
|
|
||||||
return "test-uid"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockUser) GetIdentityType() claims.IdentityType {
|
|
||||||
return claims.TypeUser
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement other methods of identity.Requester as needed
|
// Implement other methods of identity.Requester as needed
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||||
@@ -92,5 +91,4 @@ type AdvisorAppConfig struct {
|
|||||||
CheckRegistry CheckService
|
CheckRegistry CheckService
|
||||||
PluginConfig map[string]string
|
PluginConfig map[string]string
|
||||||
StackID string
|
StackID string
|
||||||
OrgService org.Service
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package datasourcecheck
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
sysruntime "runtime"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
@@ -20,47 +18,37 @@ const (
|
|||||||
HealthCheckStepID = "health-check"
|
HealthCheckStepID = "health-check"
|
||||||
UIDValidationStepID = "uid-validation"
|
UIDValidationStepID = "uid-validation"
|
||||||
MissingPluginStepID = "missing-plugin"
|
MissingPluginStepID = "missing-plugin"
|
||||||
PromDepAuthStepID = "prom-dep-auth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type check struct {
|
type check struct {
|
||||||
DatasourceSvc datasources.DataSourceService
|
DatasourceSvc datasources.DataSourceService
|
||||||
PluginStore pluginstore.Store
|
PluginStore pluginstore.Store
|
||||||
PluginContextProvider PluginContextProvider
|
PluginContextProvider pluginContextProvider
|
||||||
PluginClient plugins.Client
|
PluginClient plugins.Client
|
||||||
PluginRepo repo.Service
|
PluginRepo repo.Service
|
||||||
GrafanaVersion string
|
GrafanaVersion string
|
||||||
pluginCanBeInstalledCache map[string]bool
|
|
||||||
pluginExistsCacheMu sync.RWMutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
datasourceSvc datasources.DataSourceService,
|
datasourceSvc datasources.DataSourceService,
|
||||||
pluginStore pluginstore.Store,
|
pluginStore pluginstore.Store,
|
||||||
pluginContextProvider PluginContextProvider,
|
pluginContextProvider pluginContextProvider,
|
||||||
pluginClient plugins.Client,
|
pluginClient plugins.Client,
|
||||||
pluginRepo repo.Service,
|
pluginRepo repo.Service,
|
||||||
grafanaVersion string,
|
grafanaVersion string,
|
||||||
) checks.Check {
|
) checks.Check {
|
||||||
return &check{
|
return &check{
|
||||||
DatasourceSvc: datasourceSvc,
|
DatasourceSvc: datasourceSvc,
|
||||||
PluginStore: pluginStore,
|
PluginStore: pluginStore,
|
||||||
PluginContextProvider: pluginContextProvider,
|
PluginContextProvider: pluginContextProvider,
|
||||||
PluginClient: pluginClient,
|
PluginClient: pluginClient,
|
||||||
PluginRepo: pluginRepo,
|
PluginRepo: pluginRepo,
|
||||||
GrafanaVersion: grafanaVersion,
|
GrafanaVersion: grafanaVersion,
|
||||||
pluginCanBeInstalledCache: make(map[string]bool),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *check) Items(ctx context.Context) ([]any, error) {
|
func (c *check) Items(ctx context.Context) ([]any, error) {
|
||||||
requester, err := identity.GetRequester(ctx)
|
dss, err := c.DatasourceSvc.GetAllDataSources(ctx, &datasources.GetAllDataSourcesQuery{})
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dss, err := c.DatasourceSvc.GetDataSources(ctx, &datasources.GetDataSourcesQuery{
|
|
||||||
OrgID: requester.GetOrgID(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -99,7 +87,6 @@ func (c *check) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *check) Init(ctx context.Context) error {
|
func (c *check) Init(ctx context.Context) error {
|
||||||
c.pluginCanBeInstalledCache = make(map[string]bool)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,59 +102,9 @@ func (c *check) Steps() []checks.Step {
|
|||||||
PluginRepo: c.PluginRepo,
|
PluginRepo: c.PluginRepo,
|
||||||
GrafanaVersion: c.GrafanaVersion,
|
GrafanaVersion: c.GrafanaVersion,
|
||||||
},
|
},
|
||||||
&promDepAuthStep{
|
|
||||||
canBeInstalled: c.canBeInstalled,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// canBeInstalled checks if a plugin is already installed or if it's available in the plugin repository.
|
type pluginContextProvider interface {
|
||||||
// Returns true if:
|
|
||||||
// - The plugin is NOT installed AND it IS available in the repository (can be installed)
|
|
||||||
// Returns false if:
|
|
||||||
// - The plugin is already installed, OR
|
|
||||||
// - The plugin is NOT available in the repository (nothing to install)
|
|
||||||
func (c *check) canBeInstalled(ctx context.Context, pluginType string) (bool, error) {
|
|
||||||
// Check cache first with read lock for performance
|
|
||||||
c.pluginExistsCacheMu.RLock()
|
|
||||||
if canBeInstalled, found := c.pluginCanBeInstalledCache[pluginType]; found {
|
|
||||||
c.pluginExistsCacheMu.RUnlock()
|
|
||||||
return canBeInstalled, nil
|
|
||||||
}
|
|
||||||
c.pluginExistsCacheMu.RUnlock()
|
|
||||||
|
|
||||||
// Cache miss - acquire write lock and check again (double-checked locking pattern)
|
|
||||||
c.pluginExistsCacheMu.Lock()
|
|
||||||
defer c.pluginExistsCacheMu.Unlock()
|
|
||||||
|
|
||||||
// Another goroutine may have populated the cache while we waited for the lock
|
|
||||||
if canBeInstalled, found := c.pluginCanBeInstalledCache[pluginType]; found {
|
|
||||||
return canBeInstalled, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if plugin is already installed
|
|
||||||
if _, isInstalled := c.PluginStore.Plugin(ctx, pluginType); isInstalled {
|
|
||||||
c.pluginCanBeInstalledCache[pluginType] = false
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin is not installed - check if it's available in the repository
|
|
||||||
availablePlugins, err := c.PluginRepo.GetPluginsInfo(ctx, repo.GetPluginsInfoOptions{
|
|
||||||
IncludeDeprecated: true,
|
|
||||||
Plugins: []string{pluginType},
|
|
||||||
}, repo.NewCompatOpts(c.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH))
|
|
||||||
if err != nil {
|
|
||||||
// On error, assume plugin is installed/unavailable to avoid showing incorrect install links
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin is not installed but IS available - return false to show install link
|
|
||||||
// Plugin is not installed and NOT available in repo - return true (nothing to install)
|
|
||||||
isAvailableInRepo := len(availablePlugins) > 0
|
|
||||||
c.pluginCanBeInstalledCache[pluginType] = !isAvailableInRepo
|
|
||||||
return isAvailableInRepo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PluginContextProvider interface {
|
|
||||||
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
|
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
@@ -231,101 +230,6 @@ func TestCheck_Run(t *testing.T) {
|
|||||||
assert.Equal(t, MissingPluginStepID, failures[0].StepID)
|
assert.Equal(t, MissingPluginStepID, failures[0].StepID)
|
||||||
assert.Len(t, failures[0].Links, 1)
|
assert.Len(t, failures[0].Links, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should return failure when prometheus datasource uses SigV4 auth", func(t *testing.T) {
|
|
||||||
jsonData := simplejson.New()
|
|
||||||
jsonData.Set("sigV4Auth", true)
|
|
||||||
datasources := []*datasources.DataSource{
|
|
||||||
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
|
|
||||||
}
|
|
||||||
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
|
|
||||||
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
|
|
||||||
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
|
|
||||||
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
|
|
||||||
{ID: 1, Slug: "prometheus", Status: "active"},
|
|
||||||
{ID: 2, Slug: "grafana-amazonprometheus-datasource", Status: "active"},
|
|
||||||
}}
|
|
||||||
mockPluginStore := &MockPluginStore{exists: true}
|
|
||||||
|
|
||||||
check := &check{
|
|
||||||
DatasourceSvc: mockDatasourceSvc,
|
|
||||||
PluginContextProvider: mockPluginContextProvider,
|
|
||||||
PluginClient: mockPluginClient,
|
|
||||||
PluginRepo: mockPluginRepo,
|
|
||||||
PluginStore: mockPluginStore,
|
|
||||||
GrafanaVersion: "11.0.0",
|
|
||||||
}
|
|
||||||
|
|
||||||
failures, err := runChecks(check)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, failures, 1)
|
|
||||||
assert.Equal(t, PromDepAuthStepID, failures[0].StepID)
|
|
||||||
assert.Contains(t, failures[0].Links, advisor.CheckErrorLink{
|
|
||||||
Message: "View SigV4 docs",
|
|
||||||
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/aws-authentication/",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should return failure when prometheus datasource uses Azure auth", func(t *testing.T) {
|
|
||||||
jsonData := simplejson.New()
|
|
||||||
jsonData.Set("azureCredentials", map[string]interface{}{"authType": "msi"})
|
|
||||||
datasources := []*datasources.DataSource{
|
|
||||||
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
|
|
||||||
}
|
|
||||||
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
|
|
||||||
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
|
|
||||||
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
|
|
||||||
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
|
|
||||||
{ID: 1, Slug: "prometheus", Status: "active"},
|
|
||||||
{ID: 2, Slug: "grafana-azureprometheus-datasource", Status: "active"},
|
|
||||||
}}
|
|
||||||
mockPluginStore := &MockPluginStore{exists: true}
|
|
||||||
|
|
||||||
check := &check{
|
|
||||||
DatasourceSvc: mockDatasourceSvc,
|
|
||||||
PluginContextProvider: mockPluginContextProvider,
|
|
||||||
PluginClient: mockPluginClient,
|
|
||||||
PluginRepo: mockPluginRepo,
|
|
||||||
PluginStore: mockPluginStore,
|
|
||||||
GrafanaVersion: "11.0.0",
|
|
||||||
}
|
|
||||||
|
|
||||||
failures, err := runChecks(check)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, failures, 1)
|
|
||||||
assert.Equal(t, PromDepAuthStepID, failures[0].StepID)
|
|
||||||
assert.Contains(t, failures[0].Links, advisor.CheckErrorLink{
|
|
||||||
Message: "View Azure auth docs",
|
|
||||||
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/azure-authentication/",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should not return failure when prometheus datasource does not use deprecated auth", func(t *testing.T) {
|
|
||||||
jsonData := simplejson.New()
|
|
||||||
datasources := []*datasources.DataSource{
|
|
||||||
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
|
|
||||||
}
|
|
||||||
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
|
|
||||||
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
|
|
||||||
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
|
|
||||||
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
|
|
||||||
{ID: 1, Slug: "prometheus", Status: "active"},
|
|
||||||
}}
|
|
||||||
mockPluginStore := &MockPluginStore{exists: true}
|
|
||||||
|
|
||||||
check := &check{
|
|
||||||
DatasourceSvc: mockDatasourceSvc,
|
|
||||||
PluginContextProvider: mockPluginContextProvider,
|
|
||||||
PluginClient: mockPluginClient,
|
|
||||||
PluginRepo: mockPluginRepo,
|
|
||||||
PluginStore: mockPluginStore,
|
|
||||||
GrafanaVersion: "11.0.0",
|
|
||||||
}
|
|
||||||
|
|
||||||
failures, err := runChecks(check)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Empty(t, failures)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheck_Item(t *testing.T) {
|
func TestCheck_Item(t *testing.T) {
|
||||||
@@ -347,7 +251,7 @@ type MockDatasourceSvc struct {
|
|||||||
dss []*datasources.DataSource
|
dss []*datasources.DataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockDatasourceSvc) GetDataSources(context.Context, *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
|
func (m *MockDatasourceSvc) GetAllDataSources(context.Context, *datasources.GetAllDataSourcesQuery) ([]*datasources.DataSource, error) {
|
||||||
return m.dss, nil
|
return m.dss, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type healthCheckStep struct {
|
type healthCheckStep struct {
|
||||||
PluginContextProvider PluginContextProvider
|
PluginContextProvider pluginContextProvider
|
||||||
PluginClient plugins.Client
|
PluginClient plugins.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,147 +0,0 @@
|
|||||||
package datasourcecheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/logging"
|
|
||||||
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
|
||||||
)
|
|
||||||
|
|
||||||
type promDepAuthStep struct {
|
|
||||||
canBeInstalled func(ctx context.Context, pluginType string) (bool, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) Title() string {
|
|
||||||
return "Prometheus deprecated authentication check"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) Description() string {
|
|
||||||
return "Check if Prometheus data sources are using deprecated authentication methods (Azure auth and SigV4)"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) Resolution() string {
|
|
||||||
return fmt.Sprintf("Enable the feature toggle for 'prometheusTypeMigration'. If this feature toggle is already enabled, make sure that 'Azure Monitor Managed Service for Prometheus' and/or 'Amazon Managed Service for Prometheus' plugins are installed. If the data source is provisioned, edit data source type in the provisioning file to use '%s' or '%s'.", datasources.DS_AMAZON_PROMETHEUS, datasources.DS_AZURE_PROMETHEUS)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) ID() string {
|
|
||||||
return PromDepAuthStepID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) Run(ctx context.Context, log logging.Logger, obj *advisor.CheckSpec, item any) ([]advisor.CheckReportFailure, error) {
|
|
||||||
dataSource, ok := item.(*datasources.DataSource)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("invalid item type %T", item)
|
|
||||||
}
|
|
||||||
if dataSource.Type != datasources.DS_PROMETHEUS {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if dataSource.JsonData == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
awsAuthLinks, err := s.checkUsingAWSAuth(ctx, dataSource)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
azureAuthLinks, err := s.checkUsingAzureAuth(ctx, dataSource)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
errorLinks := append(awsAuthLinks, azureAuthLinks...)
|
|
||||||
|
|
||||||
if len(errorLinks) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return []advisor.CheckReportFailure{checks.NewCheckReportFailureWithMoreInfo(
|
|
||||||
advisor.CheckReportFailureSeverityHigh,
|
|
||||||
s.ID(),
|
|
||||||
dataSource.Name,
|
|
||||||
dataSource.UID,
|
|
||||||
errorLinks,
|
|
||||||
fmt.Sprintf("Datasource %s (UID: %s) is of type %s but it's using a deprecated authentication method so it should be migrated", dataSource.Name, dataSource.UID, dataSource.Type),
|
|
||||||
)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) checkUsingAWSAuth(ctx context.Context, dataSource *datasources.DataSource) ([]advisor.CheckErrorLink, error) {
|
|
||||||
var errorLinks []advisor.CheckErrorLink
|
|
||||||
if sigV4Auth, found := dataSource.JsonData.CheckGet("sigV4Auth"); found {
|
|
||||||
if enabled, err := sigV4Auth.Bool(); err != nil || !enabled {
|
|
||||||
// Disabled or not a valid boolean
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
readOnlyLink := checkReadOnly(dataSource)
|
|
||||||
|
|
||||||
if readOnlyLink != nil {
|
|
||||||
errorLinks = append(errorLinks, *readOnlyLink)
|
|
||||||
}
|
|
||||||
|
|
||||||
errorLinks = append(errorLinks,
|
|
||||||
advisor.CheckErrorLink{
|
|
||||||
Message: "View SigV4 docs",
|
|
||||||
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/aws-authentication/",
|
|
||||||
})
|
|
||||||
pluginLink := s.linkDataSource(ctx, datasources.DS_AMAZON_PROMETHEUS, "Amazon Managed Service for Prometheus")
|
|
||||||
if pluginLink != nil {
|
|
||||||
errorLinks = append(errorLinks, *pluginLink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errorLinks, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) checkUsingAzureAuth(ctx context.Context, dataSource *datasources.DataSource) ([]advisor.CheckErrorLink, error) {
|
|
||||||
var errorLinks []advisor.CheckErrorLink
|
|
||||||
if azureAuth, found := dataSource.JsonData.CheckGet("azureCredentials"); found {
|
|
||||||
if _, err := azureAuth.Value(); err != nil {
|
|
||||||
// azureAuth does not have a value
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
readOnlyLink := checkReadOnly(dataSource)
|
|
||||||
if readOnlyLink != nil {
|
|
||||||
errorLinks = append(errorLinks, *readOnlyLink)
|
|
||||||
}
|
|
||||||
errorLinks = append(errorLinks,
|
|
||||||
advisor.CheckErrorLink{
|
|
||||||
Message: "View Azure auth docs",
|
|
||||||
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/azure-authentication/",
|
|
||||||
})
|
|
||||||
pluginLink := s.linkDataSource(ctx, datasources.DS_AZURE_PROMETHEUS, "Azure Monitor Managed Service for Prometheus")
|
|
||||||
if pluginLink != nil {
|
|
||||||
errorLinks = append(errorLinks, *pluginLink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errorLinks, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkReadOnly(dataSource *datasources.DataSource) *advisor.CheckErrorLink {
|
|
||||||
if readOnly, found := dataSource.JsonData.CheckGet("readonly"); found {
|
|
||||||
if enabled, err := readOnly.Bool(); err != nil || !enabled {
|
|
||||||
// Disabled or not a valid boolean
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &advisor.CheckErrorLink{
|
|
||||||
Message: "Change provisioning file",
|
|
||||||
Url: "https://grafana.com/docs/grafana/latest/administration/provisioning/#data-sources",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *promDepAuthStep) linkDataSource(ctx context.Context, pluginType string, pluginName string) *advisor.CheckErrorLink {
|
|
||||||
canBeInstalled, err := s.canBeInstalled(ctx, pluginType)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if canBeInstalled {
|
|
||||||
// Plugin is available in the repo
|
|
||||||
return &advisor.CheckErrorLink{
|
|
||||||
Message: fmt.Sprintf("Install %s", pluginName),
|
|
||||||
Url: fmt.Sprintf("/plugins/%s", pluginType),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/grafana/authlib/types"
|
"github.com/grafana/authlib/types"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -57,26 +57,15 @@ func NewCheckReportFailureWithMoreInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetNamespaces(ctx context.Context, stackID string, orgService org.Service) ([]string, error) {
|
func GetNamespace(stackID string) (string, error) {
|
||||||
var namespaces []string
|
if stackID == "" {
|
||||||
if stackID != "" {
|
return metav1.NamespaceDefault, nil
|
||||||
// Single namespace for cloud stack
|
|
||||||
stackId, err := strconv.ParseInt(stackID, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid stack id: %s", stackID)
|
|
||||||
}
|
|
||||||
namespaces = []string{types.CloudNamespaceFormatter(stackId)}
|
|
||||||
} else {
|
|
||||||
// Multiple namespaces for each org
|
|
||||||
orgs, err := orgService.Search(ctx, &org.SearchOrgsQuery{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to fetch orgs: %w", err)
|
|
||||||
}
|
|
||||||
for _, o := range orgs {
|
|
||||||
namespaces = append(namespaces, types.OrgNamespaceFormatter(o.ID))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return namespaces, nil
|
stackId, err := strconv.ParseInt(stackID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("invalid stack id: %s", stackID)
|
||||||
|
}
|
||||||
|
return types.CloudNamespaceFormatter(stackId), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStatusAnnotation(obj resource.Object) string {
|
func GetStatusAnnotation(obj resource.Object) string {
|
||||||
|
|||||||
@@ -1,61 +1,40 @@
|
|||||||
package checks
|
package checks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetNamespaces(t *testing.T) {
|
func TestGetNamespace(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
stackID string
|
input string
|
||||||
orgs []string
|
expected string
|
||||||
expected []string
|
|
||||||
expectedErr string
|
expectedErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty stack ID",
|
name: "empty stack ID",
|
||||||
stackID: "",
|
input: "",
|
||||||
orgs: []string{"default"},
|
expected: metav1.NamespaceDefault,
|
||||||
expected: []string{metav1.NamespaceDefault},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid stack ID",
|
name: "valid stack ID",
|
||||||
stackID: "1234567890",
|
input: "1234567890",
|
||||||
orgs: []string{"default"},
|
expected: "stacks-1234567890",
|
||||||
expected: []string{"stacks-1234567890"},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid stack ID",
|
name: "invalid stack ID",
|
||||||
stackID: "invalid",
|
input: "invalid",
|
||||||
orgs: []string{"default"},
|
expected: "",
|
||||||
expected: nil,
|
|
||||||
expectedErr: "invalid stack id: invalid",
|
expectedErr: "invalid stack id: invalid",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "multiple orgs and no stack ID",
|
|
||||||
stackID: "",
|
|
||||||
orgs: []string{"default", "org-2"},
|
|
||||||
expected: []string{"default", "org-2"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
fakeOrgService := &mockOrgService{
|
result, err := GetNamespace(tt.input)
|
||||||
SearchFunc: func(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
|
||||||
orgs := make([]*org.OrgDTO, len(tt.orgs))
|
|
||||||
for i, o := range tt.orgs {
|
|
||||||
orgs[i] = &org.OrgDTO{ID: int64(i + 1), Name: o}
|
|
||||||
}
|
|
||||||
return orgs, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
result, err := GetNamespaces(context.Background(), tt.stackID, fakeOrgService)
|
|
||||||
if tt.expectedErr != "" {
|
if tt.expectedErr != "" {
|
||||||
assert.EqualError(t, err, tt.expectedErr)
|
assert.EqualError(t, err, tt.expectedErr)
|
||||||
} else {
|
} else {
|
||||||
@@ -65,12 +44,3 @@ func TestGetNamespaces(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockOrgService struct {
|
|
||||||
org.Service
|
|
||||||
SearchFunc func(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
|
||||||
return m.SearchFunc(ctx, query)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,23 +23,21 @@ const defaultEvaluationInterval = 7 * 24 * time.Hour // 7 days
|
|||||||
const defaultMaxHistory = 10
|
const defaultMaxHistory = 10
|
||||||
|
|
||||||
var (
|
var (
|
||||||
waitInterval = 5 * time.Second
|
waitInterval = 5 * time.Second
|
||||||
waitMaxRetries = 3
|
waitMaxRetries = 3
|
||||||
evalIntervalRandomVariation = 1 * time.Hour
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Runner is a "runnable" app used to be able to expose and API endpoint
|
// Runner is a "runnable" app used to be able to expose and API endpoint
|
||||||
// with the existing checks types. This does not need to be a CRUD resource, but it is
|
// with the existing checks types. This does not need to be a CRUD resource, but it is
|
||||||
// the only way existing at the moment to expose the check types.
|
// the only way existing at the moment to expose the check types.
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
checkRegistry checkregistry.CheckService
|
checkRegistry checkregistry.CheckService
|
||||||
checksClient resource.Client
|
client resource.Client
|
||||||
typesClient resource.Client
|
typesClient resource.Client
|
||||||
defaultEvalInterval time.Duration
|
evaluationInterval time.Duration
|
||||||
maxHistory int
|
maxHistory int
|
||||||
log logging.Logger
|
namespace string
|
||||||
orgService org.Service
|
log logging.Logger
|
||||||
stackID string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRunner creates a new Runner.
|
// NewRunner creates a new Runner.
|
||||||
@@ -51,7 +48,6 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
return nil, fmt.Errorf("invalid config type")
|
return nil, fmt.Errorf("invalid config type")
|
||||||
}
|
}
|
||||||
checkRegistry := specificConfig.CheckRegistry
|
checkRegistry := specificConfig.CheckRegistry
|
||||||
orgService := specificConfig.OrgService
|
|
||||||
evalInterval, err := getEvaluationInterval(specificConfig.PluginConfig)
|
evalInterval, err := getEvaluationInterval(specificConfig.PluginConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -60,6 +56,10 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
namespace, err := checks.GetNamespace(specificConfig.StackID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare storage client
|
// Prepare storage client
|
||||||
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
||||||
@@ -73,112 +73,73 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Runner{
|
return &Runner{
|
||||||
checkRegistry: checkRegistry,
|
checkRegistry: checkRegistry,
|
||||||
checksClient: client,
|
client: client,
|
||||||
typesClient: typesClient,
|
typesClient: typesClient,
|
||||||
defaultEvalInterval: evalInterval,
|
evaluationInterval: evalInterval,
|
||||||
maxHistory: maxHistory,
|
maxHistory: maxHistory,
|
||||||
log: log.With("runner", "advisor.checkscheduler"),
|
namespace: namespace,
|
||||||
orgService: orgService,
|
log: log.With("runner", "advisor.checkscheduler"),
|
||||||
stackID: specificConfig.StackID,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) Run(ctx context.Context) error {
|
func (r *Runner) Run(ctx context.Context) error {
|
||||||
logger := r.log.WithContext(ctx)
|
logger := r.log.WithContext(ctx)
|
||||||
if r.stackID == "" && r.orgService == nil {
|
|
||||||
logger.Debug("Check scheduler disabled")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We still need the context to eventually be cancelled to exit this function
|
// We still need the context to eventually be cancelled to exit this function
|
||||||
// but we don't want the requests to fail because of it
|
// but we don't want the requests to fail because of it
|
||||||
ctxWithoutCancel := context.WithoutCancel(ctx)
|
ctxWithoutCancel := context.WithoutCancel(ctx)
|
||||||
|
lastCreated, err := r.checkLastCreated(ctxWithoutCancel, logger)
|
||||||
// Determine namespaces based on StackID or OrgID
|
|
||||||
namespaces, err := checks.GetNamespaces(ctxWithoutCancel, r.stackID, r.orgService)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get namespaces: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Debug("Scheduling checks", "namespaces", len(namespaces))
|
|
||||||
|
|
||||||
// Get the last created time for this specific namespace
|
|
||||||
lastCreatedMap, err := r.checkLastCreated(ctx, logger, namespaces)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error getting last check creation time", "error", err)
|
logger.Error("Error getting last check creation time", "error", err)
|
||||||
return err
|
// Wait for interval to create the next scheduled check
|
||||||
}
|
lastCreated = time.Now()
|
||||||
|
} else {
|
||||||
// If there are checks already created, run an initial cleanup
|
// do an initial creation if necessary
|
||||||
for _, namespace := range namespaces {
|
if lastCreated.IsZero() {
|
||||||
logger = logger.With("namespace", namespace)
|
err = r.createChecks(ctxWithoutCancel, logger)
|
||||||
lastCreated := lastCreatedMap[namespace]
|
if err != nil {
|
||||||
|
logger.Error("Error creating new check reports", "error", err)
|
||||||
if !lastCreated.IsZero() {
|
} else {
|
||||||
err = r.cleanupChecks(ctx, logger, namespace)
|
lastCreated = time.Now()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Run an initial cleanup to remove old checks
|
||||||
|
err = r.cleanupChecks(ctxWithoutCancel, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error cleaning up old check reports", "error", err)
|
logger.Error("Error cleaning up old check reports", "error", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = r.markUnprocessedChecks(ctx, logger, namespace)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Error marking unprocessed checks", "error", err)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextEvalTime := r.getNextEvalTime(r.defaultEvalInterval, lastCreatedMap)
|
nextSendInterval := getNextSendInterval(lastCreated, r.evaluationInterval)
|
||||||
ticker := time.NewTicker(nextEvalTime)
|
ticker := time.NewTicker(nextSendInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
// Get the current last created time for this namespace
|
err = r.createChecks(ctxWithoutCancel, logger)
|
||||||
lastCreatedMap, err := r.checkLastCreated(ctx, logger, namespaces)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error getting last check creation time", "error", err)
|
logger.Error("Error creating new check reports", "error", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, namespace := range namespaces {
|
err = r.cleanupChecks(ctxWithoutCancel, logger)
|
||||||
logger = logger.With("namespace", namespace)
|
if err != nil {
|
||||||
lastCreated := lastCreatedMap[namespace]
|
logger.Error("Error cleaning up old check reports", "error", err)
|
||||||
|
|
||||||
// If there are checks already created and they are older than the evaluation interval
|
|
||||||
// then we can automatically create more
|
|
||||||
if !lastCreated.IsZero() && lastCreated.Before(time.Now().Add(-r.defaultEvalInterval)) {
|
|
||||||
err = r.createChecks(ctx, logger, namespace)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Error creating new check reports", "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up old checks to avoid going over the limit
|
|
||||||
err = r.cleanupChecks(ctx, logger, namespace)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Error cleaning up old check reports", "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the last created time with the new created checks
|
|
||||||
lastCreatedMap[namespace] = time.Now()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the ticker to the next send interval
|
if nextSendInterval != r.evaluationInterval {
|
||||||
nextEvalTime = r.getNextEvalTime(r.defaultEvalInterval, lastCreatedMap)
|
nextSendInterval = r.evaluationInterval
|
||||||
ticker.Reset(nextEvalTime)
|
}
|
||||||
|
ticker.Reset(nextSendInterval)
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespace string) ([]resource.Object, error) {
|
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resource.Object, error) {
|
||||||
list, err := r.checksClient.List(ctx, namespace, resource.ListOptions{
|
list, err := r.client.List(ctx, r.namespace, resource.ListOptions{
|
||||||
Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation
|
Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -188,7 +149,7 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespac
|
|||||||
checks := list.GetItems()
|
checks := list.GetItems()
|
||||||
for list.GetContinue() != "" {
|
for list.GetContinue() != "" {
|
||||||
logger.Debug("List has continue token, listing next page", "continue", list.GetContinue())
|
logger.Debug("List has continue token, listing next page", "continue", list.GetContinue())
|
||||||
list, err = r.checksClient.List(ctx, namespace, resource.ListOptions{Continue: list.GetContinue(), Limit: 1000})
|
list, err = r.client.List(ctx, r.namespace, resource.ListOptions{Continue: list.GetContinue(), Limit: 1000})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -197,48 +158,38 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespac
|
|||||||
return checks, nil
|
return checks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkLastCreated returns the creation time of the last check created for a specific namespace.
|
// checkLastCreated returns the creation time of the last check created
|
||||||
// This assumes that the checks are created in batches so a batch will have a similar creation time.
|
// regardless of its ID. This assumes that the checks are created in batches
|
||||||
|
// so a batch will have a similar creation time.
|
||||||
// In case it finds an unprocessed check from a previous run, it will set it to error.
|
// In case it finds an unprocessed check from a previous run, it will set it to error.
|
||||||
func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger, namespaces []string) (map[string]time.Time, error) {
|
func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger) (time.Time, error) {
|
||||||
lastCreated := map[string]time.Time{}
|
checkList, err := r.listChecks(ctx, log)
|
||||||
for _, namespace := range namespaces {
|
if err != nil {
|
||||||
checkList, err := r.listChecks(ctx, log, namespace)
|
return time.Time{}, err
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
lastCreated := time.Time{}
|
||||||
|
for _, item := range checkList {
|
||||||
|
itemCreated := item.GetCreationTimestamp().Time
|
||||||
|
if itemCreated.After(lastCreated) {
|
||||||
|
lastCreated = itemCreated
|
||||||
}
|
}
|
||||||
for _, item := range checkList {
|
|
||||||
itemCreated := item.GetCreationTimestamp().Time
|
// If the check is unprocessed, set it to error
|
||||||
if itemCreated.After(lastCreated[namespace]) {
|
if checks.GetStatusAnnotation(item) == "" {
|
||||||
lastCreated[namespace] = itemCreated
|
log.Info("Check is unprocessed, marking as error", "check", item.GetStaticMetadata().Identifier())
|
||||||
|
err := checks.SetStatusAnnotation(ctx, r.client, item, checks.StatusAnnotationError)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error setting check status to error", "error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lastCreated, nil
|
return lastCreated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) markUnprocessedChecks(ctx context.Context, log logging.Logger, namespace string) error {
|
|
||||||
checkList, err := r.listChecks(ctx, log, namespace)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, item := range checkList {
|
|
||||||
if checks.GetStatusAnnotation(item) == "" {
|
|
||||||
log.Info("Check is unprocessed, marking as error", "check", item.GetStaticMetadata().Identifier())
|
|
||||||
err := checks.SetStatusAnnotation(ctx, r.checksClient, item, checks.StatusAnnotationError)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error setting check status to error", "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createChecks creates a new check for each check type in the registry.
|
// createChecks creates a new check for each check type in the registry.
|
||||||
func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namespace string) error {
|
func (r *Runner) createChecks(ctx context.Context, logger logging.Logger) error {
|
||||||
// List existing CheckType objects
|
// List existing CheckType objects
|
||||||
list, err := r.typesClient.List(ctx, namespace, resource.ListOptions{})
|
list, err := r.typesClient.List(ctx, r.namespace, resource.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error listing check types: %w", err)
|
return fmt.Errorf("error listing check types: %w", err)
|
||||||
}
|
}
|
||||||
@@ -248,7 +199,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
|
|||||||
for !allChecksRegistered && retryCount < waitMaxRetries {
|
for !allChecksRegistered && retryCount < waitMaxRetries {
|
||||||
logger.Info("Waiting for all check types to be registered", "retryCount", retryCount, "waitInterval", waitInterval)
|
logger.Info("Waiting for all check types to be registered", "retryCount", retryCount, "waitInterval", waitInterval)
|
||||||
time.Sleep(waitInterval)
|
time.Sleep(waitInterval)
|
||||||
list, err = r.typesClient.List(ctx, namespace, resource.ListOptions{})
|
list, err = r.typesClient.List(ctx, r.namespace, resource.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error listing check types: %w", err)
|
return fmt.Errorf("error listing check types: %w", err)
|
||||||
}
|
}
|
||||||
@@ -266,7 +217,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
|
|||||||
obj := &advisorv0alpha1.Check{
|
obj := &advisorv0alpha1.Check{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
GenerateName: "check-",
|
GenerateName: "check-",
|
||||||
Namespace: namespace,
|
Namespace: r.namespace,
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
checks.TypeLabel: checkType.Spec.Name,
|
checks.TypeLabel: checkType.Spec.Name,
|
||||||
},
|
},
|
||||||
@@ -274,7 +225,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
|
|||||||
Spec: advisorv0alpha1.CheckSpec{},
|
Spec: advisorv0alpha1.CheckSpec{},
|
||||||
}
|
}
|
||||||
id := obj.GetStaticMetadata().Identifier()
|
id := obj.GetStaticMetadata().Identifier()
|
||||||
_, err := r.checksClient.Create(ctx, id, obj, resource.CreateOptions{})
|
_, err := r.client.Create(ctx, id, obj, resource.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating check: %w", err)
|
return fmt.Errorf("error creating check: %w", err)
|
||||||
}
|
}
|
||||||
@@ -283,13 +234,13 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cleanupChecks deletes the olders checks if the number of checks exceeds the limit.
|
// cleanupChecks deletes the olders checks if the number of checks exceeds the limit.
|
||||||
func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger, namespace string) error {
|
func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger) error {
|
||||||
checkList, err := r.listChecks(ctx, logger, namespace)
|
checkList, err := r.listChecks(ctx, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("Cleaning up checks", "namespace", namespace, "numChecks", len(checkList))
|
logger.Debug("Cleaning up checks", "numChecks", len(checkList))
|
||||||
|
|
||||||
// organize checks by type
|
// organize checks by type
|
||||||
checksByType := map[string][]resource.Object{}
|
checksByType := map[string][]resource.Object{}
|
||||||
@@ -317,7 +268,7 @@ func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger, names
|
|||||||
for i := 0; i < len(checks)-r.maxHistory; i++ {
|
for i := 0; i < len(checks)-r.maxHistory; i++ {
|
||||||
check := checks[i]
|
check := checks[i]
|
||||||
id := check.GetStaticMetadata().Identifier()
|
id := check.GetStaticMetadata().Identifier()
|
||||||
err := r.checksClient.Delete(ctx, id, resource.DeleteOptions{})
|
err := r.client.Delete(ctx, id, resource.DeleteOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error deleting check: %w", err)
|
return fmt.Errorf("error deleting check: %w", err)
|
||||||
}
|
}
|
||||||
@@ -342,28 +293,15 @@ func getEvaluationInterval(pluginConfig map[string]string) (time.Duration, error
|
|||||||
return evaluationInterval, nil
|
return evaluationInterval, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) getNextEvalTime(defaultEvaluationInterval time.Duration, lastCreated map[string]time.Time) time.Duration {
|
func getNextSendInterval(lastCreated time.Time, evaluationInterval time.Duration) time.Duration {
|
||||||
nextEvalTime := defaultEvaluationInterval
|
nextSendInterval := time.Until(lastCreated.Add(evaluationInterval))
|
||||||
|
// Add random variation of one hour
|
||||||
// Get the oldest last created time
|
randomVariation := time.Duration(rand.Int63n(time.Hour.Nanoseconds()))
|
||||||
baseTime := time.Now()
|
nextSendInterval += randomVariation
|
||||||
for _, lastNamespacedCreated := range lastCreated {
|
if nextSendInterval < time.Minute {
|
||||||
if !lastNamespacedCreated.IsZero() && lastNamespacedCreated.Before(baseTime) {
|
nextSendInterval = 1 * time.Minute
|
||||||
baseTime = lastNamespacedCreated
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return nextSendInterval
|
||||||
// Calculate the next evaluation time and add random variation
|
|
||||||
nextEvalTime = time.Until(baseTime.Add(nextEvalTime))
|
|
||||||
randomVariation := time.Duration(rand.Int63n(evalIntervalRandomVariation.Nanoseconds()))
|
|
||||||
nextEvalTime += randomVariation
|
|
||||||
|
|
||||||
// Ensure we always return a positive duration to avoid ticker panics
|
|
||||||
if nextEvalTime <= 0 {
|
|
||||||
nextEvalTime = 1 * time.Millisecond
|
|
||||||
}
|
|
||||||
|
|
||||||
return nextEvalTime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMaxHistory(pluginConfig map[string]string) (int, error) {
|
func getMaxHistory(pluginConfig map[string]string) (int, error) {
|
||||||
|
|||||||
@@ -4,50 +4,26 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand/v2"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/logging"
|
"github.com/grafana/grafana-app-sdk/logging"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
waitInterval = 1 * time.Millisecond
|
|
||||||
evalIntervalRandomVariation = 1 * time.Millisecond
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestRunner_Run tests the main Run function with various scenarios
|
|
||||||
func TestRunner_Run(t *testing.T) {
|
func TestRunner_Run(t *testing.T) {
|
||||||
t.Run("handles context cancellation gracefully", func(t *testing.T) {
|
t.Run("does not crash when error on list", func(t *testing.T) {
|
||||||
runner := createTestRunner(&MockClient{}, &MockClient{})
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
cancel() // Cancel immediately
|
|
||||||
|
|
||||||
err := runner.Run(ctx)
|
|
||||||
assert.ErrorAs(t, err, &context.Canceled)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("handles timeout gracefully", func(t *testing.T) {
|
|
||||||
runner := createTestRunner(&MockClient{}, &MockClient{})
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
err := runner.Run(ctx)
|
|
||||||
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("handles check list error gracefully", func(t *testing.T) {
|
|
||||||
mockClient := &MockClient{
|
mockClient := &MockClient{
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
return nil, errors.New("list checks error")
|
return nil, errors.New("list error")
|
||||||
|
},
|
||||||
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
|
return &advisorv0alpha1.Check{}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,289 +33,352 @@ func TestRunner_Run(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := createTestRunner(mockClient, mockTypesClient)
|
runner := &Runner{
|
||||||
err := runner.Run(context.Background())
|
client: mockClient,
|
||||||
assert.ErrorContains(t, err, "list checks error")
|
typesClient: mockTypesClient,
|
||||||
|
log: &logging.NoOpLogger{},
|
||||||
|
evaluationInterval: 1 * time.Hour,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel()
|
||||||
|
err := runner.Run(ctx)
|
||||||
|
assert.ErrorAs(t, err, &context.Canceled)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRunner_Run_CheckCreation tests check creation scenarios
|
func TestRunner_checkLastCreated_ErrorOnList(t *testing.T) {
|
||||||
func TestRunner_Run_CheckCreation(t *testing.T) {
|
mockClient := &MockClient{
|
||||||
t.Run("does not create checks on first run when no previous checks exist", func(t *testing.T) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
checksCreated := []string{}
|
return nil, errors.New("list error")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
mockClient := &MockClient{
|
runner := &Runner{
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
client: mockClient,
|
||||||
// Return empty list - no previous checks
|
log: &logging.NoOpLogger{},
|
||||||
return &advisorv0alpha1.CheckList{Items: []advisorv0alpha1.Check{}}, nil
|
}
|
||||||
},
|
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
|
||||||
checksCreated = append(checksCreated, id.Name)
|
|
||||||
return obj, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
mockTypesClient := &MockClient{
|
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
assert.Error(t, err)
|
||||||
return &advisorv0alpha1.CheckTypeList{
|
assert.True(t, lastCreated.IsZero())
|
||||||
Items: []advisorv0alpha1.CheckType{
|
}
|
||||||
{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
func TestRunner_checkLastCreated_UnprocessedCheck(t *testing.T) {
|
||||||
Name: "test-check",
|
patchOperation := resource.PatchOperation{}
|
||||||
},
|
identifier := resource.Identifier{}
|
||||||
Spec: advisorv0alpha1.CheckTypeSpec{
|
|
||||||
Name: "test-check",
|
mockClient := &MockClient{
|
||||||
},
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
return &advisorv0alpha1.CheckList{
|
||||||
|
Items: []advisorv0alpha1.Check{
|
||||||
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "check-1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
},
|
||||||
},
|
}, nil
|
||||||
}
|
},
|
||||||
|
patchFunc: func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
|
||||||
|
patchOperation = patch.Operations[0]
|
||||||
|
identifier = id
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Create a mock check service with one check to match the check type
|
runner := &Runner{
|
||||||
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "test-check"}}}
|
client: mockClient,
|
||||||
runner := createTestRunnerWithRegistry(mockClient, mockTypesClient, mockCheckService)
|
log: &logging.NoOpLogger{},
|
||||||
|
}
|
||||||
|
|
||||||
err := runAndTimeout(runner)
|
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
|
||||||
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
assert.NoError(t, err)
|
||||||
// Should not create checks on first run when no previous checks exist
|
assert.True(t, lastCreated.IsZero())
|
||||||
assert.Empty(t, checksCreated, "Should not create checks on first run when no previous checks exist")
|
assert.Equal(t, "check-1", identifier.Name)
|
||||||
})
|
assert.Equal(t, "/metadata/annotations", patchOperation.Path)
|
||||||
|
expectedAnnotations := map[string]string{
|
||||||
|
checks.StatusAnnotation: "error",
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedAnnotations, patchOperation.Value)
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("creates checks when evaluation interval has passed", func(t *testing.T) {
|
func TestRunner_checkLastCreated_PaginatedResponse(t *testing.T) {
|
||||||
checksCreated := []string{}
|
// Create checks with different creation times
|
||||||
|
past := time.Now().Add(-1 * time.Hour)
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
mockClient := &MockClient{
|
mockClient := &MockClient{
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
// Return a check that was created long ago (past the evaluation interval)
|
if options.Continue == "" {
|
||||||
|
// First page - return oldest and middle checks with continue token
|
||||||
return &advisorv0alpha1.CheckList{
|
return &advisorv0alpha1.CheckList{
|
||||||
|
ListMeta: metav1.ListMeta{
|
||||||
|
Continue: "continue-token-123",
|
||||||
|
},
|
||||||
Items: []advisorv0alpha1.Check{
|
Items: []advisorv0alpha1.Check{
|
||||||
{
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "old-check",
|
Name: "check-1",
|
||||||
CreationTimestamp: metav1.NewTime(time.Now().Add(-15 * 24 * time.Hour)), // 15 days ago
|
CreationTimestamp: metav1.NewTime(past),
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
checks.StatusAnnotation: checks.StatusAnnotationProcessed,
|
checks.StatusAnnotation: "completed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "check-2",
|
||||||
|
CreationTimestamp: metav1.NewTime(past),
|
||||||
|
Annotations: map[string]string{
|
||||||
|
checks.StatusAnnotation: "completed",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
},
|
}
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
// Second page - verify continue token is passed and return newest check
|
||||||
checksCreated = append(checksCreated, id.Name)
|
assert.Equal(t, "continue-token-123", options.Continue)
|
||||||
return obj, nil
|
return &advisorv0alpha1.CheckList{
|
||||||
},
|
Items: []advisorv0alpha1.Check{
|
||||||
}
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
mockTypesClient := &MockClient{
|
Name: "check-3",
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
CreationTimestamp: metav1.NewTime(now),
|
||||||
return &advisorv0alpha1.CheckTypeList{
|
Annotations: map[string]string{
|
||||||
Items: []advisorv0alpha1.CheckType{
|
checks.StatusAnnotation: "completed",
|
||||||
{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "test-check",
|
|
||||||
},
|
|
||||||
Spec: advisorv0alpha1.CheckTypeSpec{
|
|
||||||
Name: "test-check",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
},
|
||||||
},
|
}, nil
|
||||||
}
|
},
|
||||||
|
|
||||||
// Create a mock check service with one check to match the check type
|
|
||||||
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "test-check"}}}
|
|
||||||
runner := createTestRunnerWithRegistry(mockClient, mockTypesClient, mockCheckService)
|
|
||||||
|
|
||||||
err := runAndTimeout(runner)
|
|
||||||
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
|
||||||
// Should create checks when the evaluation interval has passed
|
|
||||||
assert.Greater(t, len(checksCreated), 0, "Should create checks when evaluation interval has passed")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestRunner_Run_CheckCleanup tests check cleanup scenarios
|
|
||||||
func TestRunner_Run_CheckCleanup(t *testing.T) {
|
|
||||||
t.Run("cleans up old checks when limit exceeded", func(t *testing.T) {
|
|
||||||
checksDeleted := []string{}
|
|
||||||
|
|
||||||
// Create checks that exceed the max history limit
|
|
||||||
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+2)
|
|
||||||
for i := 0; i < defaultMaxHistory+2; i++ {
|
|
||||||
item := advisorv0alpha1.Check{}
|
|
||||||
item.SetName(fmt.Sprintf("check-%d", i))
|
|
||||||
item.SetLabels(map[string]string{
|
|
||||||
checks.TypeLabel: "test-type",
|
|
||||||
})
|
|
||||||
item.SetCreationTimestamp(metav1.NewTime(time.Now().Add(-time.Duration(i) * time.Hour)))
|
|
||||||
items = append(items, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
mockClient := &MockClient{
|
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
return &advisorv0alpha1.CheckList{Items: items}, nil
|
|
||||||
},
|
|
||||||
deleteFunc: func(ctx context.Context, id resource.Identifier, opts resource.DeleteOptions) error {
|
|
||||||
checksDeleted = append(checksDeleted, id.Name)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
mockTypesClient := &MockClient{
|
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := createTestRunner(mockClient, mockTypesClient)
|
|
||||||
|
|
||||||
err := runAndTimeout(runner)
|
|
||||||
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
|
||||||
// Should delete some checks due to cleanup
|
|
||||||
assert.Greater(t, len(checksDeleted), 0)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestRunner_Run_UnprocessedChecks tests handling of unprocessed checks
|
|
||||||
func TestRunner_Run_UnprocessedChecks(t *testing.T) {
|
|
||||||
t.Run("marks unprocessed checks as error", func(t *testing.T) {
|
|
||||||
patchOperations := []resource.PatchOperation{}
|
|
||||||
|
|
||||||
mockClient := &MockClient{
|
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
return &advisorv0alpha1.CheckList{
|
|
||||||
Items: []advisorv0alpha1.Check{
|
|
||||||
{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "unprocessed-check",
|
|
||||||
CreationTimestamp: metav1.NewTime(time.Now().Add(-1 * time.Hour)),
|
|
||||||
// No status annotation - unprocessed
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
patchFunc: func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
|
|
||||||
patchOperations = append(patchOperations, patch.Operations...)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
mockTypesClient := &MockClient{
|
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := createTestRunner(mockClient, mockTypesClient)
|
|
||||||
|
|
||||||
err := runAndTimeout(runner)
|
|
||||||
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
|
||||||
// Should patch unprocessed check with error status
|
|
||||||
assert.Greater(t, len(patchOperations), 0)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestRunner_Run_Pagination tests pagination handling
|
|
||||||
func TestRunner_Run_Pagination(t *testing.T) {
|
|
||||||
t.Run("handles paginated check lists", func(t *testing.T) {
|
|
||||||
callCount := 0
|
|
||||||
|
|
||||||
mockClient := &MockClient{
|
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
callCount++
|
|
||||||
if callCount == 1 {
|
|
||||||
return &advisorv0alpha1.CheckList{
|
|
||||||
ListMeta: metav1.ListMeta{Continue: "continue-token"},
|
|
||||||
Items: []advisorv0alpha1.Check{
|
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "check-1"}},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return &advisorv0alpha1.CheckList{
|
|
||||||
Items: []advisorv0alpha1.Check{
|
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "check-2"}},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
mockTypesClient := &MockClient{
|
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := createTestRunner(mockClient, mockTypesClient)
|
|
||||||
|
|
||||||
err := runAndTimeout(runner)
|
|
||||||
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
|
||||||
// Should handle pagination correctly
|
|
||||||
assert.GreaterOrEqual(t, callCount, 2)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions
|
|
||||||
|
|
||||||
// runAndTimeout runs a runner with a short timeout for testing purposes.
|
|
||||||
// This is used to terminate the runner's infinite loop in tests that don't specifically test timeout behavior.
|
|
||||||
func runAndTimeout(runner *Runner) error {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond)
|
|
||||||
defer cancel()
|
|
||||||
return runner.Run(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// createTestRunner creates a test runner with mock clients
|
|
||||||
func createTestRunner(checkClient, typesClient *MockClient) *Runner {
|
|
||||||
return createTestRunnerWithRegistry(checkClient, typesClient, &MockCheckService{checks: []checks.Check{}})
|
|
||||||
}
|
|
||||||
|
|
||||||
// createTestRunnerWithRegistry creates a test runner with mock clients and custom registry
|
|
||||||
func createTestRunnerWithRegistry(checkClient, typesClient *MockClient, checkRegistry checkregistry.CheckService) *Runner {
|
|
||||||
// Ensure mock clients have default implementations
|
|
||||||
if checkClient.listFunc == nil {
|
|
||||||
checkClient.listFunc = func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
return &advisorv0alpha1.CheckList{Items: []advisorv0alpha1.Check{}}, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if checkClient.createFunc == nil {
|
|
||||||
checkClient.createFunc = func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
runner := &Runner{
|
||||||
return obj, nil
|
client: mockClient,
|
||||||
}
|
log: &logging.NoOpLogger{},
|
||||||
}
|
}
|
||||||
if checkClient.deleteFunc == nil {
|
|
||||||
checkClient.deleteFunc = func(ctx context.Context, id resource.Identifier, opts resource.DeleteOptions) error {
|
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, now.Truncate(time.Second), lastCreated.Truncate(time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner_createChecks_ErrorOnCreate(t *testing.T) {
|
||||||
|
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "check-1"}}}
|
||||||
|
|
||||||
|
mockClient := &MockClient{
|
||||||
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
|
return nil, errors.New("create error")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockTypesClient := &MockClient{
|
||||||
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
checkType := &advisorv0alpha1.CheckType{}
|
||||||
|
checkType.Spec.Name = "check-1"
|
||||||
|
return &advisorv0alpha1.CheckTypeList{
|
||||||
|
Items: []advisorv0alpha1.CheckType{*checkType},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := &Runner{
|
||||||
|
checkRegistry: mockCheckService,
|
||||||
|
client: mockClient,
|
||||||
|
typesClient: mockTypesClient,
|
||||||
|
log: &logging.NoOpLogger{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := runner.createChecks(context.Background(), &logging.NoOpLogger{})
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner_createChecks_Success(t *testing.T) {
|
||||||
|
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "check-1"}}}
|
||||||
|
|
||||||
|
mockClient := &MockClient{
|
||||||
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
|
return &advisorv0alpha1.Check{}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockTypesClient := &MockClient{
|
||||||
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
checkType := &advisorv0alpha1.CheckType{}
|
||||||
|
checkType.Spec.Name = "check-1"
|
||||||
|
return &advisorv0alpha1.CheckTypeList{
|
||||||
|
Items: []advisorv0alpha1.CheckType{*checkType},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := &Runner{
|
||||||
|
checkRegistry: mockCheckService,
|
||||||
|
client: mockClient,
|
||||||
|
typesClient: mockTypesClient,
|
||||||
|
log: &logging.NoOpLogger{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := runner.createChecks(context.Background(), &logging.NoOpLogger{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner_cleanupChecks_ErrorOnList(t *testing.T) {
|
||||||
|
mockClient := &MockClient{
|
||||||
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
return nil, errors.New("list error")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := &Runner{
|
||||||
|
client: mockClient,
|
||||||
|
log: &logging.NoOpLogger{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner_cleanupChecks_WithinMax(t *testing.T) {
|
||||||
|
mockClient := &MockClient{
|
||||||
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
return &advisorv0alpha1.CheckList{
|
||||||
|
Items: []advisorv0alpha1.Check{{}, {}},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
||||||
|
return fmt.Errorf("shouldn't be called")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := &Runner{
|
||||||
|
client: mockClient,
|
||||||
|
log: &logging.NoOpLogger{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner_cleanupChecks_ErrorOnDelete(t *testing.T) {
|
||||||
|
mockClient := &MockClient{
|
||||||
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+1)
|
||||||
|
for i := 0; i < defaultMaxHistory+1; i++ {
|
||||||
|
item := advisorv0alpha1.Check{}
|
||||||
|
item.SetLabels(map[string]string{
|
||||||
|
checks.TypeLabel: "mock",
|
||||||
|
})
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
return &advisorv0alpha1.CheckList{
|
||||||
|
Items: items,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
||||||
|
return errors.New("delete error")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := &Runner{
|
||||||
|
client: mockClient,
|
||||||
|
maxHistory: defaultMaxHistory,
|
||||||
|
log: &logging.NoOpLogger{},
|
||||||
|
}
|
||||||
|
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
||||||
|
assert.ErrorContains(t, err, "delete error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunner_cleanupChecks_Success(t *testing.T) {
|
||||||
|
itemsDeleted := []string{}
|
||||||
|
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+1)
|
||||||
|
for i := 0; i < defaultMaxHistory+1; i++ {
|
||||||
|
item := advisorv0alpha1.Check{}
|
||||||
|
item.SetName(fmt.Sprintf("check-%d", i))
|
||||||
|
item.SetLabels(map[string]string{
|
||||||
|
checks.TypeLabel: "mock",
|
||||||
|
})
|
||||||
|
item.SetCreationTimestamp(metav1.NewTime(time.Time{}.Add(time.Duration(i) * time.Hour)))
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
// shuffle the items to ensure the oldest are deleted
|
||||||
|
rand.Shuffle(len(items), func(i, j int) { items[i], items[j] = items[j], items[i] })
|
||||||
|
|
||||||
|
mockClient := &MockClient{
|
||||||
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
return &advisorv0alpha1.CheckList{
|
||||||
|
Items: items,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
||||||
|
itemsDeleted = append(itemsDeleted, identifier.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
},
|
||||||
}
|
|
||||||
if checkClient.patchFunc == nil {
|
|
||||||
checkClient.patchFunc = func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, opts resource.PatchOptions, into resource.Object) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if typesClient.listFunc == nil {
|
runner := &Runner{
|
||||||
typesClient.listFunc = func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
client: mockClient,
|
||||||
// Return empty list to match the empty MockCheckService
|
maxHistory: defaultMaxHistory,
|
||||||
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
log: &logging.NoOpLogger{},
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Runner{
|
|
||||||
checkRegistry: checkRegistry,
|
|
||||||
checksClient: checkClient,
|
|
||||||
typesClient: typesClient,
|
|
||||||
defaultEvalInterval: 5 * time.Millisecond,
|
|
||||||
maxHistory: defaultMaxHistory,
|
|
||||||
log: &logging.NoOpLogger{},
|
|
||||||
orgService: &mockOrgService{orgs: []*org.OrgDTO{{ID: 1}}},
|
|
||||||
stackID: "",
|
|
||||||
}
|
}
|
||||||
|
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []string{"check-0"}, itemsDeleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock implementations
|
func Test_getEvaluationInterval(t *testing.T) {
|
||||||
|
t.Run("default", func(t *testing.T) {
|
||||||
|
interval, err := getEvaluationInterval(map[string]string{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 7*24*time.Hour, interval)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid", func(t *testing.T) {
|
||||||
|
interval, err := getEvaluationInterval(map[string]string{"evaluation_interval": "invalid"})
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Zero(t, interval)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("custom", func(t *testing.T) {
|
||||||
|
interval, err := getEvaluationInterval(map[string]string{"evaluation_interval": "1h"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, time.Hour, interval)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_getMaxHistory(t *testing.T) {
|
||||||
|
t.Run("default", func(t *testing.T) {
|
||||||
|
history, err := getMaxHistory(map[string]string{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 10, history)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid", func(t *testing.T) {
|
||||||
|
history, err := getMaxHistory(map[string]string{"max_history": "invalid"})
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Zero(t, history)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("custom", func(t *testing.T) {
|
||||||
|
history, err := getMaxHistory(map[string]string{"max_history": "5"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 5, history)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_getNextSendInterval(t *testing.T) {
|
||||||
|
lastCreated := time.Now().Add(-7 * 24 * time.Hour)
|
||||||
|
evaluationInterval := 7 * 24 * time.Hour
|
||||||
|
nextSendInterval := getNextSendInterval(lastCreated, evaluationInterval)
|
||||||
|
// The next send interval should be in < 1 hour
|
||||||
|
assert.True(t, nextSendInterval < time.Hour)
|
||||||
|
// Calculate the next send interval again and it should be different
|
||||||
|
nextSendInterval2 := getNextSendInterval(lastCreated, evaluationInterval)
|
||||||
|
assert.NotEqual(t, nextSendInterval, nextSendInterval2)
|
||||||
|
}
|
||||||
|
|
||||||
type MockClient struct {
|
type MockClient struct {
|
||||||
resource.Client
|
resource.Client
|
||||||
@@ -375,6 +414,7 @@ func (m *MockCheckService) Checks() []checks.Check {
|
|||||||
|
|
||||||
type mockCheck struct {
|
type mockCheck struct {
|
||||||
checks.Check
|
checks.Check
|
||||||
|
|
||||||
id string
|
id string
|
||||||
steps []checks.Step
|
steps []checks.Step
|
||||||
}
|
}
|
||||||
@@ -386,12 +426,3 @@ func (m *mockCheck) ID() string {
|
|||||||
func (m *mockCheck) Steps() []checks.Step {
|
func (m *mockCheck) Steps() []checks.Step {
|
||||||
return m.steps
|
return m.steps
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockOrgService struct {
|
|
||||||
org.Service
|
|
||||||
orgs []*org.OrgDTO
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
|
||||||
return m.orgs, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@@ -27,24 +26,24 @@ import (
|
|||||||
type Runner struct {
|
type Runner struct {
|
||||||
checkRegistry checkregistry.CheckService
|
checkRegistry checkregistry.CheckService
|
||||||
client resource.Client
|
client resource.Client
|
||||||
orgService org.Service
|
namespace string
|
||||||
stackID string
|
|
||||||
log logging.Logger
|
log logging.Logger
|
||||||
retryAttempts int
|
retryAttempts int
|
||||||
retryDelay time.Duration
|
retryDelay time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ app.Runnable = (*Runner)(nil)
|
|
||||||
|
|
||||||
// NewRunner creates a new Runner.
|
// NewRunner creates a new Runner.
|
||||||
func New(cfg app.Config, log logging.Logger) (*Runner, error) {
|
func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
||||||
// Read config
|
// Read config
|
||||||
specificConfig, ok := cfg.SpecificConfig.(checkregistry.AdvisorAppConfig)
|
specificConfig, ok := cfg.SpecificConfig.(checkregistry.AdvisorAppConfig)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid config type")
|
return nil, fmt.Errorf("invalid config type")
|
||||||
}
|
}
|
||||||
checkRegistry := specificConfig.CheckRegistry
|
checkRegistry := specificConfig.CheckRegistry
|
||||||
orgService := specificConfig.OrgService
|
namespace, err := checks.GetNamespace(specificConfig.StackID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare storage client
|
// Prepare storage client
|
||||||
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
||||||
@@ -56,8 +55,7 @@ func New(cfg app.Config, log logging.Logger) (*Runner, error) {
|
|||||||
return &Runner{
|
return &Runner{
|
||||||
checkRegistry: checkRegistry,
|
checkRegistry: checkRegistry,
|
||||||
client: client,
|
client: client,
|
||||||
orgService: orgService,
|
namespace: namespace,
|
||||||
stackID: specificConfig.StackID,
|
|
||||||
log: log.With("runner", "advisor.checktyperegisterer"),
|
log: log.With("runner", "advisor.checktyperegisterer"),
|
||||||
retryAttempts: 5,
|
retryAttempts: 5,
|
||||||
retryDelay: time.Second * 10,
|
retryDelay: time.Second * 10,
|
||||||
@@ -66,24 +64,36 @@ func New(cfg app.Config, log logging.Logger) (*Runner, error) {
|
|||||||
|
|
||||||
func (r *Runner) Run(ctx context.Context) error {
|
func (r *Runner) Run(ctx context.Context) error {
|
||||||
logger := r.log.WithContext(ctx)
|
logger := r.log.WithContext(ctx)
|
||||||
// If stackID is empty and OrgService is nil, do nothing (on-demand registration only)
|
for _, t := range r.checkRegistry.Checks() {
|
||||||
if r.stackID == "" && r.orgService == nil {
|
steps := t.Steps()
|
||||||
logger.Debug("Auto-registration of checktypes disabled")
|
stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
|
||||||
return nil
|
for i, s := range steps {
|
||||||
}
|
stepTypes[i] = advisorv0alpha1.CheckTypeStep{
|
||||||
|
Title: s.Title(),
|
||||||
// Determine namespaces based on StackID or OrgID
|
Description: s.Description(),
|
||||||
namespaces, err := checks.GetNamespaces(ctx, r.stackID, r.orgService)
|
StepID: s.ID(),
|
||||||
if err != nil {
|
Resolution: s.Resolution(),
|
||||||
return fmt.Errorf("failed to get namespaces: %w", err)
|
}
|
||||||
}
|
}
|
||||||
logger.Debug("Registering check types", "namespaces", len(namespaces))
|
obj := &advisorv0alpha1.CheckType{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
// Register check types in each namespace
|
Name: t.ID(),
|
||||||
for _, namespace := range namespaces {
|
Namespace: r.namespace,
|
||||||
err := r.RegisterCheckTypesInNamespace(ctx, logger, namespace)
|
Annotations: map[string]string{
|
||||||
|
checks.NameAnnotation: t.Name(),
|
||||||
|
// Flag to indicate feature availability
|
||||||
|
checks.RetryAnnotation: "1",
|
||||||
|
checks.IgnoreStepsAnnotation: "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: advisorv0alpha1.CheckTypeSpec{
|
||||||
|
Name: t.ID(),
|
||||||
|
Steps: stepTypes,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := r.registerCheckType(ctx, logger, t.ID(), obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to register check types in namespace %s: %w", namespace, err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -217,38 +227,3 @@ func isAPIServerShuttingDown(err error, logger logging.Logger) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) RegisterCheckTypesInNamespace(ctx context.Context, logger logging.Logger, namespace string) error {
|
|
||||||
for _, t := range r.checkRegistry.Checks() {
|
|
||||||
steps := t.Steps()
|
|
||||||
stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
|
|
||||||
for i, s := range steps {
|
|
||||||
stepTypes[i] = advisorv0alpha1.CheckTypeStep{
|
|
||||||
Title: s.Title(),
|
|
||||||
Description: s.Description(),
|
|
||||||
StepID: s.ID(),
|
|
||||||
Resolution: s.Resolution(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
obj := &advisorv0alpha1.CheckType{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: t.ID(),
|
|
||||||
Namespace: namespace,
|
|
||||||
Annotations: map[string]string{
|
|
||||||
checks.NameAnnotation: t.Name(),
|
|
||||||
// Flag to indicate feature availability
|
|
||||||
checks.RetryAnnotation: "1",
|
|
||||||
checks.IgnoreStepsAnnotation: "1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: advisorv0alpha1.CheckTypeSpec{
|
|
||||||
Name: t.ID(),
|
|
||||||
Steps: stepTypes,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if err := r.registerCheckType(ctx, logger, t.ID(), obj); err != nil {
|
|
||||||
return fmt.Errorf("failed to register check type %s: %w", t.ID(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
|
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@@ -68,17 +67,14 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
checks []checks.Check
|
checks []checks.Check
|
||||||
stackID string
|
|
||||||
orgService org.Service
|
|
||||||
getFunc func(ctx context.Context, id resource.Identifier) (resource.Object, error)
|
getFunc func(ctx context.Context, id resource.Identifier) (resource.Object, error)
|
||||||
createFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error)
|
createFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error)
|
||||||
updateFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error)
|
updateFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error)
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "successful create",
|
name: "successful create",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
||||||
},
|
},
|
||||||
@@ -89,9 +85,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists with different annotations, should update",
|
name: "resource exists with different annotations, should update",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -101,9 +96,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists with different steps, should update",
|
name: "resource exists with different steps, should update",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentSteps, nil
|
return existingObjectDifferentSteps, nil
|
||||||
},
|
},
|
||||||
@@ -113,9 +107,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists with same annotations and steps, should not update",
|
name: "resource exists with same annotations and steps, should not update",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectSameContent, nil
|
return existingObjectSameContent, nil
|
||||||
},
|
},
|
||||||
@@ -125,9 +118,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists, with custom annotations preserved",
|
name: "resource exists, with custom annotations preserved",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -140,9 +132,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "create error",
|
name: "create error",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
||||||
},
|
},
|
||||||
@@ -153,9 +144,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: errors.New("create error"),
|
expectedErr: errors.New("create error"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "update error",
|
name: "update error",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -165,9 +155,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: errors.New("update error"),
|
expectedErr: errors.New("update error"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "shutting down error",
|
name: "shutting down error",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "123",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -177,33 +166,14 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "cloud stack namespace",
|
name: "custom namespace",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
stackID: "456",
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
if obj.GetNamespace() != "stack-456" {
|
if obj.GetNamespace() != "custom-namespace" {
|
||||||
return nil, fmt.Errorf("expected namespace %s, got %s", "stack-456", obj.GetNamespace())
|
return nil, fmt.Errorf("expected namespace %s, got %s", "custom-namespace", obj.GetNamespace())
|
||||||
}
|
|
||||||
return obj, nil
|
|
||||||
},
|
|
||||||
expectedErr: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "multiple orgs",
|
|
||||||
checks: []checks.Check{newMockCheck},
|
|
||||||
stackID: "",
|
|
||||||
orgService: &mockOrgService{orgs: []*org.OrgDTO{{ID: 1, Name: "Org1"}, {ID: 2, Name: "Org2"}}},
|
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
|
||||||
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
|
||||||
},
|
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
|
||||||
// Should create in both org-1 and org-2 namespaces
|
|
||||||
ns := obj.GetNamespace()
|
|
||||||
if ns != "org-1" && ns != "org-2" {
|
|
||||||
return nil, fmt.Errorf("expected namespace org-1 or org-2, got %s", ns)
|
|
||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
},
|
},
|
||||||
@@ -213,10 +183,6 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
orgSvc := tt.orgService
|
|
||||||
if orgSvc == nil {
|
|
||||||
orgSvc = &mockOrgService{orgs: []*org.OrgDTO{}}
|
|
||||||
}
|
|
||||||
r := &Runner{
|
r := &Runner{
|
||||||
checkRegistry: &mockCheckRegistry{checks: tt.checks},
|
checkRegistry: &mockCheckRegistry{checks: tt.checks},
|
||||||
client: &mockClient{
|
client: &mockClient{
|
||||||
@@ -224,8 +190,7 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
createFunc: tt.createFunc,
|
createFunc: tt.createFunc,
|
||||||
updateFunc: tt.updateFunc,
|
updateFunc: tt.updateFunc,
|
||||||
},
|
},
|
||||||
orgService: orgSvc,
|
namespace: "custom-namespace",
|
||||||
stackID: tt.stackID,
|
|
||||||
log: logging.DefaultLogger,
|
log: logging.DefaultLogger,
|
||||||
retryAttempts: 1,
|
retryAttempts: 1,
|
||||||
retryDelay: 0,
|
retryDelay: 0,
|
||||||
@@ -333,12 +298,3 @@ func (m *mockClient) Update(ctx context.Context, id resource.Identifier, obj res
|
|||||||
}
|
}
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockOrgService struct {
|
|
||||||
org.Service
|
|
||||||
orgs []*org.OrgDTO
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
|
||||||
return m.orgs, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/authlib/types"
|
|
||||||
"github.com/grafana/grafana-app-sdk/logging"
|
"github.com/grafana/grafana-app-sdk/logging"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
@@ -318,12 +317,3 @@ func waitForRetryAnnotation(ctx context.Context, log logging.Logger, client reso
|
|||||||
log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry)
|
log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getOrgIDFromNamespace extracts the org ID from a namespace using the standard authlib parser.
|
|
||||||
func getOrgIDFromNamespace(namespace string) (int64, error) {
|
|
||||||
info, err := types.ParseNamespace(namespace)
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("failed to parse namespace %s: %w", namespace, err)
|
|
||||||
}
|
|
||||||
return info.OrgID, nil
|
|
||||||
}
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user