Compare commits

...

6 Commits

Author SHA1 Message Date
Dimitris Sotirakis 63cb359220 Update grabpl version (#42091) 2021-11-22 18:02:08 +01:00
Dimitris Sotirakis 748824836f Remove Linux grabpl download step from Windows enterprise builds (#42065) 2021-11-22 13:15:18 +01:00
Dimitris Sotirakis 05bd79087a Remove grabpl step from Windows builds (#42052) 2021-11-22 12:02:37 +01:00
Dimitris Sotirakis 20745e2f71 Add deployment_tools_config.json to git and eslint ignore (#42040) 2021-11-22 11:19:32 +01:00
Dominik Prokop 71935ec4d7 [v8.3.0-beta1] Manual backports (#42032)
* Alerting: increase timeout for silences tests (#41918) (#41958)

(cherry picked from commit 81155e2d55)

Co-authored-by: Nathan Rodman <nathanrodman@gmail.com>

* Fix loop when cannot fetch roles (#41901) (#41945)

(cherry picked from commit d66158a042)

Co-authored-by: Alexander Zobnin <alexanderzobnin@gmail.com>

* ThresholdControls: Use correct scale key when calculating handle position (#41942) (#41971)

(cherry picked from commit 67f43cd7ab)

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>

* Candlestick: fix volume histogram height by using mapped field name (#41931) (#41934)

(cherry picked from commit 17c2f52dcf)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>

Co-authored-by: Grot (@grafanabot) <43478413+grafanabot@users.noreply.github.com>
Co-authored-by: Nathan Rodman <nathanrodman@gmail.com>
Co-authored-by: Alexander Zobnin <alexanderzobnin@gmail.com>
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
2021-11-22 10:32:11 +01:00
Dimitris Sotirakis d95a4c6488 Make integration tests depend on initialize for enterprise-release-* branches (#42004) (#42031) 2021-11-22 09:44:05 +01:00
16 changed files with 436 additions and 364 deletions
+41 -77
View File
@@ -11,7 +11,7 @@ services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -106,7 +106,7 @@ services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -279,7 +279,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -301,7 +301,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database postgres
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
@@ -317,7 +317,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database mysql
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql
@@ -353,7 +353,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -450,7 +450,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database postgres
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
@@ -466,7 +466,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database mysql
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql
@@ -691,7 +691,7 @@ steps:
name: identify-runner
- commands:
- $$ProgressPreference = "SilentlyContinue"
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/windows/grabpl.exe
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/windows/grabpl.exe
-OutFile grabpl.exe
image: grafana/ci-wix:0.1.1
name: initialize
@@ -734,7 +734,7 @@ services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -824,7 +824,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -905,7 +905,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database postgres
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
@@ -921,7 +921,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database mysql
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql
@@ -1115,19 +1115,13 @@ platform:
version: "1809"
services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
- commands:
- echo $env:DRONE_RUNNER_NAME
image: mcr.microsoft.com/windows:1809
name: identify-runner
- commands:
- $$ProgressPreference = "SilentlyContinue"
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/windows/grabpl.exe
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/windows/grabpl.exe
-OutFile grabpl.exe
image: grafana/ci-wix:0.1.1
name: initialize
@@ -1190,7 +1184,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -1206,7 +1200,7 @@ steps:
GITHUB_TOKEN:
from_secret: github_token
image: grafana/build-container:1.4.5
name: clone
name: clone-enterprise
- commands:
- mv bin/grabpl /tmp/
- rmdir bin
@@ -1220,7 +1214,7 @@ steps:
- ./bin/grabpl gen-version ${DRONE_TAG}
- yarn install --immutable
depends_on:
- clone
- clone-enterprise
image: grafana/build-container:1.4.5
name: initialize
- commands:
@@ -1587,19 +1581,13 @@ platform:
version: "1809"
services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
- commands:
- echo $env:DRONE_RUNNER_NAME
image: mcr.microsoft.com/windows:1809
name: identify-runner
- commands:
- $$ProgressPreference = "SilentlyContinue"
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/windows/grabpl.exe
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/windows/grabpl.exe
-OutFile grabpl.exe
- git clone "https://$$env:GITHUB_TOKEN@github.com/grafana/grafana-enterprise.git"
- cd grafana-enterprise
@@ -1660,7 +1648,7 @@ services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -1769,7 +1757,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -1850,7 +1838,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database postgres
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
@@ -1866,7 +1854,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database mysql
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql
@@ -2048,19 +2036,13 @@ platform:
version: "1809"
services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
- commands:
- echo $env:DRONE_RUNNER_NAME
image: mcr.microsoft.com/windows:1809
name: identify-runner
- commands:
- $$ProgressPreference = "SilentlyContinue"
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/windows/grabpl.exe
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/windows/grabpl.exe
-OutFile grabpl.exe
image: grafana/ci-wix:0.1.1
name: initialize
@@ -2124,7 +2106,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -2140,7 +2122,7 @@ steps:
GITHUB_TOKEN:
from_secret: github_token
image: grafana/build-container:1.4.5
name: clone
name: clone-enterprise
- commands:
- mv bin/grabpl /tmp/
- rmdir bin
@@ -2154,7 +2136,7 @@ steps:
- ./bin/grabpl gen-version v7.3.0-test
- yarn install --immutable
depends_on:
- clone
- clone-enterprise
image: grafana/build-container:1.4.5
name: initialize
- commands:
@@ -2223,7 +2205,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database postgres
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
@@ -2239,7 +2221,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database mysql
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql
@@ -2398,7 +2380,7 @@ steps:
- dockerize -wait tcp://redis:6379/0 -timeout 120s
- ./bin/grabpl integration-tests
depends_on:
- initialize
- grabpl
environment:
REDIS_URL: redis://redis:6379/0
image: grafana/build-container:1.4.5
@@ -2407,7 +2389,7 @@ steps:
- dockerize -wait tcp://memcached:11211 -timeout 120s
- ./bin/grabpl integration-tests
depends_on:
- initialize
- grabpl
environment:
MEMCACHED_HOSTS: memcached:11211
image: grafana/build-container:1.4.5
@@ -2513,19 +2495,13 @@ platform:
version: "1809"
services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
- commands:
- echo $env:DRONE_RUNNER_NAME
image: mcr.microsoft.com/windows:1809
name: identify-runner
- commands:
- $$ProgressPreference = "SilentlyContinue"
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/windows/grabpl.exe
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/windows/grabpl.exe
-OutFile grabpl.exe
- git clone "https://$$env:GITHUB_TOKEN@github.com/grafana/grafana-enterprise.git"
- cd grafana-enterprise
@@ -2587,7 +2563,7 @@ services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -2701,7 +2677,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -2781,7 +2757,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database postgres
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
@@ -2797,7 +2773,7 @@ steps:
- go clean -testcache
- ./bin/grabpl integration-tests --database mysql
depends_on:
- initialize
- grabpl
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql
@@ -2957,19 +2933,13 @@ platform:
version: "1809"
services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
- commands:
- echo $env:DRONE_RUNNER_NAME
image: mcr.microsoft.com/windows:1809
name: identify-runner
- commands:
- $$ProgressPreference = "SilentlyContinue"
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/windows/grabpl.exe
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/windows/grabpl.exe
-OutFile grabpl.exe
image: grafana/ci-wix:0.1.1
name: initialize
@@ -3028,7 +2998,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -3044,7 +3014,7 @@ steps:
GITHUB_TOKEN:
from_secret: github_token
image: grafana/build-container:1.4.5
name: clone
name: clone-enterprise
- commands:
- mv bin/grabpl /tmp/
- rmdir bin
@@ -3057,7 +3027,7 @@ steps:
- ./bin/grabpl gen-version --build-id ${DRONE_BUILD_NUMBER}
- yarn install --immutable
depends_on:
- clone
- clone-enterprise
image: grafana/build-container:1.4.5
name: initialize
- commands:
@@ -3421,19 +3391,13 @@ platform:
version: "1809"
services: []
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
- commands:
- echo $env:DRONE_RUNNER_NAME
image: mcr.microsoft.com/windows:1809
name: identify-runner
- commands:
- $$ProgressPreference = "SilentlyContinue"
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.1/windows/grabpl.exe
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v2.6.2/windows/grabpl.exe
-OutFile grabpl.exe
- git clone "https://$$env:GITHUB_TOKEN@github.com/grafana/grafana-enterprise.git"
- cd grafana-enterprise
@@ -3556,6 +3520,6 @@ kind: secret
name: drone_token
---
kind: signature
hmac: 12c6a397733d4624d68b34b9eeb4b3b0728eb9a1c678cf6eeb9b435f9b9a652f
hmac: 5c5b90b18e6dacf446355a37979d19ba09ad6128a12a6fff2099fac3fff02b08
...
+1
View File
@@ -7,3 +7,4 @@ data
dist
e2e/tmp
public/lib/monaco
deployment_tools_config.json
+2
View File
@@ -149,3 +149,5 @@ compilation-stats.json
# auto generated Go files
*_gen.go
deployment_tools_config.json
@@ -6,6 +6,7 @@ import {
DataFrame,
DataHoverClearEvent,
DataHoverEvent,
Field,
FieldMatcherID,
fieldMatchers,
LegacyGraphHoverEvent,
@@ -44,8 +45,8 @@ export interface GraphNGProps extends Themeable2 {
legend: VizLegendOptions;
fields?: XYFieldMatchers; // default will assume timeseries data
renderers?: Renderers;
tweakScale?: (opts: ScaleProps) => ScaleProps;
tweakAxis?: (opts: AxisProps) => AxisProps;
tweakScale?: (opts: ScaleProps, forField: Field) => ScaleProps;
tweakAxis?: (opts: AxisProps, forField: Field) => AxisProps;
onLegendClick?: (event: GraphNGLegendEvent) => void;
children?: (builder: UPlotConfigBuilder, alignedFrame: DataFrame) => React.ReactNode;
prepConfig: (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => UPlotConfigBuilder;
@@ -1,6 +1,8 @@
import { XYFieldMatchers } from './types';
import { ArrayVector, DataFrame, FieldType, outerJoinDataFrames } from '@grafana/data';
import { ArrayVector, DataFrame, FieldConfig, FieldType, outerJoinDataFrames } from '@grafana/data';
import { nullToUndefThreshold } from './nullToUndefThreshold';
import { AxisPlacement, GraphFieldConfig, ScaleDistribution, ScaleDistributionConfig } from '@grafana/schema';
import { FIXED_UNIT } from './GraphNG';
// will mutate the DataFrame's fields' values
function applySpanNullsThresholds(frame: DataFrame) {
@@ -38,3 +40,36 @@ export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers
return alignedFrame && applySpanNullsThresholds(alignedFrame);
}
export function buildScaleKey(config: FieldConfig<GraphFieldConfig>) {
const defaultPart = 'na';
const scaleRange = `${config.min !== undefined ? config.min : defaultPart}-${
config.max !== undefined ? config.max : defaultPart
}`;
const scaleSoftRange = `${config.custom?.axisSoftMin !== undefined ? config.custom.axisSoftMin : defaultPart}-${
config.custom?.axisSoftMax !== undefined ? config.custom.axisSoftMax : defaultPart
}`;
const scalePlacement = `${
config.custom?.axisPlacement !== undefined ? config.custom?.axisPlacement : AxisPlacement.Auto
}`;
const scaleUnit = config.unit ?? FIXED_UNIT;
const scaleDistribution = config.custom?.scaleDistribution
? getScaleDistributionPart(config.custom.scaleDistribution)
: ScaleDistribution.Linear;
const scaleLabel = Boolean(config.custom?.axisLabel) ? config.custom!.axisLabel : defaultPart;
return `${scaleUnit}/${scaleRange}/${scaleSoftRange}/${scalePlacement}/${scaleDistribution}/${scaleLabel}`;
}
function getScaleDistributionPart(config: ScaleDistributionConfig) {
if (config.type === ScaleDistribution.Log) {
return `${config.type}${config.log}`;
}
return config.type;
}
@@ -14,7 +14,6 @@ import {
} from '@grafana/data';
import { UPlotConfigBuilder, UPlotConfigPrepFn } from '../uPlot/config/UPlotConfigBuilder';
import { FIXED_UNIT } from '../GraphNG/GraphNG';
import {
AxisPlacement,
GraphDrawStyle,
@@ -24,11 +23,10 @@ import {
ScaleDirection,
ScaleOrientation,
VizLegendOptions,
ScaleDistributionConfig,
ScaleDistribution,
} from '@grafana/schema';
import { collectStackingGroups, orderIdsByCalcs, preparePlotData } from '../uPlot/utils';
import uPlot from 'uplot';
import { buildScaleKey } from '../GraphNG/utils';
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
@@ -146,17 +144,20 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
// The builder will manage unique scaleKeys and combine where appropriate
builder.addScale(
tweakScale({
scaleKey,
orientation: ScaleOrientation.Vertical,
direction: ScaleDirection.Up,
distribution: customConfig.scaleDistribution?.type,
log: customConfig.scaleDistribution?.log,
min: field.config.min,
max: field.config.max,
softMin: customConfig.axisSoftMin,
softMax: customConfig.axisSoftMax,
})
tweakScale(
{
scaleKey,
orientation: ScaleOrientation.Vertical,
direction: ScaleDirection.Up,
distribution: customConfig.scaleDistribution?.type,
log: customConfig.scaleDistribution?.log,
min: field.config.min,
max: field.config.max,
softMin: customConfig.axisSoftMin,
softMax: customConfig.axisSoftMax,
},
field
)
);
if (!yScaleKey) {
@@ -165,15 +166,18 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
if (customConfig.axisPlacement !== AxisPlacement.Hidden) {
builder.addAxis(
tweakAxis({
scaleKey,
label: customConfig.axisLabel,
size: customConfig.axisWidth,
placement: customConfig.axisPlacement ?? AxisPlacement.Auto,
formatValue: (v) => formattedValueToString(fmt(v)),
theme,
grid: { show: customConfig.axisGridShow },
})
tweakAxis(
{
scaleKey,
label: customConfig.axisLabel,
size: customConfig.axisWidth,
placement: customConfig.axisPlacement ?? AxisPlacement.Auto,
formatValue: (v) => formattedValueToString(fmt(v)),
theme,
grid: { show: customConfig.axisGridShow },
},
field
)
);
}
@@ -435,34 +439,3 @@ export function getNamesToFieldIndex(frame: DataFrame, allFrames: DataFrame[]):
});
return originNames;
}
function buildScaleKey(config: FieldConfig<GraphFieldConfig>) {
const defaultPart = 'na';
const scaleRange = `${config.min !== undefined ? config.min : defaultPart}-${
config.max !== undefined ? config.max : defaultPart
}`;
const scaleSoftRange = `${config.custom?.axisSoftMin !== undefined ? config.custom.axisSoftMin : defaultPart}-${
config.custom?.axisSoftMax !== undefined ? config.custom.axisSoftMax : defaultPart
}`;
const scalePlacement = `${config.custom?.axisPlacement !== undefined ? config.custom?.axisPlacement : defaultPart}`;
const scaleUnit = config.unit ?? FIXED_UNIT;
const scaleDistribution = config.custom?.scaleDistribution
? getScaleDistributionPart(config.custom.scaleDistribution)
: ScaleDistribution.Linear;
const scaleLabel = Boolean(config.custom?.axisLabel) ? config.custom!.axisLabel : defaultPart;
return `${scaleUnit}/${scaleRange}/${scaleSoftRange}/${scalePlacement}/${scaleDistribution}/${scaleLabel}`;
}
function getScaleDistributionPart(config: ScaleDistributionConfig) {
if (config.type === ScaleDistribution.Log) {
return `${config.type}${config.log}`;
}
return config.type;
}
+1 -1
View File
@@ -265,7 +265,7 @@ export { UPlotConfigPrepFn } from './uPlot/config/UPlotConfigBuilder';
export { GraphNG, GraphNGProps, FIXED_UNIT } from './GraphNG/GraphNG';
export { TimeSeries } from './TimeSeries/TimeSeries';
export { useGraphNGContext } from './GraphNG/hooks';
export { preparePlotFrame } from './GraphNG/utils';
export { preparePlotFrame, buildScaleKey } from './GraphNG/utils';
export { GraphNGLegendEvent } from './GraphNG/types';
export * from './PanelChrome/types';
export { EmotionPerfTest } from './ThemeDemos/EmotionPerfTest';
@@ -4,6 +4,7 @@ import {
DataFrame,
DefaultTimeZone,
EventBus,
Field,
getTimeZoneInfo,
GrafanaTheme2,
TimeRange,
@@ -287,8 +288,8 @@ type UPlotConfigPrepOpts<T extends Record<string, any> = {}> = {
eventBus: EventBus;
allFrames: DataFrame[];
renderers?: Renderers;
tweakScale?: (opts: ScaleProps) => ScaleProps;
tweakAxis?: (opts: AxisProps) => AxisProps;
tweakScale?: (opts: ScaleProps, forField: Field) => ScaleProps;
tweakAxis?: (opts: AxisProps, forField: Field) => AxisProps;
} & T;
/** @alpha */
@@ -60,11 +60,16 @@ export const fetchUserRoles = async (userId: number, orgId?: number): Promise<Ro
if (orgId) {
userRolesUrl += `?targetOrgId=${orgId}`;
}
const roles = await getBackendSrv().get(userRolesUrl);
if (!roles || !roles.length) {
try {
const roles = await getBackendSrv().get(userRolesUrl);
if (!roles || !roles.length) {
return [];
}
return roles;
} catch (error) {
error.isHandled = true;
return [];
}
return roles;
};
export const updateUserRoles = (roleUids: string[], userId: number, orgId?: number) => {
@@ -17,6 +17,8 @@ import userEvent from '@testing-library/user-event';
jest.mock('./api/alertmanager');
const TEST_TIMEOUT = 60000;
const mocks = {
api: {
fetchSilences: typeAsJestMock(fetchSilences),
@@ -99,53 +101,65 @@ describe('Silences', () => {
setDataSourceSrv(new MockDataSourceSrv(dataSources));
});
it('loads and shows silences', async () => {
renderSilences();
await waitFor(() => expect(mocks.api.fetchSilences).toHaveBeenCalled());
await waitFor(() => expect(mocks.api.fetchAlerts).toHaveBeenCalled());
it(
'loads and shows silences',
async () => {
renderSilences();
await waitFor(() => expect(mocks.api.fetchSilences).toHaveBeenCalled());
await waitFor(() => expect(mocks.api.fetchAlerts).toHaveBeenCalled());
expect(ui.silencesTable.query()).not.toBeNull();
expect(ui.silencesTable.query()).not.toBeNull();
const silences = ui.silenceRow.queryAll();
expect(silences).toHaveLength(2);
expect(silences[0]).toHaveTextContent('foo=bar');
expect(silences[1]).toHaveTextContent('foo!=bar');
});
const silences = ui.silenceRow.queryAll();
expect(silences).toHaveLength(2);
expect(silences[0]).toHaveTextContent('foo=bar');
expect(silences[1]).toHaveTextContent('foo!=bar');
},
TEST_TIMEOUT
);
it('shows the correct number of silenced alerts', async () => {
mocks.api.fetchAlerts.mockImplementation(() => {
return Promise.resolve([
mockAlertmanagerAlert({
labels: { foo: 'bar', buzz: 'bazz' },
status: { state: AlertState.Suppressed, silencedBy: ['12345'], inhibitedBy: [] },
}),
mockAlertmanagerAlert({
labels: { foo: 'bar', buzz: 'bazz' },
status: { state: AlertState.Suppressed, silencedBy: ['12345'], inhibitedBy: [] },
}),
]);
});
it(
'shows the correct number of silenced alerts',
async () => {
mocks.api.fetchAlerts.mockImplementation(() => {
return Promise.resolve([
mockAlertmanagerAlert({
labels: { foo: 'bar', buzz: 'bazz' },
status: { state: AlertState.Suppressed, silencedBy: ['12345'], inhibitedBy: [] },
}),
mockAlertmanagerAlert({
labels: { foo: 'bar', buzz: 'bazz' },
status: { state: AlertState.Suppressed, silencedBy: ['12345'], inhibitedBy: [] },
}),
]);
});
renderSilences();
await waitFor(() => expect(mocks.api.fetchSilences).toHaveBeenCalled());
await waitFor(() => expect(mocks.api.fetchAlerts).toHaveBeenCalled());
renderSilences();
await waitFor(() => expect(mocks.api.fetchSilences).toHaveBeenCalled());
await waitFor(() => expect(mocks.api.fetchAlerts).toHaveBeenCalled());
const silencedAlertRows = ui.silencedAlertCell.getAll(ui.silencesTable.get());
expect(silencedAlertRows).toHaveLength(2);
expect(silencedAlertRows[0]).toHaveTextContent('2');
expect(silencedAlertRows[1]).toHaveTextContent('0');
});
const silencedAlertRows = ui.silencedAlertCell.getAll(ui.silencesTable.get());
expect(silencedAlertRows).toHaveLength(2);
expect(silencedAlertRows[0]).toHaveTextContent('2');
expect(silencedAlertRows[1]).toHaveTextContent('0');
},
TEST_TIMEOUT
);
it('filters silences by matchers', async () => {
renderSilences();
await waitFor(() => expect(mocks.api.fetchSilences).toHaveBeenCalled());
await waitFor(() => expect(mocks.api.fetchAlerts).toHaveBeenCalled());
it(
'filters silences by matchers',
async () => {
renderSilences();
await waitFor(() => expect(mocks.api.fetchSilences).toHaveBeenCalled());
await waitFor(() => expect(mocks.api.fetchAlerts).toHaveBeenCalled());
const queryBar = ui.queryBar.get();
userEvent.paste(queryBar, 'foo=bar');
const queryBar = ui.queryBar.get();
userEvent.paste(queryBar, 'foo=bar');
await waitFor(() => expect(ui.silenceRow.getAll()).toHaveLength(1));
});
await waitFor(() => expect(ui.silenceRow.getAll()).toHaveLength(1));
},
TEST_TIMEOUT
);
});
describe('Silence edit', () => {
@@ -157,94 +171,102 @@ describe('Silence edit', () => {
setDataSourceSrv(new MockDataSourceSrv(dataSources));
});
it('prefills the matchers field with matchers params', async () => {
renderSilences(
`${baseUrlPath}?matchers=${encodeURIComponent('foo=bar,bar=~ba.+,hello!=world,cluster!~us-central.*')}`
);
await waitFor(() => expect(ui.editor.durationField.query()).not.toBeNull());
it(
'prefills the matchers field with matchers params',
async () => {
renderSilences(
`${baseUrlPath}?matchers=${encodeURIComponent('foo=bar,bar=~ba.+,hello!=world,cluster!~us-central.*')}`
);
await waitFor(() => expect(ui.editor.durationField.query()).not.toBeNull());
const matchers = ui.editor.matchersField.queryAll();
expect(matchers).toHaveLength(4);
const matchers = ui.editor.matchersField.queryAll();
expect(matchers).toHaveLength(4);
expect(ui.editor.matcherName.query(matchers[0])).toHaveValue('foo');
expect(ui.editor.matcherOperator(MatcherOperator.equal).query(matchers[0])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[0])).toHaveValue('bar');
expect(ui.editor.matcherName.query(matchers[0])).toHaveValue('foo');
expect(ui.editor.matcherOperator(MatcherOperator.equal).query(matchers[0])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[0])).toHaveValue('bar');
expect(ui.editor.matcherName.query(matchers[1])).toHaveValue('bar');
expect(ui.editor.matcherOperator(MatcherOperator.regex).query(matchers[1])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[1])).toHaveValue('ba.+');
expect(ui.editor.matcherName.query(matchers[1])).toHaveValue('bar');
expect(ui.editor.matcherOperator(MatcherOperator.regex).query(matchers[1])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[1])).toHaveValue('ba.+');
expect(ui.editor.matcherName.query(matchers[2])).toHaveValue('hello');
expect(ui.editor.matcherOperator(MatcherOperator.notEqual).query(matchers[2])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[2])).toHaveValue('world');
expect(ui.editor.matcherName.query(matchers[2])).toHaveValue('hello');
expect(ui.editor.matcherOperator(MatcherOperator.notEqual).query(matchers[2])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[2])).toHaveValue('world');
expect(ui.editor.matcherName.query(matchers[3])).toHaveValue('cluster');
expect(ui.editor.matcherOperator(MatcherOperator.notRegex).query(matchers[3])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[3])).toHaveValue('us-central.*');
});
expect(ui.editor.matcherName.query(matchers[3])).toHaveValue('cluster');
expect(ui.editor.matcherOperator(MatcherOperator.notRegex).query(matchers[3])).not.toBeNull();
expect(ui.editor.matcherValue.query(matchers[3])).toHaveValue('us-central.*');
},
TEST_TIMEOUT
);
it('creates a new silence', async () => {
renderSilences(baseUrlPath);
await waitFor(() => expect(ui.editor.durationField.query()).not.toBeNull());
it(
'creates a new silence',
async () => {
renderSilences(baseUrlPath);
await waitFor(() => expect(ui.editor.durationField.query()).not.toBeNull());
const start = new Date();
const end = new Date(start.getTime() + 24 * 60 * 60 * 1000);
const start = new Date();
const end = new Date(start.getTime() + 24 * 60 * 60 * 1000);
const startDateString = dateTime(start).format('YYYY-MM-DD');
const endDateString = dateTime(end).format('YYYY-MM-DD');
const startDateString = dateTime(start).format('YYYY-MM-DD');
const endDateString = dateTime(end).format('YYYY-MM-DD');
userEvent.clear(ui.editor.durationInput.get());
userEvent.type(ui.editor.durationInput.get(), '1d');
userEvent.clear(ui.editor.durationInput.get());
userEvent.type(ui.editor.durationInput.get(), '1d');
await waitFor(() => expect(ui.editor.durationInput.query()).toHaveValue('1d'));
await waitFor(() => expect(ui.editor.timeRange.get()).toHaveTextContent(startDateString));
await waitFor(() => expect(ui.editor.timeRange.get()).toHaveTextContent(endDateString));
await waitFor(() => expect(ui.editor.durationInput.query()).toHaveValue('1d'));
await waitFor(() => expect(ui.editor.timeRange.get()).toHaveTextContent(startDateString));
await waitFor(() => expect(ui.editor.timeRange.get()).toHaveTextContent(endDateString));
userEvent.type(ui.editor.matcherName.get(), 'foo');
userEvent.type(ui.editor.matcherOperatorSelect.get(), '=');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.get(), 'bar');
userEvent.type(ui.editor.matcherName.get(), 'foo');
userEvent.type(ui.editor.matcherOperatorSelect.get(), '=');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.get(), 'bar');
// TODO remove skipPointerEventsCheck once https://github.com/jsdom/jsdom/issues/3232 is fixed
userEvent.click(ui.editor.addMatcherButton.get(), undefined, { skipPointerEventsCheck: true });
userEvent.type(ui.editor.matcherName.getAll()[1], 'bar');
userEvent.type(ui.editor.matcherOperatorSelect.getAll()[1], '!=');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.getAll()[1], 'buzz');
// TODO remove skipPointerEventsCheck once https://github.com/jsdom/jsdom/issues/3232 is fixed
userEvent.click(ui.editor.addMatcherButton.get(), undefined, { skipPointerEventsCheck: true });
userEvent.type(ui.editor.matcherName.getAll()[1], 'bar');
userEvent.type(ui.editor.matcherOperatorSelect.getAll()[1], '!=');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.getAll()[1], 'buzz');
// TODO remove skipPointerEventsCheck once https://github.com/jsdom/jsdom/issues/3232 is fixed
userEvent.click(ui.editor.addMatcherButton.get(), undefined, { skipPointerEventsCheck: true });
userEvent.type(ui.editor.matcherName.getAll()[2], 'region');
userEvent.type(ui.editor.matcherOperatorSelect.getAll()[2], '=~');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.getAll()[2], 'us-west-.*');
// TODO remove skipPointerEventsCheck once https://github.com/jsdom/jsdom/issues/3232 is fixed
userEvent.click(ui.editor.addMatcherButton.get(), undefined, { skipPointerEventsCheck: true });
userEvent.type(ui.editor.matcherName.getAll()[2], 'region');
userEvent.type(ui.editor.matcherOperatorSelect.getAll()[2], '=~');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.getAll()[2], 'us-west-.*');
// TODO remove skipPointerEventsCheck once https://github.com/jsdom/jsdom/issues/3232 is fixed
userEvent.click(ui.editor.addMatcherButton.get(), undefined, { skipPointerEventsCheck: true });
userEvent.type(ui.editor.matcherName.getAll()[3], 'env');
userEvent.type(ui.editor.matcherOperatorSelect.getAll()[3], '!~');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.getAll()[3], 'dev|staging');
// TODO remove skipPointerEventsCheck once https://github.com/jsdom/jsdom/issues/3232 is fixed
userEvent.click(ui.editor.addMatcherButton.get(), undefined, { skipPointerEventsCheck: true });
userEvent.type(ui.editor.matcherName.getAll()[3], 'env');
userEvent.type(ui.editor.matcherOperatorSelect.getAll()[3], '!~');
userEvent.tab();
userEvent.type(ui.editor.matcherValue.getAll()[3], 'dev|staging');
userEvent.type(ui.editor.comment.get(), 'Test');
userEvent.type(ui.editor.createdBy.get(), 'Homer Simpson');
userEvent.type(ui.editor.comment.get(), 'Test');
userEvent.type(ui.editor.createdBy.get(), 'Homer Simpson');
userEvent.click(ui.editor.submit.get());
userEvent.click(ui.editor.submit.get());
await waitFor(() =>
expect(mocks.api.createOrUpdateSilence).toHaveBeenCalledWith(
'grafana',
expect.objectContaining({
comment: 'Test',
createdBy: 'Homer Simpson',
matchers: [
{ isEqual: true, isRegex: false, name: 'foo', value: 'bar' },
{ isEqual: false, isRegex: false, name: 'bar', value: 'buzz' },
{ isEqual: true, isRegex: true, name: 'region', value: 'us-west-.*' },
{ isEqual: false, isRegex: true, name: 'env', value: 'dev|staging' },
],
})
)
);
});
await waitFor(() =>
expect(mocks.api.createOrUpdateSilence).toHaveBeenCalledWith(
'grafana',
expect.objectContaining({
comment: 'Test',
createdBy: 'Homer Simpson',
matchers: [
{ isEqual: true, isRegex: false, name: 'foo', value: 'bar' },
{ isEqual: false, isRegex: false, name: 'bar', value: 'buzz' },
{ isEqual: true, isRegex: true, name: 'region', value: 'us-west-.*' },
{ isEqual: false, isRegex: true, name: 'env', value: 'dev|staging' },
],
})
)
);
},
TEST_TIMEOUT
);
});
@@ -43,8 +43,8 @@ export const MarketTrendPanel: React.FC<CandlestickPanelProps> = ({
const info = useMemo(() => prepareCandlestickFields(data?.series, options, theme), [data, options, theme]);
const { renderers, tweakScale, tweakAxis } = useMemo(() => {
let tweakScale = (opts: ScaleProps) => opts;
let tweakAxis = (opts: AxisProps) => opts;
let tweakScale = (opts: ScaleProps, forField: Field) => opts;
let tweakAxis = (opts: AxisProps, forField: Field) => opts;
let doNothing = {
renderers: [],
@@ -97,8 +97,9 @@ export const MarketTrendPanel: React.FC<CandlestickPanelProps> = ({
theme: config.theme2,
});
tweakAxis = (opts: AxisProps) => {
if (opts.scaleKey === 'short') {
tweakAxis = (opts: AxisProps, forField: Field) => {
// we can't do forField === info.volume because of copies :(
if (forField.name === info.volume?.name) {
let filter = (u: uPlot, splits: number[]) => {
let _splits = [];
let max = u.series[volumeIdx].max as number;
@@ -122,8 +123,9 @@ export const MarketTrendPanel: React.FC<CandlestickPanelProps> = ({
return opts;
};
tweakScale = (opts: ScaleProps) => {
if (opts.scaleKey === 'short') {
tweakScale = (opts: ScaleProps, forField: Field) => {
// we can't do forField === info.volume because of copies :(
if (forField.name === info.volume?.name) {
opts.range = (u: uPlot, min: number, max: number) => [0, max * 7];
}
@@ -1,6 +1,6 @@
import React, { useState, useLayoutEffect, useMemo, useRef } from 'react';
import { FieldConfigSource, ThresholdsConfig, getValueFormat } from '@grafana/data';
import { UPlotConfigBuilder, FIXED_UNIT } from '@grafana/ui';
import { FieldConfigSource, ThresholdsConfig, getValueFormat, FieldConfig } from '@grafana/data';
import { UPlotConfigBuilder, buildScaleKey, GraphFieldConfig } from '@grafana/ui';
import { ThresholdDragHandle } from './ThresholdDragHandle';
import uPlot from 'uplot';
@@ -42,7 +42,8 @@ export const ThresholdControlsPlugin: React.FC<ThresholdControlsPluginProps> = (
if (!thresholds) {
return null;
}
const scale = fieldConfig.defaults.unit ?? FIXED_UNIT;
const scale = buildScaleKey(fieldConfig as FieldConfig<GraphFieldConfig>);
const decimals = fieldConfig.defaults.decimals;
const handles = [];
+3 -3
View File
@@ -65,8 +65,8 @@ def get_steps(edition, is_downstream=False):
test_backend_step(edition=edition),
test_backend_integration_step(edition=edition),
test_frontend_step(),
postgres_integration_tests_step(),
mysql_integration_tests_step(),
postgres_integration_tests_step(edition=edition, ver_mode=ver_mode),
mysql_integration_tests_step(edition=edition, ver_mode=ver_mode),
build_backend_step(edition=edition, ver_mode=ver_mode, is_downstream=is_downstream),
build_frontend_step(edition=edition, ver_mode=ver_mode, is_downstream=is_downstream),
build_plugins_step(edition=edition, sign=True),
@@ -99,7 +99,7 @@ def get_steps(edition, is_downstream=False):
])
if include_enterprise2:
steps.extend([redis_integration_tests_step(), memcached_integration_tests_step()])
steps.extend([redis_integration_tests_step(edition=edition2, ver_mode=ver_mode), memcached_integration_tests_step(edition=edition2, ver_mode=ver_mode)])
steps.extend([
release_canary_npm_packages_step(edition),
+4 -4
View File
@@ -66,8 +66,8 @@ def pr_pipelines(edition):
ensure_cuetsified_step(),
]
integration_test_steps = [
postgres_integration_tests_step(),
mysql_integration_tests_step(),
postgres_integration_tests_step(edition=edition, ver_mode=ver_mode),
mysql_integration_tests_step(edition=edition, ver_mode=ver_mode),
]
if include_enterprise2:
@@ -98,8 +98,8 @@ def pr_pipelines(edition):
if include_enterprise2:
integration_test_steps.extend([
redis_integration_tests_step(),
memcached_integration_tests_step(),
redis_integration_tests_step(edition=edition2, ver_mode=ver_mode),
memcached_integration_tests_step(edition=edition, ver_mode=ver_mode),
])
build_steps.extend([
package_step(edition=edition2, ver_mode=ver_mode, include_enterprise2=include_enterprise2, variants=['linux-x64']),
+28 -25
View File
@@ -77,14 +77,15 @@ def release_npm_packages_step(edition, ver_mode):
}
def get_steps(edition, ver_mode):
build_steps = []
package_steps = []
windows_package_steps = []
publish_steps = []
should_publish = ver_mode in ('release', 'test-release',)
should_upload = should_publish or ver_mode in ('release-branch',)
include_enterprise2 = edition == 'enterprise'
tries = None
if should_publish:
tries = 5
steps = [
build_steps = [
codespell_step(),
shellcheck_step(),
lint_backend_step(edition=edition),
@@ -92,8 +93,8 @@ def get_steps(edition, ver_mode):
test_backend_step(edition=edition),
test_backend_integration_step(edition=edition),
test_frontend_step(),
postgres_integration_tests_step(),
mysql_integration_tests_step(),
postgres_integration_tests_step(edition=edition, ver_mode=ver_mode),
mysql_integration_tests_step(edition=edition, ver_mode=ver_mode),
build_backend_step(edition=edition, ver_mode=ver_mode),
build_frontend_step(edition=edition, ver_mode=ver_mode),
build_plugins_step(edition=edition, sign=True),
@@ -101,9 +102,9 @@ def get_steps(edition, ver_mode):
ensure_cuetsified_step(),
]
edition2 = 'enterprise2'
if include_enterprise2:
edition2 = 'enterprise2'
steps.extend([
build_steps.extend([
lint_backend_step(edition=edition2),
test_backend_step(edition=edition2),
test_backend_integration_step(edition=edition2),
@@ -111,7 +112,7 @@ def get_steps(edition, ver_mode):
])
# Insert remaining steps
steps.extend([
build_steps.extend([
package_step(edition=edition, ver_mode=ver_mode, include_enterprise2=include_enterprise2),
e2e_tests_server_step(edition=edition),
e2e_tests_step(edition=edition, tries=3),
@@ -122,26 +123,26 @@ def get_steps(edition, ver_mode):
build_storybook = build_storybook_step(edition=edition, ver_mode=ver_mode)
if build_storybook:
steps.append(build_storybook)
build_steps.append(build_storybook)
if include_enterprise2:
steps.extend([redis_integration_tests_step(), memcached_integration_tests_step()])
build_steps.extend([redis_integration_tests_step(edition=edition2, ver_mode=ver_mode), memcached_integration_tests_step(edition=edition2, ver_mode=ver_mode)])
if should_upload:
steps.append(upload_cdn_step(edition=edition))
steps.append(upload_packages_step(edition=edition, ver_mode=ver_mode))
publish_steps.append(upload_cdn_step(edition=edition))
publish_steps.append(upload_packages_step(edition=edition, ver_mode=ver_mode))
if should_publish:
publish_step = publish_storybook_step(edition=edition, ver_mode=ver_mode)
release_npm_step = release_npm_packages_step(edition=edition, ver_mode=ver_mode)
if publish_step:
steps.append(publish_step)
publish_steps.append(publish_step)
if release_npm_step:
steps.append(release_npm_step)
windows_steps = get_windows_steps(edition=edition, ver_mode=ver_mode)
publish_steps.append(release_npm_step)
windows_package_steps = get_windows_steps(edition=edition, ver_mode=ver_mode)
if include_enterprise2:
edition2 = 'enterprise2'
steps.extend([
publish_steps.extend([
package_step(edition=edition2, ver_mode=ver_mode, include_enterprise2=include_enterprise2, variants=['linux-x64']),
e2e_tests_server_step(edition=edition2, port=3002),
e2e_tests_step(edition=edition2, port=3002, tries=3),
@@ -150,22 +151,23 @@ def get_steps(edition, ver_mode):
if should_upload:
step = upload_packages_step(edition=edition2, ver_mode=ver_mode)
if step:
steps.append(step)
publish_steps.append(step)
return steps, windows_steps
return build_steps, package_steps, windows_package_steps, publish_steps
def get_oss_pipelines(trigger, ver_mode):
edition = 'oss'
services = integration_test_services(edition=edition)
steps, windows_steps = get_steps(edition=edition, ver_mode=ver_mode)
build_steps, package_steps, windows_package_steps, publish_steps = get_steps(edition=edition, ver_mode=ver_mode)
return [
pipeline(
name='oss-build-{}'.format(ver_mode), edition=edition, trigger=trigger, services=services,
steps=[download_grabpl_step()] + initialize_step(edition, platform='linux', ver_mode=ver_mode) + steps,
steps=[download_grabpl_step()] + initialize_step(edition, platform='linux', ver_mode=ver_mode) +
build_steps + package_steps + publish_steps,
),
pipeline(
name='oss-windows-{}'.format(ver_mode), edition=edition, trigger=trigger,
steps=[download_grabpl_step()] + initialize_step(edition, platform='windows', ver_mode=ver_mode) + windows_steps,
steps=initialize_step(edition, platform='windows', ver_mode=ver_mode) + windows_package_steps,
platform='windows', depends_on=['oss-build-{}'.format(ver_mode)],
),
]
@@ -173,15 +175,16 @@ def get_oss_pipelines(trigger, ver_mode):
def get_enterprise_pipelines(trigger, ver_mode):
edition = 'enterprise'
services = integration_test_services(edition=edition)
steps, windows_steps = get_steps(edition=edition, ver_mode=ver_mode)
build_steps, package_steps, windows_package_steps, publish_steps = get_steps(edition=edition, ver_mode=ver_mode)
return [
pipeline(
name='enterprise-build-{}'.format(ver_mode), edition=edition, trigger=trigger, services=services,
steps=[download_grabpl_step()] + initialize_step(edition, platform='linux', ver_mode=ver_mode) + steps,
steps=[download_grabpl_step()] + initialize_step(edition, platform='linux', ver_mode=ver_mode) +
build_steps + package_steps + publish_steps,
),
pipeline(
name='enterprise-windows-{}'.format(ver_mode), edition=edition, trigger=trigger,
steps=[download_grabpl_step()] + initialize_step(edition, platform='windows', ver_mode=ver_mode) + windows_steps,
steps=initialize_step(edition, platform='windows', ver_mode=ver_mode) + windows_package_steps,
platform='windows', depends_on=['enterprise-build-{}'.format(ver_mode)],
),
]
+133 -71
View File
@@ -1,6 +1,6 @@
load('scripts/drone/vault.star', 'from_secret', 'github_token', 'pull_secret', 'drone_token')
grabpl_version = '2.6.1'
grabpl_version = '2.6.2'
build_image = 'grafana/build-container:1.4.5'
publish_image = 'grafana/grafana-ci-deploy:1.3.1'
grafana_docker_image = 'grafana/drone-grafana-docker:0.3.2'
@@ -11,6 +11,7 @@ windows_image = 'mcr.microsoft.com/windows:1809'
wix_image = 'grafana/ci-wix:0.1.1'
test_release_ver = 'v7.3.0-test'
def slack_step(channel):
return {
'name': 'slack',
@@ -22,6 +23,7 @@ def slack_step(channel):
},
}
def initialize_step(edition, platform, ver_mode, is_downstream=False, install_deps=True):
if platform == 'windows':
return [
@@ -53,13 +55,7 @@ def initialize_step(edition, platform, ver_mode, is_downstream=False, install_de
build_no = '$${SOURCE_BUILD_NUMBER}'
args = '--build-id {}'.format(build_no)
identify_runner_step = {
'name': 'identify-runner',
'image': alpine_image,
'commands': [
'echo $DRONE_RUNNER_NAME',
],
}
identify_runner = identify_runner_step(platform)
if install_deps:
common_cmds.extend([
@@ -80,41 +76,30 @@ def initialize_step(edition, platform, ver_mode, is_downstream=False, install_de
source_commit = ' $${SOURCE_COMMIT}'
committish = '${DRONE_COMMIT}'
steps = [
identify_runner_step,
{
'name': 'clone',
'image': build_image,
'environment': {
'GITHUB_TOKEN': from_secret(github_token),
},
'commands': [
'git clone "https://$${GITHUB_TOKEN}@github.com/grafana/grafana-enterprise.git"',
'cd grafana-enterprise',
'git checkout {}'.format(committish),
],
},
identify_runner,
clone_enterprise(committish),
{
'name': 'initialize',
'image': build_image,
'depends_on': [
'clone',
'clone-enterprise',
],
'commands': [
'mv bin/grabpl /tmp/',
'rmdir bin',
'mv grafana-enterprise /tmp/',
'/tmp/grabpl init-enterprise /tmp/grafana-enterprise{}'.format(source_commit),
'mv /tmp/grafana-enterprise/deployment_tools_config.json deployment_tools_config.json',
'mkdir bin',
'mv /tmp/grabpl bin/'
] + common_cmds,
'mv bin/grabpl /tmp/',
'rmdir bin',
'mv grafana-enterprise /tmp/',
'/tmp/grabpl init-enterprise /tmp/grafana-enterprise{}'.format(source_commit),
'mv /tmp/grafana-enterprise/deployment_tools_config.json deployment_tools_config.json',
'mkdir bin',
'mv /tmp/grabpl bin/'
] + common_cmds,
},
]
return steps
steps = [
identify_runner_step,
identify_runner,
{
'name': 'initialize',
'image': build_image,
@@ -124,6 +109,41 @@ def initialize_step(edition, platform, ver_mode, is_downstream=False, install_de
return steps
def identify_runner_step(platform):
if platform == 'linux':
return {
'name': 'identify-runner',
'image': alpine_image,
'commands': [
'echo $DRONE_RUNNER_NAME',
],
}
else:
return {
'name': 'identify-runner',
'image': windows_image,
'commands': [
'echo $env:DRONE_RUNNER_NAME',
],
}
def clone_enterprise(committish):
return {
'name': 'clone-enterprise',
'image': build_image,
'environment': {
'GITHUB_TOKEN': from_secret(github_token),
},
'commands': [
'git clone "https://$${GITHUB_TOKEN}@github.com/grafana/grafana-enterprise.git"',
'cd grafana-enterprise',
'git checkout {}'.format(committish),
],
}
def download_grabpl_step():
return {
'name': 'grabpl',
@@ -137,6 +157,7 @@ def download_grabpl_step():
]
}
def lint_drone_step():
return {
'name': 'lint-drone',
@@ -149,6 +170,7 @@ def lint_drone_step():
],
}
def enterprise_downstream_step(edition):
if edition in ('enterprise', 'enterprise2'):
return None
@@ -169,6 +191,7 @@ def enterprise_downstream_step(edition):
},
}
def lint_backend_step(edition):
return {
'name': 'lint-backend' + enterprise2_suffix(edition),
@@ -186,6 +209,7 @@ def lint_backend_step(edition):
],
}
def benchmark_ldap_step():
return {
'name': 'benchmark-ldap',
@@ -194,7 +218,7 @@ def benchmark_ldap_step():
'initialize',
],
'environment': {
'LDAP_HOSTNAME': 'ldap',
'LDAP_HOSTNAME': 'ldap',
},
'commands': [
'dockerize -wait tcp://ldap:389 -timeout 120s',
@@ -202,6 +226,7 @@ def benchmark_ldap_step():
],
}
def build_storybook_step(edition, ver_mode):
if edition in ('enterprise', 'enterprise2') and ver_mode in ('release', 'test-release'):
return None
@@ -222,6 +247,7 @@ def build_storybook_step(edition, ver_mode):
],
}
def publish_storybook_step(edition, ver_mode):
if edition in ('enterprise', 'enterprise2'):
return None
@@ -233,16 +259,17 @@ def publish_storybook_step(edition, ver_mode):
else:
commands = []
if ver_mode == 'release':
channels = ['latest', '${DRONE_TAG}',]
channels = ['latest', '${DRONE_TAG}', ]
else:
channels = ['canary',]
channels = ['canary', ]
commands.extend([
'printenv GCP_KEY | base64 -d > /tmp/gcpkey.json',
'gcloud auth activate-service-account --key-file=/tmp/gcpkey.json',
] + [
'gsutil -m rsync -d -r ./packages/grafana-ui/dist/storybook gs://grafana-storybook/{}'.format(c)
for c in channels
])
'printenv GCP_KEY | base64 -d > /tmp/gcpkey.json',
'gcloud auth activate-service-account --key-file=/tmp/gcpkey.json',
] + [
'gsutil -m rsync -d -r ./packages/grafana-ui/dist/storybook gs://grafana-storybook/{}'.format(
c)
for c in channels
])
return {
'name': 'publish-storybook',
@@ -257,6 +284,7 @@ def publish_storybook_step(edition, ver_mode):
'commands': commands,
}
def upload_cdn_step(edition):
return {
'name': 'upload-cdn-assets' + enterprise2_suffix(edition),
@@ -268,10 +296,11 @@ def upload_cdn_step(edition):
'GCP_GRAFANA_UPLOAD_KEY': from_secret('gcp_key'),
},
'commands': [
'./bin/grabpl upload-cdn --edition {} --bucket "grafana-static-assets"'.format(edition),
'./bin/grabpl upload-cdn --edition {} --bucket "grafana-static-assets"'.format(edition),
],
}
def build_backend_step(edition, ver_mode, variants=None, is_downstream=False):
variants_str = ''
if variants:
@@ -318,6 +347,7 @@ def build_backend_step(edition, ver_mode, variants=None, is_downstream=False):
'commands': cmds,
}
def build_frontend_step(edition, ver_mode, is_downstream=False):
if not is_downstream:
build_no = '${DRONE_BUILD_NUMBER}'
@@ -328,17 +358,17 @@ def build_frontend_step(edition, ver_mode, is_downstream=False):
if ver_mode == 'release':
cmds = [
'./bin/grabpl build-frontend --jobs 8 --github-token $${GITHUB_TOKEN} --no-install-deps ' + \
'--edition {} --no-pull-enterprise ${{DRONE_TAG}}'.format(edition),
'--edition {} --no-pull-enterprise ${{DRONE_TAG}}'.format(edition),
]
elif ver_mode == 'test-release':
cmds = [
'./bin/grabpl build-frontend --jobs 8 --github-token $${GITHUB_TOKEN} --no-install-deps ' + \
'--edition {} --no-pull-enterprise {}'.format(edition, test_release_ver),
]
'--edition {} --no-pull-enterprise {}'.format(edition, test_release_ver),
]
else:
cmds = [
'./bin/grabpl build-frontend --jobs 8 --no-install-deps --edition {} '.format(edition) + \
'--build-id {} --no-pull-enterprise'.format(build_no),
'--build-id {} --no-pull-enterprise'.format(build_no),
]
return {
@@ -350,6 +380,7 @@ def build_frontend_step(edition, ver_mode, is_downstream=False):
'commands': cmds,
}
def build_frontend_docs_step(edition):
return {
'name': 'build-frontend-docs',
@@ -362,6 +393,7 @@ def build_frontend_docs_step(edition):
]
}
def build_plugins_step(edition, sign=False):
if sign:
env = {
@@ -384,6 +416,7 @@ def build_plugins_step(edition, sign=False):
],
}
def test_backend_step(edition):
return {
'name': 'test-backend' + enterprise2_suffix(edition),
@@ -396,6 +429,7 @@ def test_backend_step(edition):
],
}
def test_backend_integration_step(edition):
return {
'name': 'test-backend-integration' + enterprise2_suffix(edition),
@@ -408,6 +442,7 @@ def test_backend_integration_step(edition):
],
}
def test_frontend_step():
return {
'name': 'test-frontend',
@@ -423,6 +458,7 @@ def test_frontend_step():
],
}
def lint_frontend_step():
return {
'name': 'lint-frontend',
@@ -440,6 +476,7 @@ def lint_frontend_step():
],
}
def test_a11y_frontend_step(ver_mode, edition, port=3001):
commands = [
'yarn wait-on http://$HOST:$PORT',
@@ -459,9 +496,9 @@ def test_a11y_frontend_step(ver_mode, edition, port=3001):
'name': 'test-a11y-frontend' + enterprise2_suffix(edition),
'image': 'hugohaggmark/docker-puppeteer',
'depends_on': [
'end-to-end-tests-server' + enterprise2_suffix(edition),
'end-to-end-tests-server' + enterprise2_suffix(edition),
],
'environment': {
'environment': {
'GRAFANA_MISC_STATS_API_KEY': from_secret('grafana_misc_stats_api_key'),
'HOST': 'end-to-end-tests-server' + enterprise2_suffix(edition),
'PORT': port,
@@ -470,6 +507,7 @@ def test_a11y_frontend_step(ver_mode, edition, port=3001):
'commands': commands,
}
def frontend_metrics_step(edition):
if edition in ('enterprise', 'enterprise2'):
return None
@@ -489,6 +527,7 @@ def frontend_metrics_step(edition):
],
}
def codespell_step():
return {
'name': 'codespell',
@@ -504,6 +543,7 @@ def codespell_step():
],
}
def shellcheck_step():
return {
'name': 'shellcheck',
@@ -516,6 +556,7 @@ def shellcheck_step():
],
}
def package_step(edition, ver_mode, include_enterprise2=False, variants=None, is_downstream=False):
deps = [
'build-plugins',
@@ -552,16 +593,16 @@ def package_step(edition, ver_mode, include_enterprise2=False, variants=None, is
if ver_mode == 'release':
cmds = [
'{}./bin/grabpl package --jobs 8 --edition {} '.format(test_args, edition) + \
'--github-token $${{GITHUB_TOKEN}} --no-pull-enterprise{} ${{DRONE_TAG}}'.format(
sign_args
),
'--github-token $${{GITHUB_TOKEN}} --no-pull-enterprise{} ${{DRONE_TAG}}'.format(
sign_args
),
]
elif ver_mode == 'test-release':
cmds = [
'{}./bin/grabpl package --jobs 8 --edition {} '.format(test_args, edition) + \
'--github-token $${{GITHUB_TOKEN}} --no-pull-enterprise{} {}'.format(
sign_args, test_release_ver,
),
'--github-token $${{GITHUB_TOKEN}} --no-pull-enterprise{} {}'.format(
sign_args, test_release_ver,
),
]
else:
if not is_downstream:
@@ -570,7 +611,7 @@ def package_step(edition, ver_mode, include_enterprise2=False, variants=None, is
build_no = '$${SOURCE_BUILD_NUMBER}'
cmds = [
'{}./bin/grabpl package --jobs 8 --edition {} '.format(test_args, edition) + \
'--build-id {} --no-pull-enterprise{}{}'.format(build_no, variants_str, sign_args),
'--build-id {} --no-pull-enterprise{}{}'.format(build_no, variants_str, sign_args),
]
return {
@@ -581,6 +622,7 @@ def package_step(edition, ver_mode, include_enterprise2=False, variants=None, is
'commands': cmds,
}
def e2e_tests_server_step(edition, port=3001):
package_file_pfx = ''
if edition == 'enterprise2':
@@ -608,6 +650,7 @@ def e2e_tests_server_step(edition, port=3001):
],
}
def e2e_tests_step(edition, port=3001, tries=None):
cmd = './bin/grabpl e2e-tests --port {}'.format(port)
if tries:
@@ -629,6 +672,7 @@ def e2e_tests_step(edition, port=3001, tries=None):
],
}
def build_docs_website_step():
return {
'name': 'build-docs-website',
@@ -644,6 +688,7 @@ def build_docs_website_step():
],
}
def copy_packages_for_docker_step():
return {
'name': 'copy-packages-for-docker',
@@ -657,6 +702,7 @@ def copy_packages_for_docker_step():
],
}
def build_docker_images_step(edition, ver_mode, archs=None, ubuntu=False, publish=False):
if ver_mode == 'test-release':
publish = False
@@ -683,13 +729,17 @@ def build_docker_images_step(edition, ver_mode, archs=None, ubuntu=False, publis
'settings': settings,
}
def postgres_integration_tests_step():
def postgres_integration_tests_step(edition, ver_mode):
deps = []
if edition in ('enterprise', 'enterprise2') and ver_mode in ('release-branch', 'release'):
deps.extend(['initialize'])
else:
deps.extend(['grabpl'])
return {
'name': 'postgres-integration-tests',
'image': build_image,
'depends_on': [
'initialize',
],
'depends_on': deps,
'environment': {
'PGPASSWORD': 'grafanatest',
'GRAFANA_TEST_DB': 'postgres',
@@ -700,20 +750,24 @@ def postgres_integration_tests_step():
'apt-get install -yq postgresql-client',
'dockerize -wait tcp://postgres:5432 -timeout 120s',
'psql -p 5432 -h postgres -U grafanatest -d grafanatest -f ' +
'devenv/docker/blocks/postgres_tests/setup.sql',
'devenv/docker/blocks/postgres_tests/setup.sql',
# Make sure that we don't use cached results for another database
'go clean -testcache',
'./bin/grabpl integration-tests --database postgres',
],
}
def mysql_integration_tests_step():
def mysql_integration_tests_step(edition, ver_mode):
deps = []
if edition in ('enterprise', 'enterprise2') and ver_mode in ('release-branch', 'release'):
deps.extend(['initialize'])
else:
deps.extend(['grabpl'])
return {
'name': 'mysql-integration-tests',
'image': build_image,
'depends_on': [
'initialize',
],
'depends_on': deps,
'environment': {
'GRAFANA_TEST_DB': 'mysql',
'MYSQL_HOST': 'mysql',
@@ -729,13 +783,17 @@ def mysql_integration_tests_step():
],
}
def redis_integration_tests_step():
def redis_integration_tests_step(edition, ver_mode):
deps = []
if edition in ('enterprise', 'enterprise2') and ver_mode in ('release-branch', 'release'):
deps.extend(['initialize'])
else:
deps.extend(['grabpl'])
return {
'name': 'redis-integration-tests',
'image': build_image,
'depends_on': [
'initialize',
],
'depends_on': deps,
'environment': {
'REDIS_URL': 'redis://redis:6379/0',
},
@@ -745,13 +803,17 @@ def redis_integration_tests_step():
],
}
def memcached_integration_tests_step():
def memcached_integration_tests_step(edition, ver_mode):
deps = []
if edition in ('enterprise', 'enterprise2') and ver_mode in ('release-branch', 'release'):
deps.extend(['initialize'])
else:
deps.extend(['grabpl'])
return {
'name': 'memcached-integration-tests',
'image': build_image,
'depends_on': [
'initialize',
],
'depends_on': deps,
'environment': {
'MEMCACHED_HOSTS': 'memcached:11211',
},