Compare commits

..

127 Commits

Author SHA1 Message Date
github-actions[bot]
84215c8047 Release: 12.2.2 (#114162)
* Update changelog

* Update version to 12.2.2

* update changelog

---------

Co-authored-by: grafana-delivery-bot[bot] <grafana-delivery-bot[bot]@users.noreply.github.com>
Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com>
2025-11-19 14:47:13 +00:00
Andres Torres
343ac92c45 [release-12.2.2] refactor(annotations): Allow skipping always on dashboard UID migrations (#114108)
refactor(annotations): Allow skipping always on dashboard UID migrations (#113780)

(cherry picked from commit b70c6a726f)
2025-11-18 17:18:27 -05:00
grafana-delivery-bot[bot]
8e40f581ef [release-12.2.2] Docs: Add secrets management beta API docs (#114115)
Co-authored-by: Matheus Macabu <macabu@users.noreply.github.com>
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
Co-authored-by: Jacob Valdez <jacob.valdez@grafana.com>
2025-11-18 17:52:33 +00:00
grafana-delivery-bot[bot]
1ce228784b [release-12.2.2] alerts docs: triage page (#114054)
alerts docs: triage page (#113869)

* alerts docs: triage page

documentation for the alert triage page

* public preview note added

* Update alert-triage.md

* prettier

* removed alerts triage references

* rename

* image

* prettier

(cherry picked from commit 441556d1a3)

Co-authored-by: Johnny Kartheiser <140559259+JohnnyK-Grafana@users.noreply.github.com>
2025-11-18 10:31:44 -06:00
grafana-delivery-bot[bot]
ce6e473d19 [release-12.2.2] CI: run publish artifacts on self-hosted runner (#114074)
CI: run publish artifacts on self-hosted runner (#114068)

run publish artifacts on self-hosted runner

(cherry picked from commit a553256b46)

Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com>
2025-11-18 09:56:28 +00:00
Jack Baldry
7f6371a873 [release-12.2.2] Restructure As code and developer resources (#113964) 2025-11-14 18:05:45 +00:00
Kevin Minehart
71cbf1c25a [release-12.2.2] CI: Make notify-pr workflow optional (#113904)
* CI: Make notify-pr workflow optional (#113896)

* CI: Make notify-pr workflow optional

* also set repo to the current repo

* fix find-pr

(cherry picked from commit d92cb9f7a6)
(cherry picked from commit 3b345a99bc)

* CI: Continue notify even on error

(cherry picked from commit 2e33b077f1)

* CI: Fix release-build bug; github.repository includes org (#113909)

* CI: Fix release-build bug; github.repository includes org

* set pipefail

* fix notify in release-build; this step should fail if it actually fails

(cherry picked from commit 9376d569cc)

* CI: release-build.yml missing pipe (#113915)

(cherry picked from commit 92ef1c4942)
2025-11-14 11:39:49 +00:00
grafana-delivery-bot[bot]
dc39aa123a [release-12.2.2] Stricter validation for redirect URLs (#113860)
Stricter validation for redirect URLs (#113852)

(cherry picked from commit 3f48a6358f)
2025-11-13 18:43:47 +01:00
grafana-delivery-bot[bot]
2df2d435bf [release-12.2.2] DashboardAPI: Remove manual slug creation in dashboards (#113519)
DashboardAPI: Remove manual slug creation in dashboards (#111657)

* remove slug creation on frontend due to slugify issues

* adjust tests

* fix

(cherry picked from commit 90da925985)

Co-authored-by: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com>
Co-authored-by: Sergej-Vlasov <sergej.s.vlasov@gmail.com>
2025-11-13 13:57:33 +00:00
grafana-delivery-bot[bot]
95e54677c0 [release-12.2.2] Playwright: fix timezone test to work at all times (#113840)
Playwright: fix timezone test to work at all times (#113827)

* fix timezone test to work at all times

* remove unused imports

(cherry picked from commit f5f0c1e6f6)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2025-11-13 13:50:01 +00:00
Matheus Macabu
51394e1c81 [release-12.2.2] Secrets: Fix MariaDB syntax error due to unsupported CTE syntax (#113770)
Secrets: Fix MariaDB syntax error due to unsupported CTE syntax (#111610) (#113690)

* Secrets: fix MariaDB syntax error due to unsupported CTE syntax (#111610)

* parametrize guid/created columns and re-generate test fixtures

---------


(cherry picked from commit 6c512dabdc)

Co-authored-by: Mike <mmelvin0@gmail.com>
2025-11-12 17:56:06 +01:00
Matheus Macabu
3d151f7517 [release-12.2.2] E2E: Improve ad-hoc filtering test (#113746)
E2E: Improve ad-hoc filtering test
2025-11-12 11:59:02 +00:00
Kevin Minehart
c48ccd3955 [release-12.2.2] use adhoc filters test from main (#113733)
use adhoc filters test from main
2025-11-12 12:00:14 +01:00
grafana-delivery-bot[bot]
cc5849e9c4 [release-12.2.2] DashboardScene: Ignore defaults changes when exiting edit mode (#113213)
* DashboardScene: Ignore defaults changes when exiting edit mode (#112796)

* exit dashboard without confirmation with only optional changes

* centralise

* clean up logic

* export to util

(cherry picked from commit 51b39d8c6e)

* Frontend tests: Fix for timechange (#113338)

(cherry picked from commit 6d9e28a59f)

---------

Co-authored-by: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com>
Co-authored-by: Sergej-Vlasov <sergej.s.vlasov@gmail.com>
Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
2025-11-11 10:30:17 +00:00
grafana-delivery-bot[bot]
68b77a9701 [release-12.2.2] docs: clarifying info on what's new lading page (#113641)
Co-authored-by: Jacob Valdez <jacob.valdez@grafana.com>
2025-11-07 22:28:44 +00:00
grafana-delivery-bot[bot]
883acf1bd3 [release-12.2.2] LibraryPanels: Improve getAllLibraryElements filter performance (#113599)
LibraryPanels: Improve `getAllLibraryElements` filter performance (#113544)

(cherry picked from commit 33390a1483)

Co-authored-by: Juan Cabanas <juan.cabanas@grafana.com>
2025-11-07 12:16:13 -03:00
grafana-delivery-bot[bot]
a917724465 [release-12.2.2] SCIM: Upgrade the User.UID field to allow for the new scim- prefix (#113521)
SCIM: Upgrade the User.UID field to allow for the new scim- prefix (#113500)

Upgrade the User.UID field to allow for the new scim- prefix

(cherry picked from commit ca5d898120)

Co-authored-by: linoman <2051016+linoman@users.noreply.github.com>
2025-11-06 19:05:13 +01:00
grafana-delivery-bot[bot]
ffed6cfeab [release-12.2.2] Update grafanacli-workflows.md with command link (#113532)
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-06 16:29:39 +00:00
grafana-delivery-bot[bot]
3696a9aadf [release-12.2.2] Docs: Git Sync permissions (#113431)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
2025-11-05 11:18:52 +01:00
grafana-delivery-bot[bot]
2f15f7f695 [release-12.2.2] fix(accesscontrol): Reduce memory usage in GroupScopesByActionContext (#113414)
fix(accesscontrol): Reduce memory usage in GroupScopesByActionContext (#112295)


(cherry picked from commit fbc81d2fd0)

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>
Co-authored-by: Dave Henderson <dave.henderson@grafana.com>
2025-11-04 17:23:47 +00:00
grafana-delivery-bot[bot]
a36d95abd3 [release-12.2.2] docs(alerting): add note about invalid numeric identifiers in templates (#113413)
docs(alerting): add note about invalid numeric identifiers in templates (#113269)

(cherry picked from commit ffa5e41bec)

Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com>
2025-11-04 11:15:21 -06:00
Isabel Matwawana
1d51a8c8a7 [v12.2.x] Docs: Clarify difference between "Add" and "Replace" for saved queries (#113374) 2025-11-04 09:09:24 -05:00
grafana-delivery-bot[bot]
ee12001ce7 [release-12.2.2] Docs: Full instance Git Sync notes (#113353)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
Co-authored-by: Roberto Jiménez Sánchez <roberto.jimenez@grafana.com>
2025-11-03 13:57:44 +00:00
grafana-delivery-bot[bot]
dc12aeb4ab [release-12.2.2] Table: Pill and JSON Cells should allow formatting (#113130)
Table: Pill and JSON Cells should allow formatting (#111951)

* Table: PillCell should use formatted text inside pills

* Table: JSONCell should use formatted text

* remove unused imports

(cherry picked from commit 237ab6c1b4)

Co-authored-by: Paul Marbach <paul.marbach@grafana.com>
2025-11-03 08:37:35 -05:00
grafana-delivery-bot[bot]
75d12036b8 [release-12.2.2] PublicDashboards: Dont call API on dashboard page if public dashboards is disabled (#113282)
PublicDashboards: Dont call API on dashboard page if public dashboards is disabled (#113273)

(cherry picked from commit 452fc04d1d)

Co-authored-by: Matheus Macabu <macabu@users.noreply.github.com>
2025-10-31 11:30:38 +00:00
grafana-delivery-bot[bot]
b344916377 [release-12.2.2] Annotations: Honor dashboardUID on dashboardsWithVisibleAnnotations (#113229)
Annotations: Honor dashboardUID on dashboardsWithVisibleAnnotations (#112350)

* Annotations: Honor dashboardUID on dashboardsWithVisibleAnnotations



---------


(cherry picked from commit 75a1846344)

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>
Co-authored-by: maicon <maiconscosta@gmail.com>
2025-10-30 14:27:04 -03:00
grafana-delivery-bot[bot]
eb0899aa9e [release-12.2.2] Docs: Plugins link to catalog (#113199)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
2025-10-30 10:45:45 +01:00
grafana-delivery-bot[bot]
a9d9dc264e [release-12.2.2] docs(alerting): clarify notification group deletion after group interval elapses (#113174)
docs(alerting): clarify notification group deletion after group interval elapses (#113160)

(cherry picked from commit 7eb8a9af99)

Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com>
2025-10-29 15:27:23 +00:00
grafana-delivery-bot[bot]
324ca8847c [release-12.2.2] Docs: Add query variable static options (#113169)
Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com>
2025-10-29 13:52:31 +00:00
grafana-delivery-bot[bot]
c3460a4038 [release-12.2.2] docs(alerting): add additional migration details (#113165)
docs(alerting): add additional migration details (#112383)

(cherry picked from commit 86bf99aaaa)

Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com>
2025-10-29 13:14:25 +00:00
grafana-delivery-bot[bot]
f639587fc9 [release-12.2.2] Update Git Sync and File provisioning status to private preview (#113162)
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
2025-10-29 14:07:25 +01:00
grafana-delivery-bot[bot]
6751fadc01 [release-12.2.2] Log TLS handshake EOF error as DEBUG instead INFO (#113098)
Log TLS handshake EOF error as DEBUG instead INFO (#112294)

* Log TLS handshake EOF error as DEBUG instead INFO



---------


(cherry picked from commit a75b01907d)

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>
Co-authored-by: maicon <maiconscosta@gmail.com>
2025-10-28 16:07:06 -03:00
grafana-delivery-bot[bot]
0f6741ff29 [release-12.2.2] Docs: Admin tweaks - Edits, weights (#113089)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
2025-10-28 13:24:16 +01:00
Irene Rodríguez
d76881cc92 [release-12.2.2] Docs: Fix markdown syntax for config options table (#112846)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Mihai Doarna <mihai.doarna@grafana.com>
Co-authored-by: jtvdez <jacob.valdez@grafana.com>
Fix markdown syntax for config options table (#112805)
2025-10-27 14:25:59 +00:00
grafana-delivery-bot[bot]
c001d12745 [release-12.2.2] Docs: Update saved queries permissions for Viewer role (#112979)
Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com>
2025-10-24 15:38:34 -04:00
Jack Baldry
0a29332f80 [v12.2] Restructure IAM documentation (#112930) 2025-10-24 12:48:29 +01:00
grafana-delivery-bot[bot]
06482877cb [release-12.2.2] DOCS: Added a warning about using timezone with macros in MSSQL (#112909)
DOCS: Added a warning about using timezone with macros in MSSQL (#112900)

added warning about using timezone with macros in MSSQL

(cherry picked from commit 64f6bd5348)

Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>
2025-10-23 21:31:13 +00:00
grafana-delivery-bot[bot]
7bbc1174d5 [release-12.2.2] pkg/build: Add nocgo option (#112882)
pkg/build: Add nocgo option (#112834)

Add nocgo option

(cherry picked from commit 2a0f149a63)

Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com>
2025-10-23 16:25:20 +00:00
grafana-delivery-bot[bot]
c94396d80a [release-12.2.2] Dashboards: Return the correct model in openapi spec (#112872)
Return the correct model (#112858)

(cherry picked from commit 0ba040e866)

Co-authored-by: Selene <selenepinillos@gmail.com>
2025-10-23 17:59:22 +02:00
grafana-delivery-bot[bot]
a46fcfc0c6 [release-12.2.2] Table: Update ad-hoc filter to use name instead of displayName (#112817) 2025-10-23 08:59:28 -04:00
grafana-delivery-bot[bot]
9990c74ab2 [release-12.2.2] Remove hipchat alert notification details (#112807)
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
2025-10-22 13:37:47 +00:00
grafana-delivery-bot[bot]
708fd7c6e8 [release-12.2.2] Docs: Added known limitations to SQL Expressions (#112760)
Docs: Added known limitations to SQL Expressions (#112676)

* initial new section creation

* added additional known limitations

* adding some clarification

(cherry picked from commit e5627bcc67)

Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>
2025-10-21 16:39:07 -05:00
grafana-delivery-bot[bot]
470edab706 [release-12.2.2] docs(alerting): clarify usage of templates in webhook custom payloads (#112755)
docs(alerting): clarify usage of templates in webhook custom payloads (#112672)

* docs(alerting): clarify usage of templates in webhook custom payloads

* Update docs/sources/alerting/configure-notifications/template-notifications/manage-notification-templates.md



---------


(cherry picked from commit fb5c5411f8)

Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com>
Co-authored-by: Johnny Kartheiser <140559259+JohnnyK-Grafana@users.noreply.github.com>
2025-10-21 18:49:20 +00:00
grafana-delivery-bot[bot]
569738c316 [release-12.2.1] Alerting: Fix unmarshalling of GettableStatus to include time intervals (#112734)
Alerting: Fix unmarshalling of GettableStatus to include time intervals (#112602)

* move test files into test-data

* add test for the bug

* populate time-intervals of gettableStatus config

(cherry picked from commit 5f9a51418c)

Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2025-10-21 13:27:31 -04:00
grafana-delivery-bot[bot]
c66f019dfc [release-12.2.1] Include author in patch creation (#112696)
Include author in patch creation (#112675)

Include author in security mirror

(cherry picked from commit ef2e62c852)

Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com>
2025-10-21 18:08:21 +02:00
grafana-delivery-bot[bot]
576d2e3cb5 [release-12.2.1] Tag / content discrepancy (#111889)
Co-authored-by: Clément Duveau <clement@duveau.eu>
2025-10-21 14:41:38 +00:00
github-actions[bot]
ef1a904cbe Release: 12.2.1 (#112736)
* Update changelog

* Update version to 12.2.1

---------

Co-authored-by: grafana-delivery-bot[bot] <grafana-delivery-bot[bot]@users.noreply.github.com>
2025-10-21 14:39:47 +00:00
Josh Hunt
563109b696 [release-12.2.1] CI: Remove OIDC debug step from npm publish (#112657)
CI: Remove OIDC debug step from npm publish (#112631)

(cherry picked from commit b0acfd1189)
2025-10-20 14:49:24 +00:00
linoman
f06bb75310 [release-12.2.1] Backport 112615 to release 12.2.1 (#112636)
Update validation of non-provisioned users rejection (#112615)

* Update validation of non-provisioned users rejection

* Align tests

(cherry picked from commit 0e4237b775)
2025-10-20 13:30:27 +02:00
grafana-delivery-bot[bot]
64b98e9866 [release-12.2.1] docs(alerting) Add examples of high-cardinality alerts (#112633)
docs(alerting) Add examples of high-cardinality alerts (#112311)

* docs(alerting) Add examples of high-cardinality alerts

* minor intro edits

(cherry picked from commit 9e505ea2de)

Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com>
2025-10-20 13:12:51 +02:00
grafana-delivery-bot[bot]
d5732fe526 [release-12.2.1] Docs: Git Sync resource reqs (#112592)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
2025-10-17 18:06:48 +02:00
grafana-delivery-bot[bot]
3d65272316 [release-12.2.1] Grammar: wrap in try/catch in case regex creation fails (#112600)
Grammar: wrap in try/catch in case regex creation fails (#112595)

* Grammar: wrap in try/catch in case regex creation fails

* Improve breadcrumbs

(cherry picked from commit bbb5322008)

Co-authored-by: Matias Chomicki <matias.chomicki@grafana.com>
2025-10-17 15:52:42 +00:00
grafana-delivery-bot[bot]
1029b8df35 [release-12.2.1] Docs: Manage multi-team access (#112500)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
Co-authored-by: Jacob Valdez <jacob.valdez@grafana.com>
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
Co-authored-by: Sarah Constant <sarahleejane@users.noreply.github.com>
2025-10-16 09:11:02 +00:00
grafana-delivery-bot[bot]
4da7576d4e [release-12.2.1] Docs: Add batch_wait_duration and batch_size_bytes to usage insights Loki exporter (#112416)
Docs: Add batch_wait_duration and batch_size_bytes to usage insights Loki exporter (#112408)

* Docs: Add batch_wait_duration and batch_size_bytes to usage insights Loki exporter

* Run linter

(cherry picked from commit 1c614fdc9a)

Co-authored-by: Matheus Macabu <macabu@users.noreply.github.com>
2025-10-15 10:35:27 +00:00
Mariell Hoversholm
e86240eb62 [release-12.2.1] Chore: Update Redis library to v9 (#112363) 2025-10-14 12:52:42 +02:00
Matheus Macabu
e6db6c929a [release-12.2.1] Go: Update to 1.25.3 (#112361)
Go: Update to 1.25.3
2025-10-14 10:23:35 +00:00
grafana-delivery-bot[bot]
b1f5d62c38 [release-12.2.1] Logs context: fix position on small viewports (#112343)
Logs context: fix position on small viewports (#112342)

(cherry picked from commit 6c726cf0ea)

Co-authored-by: Matias Chomicki <matias.chomicki@grafana.com>
2025-10-13 16:27:28 +00:00
grafana-delivery-bot[bot]
9bb79a0e8e [release-12.2.1] TimeSeries: Fix memory leak with boolean fields (#112290)
TimeSeries: Fix memory leak with boolean fields (#112252)


(cherry picked from commit 248c20a6b6)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
Co-authored-by: Paul Marbach <paul.marbach@grafana.com>
2025-10-10 15:05:26 +00:00
grafana-delivery-bot[bot]
664a91dc84 [release-12.2.1] GenAI: Fix uncaught error when panel title is missing (#112286) 2025-10-10 13:51:16 +00:00
grafana-delivery-bot[bot]
6ae40fc592 [release-12.2.1] Docs: Clarify role assignment to users and teams when using terraform (#112261)
Co-authored-by: Vardan Torosyan <vardants@gmail.com>
2025-10-10 09:04:32 +00:00
grafana-delivery-bot[bot]
208eb881d6 [release-12.2.1] Docs: Adding new entry to 12.2 whats new (#112235)
Docs: Adding new entry to 12.2 whats new (#112234)

(cherry picked from commit 5eb295d850)

Co-authored-by: Jacob Valdez <jacob.valdez@grafana.com>
2025-10-09 17:20:17 +00:00
grafana-delivery-bot[bot]
05e3befe99 [release-12.2.1] Auth: Fix render user OAuth passthrough (#112092)
Auth: Fix render user OAuth passthrough (#111636)

* devenv: fix volumes section when sources don't contain one

* wip

* Working correctly with improvedExternalSessionHandling on

* Remove not needed lines

* Working with the old flow, tests

* Handle compatibility with the feature toggle, tests wip

* Tests

* Cleanup

* Address feedback

* Align tests

* Add comment

* Fix issue with session removal after the invalidation of tokens

* Remove commented out code

* clean up

(cherry picked from commit 53f4803e98)

Co-authored-by: Misi <mgyongyosi@users.noreply.github.com>
2025-10-09 15:47:18 +02:00
grafana-delivery-bot[bot]
b3551d6d0d [release-12.2.1] Explore: Add missing height to logs in Explore (#112177)
Explore: Add missing height to logs in Explore (#112176)

* Explore: Add missing height to logs in Explore

* Add max height to controlled log rows

(cherry picked from commit a0fc683a67)

Co-authored-by: Matias Chomicki <matias.chomicki@grafana.com>
2025-10-08 18:42:10 +02:00
grafana-delivery-bot[bot]
46f2c100e0 [release-12.2.1] Docs: Clarify RBAC availability in documentation (#112173)
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
2025-10-08 15:20:24 +00:00
Matheus Macabu
d690b06941 [release-12.2.1] Go: Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 (#112156)
* Go: Update to 1.25.2

* golangci-lint: Update to 2.5.0

* Dependencies: Bump golang.org/x/net to v0.45.0

* Fix broken feature toggle test
2025-10-08 15:00:14 +02:00
Pepe Cano
37eeb82b5c [release-12.2.1] docs(alerting): Email contact point enhancements (#112121)
docs(alerting): Email contact point enhancements (#111944)

* docs(alerting): Email contact point enhancements

* minor content tweaks

(cherry picked from commit 5438df01a1)
2025-10-08 05:12:10 +02:00
grafana-delivery-bot[bot]
2a12896e81 [release-12.2.1] DOCS: Amazon CloudWatch data source docs revmp (#112132)
DOCS: Amazon CloudWatch data source docs revmp (#109945)

* started new configure doc

* updates to the configure doc

* worked on variables doc

* made edits

* query editor edits

* query editor updates

* continued with updates

* added updates

* additional updates, rewrite of auth doc

* finished query editor updates

* cleaned up the intro doc, added ref URIs to other docs

* some final edits

* more edits prior to PR creation

* ran prettier, added a screenshot

* linter fixes

* updates based on questions doc

* ran prettier

* updates based on feedback

* made more edits based on feedback

* more updates based on feedback

* updates based on feedback

* moved alerting under logs

* ran prettier

(cherry picked from commit 725a91e9eb)

Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>
2025-10-07 19:40:19 +00:00
Paul Marbach
10fe7d04e9 [release-12.2.1] Table: Backport the Safari 26 fixes to 12.2.1 (#111906)
* [release-12.2.1] Table: Disable virtualization, hover overflow, and scrollbar width resizing on Safari 26 (#111834)

* Table: Disable virtualization, hover overflow, and scrollbar width resizing on Safari 26

* pull obj def out of method

* [release-12.2.1] Table: Avoid overflow issues in Safari 26 (#111858)
2025-10-07 11:08:14 -04:00
grafana-delivery-bot[bot]
0c5602dd10 [release-12.2.1] Docs: Last note for GitSync for ObsCon (#112085)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
2025-10-07 16:50:31 +02:00
grafana-delivery-bot[bot]
0be513c593 [release-12.2.1] Docs: Git Sync - Tim's feedback (#112104)
Docs: Git Sync - Tim's feedback (#112098)

* Feedback

* Prettier

(cherry picked from commit 96b5f63711)

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
2025-10-07 15:08:42 +02:00
grafana-delivery-bot[bot]
89be22e8e8 [release-12.2.1] Prometheus: Prom Azure and AWS auth with mig info (#112072)
Prometheus: Prom Azure and AWS auth with mig info (#111142)

* docs for prom type mig

* andreas feedback

* update scripts and add forward settings issue

* make links internal

* prettier

* Update docs/sources/datasources/prometheus/configure/aws-authentication.md



* Update docs/sources/datasources/prometheus/configure/aws-authentication.md



* Apply suggestions from code review



* Update docs/sources/datasources/prometheus/configure/aws-authentication.md

* Apply suggestions from code review

* Update docs/sources/datasources/prometheus/configure/azure-authentication.md

* feedback

* prettier

* clarify the revert script is only for self-hosted

* Update docs/sources/datasources/prometheus/configure/aws-authentication.md



* Apply suggestions from code review



---------


(cherry picked from commit 96c24bc64c)

Co-authored-by: Andrew Hackmann <5140848+bossinc@users.noreply.github.com>
Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>
2025-10-06 16:53:54 -05:00
grafana-delivery-bot[bot]
52843f360e [release-12.2.1] Docs: Fixed a broken link on the Intro to Exemplars page (#112068)
Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
Fixed a broken link on the Intro to Exemplars page (#112025)
2025-10-06 17:24:56 +02:00
grafana-delivery-bot[bot]
623e927983 [release-12.2.1] Docs: OaC/Git Sync updates for Obs Con (#112066)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
Co-authored-by: Jack Baldry <jack.baldry@grafana.com>
2025-10-06 15:18:02 +00:00
Jacob Valdez
e188650524 [release-12.2.1] Update index.md (#112028) (#112064)
Co-authored-by: Michael Lamb <michael@michaellamb.dev>
2025-10-06 09:29:22 -05:00
Josh Hunt
aa00229a8b [release-12.2.1] NPM: Backport NPM publishing from main (#112000)
* Backport npm publishing workflow from main

* Ignore false-cjs in validate-npm-packages

(cherry picked from commit 6916b39439)
(cherry picked from commit 1aba469bab)

* Ignore untyped-resolutions for grafana-i18n in validate-npm-packages

(cherry picked from commit b250fe8d22)
2025-10-06 13:51:48 +01:00
grafana-delivery-bot[bot]
cda0661803 [release-12.2.1] Influx: Improve variable regex handling (#111941)
Influx: Improve variable regex handling (#111853)

(cherry picked from commit b50737a76c)

Co-authored-by: Andreas Christou <andreas.christou@grafana.com>
2025-10-03 15:22:19 +01:00
grafana-delivery-bot[bot]
5ebd75d3fb [release-12.2.1] docs(alerting): add settings for alert evaluation backoff retries (#111973)
docs(alerting): add settings for alert evaluation backoff retries (#111891)

* docs(alerting): add settings for alert evaluation backoff retries

* docs(alerting): add mention of backoff settings on the Error state docs

* fix vale prose

(cherry picked from commit 6248971d1e)

Co-authored-by: Pepe Cano <825430+ppcano@users.noreply.github.com>
2025-10-03 11:34:44 +02:00
Pepe Cano
71b3906cf8 [release-12.2.1] docs(alerting): alertingSaveStateCompressed is enabled by default (#111972)
* docs(alerting): `alertingSaveStateCompressed` is enabled by default (#111897)

(cherry picked from commit 7ed46fd321)

* update feature flag default state
2025-10-03 10:54:18 +02:00
grafana-delivery-bot[bot]
2ea9a8a6ed [release-12.2.1] Chore: Update on-prem stable release dates (#111953)
Chore: Update on-prem stable release dates (#111909)

* baldm0mma/ update release dates

* Update docs/sources/upgrade-guide/when-to-upgrade/index.md



---------


(cherry picked from commit 2f3c503182)

Co-authored-by: Jev Forsberg <46619047+baldm0mma@users.noreply.github.com>
Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com>
2025-10-02 10:10:28 -06:00
grafana-delivery-bot[bot]
fdd99e9653 [release-12.2.1] Docs: Add panel options section to dashboard settings (#111947)
Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com>
2025-10-02 15:21:16 +00:00
grafana-delivery-bot[bot]
03f738ea1d [release-12.2.1] Doc: Filter by value update (#111886)
* Doc: Filter by value update (#111881)

doc(transformation): filter by value

---------

Co-authored-by: Ihor Yeromin <yeryomin.igor@gmail.com>
2025-10-02 11:17:20 +02:00
grafana-delivery-bot[bot]
547c496b2d [release-12.2.1] [InfluxDB]: Remove version notices (#111850) 2025-09-30 15:11:07 -06:00
grafana-delivery-bot[bot]
0594304843 [release-12.2.1] LDAP Authentication: Fix URL to propagate username context as parameter (#111849)
LDAP Authentication: Fix URL to propagate username context as parameter (#111723)

Fix URL to propagate username context as parameter

(cherry picked from commit 7055ba9140)

Co-authored-by: Bradley <12028233+bradleypettit@users.noreply.github.com>
2025-09-30 17:08:04 -04:00
grafana-delivery-bot[bot]
57d0237fda [release-12.2.1] Plugins: Dependencies do not inherit parent URL for preinstall (#111769)
Plugins: Dependencies do not inherit parent URL for preinstall (#111762)

dependencies dont inehrit parent url for preinstall

(cherry picked from commit 073338ec29)

Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
2025-09-30 15:05:02 +01:00
grafana-delivery-bot[bot]
87fa31e57b [release-12.2.1] Geomap: Fix duplicated data links (#111772) 2025-09-30 08:21:39 -05:00
grafana-delivery-bot[bot]
26359899d5 [release-12.2.1] feat(ci): Allow overriding runs-on for publish-artifact workflow (#111765)
feat(ci): Allow overriding runs-on for publish-artifact workflow (#111695)


(cherry picked from commit ffe85d7c7e)

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>
Co-authored-by: Dave Henderson <dave.henderson@grafana.com>
2025-09-29 12:39:54 -05:00
grafana-delivery-bot[bot]
b841dfa2bc [release-12.2.1] Documentation Node graph broken link (#111757)
Co-authored-by: Jara Suárez de Puga García <jara.suarezdepuga@grafana.com>
Co-authored-by: Isabel Matwawana <isabel.matwawana@grafana.com>
2025-09-29 12:04:41 -04:00
grafana-delivery-bot[bot]
e675b6a032 [release-12.2.1] Docs: provisioning fix (#111749)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
fix (#111744)
2025-09-29 16:05:32 +02:00
grafana-delivery-bot[bot]
271f268d68 [release-12.2.1] Docs: Edits to OaC/Git Sync (#111732)
Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
Co-authored-by: Irene Rodriguez <irene.rodriguez@grafana.com>
2025-09-29 12:25:40 +02:00
grafana-delivery-bot[bot]
b059912f7d [release-12.2.1] Refactor SCIM provisioning documentation (#111731)
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
2025-09-29 12:20:30 +02:00
John Troy
24df78fb4e [release-12.2.1] Docs: Fix broken links in SAML docs (#111693)
Docs: Fix broken links in SAML docs (#111039)

* Rename this heading to match the link in 'Request Initiation'

* Fix link to 'Configure SAML using the Grafana configuration file' and make the link text match

(cherry picked from commit 004f30fcb7)
2025-09-26 20:16:15 +02:00
grafana-delivery-bot[bot]
dcbbf64aa0 [release-12.2.1] Docs: Marking the image renderer plugin as deprecated (#111670)
Co-authored-by: Jacob Valdez <jacob.valdez@grafana.com>
2025-09-26 14:14:03 +02:00
grafana-delivery-bot[bot]
ce8c46fb91 [release-12.2.1] Docs: Fix link reference in Generic OAuth documentation (#111656)
Co-authored-by: Andrew Hackmann <5140848+bossinc@users.noreply.github.com>
Fix link reference in Generic OAuth documentation (#111647)
2025-09-26 11:20:03 +02:00
grafana-delivery-bot[bot]
0f8f5c86ef [release-12.2.1] FlameGraph: Ensure total is only counted once for recursive function calls (#111606)
FlameGraph: Ensure total is only counted once for recursive function calls (#111548)

grafana-flamegraph: Ensure total is only counted once for recursive function calls

Example flamegraph: https://flamegraph.com/share/2bb59df3-9930-11f0-94ec-760777e76ccd

(cherry picked from commit c5f6318b7b)

Co-authored-by: Christian Simon <simon@swine.de>
2025-09-26 10:39:43 +02:00
grafana-delivery-bot[bot]
111c53f9fd [release-12.2.1] Docs: Update saved queries feature availability details (#111644)
Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com>
2025-09-25 15:46:29 -04:00
grafana-delivery-bot[bot]
cc8928a6a7 [release-12.2.1] DOCS: FIx broken link on RBAC for app plugins page (#111633)
DOCS: FIx broken link on RBAC for app plugins page (#111574)

fixed incorrect RefURI

(cherry picked from commit 0bf37742f1)

Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>
2025-09-25 10:56:36 -05:00
grafana-delivery-bot[bot]
46956a2997 [release-12.2.1] Fix grafanactl resource pull command syntax (#111608)
Co-authored-by: Irene Rodríguez <irene.rodriguez@grafana.com>
Fix grafanactl resource pull command syntax (#111465)
2025-09-25 14:49:17 +02:00
grafana-delivery-bot[bot]
af460952d5 [release-12.2.1] Chore: Fix @grafana/alerting package repo (#111532)
Chore: Fix @grafana/alerting package repo (#110939)

(cherry picked from commit ab3c93b279)

Co-authored-by: Josh Hunt <joshhunt@users.noreply.github.com>
2025-09-24 10:13:31 +01:00
Kevin Minehart
3a8bff55cd update missing npm publish scripts 2025-09-23 10:30:24 -05:00
Kevin Minehart
7223130454 update release-npm and validate script 2025-09-23 09:54:45 -05:00
grafana-delivery-bot[bot]
d53bf3d740 [release-12.2.1] docs: reorder whats new posts and include plugin translation (#111484)
Co-authored-by: Jacob Valdez <jacob.valdez@grafana.com>
2025-09-23 16:40:33 +02:00
Jacob Valdez
6a046831fc Docs: What's new and Upgrade guide v12.2 (#110727) (#111472) 2025-09-23 13:55:49 +02:00
grafana-delivery-bot[bot]
9b4414de27 Release: Bump version to 12.2.1 (#111415)
bump version 12.2.1

Co-authored-by: grafana-delivery-bot[bot] <grafana-delivery-bot[bot]@users.noreply.github.com>
2025-09-19 14:00:37 -05:00
Josh Hunt
c7b629d3bc [release-12.2.1] CI: Backport release-npm.yml (#111396)
backport release-npm.yml from main
2025-09-19 18:31:47 +01:00
grafana-delivery-bot[bot]
bbd19baaaf [release-12.2.1] Dashboards: Fix missing Ctrl+O keyboard shortcut for crosshair toggle (#111402)
Dashboards: Fix missing Ctrl+O keyboard shortcut for crosshair toggle (#111310)

* Dashboard Scenes: Fix missing Ctrl+O keyboard shortcut for crosshair toggle

- Add missing mod+o keybind to dashboard scenes keyboard shortcuts
- Implement crosshair state cycling (Default -> Crosshair -> Tooltip -> Default)
- Add comprehensive unit tests for keyboard shortcuts functionality
- Add e2e test to verify shortcut works and prevents browser file dialog
- Fix ensures parity between legacy and scenes dashboard implementations

Fixes issue where Ctrl+O/Cmd+O was opening browser file dialog instead of
toggling shared crosshair modes in scenes-based dashboards.

* Remove waitForTimeout from e2e test

- Replace arbitrary timeouts with proper element waiting
- Use waitFor with visible state instead of setTimeout
- Improve test reliability and follow Playwright best practices

* Optimize e2e test for crosshair keyboard shortcut

- Remove unnecessary console logging and timeout settings
- Simplify assertions to only check the currently selected radio button
- Improve test performance by reducing DOM queries
- Focus on essential functionality verification

* Fix linting

(cherry picked from commit c0ce4ff1f2)

Co-authored-by: Ivan Ortega Alba <ivanortegaalba@gmail.com>
2025-09-19 16:21:15 +00:00
grafana-delivery-bot[bot]
5a2ab9b8b0 [release-12.2.1] Auth: Add SCIM settings permission to auth config writer role (#111398)
Auth: Add SCIM settings permission to auth config writer role (#111326)

* Auth: add SCIM settings permission to authentication config writer role

* make update-workspace

(cherry picked from commit 1ef27e9749)

Co-authored-by: colin-stuart <colindonstuart@gmail.com>
2025-09-19 10:46:31 -05:00
grafana-delivery-bot[bot]
d1bd29aa3b [release-12.2.1] Page limit config for dashboards with visible annotations (#111379)
Page limit config for dashboards with visible annotations (#110911)

* Page limit config for dashboards with visible annotations



---------


(cherry picked from commit 77fa3333e4)

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>
Co-authored-by: maicon <maiconscosta@gmail.com>
2025-09-19 11:10:55 -03:00
grafana-delivery-bot[bot]
7d205c7dee [release-12.2.1] CI: Fix NPM workflow inputs (#111350)
Fix referring to inputs (#111345)

(cherry picked from commit 1d6c1da94f)

Co-authored-by: Josh Hunt <joshhunt@users.noreply.github.com>
2025-09-18 23:16:26 +01:00
Kevin Minehart
e5a98c3c43 [release-12.2.1] backport bump-version.yml and release-build.yml (#111341)
* [release-12.2.1] backport bump-version.yml and release-build.yml

* add release-npm.yml
2025-09-18 16:57:08 -05:00
grafana-delivery-bot[bot]
50403b38d6 [release-12.2.1] Chore: Improve short url redirection (#111183)
Chore: Improve short url redirection (#111162)

Improve short url redirection

(cherry picked from commit 81fe57478f)

Co-authored-by: Misi <mgyongyosi@users.noreply.github.com>
2025-09-16 15:41:37 +02:00
grafana-delivery-bot[bot]
f6570f8123 [release-12.2.1] LDAP: Restore test user mapping functionality (#111120)
LDAP: Restore test user mapping functionality (#110841)

* Migrate LdapPage from connect() to React-Redux hooks

* Convert LDAP debug page into a drawer and hook it into settings

* prettier

* Use the Text component and make the input and button look like they do on the main settings page.

* Bring back isLoading and put in a LoadingPlaceholder

* i18n-extract

* rejigger

* linter fix

(cherry picked from commit 585b53bc7d)

Co-authored-by: John Troy <jtroy@users.noreply.github.com>
2025-09-15 15:28:00 -04:00
grafana-delivery-bot[bot]
c5cf9ff393 [release-12.2.1] Chore: bump axios to a version without CVE (#111110)
Chore: bump `axios` to a version without CVE (#111076)

bump axios to a version without CVE

(cherry picked from commit 7bba151416)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2025-09-15 16:25:52 +01:00
Adela Almasan
9738c198b9 [release-12.2.1] Actions: Add permission check to missing panels (#111103) 2025-09-15 09:54:27 -05:00
Luminessa Starlight
06bf567e1c [release-12.2.1]: Accessibility: enable responsive reflow of variables in dashboard edit (#111033)
Accessibility: enable responsive reflow of variables in dashboard edit (#110967)

enable responsive reflow of variables in dashboard edit
2025-09-15 10:46:58 -04:00
Ashley Harrison
c68d3a2ffa Geomap: Only prefix with grafana public path if relative url (#111081) (#111106)
only prefix with grafana public path if relative url
2025-09-15 15:42:47 +01:00
grafana-delivery-bot[bot]
59cc00b07e [release-12.2.1] Fix: Fix redirection after login when Grafana is served from subpath (#111069)
Fix: Fix redirection after login when Grafana is served from subpath (#110889)

Fix short link (/goto) redirection when Grafana is served from subpath

(cherry picked from commit ccc87a03f0)

Co-authored-by: Misi <mgyongyosi@users.noreply.github.com>
2025-09-15 16:39:21 +02:00
Paul Marbach
8ce2c2d3eb [release-12.2.1] Table: Fix logic to calculate footer height (#110954) (#111107)
Table: Fix logic to calculate footer height (#110954)

* Table: Fix logic to calculate footer height

* add non-numeric footer case to gdev

* Update packages/grafana-ui/src/components/Table/TableNG/utils.ts



* Update packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx



---------


(cherry picked from commit cb37539ed7)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
2025-09-15 09:37:08 -05:00
Paul Marbach
987573a17c [release-12.2.1] Table: Restore previous footer behavior of reducers applying to filtered data (#111041) (#111109)
Table: Restore previous footer behavior of reducers applying to filtered data (#111041)

* Table: Restore previous footer behavior of reducers applying to filtered data

* update e2e to match new behavior

(cherry picked from commit f258d8a417)
2025-09-15 09:36:55 -05:00
Kevin Minehart
49f78c15e8 [release-12.2.0] CI: fix bump version action to use grafana-delivery-bot (#110976) (#110981)
CI: fix bump version action to use grafana-delivery-bot (#110976)

* update bump-version

* Add id-token: write

* update generate-token step

* pull-requests -> pull_requests

* clone with token and set right name

(cherry picked from commit c28a917871)
2025-09-11 15:47:47 -05:00
grafana-delivery-bot[bot]
76340a9741 [release-12.2.0] Alerting: Fix bug where rules with identical mute/active intervals produced conflicting routes (#110971)
Alerting: Fix bug where rules with identical mute/active intervals produced conflicting routes (#110935)

Alerting: Fix hash collision in NotificationSettings fingerprint
(cherry picked from commit fc3636acf2)

Co-authored-by: Alexander Akhmetov <me@alx.cx>
2025-09-11 19:44:08 +02:00
Isabel Matwawana
b15acdf1f2 [release-12.2.0] Docs: ad hoc filter improvements (#110961) 2025-09-11 12:15:52 -04:00
Isabel Matwawana
ca8402fbda [release-12.2.0] docs: clarify that data links must use variable names, not labels (#110965)
Co-authored-by: Sidharth Chauhan <chauhansiddharth71@gmail.com>
2025-09-11 12:09:51 -04:00
Isabel Matwawana
abb44794fe [release-12.2.0] Docs: Replace screenshots for pill and markdown cells (#110962) 2025-09-11 12:03:56 -04:00
Isabel Matwawana
c228eaa99d [release-12.2.0] Docs: Add panel filtering (#110960)
Co-authored-by: Sam Jewell <2903904+samjewell@users.noreply.github.com>
2025-09-11 11:59:24 -04:00
Larissa Wandzura
f41cc1c0d6 created new doc 2025-09-11 10:03:36 -05:00
Larissa Wandzura
b557d71c9a Merge branch 'docs/sql-expressions-updates-082025' of github.com:grafana/grafana into docs/sql-expressions-updates-082025
(cherry picked from commit b0bfbbf547)
2025-09-11 10:01:19 -05:00
Will Browne
e404352a38 Plugins: StaticFS should implement FSRemover (#110706) (#110943)
make staticfs implement fs removal interface
2025-09-11 14:44:47 +01:00
3989 changed files with 98983 additions and 359521 deletions

View File

@@ -1,13 +1,13 @@
[build]
bin = "./bin/grafana-air"
bin = "./bin/grafana"
args_bin = ["server", "-profile", "-profile-addr=127.0.0.1", "-profile-port=6000", "-profile-block-rate=1", "-profile-mutex-rate=5", "-packaging=dev", "cfg:app_mode=development"]
cmd = "make GO_BUILD_DEV=1 build-air"
cmd = "make GO_BUILD_DEV=1 build-backend"
exclude_regex = ["_test.go", "_gen.go"]
exclude_unchanged = true
follow_symlink = true
include_dir = ["apps", "conf", "pkg", "public/views"]
include_dir = ["apps", "conf", "devenv/dev-dashboards", "pkg", "public/views"]
include_ext = ["go", "ini", "toml", "html", "json"]
stop_on_error = true
stop_on_error = false
send_interrupt = true
kill_delay = 500

View File

@@ -17,7 +17,7 @@ watch_exts = [".go", ".ini", ".toml", ".template.html"]
ignore_files = [".*_gen.go"]
build_delay = 1500
cmds = [
["make", "GO_BUILD_DEV=1", "build-go"],
["make", "GO_BUILD_DEV=1", "build-go-fast"],
["make", "gen-jsonnet"],
["./bin/grafana", "server", "-profile", "-profile-addr=127.0.0.1", "-profile-port=6000", "-profile-block-rate=1", "-profile-mutex-rate=5", "-packaging=dev", "cfg:app_mode=development"]
]

View File

@@ -4,7 +4,6 @@
.gitignore
.vscode
bin
!bin/grafana-linux-k8s
data*
dist
docker

66
.github/CODEOWNERS vendored
View File

@@ -32,29 +32,30 @@
/devenv/README.md @grafana/docs-grafana
# START Technical documentation
/.vale.ini @grafana/docs-tooling
/AGENTS.md @grafana/docs-tooling
/.vale.ini @grafana/docs-tooling
# `make docs` procedure and related workflows are owned @grafana/docs-tooling. Slack #docs.
/docs/ @grafana/docs-tooling
/docs/sources/ @irenerl24
/docs/sources/alerting/ @JohnnyK-Grafana
/docs/sources/dashboards/ @imatwawana
/docs/sources/as-code/ @urbiz-grafana
/docs/sources/developer-resources/ @urbiz-grafana
/docs/sources/datasources/ @lwandz13
/docs/sources/panels-visualizations/ @imatwawana
/docs/sources/upgrade-guide/ @jtvdez
/docs/sources/whatsnew/ @jtvdez
/docs/sources/developers/plugins/ @grafana/plugins-platform-frontend @grafana/plugins-platform-backend
/docs/sources/developer-resources/plugins/ @grafana/plugins-platform-frontend @grafana/plugins-platform-backend
/docs/sources/visualizations/dashboards/ @imatwawana
/docs/sources/visualizations/panels-visualizations/ @imatwawana
/docs/sources/visualizations/dashboards/share-dashboards-panels/_index.md @imatwawana @jtvdez
/docs/sources/visualizations/dashboards/share-dashboards-panels/shared-dashboards/index.md @jtvdez
/docs/sources/visualizations/panels-visualizations/query-transform-data/transform-data/index.md @imatwawana @baldm0mma
/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md @lwandz13 @irenerl24
/docs/sources/dashboards/share-dashboards-panels/_index.md @imatwawana @jtvdez
/docs/sources/dashboards/share-dashboards-panels/shared-dashboards/index.md @jtvdez
/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md @imatwawana @baldm0mma
/docs/sources/panels-visualizations/query-transform-data/sql-expressions/index.md @lwandz13 @irenerl24
# END Technical documentation
# Backend code
@@ -90,13 +91,10 @@
/apps/preferences/ @grafana/grafana-app-platform-squad @grafana/grafana-frontend-platform
/apps/shorturl/ @grafana/sharing-squad
/apps/secret/ @grafana/grafana-operator-experience-squad
/apps/scope/ @grafana/grafana-operator-experience-squad
/apps/investigations/ @fcjack @matryer @svennergr
/apps/advisor/ @grafana/plugins-platform-backend
/apps/iam/ @grafana/access-squad
/apps/sdk.mk @grafana/grafana-app-platform-squad
/apps/correlations @grafana/datapro
/apps/logsdrilldown/ @grafana/observability-logs
/pkg/api/ @grafana/grafana-backend-group
/pkg/apis/ @grafana/grafana-app-platform-squad
/pkg/apis/query @grafana/grafana-datasources-core-services
@@ -194,7 +192,7 @@
/pkg/setting/ @grafana/grafana-backend-services-squad
/pkg/tests/ @grafana/grafana-backend-services-squad
/pkg/tests/apis/ @grafana/grafana-app-platform-squad
/pkg/tests/apis/alerting @grafana/alerting-backend
/pkg/tests/apis/alerting @grafana/grafana-app-platform-squad @grafana/alerting-backend
/pkg/tests/apis/features @grafana/grafana-backend-services-squad
/pkg/tests/apis/folder @grafana/grafana-search-and-storage
/pkg/tests/apis/iam @grafana/identity-access-team
@@ -305,7 +303,7 @@
/devenv/docker/blocks/prometheus_random_data/ @grafana/oss-big-tent
/devenv/docker/blocks/prometheus_high_card/ @grafana/oss-big-tent
/devenv/docker/blocks/prometheus_utf8/ @grafana/oss-big-tent
/devenv/docker/blocks/pyroscope/ @grafana/oss-big-tent
/devenv/docker/blocks/pyroscope/ @grafana/observability-traces-and-profiling
/devenv/docker/blocks/redis/ @bergquist
/devenv/docker/blocks/sensugo/ @grafana/grafana-backend-group
/devenv/docker/blocks/slow_proxy/ @bergquist
@@ -316,7 +314,6 @@
/devenv/docker/blocks/webdav/ @grafana/alerting-backend
/devenv/docker/buildcontainer/ @bergquist
/devenv/docker/compose_header.yml @grafana/grafana-backend-services-squad
/devenv/docker/compose_volume_section.yml @grafana/grafana-backend-services-squad
/devenv/docker/debtest/ @bergquist
/devenv/docker/ha-test-unified-alerting/ @grafana/alerting-backend
/devenv/docker/ha_test/ @grafana/grafana-backend-services-squad
@@ -355,8 +352,8 @@
/pkg/tsdb/prometheus/ @grafana/oss-big-tent
/pkg/tsdb/elasticsearch/ @grafana/partner-datasources
/pkg/tsdb/loki/ @grafana/oss-big-tent
/pkg/tsdb/tempo/ @grafana/oss-big-tent
/pkg/tsdb/grafana-pyroscope-datasource/ @grafana/oss-big-tent
/pkg/tsdb/tempo/ @grafana/oss-big-tent @grafana/observability-traces-and-profiling
/pkg/tsdb/grafana-pyroscope-datasource/ @grafana/observability-traces-and-profiling
/pkg/tsdb/parca/ @grafana/oss-big-tent
# OSS Big Tent backend code
@@ -431,8 +428,6 @@
/e2e-playwright/dashboards/PanelSandboxDashboard.json @grafana/plugins-platform-frontend
/e2e-playwright/dashboards/TestDashboard.json @grafana/dashboards-squad @grafana/grafana-search-navigate-organise
/e2e-playwright/dashboards/TestV2Dashboard.json @grafana/dashboards-squad
/e2e-playwright/dashboards/V2DashWithRepeats.json @grafana/dashboards-squad
/e2e-playwright/dashboards/V2DashWithTabRepeats.json @grafana/dashboards-squad
/e2e-playwright/dashboards-suite/adhoc-filter-from-panel.spec.ts @grafana/datapro
/e2e-playwright/dashboards-suite/dashboard-browse-nested.spec.ts @grafana/grafana-search-navigate-organise
/e2e-playwright/dashboards-suite/dashboard-browse.spec.ts @grafana/grafana-search-navigate-organise
@@ -561,7 +556,6 @@
/packages/grafana-data/src/themes/ @grafana/grafana-frontend-platform
/packages/grafana-data/src/transformations/ @grafana/datapro
/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/utils/__snapshots__/ @grafanabot
/packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform
/packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform
@@ -614,7 +608,7 @@
/packages/grafana-o11y-ds-frontend/ @grafana/observability-logs
/packages/grafana-o11y-ds-frontend/src/IntervalInput/ @grafana/observability-traces-and-profiling
/packages/grafana-o11y-ds-frontend/src/NodeGraph/ @grafana/observability-traces-and-profiling
/packages/grafana-o11y-ds-frontend/src/pyroscope/ @grafana/oss-big-tent @grafana/observability-traces-and-profiling
/packages/grafana-o11y-ds-frontend/src/pyroscope/ @grafana/observability-traces-and-profiling
/packages/grafana-o11y-ds-frontend/src/SpanBar/ @grafana/oss-big-tent @grafana/observability-traces-and-profiling
/packages/grafana-o11y-ds-frontend/src/TraceToLogs/ @grafana/oss-big-tent @grafana/observability-traces-and-profiling
/packages/grafana-o11y-ds-frontend/src/TraceToMetrics/ @grafana/oss-big-tent @grafana/observability-traces-and-profiling
@@ -635,7 +629,6 @@
/packages/grafana-runtime/rollup.config.ts @grafana/grafana-frontend-platform
/packages/grafana-runtime/src/index.ts @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
/packages/grafana-runtime/src/internal/index.ts @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
/packages/grafana-runtime/src/internal/openFeature @grafana/grafana-frontend-platform
/packages/grafana-runtime/src/unstable.ts @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
/packages/grafana-runtime/tsconfig.build.json @grafana/grafana-frontend-platform
/packages/grafana-runtime/tsconfig.json @grafana/grafana-frontend-platform
@@ -690,9 +683,10 @@
/packages/grafana-schema/src/**/gauge @grafana/dataviz-squad
/packages/grafana-schema/src/**/geomap @grafana/dataviz-squad
/packages/grafana-schema/src/**/googlecloudmonitoring @grafana/partner-datasources
/packages/grafana-schema/src/**/grafanapyroscope @grafana/oss-big-tent
/packages/grafana-schema/src/**/grafanapyroscope @grafana/observability-traces-and-profiling
/packages/grafana-schema/src/**/heatmap @grafana/dataviz-squad
/packages/grafana-schema/src/**/histogram @grafana/dataviz-squad
/packages/grafana-schema/src/**/librarypanel @grafana/sharing-squad
/packages/grafana-schema/src/**/logs @grafana/observability-logs
/packages/grafana-schema/src/**/logsnew @grafana/observability-logs
/packages/grafana-schema/src/**/loki @grafana/oss-big-tent @grafana/observability-logs
@@ -741,9 +735,6 @@
# @grafana/test-utils
/packages/grafana-test-utils @grafana/grafana-frontend-platform
# @grafana/api-clients
/packages/grafana-api-clients/ @grafana/grafana-frontend-platform @grafana/grafana-search-navigate-organise
# root files, mostly frontend
/.browserslistrc @grafana/frontend-ops
/package.json @grafana/frontend-ops
@@ -884,7 +875,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/public/app/core/utils/accessControl.ts @grafana/identity-access-team
/public/app/core/utils/applyStateChanges.ts @grafana/dashboards-squad
/public/app/core/utils/arrayMove.ts @grafana/grafana-frontend-platform
/public/app/core/utils/isFrontendService.ts @grafana/grafana-frontend-platform
/public/app/core/utils/auth.ts @grafana/identity-access-team
/public/app/core/utils/browser* @grafana/grafana-frontend-platform
/public/app/core/utils/colors.ts @grafana/grafana-frontend-platform
@@ -938,7 +928,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/public/app/features/inspector/ @grafana/dashboards-squad
/public/app/features/logs/ @grafana/observability-logs
/public/app/features/live/ @grafana/dashboards-squad
/public/app/features/stars/ @grafana/grafana-search-navigate-organise
/public/app/features/apiserver/ @grafana/grafana-app-platform-squad
/public/app/features/manage-dashboards/ @grafana/dashboards-squad
/public/app/features/migrate-to-cloud @grafana/grafana-operator-experience-squad
@@ -956,14 +945,13 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/public/app/features/serviceaccounts/ @grafana/identity-squad
/public/app/features/teams/ @grafana/access-squad
/public/app/features/templating/ @grafana/dashboards-squad
/public/app/features/theme-playground/ @grafana/grafana-frontend-platform
/public/app/features/trails/ @grafana/observability-metrics
/public/app/features/transformers/ @grafana/datapro
/public/app/features/transformers/timeSeriesTable/ @grafana/dataviz-squad @grafana/app-o11y-visualizations
/public/app/features/users/ @grafana/access-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/plugins/panel/* @grafana/dataviz-squad
/public/app/plugins/panel/alertlist/ @grafana/alerting-frontend
/public/app/plugins/panel/annolist/ @grafana/dashboards-squad
/public/app/plugins/panel/barchart/ @grafana/dataviz-squad
@@ -1057,14 +1045,13 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/scripts/trigger_windows_build.sh @grafana/grafana-developer-enablement-squad
/scripts/cleanup-husky.sh @grafana/frontend-ops
/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/levitate-parse-json-report.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/codeowners-manifest/ @grafana/dataviz-squad
/scripts/test-coverage-by-codeowner.js @grafana/dataviz-squad
/jest.config.codeowner.js @grafana/dataviz-squad
/scripts/rtk-client-generator/ @grafana/grafana-search-navigate-organise
/scripts/**/generate-transformations* @grafana/datapro
/scripts/webpack/ @grafana/frontend-ops
@@ -1093,8 +1080,8 @@ eslint-suppressions.json @grafanabot
/public/app/plugins/datasource/prometheus/ @grafana/oss-big-tent
/public/app/plugins/datasource/cloud-monitoring/ @grafana/partner-datasources
/public/app/plugins/datasource/zipkin/ @grafana/oss-big-tent
/public/app/plugins/datasource/tempo/ @grafana/oss-big-tent
/public/app/plugins/datasource/grafana-pyroscope-datasource/ @grafana/oss-big-tent
/public/app/plugins/datasource/tempo/ @grafana/oss-big-tent @grafana/observability-traces-and-profiling
/public/app/plugins/datasource/grafana-pyroscope-datasource/ @grafana/observability-traces-and-profiling
/public/app/plugins/datasource/parca/ @grafana/oss-big-tent
/public/app/plugins/datasource/alertmanager/ @grafana/alerting-squad
@@ -1274,7 +1261,6 @@ embed.go @grafana/grafana-as-code
/.github/workflows/changelog.yml @zserge
/.github/workflows/shellcheck.yml @grafana/grafana-developer-enablement-squad
/.github/workflows/release-build.yml @grafana/grafana-developer-enablement-squad
/.github/workflows/cleanup-branches.yml @grafana/grafana-developer-enablement-squad
/.github/workflows/publish-artifact.yml @grafana/grafana-developer-enablement-squad
/.github/actions/changelog @zserge
/.github/workflows/swagger-gen.yml @grafana/grafana-backend-group
@@ -1284,14 +1270,10 @@ embed.go @grafana/grafana-as-code
/.github/workflows/pr-e2e-tests.yml @grafana/grafana-developer-enablement-squad
/.github/workflows/skye-add-to-project.yml @grafana/grafana-frontend-platform
/.github/workflows/frontend-perf-tests.yaml @grafana/grafana-frontend-platform
/.github/workflows/release-npm.yml @grafana/grafana-frontend-platform
/.github/workflows/scripts/determine-npm-tag.sh @grafana/grafana-frontend-platform
/.github/workflows/scripts/validate-commit-in-head.sh @grafana/grafana-frontend-platform
/.github/zizmor.yml @grafana/grafana-developer-enablement-squad
/.github/license_finder.yaml @bergquist
/.github/actionlint.yaml @grafana/grafana-developer-enablement-squad
/.github/workflows/pr-test-docker.yml @grafana/grafana-developer-enablement-squad
/.github/workflows/update-schema-types.yml @grafana/plugins-platform-frontend
# Generated files not requiring owner approval
/packages/grafana-data/src/types/featureToggles.gen.ts @grafanabot

View File

@@ -144,7 +144,7 @@
"name": "datasource/grafana-pyroscope",
"action": "addToProject",
"addToProject": {
"url": "https://github.com/orgs/grafana/projects/457"
"url": "https://github.com/orgs/grafana/projects/221"
}
},
{

View File

@@ -1,65 +1,32 @@
version: 2
updates:
- package-ecosystem: "github-actions"
commit-message:
prefix: deps(actions)
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
commit-message:
prefix: deps(go)
directories:
- "/"
- "/apps/advisor"
- "/apps/alerting/alertenrichment"
- "/apps/alerting/notifications"
- "/apps/alerting/rules"
- "/apps/correlations"
- "/apps/dashboard"
- "/apps/folder"
- "/apps/iam"
- "/apps/investigations"
- "/apps/playlist"
- "/apps/plugins"
- "/apps/preferences"
- "/apps/provisioning"
- "/apps/scope"
- "/apps/secret"
- "/apps/shorturl"
- "/hack"
- "/apps/investigations"
- "/pkg/aggregator"
- "/pkg/apimachinery"
- "/pkg/apis/folder"
- "/pkg/apiserver"
- "/pkg/build"
- "/pkg/build/wire"
- "/pkg/codegen"
- "/pkg/plugins/codegen"
- "/pkg/promlib"
- "/pkg/semconv"
- "/pkg/storage/unified/apistore"
- "/pkg/storage/unified/resource"
- "/pkg/util/xorm"
- "/scripts/go-workspace"
- "/scripts/modowners"
schedule:
interval: "daily"
time: "02:00"
timezone: Etc/UTC
open-pull-requests-limit: 20
# group some updates together for easier review
groups:
go.opentelemetry.io:
patterns:
- "go.opentelemetry.io/*"
k8s.io:
patterns:
- "k8s.io/*"
aws-sdk-go:
patterns:
- "github.com/aws/aws-sdk-go*"
- "github.com/aws/smithy-go"
open-pull-requests-limit: 10
- package-ecosystem: "docker"
commit-message:
prefix: deps(docker)
directories:
- "/"
- "/packaging/docker/custom"
@@ -68,4 +35,4 @@ updates:
interval: "daily"
time: "02:00"
timezone: Etc/UTC
open-pull-requests-limit: 20
open-pull-requests-limit: 10

View File

@@ -1,9 +1,6 @@
{
extends: ["config:recommended"],
enabledManagers: ["npm"],
ignorePresets: [
"github>grafana/grafana-renovate-config//presets/labels",
],
ignoreDeps: [
// ignoring these until we can upgrade to react 19
// see epic here: https://github.com/grafana/grafana/issues/98813

View File

@@ -34,7 +34,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
persist-credentials: false
@@ -54,7 +54,7 @@ jobs:
- name: Upload to GitHub security events
if: success() || failure()
# 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:
sarif_file: results.sarif
category: actionlint

View File

@@ -10,12 +10,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
fetch-depth: 2
persist-credentials: false
- name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: go.mod
- name: Build swagger

View File

@@ -17,7 +17,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4 # 4.2.2
with:
persist-credentials: false
- name: Check if update branch exists
@@ -29,7 +29,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # 6.0.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # 5.5.0
with:
"go-version-file": "go.mod"
@@ -60,10 +60,10 @@ jobs:
run: |
FROM_COMMIT="${{ steps.current-commit.outputs.from_commit }}"
TO_COMMIT="${{ steps.latest-commit.outputs.to_commit }}"
# Compare just the length of the shorter hash
SHORT_TO_COMMIT="${TO_COMMIT:0:${#FROM_COMMIT}}"
if [ "$FROM_COMMIT" = "$SHORT_TO_COMMIT" ]; then
echo "Current version ($FROM_COMMIT) is already at latest ($SHORT_TO_COMMIT). No update needed."
exit 0
@@ -148,7 +148,7 @@ jobs:
echo "🔗 [View Pull Request]($PR_URL)"
} >> "$GITHUB_STEP_SUMMARY"
- name: Send Slack Message
uses: grafana/shared-workflows/actions/send-slack-message@send-slack-message/v2.0.4
uses: grafana/shared-workflows/actions/send-slack-message@send-slack-message/v2.0.3
with:
method: 'chat.postMessage'
# send to alerting-reviews channel
@@ -157,4 +157,4 @@ jobs:
{
"channel": "C076RNRRZ2N",
"text": "Update alerting module in Grafana ${{ steps.create-pr.outputs.pull-request-url }}"
}
}

View File

@@ -12,12 +12,12 @@ jobs:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'

View File

@@ -23,7 +23,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.backend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -42,20 +42,22 @@ jobs:
name: Validate Backend Configs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
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
- name: Verify code generation
run: |
CODEGEN_VERIFY=1 make gen-cue
CODEGEN_VERIFY=1 make gen-jsonnet
CODEGEN_VERIFY=1 make gen-apps
- name: Validate go.mod
run: go run scripts/modowners/modowners.go check go.mod

View File

@@ -24,7 +24,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.backend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -55,11 +55,11 @@ jobs:
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
- name: Run unit tests
@@ -90,11 +90,11 @@ jobs:
steps:
# Set up repository clone
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
- name: Setup Enterprise

View File

@@ -36,7 +36,7 @@ jobs:
private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }}
- name: Download PR info artifact
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
id: download-pr-info
with:
github-token: ${{ github.token }}
@@ -62,7 +62,7 @@ jobs:
echo "PR number: $PR_NUMBER"
- name: Checkout Grafana
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.default_branch }}
fetch-depth: 2

View File

@@ -84,7 +84,7 @@ jobs:
app_id: ${{ vars.DELIVERY_BOT_APP_ID }}
private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }}
- name: "Checkout Grafana repo"
uses: "actions/checkout@v5"
uses: "actions/checkout@v4"
with:
ref: main
sparse-checkout: |
@@ -97,7 +97,7 @@ jobs:
fetch-depth: 0
fetch-tags: true
- name: Setup nodejs environment
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: "Configure git user"

View File

@@ -1,18 +0,0 @@
name: Clean up orphaned branches
on:
workflow_dispatch:
schedule:
- cron: "0 9 * * 1"
jobs:
cleanup-branches:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: read
steps:
- uses: actions/checkout@v5
- uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v0.2.1
with:
dry-run: true
max-date: "1 month ago"

View File

@@ -13,7 +13,7 @@ jobs:
contents: read
steps:
# Checks-out your repository, which is validated in the next step
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: GitHub CODEOWNERS Validator

View File

@@ -33,7 +33,7 @@ jobs:
go: ${{ steps.detect-changes.outputs.backend }}
actions: 'true'
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -63,7 +63,7 @@ jobs:
steps:
- name: Checkout repository
if: needs.detect-changes.outputs[matrix.language] == 'true'
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@@ -72,14 +72,14 @@ jobs:
- if: matrix.language == 'go' && needs.detect-changes.outputs.go == 'true'
name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: go.mod
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
if: needs.detect-changes.outputs[matrix.language] == 'true'
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -94,4 +94,4 @@ jobs:
make build-go
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v3

View File

@@ -53,7 +53,7 @@ jobs:
private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }}
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v4 # v4.2.2
with:
repository: "grafana/grafana-github-actions"
path: ./actions

View File

@@ -43,7 +43,7 @@ jobs:
version: ${{ steps.build_frontend.outputs.version }}
steps:
- name: checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Verify inputs
@@ -58,13 +58,13 @@ jobs:
PLUGINS_GRAFANA_API_KEY=core-plugins-build-and-release:PLUGINS_GRAFANA_API_KEY
PLUGINS_GCOM_TOKEN=core-plugins-build-and-release:PLUGINS_GCOM_TOKEN
- name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093'
uses: 'google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f'
with:
credentials_json: '${{ env.PLUGINS_GOOGLE_CREDENTIALS }}'
- name: 'Set up Cloud SDK'
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
- name: Setup nodejs environment
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: yarn
@@ -101,7 +101,7 @@ jobs:
echo "has_backend=false" >> "$GITHUB_OUTPUT"
fi
- name: Setup golang environment
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
if: steps.check_backend.outputs.has_backend == 'true'
with:
go-version-file: go.mod

View File

@@ -61,7 +61,7 @@ jobs:
private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }}
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
token: ${{ steps.generate_token.outputs.token }}
repository: ${{ inputs.repository }}

View File

@@ -27,7 +27,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false

View File

@@ -29,12 +29,12 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
path: './pr'
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: './pr/.nvmrc'
@@ -80,13 +80,13 @@ jobs:
working-directory: './base'
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
path: './base'
ref: ${{ github.event.pull_request.base.ref }}
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: './base/.nvmrc'
@@ -132,21 +132,21 @@ jobs:
id-token: 'write'
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Get built packages from pr
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: buildPr
- name: Get built packages from base
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: buildBase
@@ -157,7 +157,7 @@ jobs:
run: unzip -j base_built_packages.zip -d ./base && rm base_built_packages.zip
- id: 'auth'
uses: 'google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093'
uses: 'google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f'
if: github.event.pull_request.head.repo.full_name == github.repository
with:
workload_identity_provider: projects/304398677251/locations/global/workloadIdentityPools/github/providers/github-provider
@@ -220,17 +220,17 @@ jobs:
app-id: ${{ env.GITHUB_APP_ID }}
private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }}
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: 'Download artifact'
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: levitate
- name: Parsing levitate result
uses: actions/github-script@v8
uses: actions/github-script@v7
id: levitate-run
with:
script: |
@@ -241,7 +241,7 @@ jobs:
# Check if label exists
- name: Check if "levitate breaking change" label exists
id: does-label-exist
uses: actions/github-script@v8
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
with:
@@ -334,7 +334,7 @@ jobs:
# Add the label
- name: Add "levitate breaking change" label
if: steps.levitate-run.outputs.exit_code == 1 && steps.does-label-exist.outputs.result == 0
uses: actions/github-script@v8
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.levitate-run.outputs.pr_number }}
with:
@@ -350,7 +350,7 @@ jobs:
# Remove label (no more breaking changes)
- name: Remove "levitate breaking change" label
if: steps.levitate-run.outputs.exit_code == 0 && steps.does-label-exist.outputs.result == 1
uses: actions/github-script@v8
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.levitate-run.outputs.pr_number }}
with:
@@ -368,7 +368,7 @@ jobs:
# Related issue: https://github.com/renovatebot/renovate/issues/1908
- name: Add "grafana/plugins-platform-frontend" as a reviewer
if: steps.levitate-run.outputs.exit_code == 1
uses: actions/github-script@v8
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.levitate-run.outputs.pr_number }}
with:
@@ -385,7 +385,7 @@ jobs:
# Remove reviewers (no more breaking changes)
- name: Remove "grafana/plugins-platform-frontend" from the list of reviewers
if: steps.levitate-run.outputs.exit_code == 0
uses: actions/github-script@v8
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.levitate-run.outputs.pr_number }}
with:

View File

@@ -29,14 +29,14 @@ jobs:
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Check for plugin extension changes
id: check-changes
uses: actions/github-script@v8
uses: actions/github-script@v7
with:
script: |
const { execSync } = require('child_process');

View File

@@ -17,7 +17,7 @@ jobs:
container:
image: grafana/vale:latest # zizmor: ignore[unpinned-images]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: grafana/writers-toolkit/vale-action@vale-action/v1 # zizmor: ignore[unpinned-uses]

View File

@@ -42,7 +42,7 @@ jobs:
private_key: ${{ env.APP_PEM }}
- name: Checkout ephemeral instances repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
repository: grafana/ephemeral-grafana-instances-github-action
token: ${{ steps.generate_token.outputs.token }}

View File

@@ -11,20 +11,18 @@ permissions: {}
jobs:
test:
name: Feature toggles documentation is in sync with source
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: 'go.mod'
cache: true

View File

@@ -18,7 +18,7 @@ jobs:
changed: ${{ steps.detect-changes.outputs.frontend }}
prettier: ${{ steps.detect-changes.outputs.frontend == 'true' || steps.detect-changes.outputs.docs == 'true' }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -39,10 +39,10 @@ jobs:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
@@ -60,10 +60,10 @@ jobs:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
@@ -86,10 +86,10 @@ jobs:
name: Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
@@ -106,10 +106,10 @@ jobs:
name: Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
@@ -130,10 +130,10 @@ jobs:
name: Verify API clients
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
@@ -161,10 +161,10 @@ jobs:
name: Verify API clients (enterprise)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'

View File

@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false

View File

@@ -23,7 +23,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.backend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -38,10 +38,10 @@ jobs:
if: needs.detect-changes.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-go@v6.0.0
- uses: actions/setup-go@v5.5.0
with:
go-version-file: ./go.mod
- name: Run gofmt
@@ -59,14 +59,14 @@ jobs:
if: needs.detect-changes.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-go@v6.0.0
- uses: actions/setup-go@v5.5.0
with:
go-version-file: ./go.mod
- name: golangci-lint
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9
uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd
with:
version: v2.5.0
args: |

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v4 # v4.2.2
with:
repository: "grafana/grafana-github-actions"
path: ./actions
@@ -39,7 +39,7 @@ jobs:
- name: "Get 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:
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault
repo_secrets: |
@@ -71,7 +71,7 @@ jobs:
- name: "Get 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:
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
repo_secrets: |
@@ -97,7 +97,7 @@ jobs:
ACTOR: ${{ github.actor }}
- name: Checkout
if: steps.check-if-grafana-org-member.outputs.is_grafana_org_member != 'true' && github.event.issue.author_association != 'MEMBER' && github.event.issue.author_association != 'OWNER'
uses: actions/checkout@v5
uses: actions/checkout@v4 # v4.2.2
with:
persist-credentials: false
sparse-checkout: |
@@ -139,12 +139,12 @@ jobs:
steps:
- name: "Get 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:
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
repo_secrets: |
GITHUB_APP_ID=plugins_platform_issue_triager_github_bot:app_id
GITHUB_APP_PRIVATE_KEY=plugins_platform_issue_triager_github_bot:app_pem
GITHUB_APP_PRIVATE_KEY=plugins_platform_issue_triager_github_bot:app_pem
- name: Generate token
id: generate_token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
@@ -166,4 +166,4 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
NUMBER: ${{ github.event.issue.number }}
LABELS: internal
LABELS: internal

View File

@@ -30,12 +30,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'

View File

@@ -31,7 +31,7 @@ jobs:
if: github.event.pull_request.draft == false
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v4 # v4.2.2
with:
repository: "grafana/grafana-github-actions"
path: ./actions

View File

@@ -20,7 +20,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@@ -29,9 +29,9 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v3
with:
languages: "javascript"
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v3

View File

@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@@ -39,10 +39,10 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
if: steps.check-python.outputs.skip != 'true'
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v3
with:
languages: "python"
- name: Perform CodeQL Analysis
if: steps.check-python.outputs.skip != 'true'
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v3

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v5
uses: actions/checkout@v4 # v4.2.2
with:
repository: "grafana/grafana-github-actions"
path: ./actions

View File

@@ -37,7 +37,7 @@ jobs:
private-key: ${{ env.PRIVATE_KEY }}
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}
@@ -45,7 +45,7 @@ jobs:
persist-credentials: false
- name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: go.mod

View File

@@ -30,7 +30,7 @@ jobs:
changed: ${{ steps.detect-changes.outputs.e2e }}
cloud_plugins_changed: ${{ steps.detect-changes.outputs.e2e-cloud-plugins }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -48,7 +48,7 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
@@ -65,7 +65,7 @@ jobs:
# If no cache hit, build Grafana
- name: Build Grafana
if: steps.cache.outputs.cache-hit != 'true'
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
with:
version: 0.18.8
verb: run
@@ -118,11 +118,11 @@ jobs:
outputs:
artifact: ${{ steps.artifact.outputs.artifact }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
cache: ${{ !github.event.pull_request.head.repo.fork }}
@@ -149,17 +149,25 @@ jobs:
needs:
- build-grafana
steps:
- id: get-github-token
name: "create github app token"
uses: grafana/shared-workflows/actions/create-github-app-token@eb02241ed0a92aff205feab8ac3afcdf51c757c8 # create-github-app-token-v0.2.0
- id: vault-secrets
uses: grafana/shared-workflows/actions/get-vault-secrets@main
with:
github_app: "delivery-bot-app"
repo_secrets: |
GRAFANA_DELIVERY_BOT_APP_PEM=delivery-bot-app:PRIVATE_KEY
- name: Generate token
id: generate_token
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a
with:
app_id: ${{ vars.DELIVERY_BOT_APP_ID }}
private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }}
repositories: '["grafana"]'
permissions: '{"checks": "write"}'
- uses: grafana/shared-workflows/actions/login-to-gar@main
id: login-to-gar
with:
registry: 'us-docker.pkg.dev'
environment: 'dev'
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: grafana-docker-tar-gz
path: .
@@ -176,7 +184,7 @@ jobs:
echo "IMAGE=${DOCKER_IMAGE}" >> "$GITHUB_ENV"
- name: Add PR status check
env:
GH_TOKEN: ${{ steps.get-github-token.outputs.token }}
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
SHA: ${{ github.event.pull_request.head.sha }}
run: |
gh api \
@@ -200,6 +208,8 @@ jobs:
fail-fast: false
matrix:
include:
- suite: various-suite
path: e2e/various-suite
- suite: various-suite (old arch)
path: e2e/old-arch/various-suite
flags: --flags="--env dashboardScene=false"
@@ -218,19 +228,19 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v4
with:
name: grafana-tar-gz
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v4
with:
name: ${{ needs.build-e2e-runner.outputs.artifact }}
- name: chmod +x
run: chmod +x ./e2e-runner
- name: Run E2E tests
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
with:
version: 0.18.8
verb: run
@@ -262,12 +272,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
@@ -295,14 +305,14 @@ jobs:
shardTotal: [8]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v4
with:
name: grafana-tar-gz
- name: Run E2E tests
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
with:
version: 0.18.8
verb: run
@@ -315,7 +325,7 @@ jobs:
retention-days: 1
run-azure-monitor-e2e:
if: needs.detect-changes.outputs.cloud_plugins_changed == 'true' && github.event.pull_request.head.repo.fork == false && github.event_name == 'pull_request'
if: needs.detect-changes.outputs.cloud_plugins_changed == 'true' && github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-x64-large
needs:
- build-grafana
@@ -324,7 +334,7 @@ jobs:
contents: read
id-token: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
@@ -360,12 +370,12 @@ jobs:
run: |
docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v4
with:
name: grafana-tar-gz
- name: Run E2E tests
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
with:
version: 0.18.8
verb: run
@@ -391,16 +401,16 @@ jobs:
name: All Playwright tests complete
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
path: blobs
pattern: playwright-blob-*
@@ -476,22 +486,22 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v4
with:
name: grafana-tar-gz
- name: Run PR a11y test
if: github.event_name == 'pull_request'
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
with:
version: 0.18.8
verb: run
args: go run ./pkg/build/a11y --package=grafana.tar.gz
- name: Run non-PR a11y test
if: github.event_name != 'pull_request'
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
with:
version: 0.18.8
verb: run
@@ -521,17 +531,17 @@ jobs:
repo_secrets: |
GRAFANA_MISC_STATS_API_KEY=grafana-misc-stats:api_key
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install dependencies
run: yarn install --immutable
- name: Get pa11y results
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: pa11y-ci-results
- name: Extract and publish metrics
@@ -556,7 +566,7 @@ jobs:
name: All E2E tests complete
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false

View File

@@ -19,7 +19,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.frontend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -46,7 +46,7 @@ jobs:
shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
total: [16]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
@@ -78,7 +78,7 @@ jobs:
shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
total: [16]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Enterprise
@@ -107,7 +107,7 @@ jobs:
runs-on: ubuntu-x64-large
name: "Decoupled plugin tests"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
@@ -128,7 +128,7 @@ jobs:
runs-on: ubuntu-x64-large
name: "Packages unit tests"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
@@ -160,7 +160,7 @@ jobs:
name: All frontend unit tests complete
runs-on: ubuntu-x64-small
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Check test suites

View File

@@ -16,7 +16,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.backend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -34,12 +34,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
cache: false
go-version-file: go.mod
@@ -71,12 +71,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
cache: false
go-version-file: go.mod
@@ -123,7 +123,7 @@ jobs:
echo "No changes in generated Go files"
else
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 link Enterprise and run 'make gen-go', then commit the changes to both repositories."
else
echo "> !!! Please run 'make gen-go' and commit the changes."
fi

View File

@@ -19,12 +19,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set go version
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
with:
go-version-file: go.mod

View File

@@ -55,7 +55,7 @@ jobs:
permissions: "{\"actions\": \"write\", \"workflows\": \"write\"}"
repositories: "[\"security-patch-actions\"]"
- name: "Dispatch job"
uses: actions/github-script@v8
uses: actions/github-script@v7
with:
github-token: ${{ steps.generate_token.outputs.token }}
script: |

View File

@@ -13,7 +13,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.backend || steps.detect-changes.outputs.frontend || steps.detect-changes.outputs.dockerfile }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -21,7 +21,7 @@ jobs:
id: detect-changes
uses: ./.github/actions/change-detection
with:
self: .github/workflows/pr-test-docker.yml
self: .github/workflows/pr-test-integration.yml
build-dockerfile:
needs: detect-changes
@@ -31,9 +31,9 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4
- uses: docker/setup-docker-action@b60f85385d03ac8acfca6d9996982511d8620a19 # v4
- name: Build Dockerfile
run: make build-docker-full

View File

@@ -28,7 +28,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.backend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -54,11 +54,11 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
cache: true
@@ -87,11 +87,11 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
cache: true
@@ -101,8 +101,7 @@ jobs:
run: |
set -euo pipefail
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)"
# ionice since tests are IO intensive
CGO_ENABLED=0 ionice -c2 -n7 go test -p=4 -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
CGO_ENABLED=0 go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
mysql:
needs: detect-changes
if: needs.detect-changes.outputs.changed == 'true'
@@ -136,11 +135,11 @@ jobs:
- 3306:3306
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
cache: true
@@ -185,11 +184,11 @@ jobs:
- 5432:5432
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
cache: true

View File

@@ -44,7 +44,7 @@ jobs:
permissions:
id-token: write
steps:
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: ${{ inputs.name }}
pattern: ${{ inputs.pattern }}

View File

@@ -21,13 +21,13 @@ jobs:
steps:
- name: "Checkout Grafana repo"
uses: "actions/checkout@v5"
uses: "actions/checkout@v4"
with:
fetch-depth: 0
persist-credentials: false
- name: "Setup Go"
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
with:
go-version-file: go.mod

View File

@@ -23,14 +23,14 @@ jobs:
steps:
- name: "Checkout Grafana repo"
uses: "actions/checkout@v5"
uses: "actions/checkout@v4"
with:
# required for the `grafana/grafana-github-actions/has-matching-release-tag` action to work
fetch-depth: 0
persist-credentials: false
- name: "Setup Go"
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
with:
go-version-file: go.mod
@@ -38,7 +38,7 @@ jobs:
run: go run .github/workflows/scripts/kinds/verify-kinds.go
- name: "Checkout Actions library"
uses: "actions/checkout@v5"
uses: "actions/checkout@v4"
with:
repository: "grafana/grafana-github-actions"
path: "./actions"

View File

@@ -15,7 +15,7 @@ jobs:
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: grafana/writers-toolkit/publish-technical-documentation@publish-technical-documentation/v1 # zizmor: ignore[unpinned-uses]

View File

@@ -17,7 +17,7 @@ jobs:
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false

View File

@@ -20,7 +20,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
persist-credentials: false

View File

@@ -96,7 +96,7 @@ jobs:
private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }}
repositories: '["grafana-enterprise"]'
permissions: '{"actions": "write"}'
- uses: actions/github-script@v8
- uses: actions/github-script@v7
env:
REF: ${{ github.ref_name }}
VERSION: ${{ needs.setup.outputs.version }}
@@ -212,6 +212,7 @@ jobs:
run-id: ${{ github.run_id }}
bucket-path: ${{ needs.setup.outputs.version }}_${{ github.run_id }}
environment: prod
runs-on: ubuntu-x64-small
publish-dockerhub:
if: github.ref_name == 'main'
@@ -224,27 +225,27 @@ jobs:
- build
steps:
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: artifacts-list-linux-amd64
path: .
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: artifacts-list-linux-arm64
path: .
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: artifacts-list-linux-armv7
path: .
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: artifacts-linux-amd64
path: dist
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: artifacts-linux-arm64
path: dist
- uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: artifacts-linux-armv7
path: dist
@@ -271,30 +272,21 @@ jobs:
docker manifest push "grafana/grafana-dev:${VERSION}"
docker manifest push "grafana/grafana-dev:${VERSION}-ubuntu"
dispatch-npm-canaries:
publish-npm-canaries:
if: github.ref_name == 'main'
name: Dispatch publish NPM canaries
name: Publish NPM canaries
uses: ./.github/workflows/release-npm.yml
permissions:
actions: write
contents: read
runs-on: ubuntu-x64-small
id-token: write
needs:
- setup
steps:
- name: Dispatch action
env:
GRAFANA_COMMIT: ${{ needs.setup.outputs.grafana-commit }}
VERSION: ${{ needs.setup.outputs.version }}
BUILD_ID: ${{ github.run_id }}
GH_TOKEN: ${{ github.token }}
run: |
gh workflow run release-npm.yml \
--repo grafana/grafana \
--ref main \
--field grafana_commit="$GRAFANA_COMMIT" \
--field version="$VERSION" \
--field build_id="$BUILD_ID"\
--field version_type="canary"
- build
with:
grafana_commit: ${{ needs.setup.outputs.grafana-commit }}
version: ${{ needs.setup.outputs.version }}
build_id: ${{ github.run_id }}
version_type: "canary"
# notify-pr creates (or updates) a comment in a pull request to link to this workflow where the release artifacts are
# being built.
@@ -320,13 +312,21 @@ jobs:
repositories: '["grafana"]'
permissions: '{"issues": "write", "pull_requests": "write", "contents": "read"}'
- name: Find PR
continue-on-error: true
id: find-pr
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
GRAFANA_COMMIT: ${{ needs.setup.outputs.grafana-commit }}
run: echo "ISSUE_NUMBER=$(gh api "/repos/grafana/grafana/commits/${GRAFANA_COMMIT}/pulls" | jq -r '.[0].number')" >> "$GITHUB_ENV"
REPO: ${{ github.repository }}
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
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
if: ${{ steps.find-pr.outcome == 'success' }}
id: fc
continue-on-error: true
with:
issue-number: ${{ env.ISSUE_NUMBER }}
comment-author: 'grafana-delivery-bot[bot]'
@@ -334,6 +334,7 @@ jobs:
token: ${{ steps.generate_token.outputs.token }}
- name: Create or update comment
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v4
if: ${{ steps.find-pr.outcome == 'success' }} # Run even if comment wasn't found
with:
token: ${{ steps.generate_token.outputs.token }}
comment-id: ${{ steps.fc.outputs.comment-id }}

View File

@@ -60,7 +60,7 @@ jobs:
echo "github.ref: $GITHUB_REF"
- name: Checkout workflow ref
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 100
@@ -86,7 +86,7 @@ jobs:
shell: bash
- name: Checkout build commit
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
ref: ${{ inputs.grafana_commit }}

View File

@@ -118,14 +118,14 @@ jobs:
permissions: "{\"contents\": \"write\", \"pull_requests\": \"write\", \"workflows\":\"write\"}"
- run: echo "RELEASE_BRANCH=release-${VERSION}" >> "$GITHUB_ENV"
- name: Checkout Grafana
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
token: ${{ steps.generate_changelog_token.outputs.token }}
ref: ${{ env.RELEASE_BRANCH }}
fetch-tags: true
fetch-depth: 0
- name: Checkout Grafana (main)
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
token: ${{ steps.generate_changelog_token.outputs.token }}
ref: main
@@ -133,10 +133,10 @@ jobs:
path: .grafana-main
- name: Setup nodejs environment
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- uses: actions/setup-go@v6.0.0
- uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
- name: Configure git user
@@ -196,7 +196,7 @@ jobs:
run: git add CHANGELOG.md && git commit --allow-empty -m "Update changelog" CHANGELOG.md
- name: Bump versions
if: ${{ inputs.bump == true || inputs.bump == 'true' }}
uses: dagger/dagger-for-github@d913e70051faf3b907d4dd96ef1161083c88c644
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
with:
version: 0.18.8
verb: run

View File

@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false

View File

@@ -25,16 +25,16 @@ jobs:
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Pin Go version to mod file
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: 'go.mod'
cache: true
- run: go version
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
@@ -96,7 +96,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Restore Cached Node Modules

View File

@@ -18,15 +18,15 @@ jobs:
if: github.event.pull_request.draft == false
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Pin Go version to mod file
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: 'go.mod'
- run: go version
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'

View File

@@ -24,7 +24,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run Shellcheck

View File

@@ -11,7 +11,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
operations-per-run: 750

View File

@@ -17,7 +17,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.frontend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -27,7 +27,7 @@ jobs:
with:
self: .github/workflows/storybook-a11y.yml
test-storybook-a11y-light:
test-storybook-a11y:
runs-on: ubuntu-latest-8-cores
permissions:
contents: read
@@ -36,48 +36,17 @@ jobs:
if: needs.detect-changes.outputs.changed == 'true'
name: "Run Storybook a11y tests"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
package-manager-cache: false # too large for GH's cache limits :-(
- run: yarn install --immutable --check-cache
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Start Storybook
run: STORYBOOK_THEME=light yarn storybook &
- name: Run tests
# the chromium browser used by Playwright sets its locale to "en_US@posix" by default
# this is not a valid language code, and causes some stories to fail to load!
# instead, we set the LANG environment variable to en_US to override this
# see https://github.com/microsoft/playwright/issues/34046
env:
LANG: en_US
run: npx wait-on --timeout 120000 http://localhost:9001 && yarn test:storybook
test-storybook-a11y-dark:
runs-on: ubuntu-latest-8-cores
permissions:
contents: read
id-token: write
needs: detect-changes
if: needs.detect-changes.outputs.changed == 'true'
name: "Run Storybook a11y tests"
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
package-manager-cache: false # too large for GH's cache limits :-(
- run: yarn install --immutable --check-cache
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Start Storybook
run: STORYBOOK_THEME=dark yarn storybook &
run: yarn storybook &
- name: Run tests
# the chromium browser used by Playwright sets its locale to "en_US@posix" by default
# this is not a valid language code, and causes some stories to fail to load!

View File

@@ -24,7 +24,7 @@ jobs:
outputs:
changed: ${{ steps.detect-changes.outputs.backend }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: true # required to get more history in the changed-files action
fetch-depth: 2
@@ -45,11 +45,11 @@ jobs:
steps:
# Set up repository clone
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v6.0.0
uses: actions/setup-go@v5.5.0
with:
go-version-file: go.mod
- name: Setup Enterprise

View File

@@ -41,7 +41,7 @@ jobs:
app_id: ${{ vars.DELIVERY_BOT_APP_ID }}
private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }}
- uses: actions/github-script@v8
- uses: actions/github-script@v7
if: github.repository == 'grafana/grafana'
with:
github-token: ${{ steps.generate_token.outputs.token }}

View File

@@ -16,11 +16,11 @@ jobs:
trivy-scan:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Trivy
uses: aquasecurity/setup-trivy@e6c2c5e321ed9123bda567646e2f96565e34abe1
uses: aquasecurity/setup-trivy@9ea583eb67910444b1f64abf338bd2e105a0a93d
with:
version: v0.56.2
cache: true
@@ -64,7 +64,7 @@ jobs:
.
if: always() && github.repository == 'grafana/grafana'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
if: always() && github.repository == 'grafana/grafana'

View File

@@ -26,11 +26,11 @@ jobs:
shell: bash
run: echo "fetch_depth=$(( ${{ github.event.pull_request.commits }} + 2 ))" >> "$GITHUB_OUTPUT"
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }}
- name: Trufflehog
uses: trufflesecurity/trufflehog@ad6fc8fb446b8fafbf7ea8193d2d6bfd42f45690 # v3.90.11
uses: trufflesecurity/trufflehog@eafb8c5f6a06175141c27f17bcc17941853d0047 # v3.90.0
with:
extra_args: --results=verified

View File

@@ -8,7 +8,7 @@ jobs:
if: github.repository == 'grafana/grafana'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: grafana/writers-toolkit/update-make-docs@update-make-docs/v1 # zizmor: ignore[unpinned-uses]

View File

@@ -1,22 +0,0 @@
name: Update Schema Types
on:
push:
branches:
- main
paths:
- docs/sources/developers/plugins/plugin.schema.json
workflow_dispatch:
# These permissions are needed to assume roles from Github's OIDC.
permissions:
contents: read
id-token: write
jobs:
bundle-schema-types:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: grafana/plugin-actions/bundle-schema-types@main

View File

@@ -6,22 +6,18 @@ on:
paths:
- '**/*.cue'
permissions: {}
jobs:
main:
runs-on: "ubuntu-latest"
permissions:
contents: read # clone repository
steps:
- name: "Checkout Grafana repo"
uses: "actions/checkout@v5"
uses: "actions/checkout@v4"
with:
fetch-depth: 0
persist-credentials: false
- name: "Setup Go"
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
with:
go-version-file: go.mod

8
.gitignore vendored
View File

@@ -42,7 +42,6 @@ __debug_bin*
/devenv/docker/blocks/auth/saml-enterprise
/devenv/docker/blocks/auth/signer
/devenv/docker/blocks/mt-db
/devenv/mt-tilt
/tmp
tools/phantomjs/phantomjs
@@ -130,9 +129,6 @@ profile.cov
/public/app/extensions
!/public/app/extensions/.keep
# Enterprise operators
/pkg/operators/enterprise_*
/pkg/operators/**/enterprise_*
debug.test
/examples/*/dist
@@ -253,7 +249,3 @@ public/mockServiceWorker.js
# Ignore unified storage kv store files
/grafana-kv-data
/codeowners-manifest/
# Ignore grafana/hippocampus local cache folder
.hippo

View File

@@ -101,8 +101,6 @@ linters:
- '**/pkg/tsdb/azuremonitor/**/*'
- '**/pkg/tsdb/cloud-monitoring/*'
- '**/pkg/tsdb/cloud-monitoring/**/*'
- '**/pkg/tsdb/graphite/*'
- '**/pkg/tsdb/graphite/**/*'
- '**/pkg/tsdb/mysql/*'
- '**/pkg/tsdb/mysql/**/*'
- '**/pkg/tsdb/parca/*'

View File

@@ -14,9 +14,6 @@ public/sass/*.generated.scss
scripts/grafana-server/tmp
vendor
/coverage
/codeowners-manifest
# TS generate from cue by cuetsy
**/*.gen.ts
@@ -26,7 +23,6 @@ vendor
# Auto-generated theme files
theme.light.generated.json
theme.dark.generated.json
public/app/features/theme-playground/schema.generated.json
# Generated Swagger API specs
public/api-merged.json

File diff suppressed because one or more lines are too long

View File

@@ -25,6 +25,4 @@ plugins:
path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs
spec: "https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.15.0/bundles/@yarnpkg/plugin-licenses.js"
yarnPath: .yarn/releases/yarn-4.10.3.cjs
enableScripts: false
yarnPath: .yarn/releases/yarn-4.9.2.cjs

297
AGENTS.md
View File

@@ -1,297 +0,0 @@
# AGENTS.md
<!-- docs-ai-begin -->
<!-- version: 1.1.0 -->
## Documentation
Instructions for documentation authoring in Markdown files.
DOCS.md contains all the Docs AI toolkit docs in one file.
## Role
Act as an experienced software engineer and technical writer for Grafana Labs.
Write for software developers and engineers who understand general programming concepts.
Focus on practical implementation and clear problem-solving guidance.
### Grafana
Use full product names on first mention, then short names:
- Grafana Alloy (full), Alloy (short)
- Grafana Beyla (full), Beyla (short)
Use "OpenTelemetry Collector" on first mention, then "Collector" for subsequent references.
Keep full name for distributions, headings, and links.
Always use "Grafana Cloud" in full.
Use complete terms:
- "OpenTelemetry" (not "OTel")
- "Kubernetes" (not "K8s")
Present observability signals in order: metrics, logs, traces, and profiles.
Focus content on Grafana solutions when discussing integrations or migrations.
## Style
### Structure
Structure articles into sections with headings.
Leave Markdown front matter content between two triple dashes `---`.
The front matter YAML `title` and the content h1 (#) heading should be the same.
Make sure there's an h1 heading in the content; this redundancy is required.
Always include copy after a heading or between headings, for example:
```markdown
## Heading
Immediately followed by copy and not another heading.
## Sub heading
```
The immediate copy after a heading should introduce and provide an overview of what's covered in the section.
Start articles with an introduction that covers the goal of the article. Example goals:
- Learn concepts
- Set up or install something
- Configure something
- Use a product to solve a business problem
- Troubleshoot a problem
- Integrate with other software or systems
- Migrate from one thing to another
- Refer to APIs or reference documentation
Follow the goal with a list of prerequisites, for example:
```markdown
Before you begin, ensure you have the following:
- <Prerequisite 1>
- <Prerequisite 2>
- ...
```
Suggest and link to next steps and related resources at the end of the article, for example:
- Learn more about A, B, C
- Configure X
- Use X to achieve Y
- Use X to achieve Z
- Project homepage or documentation
- Project repository (for example, GitHub, GitLab)
- Project package (for example, pip or NPM)
You don't need to use the "Refer to..." syntax for next steps; use the link text directly.
### Copy
Write simple, direct copy with short sentences and paragraphs.
Use contractions:
- it's, isn't, that's, you're, don't
Choose simple words:
- use (not utilize)
- help (not assist)
- show (not demonstrate)
Write with verbs and nouns. Use minimal adjectives except when describing Grafana Labs products.
## Tense
Write in present simple tense.
Avoid present continuous tense.
Only write in future tense to show future actions.
### Voice
Always write in an active voice.
Change passive voice to active voice.
### Perspective
Address users as "you".
Use second person perspective consistently.
### Wordlist
Use allowlist/blocklist instead of whitelist/blacklist.
Use primary/secondary instead of master/slave.
Use "refer to" instead of "see", "consult", "check out", and other phrases.
### Formatting
Use sentence case for titles and headings.
Use inline Markdown links: [Link text](https://example.com).
Link to other sections using descriptive phrases that include the section name:
"For setup details, refer to the [Lists](#lists) section."
Bold text with two asterisks: **bold**
Emphasize text with one underscore: _italics_
Format UI elements using sentence case as they appear:
- Click **Submit**.
- Navigate to **User settings**.
- Configure **Alerting rules**.
### Lists
Write complete sentences for lists:
- Works with all languages and frameworks (correct)
- All languages and frameworks (incorrect)
Use dashes for unordered lists.
Bold keywords at list start and follow with a colon.
### Images
Include descriptive alt text that conveys the essential information or purpose.
Write alt text without "Image of..." or "Picture of..." prefixes.
### Code
Use single code backticks for:
- user input
- placeholders in markdown, for example _`<PLACEHOLDER_NAME>`_
- files and directories, for example `/opt/file.md`
- source code keywords and identifiers,
for example variables, function and class names
- configuration options and values, for example `PORT` and `80`
- status codes, for example `404`
Use triple code backticks followed by the syntax for code blocks, for example:
```javascript
console.log('Hello World!');
```
Introduce each code block with a short description.
End the introduction with a colon if the code sample follows it, for example:
```markdown
The code sample outputs "Hello World!" to the browser console:
<CODE_BLOCK>
```
Use descriptive placeholder names in code samples.
Use uppercase letters with underscores to separate words in placeholders,
for example:
```sh
OTEL_RESOURCE_ATTRIBUTES="service.name=<SERVICE_NAME>
OTEL_EXPORTER_OTLP_ENDPOINT=<OTLP_ENDPOINT>
```
The placeholder includes the name and the less than and greater than symbols,
for example <PLACEHOLDER_NAME>.
If the placeholder is markdown emphasize it with underscores,
for example _`<PLACEHOLDER_NAME>`_.
In code blocks use the placeholder without additional backticks or emphasis,
for example <PLACEHOLDER_NAME>.
Provide an explanation for each placeholder,
typically in the text following the code block or in a configuration section.
Follow code samples with an explanation
and configuration options for placeholders, for example:
```markdown
<CODE_BLOCK>
This code sets required environment variables
to send OTLP data to an OTLP endpoint.
To configure the code refer to the configuration section.
<CONFIGURATION>
```
Put configuration for a code block after the code block.
## APIs
When documenting API endpoints specify the HTTP method,
for example `GET`, `POST`, `PUT`, `DELETE`.
Provide the full request path, using backticks.
Use backticks for parameter names and example values.
Use placeholders like `{userId}` for path parameters, for example:
- To retrieve user details, make a `GET` request to `/api/v1/users/{userId}`.
### CLI commands
When presenting CLI commands and their output,
introduce the command with a brief explanation of its purpose.
Clearly distinguish the command from its output.
For commands, use `sh` to specify the code block language.
For output, use a generic specifier like `text`, `console`,
or `json`/`yaml` if the output is structured.
For example:
```markdown
To list all running pods in the `default` namespace, use the following command:
<CODE_BLOCK>
```
The output will resemble the following:
```text
NAME READY STATUS RESTARTS AGE
my-app-deployment-7fdb6c5f65-abcde 1/1 Running 0 2d1h
another-service-pod-xyz123 2/2 Running 0 5h30m
```
### Shortcodes
Leave Hugo shortcodes in the content when editing.
Use our custom admonition Hugo shortcode for notes, cautions, or warnings,
with `<TYPE>` as "note", "caution", or "warning":
```markdown
{{< admonition type="<TYPE>" >}}
...
{{< /admonition >}}
```
Use admonitions sparingly.
Only include exceptional information in admonitions.
<!-- docs-ai-end -->

View File

@@ -1,3 +1,19 @@
<!-- 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 -->
<!-- 12.2.1 START -->
# 12.2.1 (2025-10-21)
@@ -18,296 +34,6 @@
- **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 (2025-09-23)
### Features and enhancements
- ** Alerting:** Add feedback buttons for the new AI helpers (Enterprise)
- **Access:** Remove plugin app access in plugin basic role seeder (Enterprise)
- **Actions:** Infinity authentication [#109493](https://github.com/grafana/grafana/pull/109493), [@adela-almasan](https://github.com/adela-almasan)
- **Alerting:** Add GMA export to the new list page [#109784](https://github.com/grafana/grafana/pull/109784), [@konrad147](https://github.com/konrad147)
- **Alerting:** Add alerting AI buttons for cloud (Enterprise)
- **Alerting:** Add contact point filter to Active Notifications page [#109775](https://github.com/grafana/grafana/pull/109775), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Add enrichment per rule extension component (Enterprise)
- **Alerting:** Add extension point link from alert rule to grafana-metricsdrilldown-app [#108566](https://github.com/grafana/grafana/pull/108566), [@bohandley](https://github.com/bohandley)
- **Alerting:** Add feature toggle and extension point [#110141](https://github.com/grafana/grafana/pull/110141), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
- **Alerting:** Add keepFiringFor and missing_series_evals_to_resolve to file provisioning [#109699](https://github.com/grafana/grafana/pull/109699), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Add observability to enrichment UI (Enterprise)
- **Alerting:** Add tooltips in enrichment list for enrichment type (Enterprise)
- **Alerting:** Alert enrichment list page (Enterprise)
- **Alerting:** Allow filter by rule source in Filter V2 [#110336](https://github.com/grafana/grafana/pull/110336), [@laurenashleigh](https://github.com/laurenashleigh)
- **Alerting:** Auto refresh contact points in the rule form [#109539](https://github.com/grafana/grafana/pull/109539), [@konrad147](https://github.com/konrad147)
- **Alerting:** Check if TimeInterval is used in ActiveTimings when deleting [#110691](https://github.com/grafana/grafana/pull/110691), [@fayzal-g](https://github.com/fayzal-g)
- **Alerting:** Disable group consistency check for GMA rules [#109599](https://github.com/grafana/grafana/pull/109599), [@konrad147](https://github.com/konrad147)
- **Alerting:** Display Error Message in Alert History View [#110123](https://github.com/grafana/grafana/pull/110123), [@laurenashleigh](https://github.com/laurenashleigh)
- **Alerting:** Enrichment Config Form (Enterprise)
- **Alerting:** Filter out private labels before writing recording rules [#109295](https://github.com/grafana/grafana/pull/109295), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** List V2 - Add a group link to the rule list item [#108960](https://github.com/grafana/grafana/pull/108960), [@konrad147](https://github.com/konrad147)
- **Alerting:** List V2 - datasource icons for rules [#109033](https://github.com/grafana/grafana/pull/109033), [@konrad147](https://github.com/konrad147)
- **Alerting:** Load labels in drop-downs without blocking the interaction with the form inputs [#110648](https://github.com/grafana/grafana/pull/110648), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
- **Alerting:** Mark Prometheus to Grafana conversion API as stable [#103499](https://github.com/grafana/grafana/pull/103499), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Move alerting file to an alerting folder [#110257](https://github.com/grafana/grafana/pull/110257), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
- **Alerting:** Support JSON responses in the Prometheus conversion API [#109070](https://github.com/grafana/grafana/pull/109070), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Support extra labels in the Prometheus conversion API [#109136](https://github.com/grafana/grafana/pull/109136), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Support retry with backoff in alert rule evaluation [#99710](https://github.com/grafana/grafana/pull/99710), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Triage alert history with Assistant if available (Enterprise)
- **Auditing:** Add settings to control recording of datasource query request and response body (Enterprise)
- **Auth:** Add setting to disable username based brute force login protection [#109152](https://github.com/grafana/grafana/pull/109152), [@TheoBrigitte](https://github.com/TheoBrigitte)
- **Auth:** Support JWT configs `tls_client_ca` and `jwk_set_bearer_token_file` [#109095](https://github.com/grafana/grafana/pull/109095), [@Baarsgaard](https://github.com/Baarsgaard)
- **Azure:** Resource picker improvements (#109458) [#109520](https://github.com/grafana/grafana/pull/109520), [@aangelisc](https://github.com/aangelisc)
- **Azure:** Show resource group in picker [#110442](https://github.com/grafana/grafana/pull/110442), [@aangelisc](https://github.com/aangelisc)
- **Canvas:** Add option to disable tooltips for one-click elements [#109937](https://github.com/grafana/grafana/pull/109937), [@adela-almasan](https://github.com/adela-almasan)
- **Canvas:** Dynamic connection direction [#108423](https://github.com/grafana/grafana/pull/108423), [@adela-almasan](https://github.com/adela-almasan)
- **Chore:** Remove prometheusCodeModeMetricNamesSearch feature toggle [#109024](https://github.com/grafana/grafana/pull/109024), [@itsmylife](https://github.com/itsmylife)
- **Chore:** Removes HideAngularDeprecation configuration [#110665](https://github.com/grafana/grafana/pull/110665), [@hugohaggmark](https://github.com/hugohaggmark)
- **CloudConfig:** Add config from defaults.ini to StackInfo (Enterprise)
- **CloudWatch:** Append query type to the request id [#109068](https://github.com/grafana/grafana/pull/109068), [@idastambuk](https://github.com/idastambuk)
- **CloudWatch:** Use default region when query region is unset [#109089](https://github.com/grafana/grafana/pull/109089), [@iwysiu](https://github.com/iwysiu)
- **CloudWatch:** Use the correct metric name for errors per function panel in the AWS Lambda sample dashboard [#110718](https://github.com/grafana/grafana/pull/110718), [@kevinwcyu](https://github.com/kevinwcyu)
- **CommandPalette:** Use fuzzySearch util from grafana/data [#108884](https://github.com/grafana/grafana/pull/108884), [@Clarity-89](https://github.com/Clarity-89)
- **Dashboard:** Inspect drawer can no longer be opened with url or linked to [#109617](https://github.com/grafana/grafana/pull/109617), [@torkelo](https://github.com/torkelo)
- **Dashboards:** Add support for full screen panel view and embedded (solo panel) route to repeated panels and new layouts (via new SoloPanelContex) [#107375](https://github.com/grafana/grafana/pull/107375), [@torkelo](https://github.com/torkelo)
- **Dashboards:** Conserve timestamp on time range copy-paste across timezones [#109769](https://github.com/grafana/grafana/pull/109769), [@alik-r](https://github.com/alik-r)
- **Dashboards:** Enable kubernetesDashboards by default [#107618](https://github.com/grafana/grafana/pull/107618), [@dprokop](https://github.com/dprokop)
- **Dashboards:** Make it possible to render variables under a drop-down [#109225](https://github.com/grafana/grafana/pull/109225), [@leventebalogh](https://github.com/leventebalogh)
- **Database:** Add primary key to Settings table (Enterprise)
- **Database:** Add primary key to settings table (Enterprise)
- **Dependencies:** Bump Go to v1.24.5 (Enterprise)
- **Docs:** Deprecate `grafana/grafana-oss` docker repo in favor of `grafana/grafana` [#110065](https://github.com/grafana/grafana/pull/110065), [@kminehart](https://github.com/kminehart)
- **Flame Graph:** Analyze with Grafana Assistant [#108684](https://github.com/grafana/grafana/pull/108684), [@ifrost](https://github.com/ifrost)
- **Folders:** Add team folders feature toggle [#109389](https://github.com/grafana/grafana/pull/109389), [@tomratcliffe](https://github.com/tomratcliffe)
- **Folders:** Update folder using app platform APIs [#110449](https://github.com/grafana/grafana/pull/110449), [@tomratcliffe](https://github.com/tomratcliffe)
- **Folders:** Use app platform search endpoint and update tests [#108814](https://github.com/grafana/grafana/pull/108814), [@tomratcliffe](https://github.com/tomratcliffe)
- **Go:** Update to 1.24.6 [#109313](https://github.com/grafana/grafana/pull/109313), [@Proximyst](https://github.com/Proximyst)
- **InfluxDB:** Ad hoc filters support for expressions [#109344](https://github.com/grafana/grafana/pull/109344), [@aangelisc](https://github.com/aangelisc)
- **Metrics:** Add http_response_size_bytes metric [#110428](https://github.com/grafana/grafana/pull/110428), [@joshhunt](https://github.com/joshhunt)
- **Nested folders:** Remove feature flag [#109212](https://github.com/grafana/grafana/pull/109212), [@stephaniehingtgen](https://github.com/stephaniehingtgen)
- **NestedFolderPicker:** Add rootFolderUID prop [#109991](https://github.com/grafana/grafana/pull/109991), [@ywzheng1](https://github.com/ywzheng1)
- **P2P Filter:** Add adhoc filter option toggle [#110160](https://github.com/grafana/grafana/pull/110160), [@Develer](https://github.com/Develer)
- **PieChart:** Add panel options for ascending/descending sort, and no sorting [#109564](https://github.com/grafana/grafana/pull/109564), [@cglukas](https://github.com/cglukas)
- **Plugin Extensions:** DataSource Configuration Components [#108350](https://github.com/grafana/grafana/pull/108350), [@shelldandy](https://github.com/shelldandy)
- **Plugins:** Add Connections homepage [#108316](https://github.com/grafana/grafana/pull/108316), [@oshirohugo](https://github.com/oshirohugo)
- **Plugins:** Record plugin version in request metrics [#110210](https://github.com/grafana/grafana/pull/110210), [@njvrzm](https://github.com/njvrzm)
- **Preferences:** Move codegen to apps [#109178](https://github.com/grafana/grafana/pull/109178), [@ryantxu](https://github.com/ryantxu)
- **Prometheus data source:** Migration service [#107364](https://github.com/grafana/grafana/pull/107364), [@bossinc](https://github.com/bossinc)
- **Prometheus:** Refactor metrics modal to handle high cardinality metrics [#108437](https://github.com/grafana/grafana/pull/108437), [@itsmylife](https://github.com/itsmylife)
- **Pyroscope:** Process and display sampling annotations [#109707](https://github.com/grafana/grafana/pull/109707), [@aleks-p](https://github.com/aleks-p)
- **Reporting:** Permit valid but weird emails (Enterprise)
- **Reporting:** Show correct recipient count (Enterprise)
- **Revert:** DataSource: Support config CRUD from apiservers (#106996) [#110342](https://github.com/grafana/grafana/pull/110342), [@njvrzm](https://github.com/njvrzm)
- **Revert:** DataSource: Support config CRUD from apiservers (#8860) (Enterprise)
- **SCIM:** Add flag for rejecting non provisioned users from logging in (Enterprise)
- **SCIM:** Allow empty externalId on update operation (Enterprise)
- **SCIM:** Delete user instead of disabling it on SCIM DELETE user request (Enterprise)
- **SQL Expressions:** Switch feature toggle to public preview [#110473](https://github.com/grafana/grafana/pull/110473), [@kylebrandt](https://github.com/kylebrandt)
- **Table:** Frozen columns [#109276](https://github.com/grafana/grafana/pull/109276), [@fastfrwrd](https://github.com/fastfrwrd)
- **Table:** Max row height for variable height rows [#109639](https://github.com/grafana/grafana/pull/109639), [@fastfrwrd](https://github.com/fastfrwrd)
- **Table:** Tooltip from Field [#109428](https://github.com/grafana/grafana/pull/109428), [@fastfrwrd](https://github.com/fastfrwrd)
- **Table:** Update UX for uniform-reducer case in new footer and overflow [#110493](https://github.com/grafana/grafana/pull/110493), [@fastfrwrd](https://github.com/fastfrwrd)
- **TableNG:** Footer enhancements [#102948](https://github.com/grafana/grafana/pull/102948), [@alexjonspencer1](https://github.com/alexjonspencer1)
- **Text:** Add Inter italic font variants to Grafana UI [#110313](https://github.com/grafana/grafana/pull/110313), [@kapowaz](https://github.com/kapowaz)
- **TraceView:** Refine UI visual hierarchy inside details section [#108929](https://github.com/grafana/grafana/pull/108929), [@ifrost](https://github.com/ifrost)
- **Transformations:** Add empty values options to Transpose [#108421](https://github.com/grafana/grafana/pull/108421), [@gelicia](https://github.com/gelicia)
- **Trend/TimeSeries:** Add "Show values" option [#108090](https://github.com/grafana/grafana/pull/108090), [@HasithDeAlwis](https://github.com/HasithDeAlwis)
- **Trend:** Add support for a logarithmic x axis [#101433](https://github.com/grafana/grafana/pull/101433), [@gelicia](https://github.com/gelicia)
- **Variables:** shows warning when user tries to save erroneous variables [#110154](https://github.com/grafana/grafana/pull/110154), [@hugohaggmark](https://github.com/hugohaggmark)
- **VizTooltip:** Replace `ExemplarHoverView` with `VizTooltip` components [#109369](https://github.com/grafana/grafana/pull/109369), [@adela-almasan](https://github.com/adela-almasan)
### Bug fixes
- **Alerting:** Fix bug where rules with identical mute/active intervals produced conflicting routes [#110971](https://github.com/grafana/grafana/pull/110971), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Fix copying of recording rule fields [#110311](https://github.com/grafana/grafana/pull/110311), [@moustafab](https://github.com/moustafab)
- **Alerting:** Fix field names on webhook HMAC/TLS config HCL export [#110722](https://github.com/grafana/grafana/pull/110722), [@JacobsonMT](https://github.com/JacobsonMT)
- **Alerting:** Fix newly created alert rules not immediately showing up in folder view [#109584](https://github.com/grafana/grafana/pull/109584), [@tomratcliffe](https://github.com/tomratcliffe)
- **Alerting:** Fix permission checks for the Import to GMA [#109950](https://github.com/grafana/grafana/pull/109950), [@konrad147](https://github.com/konrad147)
- **Alerting:** Fix permissions for enrichment routes (Enterprise)
- **Alerting:** Fix subpath handling in the alerting package [#109448](https://github.com/grafana/grafana/pull/109448), [@konrad147](https://github.com/konrad147)
- **Alerting:** Fix wrong import (Enterprise)
- **Alerting:** Hide list view loader if we don't have anything yet [#110464](https://github.com/grafana/grafana/pull/110464), [@gillesdemey](https://github.com/gillesdemey)
- **Alerting:** Set dataSourceName to GRAFANA_RULES_SOURCE_NAME when switch… [#109900](https://github.com/grafana/grafana/pull/109900), [@laurenashleigh](https://github.com/laurenashleigh)
- **Alerting:** Update alerting module to 10915888e4f099586ad37bea5f4a70f45101d2f5 [#109989](https://github.com/grafana/grafana/pull/109989), [@yuri-tceretian](https://github.com/yuri-tceretian)
- **Azure:** Fix logs editor rendering [#109491](https://github.com/grafana/grafana/pull/109491), [@aangelisc](https://github.com/aangelisc)
- **Canvas:** Fix element selection being cleared on panel resize [#110010](https://github.com/grafana/grafana/pull/110010), [@adela-almasan](https://github.com/adela-almasan)
- **CloudConfig:** Fix panic in defaults.ini merge (Enterprise)
- **CloudWatch:** Fix handling region for legacy alerts [#109217](https://github.com/grafana/grafana/pull/109217), [@iwysiu](https://github.com/iwysiu)
- **CloudWatch:** Fix logs query requestId to prevent setting undefined-logs as a requestId [#109930](https://github.com/grafana/grafana/pull/109930), [@kevinwcyu](https://github.com/kevinwcyu)
- **CloudWatch:** Update grafana/aws-sdk-go with STS endpoint bugfix [#109120](https://github.com/grafana/grafana/pull/109120), [@idastambuk](https://github.com/idastambuk)
- **Config:** Fix date_formats options being moved to a different section [#109339](https://github.com/grafana/grafana/pull/109339), [@joshhunt](https://github.com/joshhunt)
- **Dashboard List:** Fix how link query part is created when variables are included [#109861](https://github.com/grafana/grafana/pull/109861), [@aocenas](https://github.com/aocenas)
- **Dashboard versions:** Fix list for large dashboards [#109433](https://github.com/grafana/grafana/pull/109433), [@stephaniehingtgen](https://github.com/stephaniehingtgen)
- **Dashboard:** Fix AngularJS deprecation in grafana-overview dashboard [#106462](https://github.com/grafana/grafana/pull/106462), [@schoen2](https://github.com/schoen2)
- **Dashboard:** Fixes url links to embedded panels in scene based dashboards [#109837](https://github.com/grafana/grafana/pull/109837), [@torkelo](https://github.com/torkelo)
- **Dashboards:** Fix UTF-8 characters not working with excel downloads by replacing download for excel with excel compatibility mode. [#110099](https://github.com/grafana/grafana/pull/110099), [@oscarkilhed](https://github.com/oscarkilhed)
- **Dashboards:** Fix issue where the time range picker would seemingly be hidden behind the side menu if it was set to always open. [#108607](https://github.com/grafana/grafana/pull/108607), [@oscarkilhed](https://github.com/oscarkilhed)
- **Dashboards:** Fix kiosk mode not persisting through refresh [#110284](https://github.com/grafana/grafana/pull/110284), [@oscarkilhed](https://github.com/oscarkilhed)
- **Dashboards:** Fixing saving and viewing snapshots for repeated panels [#109856](https://github.com/grafana/grafana/pull/109856), [@torkelo](https://github.com/torkelo)
- **Explore:** Fix units overflow for trace durations [#108515](https://github.com/grafana/grafana/pull/108515), [@martincostello](https://github.com/martincostello)
- **Fix:** Install plugins when they have no plugin archive info(catalog en… [#109200](https://github.com/grafana/grafana/pull/109200), [@s4kh](https://github.com/s4kh)
- **InfluxDB:** Fix Unable to use self-signed CA for adding influxdb data source [#105586](https://github.com/grafana/grafana/pull/105586), [@geekeryy](https://github.com/geekeryy)
- **Prometheus:** Don't use incremental querying if one of the queries has $\_\_range variable [#108823](https://github.com/grafana/grafana/pull/108823), [@itsmylife](https://github.com/itsmylife)
- **Prometheus:** Fix eager auto completion [#109128](https://github.com/grafana/grafana/pull/109128), [@itsmylife](https://github.com/itsmylife)
- **Prometheus:** QueryEditor fix error when switching from code to builder for undefined aggregation operations [#110179](https://github.com/grafana/grafana/pull/110179), [@jcolladokuri](https://github.com/jcolladokuri)
- **Pyroscope:** Add start and end date to profiletypes call [#110277](https://github.com/grafana/grafana/pull/110277), [@zoltanbedi](https://github.com/zoltanbedi)
- **Pyroscope:** Fix incorrect rate calculation from flamegraph totals [#110470](https://github.com/grafana/grafana/pull/110470), [@marcsanmi](https://github.com/marcsanmi)
- **Service Accounts:** Fix typo on page indicating none are present [#109560](https://github.com/grafana/grafana/pull/109560), [@eamonryan](https://github.com/eamonryan)
- **Tempo:** Fix instant query streaming [#108924](https://github.com/grafana/grafana/pull/108924), [@adrapereira](https://github.com/adrapereira)
- **TimeSeries:** Use exported time shift and fix time comparison tooltip [#109947](https://github.com/grafana/grafana/pull/109947), [@drew08t](https://github.com/drew08t)
- **Transformations:** Account for group by / count when assessing if calculation is needed [#110546](https://github.com/grafana/grafana/pull/110546), [@gelicia](https://github.com/gelicia)
- **Transforms:** GroupToMatrix transform should retain keyRowField config [#109066](https://github.com/grafana/grafana/pull/109066), [@fastfrwrd](https://github.com/fastfrwrd)
### Breaking changes
- **Alerting:** Enable alertingSaveStateCompressed by default [#109390](https://github.com/grafana/grafana/pull/109390), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Dashboards:** Repeating with no clone keys [#109839](https://github.com/grafana/grafana/pull/109839), [@torkelo](https://github.com/torkelo)
- **Provisioning:** Use inline secrets for gitsync [#109908](https://github.com/grafana/grafana/pull/109908), [@ryantxu](https://github.com/ryantxu)
- **Stars:** Remove deprecated internal ID apis [#110499](https://github.com/grafana/grafana/pull/110499), [@ryantxu](https://github.com/ryantxu)
### Plugin development fixes & changes
- **Drawer:** Truncate Drawer title to just one line [#109540](https://github.com/grafana/grafana/pull/109540), [@joshhunt](https://github.com/joshhunt)
- **Modal:** Center modals at smaller screen heights [#109256](https://github.com/grafana/grafana/pull/109256), [@ashharrison90](https://github.com/ashharrison90)
- **MultiCombobox:** Fix async options to being able to be removed [#109473](https://github.com/grafana/grafana/pull/109473), [@joshhunt](https://github.com/joshhunt)
- **MultiCombobox:** Fix select all when only a single option is available [#109910](https://github.com/grafana/grafana/pull/109910), [@aangelisc](https://github.com/aangelisc)
<!-- 12.2.0 END -->
<!-- 12.1.2 START -->
# 12.1.2 (2025-09-23)
### Features and enhancements
- **Alerting:** Update alerting module [#109999](https://github.com/grafana/grafana/pull/109999), [@yuri-tceretian](https://github.com/yuri-tceretian)
- **Auditing:** Add settings to control recording of datasource query request and response body (Enterprise)
- **Auditing:** Document new options for recording datasource query request/response body [#109981](https://github.com/grafana/grafana/pull/109981), [@macabu](https://github.com/macabu)
- **Chore:** Don't show a "Not found" for public-dashboard fetches if the service is disabled via config [#110144](https://github.com/grafana/grafana/pull/110144), [@mmandrus](https://github.com/mmandrus)
- **CloudWatch:** Use default region when query region is unset [#111079](https://github.com/grafana/grafana/pull/111079), [@iwysiu](https://github.com/iwysiu)
### Bug fixes
- **Alerting:** Fix bug where rules with identical mute/active intervals produced conflicting routes [#110973](https://github.com/grafana/grafana/pull/110973), [@alexander-akhmetov](https://github.com/alexander-akhmetov)
- **Alerting:** Fix copying of recording rule fields [#110312](https://github.com/grafana/grafana/pull/110312), [@moustafab](https://github.com/moustafab)
- **Fix:** Fix redirection after login when Grafana is served from subpath [#111097](https://github.com/grafana/grafana/pull/111097), [@mgyongyosi](https://github.com/mgyongyosi)
### Plugin development fixes & changes
- **Fix:** Prevent Rollup from treeshaking NPM packages [#108570](https://github.com/grafana/grafana/pull/108570), [@jackw](https://github.com/jackw)
<!-- 12.1.2 END -->
<!-- 12.0.5 START -->
# 12.0.5 (2025-09-23)
### Features and enhancements
- **Alerting:** Update alerting module [#110000](https://github.com/grafana/grafana/pull/110000), [@yuri-tceretian](https://github.com/yuri-tceretian)
- **Auditing:** Add settings to control recording of datasource query request and response body (Enterprise)
- **Auditing:** Document new options for recording datasource query request/response body [#109980](https://github.com/grafana/grafana/pull/109980), [@macabu](https://github.com/macabu)
### Bug fixes
- **Alerting:** Fix copying of recording rule fields [#110346](https://github.com/grafana/grafana/pull/110346), [@moustafab](https://github.com/moustafab)
- **Azure:** Fix time management field [#108481](https://github.com/grafana/grafana/pull/108481), [@aangelisc](https://github.com/aangelisc)
- **Fix:** Fix redirection after login when Grafana is served from subpath [#111156](https://github.com/grafana/grafana/pull/111156), [@mgyongyosi](https://github.com/mgyongyosi)
### Plugin development fixes & changes
- **Fix:** Prevent Rollup from treeshaking NPM packages [#110523](https://github.com/grafana/grafana/pull/110523), [@jackw](https://github.com/jackw)
<!-- 12.0.5 END -->
<!-- 11.6.6 START -->
# 11.6.6 (2025-09-23)
### Features and enhancements
- **Auditing:** Add settings to control recording of datasource query request and response body (Enterprise)
<!-- 11.6.6 END -->
<!-- 11.5.9 START -->
# 11.5.9 (2025-09-23)
### Features and enhancements
- **Auditing:** Add settings to control recording of datasource query request and response body (Enterprise)
- **Auditing:** Document new options for recording datasource query request/response body [#109976](https://github.com/grafana/grafana/pull/109976), [@macabu](https://github.com/macabu)
### Bug fixes
- **Fix:** Fix redirection after login when Grafana is served from subpath [#111099](https://github.com/grafana/grafana/pull/111099), [@mgyongyosi](https://github.com/mgyongyosi)
<!-- 11.5.9 END -->
<!-- 12.1.1 START -->
# 12.1.1 (2025-08-13)

View File

@@ -2,82 +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).
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. Its 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- its designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem.
Whether you're a new contributor or a seasoned veteran, we hope these resources help you connect with the community.
Whether you're a new contributer 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)!
- **Community Slack:** Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
#### Learn
- **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:** Wed 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 well 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.
- 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)!
- Community Slack: Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
Learn:
- 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.
Share your story:
- Meetups and blogs: Wed 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 well connect with you on next steps if accepted.
## 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.
- 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)).
### Your first contribution
**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).
1. Prepare a clear, descriptive pull request ([how-to guide](contribute/create-pull-request.md)).
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.
- [Beginner-friendly](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22) issues are generally straightforward to complete.
- [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.
### 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.
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.
Developing a Grafana plugin is a fantastic way to share your unique ideas with the community, extend the platforms 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)
### Contribute without code
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
### Report bugs
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.
@@ -90,11 +59,11 @@ For data visualization issues:
- Query results from the inspect drawer (data tab & query inspector)
- 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
@@ -106,7 +75,7 @@ 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.
### 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).

View File

@@ -14,7 +14,7 @@ ARG JS_SRC=js-builder
# Dependabot cannot update dependencies listed in ARGs
# By using FROM instructions we can delegate dependency updates to dependabot
FROM alpine:3.22.2 AS alpine-base
FROM alpine:3.21.3 AS alpine-base
FROM ubuntu:22.04 AS ubuntu-base
FROM golang:1.25.3-alpine AS go-builder-base
FROM --platform=${JS_PLATFORM} node:22-alpine AS js-builder-base
@@ -95,13 +95,10 @@ COPY pkg/aggregator pkg/aggregator
COPY apps/playlist apps/playlist
COPY apps/plugins apps/plugins
COPY apps/shorturl apps/shorturl
COPY apps/correlations apps/correlations
COPY apps/preferences apps/preferences
COPY apps/provisioning apps/provisioning
COPY apps/secret apps/secret
COPY apps/scope apps/scope
COPY apps/investigations apps/investigations
COPY apps/logsdrilldown apps/logsdrilldown
COPY apps/advisor apps/advisor
COPY apps/dashboard apps/dashboard
COPY apps/folder apps/folder
@@ -109,9 +106,8 @@ COPY apps/preferences apps/preferences
COPY apps/iam apps/iam
COPY apps apps
COPY kindsv2 kindsv2
COPY apps/alerting/alertenrichment apps/alerting/alertenrichment
COPY apps/alerting/notifications apps/alerting/notifications
COPY apps/alerting/rules apps/alerting/rules
COPY apps/alerting/alertenrichment apps/alerting/alertenrichment
COPY pkg/codegen pkg/codegen
COPY pkg/plugins/codegen pkg/plugins/codegen

View File

@@ -17,7 +17,6 @@ GO_RACE_FLAG := $(if $(GO_RACE),-race)
GO_BUILD_FLAGS += $(if $(GO_BUILD_DEV),-dev)
GO_BUILD_FLAGS += $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS))
GO_BUILD_FLAGS += $(GO_RACE_FLAG)
GO_BUILD_FLAGS += $(if $(GO_BUILD_CGO),-cgo-enabled=$(GO_BUILD_CGO))
GO_TEST_FLAGS += $(if $(GO_BUILD_TAGS),-tags=$(GO_BUILD_TAGS))
GIT_BASE = remotes/origin/main
@@ -71,7 +70,6 @@ swagger-oss-gen: ## Generate API Swagger specification
-x "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" \
-x "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" \
-x "github.com/prometheus/alertmanager" \
-x "github.com/docker/docker" \
-i pkg/api/swagger_tags.json \
--exclude-tag=alpha \
--exclude-tag=enterprise
@@ -90,7 +88,6 @@ swagger-enterprise-gen: ## Generate API Swagger specification
-x "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" \
-x "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" \
-x "github.com/prometheus/alertmanager" \
-x "github.com/docker/docker" \
-i pkg/api/swagger_tags.json \
-t enterprise \
--exclude-tag=alpha \
@@ -174,19 +171,7 @@ gen-cuev2: ## Do all CUE code generation
APPS_DIRS := ./apps/dashboard ./apps/folder ./apps/alerting/notifications
.PHONY: gen-apps
gen-apps: do-gen-apps gofmt ## Generate code for Grafana App SDK apps and run gofmt
@if [ -n "$$CODEGEN_VERIFY" ]; then \
echo "Verifying generated code is up to date..."; \
if ! git diff --quiet; then \
echo "Error: Generated apps code is not up to date. Please run 'make gen-apps' to regenerate."; \
git diff --name-only; \
exit 1; \
fi; \
echo "Generated apps code is up to date."; \
fi
.PHONY: do-gen-apps
do-gen-apps: ## Generate code for Grafana App SDK apps
gen-apps: ## Generate code for Grafana App SDK apps
for dir in $(APPS_DIRS); do \
$(MAKE) -C $$dir generate; \
done
@@ -233,23 +218,19 @@ update-workspace: gen-go
bash scripts/go-workspace/update-workspace.sh
.PHONY: build-go
build-go: ## Build all Go binaries.
build-go: gen-go update-workspace ## Build all Go binaries.
@echo "build go files with updated workspace"
$(GO) run build.go $(GO_BUILD_FLAGS) build
.PHONY: build-go-fast
build-go-fast: ## Build all Go binaries without updating workspace.
@echo "!!! [DEPRECATED] use build-go, they do the same thing now. This command will be removed soon"
build-go-fast: gen-go ## Build all Go binaries.
@echo "build go files"
$(GO) run build.go $(GO_BUILD_FLAGS) build
.PHONY: build-backend
build-backend: ## Build Grafana backend.
@echo "build backend"
$(GO) run build.go $(GO_BUILD_FLAGS) build-backend
.PHONY: build-air
build-air: build-backend
@cp ./bin/grafana ./bin/grafana-air
.PHONY: build-server
build-server: ## Build Grafana server.
@echo "build server"
@@ -405,7 +386,7 @@ lint-go-diff:
.PHONY: gofmt
gofmt: ## Run gofmt for all Go files.
@go list -m -f '{{.Dir}}' | xargs -I{} sh -c 'test ! -f {}/.nolint && echo {}' | xargs gofmt -s -w 2>&1 | grep -v '/pkg/build/' || true
gofmt -s -w .
# with disabled SC1071 we are ignored some TCL,Expect `/usr/bin/env expect` scripts
.PHONY: shellcheck

View File

@@ -8,7 +8,7 @@ require (
github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
github.com/grafana/grafana-app-sdk v0.40.2
github.com/grafana/grafana-app-sdk/logging v0.40.2
github.com/grafana/grafana-app-sdk/logging v0.40.1
github.com/grafana/grafana-plugin-sdk-go v0.278.0
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2
github.com/stretchr/testify v1.10.0
@@ -244,14 +244,14 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.36.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.37.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/otlptracegrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp 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/trace v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
@@ -291,9 +291,10 @@ require (
modernc.org/libc v1.65.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.10.0 // indirect
modernc.org/sqlite v1.38.0 // indirect
modernc.org/sqlite v1.37.0 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
sigs.k8s.io/yaml v1.5.0 // indirect
xorm.io/builder v0.3.6 // indirect
)

View File

@@ -665,8 +665,8 @@ github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E=
github.com/grafana/grafana-app-sdk v0.40.2 h1:j2ftFuqhX+exYUipfEjeWDs3i7oiJkweTF8gFLL7wWU=
github.com/grafana/grafana-app-sdk v0.40.2/go.mod h1:BbNXPNki3mtbkWxYqJsyA1Cj9AShSyaY33z8WkyfVv0=
github.com/grafana/grafana-app-sdk/logging v0.40.2 h1:HQ1+y9Od92iMbWWB54QxiYpNtCvYGUVpyxvxZ7ywB1k=
github.com/grafana/grafana-app-sdk/logging v0.40.2/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU=
github.com/grafana/grafana-app-sdk/logging v0.40.1 h1:ru+GqbaQk6jthA5l2Yo1WI/JbNXKNQmLiqNrxz7HGP4=
github.com/grafana/grafana-app-sdk/logging v0.40.1/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU=
github.com/grafana/grafana-aws-sdk v1.1.0 h1:G0fvwbQmHw14c5RXPd7Gnw9ZQcgzl139LtMDoe0KhmE=
github.com/grafana/grafana-aws-sdk v1.1.0/go.mod h1:7e+47EdHynteYWGoT5Ere9KeOXQObsk8F0vkOLQ1tz8=
github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 h1:0TYrkzAc3u0HX+9GK86cGrLTUAcmQfl3/LEB3tL+SOA=

View File

@@ -7,7 +7,6 @@ import (
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/k8s"
"github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/operator"
"github.com/grafana/grafana-app-sdk/resource"
"github.com/grafana/grafana-app-sdk/simple"
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
@@ -49,10 +48,8 @@ func New(cfg app.Config) (app.App, error) {
Name: "advisor",
KubeConfig: cfg.KubeConfig,
InformerConfig: simple.AppInformerConfig{
InformerOptions: operator.InformerOptions{
ErrorHandler: func(ctx context.Context, err error) {
log.WithContext(ctx).Error("Informer processing error", "error", err)
},
ErrorHandler: func(ctx context.Context, err error) {
log.WithContext(ctx).Error("Informer processing error", "error", err)
},
},
ManagedKinds: []simple.AppManagedKind{
@@ -69,12 +66,12 @@ func New(cfg app.Config) (app.App, error) {
go func() {
logger := log.WithContext(ctx).With("check", check.ID())
logger.Debug("Processing check", "namespace", req.Object.GetNamespace())
orgID, err := getOrgIDFromNamespace(req.Object.GetNamespace())
requester, err := identity.GetRequester(ctx)
if err != nil {
logger.Error("Error getting org ID from namespace", "error", err)
logger.Error("Error getting requester", "error", err)
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)
if err != nil {
logger.Error("Error processing check", "error", err)
@@ -85,12 +82,12 @@ func New(cfg app.Config) (app.App, error) {
go func() {
logger := log.WithContext(ctx).With("check", check.ID())
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 {
logger.Error("Error getting org ID from namespace", "error", err)
logger.Error("Error getting requester", "error", err)
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)
if err != nil {
logger.Error("Error processing check retry", "error", err)

View File

@@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/repo"
"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/pluginchecker"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
@@ -92,5 +91,4 @@ type AdvisorAppConfig struct {
CheckRegistry CheckService
PluginConfig map[string]string
StackID string
OrgService org.Service
}

View File

@@ -3,8 +3,6 @@ package datasourcecheck
import (
"context"
"errors"
sysruntime "runtime"
"sync"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
@@ -20,18 +18,15 @@ const (
HealthCheckStepID = "health-check"
UIDValidationStepID = "uid-validation"
MissingPluginStepID = "missing-plugin"
PromDepAuthStepID = "prom-dep-auth"
)
type check struct {
DatasourceSvc datasources.DataSourceService
PluginStore pluginstore.Store
PluginContextProvider pluginContextProvider
PluginClient plugins.Client
PluginRepo repo.Service
GrafanaVersion string
pluginCanBeInstalledCache map[string]bool
pluginExistsCacheMu sync.RWMutex
DatasourceSvc datasources.DataSourceService
PluginStore pluginstore.Store
PluginContextProvider pluginContextProvider
PluginClient plugins.Client
PluginRepo repo.Service
GrafanaVersion string
}
func New(
@@ -43,24 +38,17 @@ func New(
grafanaVersion string,
) checks.Check {
return &check{
DatasourceSvc: datasourceSvc,
PluginStore: pluginStore,
PluginContextProvider: pluginContextProvider,
PluginClient: pluginClient,
PluginRepo: pluginRepo,
GrafanaVersion: grafanaVersion,
pluginCanBeInstalledCache: make(map[string]bool),
DatasourceSvc: datasourceSvc,
PluginStore: pluginStore,
PluginContextProvider: pluginContextProvider,
PluginClient: pluginClient,
PluginRepo: pluginRepo,
GrafanaVersion: grafanaVersion,
}
}
func (c *check) Items(ctx context.Context) ([]any, error) {
requester, err := identity.GetRequester(ctx)
if err != nil {
return nil, err
}
dss, err := c.DatasourceSvc.GetDataSources(ctx, &datasources.GetDataSourcesQuery{
OrgID: requester.GetOrgID(),
})
dss, err := c.DatasourceSvc.GetAllDataSources(ctx, &datasources.GetAllDataSourcesQuery{})
if err != nil {
return nil, err
}
@@ -99,7 +87,6 @@ func (c *check) Name() string {
}
func (c *check) Init(ctx context.Context) error {
c.pluginCanBeInstalledCache = make(map[string]bool)
return nil
}
@@ -115,59 +102,9 @@ func (c *check) Steps() []checks.Step {
PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion,
},
&promDepAuthStep{
canBeInstalled: c.canBeInstalled,
},
}
}
// canBeInstalled checks if a plugin is already installed or if it's available in the plugin repository.
// 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)
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"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/repo"
"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.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) {
@@ -347,7 +251,7 @@ type MockDatasourceSvc struct {
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
}

View File

@@ -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
}

View File

@@ -5,8 +5,6 @@ import (
"testing"
"github.com/grafana/grafana-app-sdk/logging"
"github.com/stretchr/testify/assert"
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/repo"
@@ -14,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
"github.com/stretchr/testify/assert"
)
func TestRun(t *testing.T) {
@@ -23,7 +22,7 @@ func TestRun(t *testing.T) {
pluginInfo []repo.PluginInfo
pluginPreinstalled []string
pluginManaged []string
pluginProvisioned []provisionedplugins.Plugin
pluginProvisioned []string
pluginErrors []*plugins.Error
expectedFailures []advisor.CheckReportFailure
}{
@@ -118,7 +117,7 @@ func TestRun(t *testing.T) {
pluginInfo: []repo.PluginInfo{
{Status: "deprecated", Slug: "plugin5", Version: "1.1.0"}, // This should be ignored
},
pluginProvisioned: []provisionedplugins.Plugin{{ID: "plugin5"}},
pluginProvisioned: []string{"plugin5"},
expectedFailures: []advisor.CheckReportFailure{},
},
{
@@ -282,10 +281,10 @@ func (m *mockManagedPlugins) ManagedPlugins(ctx context.Context) []string {
type mockProvisionedPlugins struct {
provisionedplugins.Manager
provisioned []provisionedplugins.Plugin
provisioned []string
}
func (m *mockProvisionedPlugins) ProvisionedPlugins(_ context.Context) ([]provisionedplugins.Plugin, error) {
func (m *mockProvisionedPlugins) ProvisionedPlugins(ctx context.Context) ([]string, error) {
return m.provisioned, nil
}

View File

@@ -9,7 +9,7 @@ import (
"github.com/grafana/authlib/types"
"github.com/grafana/grafana-app-sdk/resource"
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 (
@@ -57,26 +57,15 @@ func NewCheckReportFailureWithMoreInfo(
}
}
func GetNamespaces(ctx context.Context, stackID string, orgService org.Service) ([]string, error) {
var namespaces []string
if stackID != "" {
// 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))
}
func GetNamespace(stackID string) (string, error) {
if stackID == "" {
return metav1.NamespaceDefault, nil
}
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 {

View File

@@ -1,61 +1,40 @@
package checks
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/org"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestGetNamespaces(t *testing.T) {
func TestGetNamespace(t *testing.T) {
tests := []struct {
name string
stackID string
orgs []string
expected []string
input string
expected string
expectedErr string
}{
{
name: "empty stack ID",
stackID: "",
orgs: []string{"default"},
expected: []string{metav1.NamespaceDefault},
input: "",
expected: metav1.NamespaceDefault,
},
{
name: "valid stack ID",
stackID: "1234567890",
orgs: []string{"default"},
expected: []string{"stacks-1234567890"},
input: "1234567890",
expected: "stacks-1234567890",
},
{
name: "invalid stack ID",
stackID: "invalid",
orgs: []string{"default"},
expected: nil,
input: "invalid",
expected: "",
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 {
t.Run(tt.name, func(t *testing.T) {
fakeOrgService := &mockOrgService{
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)
result, err := GetNamespace(tt.input)
if tt.expectedErr != "" {
assert.EqualError(t, err, tt.expectedErr)
} 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)
}

View File

@@ -16,7 +16,6 @@ import (
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/pkg/services/org"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -24,23 +23,21 @@ const defaultEvaluationInterval = 7 * 24 * time.Hour // 7 days
const defaultMaxHistory = 10
var (
waitInterval = 5 * time.Second
waitMaxRetries = 3
evalIntervalRandomVariation = 1 * time.Hour
waitInterval = 5 * time.Second
waitMaxRetries = 3
)
// 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
// the only way existing at the moment to expose the check types.
type Runner struct {
checkRegistry checkregistry.CheckService
checksClient resource.Client
typesClient resource.Client
defaultEvalInterval time.Duration
maxHistory int
log logging.Logger
orgService org.Service
stackID string
checkRegistry checkregistry.CheckService
client resource.Client
typesClient resource.Client
evaluationInterval time.Duration
maxHistory int
namespace string
log logging.Logger
}
// 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")
}
checkRegistry := specificConfig.CheckRegistry
orgService := specificConfig.OrgService
evalInterval, err := getEvaluationInterval(specificConfig.PluginConfig)
if err != nil {
return nil, err
@@ -60,6 +56,10 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
if err != nil {
return nil, err
}
namespace, err := checks.GetNamespace(specificConfig.StackID)
if err != nil {
return nil, err
}
// Prepare storage client
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
@@ -73,14 +73,13 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
}
return &Runner{
checkRegistry: checkRegistry,
checksClient: client,
typesClient: typesClient,
defaultEvalInterval: evalInterval,
maxHistory: maxHistory,
log: log.With("runner", "advisor.checkscheduler"),
orgService: orgService,
stackID: specificConfig.StackID,
checkRegistry: checkRegistry,
client: client,
typesClient: typesClient,
evaluationInterval: evalInterval,
maxHistory: maxHistory,
namespace: namespace,
log: log.With("runner", "advisor.checkscheduler"),
}, nil
}
@@ -89,91 +88,58 @@ func (r *Runner) Run(ctx context.Context) error {
// 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
ctxWithoutCancel := context.WithoutCancel(ctx)
// 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)
lastCreated, err := r.checkLastCreated(ctxWithoutCancel, logger)
if err != nil {
logger.Error("Error getting last check creation time", "error", err)
return err
}
// If there are checks already created, run an initial cleanup
for _, namespace := range namespaces {
logger = logger.With("namespace", namespace)
lastCreated := lastCreatedMap[namespace]
if !lastCreated.IsZero() {
err = r.cleanupChecks(ctx, logger, namespace)
// Wait for interval to create the next scheduled check
lastCreated = time.Now()
} else {
// do an initial creation if necessary
if lastCreated.IsZero() {
err = r.createChecks(ctxWithoutCancel, logger)
if err != nil {
logger.Error("Error creating new check reports", "error", err)
} else {
lastCreated = time.Now()
}
} else {
// Run an initial cleanup to remove old checks
err = r.cleanupChecks(ctxWithoutCancel, logger)
if err != nil {
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)
ticker := time.NewTicker(nextEvalTime)
nextSendInterval := getNextSendInterval(lastCreated, r.evaluationInterval)
ticker := time.NewTicker(nextSendInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// Get the current last created time for this namespace
lastCreatedMap, err := r.checkLastCreated(ctx, logger, namespaces)
err = r.createChecks(ctxWithoutCancel, logger)
if err != nil {
logger.Error("Error getting last check creation time", "error", err)
return err
logger.Error("Error creating new check reports", "error", err)
}
for _, namespace := range namespaces {
logger = logger.With("namespace", namespace)
lastCreated := lastCreatedMap[namespace]
// 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()
}
err = r.cleanupChecks(ctxWithoutCancel, logger)
if err != nil {
logger.Error("Error cleaning up old check reports", "error", err)
}
// Reset the ticker to the next send interval
nextEvalTime = r.getNextEvalTime(r.defaultEvalInterval, lastCreatedMap)
ticker.Reset(nextEvalTime)
if nextSendInterval != r.evaluationInterval {
nextSendInterval = r.evaluationInterval
}
ticker.Reset(nextSendInterval)
case <-ctx.Done():
return ctx.Err()
}
}
}
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespace string) ([]resource.Object, error) {
list, err := r.checksClient.List(ctx, namespace, resource.ListOptions{
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resource.Object, error) {
list, err := r.client.List(ctx, r.namespace, resource.ListOptions{
Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation
})
if err != nil {
@@ -183,7 +149,7 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespac
checks := list.GetItems()
for 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 {
return nil, err
}
@@ -192,48 +158,38 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespac
return checks, nil
}
// checkLastCreated returns the creation time of the last check created for a specific namespace.
// This assumes that the checks are created in batches so a batch will have a similar creation time.
// checkLastCreated returns the creation time of the last check created
// 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.
func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger, namespaces []string) (map[string]time.Time, error) {
lastCreated := map[string]time.Time{}
for _, namespace := range namespaces {
checkList, err := r.listChecks(ctx, log, namespace)
if err != nil {
return nil, err
func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger) (time.Time, error) {
checkList, err := r.listChecks(ctx, log)
if err != nil {
return time.Time{}, 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 itemCreated.After(lastCreated[namespace]) {
lastCreated[namespace] = itemCreated
// If the check is unprocessed, set it to error
if checks.GetStatusAnnotation(item) == "" {
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
}
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.
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, err := r.typesClient.List(ctx, namespace, resource.ListOptions{})
list, err := r.typesClient.List(ctx, r.namespace, resource.ListOptions{})
if err != nil {
return fmt.Errorf("error listing check types: %w", err)
}
@@ -243,7 +199,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
for !allChecksRegistered && retryCount < waitMaxRetries {
logger.Info("Waiting for all check types to be registered", "retryCount", retryCount, "waitInterval", 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 {
return fmt.Errorf("error listing check types: %w", err)
}
@@ -261,7 +217,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
obj := &advisorv0alpha1.Check{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "check-",
Namespace: namespace,
Namespace: r.namespace,
Labels: map[string]string{
checks.TypeLabel: checkType.Spec.Name,
},
@@ -269,7 +225,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namesp
Spec: advisorv0alpha1.CheckSpec{},
}
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 {
return fmt.Errorf("error creating check: %w", err)
}
@@ -278,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.
func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger, namespace string) error {
checkList, err := r.listChecks(ctx, logger, namespace)
func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger) error {
checkList, err := r.listChecks(ctx, logger)
if err != nil {
return err
}
logger.Debug("Cleaning up checks", "namespace", namespace, "numChecks", len(checkList))
logger.Debug("Cleaning up checks", "numChecks", len(checkList))
// organize checks by type
checksByType := map[string][]resource.Object{}
@@ -312,7 +268,7 @@ func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger, names
for i := 0; i < len(checks)-r.maxHistory; i++ {
check := checks[i]
id := check.GetStaticMetadata().Identifier()
err := r.checksClient.Delete(ctx, id, resource.DeleteOptions{})
err := r.client.Delete(ctx, id, resource.DeleteOptions{})
if err != nil {
return fmt.Errorf("error deleting check: %w", err)
}
@@ -337,28 +293,15 @@ func getEvaluationInterval(pluginConfig map[string]string) (time.Duration, error
return evaluationInterval, nil
}
func (r *Runner) getNextEvalTime(defaultEvaluationInterval time.Duration, lastCreated map[string]time.Time) time.Duration {
nextEvalTime := defaultEvaluationInterval
// Get the oldest last created time
baseTime := time.Now()
for _, lastNamespacedCreated := range lastCreated {
if !lastNamespacedCreated.IsZero() && lastNamespacedCreated.Before(baseTime) {
baseTime = lastNamespacedCreated
}
func getNextSendInterval(lastCreated time.Time, evaluationInterval time.Duration) time.Duration {
nextSendInterval := time.Until(lastCreated.Add(evaluationInterval))
// Add random variation of one hour
randomVariation := time.Duration(rand.Int63n(time.Hour.Nanoseconds()))
nextSendInterval += randomVariation
if nextSendInterval < time.Minute {
nextSendInterval = 1 * time.Minute
}
// 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
return nextSendInterval
}
func getMaxHistory(pluginConfig map[string]string) (int, error) {

View File

@@ -4,50 +4,26 @@ import (
"context"
"errors"
"fmt"
"math/rand/v2"
"testing"
"time"
"github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/resource"
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/pkg/services/org"
"github.com/stretchr/testify/assert"
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) {
t.Run("handles context cancellation gracefully", 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) {
t.Run("does not crash when error on list", func(t *testing.T) {
mockClient := &MockClient{
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)
err := runner.Run(context.Background())
assert.ErrorContains(t, err, "list checks error")
runner := &Runner{
client: mockClient,
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_Run_CheckCreation(t *testing.T) {
t.Run("does not create checks on first run when no previous checks exist", func(t *testing.T) {
checksCreated := []string{}
func TestRunner_checkLastCreated_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")
},
}
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
// Return empty list - no previous checks
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
},
}
runner := &Runner{
client: mockClient,
log: &logging.NoOpLogger{},
}
mockTypesClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckTypeList{
Items: []advisorv0alpha1.CheckType{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test-check",
},
Spec: advisorv0alpha1.CheckTypeSpec{
Name: "test-check",
},
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
assert.Error(t, err)
assert.True(t, lastCreated.IsZero())
}
func TestRunner_checkLastCreated_UnprocessedCheck(t *testing.T) {
patchOperation := resource.PatchOperation{}
identifier := resource.Identifier{}
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
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "test-check"}}}
runner := createTestRunnerWithRegistry(mockClient, mockTypesClient, mockCheckService)
runner := &Runner{
client: mockClient,
log: &logging.NoOpLogger{},
}
err := runAndTimeout(runner)
assert.ErrorAs(t, err, &context.DeadlineExceeded)
// Should not create checks on first run when no previous checks exist
assert.Empty(t, checksCreated, "Should not create checks on first run when no previous checks exist")
})
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
assert.NoError(t, err)
assert.True(t, lastCreated.IsZero())
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) {
checksCreated := []string{}
func TestRunner_checkLastCreated_PaginatedResponse(t *testing.T) {
// Create checks with different creation times
past := time.Now().Add(-1 * time.Hour)
now := time.Now()
mockClient := &MockClient{
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)
mockClient := &MockClient{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
if options.Continue == "" {
// First page - return oldest and middle checks with continue token
return &advisorv0alpha1.CheckList{
ListMeta: metav1.ListMeta{
Continue: "continue-token-123",
},
Items: []advisorv0alpha1.Check{
{
ObjectMeta: metav1.ObjectMeta{
Name: "old-check",
CreationTimestamp: metav1.NewTime(time.Now().Add(-15 * 24 * time.Hour)), // 15 days ago
Name: "check-1",
CreationTimestamp: metav1.NewTime(past),
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
},
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{
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
return &advisorv0alpha1.CheckTypeList{
Items: []advisorv0alpha1.CheckType{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test-check",
},
Spec: advisorv0alpha1.CheckTypeSpec{
Name: "test-check",
}
// Second page - verify continue token is passed and return newest check
assert.Equal(t, "continue-token-123", options.Continue)
return &advisorv0alpha1.CheckList{
Items: []advisorv0alpha1.Check{
{
ObjectMeta: metav1.ObjectMeta{
Name: "check-3",
CreationTimestamp: metav1.NewTime(now),
Annotations: map[string]string{
checks.StatusAnnotation: "completed",
},
},
},
}, 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
}
},
}, nil
},
}
if checkClient.createFunc == nil {
checkClient.createFunc = func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
return obj, nil
}
runner := &Runner{
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
}
}
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 {
typesClient.listFunc = func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
// Return empty list to match the empty MockCheckService
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
}
}
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: "",
runner := &Runner{
client: mockClient,
maxHistory: defaultMaxHistory,
log: &logging.NoOpLogger{},
}
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 {
resource.Client
@@ -375,6 +414,7 @@ func (m *MockCheckService) Checks() []checks.Check {
type mockCheck struct {
checks.Check
id string
steps []checks.Step
}
@@ -386,12 +426,3 @@ func (m *mockCheck) ID() string {
func (m *mockCheck) Steps() []checks.Step {
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
}

View File

@@ -16,7 +16,6 @@ import (
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/pkg/services/org"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -27,8 +26,7 @@ import (
type Runner struct {
checkRegistry checkregistry.CheckService
client resource.Client
orgService org.Service
stackID string
namespace string
log logging.Logger
retryAttempts int
retryDelay time.Duration
@@ -42,7 +40,10 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
return nil, fmt.Errorf("invalid config type")
}
checkRegistry := specificConfig.CheckRegistry
orgService := specificConfig.OrgService
namespace, err := checks.GetNamespace(specificConfig.StackID)
if err != nil {
return nil, err
}
// Prepare storage client
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
@@ -54,8 +55,7 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
return &Runner{
checkRegistry: checkRegistry,
client: client,
orgService: orgService,
stackID: specificConfig.StackID,
namespace: namespace,
log: log.With("runner", "advisor.checktyperegisterer"),
retryAttempts: 5,
retryDelay: time.Second * 10,
@@ -64,47 +64,36 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
func (r *Runner) Run(ctx context.Context) error {
logger := r.log.WithContext(ctx)
// Determine namespaces based on StackID or OrgID
namespaces, err := checks.GetNamespaces(ctx, r.stackID, r.orgService)
if err != nil {
return fmt.Errorf("failed to get namespaces: %w", err)
}
logger.Debug("Registering check types", "namespaces", len(namespaces))
// Register check types in each namespace
for _, namespace := range namespaces {
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(),
}
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",
},
}
obj := &advisorv0alpha1.CheckType{
ObjectMeta: metav1.ObjectMeta{
Name: t.ID(),
Namespace: r.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 {
return err
}
},
Spec: advisorv0alpha1.CheckTypeSpec{
Name: t.ID(),
Steps: stepTypes,
},
}
err := r.registerCheckType(ctx, logger, t.ID(), obj)
if err != nil {
return err
}
}
return nil

View File

@@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana-app-sdk/resource"
advisorv0alpha1 "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/org"
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -68,17 +67,14 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
tests := []struct {
name string
checks []checks.Check
stackID string
orgService org.Service
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)
updateFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error)
expectedErr error
}{
{
name: "successful create",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "successful create",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
},
@@ -89,9 +85,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil,
},
{
name: "resource exists with different annotations, should update",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "resource exists with different annotations, should update",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil
},
@@ -101,9 +96,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil,
},
{
name: "resource exists with different steps, should update",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "resource exists with different steps, should update",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentSteps, nil
},
@@ -113,9 +107,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil,
},
{
name: "resource exists with same annotations and steps, should not update",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "resource exists with same annotations and steps, should not update",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectSameContent, nil
},
@@ -125,9 +118,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil,
},
{
name: "resource exists, with custom annotations preserved",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "resource exists, with custom annotations preserved",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil
},
@@ -140,9 +132,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil,
},
{
name: "create error",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "create error",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
},
@@ -153,9 +144,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: errors.New("create error"),
},
{
name: "update error",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "update error",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil
},
@@ -165,9 +155,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: errors.New("update error"),
},
{
name: "shutting down error",
checks: []checks.Check{newMockCheck},
stackID: "123",
name: "shutting down error",
checks: []checks.Check{newMockCheck},
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
return existingObjectDifferentAnnotations, nil
},
@@ -177,33 +166,14 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
expectedErr: nil,
},
{
name: "cloud stack namespace",
checks: []checks.Check{newMockCheck},
stackID: "456",
name: "custom namespace",
checks: []checks.Check{newMockCheck},
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) {
if obj.GetNamespace() != "stack-456" {
return nil, fmt.Errorf("expected namespace %s, got %s", "stack-456", 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)
if obj.GetNamespace() != "custom-namespace" {
return nil, fmt.Errorf("expected namespace %s, got %s", "custom-namespace", obj.GetNamespace())
}
return obj, nil
},
@@ -213,10 +183,6 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
orgSvc := tt.orgService
if orgSvc == nil {
orgSvc = &mockOrgService{orgs: []*org.OrgDTO{}}
}
r := &Runner{
checkRegistry: &mockCheckRegistry{checks: tt.checks},
client: &mockClient{
@@ -224,8 +190,7 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
createFunc: tt.createFunc,
updateFunc: tt.updateFunc,
},
orgService: orgSvc,
stackID: tt.stackID,
namespace: "custom-namespace",
log: logging.DefaultLogger,
retryAttempts: 1,
retryDelay: 0,
@@ -333,12 +298,3 @@ func (m *mockClient) Update(ctx context.Context, id resource.Identifier, obj res
}
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
}

View File

@@ -9,13 +9,11 @@ import (
"sync"
"time"
"github.com/grafana/authlib/types"
"github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/resource"
advisorv0alpha1 "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/contexthandler"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
)
var retryAnnotationPollingInterval = 1 * time.Second
@@ -83,11 +81,7 @@ func processCheck(ctx context.Context, log logging.Logger, client resource.Clien
}
return fmt.Errorf("error running steps: %w", err)
}
// Wait for the item to be persisted before patching the object
err = waitForItem(ctx, log, client, obj)
if err != nil {
return err
}
report := &advisorv0alpha1.CheckReport{
Failures: failures,
Count: int64(len(items)),
@@ -270,24 +264,6 @@ func retryAnnotationChanged(oldObj, newObj resource.Object) bool {
oldAnnotations[checks.RetryAnnotation] != newAnnotations[checks.RetryAnnotation]
}
func waitForItem(ctx context.Context, log logging.Logger, client resource.Client, obj resource.Object) error {
_, err := client.Get(ctx, resource.Identifier{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
})
retries := 0
for err != nil && k8serrors.IsNotFound(err) && retries < 5 {
log.Debug("Waiting for item to be persisted", "check", obj.GetName(), "retries", retries)
time.Sleep(retryAnnotationPollingInterval)
retries++
_, err = client.Get(ctx, resource.Identifier{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
})
}
return err
}
// waitForRetryAnnotation waits for the retry annotation to match the item to retry
func waitForRetryAnnotation(ctx context.Context, log logging.Logger, client resource.Client, obj resource.Object, itemToRetry string) error {
currentObj, err := client.Get(ctx, resource.Identifier{
@@ -318,12 +294,3 @@ func waitForRetryAnnotation(ctx context.Context, log logging.Logger, client reso
log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry)
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
}

View File

@@ -3,38 +3,37 @@ module github.com/grafana/grafana/apps/alerting/alertenrichment
go 1.25.3
require (
github.com/grafana/grafana-app-sdk v0.47.0
github.com/grafana/grafana-app-sdk v0.40.3
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28
k8s.io/apimachinery v0.34.1
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
k8s.io/apimachinery v0.33.3
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)
require (
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-openapi/jsonpointer v0.22.1 // indirect
github.com/go-openapi/jsonreference v0.21.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.9.0 // 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/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/net v0.45.0 // indirect
golang.org/x/text v0.30.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
golang.org/x/text v0.29.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.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
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
sigs.k8s.io/yaml v1.5.0 // indirect
)

View File

@@ -2,29 +2,28 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8=
github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA=
github.com/grafana/grafana-app-sdk v0.40.3 h1:JFo7uAfbAJUfZ9neD7/4sODKm1xgu9zhckclH/N4DYU=
github.com/grafana/grafana-app-sdk v0.40.3/go.mod h1:j0KzHo3Sa6kd+lnwSScBNoV9Vobkg/YY9HtEjxpyPrk=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 h1:PgMfX4OPENz/iXmtDDIW9+poZY4UD0hhmXm7flVclDo=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28/go.mod h1:av5N0Naq+8VV9MLF7zAkihy/mVq5UbS2EvRSJukDHlY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -42,28 +41,25 @@ github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUt
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -83,8 +79,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -93,8 +89,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -102,19 +98,21 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA=
k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=

View File

@@ -132,7 +132,6 @@ const (
EnricherTypeAsserts EnricherType = "asserts"
EnricherTypeExplain EnricherType = "explain"
EnricherTypeLoop EnricherType = "loop"
EnricherTypeAssistant EnricherType = "assistant"
)
// EnricherConfig is a discriminated union of enricher configurations.
@@ -146,7 +145,6 @@ type EnricherConfig struct {
Asserts *AssertsEnricher `json:"asserts,omitempty" yaml:"asserts,omitempty" jsonschema:"description=Asserts enricher settings"`
Explain *ExplainEnricher `json:"explain,omitempty" yaml:"explain,omitempty" jsonschema:"description=Explain enricher settings"`
Loop *LoopEnricher `json:"loop,omitempty" yaml:"loop,omitempty" jsonschema:"description=Loop enricher settings"`
Assistant *AssistantEnricher `json:"assistant,omitempty" yaml:"assistant,omitempty" jsonschema:"description=Assistant enricher settings"`
}
// AssignEnricher configures an enricher which assigns annotations.
@@ -226,15 +224,10 @@ type AssertsEnricher struct {
// ExplainEnricher uses LLM to generate explanations for alerts.
type ExplainEnricher struct {
Annotation string `json:"annotation" yaml:"annotation" jsonschema:"description=Annotation name to set the explanation in, by default '__enriched_ai_explanation'"`
Annotation string `json:"annotation" yaml:"annotation" jsonschema:"description=Annotation name to set the explanation in, by default 'ai_explanation'"`
}
// LoopEnricher configures an enricher which calls into Loop.
type LoopEnricher struct {
// In the future, there may be configuration options.
}
// AssistantEnricher configures an enricher which calls into Assistant.
type AssistantEnricher struct {
// In the future, there may be configuration options.
}

View File

@@ -183,22 +183,6 @@ func (in *Assignment) DeepCopy() *Assignment {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AssistantEnricher) DeepCopyInto(out *AssistantEnricher) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssistantEnricher.
func (in *AssistantEnricher) DeepCopy() *AssistantEnricher {
if in == nil {
return nil
}
out := new(AssistantEnricher)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Condition) DeepCopyInto(out *Condition) {
*out = *in
@@ -325,11 +309,6 @@ func (in *EnricherConfig) DeepCopyInto(out *EnricherConfig) {
*out = new(LoopEnricher)
**out = **in
}
if in.Assistant != nil {
in, out := &in.Assistant, &out.Assistant
*out = new(AssistantEnricher)
**out = **in
}
return
}

View File

@@ -21,7 +21,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssertsEnricher": schema_pkg_apis_alertenrichment_v1beta1_AssertsEnricher(ref),
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssignEnricher": schema_pkg_apis_alertenrichment_v1beta1_AssignEnricher(ref),
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.Assignment": schema_pkg_apis_alertenrichment_v1beta1_Assignment(ref),
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssistantEnricher": schema_pkg_apis_alertenrichment_v1beta1_AssistantEnricher(ref),
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.Condition": schema_pkg_apis_alertenrichment_v1beta1_Condition(ref),
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.Conditional": schema_pkg_apis_alertenrichment_v1beta1_Conditional(ref),
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.DataSourceEnricher": schema_pkg_apis_alertenrichment_v1beta1_DataSourceEnricher(ref),
@@ -326,17 +325,6 @@ func schema_pkg_apis_alertenrichment_v1beta1_Assignment(ref common.ReferenceCall
}
}
func schema_pkg_apis_alertenrichment_v1beta1_AssistantEnricher(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "AssistantEnricher configures an enricher which calls into Assistant.",
Type: []string{"object"},
},
},
}
}
func schema_pkg_apis_alertenrichment_v1beta1_Condition(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -479,11 +467,11 @@ func schema_pkg_apis_alertenrichment_v1beta1_EnricherConfig(ref common.Reference
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
Description: "Possible enum values:\n - `\"asserts\"`\n - `\"assign\"`\n - `\"assistant\"`\n - `\"dsquery\"`\n - `\"explain\"`\n - `\"external\"`\n - `\"loop\"`\n - `\"sift\"`",
Description: "Possible enum values:\n - `\"asserts\"`\n - `\"assign\"`\n - `\"dsquery\"`\n - `\"explain\"`\n - `\"external\"`\n - `\"loop\"`\n - `\"sift\"`",
Default: "",
Type: []string{"string"},
Format: "",
Enum: []interface{}{"asserts", "assign", "assistant", "dsquery", "explain", "external", "loop", "sift"},
Enum: []interface{}{"asserts", "assign", "dsquery", "explain", "external", "loop", "sift"},
},
},
"assign": {
@@ -521,17 +509,12 @@ func schema_pkg_apis_alertenrichment_v1beta1_EnricherConfig(ref common.Reference
Ref: ref("github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.LoopEnricher"),
},
},
"assistant": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssistantEnricher"),
},
},
},
Required: []string{"type"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssertsEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssignEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssistantEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.DataSourceEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.ExplainEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.ExternalEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.LoopEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.SiftEnricher"},
"github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssertsEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.AssignEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.DataSourceEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.ExplainEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.ExternalEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.LoopEnricher", "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1.SiftEnricher"},
}
}

View File

@@ -5,4 +5,5 @@ generate: do-generate ## Run Grafana App SDK code generation
.PHONY: do-generate
do-generate: install-app-sdk update-app-sdk
@$(APP_SDK_BIN) generate --grouping=group --gogenpath=./pkg/apis --defencoding=yaml --postprocess
## --defencoding=none and noschemasinmanifest are needed to avoid infinite loop while generating recursive models (see routingtree.cue)
@$(APP_SDK_BIN) generate --grouping=group --gogenpath=./pkg/apis --defencoding=none --postprocess --noschemasinmanifest --useoldmanifestkinds

View File

@@ -1,433 +0,0 @@
apiVersion: apps.grafana.com/v1alpha2
kind: AppManifest
metadata:
name: alerting-notifications
spec:
appName: alerting-notifications
group: notifications.alerting.grafana.app
preferredVersion: v0alpha1
versions:
- kinds:
- conversion: false
kind: Receiver
plural: Receivers
schemas:
Integration:
additionalProperties: false
properties:
disableResolveMessage:
type: boolean
secureFields:
additionalProperties:
type: boolean
type: object
settings:
additionalProperties:
additionalProperties: {}
type: object
type: object
type:
type: string
uid:
type: string
version:
type: string
required:
- type
- version
- settings
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.
It is limited to three possible states for machine evaluation.
enum:
- success
- in_progress
- failed
type: string
required:
- lastEvaluation
- state
type: object
Receiver:
properties:
spec:
$ref: '#/components/schemas/spec'
status:
$ref: '#/components/schemas/status'
required:
- spec
spec:
additionalProperties: false
properties:
integrations:
items:
$ref: '#/components/schemas/Integration'
type: array
title:
type: string
required:
- title
- integrations
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.
Any operator which consumes this kind SHOULD add its state evaluation information to this field.
type: object
type: object
scope: Namespaced
- conversion: false
kind: RoutingTree
plural: RoutingTrees
schemas:
Matcher:
additionalProperties: false
properties:
label:
type: string
type:
enum:
- =
- '!='
- =~
- '!~'
type: string
value:
type: string
required:
- type
- label
- value
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.
It is limited to three possible states for machine evaluation.
enum:
- success
- in_progress
- failed
type: string
required:
- lastEvaluation
- state
type: object
Route:
additionalProperties: false
properties:
active_time_intervals:
items:
type: string
type: array
continue:
type: boolean
group_by:
items:
type: string
type: array
group_interval:
type: string
group_wait:
type: string
matchers:
items:
$ref: '#/components/schemas/Matcher'
type: array
mute_time_intervals:
items:
type: string
type: array
receiver:
type: string
repeat_interval:
type: string
routes:
items:
$ref: '#/components/schemas/Route'
type: array
required:
- continue
type: object
RouteDefaults:
additionalProperties: false
properties:
group_by:
items:
type: string
type: array
group_interval:
type: string
group_wait:
type: string
receiver:
type: string
repeat_interval:
type: string
required:
- receiver
type: object
RoutingTree:
properties:
spec:
$ref: '#/components/schemas/spec'
status:
$ref: '#/components/schemas/status'
required:
- spec
spec:
additionalProperties: false
properties:
defaults:
$ref: '#/components/schemas/RouteDefaults'
routes:
items:
$ref: '#/components/schemas/Route'
type: array
required:
- defaults
- routes
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.
Any operator which consumes this kind SHOULD add its state evaluation information to this field.
type: object
type: object
scope: Namespaced
- conversion: false
kind: TemplateGroup
plural: TemplateGroups
schemas:
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.
It is limited to three possible states for machine evaluation.
enum:
- success
- in_progress
- failed
type: string
required:
- lastEvaluation
- state
type: object
TemplateGroup:
properties:
spec:
$ref: '#/components/schemas/spec'
status:
$ref: '#/components/schemas/status'
required:
- spec
spec:
additionalProperties: false
properties:
content:
type: string
title:
type: string
required:
- title
- content
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.
Any operator which consumes this kind SHOULD add its state evaluation information to this field.
type: object
type: object
scope: Namespaced
- conversion: false
kind: TimeInterval
plural: TimeIntervals
schemas:
Interval:
additionalProperties: false
properties:
days_of_month:
items:
type: string
type: array
location:
type: string
months:
items:
type: string
type: array
times:
items:
$ref: '#/components/schemas/TimeRange'
type: array
weekdays:
items:
type: string
type: array
years:
items:
type: string
type: array
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.
It is limited to three possible states for machine evaluation.
enum:
- success
- in_progress
- failed
type: string
required:
- lastEvaluation
- state
type: object
TimeInterval:
properties:
spec:
$ref: '#/components/schemas/spec'
status:
$ref: '#/components/schemas/status'
required:
- spec
TimeRange:
additionalProperties: false
properties:
end_time:
type: string
start_time:
type: string
required:
- start_time
- end_time
type: object
spec:
additionalProperties: false
properties:
name:
type: string
time_intervals:
items:
$ref: '#/components/schemas/Interval'
type: array
required:
- name
- time_intervals
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.
Any operator which consumes this kind SHOULD add its state evaluation information to this field.
type: object
type: object
scope: Namespaced
name: v0alpha1
served: true

View File

@@ -1,93 +0,0 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: receivers.notifications.alerting.grafana.app
spec:
group: notifications.alerting.grafana.app
names:
kind: Receiver
plural: receivers
scope: Namespaced
versions:
- name: v0alpha1
schema:
openAPIV3Schema:
properties:
spec:
properties:
integrations:
items:
properties:
disableResolveMessage:
type: boolean
secureFields:
additionalProperties:
type: boolean
type: object
settings:
type: object
x-kubernetes-preserve-unknown-fields: true
type:
type: string
uid:
type: string
version:
type: string
required:
- type
- version
- settings
type: object
type: array
title:
type: string
required:
- title
- integrations
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.
It 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.
Any operator which consumes this kind SHOULD add its state evaluation information to this field.
type: object
type: object
required:
- spec
type: object
served: true
storage: true
subresources:
status: {}

View File

@@ -1,138 +0,0 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: routingtrees.notifications.alerting.grafana.app
spec:
group: notifications.alerting.grafana.app
names:
kind: RoutingTree
plural: routingtrees
scope: Namespaced
versions:
- name: v0alpha1
schema:
openAPIV3Schema:
properties:
spec:
properties:
defaults:
properties:
group_by:
items:
type: string
type: array
group_interval:
type: string
group_wait:
type: string
receiver:
type: string
repeat_interval:
type: string
required:
- receiver
type: object
routes:
items:
properties:
active_time_intervals:
items:
type: string
type: array
continue:
type: boolean
group_by:
items:
type: string
type: array
group_interval:
type: string
group_wait:
type: string
matchers:
items:
properties:
label:
type: string
type:
enum:
- =
- '!='
- =~
- '!~'
type: string
value:
type: string
required:
- type
- label
- value
type: object
type: array
mute_time_intervals:
items:
type: string
type: array
receiver:
type: string
repeat_interval:
type: string
routes:
items:
type: object
x-kubernetes-preserve-unknown-fields: true
type: array
required:
- continue
type: object
type: array
required:
- defaults
- routes
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.
It 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.
Any operator which consumes this kind SHOULD add its state evaluation information to this field.
type: object
type: object
required:
- spec
type: object
served: true
storage: true
subresources:
status: {}

Some files were not shown because too many files have changed in this diff Show More