mirror of https://github.com/grafana/grafana.git
Merge origin/main into iortega/transform-v1-to-v2
CodeQL checks / Detect whether code changed (push) Waiting to run
Details
CodeQL checks / Analyze (actions) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (go) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (javascript) (push) Blocked by required conditions
Details
CodeQL checks / Detect whether code changed (push) Waiting to run
Details
CodeQL checks / Analyze (actions) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (go) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (javascript) (push) Blocked by required conditions
Details
Resolved conflicts in: - apps/dashboard/pkg/migration/conversion/conversion.go: Updated conversion functions to use withConversionMetrics - pkg/registry/apis/dashboard/register.go: Updated migration initialization - pkg/storage/unified/testing/storage_backend.go: Fixed test helper function - public/app/features/dashboard/state/DashboardMigratorToBackend.test.ts: Updated variable adapters registration - Removed .betterer.results file as it was deleted in origin/main
This commit is contained in:
commit
0b0282050f
|
@ -1,13 +1,13 @@
|
|||
[build]
|
||||
bin = "./bin/grafana"
|
||||
bin = "./bin/grafana-air"
|
||||
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-backend"
|
||||
cmd = "make GO_BUILD_DEV=1 build-air"
|
||||
exclude_regex = ["_test.go", "_gen.go"]
|
||||
exclude_unchanged = true
|
||||
follow_symlink = true
|
||||
include_dir = ["apps", "conf", "devenv/dev-dashboards", "pkg", "public/views"]
|
||||
include_dir = ["apps", "conf", "pkg", "public/views"]
|
||||
include_ext = ["go", "ini", "toml", "html", "json"]
|
||||
stop_on_error = false
|
||||
stop_on_error = true
|
||||
send_interrupt = true
|
||||
kill_delay = 500
|
||||
|
||||
|
|
|
@ -1,181 +0,0 @@
|
|||
// @ts-check
|
||||
const emotionPlugin = require('@emotion/eslint-plugin');
|
||||
const importPlugin = require('eslint-plugin-import');
|
||||
const jestPlugin = require('eslint-plugin-jest');
|
||||
const jsxA11yPlugin = require('eslint-plugin-jsx-a11y');
|
||||
const lodashPlugin = require('eslint-plugin-lodash');
|
||||
const barrelPlugin = require('eslint-plugin-no-barrel-files');
|
||||
const reactPlugin = require('eslint-plugin-react');
|
||||
const testingLibraryPlugin = require('eslint-plugin-testing-library');
|
||||
|
||||
const grafanaConfig = require('@grafana/eslint-config/flat');
|
||||
const grafanaPlugin = require('@grafana/eslint-plugin');
|
||||
const grafanaI18nPlugin = require('@grafana/i18n/eslint-plugin');
|
||||
|
||||
// Include the base Grafana configs and remove the rules,
|
||||
// as we just want to pull in all of the necessary configuration but not run the rules
|
||||
// (this should only be concerned with checking rules that we want to improve,
|
||||
// so there's no need to try and run the rules that will be linted properly anyway)
|
||||
const mappedBaseConfigs = grafanaConfig.map((config) => {
|
||||
const { rules, ...baseConfig } = config;
|
||||
return baseConfig;
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {Array<import('eslint').Linter.Config>}
|
||||
*/
|
||||
module.exports = [
|
||||
{
|
||||
name: 'grafana/betterer-ignores',
|
||||
ignores: [
|
||||
'.github',
|
||||
'.yarn',
|
||||
'**/.*',
|
||||
'**/*.gen.ts',
|
||||
'**/build/',
|
||||
'**/compiled/',
|
||||
'**/dist/',
|
||||
'data/',
|
||||
'deployment_tools_config.json',
|
||||
'devenv',
|
||||
'e2e-playwright/test-plugins',
|
||||
'e2e/tmp',
|
||||
'packages/grafana-ui/src/components/Icon/iconBundle.ts',
|
||||
'pkg',
|
||||
'playwright-report',
|
||||
'public/lib/monaco/',
|
||||
'public/locales/_build',
|
||||
'public/locales/**/*.js',
|
||||
'public/vendor/',
|
||||
'scripts/grafana-server/tmp',
|
||||
'!.betterer.eslint.config.js',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'react/jsx-runtime-rules',
|
||||
rules: reactPlugin.configs.flat['jsx-runtime'].rules,
|
||||
},
|
||||
...mappedBaseConfigs,
|
||||
{
|
||||
files: ['**/*.{ts,tsx,js}'],
|
||||
plugins: {
|
||||
'@emotion': emotionPlugin,
|
||||
lodash: lodashPlugin,
|
||||
jest: jestPlugin,
|
||||
import: importPlugin,
|
||||
'jsx-a11y': jsxA11yPlugin,
|
||||
'no-barrel-files': barrelPlugin,
|
||||
'@grafana': grafanaPlugin,
|
||||
'testing-library': testingLibraryPlugin,
|
||||
'@grafana/i18n': grafanaI18nPlugin,
|
||||
},
|
||||
linterOptions: {
|
||||
// This reports unused disable directives that we can clean up but
|
||||
// it also conflicts with the betterer eslint rules so disabled
|
||||
reportUnusedDisableDirectives: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@grafana/no-aria-label-selectors': 'error',
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
group: ['@grafana/ui*', '*/Layout/*'],
|
||||
importNames: ['Layout', 'HorizontalGroup', 'VerticalGroup'],
|
||||
message: 'Use Stack component instead.',
|
||||
},
|
||||
{
|
||||
group: ['@grafana/ui/src/*', '@grafana/runtime/src/*', '@grafana/data/src/*'],
|
||||
message: 'Import from the public export instead.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
ignores: [
|
||||
'**/*.{test,spec}.{ts,tsx}',
|
||||
'**/__mocks__/**',
|
||||
'**/public/test/**',
|
||||
'**/mocks.{ts,tsx}',
|
||||
'**/mocks/**/*.{ts,tsx}',
|
||||
'**/spec/**/*.{ts,tsx}',
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
ignores: [
|
||||
'**/*.{test,spec}.{ts,tsx}',
|
||||
'**/__mocks__/**',
|
||||
'**/public/test/**',
|
||||
'**/mocks.{ts,tsx}',
|
||||
'**/spec/**/*.{ts,tsx}',
|
||||
],
|
||||
rules: {
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: 'Identifier[name=localStorage]',
|
||||
message: 'Direct usage of localStorage is not allowed. import store from @grafana/data instead',
|
||||
},
|
||||
{
|
||||
selector: 'MemberExpression[object.name=localStorage]',
|
||||
message: 'Direct usage of localStorage is not allowed. import store from @grafana/data instead',
|
||||
},
|
||||
{
|
||||
selector:
|
||||
'Program:has(ImportDeclaration[source.value="@grafana/ui"] ImportSpecifier[imported.name="Card"]) JSXOpeningElement[name.name="Card"]:not(:has(JSXAttribute[name.name="noMargin"]))',
|
||||
message:
|
||||
'Add noMargin prop to Card components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.',
|
||||
},
|
||||
{
|
||||
selector:
|
||||
'Program:has(ImportDeclaration[source.value="@grafana/ui"] ImportSpecifier[imported.name="Field"]) JSXOpeningElement[name.name="Field"]:not(:has(JSXAttribute[name.name="noMargin"]))',
|
||||
message:
|
||||
'Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.',
|
||||
},
|
||||
{
|
||||
selector: 'CallExpression[callee.type="MemberExpression"][callee.property.name="localeCompare"]',
|
||||
message:
|
||||
'Using localeCompare() can cause performance issues when sorting large datasets. Consider using Intl.Collator for better performance when sorting arrays, or add an eslint-disable comment if sorting a small, known dataset.',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['public/app/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-barrel-files/no-barrel-files': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
// custom rule for Table to avoid performance regressions
|
||||
files: ['packages/grafana-ui/src/components/Table/TableNG/Cells/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
group: ['**/themes/ThemeContext'],
|
||||
importNames: ['useStyles2', 'useTheme2'],
|
||||
message:
|
||||
'Do not use "useStyles2" or "useTheme2" in a cell directly. Instead, provide styles to cells via `getDefaultCellStyles` or `getCellSpecificStyles`.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
4789
.betterer.results
4789
.betterer.results
File diff suppressed because it is too large
Load Diff
119
.betterer.ts
119
.betterer.ts
|
@ -1,119 +0,0 @@
|
|||
import { BettererFileTest } from '@betterer/betterer';
|
||||
import { ESLint } from 'eslint';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
// Why are we ignoring these?
|
||||
// They're all deprecated/being removed so doesn't make sense to fix types
|
||||
const eslintPathsToIgnore = [
|
||||
'packages/grafana-ui/src/graveyard', // will be removed alongside angular in Grafana 12
|
||||
'public/app/angular', // will be removed in Grafana 12
|
||||
'public/app/plugins/panel/graph', // will be removed alongside angular in Grafana 12
|
||||
'public/app/plugins/panel/table-old', // will be removed alongside angular in Grafana 12
|
||||
];
|
||||
|
||||
// Avoid using functions that report the position of the issues, as this causes a lot of merge conflicts
|
||||
export default {
|
||||
'better eslint': () =>
|
||||
countEslintErrors()
|
||||
.include('**/*.{ts,tsx}')
|
||||
.exclude(new RegExp(eslintPathsToIgnore.join('|'))),
|
||||
'no undocumented stories': () => countUndocumentedStories().include('**/*.story.tsx'),
|
||||
'no skipping a11y tests in stories': () => countSkippedA11yTestStories().include('**/*.story.tsx'),
|
||||
'no gf-form usage': () =>
|
||||
regexp(/gf-form/gm, 'gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.')
|
||||
.include('**/*.{ts,tsx,html}')
|
||||
.exclude(new RegExp('packages/grafana-ui/src/themes/GlobalStyles')),
|
||||
};
|
||||
|
||||
function countSkippedA11yTestStories() {
|
||||
return new BettererFileTest(async (filePaths, fileTestResult) => {
|
||||
await Promise.all(
|
||||
filePaths.map(async (filePath) => {
|
||||
// look for skipped a11y tests
|
||||
const skipRegex = new RegExp("a11y: { test: 'off' }", 'gm');
|
||||
|
||||
const fileText = await fs.readFile(filePath, 'utf8');
|
||||
|
||||
const hasSkip = skipRegex.test(fileText);
|
||||
if (hasSkip) {
|
||||
// In this case the file contents don't matter:
|
||||
const file = fileTestResult.addFile(filePath, '');
|
||||
// Add the issue to the first character of the file:
|
||||
file.addIssue(0, 0, 'No skipping of a11y tests in stories. Please fix the component or story instead.');
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function countUndocumentedStories() {
|
||||
return new BettererFileTest(async (filePaths, fileTestResult) => {
|
||||
await Promise.all(
|
||||
filePaths.map(async (filePath) => {
|
||||
// look for .mdx import in the story file
|
||||
const mdxImportRegex = new RegExp("^import.*\\.mdx';$", 'gm');
|
||||
// Looks for the "autodocs" string in the file
|
||||
const autodocsStringRegex = /autodocs/;
|
||||
|
||||
const fileText = await fs.readFile(filePath, 'utf8');
|
||||
|
||||
const hasMdxImport = mdxImportRegex.test(fileText);
|
||||
const hasAutodocsString = autodocsStringRegex.test(fileText);
|
||||
// If both .mdx import and autodocs string are missing, add an issue
|
||||
if (!hasMdxImport && !hasAutodocsString) {
|
||||
// In this case the file contents don't matter:
|
||||
const file = fileTestResult.addFile(filePath, '');
|
||||
// Add the issue to the first character of the file:
|
||||
file.addIssue(0, 0, 'No undocumented stories are allowed, please add an .mdx file with some documentation');
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic regexp pattern matcher, similar to @betterer/regexp.
|
||||
* The only difference is that the positions of the errors are not reported, as this may cause a lot of merge conflicts.
|
||||
*/
|
||||
function regexp(pattern: RegExp, issueMessage: string) {
|
||||
return new BettererFileTest(async (filePaths, fileTestResult) => {
|
||||
await Promise.all(
|
||||
filePaths.map(async (filePath) => {
|
||||
const fileText = await fs.readFile(filePath, 'utf8');
|
||||
const matches = fileText.match(pattern);
|
||||
if (matches) {
|
||||
// File contents doesn't matter, since we're not reporting the position
|
||||
const file = fileTestResult.addFile(filePath, '');
|
||||
matches.forEach(() => {
|
||||
file.addIssue(0, 0, issueMessage);
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function countEslintErrors() {
|
||||
return new BettererFileTest(async (filePaths, fileTestResult) => {
|
||||
// Just bail early if there's no files to test. Prevents trying to get the base config from failing
|
||||
if (filePaths.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const runner = new ESLint({
|
||||
overrideConfigFile: './.betterer.eslint.config.js',
|
||||
warnIgnored: false,
|
||||
});
|
||||
|
||||
const lintResults = await runner.lintFiles(Array.from(filePaths));
|
||||
|
||||
lintResults.forEach(({ messages, filePath }) => {
|
||||
const file = fileTestResult.addFile(filePath, '');
|
||||
messages
|
||||
.sort((a, b) => (a.message > b.message ? 1 : -1))
|
||||
.forEach((message, index) => {
|
||||
file.addIssue(0, 0, message.message, `${index}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -65,7 +65,7 @@ require (
|
|||
github.com/go-toolsmith/astp v1.1.0 // indirect
|
||||
github.com/go-toolsmith/strparse v1.1.0 // indirect
|
||||
github.com/go-toolsmith/typep v1.1.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
|
|
|
@ -142,8 +142,8 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi
|
|||
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
|
||||
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
|
||||
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY=
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
|
|
|
@ -18,7 +18,7 @@ require (
|
|||
github.com/evilmartians/lefthook v1.4.8 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
|
|
|
@ -29,8 +29,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
|||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
|
|
|
@ -24,7 +24,7 @@ require (
|
|||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/go-swagger/go-swagger v0.30.6-0.20240310114303-db51e79a0e37 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.2 // indirect
|
||||
|
|
|
@ -41,8 +41,8 @@ github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3Bum
|
|||
github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
|
||||
github.com/go-swagger/go-swagger v0.30.6-0.20240310114303-db51e79a0e37 h1:KFcZmKdZmapAog2+eL1buervAYrYolBZk7fMecPPDmo=
|
||||
github.com/go-swagger/go-swagger v0.30.6-0.20240310114303-db51e79a0e37/go.mod h1:i1/E+d8iPNReSE7y04FaVu5OPKB3il5cn+T1Egogg3I=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
.gitignore
|
||||
.vscode
|
||||
bin
|
||||
!bin/grafana-linux-k8s
|
||||
data*
|
||||
dist
|
||||
docker
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
# START Technical documentation
|
||||
/.vale.ini @grafana/docs-tooling
|
||||
/AGENTS.md @grafana/docs-tooling
|
||||
|
||||
# `make docs` procedure and related workflows are owned @grafana/docs-tooling. Slack #docs.
|
||||
/docs/ @grafana/docs-tooling
|
||||
|
||||
|
@ -72,6 +74,7 @@
|
|||
|
||||
# Git Sync / App Platform Provisioning
|
||||
/apps/provisioning/ @grafana/grafana-git-ui-sync-team
|
||||
/pkg/operators @grafana/grafana-git-ui-sync-team
|
||||
/public/app/features/provisioning @grafana/grafana-git-ui-sync-team
|
||||
/pkg/registry/apis/provisioning @grafana/grafana-git-ui-sync-team
|
||||
/pkg/tests/apis/provisioning @grafana/grafana-git-ui-sync-team
|
||||
|
@ -85,10 +88,12 @@
|
|||
/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
|
||||
/pkg/api/ @grafana/grafana-backend-group
|
||||
/pkg/apis/ @grafana/grafana-app-platform-squad
|
||||
/pkg/apis/query @grafana/grafana-datasources-core-services
|
||||
|
@ -138,6 +143,7 @@
|
|||
/pkg/apimachinery @grafana/grafana-app-platform-squad
|
||||
/pkg/apimachinery/identity/ @grafana/identity-squad
|
||||
/pkg/apimachinery/errutil/ @grafana/grafana-backend-group
|
||||
/pkg/operators/iam @grafana/access-squad
|
||||
/pkg/promlib @grafana/oss-big-tent
|
||||
/pkg/storage/ @grafana/grafana-search-and-storage
|
||||
/pkg/storage/secret/ @grafana/grafana-operator-experience-squad
|
||||
|
@ -185,7 +191,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/grafana-app-platform-squad @grafana/alerting-backend
|
||||
/pkg/tests/apis/alerting @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
|
||||
|
@ -307,6 +313,7 @@
|
|||
/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
|
||||
|
@ -409,12 +416,20 @@
|
|||
/e2e/ @grafana/grafana-frontend-platform
|
||||
/e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources
|
||||
/e2e-playwright/dashboard-new-layouts/ @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboard-cujs/ @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboards-search-suite/ @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboards/cujs/ @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboards/DashboardForConditionalRendering.json @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboards/DashboardWithAllConditionalRendering.json @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboards/README.md @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboards/AdHocFilterTest.json @grafana/datapro
|
||||
/e2e-playwright/dashboards/DashboardLiveTest.json @grafana/dashboards-squad
|
||||
/e2e-playwright/dashboards/DataLinkWithoutSlugTest.json @grafana/dashboards-squad
|
||||
/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-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
|
||||
/e2e-playwright/dashboards-suite/dashboard-export-image.spec.ts @grafana/sharing-squad
|
||||
|
@ -451,6 +466,8 @@
|
|||
/e2e-playwright/fixtures/exemplars-query-response.json @grafana/observability-traces-and-profiling
|
||||
/e2e-playwright/fixtures/long-trace-response.json @grafana/observability-traces-and-profiling
|
||||
/e2e-playwright/fixtures/tempo-response.json @grafana/oss-big-tent
|
||||
/e2e-playwright/fixtures/prometheus-response.json @grafana/datapro
|
||||
/e2e-playwright/panels-suite/canvas-scene.spec.ts @grafana/dataviz-squad
|
||||
/e2e-playwright/panels-suite/dashlist.spec.ts @grafana/grafana-search-navigate-organise
|
||||
/e2e-playwright/panels-suite/datagrid-data-change.spec.ts @grafana/dataviz-squad
|
||||
/e2e-playwright/panels-suite/datagrid-editing-features.spec.ts @grafana/dataviz-squad
|
||||
|
@ -461,9 +478,11 @@
|
|||
/e2e-playwright/panels-suite/panelEdit_base.spec.ts @grafana/dashboards-squad
|
||||
/e2e-playwright/panels-suite/panelEdit_queries.spec.ts @grafana/dashboards-squad
|
||||
/e2e-playwright/panels-suite/panelEdit_transforms.spec.ts @grafana/datapro
|
||||
/e2e-playwright/panels-suite/table-footer.spec.ts @grafana/dataviz-squad
|
||||
/e2e-playwright/panels-suite/table-kitchenSink.spec.ts @grafana/dataviz-squad
|
||||
/e2e-playwright/panels-suite/table-markdown.spec.ts @grafana/dataviz-squad
|
||||
/e2e-playwright/panels-suite/table-sparkline.spec.ts @grafana/dataviz-squad
|
||||
/e2e-playwright/panels-suite/table-utils.ts @grafana/dataviz-squad
|
||||
/e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources
|
||||
/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
|
||||
/e2e-playwright/smoke-tests-suite/ @grafana/grafana-frontend-platform
|
||||
|
@ -611,6 +630,7 @@
|
|||
/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
|
||||
|
@ -727,7 +747,6 @@
|
|||
/scripts/tsconfig.base.json @grafana/frontend-ops
|
||||
/.editorconfig @grafana/frontend-ops
|
||||
/eslint.config.js @grafana/frontend-ops
|
||||
/.betterer.eslint.config.js @grafana/frontend-ops
|
||||
/.gitattributes @grafana/frontend-ops
|
||||
/.gitignore @grafana/frontend-ops
|
||||
/.ignore @grafana/frontend-ops
|
||||
|
@ -753,6 +772,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
|
||||
# public folder
|
||||
/public/app/api/ @grafana/grafana-frontend-platform
|
||||
/public/app/api/clients/folder/ @grafana/grafana-search-navigate-organise
|
||||
/public/app/core/actions/ @grafana/grafana-frontend-platform
|
||||
/public/app/core/app_events.ts @grafana/grafana-frontend-platform
|
||||
/public/app/core/components/AccessControl/ @grafana/identity-access-team
|
||||
|
@ -857,6 +877,7 @@ 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
|
||||
|
@ -910,6 +931,7 @@ 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
|
||||
|
@ -934,6 +956,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
/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
|
||||
|
@ -946,7 +969,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
/public/app/plugins/panel/heatmap/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/histogram/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/logs/ @grafana/observability-logs
|
||||
/public/app/plugins/panel/logs-new/ @grafana/observability-logs
|
||||
/public/app/plugins/panel/nodeGraph/ @grafana/observability-traces-and-profiling @grafana/app-o11y-visualizations
|
||||
/public/app/plugins/panel/traces/ @grafana/observability-traces-and-profiling
|
||||
/public/app/plugins/panel/flamegraph/ @grafana/observability-traces-and-profiling
|
||||
|
@ -969,7 +991,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
/public/app/routes/ @grafana/grafana-search-navigate-organise
|
||||
/public/app/store/ @grafana/grafana-frontend-platform
|
||||
/public/app/types/ @grafana/grafana-frontend-platform
|
||||
/public/app/types/alerting.ts @grafana/alerting-frontend
|
||||
/public/app/types/unified-alerting-dto.ts @grafana/alerting-frontend
|
||||
/public/app/types/unified-alerting.ts @grafana/alerting-frontend
|
||||
/public/dashboards/ @grafana/dashboards-squad
|
||||
|
@ -1004,7 +1025,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
/public/app/index.ts @grafana/frontend-ops
|
||||
/public/app/initApp.ts @grafana/frontend-ops
|
||||
/public/app/AppWrapper.tsx @grafana/frontend-ops
|
||||
/public/app/partials/ @grafana/grafana-frontend-platform
|
||||
|
||||
/scripts/benchmark-access-control.sh @grafana/access-squad
|
||||
/scripts/check-breaking-changes.sh @grafana/plugins-platform-frontend
|
||||
|
@ -1012,7 +1032,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
/scripts/circle-* @grafana/grafana-developer-enablement-squad
|
||||
/scripts/publish-npm-packages.sh @grafana/grafana-developer-enablement-squad @grafana/plugins-platform-frontend
|
||||
/scripts/validate-npm-packages.sh @grafana/grafana-developer-enablement-squad @grafana/plugins-platform-frontend
|
||||
/scripts/ci-frontend-metrics.sh @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend @grafana/dataviz-squad @grafana/datapro
|
||||
/scripts/ci-frontend-metrics.sh @grafana/grafana-frontend-platform @grafana/frontend-ops
|
||||
/scripts/cli/ @grafana/grafana-frontend-platform
|
||||
/scripts/clean-git-or-error.sh @grafana/grafana-as-code
|
||||
/scripts/grafana-server/ @grafana/grafana-frontend-platform
|
||||
|
@ -1041,8 +1061,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
/scripts/**/generate-transformations* @grafana/datapro
|
||||
/scripts/webpack/ @grafana/frontend-ops
|
||||
/scripts/generate-a11y-report.sh @grafana/grafana-frontend-platform
|
||||
.betterer.results @grafanabot
|
||||
.betterer.ts @grafana/grafana-frontend-platform
|
||||
eslint-suppressions.json @grafanabot
|
||||
|
||||
# Design system
|
||||
/public/img/icons/unicons/ @grafana/design-system
|
||||
|
@ -1130,6 +1149,8 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
# Feature toggles
|
||||
/pkg/services/featuremgmt/ @grafana/grafana-backend-services-squad
|
||||
|
||||
# Data source migrations
|
||||
/pkg/services/promtypemigration/ @grafana/partner-datasources @grafana/aws-datasources
|
||||
|
||||
# Kind definitions
|
||||
/kinds/dashboard @grafana/dashboards-squad
|
||||
|
@ -1235,6 +1256,7 @@ embed.go @grafana/grafana-as-code
|
|||
/.github/workflows/i18n-verify.yml @grafana/grafana-frontend-platform
|
||||
/.github/workflows/deploy-storybook-preview.yml @grafana/grafana-frontend-platform
|
||||
/.github/workflows/scripts/crowdin/create-tasks.ts @grafana/grafana-frontend-platform
|
||||
/.github/workflows/scripts/publish-frontend-metrics.mts @grafana/grafana-frontend-platform
|
||||
/.github/workflows/pr-go-workspace-check.yml @grafana/grafana-app-platform-squad
|
||||
/.github/workflows/pr-dependabot-update-go-workspace.yml @grafana/grafana-app-platform-squad
|
||||
/.github/workflows/pr-k8s-codegen-check.yml @grafana/grafana-app-platform-squad
|
||||
|
@ -1244,6 +1266,7 @@ 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
|
||||
|
@ -1253,9 +1276,14 @@ 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
|
||||
|
|
|
@ -139,6 +139,7 @@ runs:
|
|||
with:
|
||||
verb: run
|
||||
dagger-flags: --verbose=0
|
||||
version: 0.18.8
|
||||
args: go run -C ${GRAFANA_PATH} ./pkg/build/cmd artifacts --artifacts ${ARTIFACTS} --grafana-dir=${GRAFANA_PATH} --alpine-base=${ALPINE_BASE} --ubuntu-base=${UBUNTU_BASE} --enterprise-dir=${ENTERPRISE_PATH} --version=${VERSION} --patches-repo=${PATCHES_REPO} --patches-ref=${PATCHES_REF} --patches-path=${PATCHES_PATH} --build-id=${BUILD_ID} --tag-format="${TAG_FORMAT}" --ubuntu-tag-format="${UBUNTU_TAG_FORMAT}" --org=${DOCKER_ORG} --registry=${DOCKER_REGISTRY} --checksum=${CHECKSUM} --verify=${VERIFY} > $OUTFILE
|
||||
- id: output
|
||||
shell: bash
|
||||
|
|
|
@ -28,6 +28,9 @@ outputs:
|
|||
docs:
|
||||
description: Whether the docs or self have changed in any way
|
||||
value: ${{ steps.changed-files.outputs.docs_any_changed || 'true' }}
|
||||
dockerfile:
|
||||
description: Whether the dockerfile or self have changed in any way
|
||||
value: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
|
@ -42,6 +45,8 @@ runs:
|
|||
self:
|
||||
- '.github/actions/change-detection/**'
|
||||
- '${{ inputs.self }}'
|
||||
dockerfile:
|
||||
- 'Dockerfile'
|
||||
backend:
|
||||
- '!*.md'
|
||||
- '!docs/**'
|
||||
|
@ -81,7 +86,6 @@ runs:
|
|||
- '.github/actions/change-detection/**'
|
||||
- '**.cue'
|
||||
- '.prettier*'
|
||||
- '.betterer*'
|
||||
- '.yarnrc.yml'
|
||||
- 'eslint.config.js'
|
||||
- 'jest.config.js'
|
||||
|
@ -151,3 +155,5 @@ runs:
|
|||
echo " --> ${{ steps.changed-files.outputs.dev_tooling_all_changed_files }}"
|
||||
echo "Docs: ${{ steps.changed-files.outputs.docs_any_changed || 'true' }}"
|
||||
echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}"
|
||||
echo "Dockerfile: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}"
|
||||
echo " --> ${{ steps.changed-files.outputs.dockerfile_all_changed_files }}"
|
||||
|
|
|
@ -34,7 +34,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4 # 4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check if update branch exists
|
||||
|
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
contents: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.backend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
|
@ -42,7 +42,7 @@ jobs:
|
|||
name: Validate Backend Configs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
@ -58,6 +58,7 @@ jobs:
|
|||
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
|
||||
|
|
|
@ -24,7 +24,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.backend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
|
@ -55,7 +55,7 @@ jobs:
|
|||
id-token: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
@ -68,7 +68,7 @@ jobs:
|
|||
run: |
|
||||
set -euo pipefail
|
||||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/shard.sh -N"$SHARD")"
|
||||
go test -short -timeout=30m "${PACKAGES[@]}"
|
||||
CGO_ENABLED=0 go test -short -timeout=30m "${PACKAGES[@]}"
|
||||
|
||||
grafana-enterprise:
|
||||
# Run this workflow for non-PR events (like pushes to `main` or `release-*`) OR for internal PRs (PRs not from forks)
|
||||
|
@ -90,7 +90,7 @@ jobs:
|
|||
steps:
|
||||
# Set up repository clone
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
@ -118,7 +118,7 @@ jobs:
|
|||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/shard.sh -N"$SHARD")"
|
||||
# This tee requires pipefail to be set, otherwise `go test`'s exit code is thrown away.
|
||||
# That means having no `-o pipefail` => failing tests => exit code 0, which is wrong.
|
||||
go test -short -timeout=30m "${PACKAGES[@]}"
|
||||
CGO_ENABLED=0 go test -short -timeout=30m "${PACKAGES[@]}"
|
||||
|
||||
# This is the job that is actually required by rulesets.
|
||||
# We need to require EITHER the OSS or the Enterprise job to pass.
|
||||
|
|
|
@ -62,7 +62,7 @@ jobs:
|
|||
echo "PR number: $PR_NUMBER"
|
||||
|
||||
- name: Checkout Grafana
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event.repository.default_branch }}
|
||||
fetch-depth: 2
|
||||
|
|
|
@ -13,17 +13,29 @@ on:
|
|||
required: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
id-token: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
bump-version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Grafana
|
||||
uses: actions/checkout@v4
|
||||
- uses: grafana/shared-workflows/actions/get-vault-secrets@main
|
||||
with:
|
||||
persist-credentials: false
|
||||
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: '{"contents": "write", "pull_requests": "write", "workflows": "write"}'
|
||||
- name: Checkout Grafana
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
- name: Update package.json versions
|
||||
uses: ./pkg/build/actions/bump-version
|
||||
with:
|
||||
|
@ -35,10 +47,10 @@ jobs:
|
|||
DRY_RUN: ${{ inputs.dry_run }}
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
run: |
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "grafana-delivery-bot[bot]"
|
||||
git config --local user.email "grafana-delivery-bot[bot]@users.noreply.github.com"
|
||||
git config --local --add --bool push.autoSetupRemote true
|
||||
git checkout -b "bump-version/${RUN_ID}/${VERSION}"
|
||||
git add .
|
||||
|
|
|
@ -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@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
ref: main
|
||||
sparse-checkout: |
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
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/v1.0.0
|
||||
with:
|
||||
dry-run: true
|
||||
max-date: "1 month ago"
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
contents: read
|
||||
steps:
|
||||
# Checks-out your repository, which is validated in the next step
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: GitHub CODEOWNERS Validator
|
||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
go: ${{ steps.detect-changes.outputs.backend }}
|
||||
actions: 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
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@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
|
|
|
@ -53,7 +53,7 @@ jobs:
|
|||
private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v4 # v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
|
|
|
@ -43,7 +43,7 @@ jobs:
|
|||
version: ${{ steps.build_frontend.outputs.version }}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Verify inputs
|
||||
|
@ -62,7 +62,7 @@ jobs:
|
|||
with:
|
||||
credentials_json: '${{ env.PLUGINS_GOOGLE_CREDENTIALS }}'
|
||||
- name: 'Set up Cloud SDK'
|
||||
uses: 'google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a'
|
||||
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
|
||||
- name: Setup nodejs environment
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
|
|
@ -61,7 +61,7 @@ jobs:
|
|||
private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
repository: ${{ inputs.repository }}
|
||||
|
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
id-token: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
path: './pr'
|
||||
persist-credentials: false
|
||||
|
@ -80,7 +80,7 @@ jobs:
|
|||
working-directory: './base'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
path: './base'
|
||||
ref: ${{ github.event.pull_request.base.ref }}
|
||||
|
@ -132,7 +132,7 @@ jobs:
|
|||
id-token: 'write'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -165,7 +165,7 @@ jobs:
|
|||
project_id: 'grafanalabs-global'
|
||||
|
||||
- name: 'Set up Cloud SDK'
|
||||
uses: 'google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a'
|
||||
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
with:
|
||||
version: '>= 363.0.0'
|
||||
|
@ -220,7 +220,7 @@ jobs:
|
|||
app-id: ${{ env.GITHUB_APP_ID }}
|
||||
private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
container:
|
||||
image: grafana/vale:latest # zizmor: ignore[unpinned-images]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: grafana/writers-toolkit/vale-action@vale-action/v1 # zizmor: ignore[unpinned-uses]
|
||||
|
|
|
@ -10,7 +10,7 @@ permissions: {}
|
|||
|
||||
jobs:
|
||||
handle-ephemeral-instances:
|
||||
if: ${{ github.event.issue.pull_request && (startsWith(github.event.comment.body, '/deploy-to-hg') || github.event.action == 'closed') && github.repository_owner == 'grafana' }}
|
||||
if: ${{ github.repository_owner == 'grafana' && ((github.event.issue.pull_request && startsWith(github.event.comment.body, '/deploy-to-hg')) || github.event.action == 'closed') }}
|
||||
runs-on:
|
||||
labels: ubuntu-x64-xlarge
|
||||
continue-on-error: true
|
||||
|
@ -42,7 +42,7 @@ jobs:
|
|||
private_key: ${{ env.APP_PEM }}
|
||||
|
||||
- name: Checkout ephemeral instances repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
repository: grafana/ephemeral-grafana-instances-github-action
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
|
|
|
@ -11,13 +11,15 @@ permissions: {}
|
|||
|
||||
jobs:
|
||||
test:
|
||||
name: Feature toggles documentation is in sync with source
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -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@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
|
@ -39,7 +39,7 @@ jobs:
|
|||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
|
@ -60,7 +60,7 @@ jobs:
|
|||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
|
@ -86,7 +86,7 @@ jobs:
|
|||
name: Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
|
@ -106,7 +106,7 @@ jobs:
|
|||
name: Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
|
@ -120,25 +120,6 @@ jobs:
|
|||
github-app-name: 'grafana-ci-bot'
|
||||
- run: yarn install --immutable --check-cache
|
||||
- run: yarn run typecheck
|
||||
lint-frontend-betterer:
|
||||
needs: detect-changes
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
name: Betterer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: 'yarn.lock'
|
||||
- run: yarn install --immutable --check-cache
|
||||
- run: yarn run betterer:ci
|
||||
lint-frontend-api-clients:
|
||||
permissions:
|
||||
contents: read
|
||||
|
@ -149,7 +130,7 @@ jobs:
|
|||
name: Verify API clients
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
|
@ -180,7 +161,7 @@ jobs:
|
|||
name: Verify API clients (enterprise)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -82,7 +82,7 @@ jobs:
|
|||
-e PROMETHEUS_URL="$PROMETHEUS_URL" \
|
||||
-e PROMETHEUS_USER="$PROMETHEUS_USER" \
|
||||
-e PROMETHEUS_PASSWORD="$PROMETHEUS_TOKEN" \
|
||||
us-docker.pkg.dev/grafanalabs-global/docker-grafana-bench-prod/grafana-bench:v0.6.0 report \
|
||||
us-docker.pkg.dev/grafanalabs-global/docker-grafana-bench-prod/grafana-bench:v0.6.1 report \
|
||||
--grafana-url "http://fsperfbaseline.grafana-dev.net" \
|
||||
--test-suite-name "FrontendPerfTests" \
|
||||
--report-input playwright \
|
||||
|
@ -104,7 +104,7 @@ jobs:
|
|||
-e PROMETHEUS_URL="$PROMETHEUS_URL" \
|
||||
-e PROMETHEUS_USER="$PROMETHEUS_USER" \
|
||||
-e PROMETHEUS_PASSWORD="$PROMETHEUS_TOKEN" \
|
||||
us-docker.pkg.dev/grafanalabs-global/docker-grafana-bench-prod/grafana-bench:v0.6.0 report \
|
||||
us-docker.pkg.dev/grafanalabs-global/docker-grafana-bench-prod/grafana-bench:v0.6.1 report \
|
||||
--grafana-url "http://fsperf.grafana-dev.net" \
|
||||
--test-suite-name "FrontendPerfTests" \
|
||||
--report-input playwright \
|
||||
|
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.backend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
|
@ -33,12 +33,33 @@ jobs:
|
|||
with:
|
||||
self: .github/workflows/go-lint.yml
|
||||
|
||||
go-fmt:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-go@v5.5.0
|
||||
with:
|
||||
go-version-file: ./go.mod
|
||||
- name: Run gofmt
|
||||
run: |
|
||||
GOFMT="$(go list -m -f '{{.Dir}}' | xargs -I{} sh -c 'test ! -f {}/.nolint && echo {}' | xargs gofmt -s -e -l 2>&1 | grep -v '/pkg/build/' || true)"
|
||||
if [ -n "$GOFMT" ]; then
|
||||
echo "Found files that are not gofmt'ed"
|
||||
echo "Run 'gofmt -s -w .' or 'make gofmt' or install the pre-commit hook with 'make lefthook-install'"
|
||||
echo "${GOFMT}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
lint-go:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-go@v5.5.0
|
||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
steps:
|
||||
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v4 # v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
|
@ -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@v4 # v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
|
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
if: github.event.pull_request.draft == false
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v4 # v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
|
|
|
@ -18,7 +18,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
|
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v4 # v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
|
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
private-key: ${{ env.PRIVATE_KEY }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
|
|
|
@ -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@v4
|
||||
- uses: actions/checkout@v5
|
||||
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@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -67,6 +67,7 @@ jobs:
|
|||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||
with:
|
||||
version: 0.18.8
|
||||
verb: run
|
||||
args: go run ./pkg/build/cmd artifacts -a targz:grafana:linux/amd64 -a docker:grafana:linux/amd64 --grafana-dir="${PWD}" > out.txt
|
||||
- name: Cat built artifact
|
||||
|
@ -117,7 +118,7 @@ jobs:
|
|||
outputs:
|
||||
artifact: ${{ steps.artifact.outputs.artifact }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
@ -148,19 +149,11 @@ jobs:
|
|||
needs:
|
||||
- build-grafana
|
||||
steps:
|
||||
- id: vault-secrets
|
||||
uses: grafana/shared-workflows/actions/get-vault-secrets@main
|
||||
- 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
|
||||
with:
|
||||
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"}'
|
||||
github_app: "delivery-bot-app"
|
||||
- uses: grafana/shared-workflows/actions/login-to-gar@main
|
||||
id: login-to-gar
|
||||
with:
|
||||
|
@ -183,7 +176,7 @@ jobs:
|
|||
echo "IMAGE=${DOCKER_IMAGE}" >> "$GITHUB_ENV"
|
||||
- name: Add PR status check
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
GH_TOKEN: ${{ steps.get-github-token.outputs.token }}
|
||||
SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
gh api \
|
||||
|
@ -207,8 +200,6 @@ 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"
|
||||
|
@ -227,7 +218,7 @@ jobs:
|
|||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/download-artifact@v4
|
||||
|
@ -241,6 +232,7 @@ jobs:
|
|||
- name: Run E2E tests
|
||||
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||
with:
|
||||
version: 0.18.8
|
||||
verb: run
|
||||
args: go run ./pkg/build/e2e --package=grafana.tar.gz
|
||||
--suite=${{ matrix.path }}
|
||||
|
@ -270,7 +262,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -303,7 +295,7 @@ jobs:
|
|||
shardTotal: [8]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/download-artifact@v4
|
||||
|
@ -312,6 +304,7 @@ jobs:
|
|||
- name: Run E2E tests
|
||||
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||
with:
|
||||
version: 0.18.8
|
||||
verb: run
|
||||
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
@ -322,7 +315,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
|
||||
if: needs.detect-changes.outputs.cloud_plugins_changed == 'true' && github.event.pull_request.head.repo.fork == false && github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-x64-large
|
||||
needs:
|
||||
- build-grafana
|
||||
|
@ -331,7 +324,7 @@ jobs:
|
|||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -374,6 +367,7 @@ jobs:
|
|||
- name: Run E2E tests
|
||||
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||
with:
|
||||
version: 0.18.8
|
||||
verb: run
|
||||
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --playwright-command="yarn e2e:playwright:cloud-plugins" --cloud-plugin-creds=/tmp/outputs.json
|
||||
|
||||
|
@ -397,7 +391,7 @@ jobs:
|
|||
name: All Playwright tests complete
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -482,7 +476,7 @@ jobs:
|
|||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/download-artifact@v4
|
||||
|
@ -492,14 +486,58 @@ jobs:
|
|||
if: github.event_name == 'pull_request'
|
||||
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@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||
with:
|
||||
version: 0.18.8
|
||||
verb: run
|
||||
args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail
|
||||
args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail --results=./pa11y-ci-results.json
|
||||
- name: Upload pa11y results
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
retention-days: 1
|
||||
name: pa11y-ci-results
|
||||
path: pa11y-ci-results.json
|
||||
|
||||
publish-metrics:
|
||||
needs:
|
||||
- run-a11y-test
|
||||
name: Publish metrics
|
||||
# Run on `grafana/grafana` main branch only
|
||||
if: github.event_name == 'push' && github.repository == 'grafana/grafana' && github.ref_name == 'main'
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: vault-secrets
|
||||
uses: grafana/shared-workflows/actions/get-vault-secrets@main
|
||||
with:
|
||||
repo_secrets: |
|
||||
GRAFANA_MISC_STATS_API_KEY=grafana-misc-stats:api_key
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js
|
||||
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@v4
|
||||
with:
|
||||
name: pa11y-ci-results
|
||||
- name: Extract and publish metrics
|
||||
run: ./scripts/ci-frontend-metrics.sh | node --experimental-strip-types .github/workflows/scripts/publish-frontend-metrics.mts
|
||||
env:
|
||||
GRAFANA_MISC_STATS_API_KEY: ${{ env.GRAFANA_MISC_STATS_API_KEY}}
|
||||
|
||||
# This is the job that is actually required by rulesets.
|
||||
# We want to only require one job instead of all the individual tests.
|
||||
|
@ -518,7 +556,7 @@ jobs:
|
|||
name: All E2E tests complete
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.frontend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
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@v4
|
||||
- uses: actions/checkout@v5
|
||||
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@v4
|
||||
- uses: actions/checkout@v5
|
||||
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@v4
|
||||
- uses: actions/checkout@v5
|
||||
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@v4
|
||||
- uses: actions/checkout@v5
|
||||
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@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check test suites
|
||||
|
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.backend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
|
@ -34,7 +34,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -71,7 +71,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
@ -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 link Enterprise and run 'make gen-go', then commit the changes to both repositories."
|
||||
echo "> !!! Please synchronize the grafana OSS and grafana enterprise code bases as defined in the enterprise readme, then run 'make gen-go' in the OSS folder and commit the changes to both repositories."
|
||||
else
|
||||
echo "> !!! Please run 'make gen-go' and commit the changes."
|
||||
fi
|
||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
name: Test Dockerfile
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
detect-changes:
|
||||
# Run on `grafana/grafana` main branch, or on pull requests to prevent double-running on mirrors
|
||||
name: Detect whether code changed
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.backend || steps.detect-changes.outputs.frontend || steps.detect-changes.outputs.dockerfile }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
- name: Detect changes
|
||||
id: detect-changes
|
||||
uses: ./.github/actions/change-detection
|
||||
with:
|
||||
self: .github/workflows/pr-test-integration.yml
|
||||
|
||||
build-dockerfile:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
runs-on: ubuntu-x64-large-io
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: docker/setup-docker-action@b60f85385d03ac8acfca6d9996982511d8620a19 # v4
|
||||
- name: Build Dockerfile
|
||||
run: make build-docker-full
|
|
@ -28,7 +28,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.backend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
|
@ -37,7 +37,6 @@ jobs:
|
|||
uses: ./.github/actions/change-detection
|
||||
with:
|
||||
self: .github/workflows/pr-test-integration.yml
|
||||
|
||||
sqlite:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
|
@ -55,7 +54,7 @@ jobs:
|
|||
contents: read
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
@ -70,6 +69,39 @@ jobs:
|
|||
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-)"
|
||||
go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||
|
||||
sqlite_nocgo:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
# We don't need more than this since it has to wait for the other tests.
|
||||
shard: [
|
||||
1/4, 2/4, 3/4, 4/4,
|
||||
]
|
||||
fail-fast: false
|
||||
|
||||
name: Sqlite Without CGo (${{ matrix.shard }})
|
||||
runs-on: ubuntu-x64-large-io
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5.5.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
- name: Run tests
|
||||
env:
|
||||
SHARD: ${{ matrix.shard }}
|
||||
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-)"
|
||||
CGO_ENABLED=0 go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||
mysql:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
|
@ -103,7 +135,7 @@ jobs:
|
|||
- 3306:3306
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
@ -152,7 +184,7 @@ jobs:
|
|||
- 5432:5432
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
|
|
@ -33,9 +33,13 @@ on:
|
|||
type: string
|
||||
required: false
|
||||
default: github-prerelease-writer@grafanalabs-workload-identity.iam.gserviceaccount.com
|
||||
runs-on:
|
||||
type: string
|
||||
required: false
|
||||
default: github-hosted-ubuntu-x64-small
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: github-hosted-ubuntu-x64-small
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
name: Publish
|
||||
permissions:
|
||||
id-token: write
|
||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: "Checkout Grafana repo"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: "Checkout Grafana repo"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
# required for the `grafana/grafana-github-actions/has-matching-release-tag` action to work
|
||||
fetch-depth: 0
|
||||
|
@ -38,7 +38,7 @@ jobs:
|
|||
run: go run .github/workflows/scripts/kinds/verify-kinds.go
|
||||
|
||||
- name: "Checkout Actions library"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: "./actions"
|
||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: grafana/writers-toolkit/publish-technical-documentation@publish-technical-documentation/v1 # zizmor: ignore[unpinned-uses]
|
||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ jobs:
|
|||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up version (Release Branches)
|
||||
|
@ -140,7 +140,7 @@ jobs:
|
|||
# The downside to this is that the frontend will be built for each one when it could be reused for all of them.
|
||||
# This could be a future improvement.
|
||||
include:
|
||||
- name: linux-amd64
|
||||
- name: linux-amd64 # publish-npm relies on this step building npm packages
|
||||
artifacts: targz:grafana:linux/amd64,deb:grafana:linux/amd64,rpm:grafana:linux/amd64,docker:grafana:linux/amd64,docker:grafana:linux/amd64:ubuntu,npm:grafana,storybook
|
||||
verify: true
|
||||
- name: linux-arm64
|
||||
|
@ -169,7 +169,7 @@ jobs:
|
|||
verify: true
|
||||
steps:
|
||||
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up QEMU
|
||||
|
@ -197,6 +197,7 @@ jobs:
|
|||
name: artifacts-${{ matrix.name }}
|
||||
path: ${{ steps.build.outputs.dist-dir }}
|
||||
retention-days: 1
|
||||
|
||||
publish-artifacts:
|
||||
name: Upload artifacts
|
||||
uses: grafana/grafana/.github/workflows/publish-artifact.yml@main
|
||||
|
@ -211,6 +212,7 @@ jobs:
|
|||
run-id: ${{ github.run_id }}
|
||||
bucket-path: ${{ needs.setup.outputs.version }}_${{ github.run_id }}
|
||||
environment: prod
|
||||
|
||||
publish-dockerhub:
|
||||
if: github.ref_name == 'main'
|
||||
permissions:
|
||||
|
@ -268,3 +270,77 @@ jobs:
|
|||
docker manifest push grafana/grafana:main-ubuntu
|
||||
docker manifest push "grafana/grafana-dev:${VERSION}"
|
||||
docker manifest push "grafana/grafana-dev:${VERSION}-ubuntu"
|
||||
|
||||
dispatch-npm-canaries:
|
||||
if: github.ref_name == 'main'
|
||||
name: Dispatch publish NPM canaries
|
||||
permissions:
|
||||
actions: write
|
||||
contents: read
|
||||
runs-on: ubuntu-x64-small
|
||||
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"
|
||||
|
||||
# notify-pr creates (or updates) a comment in a pull request to link to this workflow where the release artifacts are
|
||||
# being built.
|
||||
notify-pr:
|
||||
runs-on: ubuntu-x64-small
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
needs:
|
||||
- setup
|
||||
steps:
|
||||
- id: vault-secrets
|
||||
uses: grafana/shared-workflows/actions/get-vault-secrets@main
|
||||
with:
|
||||
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: '{"issues": "write", "pull_requests": "write", "contents": "read"}'
|
||||
- name: 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"
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ env.ISSUE_NUMBER }}
|
||||
comment-author: 'grafana-delivery-bot[bot]'
|
||||
body-includes: GitHub Actions Build
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
- name: Create or update comment
|
||||
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
issue-number: ${{ env.ISSUE_NUMBER }}
|
||||
body: |
|
||||
:rocket: Your submission is now being built and packaged.
|
||||
|
||||
- [GitHub Actions Build](https://github.com/grafana/grafana/actions/runs/${{ github.run_id }})
|
||||
- Version: ${{ needs.setup.outputs.version }}
|
||||
edit-mode: replace
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
name: Release NPM packages
|
||||
run-name: Publish NPM ${{ inputs.version_type }} ${{ inputs.version }}
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
grafana_commit:
|
||||
description: 'Grafana commit SHA to build against'
|
||||
required: true
|
||||
type: string
|
||||
version:
|
||||
description: 'Version to publish as'
|
||||
required: true
|
||||
type: string
|
||||
build_id:
|
||||
description: 'Run ID from the original release-build workflow'
|
||||
required: true
|
||||
type: string
|
||||
version_type:
|
||||
description: 'Version type (canary, nightly, stable)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
grafana_commit:
|
||||
description: 'Grafana commit SHA to build against'
|
||||
required: true
|
||||
version:
|
||||
description: 'Version to publish as'
|
||||
required: true
|
||||
build_id:
|
||||
description: 'Run ID from the original release-build workflow'
|
||||
required: true
|
||||
version_type:
|
||||
description: 'Version type (canary, nightly, stable)'
|
||||
required: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
# If called with version_type 'canary' or 'stable', build + publish to NPM
|
||||
# If called with version_type 'nightly', do nothing (we're not yet tagging them with the nightly tag)
|
||||
|
||||
publish:
|
||||
name: Publish NPM packages
|
||||
runs-on: github-hosted-ubuntu-x64-small
|
||||
if: inputs.version_type == 'canary' || inputs.version_type == 'stable'
|
||||
# Required for this workflow to have permission to publish NPM packages
|
||||
environment: npm-publish
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Info
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
GRAFANA_COMMIT: ${{ inputs.grafana_commit }}
|
||||
run: |
|
||||
echo "GRAFANA_COMMIT: $GRAFANA_COMMIT"
|
||||
echo "github.ref: $GITHUB_REF"
|
||||
|
||||
- name: Checkout workflow ref
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 100
|
||||
fetch-tags: false
|
||||
|
||||
# this will fail with "{commit} is not a valid commit" if the commit is valid but
|
||||
# not in the last 100 commits.
|
||||
- name: Verify commit is in workflow HEAD
|
||||
env:
|
||||
GIT_COMMIT: ${{ inputs.grafana_commit }}
|
||||
run: ./.github/workflows/scripts/validate-commit-in-head.sh
|
||||
shell: bash
|
||||
|
||||
- name: Map version type to NPM tag
|
||||
id: npm-tag
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
VERSION_TYPE: ${{ inputs.version_type }}
|
||||
REFERENCE_PKG: "@grafana/runtime"
|
||||
run: |
|
||||
TAG=$(./.github/workflows/scripts/determine-npm-tag.sh)
|
||||
echo "NPM_TAG=$TAG" >> "$GITHUB_OUTPUT"
|
||||
shell: bash
|
||||
|
||||
- name: Checkout build commit
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ inputs.grafana_commit }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node
|
||||
|
||||
# Trusted Publishing is only available in npm v11.5.1 and later
|
||||
- name: Update npm
|
||||
run: npm install -g npm@^11.5.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Typecheck packages
|
||||
run: yarn run packages:typecheck
|
||||
|
||||
- name: Version, build, and pack packages
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
yarn run packages:build
|
||||
yarn lerna version "$VERSION" \
|
||||
--exact \
|
||||
--no-git-tag-version \
|
||||
--no-push \
|
||||
--force-publish \
|
||||
--yes
|
||||
yarn run packages:pack
|
||||
|
||||
- name: Debug packed files
|
||||
run: tree -a ./npm-artifacts
|
||||
|
||||
- name: Validate packages
|
||||
run: ./scripts/validate-npm-packages.sh
|
||||
|
||||
- name: Debug OIDC Claims
|
||||
uses: github/actions-oidc-debugger@2e9ba5d3f4bebaad1f91a2cede055115738b7ae8
|
||||
with:
|
||||
audience: '${{ github.server_url }}/${{ github.repository_owner }}'
|
||||
|
||||
- name: Publish packages
|
||||
env:
|
||||
NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }}
|
||||
run: ./scripts/publish-npm-packages.sh --dist-tag "$NPM_TAG" --registry 'https://registry.npmjs.org/'
|
|
@ -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@v4
|
||||
uses: actions/checkout@v5
|
||||
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@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
token: ${{ steps.generate_changelog_token.outputs.token }}
|
||||
ref: main
|
||||
|
@ -198,6 +198,7 @@ jobs:
|
|||
if: ${{ inputs.bump == true || inputs.bump == 'true' }}
|
||||
uses: dagger/dagger-for-github@e47aba410ef9bb9ed81a4d2a97df31061e5e842e
|
||||
with:
|
||||
version: 0.18.8
|
||||
verb: run
|
||||
args: go run -C .grafana-main ./pkg/build/actions/bump-version -version="patch"
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ jobs:
|
|||
id-token: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Pin Go version to mod file
|
||||
|
@ -96,7 +96,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Restore Cached Node Modules
|
||||
|
|
|
@ -18,7 +18,7 @@ jobs:
|
|||
if: github.event.pull_request.draft == false
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Pin Go version to mod file
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
fail() { echo "Error: $*" >&2; exit 1; }
|
||||
|
||||
# Ensure required variables are set
|
||||
if [[ -z "${REFERENCE_PKG}" || -z "${VERSION_TYPE}" || -z "${VERSION}" ]]; then
|
||||
fail "Missing required environment variables: REFERENCE_PKG, VERSION_TYPE, VERSION"
|
||||
fi
|
||||
|
||||
semver_cmp () {
|
||||
IFS='.' read -r -a arr_a <<< "$1"
|
||||
IFS='.' read -r -a arr_b <<< "$2"
|
||||
|
||||
for i in 0 1 2; do
|
||||
local aa=${arr_a[i]:-0}
|
||||
local bb=${arr_b[i]:-0}
|
||||
# shellcheck disable=SC2004
|
||||
if (( 10#$aa > 10#$bb )); then echo gt; return 0; fi
|
||||
if (( 10#$aa < 10#$bb )); then echo lt; return 0; fi
|
||||
done
|
||||
|
||||
echo "eq"
|
||||
}
|
||||
|
||||
|
||||
STABLE_REGEX='^([0-9]+)\.([0-9]+)\.([0-9]+)$' # x.y.z
|
||||
PRE_REGEX='^([0-9]+)\.([0-9]+)\.([0-9]+)-([0-9]+)$' # x.y.z-123456
|
||||
|
||||
# Validate that the VERSION matches VERSION_TYPE
|
||||
# - stable must be x.y.z
|
||||
# - nightly/canary must be x.y.z-123456
|
||||
case "$VERSION_TYPE" in
|
||||
stable)
|
||||
[[ $VERSION =~ $STABLE_REGEX ]] || fail "For 'stable', version must match x.y.z" ;;
|
||||
nightly|canary)
|
||||
[[ $VERSION =~ $PRE_REGEX ]] || fail "For '$VERSION_TYPE', version must match x.y.z-123456" ;;
|
||||
*)
|
||||
fail "Unknown version_type '$VERSION_TYPE'" ;;
|
||||
esac
|
||||
|
||||
# Extract major, minor from VERSION
|
||||
IFS=.- read -r major minor patch _ <<< "$VERSION"
|
||||
|
||||
# Determine NPM tag
|
||||
case "$VERSION_TYPE" in
|
||||
canary) TAG="canary" ;;
|
||||
nightly) TAG="nightly" ;;
|
||||
stable)
|
||||
# Use npm dist-tag "latest" as the reference
|
||||
LATEST="$(npm view --silent "$REFERENCE_PKG" dist-tags.latest 2>/dev/null || true)"
|
||||
echo "Latest for $REFERENCE_PKG is ${LATEST:-<none>}" >&2
|
||||
|
||||
if [[ -z ${LATEST:-} ]]; then
|
||||
TAG="latest" # first ever publish
|
||||
else
|
||||
case "$(semver_cmp "$VERSION" "$LATEST")" in
|
||||
gt) TAG="latest" ;; # newer than reference -> latest
|
||||
lt|eq) TAG="v${major}.${minor}-latest" ;; # older or equal -> vX.Y-latest
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Resolved NPM_TAG=$TAG (VERSION=$VERSION, current latest=${LATEST:-none})" 1>&2 # stderr
|
||||
printf '%s' "$TAG"
|
|
@ -0,0 +1,75 @@
|
|||
import fs from 'node:fs'
|
||||
|
||||
interface Payload {
|
||||
name: string;
|
||||
value: number;
|
||||
interval: number;
|
||||
mtype: string;
|
||||
time: number;
|
||||
}
|
||||
|
||||
console.log("Publishing metrics");
|
||||
|
||||
// Get API key from environment variable
|
||||
const key = process.env.GRAFANA_MISC_STATS_API_KEY;
|
||||
if (!key) {
|
||||
throw new Error("API key is required. Provide it via the GRAFANA_MISC_STATS_API_KEY environment variable");
|
||||
}
|
||||
|
||||
const unixTimestamp = Math.floor(Date.now() / 1000);
|
||||
const data: Payload[] = [];
|
||||
|
||||
const input = fs.readFileSync(0, "utf-8");
|
||||
// parse metrics from input
|
||||
const regexp = /^Metrics: (\{.+\})/ms;
|
||||
const matches = input.match(regexp);
|
||||
|
||||
if (!matches) {
|
||||
throw new Error("No metrics found");
|
||||
}
|
||||
|
||||
console.log('matches[0]', matches[0])
|
||||
console.log('matches[1]', matches[1])
|
||||
|
||||
const metrics: Record<string, string> = JSON.parse(matches[1]);
|
||||
|
||||
// Convert metrics to payload format
|
||||
for (const [metricName, valueStr] of Object.entries(metrics)) {
|
||||
const value = parseInt(valueStr, 10);
|
||||
if (isNaN(value)) {
|
||||
throw new Error(`Metric "${metricName}" has invalid value format: "${valueStr}"`);
|
||||
}
|
||||
|
||||
data.push({
|
||||
name: metricName,
|
||||
value: value,
|
||||
interval: 60,
|
||||
mtype: "gauge",
|
||||
time: unixTimestamp,
|
||||
});
|
||||
}
|
||||
|
||||
const jsonPayload = JSON.stringify(data);
|
||||
console.log(`Publishing metrics to https://graphite-us-central1.grafana.net/metrics, JSON: ${jsonPayload}`);
|
||||
|
||||
const url = 'https://graphite-us-central1.grafana.net/metrics';
|
||||
const username = '6371';
|
||||
const headers = new Headers();
|
||||
headers.set("Content-Type", "application/json");
|
||||
headers.set('Authorization', 'Basic ' + Buffer.from(username + ":" + key).toString('base64'));
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: jsonPayload,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Metrics publishing failed with status code ${response.status}`);
|
||||
}
|
||||
|
||||
console.log("Metrics successfully published");
|
||||
} catch (error) {
|
||||
throw new Error(`Metrics publishing failed: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${GIT_COMMIT:-}" ]]; then
|
||||
echo "Error: Environment variable GIT_COMMIT is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git merge-base --is-ancestor "$GIT_COMMIT" HEAD; then
|
||||
echo "Commit $GIT_COMMIT is contained in HEAD"
|
||||
else
|
||||
echo "Error: Commit $GIT_COMMIT is not contained in HEAD"
|
||||
exit 1
|
||||
fi
|
|
@ -24,7 +24,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run Shellcheck
|
||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.frontend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
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:
|
||||
test-storybook-a11y-light:
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
permissions:
|
||||
contents: read
|
||||
|
@ -36,17 +36,48 @@ jobs:
|
|||
if: needs.detect-changes.outputs.changed == 'true'
|
||||
name: "Run Storybook a11y tests"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v5
|
||||
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: yarn 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@v5
|
||||
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 &
|
||||
- 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!
|
||||
|
|
|
@ -24,7 +24,7 @@ jobs:
|
|||
outputs:
|
||||
changed: ${{ steps.detect-changes.outputs.backend }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true # required to get more history in the changed-files action
|
||||
fetch-depth: 2
|
||||
|
@ -45,7 +45,7 @@ jobs:
|
|||
steps:
|
||||
# Set up repository clone
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Go
|
||||
|
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
trivy-scan:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Trivy
|
||||
|
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
shell: bash
|
||||
run: echo "fetch_depth=$(( ${{ github.event.pull_request.commits }} + 2 ))" >> "$GITHUB_OUTPUT"
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }}
|
||||
|
|
|
@ -8,7 +8,7 @@ jobs:
|
|||
if: github.repository == 'grafana/grafana'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: grafana/writers-toolkit/update-make-docs@update-make-docs/v1 # zizmor: ignore[unpinned-uses]
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
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@v4
|
||||
|
||||
- uses: grafana/plugin-actions/bundle-schema-types@main
|
|
@ -6,12 +6,16 @@ on:
|
|||
paths:
|
||||
- '**/*.cue'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: "ubuntu-latest"
|
||||
permissions:
|
||||
contents: read # clone repository
|
||||
steps:
|
||||
- name: "Checkout Grafana repo"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
|
|
@ -42,6 +42,7 @@ __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
|
||||
|
@ -94,6 +95,8 @@ example-apiserver/
|
|||
/devenv/docker/blocks/auth/openldap/certs/
|
||||
|
||||
conf/custom.ini
|
||||
conf/operator.ini
|
||||
conf/storage.ini
|
||||
|
||||
/conf/provisioning/**/*.yaml
|
||||
!/conf/provisioning/**/sample.yaml
|
||||
|
@ -127,6 +130,9 @@ profile.cov
|
|||
/public/app/extensions
|
||||
!/public/app/extensions/.keep
|
||||
|
||||
# Enterprise operators
|
||||
/pkg/operators/enterprise_*
|
||||
/pkg/operators/**/enterprise_*
|
||||
|
||||
debug.test
|
||||
/examples/*/dist
|
||||
|
@ -189,6 +195,8 @@ compilation-stats.json
|
|||
/e2e/build_results.zip
|
||||
/e2e/extensions
|
||||
!/e2e/extensions/.keep
|
||||
/e2e-playwright/extensions
|
||||
!/e2e-playwright/extensions/.keep
|
||||
/e2e/extensions-suite
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
|
@ -218,7 +226,6 @@ public/api-spec.json
|
|||
|
||||
deployment_tools_config.json
|
||||
|
||||
.betterer.cache
|
||||
.nx
|
||||
|
||||
# Temporary file for backporting PRs
|
||||
|
@ -242,3 +249,7 @@ public/mockServiceWorker.js
|
|||
|
||||
/e2e-playwright/test-plugins/*/dist
|
||||
/apps/provisioning/cmd/job-controller/bin/
|
||||
|
||||
|
||||
# Ignore unified storage kv store files
|
||||
/grafana-kv-data
|
||||
|
|
|
@ -101,6 +101,8 @@ 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/*'
|
||||
|
|
|
@ -11,7 +11,6 @@ node_modules
|
|||
pkg
|
||||
public/lib/monaco
|
||||
public/sass/*.generated.scss
|
||||
scripts/cli/bettererIssueTemplate.md
|
||||
scripts/grafana-server/tmp
|
||||
vendor
|
||||
|
||||
|
@ -43,3 +42,5 @@ public/mockServiceWorker.js
|
|||
# Playwright results
|
||||
test-results
|
||||
playwright-report
|
||||
|
||||
eslint-suppressions.json
|
||||
|
|
|
@ -120,6 +120,15 @@
|
|||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "Debug ESLint with stats reporter",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "yarn",
|
||||
"runtimeArgs": ["run", "eslint", "${file}", "--format", "./scripts/cli/eslint-stats-reporter.mjs"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"name": "Debug Go test",
|
||||
"type": "go",
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -25,4 +25,6 @@ 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.9.2.cjs
|
||||
yarnPath: .yarn/releases/yarn-4.9.4.cjs
|
||||
|
||||
enableScripts: false
|
||||
|
|
|
@ -0,0 +1,297 @@
|
|||
# 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 -->
|
222
CHANGELOG.md
222
CHANGELOG.md
|
@ -1,3 +1,224 @@
|
|||
<!-- 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)
|
||||
|
@ -13,6 +234,7 @@
|
|||
- **Alerting:** Fix active time intervals when time interval is renamed [#108547](https://github.com/grafana/grafana/pull/108547), [@yuri-tceretian](https://github.com/yuri-tceretian)
|
||||
- **Alerting:** Fix subpath handling in the alerting package [#109505](https://github.com/grafana/grafana/pull/109505), [@konrad147](https://github.com/konrad147)
|
||||
- **Config:** Fix date_formats options being moved to a different section [#109366](https://github.com/grafana/grafana/pull/109366), [@joshhunt](https://github.com/joshhunt)
|
||||
- **Pyroscope:** Fix flamegraph totals showing incorrect values after rate aggregation changes [#110470](https://github.com/grafana/grafana/pull/110470), [@marcsanmiquel](https://github.com/marcsanmiquel)
|
||||
|
||||
<!-- 12.1.1 END -->
|
||||
<!-- 12.0.4 START -->
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
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 making technical contributions to Grafana.
|
||||
This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute- it’s designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem.
|
||||
|
||||
Whether you're a new contributer or a seasoned veteran we hope these resources help you connect with the community:
|
||||
|
||||
|
|
10
Dockerfile
10
Dockerfile
|
@ -28,15 +28,17 @@ ENV NODE_OPTIONS=--max_old_space_size=8000
|
|||
|
||||
WORKDIR /tmp/grafana
|
||||
|
||||
RUN apk add --no-cache make build-base python3
|
||||
|
||||
COPY package.json project.json nx.json yarn.lock .yarnrc.yml ./
|
||||
COPY .yarn .yarn
|
||||
COPY packages packages
|
||||
COPY e2e-playwright e2e-playwright
|
||||
COPY public public
|
||||
COPY LICENSE ./
|
||||
COPY conf/defaults.ini ./conf/defaults.ini
|
||||
COPY e2e e2e
|
||||
|
||||
RUN apk add --no-cache make build-base python3
|
||||
#
|
||||
# Set the node env according to defaults or argument passed
|
||||
#
|
||||
|
@ -93,16 +95,22 @@ 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/advisor apps/advisor
|
||||
COPY apps/dashboard apps/dashboard
|
||||
COPY apps/folder apps/folder
|
||||
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 pkg/codegen pkg/codegen
|
||||
COPY pkg/plugins/codegen pkg/plugins/codegen
|
||||
|
||||
|
|
25
Makefile
25
Makefile
|
@ -17,6 +17,7 @@ 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
|
||||
|
||||
|
@ -70,6 +71,7 @@ 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
|
||||
|
@ -88,6 +90,7 @@ 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 \
|
||||
|
@ -171,7 +174,19 @@ gen-cuev2: ## Do all CUE code generation
|
|||
APPS_DIRS := ./apps/dashboard ./apps/folder ./apps/alerting/notifications
|
||||
|
||||
.PHONY: gen-apps
|
||||
gen-apps: ## Generate code for Grafana App SDK apps
|
||||
gen-apps: do-gen-apps gofmt ## Generate code for Grafana App SDK apps and run gofmt
|
||||
@if [ -n "$$CODEGEN_VERIFY" ]; then \
|
||||
echo "Verifying generated code is up to date..."; \
|
||||
if ! git diff --quiet; then \
|
||||
echo "Error: Generated apps code is not up to date. Please run 'make gen-apps' to regenerate."; \
|
||||
git diff --name-only; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "Generated apps code is up to date."; \
|
||||
fi
|
||||
|
||||
.PHONY: do-gen-apps
|
||||
do-gen-apps: ## Generate code for Grafana App SDK apps
|
||||
for dir in $(APPS_DIRS); do \
|
||||
$(MAKE) -C $$dir generate; \
|
||||
done
|
||||
|
@ -231,6 +246,10 @@ 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"
|
||||
|
@ -384,6 +403,10 @@ lint-go-diff:
|
|||
sed 's,^,./,' | \
|
||||
$(XARGSR) $(golangci-lint) run --config .golangci.yml
|
||||
|
||||
.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
|
||||
|
||||
# with disabled SC1071 we are ignored some TCL,Expect `/usr/bin/env expect` scripts
|
||||
.PHONY: shellcheck
|
||||
shellcheck: $(SH_FILES) ## Run checks for shell scripts.
|
||||
|
|
|
@ -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.1
|
||||
github.com/grafana/grafana-app-sdk/logging v0.40.2
|
||||
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
|
||||
|
@ -25,7 +25,7 @@ replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-aler
|
|||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect
|
||||
|
@ -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.37.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/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/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/proto/otlp v1.7.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
|
@ -291,10 +291,9 @@ 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.37.0 // indirect
|
||||
modernc.org/sqlite v1.38.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
|
||||
)
|
||||
|
|
|
@ -72,8 +72,8 @@ cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2zn
|
|||
cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY=
|
||||
cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0=
|
||||
cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
|
@ -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.1 h1:ru+GqbaQk6jthA5l2Yo1WI/JbNXKNQmLiqNrxz7HGP4=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.40.1/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU=
|
||||
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-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=
|
||||
|
@ -1135,8 +1135,6 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8
|
|||
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/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
|
||||
github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
|
||||
github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||
github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX24kM=
|
||||
|
|
|
@ -7,6 +7,7 @@ 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"
|
||||
|
@ -48,10 +49,12 @@ 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)
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
{
|
||||
Kind: advisorv0alpha1.CheckKind(),
|
||||
|
@ -78,7 +81,7 @@ func New(cfg app.Config) (app.App, error) {
|
|||
}
|
||||
}()
|
||||
}
|
||||
if req.Action == resource.AdmissionActionUpdate {
|
||||
if req.Action == resource.AdmissionActionUpdate && retryAnnotationChanged(req.OldObject, req.Object) {
|
||||
go func() {
|
||||
logger := log.WithContext(ctx).With("check", check.ID())
|
||||
logger.Debug("Updating check", "namespace", req.Object.GetNamespace(), "name", req.Object.GetName())
|
||||
|
|
|
@ -5,6 +5,8 @@ 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"
|
||||
|
@ -12,7 +14,6 @@ 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) {
|
||||
|
@ -22,7 +23,7 @@ func TestRun(t *testing.T) {
|
|||
pluginInfo []repo.PluginInfo
|
||||
pluginPreinstalled []string
|
||||
pluginManaged []string
|
||||
pluginProvisioned []string
|
||||
pluginProvisioned []provisionedplugins.Plugin
|
||||
pluginErrors []*plugins.Error
|
||||
expectedFailures []advisor.CheckReportFailure
|
||||
}{
|
||||
|
@ -117,7 +118,7 @@ func TestRun(t *testing.T) {
|
|||
pluginInfo: []repo.PluginInfo{
|
||||
{Status: "deprecated", Slug: "plugin5", Version: "1.1.0"}, // This should be ignored
|
||||
},
|
||||
pluginProvisioned: []string{"plugin5"},
|
||||
pluginProvisioned: []provisionedplugins.Plugin{{ID: "plugin5"}},
|
||||
expectedFailures: []advisor.CheckReportFailure{},
|
||||
},
|
||||
{
|
||||
|
@ -281,10 +282,10 @@ func (m *mockManagedPlugins) ManagedPlugins(ctx context.Context) []string {
|
|||
|
||||
type mockProvisionedPlugins struct {
|
||||
provisionedplugins.Manager
|
||||
provisioned []string
|
||||
provisioned []provisionedplugins.Plugin
|
||||
}
|
||||
|
||||
func (m *mockProvisionedPlugins) ProvisionedPlugins(ctx context.Context) ([]string, error) {
|
||||
func (m *mockProvisionedPlugins) ProvisionedPlugins(_ context.Context) ([]provisionedplugins.Plugin, error) {
|
||||
return m.provisioned, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,9 @@ func (r *Runner) Run(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resource.Object, error) {
|
||||
list, err := r.client.List(ctx, r.namespace, resource.ListOptions{})
|
||||
list, err := r.client.List(ctx, r.namespace, resource.ListOptions{
|
||||
Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -147,7 +149,7 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resou
|
|||
checks := list.GetItems()
|
||||
for list.GetContinue() != "" {
|
||||
logger.Debug("List has continue token, listing next page", "continue", list.GetContinue())
|
||||
list, err = r.client.List(ctx, r.namespace, resource.ListOptions{Continue: list.GetContinue()})
|
||||
list, err = r.client.List(ctx, r.namespace, resource.ListOptions{Continue: list.GetContinue(), Limit: 1000})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/k8s"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
|
@ -60,38 +62,6 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (r *Runner) createOrUpdate(ctx context.Context, log logging.Logger, obj resource.Object) error {
|
||||
id := obj.GetStaticMetadata().Identifier()
|
||||
_, err := r.client.Create(ctx, id, obj, resource.CreateOptions{})
|
||||
if err != nil {
|
||||
if errors.IsAlreadyExists(err) {
|
||||
// Already exists, update
|
||||
log.Debug("Check type already exists, updating", "identifier", id)
|
||||
// Retrieve current annotations to avoid overriding them
|
||||
current, err := r.client.Get(ctx, obj.GetStaticMetadata().Identifier())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentAnnotations := current.GetAnnotations()
|
||||
if currentAnnotations == nil {
|
||||
currentAnnotations = make(map[string]string)
|
||||
}
|
||||
annotations := obj.GetAnnotations()
|
||||
maps.Copy(currentAnnotations, annotations)
|
||||
obj.SetAnnotations(currentAnnotations) // This will update the annotations in the object
|
||||
_, err = r.client.Update(ctx, id, obj, resource.UpdateOptions{})
|
||||
if err != nil && !errors.IsAlreadyExists(err) {
|
||||
// Ignore the error, it's probably due to a race condition
|
||||
log.Info("Error updating check type, ignoring", "error", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
log.Debug("Check type registered successfully", "identifier", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) Run(ctx context.Context) error {
|
||||
logger := r.log.WithContext(ctx)
|
||||
for _, t := range r.checkRegistry.Checks() {
|
||||
|
@ -121,26 +91,139 @@ func (r *Runner) Run(ctx context.Context) error {
|
|||
Steps: stepTypes,
|
||||
},
|
||||
}
|
||||
for i := 0; i < r.retryAttempts; i++ {
|
||||
err := r.createOrUpdate(context.WithoutCancel(ctx), logger, obj)
|
||||
err := r.registerCheckType(ctx, logger, t.ID(), obj)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "apiserver is shutting down") {
|
||||
logger.Debug("Error creating check type, not retrying", "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
logger.Debug("Error creating check type, retrying", "error", err, "attempt", i+1)
|
||||
if i == r.retryAttempts-1 {
|
||||
logger.Error("Unable to register check type", "check_type", t.ID(), "error", err)
|
||||
} else {
|
||||
// Calculate exponential backoff delay: baseDelay * 2^attempt
|
||||
delay := r.retryDelay * time.Duration(1<<i)
|
||||
time.Sleep(delay)
|
||||
|
||||
func (r *Runner) registerCheckType(ctx context.Context, logger logging.Logger, checkType string, obj resource.Object) error {
|
||||
for i := 0; i < r.retryAttempts; i++ {
|
||||
current, err := r.client.Get(ctx, obj.GetStaticMetadata().Identifier())
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// Check type does not exist, create it
|
||||
err = r.create(context.WithoutCancel(ctx), logger, obj)
|
||||
if err != nil {
|
||||
if !r.shouldRetry(err, logger, i+1, checkType) {
|
||||
return nil
|
||||
}
|
||||
// Retry
|
||||
continue
|
||||
}
|
||||
logger.Debug("Check type registered successfully", "check_type", t.ID())
|
||||
// Success
|
||||
logger.Debug("Check type created successfully", "check_type", checkType)
|
||||
break
|
||||
}
|
||||
if !r.shouldRetry(err, logger, i+1, checkType) {
|
||||
return nil
|
||||
}
|
||||
// Retry
|
||||
continue
|
||||
}
|
||||
|
||||
// Check type already exists, check if it's the same and update if needed
|
||||
logger.Debug("Check type already exists, checking if it's the same", "identifier", obj.GetStaticMetadata().Identifier())
|
||||
if r.needsUpdate(current, obj, logger) {
|
||||
err = r.update(context.WithoutCancel(ctx), logger, obj, current)
|
||||
if err != nil {
|
||||
if !r.shouldRetry(err, logger, i+1, checkType) {
|
||||
return nil
|
||||
}
|
||||
// Retry
|
||||
continue
|
||||
}
|
||||
// Success
|
||||
logger.Debug("Check type updated successfully", "check_type", checkType)
|
||||
break
|
||||
}
|
||||
|
||||
// Check type is the same, no need to update
|
||||
logger.Debug("Check type already registered", "check_type", checkType)
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) shouldRetry(err error, logger logging.Logger, attempt int, checkType string) bool {
|
||||
logger.Debug("Error storing check type", "error", err, "attempt", attempt)
|
||||
if isAPIServerShuttingDown(err, logger) {
|
||||
return false
|
||||
}
|
||||
if attempt == r.retryAttempts-1 {
|
||||
logger.Error("Unable to register check type", "check_type", checkType, "error", err)
|
||||
return false
|
||||
}
|
||||
// Calculate exponential backoff delay: baseDelay * 2^attempt
|
||||
delay := r.retryDelay * time.Duration(1<<attempt)
|
||||
time.Sleep(delay)
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *Runner) create(ctx context.Context, log logging.Logger, obj resource.Object) error {
|
||||
id := obj.GetStaticMetadata().Identifier()
|
||||
_, err := r.client.Create(ctx, id, obj, resource.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debug("Check type created successfully", "identifier", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) needsUpdate(current, newObj resource.Object, log logging.Logger) bool {
|
||||
needsUpdate := false
|
||||
// Check if the object annotations exist in the current object
|
||||
currentAnnotations := current.GetAnnotations()
|
||||
if currentAnnotations == nil {
|
||||
currentAnnotations = make(map[string]string)
|
||||
}
|
||||
annotations := newObj.GetAnnotations()
|
||||
for k, v := range annotations {
|
||||
if currentAnnotations[k] != v {
|
||||
needsUpdate = true
|
||||
}
|
||||
}
|
||||
// Compare checktype spec steps with current steps
|
||||
currentCheckType := current.(*advisorv0alpha1.CheckType)
|
||||
newCheckType := newObj.(*advisorv0alpha1.CheckType)
|
||||
newSteps := newCheckType.Spec.Steps
|
||||
currentSteps := currentCheckType.Spec.Steps
|
||||
if !cmp.Equal(newSteps, currentSteps, cmpopts.SortSlices(func(a, b advisorv0alpha1.CheckTypeStep) bool {
|
||||
return a.StepID < b.StepID
|
||||
})) {
|
||||
log.Debug("Check type step mismatch, updating", "identifier", newObj.GetStaticMetadata().Identifier())
|
||||
needsUpdate = true
|
||||
}
|
||||
return needsUpdate
|
||||
}
|
||||
|
||||
func (r *Runner) update(ctx context.Context, log logging.Logger, obj resource.Object, current resource.Object) error {
|
||||
id := obj.GetStaticMetadata().Identifier()
|
||||
log.Debug("Updating check type", "identifier", id)
|
||||
|
||||
currentAnnotations := current.GetAnnotations()
|
||||
if currentAnnotations == nil {
|
||||
currentAnnotations = make(map[string]string)
|
||||
}
|
||||
annotations := obj.GetAnnotations()
|
||||
maps.Copy(currentAnnotations, annotations)
|
||||
obj.SetAnnotations(currentAnnotations) // This will update the annotations in the object
|
||||
|
||||
_, err := r.client.Update(ctx, id, obj, resource.UpdateOptions{})
|
||||
if err != nil && !errors.IsAlreadyExists(err) {
|
||||
// Ignore the error, it's probably due to a race condition
|
||||
log.Info("Error updating check type, ignoring", "error", err)
|
||||
}
|
||||
log.Debug("Check type updated successfully", "identifier", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func isAPIServerShuttingDown(err error, logger logging.Logger) bool {
|
||||
if strings.Contains(err.Error(), "apiserver is shutting down") {
|
||||
logger.Debug("Error creating check type, not retrying", "error", err)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -16,6 +16,54 @@ import (
|
|||
)
|
||||
|
||||
func TestCheckTypesRegisterer_Run(t *testing.T) {
|
||||
newMockCheck := &mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
}
|
||||
existingObjectDifferentAnnotations := &advisorv0alpha1.CheckType{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "check1",
|
||||
Annotations: map[string]string{
|
||||
checks.NameAnnotation: "existing-name", // Different to trigger update
|
||||
},
|
||||
},
|
||||
Spec: advisorv0alpha1.CheckTypeSpec{
|
||||
Name: "check1",
|
||||
Steps: []advisorv0alpha1.CheckTypeStep{
|
||||
{StepID: "step1", Title: "Step 1", Description: "Description 1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
existingObjectDifferentSteps := &advisorv0alpha1.CheckType{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "check1",
|
||||
Annotations: map[string]string{
|
||||
checks.NameAnnotation: "mock", // Same as check name
|
||||
},
|
||||
},
|
||||
Spec: advisorv0alpha1.CheckTypeSpec{
|
||||
Name: "check1",
|
||||
Steps: []advisorv0alpha1.CheckTypeStep{
|
||||
{StepID: "step2", Title: "Step 2", Description: "Description 2"}, // Different step
|
||||
},
|
||||
},
|
||||
}
|
||||
existingObjectSameContent := &advisorv0alpha1.CheckType{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "check1",
|
||||
Annotations: map[string]string{
|
||||
checks.NameAnnotation: "mock", // Same as check name
|
||||
},
|
||||
},
|
||||
Spec: advisorv0alpha1.CheckTypeSpec{
|
||||
Name: "check1",
|
||||
Steps: []advisorv0alpha1.CheckTypeStep{
|
||||
{StepID: "step1", Title: "Step 1", Description: "Description 1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
checks []checks.Check
|
||||
|
@ -26,13 +74,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "successful create",
|
||||
checks: []checks.Check{
|
||||
&mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
},
|
||||
checks: []checks.Check{newMockCheck},
|
||||
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) {
|
||||
return obj, nil
|
||||
|
@ -41,17 +85,10 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "create already exists, successful update",
|
||||
checks: []checks.Check{
|
||||
&mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||
return nil, k8sErrs.NewAlreadyExists(schema.GroupResource{}, obj.GetName())
|
||||
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
|
||||
},
|
||||
updateFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) {
|
||||
return obj, nil
|
||||
|
@ -59,27 +96,32 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "create already exists, with custom annotations",
|
||||
checks: []checks.Check{
|
||||
&mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
name: "resource exists with different steps, should update",
|
||||
checks: []checks.Check{newMockCheck},
|
||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||
return &advisorv0alpha1.CheckType{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "check1",
|
||||
Annotations: map[string]string{
|
||||
checks.IgnoreStepsAnnotationList: "step1",
|
||||
return existingObjectDifferentSteps, nil
|
||||
},
|
||||
updateFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) {
|
||||
return obj, nil
|
||||
},
|
||||
}, nil
|
||||
expectedErr: nil,
|
||||
},
|
||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||
return nil, k8sErrs.NewAlreadyExists(schema.GroupResource{}, obj.GetName())
|
||||
{
|
||||
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
|
||||
},
|
||||
updateFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) {
|
||||
return nil, errors.New("updateFunc should not be called")
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
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
|
||||
},
|
||||
updateFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) {
|
||||
if obj.GetAnnotations()[checks.IgnoreStepsAnnotationList] != "step1" {
|
||||
|
@ -91,13 +133,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "create error",
|
||||
checks: []checks.Check{
|
||||
&mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
},
|
||||
checks: []checks.Check{newMockCheck},
|
||||
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) {
|
||||
return nil, errors.New("create error")
|
||||
|
@ -107,16 +145,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "update error",
|
||||
checks: []checks.Check{
|
||||
&mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||
return nil, k8sErrs.NewAlreadyExists(schema.GroupResource{}, obj.GetName())
|
||||
checks: []checks.Check{newMockCheck},
|
||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||
return existingObjectDifferentAnnotations, nil
|
||||
},
|
||||
updateFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) {
|
||||
return nil, errors.New("update error")
|
||||
|
@ -125,16 +156,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "shutting down error",
|
||||
checks: []checks.Check{
|
||||
&mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||
return nil, k8sErrs.NewAlreadyExists(schema.GroupResource{}, obj.GetName())
|
||||
checks: []checks.Check{newMockCheck},
|
||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||
return existingObjectDifferentAnnotations, nil
|
||||
},
|
||||
updateFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) {
|
||||
return nil, errors.New("apiserver is shutting down")
|
||||
|
@ -143,13 +167,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "custom namespace",
|
||||
checks: []checks.Check{
|
||||
&mockCheck{
|
||||
id: "check1",
|
||||
steps: []checks.Step{
|
||||
&mockStep{id: "step1", title: "Step 1", description: "Description 1"},
|
||||
},
|
||||
},
|
||||
checks: []checks.Check{newMockCheck},
|
||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||
return existingObjectDifferentAnnotations, nil
|
||||
},
|
||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||
if obj.GetNamespace() != "custom-namespace" {
|
||||
|
@ -262,13 +282,19 @@ func (m *mockClient) Get(ctx context.Context, id resource.Identifier) (resource.
|
|||
if m.getFunc != nil {
|
||||
return m.getFunc(ctx, id)
|
||||
}
|
||||
return advisorv0alpha1.CheckTypeKind().ZeroValue(), nil
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (m *mockClient) Create(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||
if m.createFunc != nil {
|
||||
return m.createFunc(ctx, id, obj, opts)
|
||||
}
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (m *mockClient) Update(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error) {
|
||||
if m.updateFunc != nil {
|
||||
return m.updateFunc(ctx, id, obj, opts)
|
||||
}
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
|
|
@ -7,14 +7,18 @@ import (
|
|||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"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/checks"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
var retryAnnotationPollingInterval = 1 * time.Second
|
||||
|
||||
func getCheck(obj resource.Object, checkMap map[string]checks.Check) (checks.Check, error) {
|
||||
labels := obj.GetLabels()
|
||||
objTypeLabel, ok := labels[checks.TypeLabel]
|
||||
|
@ -78,7 +82,11 @@ 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)),
|
||||
|
@ -100,13 +108,17 @@ func processCheckRetry(ctx context.Context, log logging.Logger, client resource.
|
|||
status := checks.GetStatusAnnotation(obj)
|
||||
if status == "" || status == checks.StatusAnnotationError {
|
||||
// Check not processed yet or errored
|
||||
log.Debug("Check not processed yet or errored, skipping retry", "check", obj.GetName(), "status", status)
|
||||
return nil
|
||||
}
|
||||
// Get the item to retry from the annotation
|
||||
itemToRetry := checks.GetRetryAnnotation(obj)
|
||||
if itemToRetry == "" {
|
||||
// No item to retry, nothing to do
|
||||
log.Debug("No item to retry, skipping retry", "check", obj.GetName())
|
||||
return nil
|
||||
} else {
|
||||
log.Debug("Item to retry found", "check", obj.GetName(), "item", itemToRetry)
|
||||
}
|
||||
c, ok := obj.(*advisorv0alpha1.Check)
|
||||
if !ok {
|
||||
|
@ -165,14 +177,23 @@ func processCheckRetry(ctx context.Context, log logging.Logger, client resource.
|
|||
// Failure not in the list of items to retry, keep it
|
||||
return false
|
||||
})
|
||||
// Wait for the retry annotation to be persisted before patching the object
|
||||
err = waitForRetryAnnotation(ctx, log, client, obj, itemToRetry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Set the status
|
||||
err = checks.SetStatus(ctx, client, obj, c.Status)
|
||||
log.Debug("Status set", "check", obj.GetName(), "status.count", c.Status.Report.Count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete the retry annotation to mark the check as processed
|
||||
annotations := checks.DeleteAnnotations(ctx, obj, []string{checks.RetryAnnotation})
|
||||
err = checks.SetAnnotations(ctx, client, obj, annotations)
|
||||
log.Debug("Annotations set", "check", obj.GetName(), "annotations", annotations)
|
||||
|
||||
return checks.SetAnnotations(ctx, client, obj, annotations)
|
||||
return err
|
||||
}
|
||||
|
||||
func runStepsInParallel(ctx context.Context, log logging.Logger, spec *advisorv0alpha1.CheckSpec, steps []checks.Step, items []any) ([]advisorv0alpha1.CheckReportFailure, error) {
|
||||
|
@ -234,3 +255,65 @@ func filterSteps(checkType resource.Object, steps []checks.Step) ([]checks.Step,
|
|||
}
|
||||
return steps, nil
|
||||
}
|
||||
|
||||
// retryAnnotationChanged compares the retry annotation between old and new objects
|
||||
func retryAnnotationChanged(oldObj, newObj resource.Object) bool {
|
||||
if oldObj == nil || newObj == nil {
|
||||
return true // If either is nil, consider it changed
|
||||
}
|
||||
|
||||
// Compare annotations
|
||||
oldAnnotations := oldObj.GetAnnotations()
|
||||
newAnnotations := newObj.GetAnnotations()
|
||||
return newAnnotations[checks.RetryAnnotation] != "" &&
|
||||
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{
|
||||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
retries := 0
|
||||
currentRetryAnnotation := checks.GetRetryAnnotation(currentObj)
|
||||
for currentRetryAnnotation != itemToRetry {
|
||||
log.Debug("Waiting for retry annotation to be persisted", "check", obj.GetName(), "item", itemToRetry, "currentRetryAnnotation", currentRetryAnnotation)
|
||||
time.Sleep(retryAnnotationPollingInterval)
|
||||
retries++
|
||||
if retries > 5 {
|
||||
return fmt.Errorf("timeout waiting for retry annotation to be persisted")
|
||||
}
|
||||
currentObj, err = client.Get(ctx, resource.Identifier{
|
||||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentRetryAnnotation = checks.GetRetryAnnotation(currentObj)
|
||||
}
|
||||
log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
|
@ -249,7 +250,9 @@ func TestProcessCheckRetry_SkipMissingItem(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
meta.SetCreatedBy("user:1")
|
||||
client := &mockClient{}
|
||||
client := &mockClient{
|
||||
res: obj,
|
||||
}
|
||||
typesClient := &mockTypesClient{}
|
||||
ctx := context.TODO()
|
||||
|
||||
|
@ -281,7 +284,9 @@ func TestProcessCheckRetry_Success(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
meta.SetCreatedBy("user:1")
|
||||
client := &mockClient{}
|
||||
client := &mockClient{
|
||||
res: obj,
|
||||
}
|
||||
typesClient := &mockTypesClient{}
|
||||
ctx := context.TODO()
|
||||
|
||||
|
@ -296,6 +301,51 @@ func TestProcessCheckRetry_Success(t *testing.T) {
|
|||
assert.Empty(t, obj.Status.Report.Failures)
|
||||
}
|
||||
|
||||
func TestProcessCheckRetry_Success_Polling(t *testing.T) {
|
||||
retryAnnotationPollingInterval = 1 * time.Millisecond
|
||||
obj := &advisorv0alpha1.Check{}
|
||||
obj.SetAnnotations(map[string]string{
|
||||
checks.RetryAnnotation: "item",
|
||||
checks.StatusAnnotation: checks.StatusAnnotationProcessed,
|
||||
})
|
||||
obj.Status.Report.Failures = []advisorv0alpha1.CheckReportFailure{
|
||||
{
|
||||
ItemID: "item",
|
||||
StepID: "step",
|
||||
},
|
||||
}
|
||||
meta, err := utils.MetaAccessor(obj)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
meta.SetCreatedBy("user:1")
|
||||
retryCount := 0
|
||||
client := &mockClient{
|
||||
get: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||
if retryCount > 0 {
|
||||
// obj contains the retry annotation
|
||||
return obj, nil
|
||||
}
|
||||
retryCount++
|
||||
oldObject := &advisorv0alpha1.Check{}
|
||||
oldObject.SetAnnotations(map[string]string{
|
||||
checks.RetryAnnotation: "",
|
||||
})
|
||||
return oldObject, nil
|
||||
},
|
||||
}
|
||||
typesClient := &mockTypesClient{}
|
||||
ctx := context.TODO()
|
||||
|
||||
check := &mockCheck{
|
||||
items: []any{"item"},
|
||||
}
|
||||
|
||||
err = processCheckRetry(ctx, logging.DefaultLogger, client, typesClient, obj, check)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, retryCount)
|
||||
}
|
||||
|
||||
func TestRunStepsInParallel_ConcurrentHeaderAccess(t *testing.T) {
|
||||
// Create an HTTP request with headers to simulate the real scenario
|
||||
req, err := http.NewRequest("GET", "/test", nil)
|
||||
|
@ -360,6 +410,8 @@ func TestRunStepsInParallel_ConcurrentHeaderAccess(t *testing.T) {
|
|||
type mockClient struct {
|
||||
resource.Client
|
||||
values []any
|
||||
res resource.Object
|
||||
get func(ctx context.Context, id resource.Identifier) (resource.Object, error)
|
||||
}
|
||||
|
||||
func (m *mockClient) PatchInto(ctx context.Context, id resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions, obj resource.Object) error {
|
||||
|
@ -368,6 +420,13 @@ func (m *mockClient) PatchInto(ctx context.Context, id resource.Identifier, req
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *mockClient) Get(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||
if m.get != nil {
|
||||
return m.get(ctx, id)
|
||||
}
|
||||
return m.res, nil
|
||||
}
|
||||
|
||||
type mockTypesClient struct {
|
||||
resource.Client
|
||||
res resource.Object
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
module github.com/grafana/grafana/apps/alerting/alertenrichment
|
||||
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // 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/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gnostic-models v0.7.0 // 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/x448/float16 v0.8.4 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.44.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // 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
|
||||
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
|
||||
)
|
|
@ -0,0 +1,118 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/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.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/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/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.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
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=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
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/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/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/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.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
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=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-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.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=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
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=
|
||||
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/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-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/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 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=
|
|
@ -0,0 +1,24 @@
|
|||
package v1beta1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// AlertEnrichmentJSONCodec is a JSON codec for AlertEnrichment resources
|
||||
type AlertEnrichmentJSONCodec struct{}
|
||||
|
||||
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
|
||||
func (*AlertEnrichmentJSONCodec) Read(reader io.Reader, into resource.Object) error {
|
||||
return json.NewDecoder(reader).Decode(into)
|
||||
}
|
||||
|
||||
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
|
||||
func (*AlertEnrichmentJSONCodec) Write(writer io.Writer, from resource.Object) error {
|
||||
return json.NewEncoder(writer).Encode(from)
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Codec = &AlertEnrichmentJSONCodec{}
|
|
@ -0,0 +1,18 @@
|
|||
package v1beta1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
const (
|
||||
// APIGroup is the API group used by all kinds in this package
|
||||
APIGroup = "alertenrichment.grafana.app"
|
||||
// APIVersion is the API version used by all kinds in this package
|
||||
APIVersion = "v1beta1"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package
|
||||
GroupVersion = schema.GroupVersion{
|
||||
Group: APIGroup,
|
||||
Version: APIVersion,
|
||||
}
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +groupName=alertenrichment.grafana.app
|
||||
|
||||
package v1beta1
|
|
@ -0,0 +1,207 @@
|
|||
package v1beta1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// App Platform resource.Object interface methods for AlertEnrichment
|
||||
|
||||
func (o *AlertEnrichment) GetSpec() any {
|
||||
return o.Spec
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) SetSpec(spec any) error {
|
||||
cast, ok := spec.(AlertEnrichmentSpec)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set spec type %#v, not of type AlertEnrichmentSpec", spec)
|
||||
}
|
||||
o.Spec = cast
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) GetSubresources() map[string]any {
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) GetSubresource(name string) (any, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) SetSubresource(name string, value any) error {
|
||||
return fmt.Errorf("subresource %s does not exist", name)
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) Copy() resource.Object {
|
||||
return resource.CopyObject(o)
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) GetStaticMetadata() resource.StaticMetadata {
|
||||
gvk := o.GroupVersionKind()
|
||||
return resource.StaticMetadata{
|
||||
Name: o.Name,
|
||||
Namespace: o.Namespace,
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) SetStaticMetadata(metadata resource.StaticMetadata) {
|
||||
o.Name = metadata.Name
|
||||
o.Namespace = metadata.Namespace
|
||||
o.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: metadata.Group,
|
||||
Version: metadata.Version,
|
||||
Kind: metadata.Kind,
|
||||
})
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) GetCommonMetadata() resource.CommonMetadata {
|
||||
dt := o.DeletionTimestamp
|
||||
var deletionTimestamp *time.Time
|
||||
if dt != nil {
|
||||
deletionTimestamp = &dt.Time
|
||||
}
|
||||
// Legacy ExtraFields support
|
||||
extraFields := make(map[string]any)
|
||||
if o.Annotations != nil {
|
||||
extraFields["annotations"] = o.Annotations
|
||||
}
|
||||
if o.ManagedFields != nil {
|
||||
extraFields["managedFields"] = o.ManagedFields
|
||||
}
|
||||
if o.OwnerReferences != nil {
|
||||
extraFields["ownerReferences"] = o.OwnerReferences
|
||||
}
|
||||
return resource.CommonMetadata{
|
||||
UID: string(o.UID),
|
||||
ResourceVersion: o.ResourceVersion,
|
||||
Generation: o.Generation,
|
||||
Labels: o.Labels,
|
||||
CreationTimestamp: o.CreationTimestamp.Time,
|
||||
DeletionTimestamp: deletionTimestamp,
|
||||
Finalizers: o.Finalizers,
|
||||
UpdateTimestamp: o.GetUpdateTimestamp(),
|
||||
CreatedBy: o.GetCreatedBy(),
|
||||
UpdatedBy: o.GetUpdatedBy(),
|
||||
ExtraFields: extraFields,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) SetCommonMetadata(metadata resource.CommonMetadata) {
|
||||
o.UID = types.UID(metadata.UID)
|
||||
o.ResourceVersion = metadata.ResourceVersion
|
||||
o.Generation = metadata.Generation
|
||||
o.Labels = metadata.Labels
|
||||
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
|
||||
if metadata.DeletionTimestamp != nil {
|
||||
dt := metav1.NewTime(*metadata.DeletionTimestamp)
|
||||
o.DeletionTimestamp = &dt
|
||||
} else {
|
||||
o.DeletionTimestamp = nil
|
||||
}
|
||||
o.Finalizers = metadata.Finalizers
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
if !metadata.UpdateTimestamp.IsZero() {
|
||||
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
|
||||
}
|
||||
if metadata.CreatedBy != "" {
|
||||
o.SetCreatedBy(metadata.CreatedBy)
|
||||
}
|
||||
if metadata.UpdatedBy != "" {
|
||||
o.SetUpdatedBy(metadata.UpdatedBy)
|
||||
}
|
||||
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
|
||||
if metadata.ExtraFields != nil {
|
||||
if annotations, ok := metadata.ExtraFields["annotations"].(map[string]string); ok {
|
||||
o.Annotations = annotations
|
||||
}
|
||||
if managedFields, ok := metadata.ExtraFields["managedFields"].([]metav1.ManagedFieldsEntry); ok {
|
||||
o.ManagedFields = managedFields
|
||||
}
|
||||
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"].([]metav1.OwnerReference); ok {
|
||||
o.OwnerReferences = ownerReferences
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) GetCreatedBy() string {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
return o.Annotations["grafana.com/createdBy"]
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) SetCreatedBy(createdBy string) {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
o.Annotations["grafana.com/createdBy"] = createdBy
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) GetUpdateTimestamp() time.Time {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
parsed, _ := time.Parse(time.RFC3339, o.Annotations["grafana.com/updateTimestamp"])
|
||||
return parsed
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) SetUpdateTimestamp(updateTimestamp time.Time) {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
o.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) GetUpdatedBy() string {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
return o.Annotations["grafana.com/updatedBy"]
|
||||
}
|
||||
|
||||
func (o *AlertEnrichment) SetUpdatedBy(updatedBy string) {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
o.Annotations["grafana.com/updatedBy"] = updatedBy
|
||||
}
|
||||
|
||||
// AlertEnrichmentList also needs to implement resource.ListObject
|
||||
func (o *AlertEnrichmentList) Copy() resource.ListObject {
|
||||
cpy := &AlertEnrichmentList{
|
||||
TypeMeta: o.TypeMeta,
|
||||
Items: make([]AlertEnrichment, len(o.Items)),
|
||||
}
|
||||
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
o.Items[i].DeepCopyInto(&cpy.Items[i])
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *AlertEnrichmentList) GetItems() []resource.Object {
|
||||
items := make([]resource.Object, len(o.Items))
|
||||
for i, item := range o.Items {
|
||||
items[i] = &item
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (o *AlertEnrichmentList) SetItems(items []resource.Object) {
|
||||
o.Items = make([]AlertEnrichment, len(items))
|
||||
for i, item := range items {
|
||||
if ae, ok := item.(*AlertEnrichment); ok {
|
||||
o.Items[i] = *ae
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue