CI: Backport CI/Release related code to v9.3.x (#62752)
* Batch-move everything
* go mod tidy
* make drone
* Remove genversions
* Bump alpine image
* Revert back pkg/build/docker/build.go
* Make sure correct enterprise branch is checked out
* Add enterprise2 version
* Remove extensions
* Bump build container
* backport node 18 test fix
(cherry picked from commit 4ff03fdbfb)
* Update scripts/drone
* Add more commands
* Fix starlark link
* Copy .drone.star
* Add drone target branch for custom events
---------
This commit is contained in:
+48
-25
@@ -3,32 +3,55 @@
|
|||||||
# 2. Login to drone and export the env variables (token and server) shown here: https://drone.grafana.net/account
|
# 2. Login to drone and export the env variables (token and server) shown here: https://drone.grafana.net/account
|
||||||
# 3. Run `make drone`
|
# 3. Run `make drone`
|
||||||
# More information about this process here: https://github.com/grafana/deployment_tools/blob/master/docs/infrastructure/drone/signing.md
|
# More information about this process here: https://github.com/grafana/deployment_tools/blob/master/docs/infrastructure/drone/signing.md
|
||||||
|
"""
|
||||||
|
This module returns a Drone configuration including pipelines and secrets.
|
||||||
|
"""
|
||||||
|
|
||||||
load('scripts/drone/events/pr.star', 'pr_pipelines')
|
load("scripts/drone/events/pr.star", "pr_pipelines")
|
||||||
load('scripts/drone/events/main.star', 'main_pipelines')
|
load("scripts/drone/events/main.star", "main_pipelines")
|
||||||
load('scripts/drone/pipelines/docs.star', 'docs_pipelines')
|
load(
|
||||||
load('scripts/drone/events/release.star', 'release_pipelines', 'publish_artifacts_pipelines', 'publish_npm_pipelines', 'publish_packages_pipeline', 'artifacts_page_pipeline')
|
"scripts/drone/events/release.star",
|
||||||
load('scripts/drone/pipelines/publish_images.star', 'publish_image_pipelines_public', 'publish_image_pipelines_security')
|
"artifacts_page_pipeline",
|
||||||
load('scripts/drone/pipelines/github.star', 'publish_github_pipeline')
|
"enterprise2_pipelines",
|
||||||
load('scripts/drone/version.star', 'version_branch_pipelines')
|
"enterprise_pipelines",
|
||||||
load('scripts/drone/events/cron.star', 'cronjobs')
|
"oss_pipelines",
|
||||||
load('scripts/drone/vault.star', 'secrets')
|
"publish_artifacts_pipelines",
|
||||||
|
"publish_npm_pipelines",
|
||||||
|
"publish_packages_pipeline",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/pipelines/publish_images.star",
|
||||||
|
"publish_image_pipelines_public",
|
||||||
|
"publish_image_pipelines_security",
|
||||||
|
)
|
||||||
|
load("scripts/drone/pipelines/github.star", "publish_github_pipeline")
|
||||||
|
load("scripts/drone/pipelines/aws_marketplace.star", "publish_aws_marketplace_pipeline")
|
||||||
|
load("scripts/drone/version.star", "version_branch_pipelines")
|
||||||
|
load("scripts/drone/events/cron.star", "cronjobs")
|
||||||
|
load("scripts/drone/vault.star", "secrets")
|
||||||
|
|
||||||
edition = 'oss'
|
def main(_ctx):
|
||||||
|
|
||||||
def main(ctx):
|
|
||||||
return (
|
return (
|
||||||
pr_pipelines(edition=edition)
|
pr_pipelines() +
|
||||||
+ main_pipelines(edition=edition)
|
main_pipelines() +
|
||||||
+ release_pipelines()
|
oss_pipelines() +
|
||||||
+ publish_image_pipelines_public()
|
enterprise_pipelines() +
|
||||||
+ publish_image_pipelines_security()
|
enterprise2_pipelines() +
|
||||||
+ publish_artifacts_pipelines('security')
|
enterprise2_pipelines(
|
||||||
+ publish_artifacts_pipelines('public')
|
prefix = "custom-",
|
||||||
+ publish_npm_pipelines('public')
|
trigger = {"event": ["custom"]},
|
||||||
+ publish_packages_pipeline()
|
) +
|
||||||
+ artifacts_page_pipeline()
|
publish_image_pipelines_public() +
|
||||||
+ version_branch_pipelines()
|
publish_image_pipelines_security() +
|
||||||
+ cronjobs(edition=edition)
|
publish_github_pipeline("public") +
|
||||||
+ secrets()
|
publish_github_pipeline("security") +
|
||||||
|
publish_aws_marketplace_pipeline("public") +
|
||||||
|
publish_artifacts_pipelines("security") +
|
||||||
|
publish_artifacts_pipelines("public") +
|
||||||
|
publish_npm_pipelines() +
|
||||||
|
publish_packages_pipeline() +
|
||||||
|
artifacts_page_pipeline() +
|
||||||
|
version_branch_pipelines() +
|
||||||
|
cronjobs() +
|
||||||
|
secrets()
|
||||||
)
|
)
|
||||||
|
|||||||
+1521
-386
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -20,7 +20,7 @@ COPY emails emails
|
|||||||
ENV NODE_ENV production
|
ENV NODE_ENV production
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
FROM golang:1.19.4-alpine3.15 as go-builder
|
FROM golang:1.19.4-alpine3.17 as go-builder
|
||||||
|
|
||||||
RUN apk add --no-cache gcc g++ make
|
RUN apk add --no-cache gcc g++ make
|
||||||
|
|
||||||
|
|||||||
@@ -244,11 +244,13 @@ require (
|
|||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.4.0
|
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.4.0
|
||||||
github.com/Azure/azure-storage-blob-go v0.15.0
|
github.com/Azure/azure-storage-blob-go v0.15.0
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.20
|
github.com/Azure/go-autorest/autorest/adal v0.9.20
|
||||||
|
github.com/Masterminds/semver/v3 v3.1.1
|
||||||
github.com/armon/go-radix v1.0.0
|
github.com/armon/go-radix v1.0.0
|
||||||
github.com/blugelabs/bluge v0.1.9
|
github.com/blugelabs/bluge v0.1.9
|
||||||
github.com/blugelabs/bluge_segment_api v0.2.0
|
github.com/blugelabs/bluge_segment_api v0.2.0
|
||||||
github.com/bufbuild/connect-go v1.0.0
|
github.com/bufbuild/connect-go v1.0.0
|
||||||
github.com/dlmiddlecote/sqlstats v1.0.2
|
github.com/dlmiddlecote/sqlstats v1.0.2
|
||||||
|
github.com/docker/docker v20.10.16+incompatible
|
||||||
github.com/drone/drone-cli v1.6.1
|
github.com/drone/drone-cli v1.6.1
|
||||||
github.com/getkin/kin-openapi v0.103.0
|
github.com/getkin/kin-openapi v0.103.0
|
||||||
github.com/golang-migrate/migrate/v4 v4.7.0
|
github.com/golang-migrate/migrate/v4 v4.7.0
|
||||||
@@ -273,8 +275,11 @@ require (
|
|||||||
github.com/armon/go-metrics v0.3.10 // indirect
|
github.com/armon/go-metrics v0.3.10 // indirect
|
||||||
github.com/bmatcuk/doublestar v1.1.1 // indirect
|
github.com/bmatcuk/doublestar v1.1.1 // indirect
|
||||||
github.com/buildkite/yaml v2.1.0+incompatible // indirect
|
github.com/buildkite/yaml v2.1.0+incompatible // indirect
|
||||||
|
github.com/containerd/containerd v1.6.8 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||||
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
github.com/drone-runners/drone-runner-docker v1.8.2 // indirect
|
github.com/drone-runners/drone-runner-docker v1.8.2 // indirect
|
||||||
github.com/drone/drone-go v1.7.1 // indirect
|
github.com/drone/drone-go v1.7.1 // indirect
|
||||||
github.com/drone/envsubst v1.0.3 // indirect
|
github.com/drone/envsubst v1.0.3 // indirect
|
||||||
@@ -292,6 +297,8 @@ require (
|
|||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
github.com/mattn/go-ieproxy v0.0.3 // indirect
|
github.com/mattn/go-ieproxy v0.0.3 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/segmentio/asm v1.1.4 // indirect
|
github.com/segmentio/asm v1.1.4 // indirect
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9B
|
|||||||
github.com/Azure/go-amqp v0.16.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
|
github.com/Azure/go-amqp v0.16.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
|
||||||
github.com/Azure/go-amqp v0.16.4/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
|
github.com/Azure/go-amqp v0.16.4/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||||
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||||
@@ -237,6 +238,7 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go
|
|||||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
|
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||||
github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||||
github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM=
|
github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM=
|
||||||
@@ -575,6 +577,7 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT
|
|||||||
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||||
github.com/containerd/containerd v1.5.4/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw=
|
github.com/containerd/containerd v1.5.4/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw=
|
||||||
github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
|
github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
|
||||||
|
github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0=
|
||||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
@@ -747,6 +750,7 @@ github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc
|
|||||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
@@ -1920,6 +1924,7 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P
|
|||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||||
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
||||||
github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE=
|
github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE=
|
||||||
@@ -2008,6 +2013,7 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
|
|||||||
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
|
||||||
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
|
|||||||
@@ -2,7 +2,22 @@ package main
|
|||||||
|
|
||||||
import "github.com/urfave/cli/v2"
|
import "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
func ArgCountWrapper(max int, action cli.ActionFunc) cli.ActionFunc {
|
// ArgCountWrapper will cause the action to fail if there were not exactly `num` args provided.
|
||||||
|
func ArgCountWrapper(num int, action cli.ActionFunc) cli.ActionFunc {
|
||||||
|
return func(ctx *cli.Context) error {
|
||||||
|
if ctx.NArg() != num {
|
||||||
|
if err := cli.ShowSubcommandHelp(ctx); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return action(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArgCountWrapper will cause the action to fail if there were more than `num` args provided.
|
||||||
|
func MaxArgCountWrapper(max int, action cli.ActionFunc) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
if ctx.NArg() > max {
|
if ctx.NArg() > max {
|
||||||
if err := cli.ShowSubcommandHelp(ctx); err != nil {
|
if err := cli.ShowSubcommandHelp(ctx); err != nil {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func BuildBackend(ctx *cli.Context) error {
|
func BuildBackend(ctx *cli.Context) error {
|
||||||
metadata, err := GenerateMetadata(ctx)
|
metadata, err := config.GenerateMetadata(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func BuildDocker(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
"github.com/grafana/grafana/pkg/build/errutil"
|
"github.com/grafana/grafana/pkg/build/errutil"
|
||||||
"github.com/grafana/grafana/pkg/build/frontend"
|
"github.com/grafana/grafana/pkg/build/frontend"
|
||||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||||
@@ -10,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func BuildFrontend(c *cli.Context) error {
|
func BuildFrontend(c *cli.Context) error {
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func BuildInternalPlugins(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const grafanaDir = "."
|
const grafanaDir = "."
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/env"
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// checkOpts are options used to create a new GitHub check for the enterprise downstream test.
|
||||||
|
type checkOpts struct {
|
||||||
|
SHA string
|
||||||
|
URL string
|
||||||
|
Branch string
|
||||||
|
PR int
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCheckOpts(args []string) (*checkOpts, error) {
|
||||||
|
branch, ok := env.Lookup("DRONE_SOURCE_BRANCH", args)
|
||||||
|
if !ok {
|
||||||
|
return nil, cli.Exit("Unable to retrieve build source branch", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
rgx = git.PRCheckRegexp()
|
||||||
|
matches = rgx.FindStringSubmatch(branch)
|
||||||
|
)
|
||||||
|
|
||||||
|
sha, ok := env.Lookup("SOURCE_COMMIT", args)
|
||||||
|
if !ok {
|
||||||
|
if matches == nil || len(matches) <= 1 {
|
||||||
|
return nil, cli.Exit("Unable to retrieve source commit", 1)
|
||||||
|
}
|
||||||
|
sha = matches[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
url, ok := env.Lookup("DRONE_BUILD_LINK", args)
|
||||||
|
if !ok {
|
||||||
|
return nil, cli.Exit(`missing environment variable "DRONE_BUILD_LINK"`, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
prStr, ok := env.Lookup("OSS_PULL_REQUEST", args)
|
||||||
|
if !ok {
|
||||||
|
if matches == nil || len(matches) <= 1 {
|
||||||
|
return nil, cli.Exit("Unable to retrieve PR number", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
prStr = matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
pr, err := strconv.Atoi(prStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &checkOpts{
|
||||||
|
Branch: branch,
|
||||||
|
PR: pr,
|
||||||
|
SHA: sha,
|
||||||
|
URL: url,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnterpriseCheckBegin creates the GitHub check and signals the beginning of the downstream build / test process
|
||||||
|
func EnterpriseCheckBegin(c *cli.Context) error {
|
||||||
|
var (
|
||||||
|
ctx = c.Context
|
||||||
|
client = git.NewGitHubClient(ctx, c.String("github-token"))
|
||||||
|
)
|
||||||
|
|
||||||
|
opts, err := getCheckOpts(os.Environ())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = git.CreateEnterpriseStatus(ctx, client.Repositories, opts.SHA, opts.URL, "pending"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EnterpriseCheckSuccess(c *cli.Context) error {
|
||||||
|
return completeEnterpriseCheck(c, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EnterpriseCheckFail(c *cli.Context) error {
|
||||||
|
return completeEnterpriseCheck(c, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func completeEnterpriseCheck(c *cli.Context, success bool) error {
|
||||||
|
var (
|
||||||
|
ctx = c.Context
|
||||||
|
client = git.NewGitHubClient(ctx, c.String("github-token"))
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update the pull request labels
|
||||||
|
opts, err := getCheckOpts(os.Environ())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
status := "failure"
|
||||||
|
if success {
|
||||||
|
status = "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the GitHub check...
|
||||||
|
if _, err := git.CreateEnterpriseStatus(ctx, client.Repositories, opts.SHA, opts.URL, status); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete branch if needed
|
||||||
|
log.Printf("Checking branch '%s' against '%s'", git.PRCheckRegexp().String(), opts.Branch)
|
||||||
|
if git.PRCheckRegexp().MatchString(opts.Branch) {
|
||||||
|
log.Println("Deleting branch", opts.Branch)
|
||||||
|
if err := git.DeleteEnterpriseBranch(ctx, client.Git, opts.Branch); err != nil {
|
||||||
|
return fmt.Errorf("error deleting enterprise branch: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label := "enterprise-failed"
|
||||||
|
if success {
|
||||||
|
label = "enterprise-ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
return git.AddLabelToPR(ctx, client.Issues, opts.PR, label)
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetCheckOpts(t *testing.T) {
|
||||||
|
t.Run("it should return the checkOpts if the correct environment variables are set", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"SOURCE_COMMIT=1234",
|
||||||
|
"DRONE_SOURCE_BRANCH=test",
|
||||||
|
"DRONE_BUILD_LINK=http://example.com",
|
||||||
|
"OSS_PULL_REQUEST=1",
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getCheckOpts(args)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, opts.SHA, "1234")
|
||||||
|
require.Equal(t, opts.URL, "http://example.com")
|
||||||
|
})
|
||||||
|
t.Run("it should return an error if SOURCE_COMMIT is not set", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"DRONE_BUILD_LINK=http://example.com",
|
||||||
|
"DRONE_SOURCE_BRANCH=test",
|
||||||
|
"DRONE_BUILD_LINK=http://example.com",
|
||||||
|
"OSS_PULL_REQUEST=1",
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getCheckOpts(args)
|
||||||
|
require.Nil(t, opts)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
t.Run("it should return an error if DRONE_BUILD_LINK is not set", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"SOURCE_COMMIT=1234",
|
||||||
|
"DRONE_SOURCE_BRANCH=test",
|
||||||
|
"OSS_PULL_REQUEST=1",
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getCheckOpts(args)
|
||||||
|
require.Nil(t, opts)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
t.Run("it should return an error if OSS_PULL_REQUEST is not set", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"SOURCE_COMMIT=1234",
|
||||||
|
"DRONE_SOURCE_BRANCH=test",
|
||||||
|
"DRONE_BUILD_LINK=http://example.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getCheckOpts(args)
|
||||||
|
require.Nil(t, opts)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
t.Run("it should return an error if OSS_PULL_REQUEST is not an integer", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"SOURCE_COMMIT=1234",
|
||||||
|
"DRONE_SOURCE_BRANCH=test",
|
||||||
|
"DRONE_BUILD_LINK=http://example.com",
|
||||||
|
"OSS_PULL_REQUEST=http://example.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getCheckOpts(args)
|
||||||
|
require.Nil(t, opts)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -4,11 +4,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExportVersion(c *cli.Context) error {
|
func ExportVersion(c *cli.Context) error {
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ const (
|
|||||||
func FetchImages(c *cli.Context) error {
|
func FetchImages(c *cli.Context) error {
|
||||||
if c.NArg() > 0 {
|
if c.NArg() > 0 {
|
||||||
if err := cli.ShowSubcommandHelp(c); err != nil {
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
return cli.NewExitError(err.Error(), 1)
|
return cli.Exit(err.Error(), 1)
|
||||||
}
|
}
|
||||||
return cli.NewExitError("", 1)
|
return cli.Exit("", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,4 +46,14 @@ var (
|
|||||||
Usage: "Google Cloud Platform key file",
|
Usage: "Google Cloud Platform key file",
|
||||||
Required: true,
|
Required: true,
|
||||||
}
|
}
|
||||||
|
gitHubTokenFlag = cli.StringFlag{
|
||||||
|
Name: "github-token",
|
||||||
|
Value: "",
|
||||||
|
EnvVars: []string{"GITHUB_TOKEN"},
|
||||||
|
Usage: "GitHub token",
|
||||||
|
}
|
||||||
|
tagFlag = cli.StringFlag{
|
||||||
|
Name: "tag",
|
||||||
|
Usage: "Grafana version tag",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/config"
|
|
||||||
"github.com/grafana/grafana/pkg/build/droneutil"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GenerateMetadata(c *cli.Context) (config.Metadata, error) {
|
|
||||||
var metadata config.Metadata
|
|
||||||
version := ""
|
|
||||||
|
|
||||||
event, err := droneutil.GetDroneEventFromEnv()
|
|
||||||
if err != nil {
|
|
||||||
return config.Metadata{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var releaseMode config.ReleaseMode
|
|
||||||
switch event {
|
|
||||||
case string(config.PullRequestMode):
|
|
||||||
releaseMode = config.ReleaseMode{Mode: config.PullRequestMode}
|
|
||||||
case config.Push:
|
|
||||||
mode, err := config.CheckDroneTargetBranch()
|
|
||||||
if err != nil {
|
|
||||||
return config.Metadata{}, err
|
|
||||||
}
|
|
||||||
releaseMode = config.ReleaseMode{Mode: mode}
|
|
||||||
case config.Custom:
|
|
||||||
mode, err := config.CheckDroneTargetBranch()
|
|
||||||
if err != nil {
|
|
||||||
return config.Metadata{}, err
|
|
||||||
}
|
|
||||||
// if there is a custom event targeting the main branch, that's an enterprise downstream build
|
|
||||||
if mode == config.MainBranch {
|
|
||||||
releaseMode = config.ReleaseMode{Mode: config.CustomMode}
|
|
||||||
} else {
|
|
||||||
releaseMode = config.ReleaseMode{Mode: mode}
|
|
||||||
}
|
|
||||||
case config.Tag, config.Promote:
|
|
||||||
tag, ok := os.LookupEnv("DRONE_TAG")
|
|
||||||
if !ok || tag == "" {
|
|
||||||
return config.Metadata{}, err
|
|
||||||
}
|
|
||||||
version = strings.TrimPrefix(tag, "v")
|
|
||||||
mode, err := config.CheckSemverSuffix()
|
|
||||||
if err != nil {
|
|
||||||
return config.Metadata{}, err
|
|
||||||
}
|
|
||||||
releaseMode = mode
|
|
||||||
case config.Cronjob:
|
|
||||||
releaseMode = config.ReleaseMode{Mode: config.CronjobMode}
|
|
||||||
}
|
|
||||||
|
|
||||||
if version == "" {
|
|
||||||
version, err = generateVersionFromBuildID()
|
|
||||||
if err != nil {
|
|
||||||
return config.Metadata{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentCommit, err := config.GetDroneCommit()
|
|
||||||
if err != nil {
|
|
||||||
return config.Metadata{}, err
|
|
||||||
}
|
|
||||||
metadata = config.Metadata{
|
|
||||||
GrafanaVersion: version,
|
|
||||||
ReleaseMode: releaseMode,
|
|
||||||
GrabplVersion: c.App.Version,
|
|
||||||
CurrentCommit: currentCommit,
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("building Grafana version: %s, release mode: %+v", metadata.GrafanaVersion, metadata.ReleaseMode)
|
|
||||||
|
|
||||||
return metadata, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateVersionFromBuildID() (string, error) {
|
|
||||||
buildID, ok := os.LookupEnv("DRONE_BUILD_NUMBER")
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("unable to get DRONE_BUILD_NUMBER environmental variable")
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
version, err := config.GetGrafanaVersion(buildID, ".")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return version, nil
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/config"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
DroneBuildEvent = "DRONE_BUILD_EVENT"
|
|
||||||
DroneTargetBranch = "DRONE_TARGET_BRANCH"
|
|
||||||
DroneTag = "DRONE_TAG"
|
|
||||||
DroneSemverPrerelease = "DRONE_SEMVER_PRERELEASE"
|
|
||||||
DroneBuildNumber = "DRONE_BUILD_NUMBER"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
hashedGrafanaVersion = "9.2.0-12345pre"
|
|
||||||
versionedBranch = "v9.2.x"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetMetadata(t *testing.T) {
|
|
||||||
tcs := []struct {
|
|
||||||
envMap map[string]string
|
|
||||||
expVersion string
|
|
||||||
mode config.ReleaseMode
|
|
||||||
}{
|
|
||||||
{map[string]string{DroneBuildEvent: config.PullRequest, DroneTargetBranch: "", DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, config.ReleaseMode{Mode: config.PullRequestMode}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Push, DroneTargetBranch: versionedBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, config.ReleaseMode{Mode: config.ReleaseBranchMode}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Push, DroneTargetBranch: config.MainBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, config.ReleaseMode{Mode: config.MainMode}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Custom, DroneTargetBranch: versionedBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, config.ReleaseMode{Mode: config.ReleaseBranchMode}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Custom, DroneTargetBranch: config.MainBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, config.ReleaseMode{Mode: config.Custom}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Tag, DroneTargetBranch: "", DroneTag: "v9.2.0", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, "9.2.0", config.ReleaseMode{Mode: config.TagMode, IsBeta: false, IsTest: false}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Tag, DroneTargetBranch: "", DroneTag: "v9.2.0-beta", DroneSemverPrerelease: "beta", DroneBuildNumber: "12345"}, "9.2.0-beta", config.ReleaseMode{Mode: config.TagMode, IsBeta: true, IsTest: false}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Tag, DroneTargetBranch: "", DroneTag: "v9.2.0-test", DroneSemverPrerelease: "test", DroneBuildNumber: "12345"}, "9.2.0-test", config.ReleaseMode{Mode: config.TagMode, IsBeta: false, IsTest: true}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Promote, DroneTargetBranch: "", DroneTag: "v9.2.0", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, "9.2.0", config.ReleaseMode{Mode: config.TagMode, IsBeta: false, IsTest: false}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Promote, DroneTargetBranch: "", DroneTag: "v9.2.0-beta", DroneSemverPrerelease: "beta", DroneBuildNumber: "12345"}, "9.2.0-beta", config.ReleaseMode{Mode: config.TagMode, IsBeta: true, IsTest: false}},
|
|
||||||
{map[string]string{DroneBuildEvent: config.Promote, DroneTargetBranch: "", DroneTag: "v9.2.0-test", DroneSemverPrerelease: "test", DroneBuildNumber: "12345"}, "9.2.0-test", config.ReleaseMode{Mode: config.TagMode, IsBeta: false, IsTest: true}},
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := cli.NewContext(cli.NewApp(), &flag.FlagSet{}, nil)
|
|
||||||
for _, tc := range tcs {
|
|
||||||
t.Run("Should return valid metadata, ", func(t *testing.T) {
|
|
||||||
setUpEnv(t, tc.envMap)
|
|
||||||
testMetadata(t, ctx, tc.expVersion, tc.mode)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testMetadata(t *testing.T, ctx *cli.Context, version string, releaseMode config.ReleaseMode) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
metadata, err := GenerateMetadata(ctx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
t.Run("with a valid version", func(t *testing.T) {
|
|
||||||
expVersion := metadata.GrafanaVersion
|
|
||||||
require.Equal(t, expVersion, version)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("with a valid release mode from the built-in list", func(t *testing.T) {
|
|
||||||
expMode := metadata.ReleaseMode
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, expMode, releaseMode)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUpEnv(t *testing.T, envMap map[string]string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
os.Clearenv()
|
|
||||||
err := os.Setenv("DRONE_COMMIT", "abcd12345")
|
|
||||||
require.NoError(t, err)
|
|
||||||
for k, v := range envMap {
|
|
||||||
err := os.Setenv(k, v)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,11 +15,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/config"
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
"github.com/grafana/grafana/pkg/build/gcloud"
|
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||||
"github.com/grafana/grafana/pkg/build/gcloud/storage"
|
"github.com/grafana/grafana/pkg/build/gcloud/storage"
|
||||||
"github.com/grafana/grafana/pkg/build/packaging"
|
"github.com/grafana/grafana/pkg/build/packaging"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const grafanaAPI = "https://grafana.com/api"
|
const grafanaAPI = "https://grafana.com/api"
|
||||||
@@ -33,7 +34,7 @@ func GrafanaCom(c *cli.Context) error {
|
|||||||
return fmt.Errorf("couldn't activate service account, err: %w", err)
|
return fmt.Errorf("couldn't activate service account, err: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -66,11 +67,11 @@ func GrafanaCom(c *cli.Context) error {
|
|||||||
|
|
||||||
grafanaAPIKey := strings.TrimSpace(os.Getenv("GRAFANA_COM_API_KEY"))
|
grafanaAPIKey := strings.TrimSpace(os.Getenv("GRAFANA_COM_API_KEY"))
|
||||||
if grafanaAPIKey == "" {
|
if grafanaAPIKey == "" {
|
||||||
return cli.NewExitError("the environment variable GRAFANA_COM_API_KEY must be set", 1)
|
return cli.Exit("the environment variable GRAFANA_COM_API_KEY must be set", 1)
|
||||||
}
|
}
|
||||||
whatsNewURL, releaseNotesURL, err := getReleaseURLs()
|
whatsNewURL, releaseNotesURL, err := getReleaseURLs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err.Error(), 1)
|
return cli.Exit(err.Error(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Verify config values
|
// TODO: Verify config values
|
||||||
@@ -89,7 +90,7 @@ func GrafanaCom(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := publishPackages(cfg); err != nil {
|
if err := publishPackages(cfg); err != nil {
|
||||||
return cli.NewExitError(err.Error(), 1)
|
return cli.Exit(err.Error(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Successfully published packages to grafana.com!")
|
log.Println("Successfully published packages to grafana.com!")
|
||||||
@@ -146,7 +147,7 @@ func publishPackages(cfg packaging.PublishConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch cfg.ReleaseMode.Mode {
|
switch cfg.ReleaseMode.Mode {
|
||||||
case config.MainMode, config.CustomMode, config.CronjobMode:
|
case config.MainMode, config.DownstreamMode, config.CronjobMode:
|
||||||
pth = path.Join(pth, packaging.MainFolder)
|
pth = path.Join(pth, packaging.MainFolder)
|
||||||
default:
|
default:
|
||||||
pth = path.Join(pth, packaging.ReleaseFolder)
|
pth = path.Join(pth, packaging.ReleaseFolder)
|
||||||
@@ -177,7 +178,7 @@ func publishPackages(cfg packaging.PublishConfig) error {
|
|||||||
Version: cfg.Version,
|
Version: cfg.Version,
|
||||||
ReleaseDate: time.Now().UTC(),
|
ReleaseDate: time.Now().UTC(),
|
||||||
Builds: builds,
|
Builds: builds,
|
||||||
Stable: cfg.ReleaseMode.Mode == config.TagMode,
|
Stable: cfg.ReleaseMode.Mode == config.TagMode && !cfg.ReleaseMode.IsBeta && !cfg.ReleaseMode.IsTest,
|
||||||
Beta: cfg.ReleaseMode.IsBeta,
|
Beta: cfg.ReleaseMode.IsBeta,
|
||||||
Nightly: cfg.ReleaseMode.Mode == config.CronjobMode,
|
Nightly: cfg.ReleaseMode.Mode == config.CronjobMode,
|
||||||
}
|
}
|
||||||
|
|||||||
+206
-11
@@ -5,10 +5,18 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/docker"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var additionalCommands []*cli.Command = make([]*cli.Command, 0, 5)
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
|
func registerAppCommand(c *cli.Command) {
|
||||||
|
additionalCommands = append(additionalCommands, c)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Commands = cli.Commands{
|
app.Commands = cli.Commands{
|
||||||
@@ -16,7 +24,7 @@ func main() {
|
|||||||
Name: "build-backend",
|
Name: "build-backend",
|
||||||
Usage: "Build one or more variants of back-end binaries",
|
Usage: "Build one or more variants of back-end binaries",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, BuildBackend),
|
Action: MaxArgCountWrapper(1, BuildBackend),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&variantsFlag,
|
&variantsFlag,
|
||||||
@@ -67,7 +75,7 @@ func main() {
|
|||||||
Name: "build-frontend",
|
Name: "build-frontend",
|
||||||
Usage: "Build front-end artifacts",
|
Usage: "Build front-end artifacts",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, BuildFrontend),
|
Action: MaxArgCountWrapper(1, BuildFrontend),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
@@ -77,7 +85,7 @@ func main() {
|
|||||||
{
|
{
|
||||||
Name: "build-docker",
|
Name: "build-docker",
|
||||||
Usage: "Build Grafana Docker images",
|
Usage: "Build Grafana Docker images",
|
||||||
Action: ArgCountWrapper(1, BuildDocker),
|
Action: MaxArgCountWrapper(1, BuildDocker),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
@@ -96,6 +104,14 @@ func main() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "upload-cdn",
|
||||||
|
Usage: "Upload public/* to a cdn bucket",
|
||||||
|
Action: UploadCDN,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&editionFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "shellcheck",
|
Name: "shellcheck",
|
||||||
Usage: "Run shellcheck on shell scripts",
|
Usage: "Run shellcheck on shell scripts",
|
||||||
@@ -104,7 +120,7 @@ func main() {
|
|||||||
{
|
{
|
||||||
Name: "build-plugins",
|
Name: "build-plugins",
|
||||||
Usage: "Build internal plug-ins",
|
Usage: "Build internal plug-ins",
|
||||||
Action: ArgCountWrapper(1, BuildInternalPlugins),
|
Action: MaxArgCountWrapper(1, BuildInternalPlugins),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
@@ -117,13 +133,19 @@ func main() {
|
|||||||
Name: "publish-metrics",
|
Name: "publish-metrics",
|
||||||
Usage: "Publish a set of metrics from stdin",
|
Usage: "Publish a set of metrics from stdin",
|
||||||
ArgsUsage: "<api-key>",
|
ArgsUsage: "<api-key>",
|
||||||
Action: ArgCountWrapper(1, PublishMetrics),
|
Action: MaxArgCountWrapper(1, PublishMetrics),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "verify-drone",
|
Name: "verify-drone",
|
||||||
Usage: "Verify Drone configuration",
|
Usage: "Verify Drone configuration",
|
||||||
Action: VerifyDrone,
|
Action: VerifyDrone,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "verify-starlark",
|
||||||
|
Usage: "Verify Starlark configuration",
|
||||||
|
ArgsUsage: "<workspace path>",
|
||||||
|
Action: VerifyStarlark,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "export-version",
|
Name: "export-version",
|
||||||
Usage: "Exports version in dist/grafana.version",
|
Usage: "Exports version in dist/grafana.version",
|
||||||
@@ -133,7 +155,7 @@ func main() {
|
|||||||
Name: "package",
|
Name: "package",
|
||||||
Usage: "Package one or more Grafana variants",
|
Usage: "Package one or more Grafana variants",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, Package),
|
Action: MaxArgCountWrapper(1, Package),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&jobsFlag,
|
&jobsFlag,
|
||||||
&variantsFlag,
|
&variantsFlag,
|
||||||
@@ -144,7 +166,7 @@ func main() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "store-storybook",
|
Name: "store-storybook",
|
||||||
Usage: "Integrity check for storybook build",
|
Usage: "Stores storybook to GCS buckets",
|
||||||
Action: StoreStorybook,
|
Action: StoreStorybook,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@@ -153,10 +175,81 @@ func main() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "verify-storybook",
|
||||||
|
Usage: "Integrity check for storybook build",
|
||||||
|
Action: VerifyStorybook,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "upload-packages",
|
||||||
|
Usage: "Upload Grafana packages",
|
||||||
|
Action: UploadPackages,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&jobsFlag,
|
||||||
|
&editionFlag,
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "enterprise2",
|
||||||
|
Usage: "Declare if the edition is enterprise2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "artifacts",
|
Name: "artifacts",
|
||||||
Usage: "Handle Grafana artifacts",
|
Usage: "Handle Grafana artifacts",
|
||||||
Subcommands: cli.Commands{
|
Subcommands: cli.Commands{
|
||||||
|
{
|
||||||
|
Name: "publish",
|
||||||
|
Usage: "Publish Grafana artifacts",
|
||||||
|
Action: PublishArtifactsAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&editionFlag,
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "security",
|
||||||
|
Usage: "Security release",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "security-dest-bucket",
|
||||||
|
Usage: "Google Cloud Storage bucket for security packages (or $SECURITY_DEST_BUCKET)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "tag",
|
||||||
|
Usage: "Grafana version tag",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "src-bucket",
|
||||||
|
Value: "grafana-prerelease",
|
||||||
|
Usage: "Google Cloud Storage bucket",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "dest-bucket",
|
||||||
|
Value: "grafana-downloads",
|
||||||
|
Usage: "Google Cloud Storage bucket for published packages",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "enterprise2-dest-bucket",
|
||||||
|
Value: "grafana-downloads-enterprise2",
|
||||||
|
Usage: "Google Cloud Storage bucket for published packages",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "enterprise2-security-prefix",
|
||||||
|
Usage: "Bucket path prefix for enterprise2 security releases (or $ENTERPRISE2_SECURITY_PREFIX)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "static-assets-bucket",
|
||||||
|
Value: "grafana-static-assets",
|
||||||
|
Usage: "Google Cloud Storage bucket for static assets",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "static-asset-editions",
|
||||||
|
Usage: "All the editions of the static assets (or $STATIC_ASSET_EDITIONS)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "storybook-bucket",
|
||||||
|
Value: "grafana-storybook",
|
||||||
|
Usage: "Google Cloud Storage bucket for storybooks",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "docker",
|
Name: "docker",
|
||||||
Usage: "Handle Grafana Docker images",
|
Usage: "Handle Grafana Docker images",
|
||||||
@@ -165,11 +258,54 @@ func main() {
|
|||||||
Name: "fetch",
|
Name: "fetch",
|
||||||
Usage: "Fetch Grafana Docker images",
|
Usage: "Fetch Grafana Docker images",
|
||||||
ArgsUsage: "[version]",
|
ArgsUsage: "[version]",
|
||||||
Action: ArgCountWrapper(1, FetchImages),
|
Action: MaxArgCountWrapper(1, FetchImages),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&editionFlag,
|
&editionFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "publish-enterprise2",
|
||||||
|
Usage: "Handle Grafana Enterprise2 Docker images",
|
||||||
|
ArgsUsage: "[version]",
|
||||||
|
Action: Enterprise2,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "dockerhub-repo",
|
||||||
|
Usage: "DockerHub repo to push images",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "npm",
|
||||||
|
Usage: "Handle Grafana npm packages",
|
||||||
|
Subcommands: cli.Commands{
|
||||||
|
{
|
||||||
|
Name: "release",
|
||||||
|
Usage: "Release npm packages",
|
||||||
|
ArgsUsage: "[version]",
|
||||||
|
Action: NpmReleaseAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&tagFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "store",
|
||||||
|
Usage: "Store npm packages tarball",
|
||||||
|
Action: NpmStoreAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&tagFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "retrieve",
|
||||||
|
Usage: "Retrieve npm packages tarball",
|
||||||
|
Action: NpmRetrieveAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&tagFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -196,7 +332,7 @@ func main() {
|
|||||||
{
|
{
|
||||||
Name: "github",
|
Name: "github",
|
||||||
Usage: "Publish packages to GitHub releases",
|
Usage: "Publish packages to GitHub releases",
|
||||||
Action: PublishGitHub,
|
Action: PublishGithub,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&dryRunFlag,
|
&dryRunFlag,
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@@ -210,7 +346,7 @@ func main() {
|
|||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "tag",
|
Name: "tag",
|
||||||
Usage: "Release tag (default from metadata)ß",
|
Usage: "Release tag (default from metadata)",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "create",
|
Name: "create",
|
||||||
@@ -218,10 +354,69 @@ func main() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "aws",
|
||||||
|
Usage: "Publish image to AWS Marketplace releases",
|
||||||
|
Action: PublishAwsMarketplace,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&dryRunFlag,
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "version",
|
||||||
|
Usage: "Release version (default from metadata)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "image",
|
||||||
|
Required: true,
|
||||||
|
Usage: "Name of the image to be released",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "repo",
|
||||||
|
Required: true,
|
||||||
|
Usage: "AWS Marketplace ECR repository",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "product",
|
||||||
|
Required: true,
|
||||||
|
Usage: "AWS Marketplace product identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "enterprise-check",
|
||||||
|
Usage: "Commands for testing against Grafana Enterprise",
|
||||||
|
Subcommands: cli.Commands{
|
||||||
|
{
|
||||||
|
Name: "begin",
|
||||||
|
Usage: "Creates the GitHub check in a pull request and begins the tests",
|
||||||
|
Action: EnterpriseCheckBegin,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&gitHubTokenFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "success",
|
||||||
|
Usage: "Updates the GitHub check in a pull request to show a successful build and updates the pull request labels",
|
||||||
|
Action: EnterpriseCheckSuccess,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&gitHubTokenFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "fail",
|
||||||
|
Usage: "Updates the GitHub check in a pull request to show a failed build and updates the pull request labels",
|
||||||
|
Action: EnterpriseCheckFail,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&gitHubTokenFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.Commands = append(app.Commands, additionalCommands...)
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/npm"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NpmRetrieveAction(c *cli.Context) error {
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := c.String("tag")
|
||||||
|
if tag == "" {
|
||||||
|
return fmt.Errorf("no tag version specified, exitting")
|
||||||
|
}
|
||||||
|
|
||||||
|
prereleaseBucket := strings.TrimSpace(os.Getenv("PRERELEASE_BUCKET"))
|
||||||
|
if prereleaseBucket == "" {
|
||||||
|
return cli.Exit("the environment variable PRERELEASE_BUCKET must be set", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := npm.FetchNpmPackages(c.Context, tag, prereleaseBucket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NpmStoreAction(c *cli.Context) error {
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := c.String("tag")
|
||||||
|
if tag == "" {
|
||||||
|
return fmt.Errorf("no tag version specified, exiting")
|
||||||
|
}
|
||||||
|
|
||||||
|
prereleaseBucket := strings.TrimSpace(os.Getenv("PRERELEASE_BUCKET"))
|
||||||
|
if prereleaseBucket == "" {
|
||||||
|
return cli.Exit("the environment variable PRERELEASE_BUCKET must be set", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := npm.StoreNpmPackages(c.Context, tag, prereleaseBucket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NpmReleaseAction(c *cli.Context) error {
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := c.String("tag")
|
||||||
|
if tag == "" {
|
||||||
|
return fmt.Errorf("no tag version specified, exitting")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("git", "checkout", ".")
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Println("command failed to run, err: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := npm.PublishNpmPackages(c.Context, tag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Package(c *cli.Context) error {
|
func Package(c *cli.Context) error {
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -22,12 +22,12 @@ func Package(c *cli.Context) error {
|
|||||||
|
|
||||||
releaseMode, err := metadata.GetReleaseMode()
|
releaseMode, err := metadata.GetReleaseMode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err.Error(), 1)
|
return cli.Exit(err.Error(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseModeConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
releaseModeConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err.Error(), 1)
|
return cli.Exit(err.Error(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.Config{
|
cfg := config.Config{
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||||
|
"github.com/grafana/grafana/pkg/build/versions"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type publishConfig struct {
|
||||||
|
tag string
|
||||||
|
srcBucket string
|
||||||
|
destBucket string
|
||||||
|
enterprise2DestBucket string
|
||||||
|
enterprise2SecurityPrefix string
|
||||||
|
staticAssetsBucket string
|
||||||
|
staticAssetEditions []string
|
||||||
|
storybookBucket string
|
||||||
|
security bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// requireListWithEnvFallback first checks the CLI for a flag with the required
|
||||||
|
// name. If this is empty, it falls back to taking the environment variable.
|
||||||
|
// Sadly, we cannot use cli.Flag.EnvVars for this due to it potentially leaking
|
||||||
|
// environment variables as default values in usage-errors.
|
||||||
|
func requireListWithEnvFallback(cctx *cli.Context, name string, envName string) ([]string, error) {
|
||||||
|
result := cctx.StringSlice(name)
|
||||||
|
if len(result) == 0 {
|
||||||
|
for _, v := range strings.Split(os.Getenv(envName), ",") {
|
||||||
|
value := strings.TrimSpace(v)
|
||||||
|
if value != "" {
|
||||||
|
result = append(result, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(result) == 0 {
|
||||||
|
return nil, cli.Exit(fmt.Sprintf("Required flag (%s) or environment variable (%s) not set", name, envName), 1)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireStringWithEnvFallback(cctx *cli.Context, name string, envName string) (string, error) {
|
||||||
|
result := cctx.String(name)
|
||||||
|
if result == "" {
|
||||||
|
result = os.Getenv(envName)
|
||||||
|
}
|
||||||
|
if result == "" {
|
||||||
|
return "", cli.Exit(fmt.Sprintf("Required flag (%s) or environment variable (%s) not set", name, envName), 1)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action implements the sub-command "publish-artifacts".
|
||||||
|
func PublishArtifactsAction(c *cli.Context) error {
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
staticAssetEditions, err := requireListWithEnvFallback(c, "static-asset-editions", "STATIC_ASSET_EDITIONS")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
securityDestBucket, err := requireStringWithEnvFallback(c, "security-dest-bucket", "SECURITY_DEST_BUCKET")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
enterprise2SecurityPrefix, err := requireStringWithEnvFallback(c, "enterprise2-security-prefix", "ENTERPRISE2_SECURITY_PREFIX")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gcloud.ActivateServiceAccount(); err != nil {
|
||||||
|
return fmt.Errorf("error connecting to gcp, %q", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := publishConfig{
|
||||||
|
srcBucket: c.String("src-bucket"),
|
||||||
|
destBucket: c.String("dest-bucket"),
|
||||||
|
enterprise2DestBucket: c.String("enterprise2-dest-bucket"),
|
||||||
|
enterprise2SecurityPrefix: enterprise2SecurityPrefix,
|
||||||
|
staticAssetsBucket: c.String("static-assets-bucket"),
|
||||||
|
staticAssetEditions: staticAssetEditions,
|
||||||
|
storybookBucket: c.String("storybook-bucket"),
|
||||||
|
security: c.Bool("security"),
|
||||||
|
tag: strings.TrimPrefix(c.String("tag"), "v"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.security {
|
||||||
|
cfg.destBucket = securityDestBucket
|
||||||
|
}
|
||||||
|
|
||||||
|
err = copyStaticAssets(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = copyStorybook(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = copyDownloads(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = copyEnterprise2Downloads(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyStaticAssets(cfg publishConfig) error {
|
||||||
|
for _, edition := range cfg.staticAssetEditions {
|
||||||
|
log.Printf("Copying static assets for %s", edition)
|
||||||
|
srcURL := fmt.Sprintf("%s/artifacts/static-assets/%s/%s/*", cfg.srcBucket, edition, cfg.tag)
|
||||||
|
destURL := fmt.Sprintf("%s/%s/%s/", cfg.staticAssetsBucket, edition, cfg.tag)
|
||||||
|
err := gcsCopy("static assets", srcURL, destURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error copying static assets, %q", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("Successfully copied static assets!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyStorybook(cfg publishConfig) error {
|
||||||
|
if cfg.security {
|
||||||
|
log.Printf("skipping storybook copy - not needed for a security release")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Printf("Copying storybooks...")
|
||||||
|
srcURL := fmt.Sprintf("%s/artifacts/storybook/v%s/*", cfg.srcBucket, cfg.tag)
|
||||||
|
destURL := fmt.Sprintf("%s/%s", cfg.storybookBucket, cfg.tag)
|
||||||
|
err := gcsCopy("storybook", srcURL, destURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error copying storybook. %q", err)
|
||||||
|
}
|
||||||
|
stableVersion, err := versions.GetLatestVersion(versions.LatestStableVersionURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
isLatest, err := versions.IsGreaterThanOrEqual(cfg.tag, stableVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if isLatest {
|
||||||
|
log.Printf("Copying storybooks to latest...")
|
||||||
|
srcURL := fmt.Sprintf("%s/artifacts/storybook/v%s/*", cfg.srcBucket, cfg.tag)
|
||||||
|
destURL := fmt.Sprintf("%s/latest", cfg.storybookBucket)
|
||||||
|
err := gcsCopy("storybook (latest)", srcURL, destURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error copying storybook to latest. %q", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Successfully copied storybook!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyDownloads(cfg publishConfig) error {
|
||||||
|
for _, edition := range []string{
|
||||||
|
"oss", "enterprise",
|
||||||
|
} {
|
||||||
|
destURL := fmt.Sprintf("%s/%s/", cfg.destBucket, edition)
|
||||||
|
srcURL := fmt.Sprintf("%s/artifacts/downloads/v%s/%s/release/*", cfg.srcBucket, cfg.tag, edition)
|
||||||
|
if !cfg.security {
|
||||||
|
destURL = filepath.Join(destURL, "release")
|
||||||
|
}
|
||||||
|
log.Printf("Copying downloads for %s, from %s bucket to %s bucket", edition, srcURL, destURL)
|
||||||
|
err := gcsCopy("downloads", srcURL, destURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error copying downloads, %q", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("Successfully copied downloads.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyEnterprise2Downloads(cfg publishConfig) error {
|
||||||
|
var prefix string
|
||||||
|
if cfg.security {
|
||||||
|
prefix = cfg.enterprise2SecurityPrefix
|
||||||
|
}
|
||||||
|
srcURL := fmt.Sprintf("%s/artifacts/downloads-enterprise2/v%s/enterprise2/release/*", cfg.srcBucket, cfg.tag)
|
||||||
|
destURL := fmt.Sprintf("%s/enterprise2/%srelease", cfg.enterprise2DestBucket, prefix)
|
||||||
|
log.Printf("Copying downloads for enterprise2, from %s bucket to %s bucket", srcURL, destURL)
|
||||||
|
err := gcsCopy("enterprise2 downloads", srcURL, destURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error copying ")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gcsCopy(desc, src, dest string) error {
|
||||||
|
args := strings.Split(fmt.Sprintf("-m cp -r gs://%s gs://%s", src, dest), " ")
|
||||||
|
// nolint:gosec
|
||||||
|
cmd := exec.Command("gsutil", args...)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to publish %s: %w\n%s", desc, err, out)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/ecr"
|
||||||
|
"github.com/aws/aws-sdk-go/service/marketplacecatalog"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
marketplaceChangeSetName = "Add new version"
|
||||||
|
marketplaceCatalogId = "AWSMarketplace"
|
||||||
|
marketplaceRegistryId = "709825985650"
|
||||||
|
marketplaceRegistryRegion = "us-east-1"
|
||||||
|
marketplaceRegistryUrl = "709825985650.dkr.ecr.us-east-1.amazonaws.com"
|
||||||
|
marketplaceRequestsUrl = "https://aws.amazon.com/marketplace/management/requests/"
|
||||||
|
releaseNotesTemplateUrl = "https://grafana.com/docs/grafana/latest/release-notes/release-notes-${TAG}/"
|
||||||
|
helmChartsUrl = "https://grafana.github.io/helm-charts/"
|
||||||
|
docsUrl = "https://grafana.com/docs/grafana/latest/enterprise/license/"
|
||||||
|
imagePlatform = "linux/amd64"
|
||||||
|
|
||||||
|
publishAwsMarketplaceTestKey publishAwsMarketplaceTestKeyType = "test-client"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errEmptyVersion = errors.New(`failed to retrieve release version from metadata, use "--version" to set it manually`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type publishAwsMarketplaceTestKeyType string
|
||||||
|
|
||||||
|
type publishAwsMarketplaceFlags struct {
|
||||||
|
dryRun bool
|
||||||
|
version string
|
||||||
|
repo string
|
||||||
|
image string
|
||||||
|
product string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AwsMarketplacePublishingService struct {
|
||||||
|
auth string
|
||||||
|
docker AwsMarketplaceDocker
|
||||||
|
ecr AwsMarketplaceRegistry
|
||||||
|
mkt AwsMarketplaceCatalog
|
||||||
|
}
|
||||||
|
|
||||||
|
type AwsMarketplaceDocker interface {
|
||||||
|
ImagePull(ctx context.Context, refStr string, options types.ImagePullOptions) (io.ReadCloser, error)
|
||||||
|
ImageTag(ctx context.Context, source string, target string) error
|
||||||
|
ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AwsMarketplaceRegistry interface {
|
||||||
|
GetAuthorizationTokenWithContext(ctx context.Context, input *ecr.GetAuthorizationTokenInput, opts ...request.Option) (*ecr.GetAuthorizationTokenOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AwsMarketplaceCatalog interface {
|
||||||
|
DescribeEntityWithContext(ctx context.Context, input *marketplacecatalog.DescribeEntityInput, opts ...request.Option) (*marketplacecatalog.DescribeEntityOutput, error)
|
||||||
|
StartChangeSetWithContext(ctx context.Context, input *marketplacecatalog.StartChangeSetInput, opts ...request.Option) (*marketplacecatalog.StartChangeSetOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PublishAwsMarketplace(ctx *cli.Context) error {
|
||||||
|
f, err := getPublishAwsMarketplaceFlags(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.version == "" {
|
||||||
|
return errEmptyVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
svc, err := getAwsMarketplacePublishingService()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Context.Value(publishAwsMarketplaceTestKey) != nil {
|
||||||
|
svc = ctx.Context.Value(publishAwsMarketplaceTestKey).(*AwsMarketplacePublishingService)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Logging in to AWS Marketplace registry")
|
||||||
|
err = svc.Login(ctx.Context)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Retrieving image '%s:%s' from Docker Hub\n", f.image, f.version)
|
||||||
|
err = svc.PullImage(ctx.Context, f.image, f.version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Renaming image '%s:%s' to '%s/%s:%s'\n", f.image, f.version, marketplaceRegistryUrl, f.repo, f.version)
|
||||||
|
err = svc.TagImage(ctx.Context, f.image, f.repo, f.version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.dryRun {
|
||||||
|
fmt.Printf("Pushing image '%s/%s:%s' to the AWS Marketplace ECR\n", marketplaceRegistryUrl, f.repo, f.version)
|
||||||
|
err = svc.PushToMarketplace(ctx.Context, f.repo, f.version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Dry-Run: Pushing image '%s/%s:%s' to the AWS Marketplace ECR\n", marketplaceRegistryUrl, f.repo, f.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Retrieving product identifier for product '%s'\n", f.product)
|
||||||
|
pid, err := svc.GetProductIdentifier(ctx.Context, f.product)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.dryRun {
|
||||||
|
fmt.Printf("Releasing to product, you can view the progress of the release on %s\n", marketplaceRequestsUrl)
|
||||||
|
return svc.ReleaseToProduct(ctx.Context, pid, f.repo, f.version)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Dry-Run: Releasing to product, you can view the progress of the release on %s\n", marketplaceRequestsUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAwsMarketplacePublishingService() (*AwsMarketplacePublishingService, error) {
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mySession := session.Must(session.NewSession())
|
||||||
|
ecr := ecr.New(mySession, aws.NewConfig().WithRegion(marketplaceRegistryRegion))
|
||||||
|
mkt := marketplacecatalog.New(mySession, aws.NewConfig().WithRegion(marketplaceRegistryRegion))
|
||||||
|
return &AwsMarketplacePublishingService{
|
||||||
|
docker: cli,
|
||||||
|
ecr: ecr,
|
||||||
|
mkt: mkt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwsMarketplacePublishingService) Login(ctx context.Context) error {
|
||||||
|
out, err := s.ecr.GetAuthorizationTokenWithContext(ctx, &ecr.GetAuthorizationTokenInput{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.auth = *out.AuthorizationData[0].AuthorizationToken
|
||||||
|
authData, err := base64.StdEncoding.DecodeString(s.auth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
authString := strings.Split(string(authData), ":")
|
||||||
|
authData, err = json.Marshal(types.AuthConfig{
|
||||||
|
Username: authString[0],
|
||||||
|
Password: authString[1],
|
||||||
|
})
|
||||||
|
s.auth = base64.StdEncoding.EncodeToString(authData)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwsMarketplacePublishingService) PullImage(ctx context.Context, image string, version string) error {
|
||||||
|
reader, err := s.docker.ImagePull(ctx, fmt.Sprintf("%s:%s", image, version), types.ImagePullOptions{
|
||||||
|
Platform: imagePlatform,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(os.Stdout, reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reader.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwsMarketplacePublishingService) TagImage(ctx context.Context, image string, repo string, version string) error {
|
||||||
|
err := s.docker.ImageTag(ctx, fmt.Sprintf("%s:%s", image, version), fmt.Sprintf("%s/%s:%s", marketplaceRegistryUrl, repo, version))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwsMarketplacePublishingService) PushToMarketplace(ctx context.Context, repo string, version string) error {
|
||||||
|
reader, err := s.docker.ImagePush(ctx, fmt.Sprintf("%s/%s:%s", marketplaceRegistryUrl, repo, version), types.ImagePushOptions{
|
||||||
|
RegistryAuth: s.auth,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(os.Stdout, reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reader.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwsMarketplacePublishingService) GetProductIdentifier(ctx context.Context, product string) (string, error) {
|
||||||
|
out, err := s.mkt.DescribeEntityWithContext(ctx, &marketplacecatalog.DescribeEntityInput{
|
||||||
|
EntityId: aws.String(product),
|
||||||
|
Catalog: aws.String(marketplaceCatalogId),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return *out.EntityIdentifier, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AwsMarketplacePublishingService) ReleaseToProduct(ctx context.Context, pid string, repo string, version string) error {
|
||||||
|
_, err := s.mkt.StartChangeSetWithContext(ctx, &marketplacecatalog.StartChangeSetInput{
|
||||||
|
Catalog: aws.String(marketplaceCatalogId),
|
||||||
|
ChangeSetName: aws.String(marketplaceChangeSetName),
|
||||||
|
ChangeSet: []*marketplacecatalog.Change{
|
||||||
|
buildAwsMarketplaceChangeSet(pid, repo, version),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPublishAwsMarketplaceFlags(ctx *cli.Context) (*publishAwsMarketplaceFlags, error) {
|
||||||
|
metadata, err := config.GenerateMetadata(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
version := ctx.String("version")
|
||||||
|
if version == "" && metadata.GrafanaVersion != "" {
|
||||||
|
version = metadata.GrafanaVersion
|
||||||
|
}
|
||||||
|
image := ctx.String("image")
|
||||||
|
repo := ctx.String("repo")
|
||||||
|
product := ctx.String("product")
|
||||||
|
dryRun := ctx.Bool("dry-run")
|
||||||
|
return &publishAwsMarketplaceFlags{
|
||||||
|
dryRun: dryRun,
|
||||||
|
version: version,
|
||||||
|
image: image,
|
||||||
|
repo: repo,
|
||||||
|
product: product,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAwsMarketplaceReleaseNotesUrl(version string) string {
|
||||||
|
sanitizedVersion := strings.ReplaceAll(version, ".", "-")
|
||||||
|
return strings.ReplaceAll(releaseNotesTemplateUrl, "${TAG}", sanitizedVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAwsMarketplaceChangeSet(entityId string, repo string, version string) *marketplacecatalog.Change {
|
||||||
|
return &marketplacecatalog.Change{
|
||||||
|
ChangeType: aws.String("AddDeliveryOptions"),
|
||||||
|
Entity: &marketplacecatalog.Entity{
|
||||||
|
Type: aws.String("ContainerProduct@1.0"),
|
||||||
|
Identifier: aws.String(entityId),
|
||||||
|
},
|
||||||
|
Details: aws.String(buildAwsMarketplaceVersionDetails(repo, version)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAwsMarketplaceVersionDetails(repo string, version string) string {
|
||||||
|
releaseNotesUrl := buildAwsMarketplaceReleaseNotesUrl(version)
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
"Version": {
|
||||||
|
"ReleaseNotes": "Release notes are available on the website %s",
|
||||||
|
"VersionTitle": "v%s"
|
||||||
|
},
|
||||||
|
"DeliveryOptions": [
|
||||||
|
{
|
||||||
|
"Details": {
|
||||||
|
"EcrDeliveryOptionDetails": {
|
||||||
|
"DeploymentResources": [
|
||||||
|
{
|
||||||
|
"Name": "Helm Charts",
|
||||||
|
"Url": "%s"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"CompatibleServices": ["EKS", "ECS", "ECS-Anywhere", "EKS-Anywhere"],
|
||||||
|
"ContainerImages": ["%s/%s:%s"],
|
||||||
|
"Description": "Grafana Enterprise can be installed using the official Grafana Helm chart repository. The repository is available on Github: %s",
|
||||||
|
"UsageInstructions": "You can apply your Grafana Enterprise license to a new or existing Grafana Enterprise deployment by updating a configuration setting or environment variable. Your Grafana instance must be deployed on AWS, or have network access to AWS. For more information, see %s"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DeliveryOptionTitle": "Helm Chart"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, releaseNotesUrl, version, helmChartsUrl, marketplaceRegistryUrl, repo, version, helmChartsUrl, docsUrl)
|
||||||
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/service/ecr"
|
||||||
|
"github.com/aws/aws-sdk-go/service/marketplacecatalog"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type awsPublishTestCase struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
expectedError error
|
||||||
|
errorContains string
|
||||||
|
expectedOutput string
|
||||||
|
mockedService *AwsMarketplacePublishingService
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPublishAwsMarketplace(t *testing.T) {
|
||||||
|
t.Setenv("DRONE_BUILD_EVENT", "promote")
|
||||||
|
t.Setenv("DRONE_TAG", "v1.0.0")
|
||||||
|
t.Setenv("DRONE_COMMIT", "abcdefgh")
|
||||||
|
testApp := setupPublishAwsMarketplaceTests(t)
|
||||||
|
errShouldNotCallMock := errors.New("shouldn't call")
|
||||||
|
|
||||||
|
testCases := []awsPublishTestCase{
|
||||||
|
{
|
||||||
|
name: "try to publish without required flags",
|
||||||
|
errorContains: `Required flags "image, repo, product" not set`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "try to publish without credentials",
|
||||||
|
args: []string{"--image", "test/test", "--repo", "test/test", "--product", "test", "--version", "1.0.0"},
|
||||||
|
mockedService: &AwsMarketplacePublishingService{
|
||||||
|
ecr: &mockAwsMarketplaceRegistry{
|
||||||
|
GetAuthorizationTokenWithContextError: credentials.ErrNoValidProvidersFoundInChain,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: credentials.ErrNoValidProvidersFoundInChain,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "try to publish with valid credentials and nonexisting version",
|
||||||
|
args: []string{"--image", "test/test", "--repo", "test/test", "--product", "test", "--version", "1.0.0"},
|
||||||
|
mockedService: &AwsMarketplacePublishingService{
|
||||||
|
ecr: &mockAwsMarketplaceRegistry{},
|
||||||
|
docker: &mockAwsMarketplaceDocker{},
|
||||||
|
mkt: &mockAwsMarketplaceCatalog{},
|
||||||
|
},
|
||||||
|
expectedOutput: "Releasing to product",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "try to publish with valid credentials and existing version",
|
||||||
|
args: []string{"--image", "test/test", "--repo", "test/test", "--product", "test", "--version", "1.0.0"},
|
||||||
|
mockedService: &AwsMarketplacePublishingService{
|
||||||
|
ecr: &mockAwsMarketplaceRegistry{},
|
||||||
|
docker: &mockAwsMarketplaceDocker{},
|
||||||
|
mkt: &mockAwsMarketplaceCatalog{},
|
||||||
|
},
|
||||||
|
expectedOutput: "Releasing to product",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dry run with invalid credentials",
|
||||||
|
args: []string{"--dry-run", "--image", "test/test", "--repo", "test/test", "--product", "test", "--version", "1.0.0"},
|
||||||
|
mockedService: &AwsMarketplacePublishingService{
|
||||||
|
ecr: &mockAwsMarketplaceRegistry{
|
||||||
|
GetAuthorizationTokenWithContextError: credentials.ErrNoValidProvidersFoundInChain,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: credentials.ErrNoValidProvidersFoundInChain,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dry run with valid credentials",
|
||||||
|
args: []string{"--dry-run", "--image", "test/test", "--repo", "test/test", "--product", "test", "--version", "1.0.0"},
|
||||||
|
mockedService: &AwsMarketplacePublishingService{
|
||||||
|
ecr: &mockAwsMarketplaceRegistry{},
|
||||||
|
docker: &mockAwsMarketplaceDocker{
|
||||||
|
ImagePushError: errShouldNotCallMock,
|
||||||
|
},
|
||||||
|
mkt: &mockAwsMarketplaceCatalog{
|
||||||
|
StartChangeSetWithContextError: errShouldNotCallMock,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedOutput: "Dry-Run: Releasing to product",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("DRONE_COMMIT") == "" {
|
||||||
|
// this test only works locally due to Drone environment
|
||||||
|
testCases = append(testCases,
|
||||||
|
awsPublishTestCase{
|
||||||
|
name: "try to publish without version",
|
||||||
|
args: []string{"--image", "test/test", "--repo", "test/test", "--product", "test"},
|
||||||
|
expectedError: errEmptyVersion,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
ctx := context.WithValue(context.Background(), publishAwsMarketplaceTestKey, test.mockedService)
|
||||||
|
args := []string{"run"}
|
||||||
|
args = append(args, test.args...)
|
||||||
|
out, err := captureStdout(t, func() error {
|
||||||
|
return testApp.RunContext(ctx, args)
|
||||||
|
})
|
||||||
|
if test.expectedOutput != "" {
|
||||||
|
assert.Contains(t, out, test.expectedOutput)
|
||||||
|
}
|
||||||
|
if test.expectedError != nil || test.errorContains != "" {
|
||||||
|
assert.Error(t, err)
|
||||||
|
if test.expectedError != nil {
|
||||||
|
assert.ErrorIs(t, err, test.expectedError)
|
||||||
|
}
|
||||||
|
if test.errorContains != "" {
|
||||||
|
assert.ErrorContains(t, err, test.errorContains)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupPublishAwsMarketplaceTests(t *testing.T) *cli.App {
|
||||||
|
t.Helper()
|
||||||
|
testApp := cli.NewApp()
|
||||||
|
testApp.Action = PublishAwsMarketplace
|
||||||
|
testApp.Flags = []cli.Flag{
|
||||||
|
&dryRunFlag,
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "version",
|
||||||
|
Usage: "Release version (default from metadata)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "image",
|
||||||
|
Required: true,
|
||||||
|
Usage: "Name of the image to be released",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "repo",
|
||||||
|
Required: true,
|
||||||
|
Usage: "AWS Marketplace ECR repository",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "product",
|
||||||
|
Required: true,
|
||||||
|
Usage: "AWS Marketplace product identifier",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return testApp
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockAwsMarketplaceDocker struct {
|
||||||
|
ImagePullError error
|
||||||
|
ImageTagError error
|
||||||
|
ImagePushError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockAwsMarketplaceDocker) ImagePull(ctx context.Context, refStr string, options types.ImagePullOptions) (io.ReadCloser, error) {
|
||||||
|
return io.NopCloser(bytes.NewReader([]byte(""))), m.ImagePullError
|
||||||
|
}
|
||||||
|
func (m *mockAwsMarketplaceDocker) ImageTag(ctx context.Context, source string, target string) error {
|
||||||
|
return m.ImageTagError
|
||||||
|
}
|
||||||
|
func (m *mockAwsMarketplaceDocker) ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error) {
|
||||||
|
return io.NopCloser(bytes.NewReader([]byte(""))), m.ImagePushError
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockAwsMarketplaceRegistry struct {
|
||||||
|
GetAuthorizationTokenWithContextError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockAwsMarketplaceRegistry) GetAuthorizationTokenWithContext(ctx context.Context, input *ecr.GetAuthorizationTokenInput, opts ...request.Option) (*ecr.GetAuthorizationTokenOutput, error) {
|
||||||
|
return &ecr.GetAuthorizationTokenOutput{
|
||||||
|
AuthorizationData: []*ecr.AuthorizationData{
|
||||||
|
{
|
||||||
|
AuthorizationToken: aws.String(base64.StdEncoding.EncodeToString([]byte("username:password"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, m.GetAuthorizationTokenWithContextError
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockAwsMarketplaceCatalog struct {
|
||||||
|
DescribeEntityWithContextError error
|
||||||
|
StartChangeSetWithContextError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockAwsMarketplaceCatalog) DescribeEntityWithContext(ctx context.Context, input *marketplacecatalog.DescribeEntityInput, opts ...request.Option) (*marketplacecatalog.DescribeEntityOutput, error) {
|
||||||
|
return &marketplacecatalog.DescribeEntityOutput{
|
||||||
|
EntityIdentifier: aws.String("productid"),
|
||||||
|
}, m.DescribeEntityWithContextError
|
||||||
|
}
|
||||||
|
func (m *mockAwsMarketplaceCatalog) StartChangeSetWithContext(ctx context.Context, input *marketplacecatalog.StartChangeSetInput, opts ...request.Option) (*marketplacecatalog.StartChangeSetOutput, error) {
|
||||||
|
return &marketplacecatalog.StartChangeSetOutput{}, m.StartChangeSetWithContextError
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/go-github/github"
|
"github.com/google/go-github/github"
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
@@ -39,9 +40,9 @@ var (
|
|||||||
errReleaseNotFound = errors.New(`release not found, use "--create" to create the release`)
|
errReleaseNotFound = errors.New(`release not found, use "--create" to create the release`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func PublishGitHub(ctx *cli.Context) error {
|
func PublishGithub(ctx *cli.Context) error {
|
||||||
token := os.Getenv("GH_TOKEN")
|
token := os.Getenv("GH_TOKEN")
|
||||||
f, err := getFlags(ctx)
|
f, err := getPublishGithubFlags(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,7 @@ func PublishGitHub(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f.dryRun {
|
if f.dryRun {
|
||||||
return runDryRun(f, token, ctx)
|
return runPublishGithubDryRun(f, token, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := newGithubClient(ctx.Context, token)
|
client := newGithubClient(ctx.Context, token)
|
||||||
@@ -99,8 +100,8 @@ func githubRepositoryClient(ctx context.Context, token string) githubRepositoryS
|
|||||||
return client.Repositories
|
return client.Repositories
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFlags(ctx *cli.Context) (*publishGithubFlags, error) {
|
func getPublishGithubFlags(ctx *cli.Context) (*publishGithubFlags, error) {
|
||||||
metadata, err := GenerateMetadata(ctx)
|
metadata, err := config.GenerateMetadata(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -130,12 +131,12 @@ func getFlags(ctx *cli.Context) (*publishGithubFlags, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDryRun(f *publishGithubFlags, token string, ctx *cli.Context) error {
|
func runPublishGithubDryRun(f *publishGithubFlags, token string, ctx *cli.Context) error {
|
||||||
client := newGithubClient(ctx.Context, token)
|
client := newGithubClient(ctx.Context, token)
|
||||||
fmt.Println("Dry-Run: Retrieving release on repository by tag")
|
fmt.Println("Dry-Run: Retrieving release on repository by tag")
|
||||||
release, res, err := client.GetReleaseByTag(ctx.Context, f.repo.owner, f.repo.name, f.tag)
|
release, res, err := client.GetReleaseByTag(ctx.Context, f.repo.owner, f.repo.name, f.tag)
|
||||||
if err != nil && res.StatusCode != 404 {
|
if err != nil && res.StatusCode != 404 {
|
||||||
fmt.Println("Dry-Run: GitHub communication error:\n", err)
|
fmt.Println("Dry-Run: Github communication error:\n", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,17 +21,19 @@ type githubPublishTestCases struct {
|
|||||||
expectedError error
|
expectedError error
|
||||||
errorContains string
|
errorContains string
|
||||||
expectedOutput string
|
expectedOutput string
|
||||||
mockedService *mockGitHubRepositoryServiceImpl
|
mockedService *mockGithubRepositoryServiceImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
var mockGitHubRepositoryService = &mockGitHubRepositoryServiceImpl{}
|
var mockGithubRepositoryService = &mockGithubRepositoryServiceImpl{}
|
||||||
|
|
||||||
func mockGithubRepositoryClient(context.Context, string) githubRepositoryService {
|
func mockGithubRepositoryClient(context.Context, string) githubRepositoryService {
|
||||||
return mockGitHubRepositoryService
|
return mockGithubRepositoryService
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPublishGitHub(t *testing.T) {
|
func TestPublishGithub(t *testing.T) {
|
||||||
t.Setenv("DRONE_BUILD_EVENT", "promote")
|
t.Setenv("DRONE_BUILD_EVENT", "promote")
|
||||||
|
t.Setenv("DRONE_TAG", "v1.0.0")
|
||||||
|
t.Setenv("DRONE_COMMIT", "abcdefgh")
|
||||||
testApp, testPath := setupPublishGithubTests(t)
|
testApp, testPath := setupPublishGithubTests(t)
|
||||||
mockErrUnauthorized := errors.New("401")
|
mockErrUnauthorized := errors.New("401")
|
||||||
|
|
||||||
@@ -49,21 +51,21 @@ func TestPublishGitHub(t *testing.T) {
|
|||||||
name: "try to publish with invalid token",
|
name: "try to publish with invalid token",
|
||||||
token: "invalid",
|
token: "invalid",
|
||||||
args: []string{"--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
args: []string{"--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
||||||
mockedService: &mockGitHubRepositoryServiceImpl{tagErr: mockErrUnauthorized},
|
mockedService: &mockGithubRepositoryServiceImpl{tagErr: mockErrUnauthorized},
|
||||||
expectedError: mockErrUnauthorized,
|
expectedError: mockErrUnauthorized,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "try to publish with valid token and nonexisting tag with create disabled",
|
name: "try to publish with valid token and nonexisting tag with create disabled",
|
||||||
token: "valid",
|
token: "valid",
|
||||||
args: []string{"--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
args: []string{"--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
||||||
mockedService: &mockGitHubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
mockedService: &mockGithubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
||||||
expectedError: errReleaseNotFound,
|
expectedError: errReleaseNotFound,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "try to publish with valid token and nonexisting tag with create enabled",
|
name: "try to publish with valid token and nonexisting tag with create enabled",
|
||||||
token: "valid",
|
token: "valid",
|
||||||
args: []string{"--path", testPath, "--repo", "test/test", "--tag", "v1.0.0", "--create"},
|
args: []string{"--path", testPath, "--repo", "test/test", "--tag", "v1.0.0", "--create"},
|
||||||
mockedService: &mockGitHubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
mockedService: &mockGithubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "try to publish with valid token and existing tag",
|
name: "try to publish with valid token and existing tag",
|
||||||
@@ -74,21 +76,21 @@ func TestPublishGitHub(t *testing.T) {
|
|||||||
name: "dry run with invalid token",
|
name: "dry run with invalid token",
|
||||||
token: "invalid",
|
token: "invalid",
|
||||||
args: []string{"--dry-run", "--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
args: []string{"--dry-run", "--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
||||||
mockedService: &mockGitHubRepositoryServiceImpl{tagErr: mockErrUnauthorized},
|
mockedService: &mockGithubRepositoryServiceImpl{tagErr: mockErrUnauthorized},
|
||||||
expectedOutput: "GitHub communication error",
|
expectedOutput: "Github communication error",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dry run with valid token and nonexisting tag with create disabled",
|
name: "dry run with valid token and nonexisting tag with create disabled",
|
||||||
token: "valid",
|
token: "valid",
|
||||||
args: []string{"--dry-run", "--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
args: []string{"--dry-run", "--path", testPath, "--repo", "test/test", "--tag", "v1.0.0"},
|
||||||
mockedService: &mockGitHubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
mockedService: &mockGithubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
||||||
expectedOutput: "Release doesn't exist",
|
expectedOutput: "Release doesn't exist",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dry run with valid token and nonexisting tag with create enabled",
|
name: "dry run with valid token and nonexisting tag with create enabled",
|
||||||
token: "valid",
|
token: "valid",
|
||||||
args: []string{"--dry-run", "--path", testPath, "--repo", "test/test", "--tag", "v1.0.0", "--create"},
|
args: []string{"--dry-run", "--path", testPath, "--repo", "test/test", "--tag", "v1.0.0", "--create"},
|
||||||
mockedService: &mockGitHubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
mockedService: &mockGithubRepositoryServiceImpl{tagErr: errReleaseNotFound},
|
||||||
expectedOutput: "Would upload asset",
|
expectedOutput: "Would upload asset",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -116,9 +118,9 @@ func TestPublishGitHub(t *testing.T) {
|
|||||||
t.Setenv("GH_TOKEN", test.token)
|
t.Setenv("GH_TOKEN", test.token)
|
||||||
}
|
}
|
||||||
if test.mockedService != nil {
|
if test.mockedService != nil {
|
||||||
mockGitHubRepositoryService = test.mockedService
|
mockGithubRepositoryService = test.mockedService
|
||||||
} else {
|
} else {
|
||||||
mockGitHubRepositoryService = &mockGitHubRepositoryServiceImpl{}
|
mockGithubRepositoryService = &mockGithubRepositoryServiceImpl{}
|
||||||
}
|
}
|
||||||
args := []string{"run"}
|
args := []string{"run"}
|
||||||
args = append(args, test.args...)
|
args = append(args, test.args...)
|
||||||
@@ -154,7 +156,7 @@ func setupPublishGithubTests(t *testing.T) (*cli.App, string) {
|
|||||||
newGithubClient = mockGithubRepositoryClient
|
newGithubClient = mockGithubRepositoryClient
|
||||||
|
|
||||||
testApp := cli.NewApp()
|
testApp := cli.NewApp()
|
||||||
testApp.Action = PublishGitHub
|
testApp.Action = PublishGithub
|
||||||
testApp.Flags = []cli.Flag{
|
testApp.Flags = []cli.Flag{
|
||||||
&dryRunFlag,
|
&dryRunFlag,
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@@ -165,7 +167,7 @@ func setupPublishGithubTests(t *testing.T) (*cli.App, string) {
|
|||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Required: true,
|
Required: true,
|
||||||
Usage: "GitHub repository",
|
Usage: "Github repository",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "tag",
|
Name: "tag",
|
||||||
@@ -194,13 +196,13 @@ func captureStdout(t *testing.T, fn func() error) (string, error) {
|
|||||||
return string(out), err
|
return string(out), err
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockGitHubRepositoryServiceImpl struct {
|
type mockGithubRepositoryServiceImpl struct {
|
||||||
tagErr error
|
tagErr error
|
||||||
createErr error
|
createErr error
|
||||||
uploadErr error
|
uploadErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockGitHubRepositoryServiceImpl) GetReleaseByTag(ctx context.Context, owner string, repo string, tag string) (*github.RepositoryRelease, *github.Response, error) {
|
func (m *mockGithubRepositoryServiceImpl) GetReleaseByTag(ctx context.Context, owner string, repo string, tag string) (*github.RepositoryRelease, *github.Response, error) {
|
||||||
var release *github.RepositoryRelease
|
var release *github.RepositoryRelease
|
||||||
res := &github.Response{Response: &http.Response{}}
|
res := &github.Response{Response: &http.Response{}}
|
||||||
if m.tagErr == nil {
|
if m.tagErr == nil {
|
||||||
@@ -212,12 +214,12 @@ func (m *mockGitHubRepositoryServiceImpl) GetReleaseByTag(ctx context.Context, o
|
|||||||
return release, res, m.tagErr
|
return release, res, m.tagErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockGitHubRepositoryServiceImpl) CreateRelease(ctx context.Context, owner string, repo string, release *github.RepositoryRelease) (*github.RepositoryRelease, *github.Response, error) {
|
func (m *mockGithubRepositoryServiceImpl) CreateRelease(ctx context.Context, owner string, repo string, release *github.RepositoryRelease) (*github.RepositoryRelease, *github.Response, error) {
|
||||||
releaseID := int64(1)
|
releaseID := int64(1)
|
||||||
return &github.RepositoryRelease{ID: &releaseID}, &github.Response{}, m.createErr
|
return &github.RepositoryRelease{ID: &releaseID}, &github.Response{}, m.createErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockGitHubRepositoryServiceImpl) UploadReleaseAsset(ctx context.Context, owner string, repo string, id int64, opt *github.UploadOptions, file *os.File) (*github.ReleaseAsset, *github.Response, error) {
|
func (m *mockGithubRepositoryServiceImpl) UploadReleaseAsset(ctx context.Context, owner string, repo string, id int64, opt *github.UploadOptions, file *os.File) (*github.ReleaseAsset, *github.Response, error) {
|
||||||
assetName := "test"
|
assetName := "test"
|
||||||
assetUrl := "testurl.com.br"
|
assetUrl := "testurl.com.br"
|
||||||
return &github.ReleaseAsset{Name: &assetName, BrowserDownloadURL: &assetUrl}, &github.Response{}, m.uploadErr
|
return &github.ReleaseAsset{Name: &assetName, BrowserDownloadURL: &assetUrl}, &github.Response{}, m.uploadErr
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
|
"github.com/grafana/grafana/pkg/build/docker"
|
||||||
|
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Enterprise2(c *cli.Context) error {
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gcloud.ActivateServiceAccount(); err != nil {
|
||||||
|
return fmt.Errorf("couldn't activate service account, err: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, err := config.GenerateMetadata(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buildConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := docker.Config{
|
||||||
|
Archs: buildConfig.Docker.Architectures,
|
||||||
|
Distribution: buildConfig.Docker.Distribution,
|
||||||
|
DockerHubRepo: c.String("dockerhub-repo"),
|
||||||
|
Tag: metadata.GrafanaVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dockerLoginEnterprise2()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var distributionStr []string
|
||||||
|
for _, distribution := range cfg.Distribution {
|
||||||
|
switch distribution {
|
||||||
|
case alpine:
|
||||||
|
distributionStr = append(distributionStr, "")
|
||||||
|
case ubuntu:
|
||||||
|
distributionStr = append(distributionStr, "-ubuntu")
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unrecognized distribution %q", distribution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, distribution := range distributionStr {
|
||||||
|
var imageFileNames []string
|
||||||
|
for _, arch := range cfg.Archs {
|
||||||
|
imageFilename := fmt.Sprintf("%s:%s%s-%s", cfg.DockerHubRepo, cfg.Tag, distribution, arch)
|
||||||
|
err := docker.PushImage(imageFilename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imageFileNames = append(imageFileNames, imageFilename)
|
||||||
|
}
|
||||||
|
manifest := fmt.Sprintf("%s:%s%s", cfg.DockerHubRepo, cfg.Tag, distribution)
|
||||||
|
args := []string{"manifest", "create", manifest}
|
||||||
|
args = append(args, imageFileNames...)
|
||||||
|
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.Command("docker", args...)
|
||||||
|
cmd.Env = append(os.Environ(), "DOCKER_CLI_EXPERIMENTAL=enabled")
|
||||||
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("failed to create Docker manifest: %w\n%s", err, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = docker.PushManifest(manifest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dockerLoginEnterprise2() error {
|
||||||
|
log.Println("Docker login...")
|
||||||
|
cmd := exec.Command("gcloud", "auth", "configure-docker")
|
||||||
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("error logging in to DockerHub: %s %q", out, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Successful login!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -8,8 +8,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/metrics"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PublishMetrics(c *cli.Context) error {
|
func PublishMetrics(c *cli.Context) error {
|
||||||
@@ -17,24 +18,24 @@ func PublishMetrics(c *cli.Context) error {
|
|||||||
|
|
||||||
input, err := io.ReadAll(os.Stdin)
|
input, err := io.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("Reading from stdin failed: %s", err), 1)
|
return cli.Exit(fmt.Sprintf("Reading from stdin failed: %s", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
reMetrics := regexp.MustCompile(`(?ms)^Metrics: (\{.+\})`)
|
reMetrics := regexp.MustCompile(`(?ms)^Metrics: (\{.+\})`)
|
||||||
ms := reMetrics.FindSubmatch(input)
|
ms := reMetrics.FindSubmatch(input)
|
||||||
if len(ms) == 0 {
|
if len(ms) == 0 {
|
||||||
return cli.NewExitError(fmt.Sprintf("Input on wrong format: %q", string(input)), 1)
|
return cli.Exit(fmt.Sprintf("Input on wrong format: %q", string(input)), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := map[string]string{}
|
m := map[string]string{}
|
||||||
if err := json.Unmarshal(ms[1], &m); err != nil {
|
if err := json.Unmarshal(ms[1], &m); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("decoding metrics failed: %s", err), 1)
|
return cli.Exit(fmt.Sprintf("decoding metrics failed: %s", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Received metrics %+v", m)
|
log.Printf("Received metrics %+v", m)
|
||||||
|
|
||||||
if err := metrics.Publish(m, apiKey); err != nil {
|
if err := metrics.Publish(m, apiKey); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("publishing metrics failed: %s", err), 1)
|
return cli.Exit(fmt.Sprintf("publishing metrics failed: %s", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
func StoreStorybook(c *cli.Context) error {
|
func StoreStorybook(c *cli.Context) error {
|
||||||
deployment := c.String("deployment")
|
deployment := c.String("deployment")
|
||||||
|
|
||||||
metadata, err := GenerateMetadata(c)
|
metadata, err := config.GenerateMetadata(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
|
"github.com/grafana/grafana/pkg/build/gcloud/storage"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UploadCDN implements the sub-command "upload-cdn".
|
||||||
|
func UploadCDN(c *cli.Context) error {
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, err := config.GenerateMetadata(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
version := metadata.GrafanaVersion
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildConfig, err := config.GetBuildConfig(metadata.ReleaseMode.Mode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
edition := os.Getenv("EDITION")
|
||||||
|
log.Printf("Uploading Grafana CDN Assets, version %s, %s edition...", version, edition)
|
||||||
|
|
||||||
|
editionPath := ""
|
||||||
|
|
||||||
|
switch config.Edition(edition) {
|
||||||
|
case config.EditionOSS:
|
||||||
|
editionPath = "grafana-oss"
|
||||||
|
case config.EditionEnterprise:
|
||||||
|
editionPath = "grafana"
|
||||||
|
case config.EditionEnterprise2:
|
||||||
|
editionPath = os.Getenv("ENTERPRISE2_CDN_PATH")
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unrecognized edition %q", edition))
|
||||||
|
}
|
||||||
|
|
||||||
|
gcs, err := storage.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket := gcs.Bucket(buildConfig.Buckets.CDNAssets)
|
||||||
|
srcPath := buildConfig.Buckets.CDNAssetsDir
|
||||||
|
srcPath = filepath.Join(srcPath, editionPath, version)
|
||||||
|
|
||||||
|
if err := gcs.DeleteDir(c.Context, bucket, srcPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("Successfully cleaned source: %s/%s\n", buildConfig.Buckets.CDNAssets, srcPath)
|
||||||
|
|
||||||
|
if err := gcs.CopyLocalDir(c.Context, "./public", bucket, srcPath, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Successfully uploaded cdn static assets to: %s/%s!\n", buildConfig.Buckets.CDNAssets, srcPath)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
|
"github.com/grafana/grafana/pkg/build/droneutil"
|
||||||
|
"github.com/grafana/grafana/pkg/build/gcloud"
|
||||||
|
"github.com/grafana/grafana/pkg/build/packaging"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const releaseFolder = "release"
|
||||||
|
const mainFolder = "main"
|
||||||
|
const releaseBranchFolder = "prerelease"
|
||||||
|
|
||||||
|
type uploadConfig struct {
|
||||||
|
config.Config
|
||||||
|
|
||||||
|
edition config.Edition
|
||||||
|
versionMode config.VersionMode
|
||||||
|
gcpKey string
|
||||||
|
distDir string
|
||||||
|
versionFolder string
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadPackages implements the sub-command "upload-packages".
|
||||||
|
func UploadPackages(c *cli.Context) error {
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
return cli.Exit("", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
gcpKeyB64 := strings.TrimSpace(os.Getenv("GCP_KEY"))
|
||||||
|
if gcpKeyB64 == "" {
|
||||||
|
return cli.Exit("the environment variable GCP_KEY must be set", 1)
|
||||||
|
}
|
||||||
|
gcpKeyB, err := base64.StdEncoding.DecodeString(gcpKeyB64)
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit("failed to base64 decode $GCP_KEY", 1)
|
||||||
|
}
|
||||||
|
gcpKey := string(gcpKeyB)
|
||||||
|
|
||||||
|
distDir, err := filepath.Abs("dist")
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, err := config.GenerateMetadata(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
version := metadata.GrafanaVersion
|
||||||
|
|
||||||
|
releaseMode, err := metadata.GetReleaseMode()
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseModeConfig, err := config.GetBuildConfig(releaseMode.Mode)
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var edition config.Edition
|
||||||
|
if e, ok := os.LookupEnv("EDITION"); ok {
|
||||||
|
edition = config.Edition(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Bool("enterprise2") {
|
||||||
|
edition = config.EditionEnterprise2
|
||||||
|
}
|
||||||
|
|
||||||
|
if edition == "" {
|
||||||
|
return fmt.Errorf("both EDITION envvar and '--enterprise2' flag are missing. At least one of those is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Verify config values
|
||||||
|
cfg := uploadConfig{
|
||||||
|
Config: config.Config{
|
||||||
|
Version: version,
|
||||||
|
Bucket: releaseModeConfig.Buckets.Artifacts,
|
||||||
|
},
|
||||||
|
edition: edition,
|
||||||
|
versionMode: releaseMode.Mode,
|
||||||
|
gcpKey: gcpKey,
|
||||||
|
distDir: distDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
event, err := droneutil.GetDroneEventFromEnv()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.edition == config.EditionEnterprise2 {
|
||||||
|
cfg.Bucket, err = bucketForEnterprise2(releaseModeConfig, event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.versionFolder, err = getVersionFolder(cfg, event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := uploadPackages(cfg); err != nil {
|
||||||
|
return cli.Exit(err.Error(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Successfully uploaded packages!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corner case for custom enterprise2 mode
|
||||||
|
func bucketForEnterprise2(releaseModeConfig *config.BuildConfig, event string) (string, error) {
|
||||||
|
if event == config.Custom {
|
||||||
|
buildConfig, err := config.GetBuildConfig(config.ReleaseBranchMode)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return buildConfig.Buckets.ArtifactsEnterprise2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if releaseModeConfig.Buckets.ArtifactsEnterprise2 != "" {
|
||||||
|
return releaseModeConfig.Buckets.ArtifactsEnterprise2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("enterprise2 bucket var doesn't exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersionFolder(cfg uploadConfig, event string) (string, error) {
|
||||||
|
switch cfg.versionMode {
|
||||||
|
case config.TagMode:
|
||||||
|
return releaseFolder, nil
|
||||||
|
case config.MainMode, config.DownstreamMode:
|
||||||
|
return mainFolder, nil
|
||||||
|
case config.ReleaseBranchMode:
|
||||||
|
return releaseBranchFolder, nil
|
||||||
|
default:
|
||||||
|
// Corner case for custom enterprise2 mode
|
||||||
|
if event == config.Custom && cfg.versionMode == config.Enterprise2Mode {
|
||||||
|
return releaseFolder, nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("unrecognized version mode: %s", cfg.versionMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func uploadPackages(cfg uploadConfig) error {
|
||||||
|
log.Printf("Uploading Grafana packages, version %s, %s edition, %s mode...\n", cfg.Version, cfg.edition,
|
||||||
|
cfg.versionMode)
|
||||||
|
|
||||||
|
if err := gcloud.ActivateServiceAccount(); err != nil {
|
||||||
|
return fmt.Errorf("couldn't activate service account, err: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
edition := strings.ToLower(string(cfg.edition))
|
||||||
|
|
||||||
|
var sfx string
|
||||||
|
switch cfg.edition {
|
||||||
|
case config.EditionOSS:
|
||||||
|
case config.EditionEnterprise:
|
||||||
|
sfx = "-enterprise"
|
||||||
|
case config.EditionEnterprise2:
|
||||||
|
sfx = "-enterprise2"
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unrecognized edition %q", cfg.edition))
|
||||||
|
}
|
||||||
|
matches, err := filepath.Glob(filepath.Join(cfg.distDir, fmt.Sprintf("grafana%s*", sfx)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to list packages: %w", err)
|
||||||
|
}
|
||||||
|
fpaths := []string{}
|
||||||
|
rePkg := packaging.PackageRegexp(cfg.edition)
|
||||||
|
for _, fpath := range matches {
|
||||||
|
fname := filepath.Base(fpath)
|
||||||
|
if strings.Contains(fname, "latest") || !rePkg.MatchString(fname) {
|
||||||
|
log.Printf("Ignoring file %q\n", fpath)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fpaths = append(fpaths, fpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tag, gcsPath string
|
||||||
|
droneTag := strings.TrimSpace(os.Getenv("DRONE_TAG"))
|
||||||
|
if droneTag != "" {
|
||||||
|
tag = droneTag
|
||||||
|
gcsPath = fmt.Sprintf("gs://%s/%s/%s/%s", cfg.Bucket, tag, edition, cfg.versionFolder)
|
||||||
|
} else {
|
||||||
|
gcsPath = fmt.Sprintf("gs://%s/%s/%s/", cfg.Bucket, edition, cfg.versionFolder)
|
||||||
|
}
|
||||||
|
log.Printf("Uploading %d file(s) to GCS (%s)...\n", len(fpaths), gcsPath)
|
||||||
|
|
||||||
|
args := []string{"-m", "cp"}
|
||||||
|
args = append(args, fpaths...)
|
||||||
|
args = append(args, gcsPath)
|
||||||
|
cmd := exec.Command("gsutil", args...)
|
||||||
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("failed to upload files to GCS: %s", output)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_getVersionFolder(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
cfg uploadConfig
|
||||||
|
event string
|
||||||
|
versionFolder string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"tag mode", args{uploadConfig{versionMode: config.TagMode}, "", releaseFolder}, nil},
|
||||||
|
{"main mode", args{uploadConfig{versionMode: config.MainMode}, "", mainFolder}, nil},
|
||||||
|
{"downstream mode", args{uploadConfig{versionMode: config.DownstreamMode}, "", mainFolder}, nil},
|
||||||
|
{"release branch mode", args{uploadConfig{versionMode: config.ReleaseBranchMode}, "", releaseBranchFolder}, nil},
|
||||||
|
{"enterprise pro mode", args{uploadConfig{versionMode: config.Enterprise2Mode}, config.Custom, releaseFolder}, nil},
|
||||||
|
{"unrecognised version mode", args{uploadConfig{versionMode: "foo"}, config.Custom, ""}, errors.New("")},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
versionMode, err := getVersionFolder(tt.args.cfg, tt.args.event)
|
||||||
|
if tt.err != nil {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
require.Equal(t, versionMode, tt.args.versionFolder)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_checkForEnterprise2Edition(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
releaseModeConfig *config.BuildConfig
|
||||||
|
event string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"event is not custom", args{releaseModeConfig: &config.BuildConfig{Buckets: config.Buckets{ArtifactsEnterprise2: "dummy"}}}, "dummy", nil},
|
||||||
|
{"event is not custom and string is empty", args{releaseModeConfig: &config.BuildConfig{Buckets: config.Buckets{ArtifactsEnterprise2: ""}}}, "", fmt.Errorf("enterprise2 bucket var doesn't exist")},
|
||||||
|
{"event is custom", args{releaseModeConfig: nil, event: "custom"}, "grafana-downloads-enterprise2", nil},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := bucketForEnterprise2(tt.args.releaseModeConfig, tt.args.event)
|
||||||
|
if tt.err != nil {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
assert.Equalf(t, tt.want, got, "bucketForEnterprise2(%v, %v)", tt.args.releaseModeConfig, tt.args.event)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,10 +13,11 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
|
||||||
cliv1 "github.com/urfave/cli"
|
cliv1 "github.com/urfave/cli"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func VerifyDrone(c *cli.Context) error {
|
func VerifyDrone(c *cli.Context) error {
|
||||||
@@ -24,7 +25,7 @@ func VerifyDrone(c *cli.Context) error {
|
|||||||
const backup = ".drone.yml.bak"
|
const backup = ".drone.yml.bak"
|
||||||
|
|
||||||
if err := fsutil.CopyFile(yml, backup); err != nil {
|
if err := fsutil.CopyFile(yml, backup); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("failed to copy %s to %s: %s", yml, backup, err), 1)
|
return cli.Exit(fmt.Sprintf("failed to copy %s to %s: %s", yml, backup, err), 1)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.Remove(yml); err != nil {
|
if err := os.Remove(yml); err != nil {
|
||||||
@@ -73,7 +74,7 @@ func readConfig(fpath string) ([]map[string]interface{}, error) {
|
|||||||
//nolint:gosec
|
//nolint:gosec
|
||||||
f, err := os.Open(fpath)
|
f, err := os.Open(fpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cli.NewExitError(fmt.Sprintf("failed to read %s: %s", fpath, err), 1)
|
return nil, cli.Exit(fmt.Sprintf("failed to read %s: %s", fpath, err), 1)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := f.Close(); err != nil {
|
if err := f.Close(); err != nil {
|
||||||
@@ -90,7 +91,7 @@ func readConfig(fpath string) ([]map[string]interface{}, error) {
|
|||||||
if errors.Is(err, io.EOF) {
|
if errors.Is(err, io.EOF) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return nil, cli.NewExitError(fmt.Sprintf("Failed to decode %s: %s", fpath, err), 1)
|
return nil, cli.Exit(fmt.Sprintf("Failed to decode %s: %s", fpath, err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m["kind"] == "signature" {
|
if m["kind"] == "signature" {
|
||||||
@@ -118,7 +119,7 @@ func verifyYAML(yml, backup string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !cmp.Equal(c1, c2) {
|
if !cmp.Equal(c1, c2) {
|
||||||
return cli.NewExitError(fmt.Sprintf("%s is out of sync with .drone.star - regenerate it with drone starlark convert",
|
return cli.Exit(fmt.Sprintf("%s is out of sync with .drone.star - regenerate it with drone starlark convert",
|
||||||
yml), 1)
|
yml), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mapSlice[I any, O any](a []I, f func(I) O) []O {
|
||||||
|
o := make([]O, len(a))
|
||||||
|
for i, e := range a {
|
||||||
|
o[i] = f(e)
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyStarlark is the CLI Action for verifying Starlark files in a workspace.
|
||||||
|
// It expects a single context argument which is the path to the workspace.
|
||||||
|
// The actual verification procedure can return multiple errors which are
|
||||||
|
// joined together to be one holistic error for the action.
|
||||||
|
func VerifyStarlark(c *cli.Context) error {
|
||||||
|
if c.NArg() != 1 {
|
||||||
|
var message string
|
||||||
|
if c.NArg() == 0 {
|
||||||
|
message = "ERROR: missing required argument <workspace path>"
|
||||||
|
}
|
||||||
|
if c.NArg() > 1 {
|
||||||
|
message = "ERROR: too many arguments"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cli.Exit(message, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace := c.Args().Get(0)
|
||||||
|
verificationErrs, executionErr := verifyStarlark(c.Context, workspace, buildifierLintCommand)
|
||||||
|
if executionErr != nil {
|
||||||
|
return executionErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(verificationErrs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
noun := "file"
|
||||||
|
if len(verificationErrs) > 1 {
|
||||||
|
noun += "s"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("verification failed for %d %s:\n%s",
|
||||||
|
len(verificationErrs),
|
||||||
|
noun,
|
||||||
|
strings.Join(
|
||||||
|
mapSlice(verificationErrs, func(e error) string { return e.Error() }),
|
||||||
|
"\n",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandFunc = func(path string) (command string, args []string)
|
||||||
|
|
||||||
|
func buildifierLintCommand(path string) (string, []string) {
|
||||||
|
return "buildifier", []string{"-lint", "warn", "-mode", "check", path}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyStarlark walks all directories starting at provided workspace path and
|
||||||
|
// verifies any Starlark files it finds.
|
||||||
|
// Starlark files are assumed to end with the .star extension.
|
||||||
|
// The verification relies on linting frovided by the 'buildifier' binary which
|
||||||
|
// must be in the PATH.
|
||||||
|
// A slice of verification errors are returned, one for each file that failed verification.
|
||||||
|
// If any execution of the `buildifier` command fails, this is returned separately.
|
||||||
|
// commandFn is executed on every Starlark file to determine the command and arguments to be executed.
|
||||||
|
// The caller is trusted and it is the callers responsibility to ensure that the resulting command is safe to execute.
|
||||||
|
func verifyStarlark(ctx context.Context, workspace string, commandFn commandFunc) ([]error, error) {
|
||||||
|
var verificationErrs []error
|
||||||
|
|
||||||
|
// All errors from filepath.WalkDir are filtered by the fs.WalkDirFunc.
|
||||||
|
// Lstat or ReadDir errors are reported as verificationErrors.
|
||||||
|
// If any execution of the `buildifier` command fails or if the context is cancelled,
|
||||||
|
// it is reported as an error and any verification of subsequent files is skipped.
|
||||||
|
err := filepath.WalkDir(workspace, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
// Skip verification of the file or files within the directory if there is an error
|
||||||
|
// returned by Lstat or ReadDir.
|
||||||
|
if err != nil {
|
||||||
|
verificationErrs = append(verificationErrs, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if filepath.Ext(path) == ".star" {
|
||||||
|
command, args := commandFn(path)
|
||||||
|
// The caller is trusted.
|
||||||
|
//nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, command, args...)
|
||||||
|
cmd.Dir = workspace
|
||||||
|
|
||||||
|
_, err = cmd.Output()
|
||||||
|
if err == nil { // No error, early return.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The error returned from cmd.Output() is never wrapped.
|
||||||
|
//nolint:errorlint
|
||||||
|
if err, ok := err.(*exec.ExitError); ok {
|
||||||
|
switch err.ExitCode() {
|
||||||
|
// Case comments are informed by the output of `buildifier --help`
|
||||||
|
case 1: // syntax errors in input
|
||||||
|
verificationErrs = append(verificationErrs, errors.New(string(err.Stderr)))
|
||||||
|
return nil
|
||||||
|
case 2: // usage errors: invoked incorrectly
|
||||||
|
return fmt.Errorf("command %q: %s", cmd, err.Stderr)
|
||||||
|
case 3: // unexpected runtime errors: file I/O problems or internal bugs
|
||||||
|
return fmt.Errorf("command %q: %s", cmd, err.Stderr)
|
||||||
|
case 4: // check mode failed (reformat is needed)
|
||||||
|
verificationErrs = append(verificationErrs, errors.New(string(err.Stderr)))
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("command %q: %s", cmd, err.Stderr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error was not an exit error from the command.
|
||||||
|
return fmt.Errorf("command %q: %v", cmd, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return verificationErrs, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
//go:build requires_buildifier
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVerifyStarlark(t *testing.T) {
|
||||||
|
t.Run("execution errors", func(t *testing.T) {
|
||||||
|
t.Run("invalid usage", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
workspace := t.TempDir()
|
||||||
|
err := os.WriteFile(filepath.Join(workspace, "ignored.star"), []byte{}, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, executionErr := verifyStarlark(ctx, workspace, func(string) (string, []string) { return "buildifier", []string{"--invalid"} })
|
||||||
|
if executionErr == nil {
|
||||||
|
t.Fatalf("Expected execution error but got none")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("context cancellation", func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
workspace := t.TempDir()
|
||||||
|
err := os.WriteFile(filepath.Join(workspace, "ignored.star"), []byte{}, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
err = os.WriteFile(filepath.Join(workspace, "other-ignored.star"), []byte{}, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
_, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||||
|
if executionErr == nil {
|
||||||
|
t.Fatalf("Expected execution error but got none")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("verification errors", func(t *testing.T) {
|
||||||
|
t.Run("a single file with lint", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
workspace := t.TempDir()
|
||||||
|
|
||||||
|
invalidContent := []byte(`load("scripts/drone/other.star", "function")
|
||||||
|
|
||||||
|
function()`)
|
||||||
|
err := os.WriteFile(filepath.Join(workspace, "has-lint.star"), invalidContent, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
verificationErrs, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||||
|
if executionErr != nil {
|
||||||
|
t.Fatalf("Unexpected execution error: %v", executionErr)
|
||||||
|
}
|
||||||
|
if len(verificationErrs) == 0 {
|
||||||
|
t.Fatalf(`"has-lint.star" requires linting but the verifyStarlark function provided no linting error`)
|
||||||
|
}
|
||||||
|
if len(verificationErrs) > 1 {
|
||||||
|
t.Fatalf(`verifyStarlark returned multiple errors for the "has-lint.star" file but only one was expected: %v`, verificationErrs)
|
||||||
|
}
|
||||||
|
if !strings.Contains(verificationErrs[0].Error(), "has-lint.star:1: module-docstring: The file has no module docstring.") {
|
||||||
|
t.Fatalf(`"has-lint.star" is missing a module docstring but the verifyStarlark function linting error did not mention this, instead we got: %v`, verificationErrs[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no files with lint", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
workspace := t.TempDir()
|
||||||
|
|
||||||
|
content := []byte(`"""
|
||||||
|
This module does nothing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
load("scripts/drone/other.star", "function")
|
||||||
|
|
||||||
|
function()
|
||||||
|
`)
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(workspace, "no-lint.star"), content, os.ModePerm))
|
||||||
|
|
||||||
|
verificationErrs, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||||
|
if executionErr != nil {
|
||||||
|
t.Fatalf("Unexpected execution error: %v", executionErr)
|
||||||
|
}
|
||||||
|
if len(verificationErrs) != 0 {
|
||||||
|
t.Log(`"no-lint.star" has no lint but the verifyStarlark function provided at least one error`)
|
||||||
|
for _, err := range verificationErrs {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple files with lint", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
workspace := t.TempDir()
|
||||||
|
|
||||||
|
invalidContent := []byte(`load("scripts/drone/other.star", "function")
|
||||||
|
|
||||||
|
function()`)
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(workspace, "has-lint.star"), invalidContent, os.ModePerm))
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(workspace, "has-lint2.star"), invalidContent, os.ModePerm))
|
||||||
|
|
||||||
|
verificationErrs, executionErr := verifyStarlark(ctx, workspace, buildifierLintCommand)
|
||||||
|
if executionErr != nil {
|
||||||
|
t.Fatalf("Unexpected execution error: %v", executionErr)
|
||||||
|
}
|
||||||
|
if len(verificationErrs) == 0 {
|
||||||
|
t.Fatalf(`Two files require linting but the verifyStarlark function provided no linting error`)
|
||||||
|
}
|
||||||
|
if len(verificationErrs) == 1 {
|
||||||
|
t.Fatalf(`Two files require linting but the verifyStarlark function provided only one linting error: %v`, verificationErrs[0])
|
||||||
|
}
|
||||||
|
if len(verificationErrs) > 2 {
|
||||||
|
t.Fatalf(`verifyStarlark returned more errors than expected: %v`, verificationErrs)
|
||||||
|
}
|
||||||
|
if !strings.Contains(verificationErrs[0].Error(), "has-lint.star:1: module-docstring: The file has no module docstring.") {
|
||||||
|
t.Errorf(`"has-lint.star" is missing a module docstring but the verifyStarlark function linting error did not mention this, instead we got: %v`, verificationErrs[0])
|
||||||
|
}
|
||||||
|
if !strings.Contains(verificationErrs[1].Error(), "has-lint2.star:1: module-docstring: The file has no module docstring.") {
|
||||||
|
t.Fatalf(`"has-lint2.star" is missing a module docstring but the verifyStarlark function linting error did not mention this, instead we got: %v`, verificationErrs[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// Package verifystorybook contains the sub-command "verify-storybook".
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VerifyStorybook Action implements the sub-command "verify-storybook".
|
||||||
|
func VerifyStorybook(c *cli.Context) error {
|
||||||
|
const grafanaDir = "."
|
||||||
|
|
||||||
|
paths := []string{
|
||||||
|
"packages/grafana-ui/dist/storybook/index.html",
|
||||||
|
"packages/grafana-ui/dist/storybook/iframe.html"}
|
||||||
|
for _, p := range paths {
|
||||||
|
exists, err := fs.Exists(filepath.Join(grafanaDir, p))
|
||||||
|
if err != nil {
|
||||||
|
return cli.Exit(fmt.Sprintf("failed to verify Storybook build: %s", err), 1)
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return fmt.Errorf("failed to verify Storybook build, missing %q", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Successfully verified Storybook integrity")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+14
-16
@@ -1,20 +1,18 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Version string
|
Version string
|
||||||
Bucket string
|
Bucket string
|
||||||
DebRepoBucket string
|
DebRepoBucket string
|
||||||
DebDBBucket string
|
DebDBBucket string
|
||||||
RPMRepoBucket string
|
RPMRepoBucket string
|
||||||
GPGPassPath string
|
GPGPassPath string
|
||||||
GPGPrivateKey string
|
GPGPrivateKey string
|
||||||
GPGPublicKey string
|
GPGPublicKey string
|
||||||
GCPKeyFile string
|
NumWorkers int
|
||||||
NumWorkers int
|
GitHubUser string
|
||||||
GitHubUser string
|
GitHubToken string
|
||||||
GitHubToken string
|
PullEnterprise bool
|
||||||
PullEnterprise bool
|
PackageVersion string
|
||||||
NetworkConcurrency bool
|
SignPackages bool
|
||||||
PackageVersion string
|
|
||||||
SignPackages bool
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/droneutil"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateMetadata(c *cli.Context) (Metadata, error) {
|
||||||
|
var metadata Metadata
|
||||||
|
version := ""
|
||||||
|
|
||||||
|
event, err := droneutil.GetDroneEventFromEnv()
|
||||||
|
if err != nil {
|
||||||
|
return Metadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tag, ok := os.LookupEnv("DRONE_TAG")
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("DRONE_TAG envvar not present, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var releaseMode ReleaseMode
|
||||||
|
switch event {
|
||||||
|
case string(PullRequestMode):
|
||||||
|
releaseMode = ReleaseMode{Mode: PullRequestMode}
|
||||||
|
case Push:
|
||||||
|
mode, err := CheckDroneTargetBranch()
|
||||||
|
if err != nil {
|
||||||
|
return Metadata{}, err
|
||||||
|
}
|
||||||
|
releaseMode = ReleaseMode{Mode: mode}
|
||||||
|
case Custom:
|
||||||
|
if edition, _ := os.LookupEnv("EDITION"); edition == string(EditionEnterprise2) {
|
||||||
|
releaseMode = ReleaseMode{Mode: Enterprise2Mode}
|
||||||
|
if tag != "" {
|
||||||
|
version = strings.TrimPrefix(tag, "v")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mode, err := CheckDroneTargetBranch()
|
||||||
|
if err != nil {
|
||||||
|
return Metadata{}, err
|
||||||
|
}
|
||||||
|
// if there is a custom event targeting the main branch, that's an enterprise downstream build
|
||||||
|
if mode == MainBranch {
|
||||||
|
releaseMode = ReleaseMode{Mode: DownstreamMode}
|
||||||
|
} else {
|
||||||
|
releaseMode = ReleaseMode{Mode: mode}
|
||||||
|
}
|
||||||
|
case Tag, Promote:
|
||||||
|
if tag == "" {
|
||||||
|
return Metadata{}, fmt.Errorf("DRONE_TAG envvar not present for a tag/promotion event, %w", err)
|
||||||
|
}
|
||||||
|
version = strings.TrimPrefix(tag, "v")
|
||||||
|
mode, err := CheckSemverSuffix()
|
||||||
|
if err != nil {
|
||||||
|
return Metadata{}, err
|
||||||
|
}
|
||||||
|
releaseMode = mode
|
||||||
|
case Cronjob:
|
||||||
|
releaseMode = ReleaseMode{Mode: CronjobMode}
|
||||||
|
}
|
||||||
|
|
||||||
|
if version == "" {
|
||||||
|
version, err = generateVersionFromBuildID()
|
||||||
|
if err != nil {
|
||||||
|
return Metadata{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCommit, err := GetDroneCommit()
|
||||||
|
if err != nil {
|
||||||
|
return Metadata{}, err
|
||||||
|
}
|
||||||
|
metadata = Metadata{
|
||||||
|
GrafanaVersion: version,
|
||||||
|
ReleaseMode: releaseMode,
|
||||||
|
GrabplVersion: c.App.Version,
|
||||||
|
CurrentCommit: currentCommit,
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("building Grafana version: %s, release mode: %+v", metadata.GrafanaVersion, metadata.ReleaseMode)
|
||||||
|
|
||||||
|
return metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateVersionFromBuildID() (string, error) {
|
||||||
|
buildID, ok := os.LookupEnv("DRONE_BUILD_NUMBER")
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("unable to get DRONE_BUILD_NUMBER environmental variable")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
version, err := GetGrafanaVersion(buildID, ".")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DroneBuildEvent = "DRONE_BUILD_EVENT"
|
||||||
|
DroneTargetBranch = "DRONE_TARGET_BRANCH"
|
||||||
|
DroneTag = "DRONE_TAG"
|
||||||
|
DroneSemverPrerelease = "DRONE_SEMVER_PRERELEASE"
|
||||||
|
DroneBuildNumber = "DRONE_BUILD_NUMBER"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hashedGrafanaVersion = "9.2.0-12345pre"
|
||||||
|
versionedBranch = "v9.2.x"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetMetadata(t *testing.T) {
|
||||||
|
tcs := []struct {
|
||||||
|
envMap map[string]string
|
||||||
|
expVersion string
|
||||||
|
mode ReleaseMode
|
||||||
|
}{
|
||||||
|
{map[string]string{DroneBuildEvent: PullRequest, DroneTargetBranch: "", DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, ReleaseMode{Mode: PullRequestMode}},
|
||||||
|
{map[string]string{DroneBuildEvent: Push, DroneTargetBranch: versionedBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, ReleaseMode{Mode: ReleaseBranchMode}},
|
||||||
|
{map[string]string{DroneBuildEvent: Push, DroneTargetBranch: MainBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, ReleaseMode{Mode: MainMode}},
|
||||||
|
{map[string]string{DroneBuildEvent: Custom, DroneTargetBranch: versionedBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, ReleaseMode{Mode: ReleaseBranchMode}},
|
||||||
|
{map[string]string{DroneBuildEvent: Custom, DroneTargetBranch: MainBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, hashedGrafanaVersion, ReleaseMode{Mode: DownstreamMode}},
|
||||||
|
{map[string]string{DroneBuildEvent: Custom, DroneTargetBranch: MainBranch, DroneTag: "", DroneSemverPrerelease: "", DroneBuildNumber: "12345", "EDITION": string(EditionEnterprise2)}, hashedGrafanaVersion, ReleaseMode{Mode: Enterprise2Mode}},
|
||||||
|
{map[string]string{DroneBuildEvent: Tag, DroneTargetBranch: "", DroneTag: "v9.2.0", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, "9.2.0", ReleaseMode{Mode: TagMode, IsBeta: false, IsTest: false}},
|
||||||
|
{map[string]string{DroneBuildEvent: Tag, DroneTargetBranch: "", DroneTag: "v9.2.0-beta", DroneSemverPrerelease: "beta", DroneBuildNumber: "12345"}, "9.2.0-beta", ReleaseMode{Mode: TagMode, IsBeta: true, IsTest: false}},
|
||||||
|
{map[string]string{DroneBuildEvent: Tag, DroneTargetBranch: "", DroneTag: "v9.2.0-test", DroneSemverPrerelease: "test", DroneBuildNumber: "12345"}, "9.2.0-test", ReleaseMode{Mode: TagMode, IsBeta: false, IsTest: true}},
|
||||||
|
{map[string]string{DroneBuildEvent: Promote, DroneTargetBranch: "", DroneTag: "v9.2.0", DroneSemverPrerelease: "", DroneBuildNumber: "12345"}, "9.2.0", ReleaseMode{Mode: TagMode, IsBeta: false, IsTest: false}},
|
||||||
|
{map[string]string{DroneBuildEvent: Promote, DroneTargetBranch: "", DroneTag: "v9.2.0-beta", DroneSemverPrerelease: "beta", DroneBuildNumber: "12345"}, "9.2.0-beta", ReleaseMode{Mode: TagMode, IsBeta: true, IsTest: false}},
|
||||||
|
{map[string]string{DroneBuildEvent: Promote, DroneTargetBranch: "", DroneTag: "v9.2.0-test", DroneSemverPrerelease: "test", DroneBuildNumber: "12345"}, "9.2.0-test", ReleaseMode{Mode: TagMode, IsBeta: false, IsTest: true}},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), &flag.FlagSet{}, nil)
|
||||||
|
for _, tc := range tcs {
|
||||||
|
t.Run("Should return valid metadata, ", func(t *testing.T) {
|
||||||
|
setUpEnv(t, tc.envMap)
|
||||||
|
testMetadata(t, ctx, tc.expVersion, tc.mode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMetadata(t *testing.T, ctx *cli.Context, version string, releaseMode ReleaseMode) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
metadata, err := GenerateMetadata(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Run("with a valid version", func(t *testing.T) {
|
||||||
|
expVersion := metadata.GrafanaVersion
|
||||||
|
require.Equal(t, expVersion, version)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("with a valid release mode from the built-in list", func(t *testing.T) {
|
||||||
|
expMode := metadata.ReleaseMode
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expMode, releaseMode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpEnv(t *testing.T, envMap map[string]string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
os.Clearenv()
|
||||||
|
err := os.Setenv("DRONE_COMMIT", "abcd12345")
|
||||||
|
require.NoError(t, err)
|
||||||
|
for k, v := range envMap {
|
||||||
|
err := os.Setenv(k, v)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"version": "9.2.0-pre"
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
@@ -100,8 +102,8 @@ func GetGrafanaVersion(buildID, grafanaDir string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CheckDroneTargetBranch() (VersionMode, error) {
|
func CheckDroneTargetBranch() (VersionMode, error) {
|
||||||
|
rePRCheckBranch := git.PRCheckRegexp()
|
||||||
reRlsBranch := regexp.MustCompile(`^v\d+\.\d+\.x$`)
|
reRlsBranch := regexp.MustCompile(`^v\d+\.\d+\.x$`)
|
||||||
rePRCheckBranch := regexp.MustCompile(`^pr-check-\d+`)
|
|
||||||
target := os.Getenv("DRONE_TARGET_BRANCH")
|
target := os.Getenv("DRONE_TARGET_BRANCH")
|
||||||
if target == "" {
|
if target == "" {
|
||||||
return "", fmt.Errorf("failed to get DRONE_TARGET_BRANCH environmental variable")
|
return "", fmt.Errorf("failed to get DRONE_TARGET_BRANCH environmental variable")
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ const (
|
|||||||
TagMode VersionMode = "release"
|
TagMode VersionMode = "release"
|
||||||
ReleaseBranchMode VersionMode = "branch"
|
ReleaseBranchMode VersionMode = "branch"
|
||||||
PullRequestMode VersionMode = "pull_request"
|
PullRequestMode VersionMode = "pull_request"
|
||||||
CustomMode VersionMode = "custom"
|
DownstreamMode VersionMode = "downstream"
|
||||||
|
Enterprise2Mode VersionMode = "enterprise2"
|
||||||
CronjobMode VersionMode = "cron"
|
CronjobMode VersionMode = "cron"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ var Versions = VersionMap{
|
|||||||
Storybook: "grafana-storybook",
|
Storybook: "grafana-storybook",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CustomMode: {
|
DownstreamMode: {
|
||||||
Variants: []Variant{
|
Variants: []Variant{
|
||||||
VariantArmV6,
|
VariantArmV6,
|
||||||
VariantArmV7,
|
VariantArmV7,
|
||||||
@@ -165,4 +165,42 @@ var Versions = VersionMap{
|
|||||||
StorybookSrcDir: "artifacts/storybook",
|
StorybookSrcDir: "artifacts/storybook",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Enterprise2Mode: {
|
||||||
|
Variants: []Variant{
|
||||||
|
VariantArmV6,
|
||||||
|
VariantArmV7,
|
||||||
|
VariantArmV7Musl,
|
||||||
|
VariantArm64,
|
||||||
|
VariantArm64Musl,
|
||||||
|
VariantDarwinAmd64,
|
||||||
|
VariantWindowsAmd64,
|
||||||
|
VariantLinuxAmd64,
|
||||||
|
VariantLinuxAmd64Musl,
|
||||||
|
},
|
||||||
|
PluginSignature: PluginSignature{
|
||||||
|
Sign: true,
|
||||||
|
AdminSign: true,
|
||||||
|
},
|
||||||
|
Docker: Docker{
|
||||||
|
ShouldSave: true,
|
||||||
|
Architectures: []Architecture{
|
||||||
|
ArchAMD64,
|
||||||
|
ArchARM64,
|
||||||
|
ArchARMv7,
|
||||||
|
},
|
||||||
|
Distribution: []Distribution{
|
||||||
|
Alpine,
|
||||||
|
Ubuntu,
|
||||||
|
},
|
||||||
|
PrereleaseBucket: "grafana-prerelease/artifacts/docker",
|
||||||
|
},
|
||||||
|
Buckets: Buckets{
|
||||||
|
Artifacts: "grafana-prerelease/artifacts/downloads",
|
||||||
|
ArtifactsEnterprise2: "grafana-prerelease/artifacts/downloads-enterprise2",
|
||||||
|
CDNAssets: "grafana-prerelease",
|
||||||
|
CDNAssetsDir: "artifacts/static-assets",
|
||||||
|
Storybook: "grafana-prerelease",
|
||||||
|
StorybookSrcDir: "artifacts/storybook",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ func BuildImage(version string, arch config.Architecture, grafanaDir string, use
|
|||||||
var additionalDockerRepo string
|
var additionalDockerRepo string
|
||||||
var tags []string
|
var tags []string
|
||||||
var imageFileBase string
|
var imageFileBase string
|
||||||
|
var dockerEnterprise2Repo string
|
||||||
|
if repo, ok := os.LookupEnv("DOCKER_ENTERPRISE2_REPO"); ok {
|
||||||
|
dockerEnterprise2Repo = repo
|
||||||
|
}
|
||||||
|
|
||||||
switch edition {
|
switch edition {
|
||||||
case config.EditionOSS:
|
case config.EditionOSS:
|
||||||
dockerRepo = "grafana/grafana-image-tags"
|
dockerRepo = "grafana/grafana-image-tags"
|
||||||
@@ -94,6 +99,10 @@ func BuildImage(version string, arch config.Architecture, grafanaDir string, use
|
|||||||
dockerRepo = "grafana/grafana-enterprise-image-tags"
|
dockerRepo = "grafana/grafana-enterprise-image-tags"
|
||||||
imageFileBase = "grafana-enterprise"
|
imageFileBase = "grafana-enterprise"
|
||||||
editionStr = "-enterprise"
|
editionStr = "-enterprise"
|
||||||
|
case config.EditionEnterprise2:
|
||||||
|
dockerRepo = dockerEnterprise2Repo
|
||||||
|
imageFileBase = "grafana-enterprise2"
|
||||||
|
editionStr = "-enterprise2"
|
||||||
default:
|
default:
|
||||||
return []string{}, fmt.Errorf("unrecognized edition %s", edition)
|
return []string{}, fmt.Errorf("unrecognized edition %s", edition)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tries = 3
|
||||||
|
sleepTime = 30
|
||||||
|
)
|
||||||
|
|
||||||
|
func PushImage(newImage string) error {
|
||||||
|
var err error
|
||||||
|
for i := 0; i < tries; i++ {
|
||||||
|
log.Printf("push attempt #%d...", i+1)
|
||||||
|
var out []byte
|
||||||
|
cmd := exec.Command("docker", "push", newImage)
|
||||||
|
cmd.Dir = "."
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("output: %s", out)
|
||||||
|
log.Printf("sleep for %d, before retrying...", sleepTime)
|
||||||
|
time.Sleep(sleepTime * time.Second)
|
||||||
|
} else {
|
||||||
|
log.Printf("Successfully pushed %s!", newImage)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error pushing images to DockerHub: %q", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func PushManifest(manifest string) error {
|
||||||
|
log.Printf("Pushing Docker manifest %s...", manifest)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for i := 0; i < tries; i++ {
|
||||||
|
log.Printf("push attempt #%d...", i+1)
|
||||||
|
var out []byte
|
||||||
|
cmd := exec.Command("docker", "manifest", "push", manifest)
|
||||||
|
cmd.Env = append(os.Environ(), "DOCKER_CLI_EXPERIMENTAL=enabled")
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("output: %s", out)
|
||||||
|
log.Printf("sleep for %d, before retrying...", sleepTime)
|
||||||
|
time.Sleep(sleepTime * time.Second)
|
||||||
|
} else {
|
||||||
|
log.Printf("Successful manifest push! %s", string(out))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to push manifest, err: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package env
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lookup is the equivalent of os.LookupEnv, only you are able to provide the list of environment variables.
|
||||||
|
// To use this as os.LookupEnv would be used, simply call
|
||||||
|
// `env.Lookup("ENVIRONMENT_VARIABLE", os.Environ())`
|
||||||
|
func Lookup(name string, vars []string) (string, bool) {
|
||||||
|
for _, v := range vars {
|
||||||
|
if strings.HasPrefix(v, name) {
|
||||||
|
return strings.TrimPrefix(v, name+"="), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
Vendored
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package env_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/env"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLookup(t *testing.T) {
|
||||||
|
values := []string{"ENV_1=a", "ENV_2=b", "ENV_3=c", "ENV_4_TEST="}
|
||||||
|
|
||||||
|
{
|
||||||
|
v, ok := env.Lookup("ENV_1", values)
|
||||||
|
require.Equal(t, v, "a")
|
||||||
|
require.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
v, ok := env.Lookup("ENV_2", values)
|
||||||
|
require.Equal(t, v, "b")
|
||||||
|
require.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
v, ok := env.Lookup("ENV_3", values)
|
||||||
|
require.Equal(t, v, "c")
|
||||||
|
require.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
v, ok := env.Lookup("ENV_4_TEST", values)
|
||||||
|
require.Equal(t, v, "")
|
||||||
|
require.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
v, ok := env.Lookup("NOT_THERE", values)
|
||||||
|
require.Equal(t, v, "")
|
||||||
|
require.False(t, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v45/github"
|
||||||
|
"github.com/grafana/grafana/pkg/build/stringutil"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MainBranch = "main"
|
||||||
|
HomeDir = "."
|
||||||
|
RepoOwner = "grafana"
|
||||||
|
OSSRepo = "grafana"
|
||||||
|
EnterpriseRepo = "grafana-enterprise"
|
||||||
|
EnterpriseCheckName = "Grafana Enterprise"
|
||||||
|
EnterpriseCheckDescription = "Downstream tests to ensure that your changes are compatible with Grafana Enterprise"
|
||||||
|
)
|
||||||
|
|
||||||
|
var EnterpriseCheckLabels = []string{"enterprise-ok", "enterprise-failed", "enterprise-override"}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrorNoDroneBuildLink = errors.New("no drone build link")
|
||||||
|
)
|
||||||
|
|
||||||
|
type GitService interface {
|
||||||
|
DeleteRef(ctx context.Context, owner string, repo string, ref string) (*github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type LabelsService interface {
|
||||||
|
ListLabelsByIssue(ctx context.Context, owner string, repo string, number int, opts *github.ListOptions) ([]*github.Label, *github.Response, error)
|
||||||
|
RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*github.Response, error)
|
||||||
|
AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*github.Label, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommentService interface {
|
||||||
|
CreateComment(ctx context.Context, owner string, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatusesService interface {
|
||||||
|
CreateStatus(ctx context.Context, owner, repo, ref string, status *github.RepoStatus) (*github.RepoStatus, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGitHubClient creates a new Client using the provided GitHub token if not empty.
|
||||||
|
func NewGitHubClient(ctx context.Context, token string) *github.Client {
|
||||||
|
var tc *http.Client
|
||||||
|
if token != "" {
|
||||||
|
ts := oauth2.StaticTokenSource(&oauth2.Token{
|
||||||
|
AccessToken: token,
|
||||||
|
})
|
||||||
|
tc = oauth2.NewClient(ctx, ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return github.NewClient(tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PRCheckRegexp() *regexp.Regexp {
|
||||||
|
reBranch, err := regexp.Compile(`^prc-([0-9]+)-([A-Za-z0-9]+)\/(.+)$`)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to compile regexp: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return reBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddLabelToPR(ctx context.Context, client LabelsService, prID int, newLabel string) error {
|
||||||
|
// Check existing labels
|
||||||
|
labels, _, err := client.ListLabelsByIssue(ctx, RepoOwner, OSSRepo, prID, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate := false
|
||||||
|
for _, label := range labels {
|
||||||
|
if *label.Name == newLabel {
|
||||||
|
duplicate = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete existing "enterprise-xx" labels
|
||||||
|
if stringutil.Contains(EnterpriseCheckLabels, *label.Name) {
|
||||||
|
_, err := client.RemoveLabelForIssue(ctx, RepoOwner, OSSRepo, prID, *label.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if duplicate {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = client.AddLabelsToIssue(ctx, RepoOwner, OSSRepo, prID, []string{newLabel})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteEnterpriseBranch(ctx context.Context, client GitService, branchName string) error {
|
||||||
|
ref := "heads/" + branchName
|
||||||
|
if _, err := client.DeleteRef(ctx, RepoOwner, EnterpriseRepo, ref); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEnterpriseStatus sets the status on a commit for the enterprise build check.
|
||||||
|
func CreateEnterpriseStatus(ctx context.Context, client StatusesService, sha, link, status string) (*github.RepoStatus, error) {
|
||||||
|
check, _, err := client.CreateStatus(ctx, RepoOwner, OSSRepo, sha, &github.RepoStatus{
|
||||||
|
Context: github.String(EnterpriseCheckName),
|
||||||
|
Description: github.String(EnterpriseCheckDescription),
|
||||||
|
TargetURL: github.String(link),
|
||||||
|
State: github.String(status),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return check, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateEnterpriseBuildFailedComment(ctx context.Context, client CommentService, link string, prID int) error {
|
||||||
|
body := fmt.Sprintf("Drone build failed: %s", link)
|
||||||
|
|
||||||
|
_, _, err := client.CreateComment(ctx, RepoOwner, OSSRepo, prID, &github.IssueComment{
|
||||||
|
Body: &body,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package git_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v45/github"
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestChecksService struct {
|
||||||
|
CreateCheckRunError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestChecksService) CreateStatus(ctx context.Context, owner, repo, ref string, status *github.RepoStatus) (*github.RepoStatus, *github.Response, error) {
|
||||||
|
if s.CreateCheckRunError != nil {
|
||||||
|
return nil, nil, s.CreateCheckRunError
|
||||||
|
}
|
||||||
|
|
||||||
|
return &github.RepoStatus{
|
||||||
|
ID: github.Int64(1),
|
||||||
|
URL: status.URL,
|
||||||
|
}, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateEnterpriseRepoStatus(t *testing.T) {
|
||||||
|
t.Run("It should create a repo status", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
client = &TestChecksService{}
|
||||||
|
link = "http://example.com"
|
||||||
|
sha = "1234"
|
||||||
|
)
|
||||||
|
|
||||||
|
_, err := git.CreateEnterpriseStatus(ctx, client, link, sha, "success")
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
t.Run("It should return an error if GitHub fails to create the status", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
createCheckError = errors.New("create check run error")
|
||||||
|
client = &TestChecksService{
|
||||||
|
CreateCheckRunError: createCheckError,
|
||||||
|
}
|
||||||
|
link = "http://example.com"
|
||||||
|
sha = "1234"
|
||||||
|
)
|
||||||
|
|
||||||
|
_, err := git.CreateEnterpriseStatus(ctx, client, link, sha, "success")
|
||||||
|
require.ErrorIs(t, err, createCheckError)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package git_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v45/github"
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestLabelsService struct {
|
||||||
|
Labels []*github.Label
|
||||||
|
ListLabelsError error
|
||||||
|
RemoveLabelError error
|
||||||
|
AddLabelsError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestLabelsService) ListLabelsByIssue(ctx context.Context, owner string, repo string, number int, opts *github.ListOptions) ([]*github.Label, *github.Response, error) {
|
||||||
|
if s.ListLabelsError != nil {
|
||||||
|
return nil, nil, s.ListLabelsError
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := s.Labels
|
||||||
|
if labels == nil {
|
||||||
|
labels = []*github.Label{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestLabelsService) RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*github.Response, error) {
|
||||||
|
if s.RemoveLabelError != nil {
|
||||||
|
return nil, s.RemoveLabelError
|
||||||
|
}
|
||||||
|
|
||||||
|
return &github.Response{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestLabelsService) AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*github.Label, *github.Response, error) {
|
||||||
|
if s.AddLabelsError != nil {
|
||||||
|
return nil, nil, s.AddLabelsError
|
||||||
|
}
|
||||||
|
|
||||||
|
l := make([]*github.Label, len(labels))
|
||||||
|
for i, v := range labels {
|
||||||
|
l[i] = &github.Label{
|
||||||
|
Name: github.String(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddLabelToPR(t *testing.T) {
|
||||||
|
t.Run("It should add a label to a pull request", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
client = &TestLabelsService{}
|
||||||
|
pr = 20
|
||||||
|
label = "test-label"
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, git.AddLabelToPR(ctx, client, pr, label))
|
||||||
|
})
|
||||||
|
t.Run("It should not return an error if the label already exists", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
client = &TestLabelsService{
|
||||||
|
Labels: []*github.Label{
|
||||||
|
{
|
||||||
|
Name: github.String("test-label"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pr = 20
|
||||||
|
label = "test-label"
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, git.AddLabelToPR(ctx, client, pr, label))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("It should return an error if GitHub returns an error when listing labels", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
listLabelsError = errors.New("list labels error")
|
||||||
|
client = &TestLabelsService{
|
||||||
|
ListLabelsError: listLabelsError,
|
||||||
|
Labels: []*github.Label{},
|
||||||
|
}
|
||||||
|
pr = 20
|
||||||
|
label = "test-label"
|
||||||
|
)
|
||||||
|
|
||||||
|
require.ErrorIs(t, git.AddLabelToPR(ctx, client, pr, label), listLabelsError)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("It should not return an error if there are existing enterprise-check labels.", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
client = &TestLabelsService{
|
||||||
|
Labels: []*github.Label{
|
||||||
|
{
|
||||||
|
Name: github.String("enterprise-failed"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pr = 20
|
||||||
|
label = "test-label"
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, git.AddLabelToPR(ctx, client, pr, label))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("It should return an error if GitHub returns an error when removing existing enterprise-check labels", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
removeLabelError = errors.New("remove label error")
|
||||||
|
client = &TestLabelsService{
|
||||||
|
RemoveLabelError: removeLabelError,
|
||||||
|
Labels: []*github.Label{
|
||||||
|
{
|
||||||
|
Name: github.String("enterprise-failed"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pr = 20
|
||||||
|
label = "test-label"
|
||||||
|
)
|
||||||
|
|
||||||
|
require.ErrorIs(t, git.AddLabelToPR(ctx, client, pr, label), removeLabelError)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package git_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/git"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPRCheckRegexp(t *testing.T) {
|
||||||
|
type match struct {
|
||||||
|
String string
|
||||||
|
Commit string
|
||||||
|
Branch string
|
||||||
|
PR string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
shouldMatch = []match{
|
||||||
|
{
|
||||||
|
String: "prc-1-a1b2c3d4/branch-name",
|
||||||
|
Branch: "branch-name",
|
||||||
|
Commit: "a1b2c3d4",
|
||||||
|
PR: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
String: "prc-111-a1b2c3d4/branch/name",
|
||||||
|
Branch: "branch/name",
|
||||||
|
Commit: "a1b2c3d4",
|
||||||
|
PR: "111",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
String: "prc-102930122-a1b2c3d4/branch-name",
|
||||||
|
Branch: "branch-name",
|
||||||
|
Commit: "a1b2c3d4",
|
||||||
|
PR: "102930122",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldNotMatch = []string{"prc-a/branch", "km/test", "test", "prc", "prc/test", "price"}
|
||||||
|
)
|
||||||
|
|
||||||
|
regex := git.PRCheckRegexp()
|
||||||
|
|
||||||
|
for _, v := range shouldMatch {
|
||||||
|
assert.Truef(t, regex.MatchString(v.String), "regex '%s' should match %s", regex.String(), v)
|
||||||
|
m := regex.FindStringSubmatch(v.String)
|
||||||
|
assert.Equal(t, m[1], v.PR)
|
||||||
|
assert.Equal(t, m[2], v.Commit)
|
||||||
|
assert.Equal(t, m[3], v.Branch)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range shouldNotMatch {
|
||||||
|
assert.False(t, regex.MatchString(v), "regex '%s' should not match %s", regex.String(), v)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package lerna
|
package lerna
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@@ -9,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/config"
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
|
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BuildFrontendPackages will bump the version for the package to the latest canary build
|
// BuildFrontendPackages will bump the version for the package to the latest canary build
|
||||||
@@ -56,3 +58,29 @@ func GetLernaVersion(grafanaDir string) (string, error) {
|
|||||||
}
|
}
|
||||||
return strings.TrimSpace(version), nil
|
return strings.TrimSpace(version), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PackFrontendPackages(ctx context.Context, tag, grafanaDir, artifactsDir string) error {
|
||||||
|
exists, err := fsutil.Exists(artifactsDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
err = os.RemoveAll(artifactsDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// nolint:gosec
|
||||||
|
if err = os.MkdirAll(artifactsDir, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, "yarn", "lerna", "exec", "--no-private", "--", "yarn", "pack", "--out", fmt.Sprintf("../../npm-artifacts/%%s-%v.tgz", tag))
|
||||||
|
cmd.Dir = grafanaDir
|
||||||
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("command '%s' failed to run, output: %s, err: %q", cmd.String(), output, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,240 @@
|
|||||||
|
package npm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/gcloud/storage"
|
||||||
|
"github.com/grafana/grafana/pkg/build/lerna"
|
||||||
|
"github.com/grafana/grafana/pkg/build/versions"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GrafanaDir = "."
|
||||||
|
const NpmArtifactDir = "./npm-artifacts"
|
||||||
|
|
||||||
|
// TODO: could this be replaced by `yarn lerna list -p` ?
|
||||||
|
var packages = []string{
|
||||||
|
"@grafana/ui",
|
||||||
|
"@grafana/data",
|
||||||
|
"@grafana/toolkit",
|
||||||
|
"@grafana/runtime",
|
||||||
|
"@grafana/e2e",
|
||||||
|
"@grafana/e2e-selectors",
|
||||||
|
"@grafana/schema",
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublishNpmPackages will publish local NPM packages to NPM registry.
|
||||||
|
func PublishNpmPackages(ctx context.Context, tag string) error {
|
||||||
|
version, err := versions.GetVersion(tag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Grafana version: %s", version.Version)
|
||||||
|
|
||||||
|
if err := setNpmCredentials(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
npmArtifacts, err := storage.ListLocalFiles(NpmArtifactDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, packedFile := range npmArtifacts {
|
||||||
|
// nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, "npm", "publish", packedFile.FullPath, "--tag", version.Channel)
|
||||||
|
cmd.Dir = GrafanaDir
|
||||||
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("command '%s' failed to run, output: %s, err: %q", cmd.String(), out, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateTag(ctx, version, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreNpmPackages will store local NPM packages in GCS bucket `bucketName`.
|
||||||
|
func StoreNpmPackages(ctx context.Context, tag, bucketName string) error {
|
||||||
|
err := lerna.PackFrontendPackages(ctx, tag, GrafanaDir, NpmArtifactDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
gcs, err := storage.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket := gcs.Bucket(bucketName)
|
||||||
|
bucketPath := fmt.Sprintf("artifacts/npm/%s/", tag)
|
||||||
|
if err = gcs.CopyLocalDir(ctx, NpmArtifactDir, bucket, bucketPath, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Print("Successfully stored npm packages!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchNpmPackages will store NPM packages stored in GCS bucket `bucketName` on local disk in `frontend.NpmArtifactDir`.
|
||||||
|
func FetchNpmPackages(ctx context.Context, tag, bucketName string) error {
|
||||||
|
gcs, err := storage.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bucketPath := fmt.Sprintf("artifacts/npm/%s/", tag)
|
||||||
|
bucket := gcs.Bucket(bucketName)
|
||||||
|
err = gcs.DownloadDirectory(ctx, bucket, NpmArtifactDir, storage.FilesFilter{
|
||||||
|
Prefix: bucketPath,
|
||||||
|
FileExts: []string{".tgz"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateTag will move next or latest npm dist-tags, if needed.
|
||||||
|
//
|
||||||
|
// Note: This function makes the assumption that npm dist-tags has already
|
||||||
|
// been updated and hence why move of dist-tags not always happens:
|
||||||
|
//
|
||||||
|
// If stable the dist-tag latest was used.
|
||||||
|
// If beta the dist-tag next was used.
|
||||||
|
//
|
||||||
|
// Scenarios:
|
||||||
|
//
|
||||||
|
// 1. Releasing a newer stable than the current stable
|
||||||
|
// Latest and next is 9.1.5.
|
||||||
|
// 9.1.6 is released, latest and next should point to 9.1.6.
|
||||||
|
// The next dist-tag is moved to point to 9.1.6.
|
||||||
|
//
|
||||||
|
// 2. Releasing during an active beta period:
|
||||||
|
// Latest and next is 9.1.6.
|
||||||
|
// 9.2.0-beta1 is released, the latest should stay on 9.1.6, next should point to 9.2.0-beta1
|
||||||
|
// No move of dist-tags
|
||||||
|
// 9.1.7 is relased, the latest should point to 9.1.7, next should stay to 9.2.0-beta1
|
||||||
|
// No move of dist-tags
|
||||||
|
// Next week 9.2.0-beta2 is released, the latest should point to 9.1.7, next should point to 9.2.0-beta2
|
||||||
|
// No move of dist-tags
|
||||||
|
// In two weeks 9.2.0 stable is relased, the latest and next should point to 9.2.0.
|
||||||
|
// The next dist-tag is moved to point to 9.2.0.
|
||||||
|
//
|
||||||
|
// 3. Releasing an older stable than the current stable
|
||||||
|
// Latest and next is 9.2.0.
|
||||||
|
// Next 9.1.8 is released, latest should point to 9.2.0, next should point to 9.2.0
|
||||||
|
// The latest dist-tag is moved to point to 9.2.0.
|
||||||
|
func updateTag(ctx context.Context, version *versions.Version, releaseVersion string) error {
|
||||||
|
if version.Channel != versions.Latest {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
latestStableVersion, err := getLatestStableVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
betaVersion, err := getLatestBetaVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
isLatest, err := versions.IsGreaterThanOrEqual(releaseVersion, latestStableVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
isNewerThanLatestBeta, err := versions.IsGreaterThanOrEqual(releaseVersion, betaVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkg := range packages {
|
||||||
|
if !isLatest {
|
||||||
|
err = runMoveLatestNPMTagCommand(ctx, pkg, latestStableVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLatest && isNewerThanLatestBeta {
|
||||||
|
err = runMoveNextNPMTagCommand(ctx, pkg, version.Version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLatestStableVersion() (string, error) {
|
||||||
|
return versions.GetLatestVersion(versions.LatestStableVersionURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLatestBetaVersion() (string, error) {
|
||||||
|
return versions.GetLatestVersion(versions.LatestBetaVersionURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runMoveNextNPMTagCommand(ctx context.Context, pkg string, packageVersion string) error {
|
||||||
|
// nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, "npm", "dist-tag", "add", fmt.Sprintf("%s@%s", pkg, packageVersion), "next")
|
||||||
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("command '%s' failed to run, output: %s, err: %q", cmd.String(), out, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runMoveLatestNPMTagCommand(ctx context.Context, pkg string, latestStableVersion string) error {
|
||||||
|
// nolint:gosec
|
||||||
|
cmd := exec.CommandContext(ctx, "npm", "dist-tag", "add", fmt.Sprintf("%s@%s", pkg, latestStableVersion), "latest")
|
||||||
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("command '%s' failed to run, output: %s, err: %q", cmd.String(), out, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setNpmCredentials Creates a .npmrc file in the users home folder and writes the
|
||||||
|
// necessary credentials to it for publishing packages to the NPM registry.
|
||||||
|
func setNpmCredentials() error {
|
||||||
|
npmToken := strings.TrimSpace(os.Getenv("NPM_TOKEN"))
|
||||||
|
if npmToken == "" {
|
||||||
|
return fmt.Errorf("npm token is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to obtain home directory, err: %q", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
npmPath := filepath.Join(homeDir, ".npmrc")
|
||||||
|
registry := []byte(fmt.Sprintf("//registry.npmjs.org/:_authToken=%s", npmToken))
|
||||||
|
if _, err = os.Stat(npmPath); os.IsNotExist(err) {
|
||||||
|
// nolint:gosec
|
||||||
|
f, err := os.Create(npmPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("couldn't create npmrc file, err: %q", err)
|
||||||
|
}
|
||||||
|
_, err = f.Write(registry)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write to file, err: %q", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
log.Printf("Failed to close file: %s", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
err = os.WriteFile(npmPath, registry, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing to file, err: %q", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -8,10 +8,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/config"
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||||
"github.com/grafana/grafana/pkg/infra/fs"
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeAptlyConf(dbDir, repoDir string) error {
|
func writeAptlyConf(dbDir, repoDir string) error {
|
||||||
@@ -166,7 +167,7 @@ func UpdateDebRepo(cfg PublishConfig, workDir string) error {
|
|||||||
cmd := exec.Command("aptly", "publish", "update", "-batch", passArg, "-force-overwrite", tp,
|
cmd := exec.Command("aptly", "publish", "update", "-batch", passArg, "-force-overwrite", tp,
|
||||||
"filesystem:repo:grafana")
|
"filesystem:repo:grafana")
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("failed to update Debian %q repository: %s", tp, output), 1)
|
return cli.Exit(fmt.Sprintf("failed to update Debian %q repository: %s", tp, output), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +180,7 @@ func UpdateDebRepo(cfg PublishConfig, workDir string) error {
|
|||||||
//nolint:gosec
|
//nolint:gosec
|
||||||
cmd = exec.Command("gsutil", "-m", "rsync", "-r", "-d", dbDir, u)
|
cmd = exec.Command("gsutil", "-m", "rsync", "-r", "-d", dbDir, u)
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("failed to upload Debian repo database to GCS: %s", output), 1)
|
return cli.Exit(fmt.Sprintf("failed to upload Debian repo database to GCS: %s", output), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,14 +194,14 @@ func UpdateDebRepo(cfg PublishConfig, workDir string) error {
|
|||||||
//nolint:gosec
|
//nolint:gosec
|
||||||
cmd = exec.Command("gsutil", "-m", "rsync", "-r", "-d", grafDir, u)
|
cmd = exec.Command("gsutil", "-m", "rsync", "-r", "-d", grafDir, u)
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("failed to upload Debian repo resources to GCS: %s", output), 1)
|
return cli.Exit(fmt.Sprintf("failed to upload Debian repo resources to GCS: %s", output), 1)
|
||||||
}
|
}
|
||||||
allRepoResources := fmt.Sprintf("%s/**/*", u)
|
allRepoResources := fmt.Sprintf("%s/**/*", u)
|
||||||
log.Printf("Setting cache ttl for Debian repo resources on GCS (%s)...\n", allRepoResources)
|
log.Printf("Setting cache ttl for Debian repo resources on GCS (%s)...\n", allRepoResources)
|
||||||
//nolint:gosec
|
//nolint:gosec
|
||||||
cmd = exec.Command("gsutil", "-m", "setmeta", "-h", CacheSettings+cfg.TTL, allRepoResources)
|
cmd = exec.Command("gsutil", "-m", "setmeta", "-h", CacheSettings+cfg.TTL, allRepoResources)
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("failed to set cache ttl for Debian repo resources on GCS: %s", output), 1)
|
return cli.Exit(fmt.Sprintf("failed to set cache ttl for Debian repo resources on GCS: %s", output), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +239,7 @@ func addPkgsToRepo(cfg PublishConfig, workDir, tmpDir, repoName string) error {
|
|||||||
//nolint:gosec
|
//nolint:gosec
|
||||||
cmd := exec.Command("aptly", "repo", "add", "-force-replace", repoName, tmpDir)
|
cmd := exec.Command("aptly", "repo", "add", "-force-replace", repoName, tmpDir)
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return cli.NewExitError(fmt.Sprintf("failed to add packages to local Debian repository: %s", output), 1)
|
return cli.Exit(fmt.Sprintf("failed to add packages to local Debian repository: %s", output), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package packaging_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
|
"github.com/grafana/grafana/pkg/build/packaging"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPackageRegexp(t *testing.T) {
|
||||||
|
t.Run("It should match enterprise2 packages", func(t *testing.T) {
|
||||||
|
rgx := packaging.PackageRegexp(config.EditionEnterprise2)
|
||||||
|
matches := []string{
|
||||||
|
"grafana-enterprise2-1.2.3-4567pre.linux-amd64.tar.gz",
|
||||||
|
"grafana-enterprise2-1.2.3-4567pre.linux-amd64.tar.gz.sha256",
|
||||||
|
}
|
||||||
|
for _, v := range matches {
|
||||||
|
assert.Truef(t, rgx.MatchString(v), "'%s' should match regex '%s'", v, rgx.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -10,12 +10,15 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
// Consider switching this over to a community fork unless there is
|
||||||
|
// an option to move us away from OpenPGP.
|
||||||
|
"golang.org/x/crypto/openpgp" //nolint:staticcheck
|
||||||
|
"golang.org/x/crypto/openpgp/armor" //nolint:staticcheck
|
||||||
|
"golang.org/x/crypto/openpgp/packet" //nolint:staticcheck
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/build/config"
|
"github.com/grafana/grafana/pkg/build/config"
|
||||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||||
"github.com/grafana/grafana/pkg/infra/fs"
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
"golang.org/x/crypto/openpgp"
|
|
||||||
"golang.org/x/crypto/openpgp/armor"
|
|
||||||
"golang.org/x/crypto/openpgp/packet"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// UpdateRPMRepo updates the RPM repository with the new release.
|
// UpdateRPMRepo updates the RPM repository with the new release.
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package stringutil
|
||||||
|
|
||||||
|
func Contains(arr []string, s string) bool {
|
||||||
|
for _, e := range arr {
|
||||||
|
if e == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package versions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
reGrafanaTag = regexp.MustCompile(`^v(\d+\.\d+\.\d+$)`)
|
||||||
|
reGrafanaTagBeta = regexp.MustCompile(`^v(\d+\.\d+\.\d+-beta)`)
|
||||||
|
reGrafanaTagCustom = regexp.MustCompile(`^v(\d+\.\d+\.\d+-\w+)`)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Latest = "latest"
|
||||||
|
Next = "next"
|
||||||
|
Test = "test"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Version struct {
|
||||||
|
Version string
|
||||||
|
Channel string
|
||||||
|
}
|
||||||
|
|
||||||
|
type VersionFromAPI struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LatestGcomAPI = string
|
||||||
|
|
||||||
|
const (
|
||||||
|
LatestStableVersionURL LatestGcomAPI = "https://grafana.com/api/grafana/versions/stable"
|
||||||
|
LatestBetaVersionURL LatestGcomAPI = "https://grafana.com/api/grafana/versions/beta"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetLatestVersion(url LatestGcomAPI) (string, error) {
|
||||||
|
// nolint:gosec
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
log.Printf("Failed to close body: %s", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", fmt.Errorf("server returned non 200 status code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiResponse VersionFromAPI
|
||||||
|
err = json.Unmarshal(body, &apiResponse)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiResponse.Version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsGreaterThanOrEqual semantically checks whether newVersion is greater than or equal to stableVersion.
|
||||||
|
func IsGreaterThanOrEqual(newVersion, stableVersion string) (bool, error) {
|
||||||
|
v1SemVer, err := semver.NewVersion(newVersion)
|
||||||
|
if err != nil {
|
||||||
|
return isGreaterThanOrEqualFourDigit(newVersion, stableVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
v2SemVer, err := semver.NewVersion(stableVersion)
|
||||||
|
if err != nil {
|
||||||
|
return isGreaterThanOrEqualFourDigit(newVersion, stableVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
comp := v1SemVer.Compare(v2SemVer)
|
||||||
|
switch comp {
|
||||||
|
case -1:
|
||||||
|
return false, nil
|
||||||
|
case 1, 0:
|
||||||
|
return true, nil
|
||||||
|
default:
|
||||||
|
return true, fmt.Errorf("unknown comparison value between scemantic versions, err: %q", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fourDigitRe = regexp.MustCompile(`(\d+\.\d+\.\d+)\.(\d+)`)
|
||||||
|
|
||||||
|
func parseFourDigit(version string) (*semver.Version, int, error) {
|
||||||
|
matches := fourDigitRe.FindStringSubmatch(version)
|
||||||
|
if len(matches) < 2 {
|
||||||
|
semVer, err := semver.NewVersion(version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return semVer, 0, nil
|
||||||
|
}
|
||||||
|
semVer, err := semver.NewVersion(matches[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
i, err := strconv.Atoi(matches[2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return semVer, i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGreaterThanOrEqualFourDigit(newVersion, stableVersion string) (bool, error) {
|
||||||
|
newVersionSemVer, newVersionSemVerNo, err := parseFourDigit(newVersion)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stableVersionSemVer, stableVersionSemVerNo, err := parseFourDigit(stableVersion)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if stableVersionSemVer.Original() != newVersionSemVer.Original() {
|
||||||
|
return IsGreaterThanOrEqual(newVersionSemVer.Original(), stableVersionSemVer.Original())
|
||||||
|
}
|
||||||
|
|
||||||
|
return newVersionSemVerNo >= stableVersionSemVerNo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVersion(tag string) (*Version, error) {
|
||||||
|
var version Version
|
||||||
|
switch {
|
||||||
|
case reGrafanaTag.MatchString(tag):
|
||||||
|
version = Version{
|
||||||
|
Version: reGrafanaTag.FindStringSubmatch(tag)[1],
|
||||||
|
Channel: Latest,
|
||||||
|
}
|
||||||
|
case reGrafanaTagBeta.MatchString(tag):
|
||||||
|
version = Version{
|
||||||
|
Version: reGrafanaTagBeta.FindStringSubmatch(tag)[1],
|
||||||
|
Channel: Next,
|
||||||
|
}
|
||||||
|
case reGrafanaTagCustom.MatchString(tag):
|
||||||
|
version = Version{
|
||||||
|
Version: reGrafanaTagCustom.FindStringSubmatch(tag)[1],
|
||||||
|
Channel: Test,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("%s not a supported Grafana version, exitting", tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &version, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package versions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsGreaterThanOrEqual(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
newVersion string
|
||||||
|
stableVersion string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{newVersion: "9.0.0", stableVersion: "8.0.0", expected: true},
|
||||||
|
{newVersion: "6.0.0", stableVersion: "6.0.0", expected: true},
|
||||||
|
{newVersion: "7.0.0", stableVersion: "8.0.0", expected: false},
|
||||||
|
{newVersion: "8.5.0-beta1", stableVersion: "8.0.0", expected: true},
|
||||||
|
{newVersion: "8.5.0", stableVersion: "8.5.0-beta1", expected: true},
|
||||||
|
{newVersion: "9.0.0.1", stableVersion: "9.0.0", expected: true},
|
||||||
|
{newVersion: "9.0.0.2", stableVersion: "9.0.0.1", expected: true},
|
||||||
|
{newVersion: "9.1.0", stableVersion: "9.0.0.1", expected: true},
|
||||||
|
{newVersion: "9.1-0-beta1", stableVersion: "9.0.0.1", expected: true},
|
||||||
|
{newVersion: "9.0.0.1", stableVersion: "9.0.1.1", expected: false},
|
||||||
|
{newVersion: "9.0.1.1", stableVersion: "9.0.0.1", expected: true},
|
||||||
|
{newVersion: "9.0.0.1", stableVersion: "9.0.0.1", expected: true},
|
||||||
|
{newVersion: "7.0.0.1", stableVersion: "8.0.0", expected: false},
|
||||||
|
{newVersion: "9.1-0-beta1", stableVersion: "9.1-0-beta2", expected: false},
|
||||||
|
{newVersion: "9.1-0-beta3", stableVersion: "9.1-0-beta2", expected: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
name := fmt.Sprintf("newVersion %s greater than or equal stableVersion %s = %v", tc.newVersion, tc.stableVersion, tc.expected)
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
result, err := IsGreaterThanOrEqual(tc.newVersion, tc.stableVersion)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.expected, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLatestVersion(t *testing.T) {
|
||||||
|
t.Run("it returns a version", func(t *testing.T) {
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
response := VersionFromAPI{
|
||||||
|
Version: "8.4.0",
|
||||||
|
}
|
||||||
|
jsonRes, err := json.Marshal(&response)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = w.Write(jsonRes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}))
|
||||||
|
version, err := GetLatestVersion(server.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "8.4.0", version)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("it handles non 200 responses", func(t *testing.T) {
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}))
|
||||||
|
_, err := GetLatestVersion(server.URL)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
+2
-1
@@ -75,6 +75,7 @@ beforeEach(() => {
|
|||||||
|
|
||||||
mockPanel = new PanelModel({
|
mockPanel = new PanelModel({
|
||||||
id: 'mockPanelId',
|
id: 'mockPanelId',
|
||||||
|
timezone: 'utc',
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true);
|
jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true);
|
||||||
@@ -145,7 +146,7 @@ describe('SharePublic', () => {
|
|||||||
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
|
await renderSharePublicDashboard({ panel: mockPanel, dashboard: mockDashboard, onDismiss: () => {} });
|
||||||
|
|
||||||
await screen.findByText('Welcome to Grafana public dashboards alpha!');
|
await screen.findByText('Welcome to Grafana public dashboards alpha!');
|
||||||
expect(screen.getByText('2022-08-30 00:00:00 to 2022-09-04 01:59:59')).toBeInTheDocument();
|
expect(screen.getByText('2022-08-30 00:00:00 to 2022-09-04 00:59:59')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
it('when modal is opened, then loader spinner appears and inputs are disabled', async () => {
|
it('when modal is opened, then loader spinner appears and inputs are disabled', async () => {
|
||||||
mockDashboard.meta.hasPublicDashboard = true;
|
mockDashboard.meta.hasPublicDashboard = true;
|
||||||
|
|||||||
@@ -0,0 +1,628 @@
|
|||||||
|
|
||||||
|
events/release.star,6652
|
||||||
|
ver_mode =ver_mode64,1602
|
||||||
|
release_trigger =release_trigger65,1623
|
||||||
|
def store_npm_packages_step():store_npm_packages_step74,1752
|
||||||
|
def retrieve_npm_packages_step():retrieve_npm_packages_step90,2193
|
||||||
|
def release_npm_packages_step():release_npm_packages_step107,2663
|
||||||
|
def oss_pipelines(ver_mode = ver_mode, trigger = release_trigger):oss_pipelines123,3076
|
||||||
|
environment =environment135,3492
|
||||||
|
edition =edition136,3529
|
||||||
|
services =services137,3549
|
||||||
|
volumes =volumes138,3609
|
||||||
|
package_steps =package_steps139,3659
|
||||||
|
publish_steps =publish_steps140,3682
|
||||||
|
should_publish =should_publish141,3705
|
||||||
|
should_upload =should_upload142,3748
|
||||||
|
init_steps =init_steps143,3818
|
||||||
|
build_steps =build_steps152,4033
|
||||||
|
integration_test_steps =integration_test_steps159,4342
|
||||||
|
build_storybook =build_storybook182,5254
|
||||||
|
publish_step =publish_step190,5674
|
||||||
|
store_npm_step =store_npm_step191,5758
|
||||||
|
windows_package_steps =windows_package_steps196,5957
|
||||||
|
windows_pipeline =windows_pipeline198,6044
|
||||||
|
name =name199,6077
|
||||||
|
edition =edition200,6127
|
||||||
|
trigger =trigger201,6154
|
||||||
|
steps =steps202,6181
|
||||||
|
platform =platform203,6256
|
||||||
|
depends_on =depends_on204,6286
|
||||||
|
environment =environment207,6393
|
||||||
|
pipelines =pipelines209,6434
|
||||||
|
name =name211,6470
|
||||||
|
edition =edition212,6550
|
||||||
|
trigger =trigger213,6581
|
||||||
|
services =services214,6612
|
||||||
|
steps =steps215,6639
|
||||||
|
environment =environment216,6717
|
||||||
|
volumes =volumes217,6756
|
||||||
|
name =name225,6970
|
||||||
|
edition =edition226,7038
|
||||||
|
trigger =trigger227,7073
|
||||||
|
services =services228,7108
|
||||||
|
steps =steps229,7145
|
||||||
|
environment =environment230,7329
|
||||||
|
volumes =volumes231,7372
|
||||||
|
deps =deps234,7433
|
||||||
|
def enterprise_pipelines(ver_mode = ver_mode, trigger = release_trigger):enterprise_pipelines247,7856
|
||||||
|
environment =environment259,8284
|
||||||
|
edition =edition260,8328
|
||||||
|
services =services261,8355
|
||||||
|
volumes =volumes262,8415
|
||||||
|
package_steps =package_steps263,8465
|
||||||
|
publish_steps =publish_steps264,8488
|
||||||
|
should_publish =should_publish265,8511
|
||||||
|
should_upload =should_upload266,8554
|
||||||
|
include_enterprise =include_enterprise267,8624
|
||||||
|
edition2 =edition2268,8673
|
||||||
|
init_steps =init_steps269,8702
|
||||||
|
build_steps =build_steps277,8909
|
||||||
|
integration_test_steps =integration_test_steps284,9218
|
||||||
|
build_storybook =build_storybook312,10299
|
||||||
|
publish_step =publish_step324,10892
|
||||||
|
store_npm_step =store_npm_step325,10976
|
||||||
|
windows_package_steps =windows_package_steps330,11175
|
||||||
|
step =step333,11284
|
||||||
|
deps_on_clone_enterprise_step =deps_on_clone_enterprise_step337,11418
|
||||||
|
windows_pipeline =windows_pipeline347,11746
|
||||||
|
name =name348,11779
|
||||||
|
edition =edition349,11836
|
||||||
|
trigger =trigger350,11863
|
||||||
|
steps =steps351,11890
|
||||||
|
platform =platform352,11965
|
||||||
|
depends_on =depends_on353,11995
|
||||||
|
environment =environment356,12109
|
||||||
|
pipelines =pipelines358,12150
|
||||||
|
name =name360,12186
|
||||||
|
edition =edition361,12273
|
||||||
|
trigger =trigger362,12304
|
||||||
|
services =services363,12335
|
||||||
|
steps =steps364,12362
|
||||||
|
environment =environment365,12440
|
||||||
|
volumes =volumes366,12479
|
||||||
|
name =name374,12711
|
||||||
|
edition =edition375,12786
|
||||||
|
trigger =trigger376,12821
|
||||||
|
services =services377,12856
|
||||||
|
steps =steps378,12893
|
||||||
|
environment =environment379,13213
|
||||||
|
volumes =volumes380,13256
|
||||||
|
deps =deps383,13317
|
||||||
|
def enterprise2_pipelines(prefix = "", ver_mode = ver_mode, trigger = release_trigger):enterprise2_pipelines397,13769
|
||||||
|
environment =environment412,14364
|
||||||
|
edition =edition415,14424
|
||||||
|
volumes =volumes416,14451
|
||||||
|
package_steps =package_steps417,14501
|
||||||
|
publish_steps =publish_steps418,14524
|
||||||
|
should_publish =should_publish419,14547
|
||||||
|
should_upload =should_upload420,14590
|
||||||
|
include_enterprise =include_enterprise421,14660
|
||||||
|
edition2 =edition2422,14709
|
||||||
|
init_steps =init_steps423,14738
|
||||||
|
build_steps =build_steps431,14945
|
||||||
|
fetch_images =fetch_images442,15355
|
||||||
|
upload_cdn =upload_cdn444,15497
|
||||||
|
step =step458,16187
|
||||||
|
deps_on_clone_enterprise_step =deps_on_clone_enterprise_step462,16321
|
||||||
|
pipelines =pipelines472,16608
|
||||||
|
name =name474,16644
|
||||||
|
edition =edition475,16742
|
||||||
|
trigger =trigger476,16773
|
||||||
|
services =services477,16804
|
||||||
|
steps =steps478,16831
|
||||||
|
volumes =volumes479,16909
|
||||||
|
environment =environment480,16940
|
||||||
|
def publish_artifacts_step(mode):publish_artifacts_step486,17019
|
||||||
|
security =security487,17053
|
||||||
|
security =security489,17098
|
||||||
|
def publish_artifacts_pipelines(mode):publish_artifacts_pipelines501,17538
|
||||||
|
trigger =trigger502,17577
|
||||||
|
steps =steps506,17655
|
||||||
|
name =name512,17768
|
||||||
|
trigger =trigger513,17820
|
||||||
|
steps =steps514,17847
|
||||||
|
edition =edition515,17870
|
||||||
|
environment =environment516,17895
|
||||||
|
def publish_packages_pipeline():publish_packages_pipeline519,17945
|
||||||
|
trigger =trigger526,18162
|
||||||
|
oss_steps =oss_steps530,18244
|
||||||
|
enterprise_steps =enterprise_steps538,18560
|
||||||
|
deps =deps545,18903
|
||||||
|
name =name552,19062
|
||||||
|
trigger =trigger553,19101
|
||||||
|
steps =steps554,19128
|
||||||
|
edition =edition555,19155
|
||||||
|
depends_on =depends_on556,19180
|
||||||
|
environment =environment557,19207
|
||||||
|
name =name559,19266
|
||||||
|
trigger =trigger560,19312
|
||||||
|
steps =steps561,19339
|
||||||
|
edition =edition562,19373
|
||||||
|
depends_on =depends_on563,19398
|
||||||
|
environment =environment564,19425
|
||||||
|
def publish_npm_pipelines(mode):publish_npm_pipelines567,19482
|
||||||
|
trigger =trigger568,19515
|
||||||
|
steps =steps572,19593
|
||||||
|
name =name580,19772
|
||||||
|
trigger =trigger581,19827
|
||||||
|
steps =steps582,19854
|
||||||
|
edition =edition583,19877
|
||||||
|
environment =environment584,19902
|
||||||
|
def artifacts_page_pipeline():artifacts_page_pipeline587,19952
|
||||||
|
trigger =trigger588,19983
|
||||||
|
name =name593,20087
|
||||||
|
trigger =trigger594,20128
|
||||||
|
steps =steps595,20155
|
||||||
|
edition =edition596,20220
|
||||||
|
environment =environment597,20245
|
||||||
|
def get_e2e_suffix():get_e2e_suffix600,20295
|
||||||
|
|
||||||
|
events/cron.star,1016
|
||||||
|
aquasec_trivy_image =aquasec_trivy_image8,209
|
||||||
|
def cronjobs(edition):cronjobs10,255
|
||||||
|
grafana_com_nightly_pipeline =grafana_com_nightly_pipeline11,278
|
||||||
|
cronName =cronName12,332
|
||||||
|
name =name13,374
|
||||||
|
steps =steps14,412
|
||||||
|
def cron_job_pipeline(cronName, name, steps):cron_job_pipeline24,773
|
||||||
|
def scan_docker_image_pipeline(edition, tag):scan_docker_image_pipeline43,1175
|
||||||
|
edition =edition55,1530
|
||||||
|
edition =edition57,1579
|
||||||
|
docker_image =docker_image59,1608
|
||||||
|
cronName =cronName62,1695
|
||||||
|
name =name63,1725
|
||||||
|
steps =steps64,1775
|
||||||
|
def scan_docker_image_unkown_low_medium_vulnerabilities_step(docker_image):scan_docker_image_unkown_low_medium_vulnerabilities_step71,2047
|
||||||
|
def scan_docker_image_high_critical_vulnerabilities_step(docker_image):scan_docker_image_high_critical_vulnerabilities_step80,2353
|
||||||
|
def slack_job_failed_step(channel, image):slack_job_failed_step89,2646
|
||||||
|
def post_to_grafana_com_step():post_to_grafana_com_step103,3069
|
||||||
|
|
||||||
|
events/main.star,633
|
||||||
|
ver_mode =ver_mode49,966
|
||||||
|
trigger =trigger50,984
|
||||||
|
def main_pipelines(edition):main_pipelines62,1168
|
||||||
|
drone_change_trigger =drone_change_trigger63,1197
|
||||||
|
pipelines =pipelines79,1513
|
||||||
|
name =name89,1951
|
||||||
|
slack_channel =slack_channel90,1994
|
||||||
|
trigger =trigger91,2045
|
||||||
|
template =template92,2089
|
||||||
|
secret =secret93,2135
|
||||||
|
name =name97,2276
|
||||||
|
slack_channel =slack_channel98,2310
|
||||||
|
trigger =trigger99,2366
|
||||||
|
depends_on =depends_on100,2425
|
||||||
|
template =template101,2563
|
||||||
|
secret =secret102,2604
|
||||||
|
|
||||||
|
events/pr.star,252
|
||||||
|
ver_mode =ver_mode48,997
|
||||||
|
trigger =trigger49,1013
|
||||||
|
def pr_pipelines(edition):pr_pipelines62,1198
|
||||||
|
def get_pr_trigger(include_paths = None, exclude_paths = None):get_pr_trigger76,2396
|
||||||
|
paths_ex =paths_ex91,3080
|
||||||
|
paths_in =paths_in92,3115
|
||||||
|
|
||||||
|
services/services.star,225
|
||||||
|
def integration_test_services_volumes():integration_test_services_volumes5,79
|
||||||
|
def integration_test_services(edition):integration_test_services14,292
|
||||||
|
services =services15,332
|
||||||
|
def ldap_service():ldap_service59,1616
|
||||||
|
|
||||||
|
utils/utils.star,561
|
||||||
|
failure_template =failure_template11,191
|
||||||
|
drone_change_template =drone_change_template12,509
|
||||||
|
services =services19,932
|
||||||
|
platform =platform20,955
|
||||||
|
depends_on =depends_on21,983
|
||||||
|
environment =environment22,1008
|
||||||
|
volumes =volumes23,1036
|
||||||
|
platform_conf =platform_conf50,2166
|
||||||
|
platform_conf =platform_conf62,2534
|
||||||
|
pipeline =pipeline70,2713
|
||||||
|
def notify_pipeline(name, slack_channel, trigger, depends_on = [], template = None, secret = None):notify_pipeline105,3545
|
||||||
|
trigger =trigger106,3645
|
||||||
|
|
||||||
|
pipelines/trigger_downstream.star,440
|
||||||
|
trigger =trigger14,249
|
||||||
|
def enterprise_downstream_pipeline(edition, ver_mode):enterprise_downstream_pipeline26,433
|
||||||
|
environment =environment27,488
|
||||||
|
steps =steps28,527
|
||||||
|
deps =deps29,587
|
||||||
|
name =name31,672
|
||||||
|
edition =edition32,714
|
||||||
|
trigger =trigger33,741
|
||||||
|
services =services34,768
|
||||||
|
steps =steps35,791
|
||||||
|
depends_on =depends_on36,814
|
||||||
|
environment =environment37,841
|
||||||
|
|
||||||
|
pipelines/verify_starlark.star,323
|
||||||
|
def verify_starlark(trigger, ver_mode):verify_starlark17,305
|
||||||
|
environment =environment18,345
|
||||||
|
steps =steps19,382
|
||||||
|
name =name26,546
|
||||||
|
edition =edition27,600
|
||||||
|
trigger =trigger28,625
|
||||||
|
services =services29,652
|
||||||
|
steps =steps30,675
|
||||||
|
environment =environment31,698
|
||||||
|
|
||||||
|
pipelines/build.star,508
|
||||||
|
def build_e2e(trigger, ver_mode, edition):build_e2e39,936
|
||||||
|
environment =environment50,1096
|
||||||
|
variants =variants51,1135
|
||||||
|
init_steps =init_steps52,1219
|
||||||
|
build_steps =build_steps61,1491
|
||||||
|
publish_suffix =publish_suffix107,4049
|
||||||
|
publish_suffix =publish_suffix109,4100
|
||||||
|
name =name112,4158
|
||||||
|
edition =edition113,4224
|
||||||
|
environment =environment114,4249
|
||||||
|
services =services115,4284
|
||||||
|
steps =steps116,4307
|
||||||
|
trigger =trigger117,4349
|
||||||
|
|
||||||
|
pipelines/shellcheck.star,386
|
||||||
|
trigger =trigger15,235
|
||||||
|
def shellcheck_step():shellcheck_step31,483
|
||||||
|
def shellcheck_pipeline():shellcheck_pipeline43,725
|
||||||
|
environment =environment44,752
|
||||||
|
steps =steps45,789
|
||||||
|
name =name50,886
|
||||||
|
edition =edition51,918
|
||||||
|
trigger =trigger52,943
|
||||||
|
services =services53,970
|
||||||
|
steps =steps54,993
|
||||||
|
environment =environment55,1016
|
||||||
|
|
||||||
|
pipelines/verify_drone.star,317
|
||||||
|
def verify_drone(trigger, ver_mode):verify_drone17,293
|
||||||
|
environment =environment18,330
|
||||||
|
steps =steps19,367
|
||||||
|
name =name26,528
|
||||||
|
edition =edition27,579
|
||||||
|
trigger =trigger28,604
|
||||||
|
services =services29,631
|
||||||
|
steps =steps30,654
|
||||||
|
environment =environment31,677
|
||||||
|
|
||||||
|
pipelines/test_backend.star,474
|
||||||
|
def test_backend(trigger, ver_mode, edition = "oss"):test_backend23,463
|
||||||
|
environment =environment35,882
|
||||||
|
init_steps =init_steps36,921
|
||||||
|
test_steps =test_steps46,1291
|
||||||
|
pipeline_name =pipeline_name51,1387
|
||||||
|
pipeline_name =pipeline_name53,1492
|
||||||
|
name =name55,1584
|
||||||
|
edition =edition56,1614
|
||||||
|
trigger =trigger57,1641
|
||||||
|
services =services58,1668
|
||||||
|
steps =steps59,1691
|
||||||
|
environment =environment60,1732
|
||||||
|
|
||||||
|
pipelines/lint_frontend.star,415
|
||||||
|
def lint_frontend_pipeline(trigger, ver_mode):lint_frontend_pipeline16,260
|
||||||
|
environment =environment26,546
|
||||||
|
yarn_step =yarn_step27,583
|
||||||
|
init_steps =init_steps29,660
|
||||||
|
test_steps =test_steps33,736
|
||||||
|
name =name37,812
|
||||||
|
edition =edition38,864
|
||||||
|
trigger =trigger39,889
|
||||||
|
services =services40,916
|
||||||
|
steps =steps41,939
|
||||||
|
environment =environment42,980
|
||||||
|
|
||||||
|
pipelines/docs.star,494
|
||||||
|
docs_paths =docs_paths19,383
|
||||||
|
def docs_pipelines(edition, ver_mode, trigger):docs_pipelines28,511
|
||||||
|
environment =environment29,559
|
||||||
|
steps =steps30,598
|
||||||
|
name =name40,815
|
||||||
|
edition =edition41,858
|
||||||
|
trigger =trigger42,885
|
||||||
|
services =services43,912
|
||||||
|
steps =steps44,935
|
||||||
|
environment =environment45,958
|
||||||
|
def lint_docs():lint_docs48,1000
|
||||||
|
def trigger_docs_main():trigger_docs_main63,1328
|
||||||
|
def trigger_docs_pr():trigger_docs_pr72,1478
|
||||||
|
|
||||||
|
pipelines/test_frontend.star,476
|
||||||
|
def test_frontend(trigger, ver_mode, edition = "oss"):test_frontend20,374
|
||||||
|
environment =environment32,794
|
||||||
|
init_steps =init_steps33,833
|
||||||
|
test_steps =test_steps41,1102
|
||||||
|
pipeline_name =pipeline_name45,1205
|
||||||
|
pipeline_name =pipeline_name47,1311
|
||||||
|
name =name49,1404
|
||||||
|
edition =edition50,1434
|
||||||
|
trigger =trigger51,1461
|
||||||
|
services =services52,1488
|
||||||
|
steps =steps53,1511
|
||||||
|
environment =environment54,1552
|
||||||
|
|
||||||
|
pipelines/integration_tests.star,483
|
||||||
|
def integration_tests(trigger, ver_mode, edition):integration_tests26,542
|
||||||
|
environment =environment37,900
|
||||||
|
services =services38,939
|
||||||
|
volumes =volumes39,989
|
||||||
|
init_steps =init_steps40,1039
|
||||||
|
test_steps =test_steps48,1282
|
||||||
|
name =name54,1412
|
||||||
|
edition =edition55,1468
|
||||||
|
trigger =trigger56,1493
|
||||||
|
services =services57,1520
|
||||||
|
steps =steps58,1549
|
||||||
|
environment =environment59,1590
|
||||||
|
volumes =volumes60,1625
|
||||||
|
|
||||||
|
pipelines/windows.star,954
|
||||||
|
def windows(trigger, edition, ver_mode):windows17,339
|
||||||
|
environment =environment29,798
|
||||||
|
init_cmds =init_cmds30,837
|
||||||
|
steps =steps38,1205
|
||||||
|
bucket =bucket49,1497
|
||||||
|
ver_part =ver_part51,1590
|
||||||
|
dir =dir52,1628
|
||||||
|
dir =dir54,1670
|
||||||
|
bucket =bucket55,1695
|
||||||
|
build_no =build_no56,1736
|
||||||
|
ver_part =ver_part57,1780
|
||||||
|
installer_commands =installer_commands58,1842
|
||||||
|
committish =committish100,3763
|
||||||
|
committish =committish102,3846
|
||||||
|
committish =committish104,3906
|
||||||
|
download_grabpl_step_cmds =download_grabpl_step_cmds107,4057
|
||||||
|
clone_cmds =clone_cmds113,4363
|
||||||
|
name =name146,5711
|
||||||
|
edition =edition147,5742
|
||||||
|
trigger =trigger148,5769
|
||||||
|
steps =steps149,5830
|
||||||
|
depends_on =depends_on150,5889
|
||||||
|
platform =platform151,6007
|
||||||
|
environment =environment152,6037
|
||||||
|
|
||||||
|
pipelines/lint_backend.star,418
|
||||||
|
def lint_backend_pipeline(trigger, ver_mode):lint_backend_pipeline18,306
|
||||||
|
environment =environment28,590
|
||||||
|
wire_step =wire_step29,627
|
||||||
|
init_steps =init_steps31,704
|
||||||
|
test_steps =test_steps36,809
|
||||||
|
name =name43,959
|
||||||
|
edition =edition44,1010
|
||||||
|
trigger =trigger45,1035
|
||||||
|
services =services46,1062
|
||||||
|
steps =steps47,1085
|
||||||
|
environment =environment48,1126
|
||||||
|
|
||||||
|
pipelines/publish_images.star,998
|
||||||
|
def publish_image_steps(edition, mode, docker_repo):publish_image_steps17,303
|
||||||
|
additional_docker_repo =additional_docker_repo31,922
|
||||||
|
additional_docker_repo =additional_docker_repo33,979
|
||||||
|
steps =steps34,1034
|
||||||
|
def publish_image_pipelines_public():publish_image_pipelines_public45,1369
|
||||||
|
mode =mode51,1521
|
||||||
|
trigger =trigger52,1541
|
||||||
|
name =name57,1641
|
||||||
|
trigger =trigger58,1694
|
||||||
|
steps =steps59,1721
|
||||||
|
edition =edition60,1813
|
||||||
|
environment =environment61,1835
|
||||||
|
name =name63,1894
|
||||||
|
trigger =trigger64,1954
|
||||||
|
steps =steps65,1981
|
||||||
|
edition =edition66,2091
|
||||||
|
environment =environment67,2113
|
||||||
|
def publish_image_pipelines_security():publish_image_pipelines_security70,2170
|
||||||
|
mode =mode71,2210
|
||||||
|
trigger =trigger72,2232
|
||||||
|
name =name77,2332
|
||||||
|
trigger =trigger78,2392
|
||||||
|
steps =steps79,2419
|
||||||
|
edition =edition80,2529
|
||||||
|
environment =environment81,2551
|
||||||
|
|
||||||
|
steps/lib.star,8579
|
||||||
|
grabpl_version =grabpl_version7,181
|
||||||
|
build_image =build_image8,208
|
||||||
|
publish_image =publish_image9,254
|
||||||
|
deploy_docker_image =deploy_docker_image10,304
|
||||||
|
alpine_image =alpine_image11,380
|
||||||
|
curl_image =curl_image12,411
|
||||||
|
windows_image =windows_image13,452
|
||||||
|
wix_image =wix_image14,501
|
||||||
|
go_image =go_image15,536
|
||||||
|
disable_tests =disable_tests17,564
|
||||||
|
trigger_oss =trigger_oss18,586
|
||||||
|
def slack_step(channel, template, secret):slack_step24,653
|
||||||
|
def yarn_install_step(edition = "oss"):yarn_install_step35,918
|
||||||
|
deps =deps36,958
|
||||||
|
deps =deps38,1004
|
||||||
|
def wire_install_step():wire_install_step48,1222
|
||||||
|
def identify_runner_step(platform = "linux"):identify_runner_step60,1454
|
||||||
|
def clone_enterprise_step(ver_mode):clone_enterprise_step78,1916
|
||||||
|
committish =committish87,2193
|
||||||
|
committish =committish89,2268
|
||||||
|
committish =committish91,2317
|
||||||
|
def init_enterprise_step(ver_mode):init_enterprise_step105,2747
|
||||||
|
source_commit =source_commit115,3098
|
||||||
|
source_commit =source_commit117,3151
|
||||||
|
environment =environment118,3191
|
||||||
|
token =token121,3280
|
||||||
|
environment =environment123,3369
|
||||||
|
token =token126,3458
|
||||||
|
environment =environment128,3518
|
||||||
|
token =token129,3543
|
||||||
|
def download_grabpl_step(platform = "linux"):download_grabpl_step148,4147
|
||||||
|
def lint_drone_step():lint_drone_step173,4973
|
||||||
|
def lint_starlark_step():lint_starlark_step185,5216
|
||||||
|
def enterprise_downstream_step(edition, ver_mode):enterprise_downstream_step206,6000
|
||||||
|
repo =repo219,6482
|
||||||
|
step =step225,6623
|
||||||
|
def lint_backend_step():lint_backend_step247,7248
|
||||||
|
def benchmark_ldap_step():benchmark_ldap_step265,7713
|
||||||
|
def build_storybook_step(edition, ver_mode):build_storybook_step278,8087
|
||||||
|
def store_storybook_step(edition, ver_mode, trigger = None):store_storybook_step300,8743
|
||||||
|
commands =commands314,9202
|
||||||
|
commands =commands323,9521
|
||||||
|
step =step325,9593
|
||||||
|
when_cond =when_cond338,10125
|
||||||
|
step =step346,10330
|
||||||
|
def e2e_tests_artifacts(edition):e2e_tests_artifacts349,10391
|
||||||
|
def upload_cdn_step(edition, ver_mode, trigger = None):upload_cdn_step386,12378
|
||||||
|
deps =deps397,12763
|
||||||
|
step =step407,12970
|
||||||
|
step =step420,13423
|
||||||
|
def build_backend_step(edition, ver_mode, variants = None):build_backend_step423,13482
|
||||||
|
variants_str =variants_str437,14070
|
||||||
|
variants_str =variants_str439,14109
|
||||||
|
cmds =cmds443,14256
|
||||||
|
build_no =build_no449,14418
|
||||||
|
cmds =cmds450,14461
|
||||||
|
def build_frontend_step(edition, ver_mode):build_frontend_step468,14906
|
||||||
|
build_no =build_no478,15246
|
||||||
|
cmds =cmds482,15356
|
||||||
|
cmds =cmds487,15505
|
||||||
|
def build_frontend_package_step(edition, ver_mode):build_frontend_package_step505,15960
|
||||||
|
build_no =build_no515,16312
|
||||||
|
cmds =cmds519,16422
|
||||||
|
cmds =cmds524,16580
|
||||||
|
def build_plugins_step(edition, ver_mode):build_plugins_step542,17053
|
||||||
|
env =env544,17121
|
||||||
|
env =env548,17220
|
||||||
|
def test_backend_step():test_backend_step563,17607
|
||||||
|
def test_backend_integration_step():test_backend_integration_step575,17880
|
||||||
|
def betterer_frontend_step(edition = "oss"):betterer_frontend_step587,18187
|
||||||
|
deps =deps596,18427
|
||||||
|
def test_frontend_step(edition = "oss"):test_frontend_step609,18728
|
||||||
|
deps =deps618,18962
|
||||||
|
def lint_frontend_step():lint_frontend_step634,19343
|
||||||
|
def test_a11y_frontend_step(ver_mode, edition, port = 3001):test_a11y_frontend_step652,19793
|
||||||
|
commands =commands664,20279
|
||||||
|
failure =failure667,20345
|
||||||
|
failure =failure672,20483
|
||||||
|
def frontend_metrics_step(edition, trigger = None):frontend_metrics_step693,21146
|
||||||
|
step =step706,21507
|
||||||
|
step =step721,22007
|
||||||
|
def codespell_step():codespell_step724,22066
|
||||||
|
def package_step(edition, ver_mode, variants = None):package_step736,22468
|
||||||
|
deps =deps750,23006
|
||||||
|
variants_str =variants_str757,23167
|
||||||
|
variants_str =variants_str759,23206
|
||||||
|
sign_args =sign_args762,23332
|
||||||
|
env =env763,23362
|
||||||
|
test_args =test_args769,23628
|
||||||
|
sign_args =sign_args771,23661
|
||||||
|
env =env772,23684
|
||||||
|
test_args =test_args773,23703
|
||||||
|
cmds =cmds777,23829
|
||||||
|
build_no =build_no784,24036
|
||||||
|
cmds =cmds785,24079
|
||||||
|
def grafana_server_step(edition, port = 3001):grafana_server_step798,24459
|
||||||
|
package_file_pfx =package_file_pfx808,24729
|
||||||
|
package_file_pfx =package_file_pfx810,24788
|
||||||
|
package_file_pfx =package_file_pfx812,24889
|
||||||
|
environment =environment814,24938
|
||||||
|
def e2e_tests_step(suite, edition, port = 3001, tries = None):e2e_tests_step837,25554
|
||||||
|
cmd =cmd838,25617
|
||||||
|
def cloud_plugins_e2e_tests_step(suite, edition, cloud, trigger = None):cloud_plugins_e2e_tests_step856,26186
|
||||||
|
environment =environment869,26649
|
||||||
|
when =when870,26670
|
||||||
|
when =when872,26700
|
||||||
|
environment =environment874,26748
|
||||||
|
when =when882,27129
|
||||||
|
branch =branch888,27345
|
||||||
|
step =step889,27401
|
||||||
|
step =step901,27822
|
||||||
|
def build_docs_website_step():build_docs_website_step904,27874
|
||||||
|
def copy_packages_for_docker_step(edition = None):copy_packages_for_docker_step916,28272
|
||||||
|
def build_docker_images_step(edition, archs = None, ubuntu = False, publish = False):build_docker_images_step929,28622
|
||||||
|
cmd =cmd943,29193
|
||||||
|
ubuntu_sfx =ubuntu_sfx947,29307
|
||||||
|
ubuntu_sfx =ubuntu_sfx949,29342
|
||||||
|
environment =environment955,29468
|
||||||
|
def fetch_images_step(edition):fetch_images_step979,30079
|
||||||
|
def publish_images_step(edition, ver_mode, mode, docker_repo, trigger = None):publish_images_step997,30745
|
||||||
|
name =name1013,31562
|
||||||
|
docker_repo =docker_repo1014,31585
|
||||||
|
mode =mode1016,31663
|
||||||
|
mode =mode1018,31709
|
||||||
|
environment =environment1020,31728
|
||||||
|
cmd =cmd1026,31912
|
||||||
|
deps =deps1029,32041
|
||||||
|
deps =deps1032,32147
|
||||||
|
name =name1035,32250
|
||||||
|
docker_repo =docker_repo1036,32273
|
||||||
|
cmd =cmd1038,32459
|
||||||
|
step =step1040,32565
|
||||||
|
step =step1052,32929
|
||||||
|
def postgres_integration_tests_step():postgres_integration_tests_step1056,32989
|
||||||
|
cmds =cmds1057,33028
|
||||||
|
def mysql_integration_tests_step():mysql_integration_tests_step1079,33850
|
||||||
|
cmds =cmds1080,33886
|
||||||
|
def redis_integration_tests_step():redis_integration_tests_step1100,34629
|
||||||
|
def memcached_integration_tests_step():memcached_integration_tests_step1114,35026
|
||||||
|
def release_canary_npm_packages_step(edition, trigger = None):release_canary_npm_packages_step1128,35435
|
||||||
|
step =step1141,35805
|
||||||
|
step =step1153,36143
|
||||||
|
def enterprise2_suffix(edition):enterprise2_suffix1156,36202
|
||||||
|
def upload_packages_step(edition, ver_mode, trigger = None):upload_packages_step1161,36320
|
||||||
|
deps =deps1176,36816
|
||||||
|
step =step1184,37036
|
||||||
|
step =step1195,37471
|
||||||
|
def publish_grafanacom_step(edition, ver_mode):publish_grafanacom_step1198,37530
|
||||||
|
cmd =cmd1211,38044
|
||||||
|
build_no =build_no1215,38188
|
||||||
|
cmd =cmd1216,38231
|
||||||
|
def publish_linux_packages_step(edition, package_manager = "deb"):publish_linux_packages_step1239,38866
|
||||||
|
def get_windows_steps(edition, ver_mode):get_windows_steps1261,39989
|
||||||
|
init_cmds =init_cmds1270,40281
|
||||||
|
steps =steps1278,40649
|
||||||
|
bucket =bucket1289,40941
|
||||||
|
ver_part =ver_part1291,41034
|
||||||
|
dir =dir1292,41072
|
||||||
|
dir =dir1294,41114
|
||||||
|
bucket =bucket1295,41139
|
||||||
|
build_no =build_no1296,41180
|
||||||
|
ver_part =ver_part1297,41224
|
||||||
|
installer_commands =installer_commands1298,41286
|
||||||
|
committish =committish1340,43207
|
||||||
|
committish =committish1342,43290
|
||||||
|
committish =committish1344,43350
|
||||||
|
download_grabpl_step_cmds =download_grabpl_step_cmds1347,43501
|
||||||
|
clone_cmds =clone_cmds1353,43807
|
||||||
|
def verify_gen_cue_step(edition):verify_gen_cue_step1387,45152
|
||||||
|
deps =deps1388,45186
|
||||||
|
def verify_gen_jsonnet_step(edition):verify_gen_jsonnet_step1402,45694
|
||||||
|
deps =deps1403,45732
|
||||||
|
def trigger_test_release():trigger_test_release1417,46236
|
||||||
|
def artifacts_page_step():artifacts_page_step1451,47731
|
||||||
|
def end_to_end_tests_deps():end_to_end_tests_deps1466,48058
|
||||||
|
def compile_build_cmd(edition = "oss"):compile_build_cmd1476,48321
|
||||||
|
dependencies =dependencies1477,48361
|
||||||
|
dependencies =dependencies1479,48432
|
||||||
|
def get_trigger_storybook(ver_mode):get_trigger_storybook1492,48780
|
||||||
|
trigger_storybook =trigger_storybook1500,49031
|
||||||
|
trigger_storybook =trigger_storybook1502,49088
|
||||||
|
trigger_storybook =trigger_storybook1506,49168
|
||||||
|
|
||||||
|
vault.star,444
|
||||||
|
pull_secret =pull_secret4,87
|
||||||
|
github_token =github_token5,120
|
||||||
|
drone_token =drone_token6,150
|
||||||
|
prerelease_bucket =prerelease_bucket7,178
|
||||||
|
gcp_upload_artifacts_key =gcp_upload_artifacts_key8,218
|
||||||
|
azure_sp_app_id =azure_sp_app_id9,272
|
||||||
|
azure_sp_app_pw =azure_sp_app_pw10,308
|
||||||
|
azure_tenant =azure_tenant11,344
|
||||||
|
def from_secret(secret):from_secret13,375
|
||||||
|
def vault_secret(name, path, key):vault_secret18,451
|
||||||
|
def secrets():secrets28,633
|
||||||
|
|
||||||
|
version.star,116
|
||||||
|
ver_mode =ver_mode12,197
|
||||||
|
trigger =trigger13,225
|
||||||
|
def version_branch_pipelines():version_branch_pipelines15,268
|
||||||
@@ -1,99 +1,115 @@
|
|||||||
load('scripts/drone/vault.star', 'from_secret', 'pull_secret')
|
"""
|
||||||
load('scripts/drone/steps/lib.star', 'publish_image', 'compile_build_cmd')
|
This module provides functions for cronjob pipelines and steps used within.
|
||||||
|
"""
|
||||||
|
|
||||||
aquasec_trivy_image = 'aquasec/trivy:0.21.0'
|
load("scripts/drone/vault.star", "from_secret")
|
||||||
|
load(
|
||||||
|
"scripts/drone/steps/lib.star",
|
||||||
|
"compile_build_cmd",
|
||||||
|
"publish_image",
|
||||||
|
)
|
||||||
|
|
||||||
def cronjobs(edition):
|
aquasec_trivy_image = "aquasec/trivy:0.21.0"
|
||||||
grafana_com_nightly_pipeline = cron_job_pipeline(
|
|
||||||
cronName='grafana-com-nightly',
|
def cronjobs():
|
||||||
name='grafana-com-nightly',
|
|
||||||
steps=[compile_build_cmd(),post_to_grafana_com_step()]
|
|
||||||
)
|
|
||||||
return [
|
return [
|
||||||
scan_docker_image_pipeline(edition, 'latest'),
|
scan_docker_image_pipeline("latest"),
|
||||||
scan_docker_image_pipeline(edition, 'main'),
|
scan_docker_image_pipeline("main"),
|
||||||
scan_docker_image_pipeline(edition, 'latest-ubuntu'),
|
scan_docker_image_pipeline("latest-ubuntu"),
|
||||||
scan_docker_image_pipeline(edition, 'main-ubuntu'),
|
scan_docker_image_pipeline("main-ubuntu"),
|
||||||
grafana_com_nightly_pipeline,
|
grafana_com_nightly_pipeline(),
|
||||||
]
|
]
|
||||||
|
|
||||||
def cron_job_pipeline(cronName, name, steps):
|
def cron_job_pipeline(cronName, name, steps):
|
||||||
return {
|
return {
|
||||||
'kind': 'pipeline',
|
"kind": "pipeline",
|
||||||
'type': 'docker',
|
"type": "docker",
|
||||||
'platform': {
|
"platform": {
|
||||||
'os': 'linux',
|
"os": "linux",
|
||||||
'arch': 'amd64',
|
"arch": "amd64",
|
||||||
},
|
},
|
||||||
'name': name,
|
"name": name,
|
||||||
'trigger': {
|
"trigger": {
|
||||||
'event': 'cron',
|
"event": "cron",
|
||||||
'cron': cronName,
|
"cron": cronName,
|
||||||
},
|
},
|
||||||
'clone': {
|
"clone": {
|
||||||
'retries': 3,
|
"retries": 3,
|
||||||
},
|
},
|
||||||
'steps': steps,
|
"steps": steps,
|
||||||
}
|
}
|
||||||
|
|
||||||
def scan_docker_image_pipeline(edition, tag):
|
def scan_docker_image_pipeline(tag):
|
||||||
if edition != 'oss':
|
"""Generates a cronjob pipeline for nightly scans of grafana Docker images.
|
||||||
edition='grafana-enterprise'
|
|
||||||
else:
|
|
||||||
edition='grafana'
|
|
||||||
|
|
||||||
dockerImage='grafana/{}:{}'.format(edition, tag)
|
Args:
|
||||||
|
tag: determines which image tag is scanned.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone cronjob pipeline.
|
||||||
|
"""
|
||||||
|
docker_image = "grafana/grafana:{}".format(tag)
|
||||||
|
|
||||||
return cron_job_pipeline(
|
return cron_job_pipeline(
|
||||||
cronName='nightly',
|
cronName = "nightly",
|
||||||
name='scan-' + dockerImage + '-image',
|
name = "scan-" + docker_image + "-image",
|
||||||
steps=[
|
steps = [
|
||||||
scan_docker_image_unkown_low_medium_vulnerabilities_step(dockerImage),
|
scan_docker_image_unkown_low_medium_vulnerabilities_step(docker_image),
|
||||||
scan_docker_image_high_critical_vulnerabilities_step(dockerImage),
|
scan_docker_image_high_critical_vulnerabilities_step(docker_image),
|
||||||
slack_job_failed_step('grafana-backend-ops', dockerImage),
|
slack_job_failed_step("grafana-backend-ops", docker_image),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def scan_docker_image_unkown_low_medium_vulnerabilities_step(dockerImage):
|
def scan_docker_image_unkown_low_medium_vulnerabilities_step(docker_image):
|
||||||
return {
|
return {
|
||||||
'name': 'scan-unkown-low-medium-vulnerabilities',
|
"name": "scan-unkown-low-medium-vulnerabilities",
|
||||||
'image': aquasec_trivy_image,
|
"image": aquasec_trivy_image,
|
||||||
'commands': [
|
"commands": [
|
||||||
'trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM ' + dockerImage,
|
"trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM " + docker_image,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
def scan_docker_image_high_critical_vulnerabilities_step(dockerImage):
|
def scan_docker_image_high_critical_vulnerabilities_step(docker_image):
|
||||||
return {
|
return {
|
||||||
'name': 'scan-high-critical-vulnerabilities',
|
"name": "scan-high-critical-vulnerabilities",
|
||||||
'image': aquasec_trivy_image,
|
"image": aquasec_trivy_image,
|
||||||
'commands': [
|
"commands": [
|
||||||
'trivy --exit-code 1 --severity HIGH,CRITICAL ' + dockerImage,
|
"trivy --exit-code 1 --severity HIGH,CRITICAL " + docker_image,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
def slack_job_failed_step(channel, image):
|
def slack_job_failed_step(channel, image):
|
||||||
return {
|
return {
|
||||||
'name': 'slack-notify-failure',
|
"name": "slack-notify-failure",
|
||||||
'image': 'plugins/slack',
|
"image": "plugins/slack",
|
||||||
'settings': {
|
"settings": {
|
||||||
'webhook': from_secret('slack_webhook_backend'),
|
"webhook": from_secret("slack_webhook_backend"),
|
||||||
'channel': channel,
|
"channel": channel,
|
||||||
'template': 'Nightly docker image scan job for ' + image + ' failed: {{build.link}}',
|
"template": "Nightly docker image scan job for " +
|
||||||
|
image +
|
||||||
|
" failed: {{build.link}}",
|
||||||
},
|
},
|
||||||
'when': {
|
"when": {"status": "failure"},
|
||||||
'status': 'failure'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def post_to_grafana_com_step():
|
def post_to_grafana_com_step():
|
||||||
return {
|
return {
|
||||||
'name': 'post-to-grafana-com',
|
"name": "post-to-grafana-com",
|
||||||
'image': publish_image,
|
"image": publish_image,
|
||||||
'environment': {
|
"environment": {
|
||||||
'GRAFANA_COM_API_KEY': from_secret('grafana_api_key'),
|
"GRAFANA_COM_API_KEY": from_secret("grafana_api_key"),
|
||||||
'GCP_KEY': from_secret('gcp_key'),
|
"GCP_KEY": from_secret("gcp_key"),
|
||||||
},
|
},
|
||||||
'depends_on': ['compile-build-cmd'],
|
"depends_on": ["compile-build-cmd"],
|
||||||
'commands': ['./bin/build publish grafana-com --edition oss'],
|
"commands": ["./bin/build publish grafana-com --edition oss"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def grafana_com_nightly_pipeline():
|
||||||
|
return cron_job_pipeline(
|
||||||
|
cronName = "grafana-com-nightly",
|
||||||
|
name = "grafana-com-nightly",
|
||||||
|
steps = [
|
||||||
|
compile_build_cmd(),
|
||||||
|
post_to_grafana_com_step(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,108 +1,116 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/utils/utils.star',
|
This module returns all the pipelines used in the event of pushes to the main branch.
|
||||||
'pipeline',
|
"""
|
||||||
'notify_pipeline',
|
|
||||||
'failure_template',
|
|
||||||
'drone_change_template',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/docs.star',
|
"scripts/drone/utils/utils.star",
|
||||||
'docs_pipelines',
|
"drone_change_template",
|
||||||
'trigger_docs_main',
|
"failure_template",
|
||||||
|
"notify_pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/test_frontend.star',
|
"scripts/drone/pipelines/docs.star",
|
||||||
'test_frontend',
|
"docs_pipelines",
|
||||||
|
"trigger_docs_main",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/test_backend.star',
|
"scripts/drone/pipelines/test_frontend.star",
|
||||||
'test_backend',
|
"test_frontend",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/integration_tests.star',
|
"scripts/drone/pipelines/test_backend.star",
|
||||||
'integration_tests',
|
"test_backend",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/build.star',
|
"scripts/drone/pipelines/integration_tests.star",
|
||||||
'build_e2e',
|
"integration_tests",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/windows.star',
|
"scripts/drone/pipelines/build.star",
|
||||||
'windows',
|
"build_e2e",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/trigger_downstream.star',
|
"scripts/drone/pipelines/windows.star",
|
||||||
'enterprise_downstream_pipeline',
|
"windows",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/lint_backend.star',
|
"scripts/drone/pipelines/trigger_downstream.star",
|
||||||
'lint_backend_pipeline',
|
"enterprise_downstream_pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/lint_frontend.star',
|
"scripts/drone/pipelines/lint_backend.star",
|
||||||
'lint_frontend_pipeline',
|
"lint_backend_pipeline",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/pipelines/lint_frontend.star",
|
||||||
|
"lint_frontend_pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
load('scripts/drone/vault.star', 'from_secret')
|
ver_mode = "main"
|
||||||
|
|
||||||
|
|
||||||
ver_mode = 'main'
|
|
||||||
trigger = {
|
trigger = {
|
||||||
'event': ['push',],
|
"event": [
|
||||||
'branch': 'main',
|
"push",
|
||||||
'paths': {
|
],
|
||||||
'exclude': [
|
"branch": "main",
|
||||||
'*.md',
|
"paths": {
|
||||||
'docs/**',
|
"exclude": [
|
||||||
'latest.json',
|
"*.md",
|
||||||
|
"docs/**",
|
||||||
|
"latest.json",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def main_pipelines(edition):
|
def main_pipelines():
|
||||||
drone_change_trigger = {
|
drone_change_trigger = {
|
||||||
'event': ['push',],
|
"event": [
|
||||||
'branch': 'main',
|
"push",
|
||||||
'repo': [
|
|
||||||
'grafana/grafana',
|
|
||||||
],
|
],
|
||||||
'paths': {
|
"branch": "main",
|
||||||
'include': [
|
"repo": [
|
||||||
'.drone.yml',
|
"grafana/grafana",
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"include": [
|
||||||
|
".drone.yml",
|
||||||
],
|
],
|
||||||
'exclude': [
|
"exclude": [
|
||||||
'exclude',
|
"exclude",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelines = [
|
pipelines = [
|
||||||
docs_pipelines(edition, ver_mode, trigger_docs_main()),
|
docs_pipelines(ver_mode, trigger_docs_main()),
|
||||||
test_frontend(trigger, ver_mode),
|
test_frontend(trigger, ver_mode),
|
||||||
lint_frontend_pipeline(trigger, ver_mode),
|
lint_frontend_pipeline(trigger, ver_mode),
|
||||||
test_backend(trigger, ver_mode),
|
test_backend(trigger, ver_mode),
|
||||||
lint_backend_pipeline(trigger, ver_mode),
|
lint_backend_pipeline(trigger, ver_mode),
|
||||||
build_e2e(trigger, ver_mode, edition),
|
build_e2e(trigger, ver_mode),
|
||||||
integration_tests(trigger, ver_mode, edition),
|
integration_tests(trigger, prefix = ver_mode, ver_mode = ver_mode),
|
||||||
windows(trigger, edition, ver_mode),
|
windows(trigger, edition = "oss", ver_mode = ver_mode),
|
||||||
notify_pipeline(
|
notify_pipeline(
|
||||||
name='notify-drone-changes', slack_channel='slack-webhooks-test', trigger=drone_change_trigger,
|
name = "notify-drone-changes",
|
||||||
template=drone_change_template, secret='drone-changes-webhook',
|
slack_channel = "slack-webhooks-test",
|
||||||
),
|
trigger = drone_change_trigger,
|
||||||
enterprise_downstream_pipeline(edition, ver_mode),
|
template = drone_change_template,
|
||||||
notify_pipeline(
|
secret = "drone-changes-webhook",
|
||||||
name='main-notify', slack_channel='grafana-ci-notifications', trigger=dict(trigger, status=['failure']),
|
),
|
||||||
depends_on=['main-test-frontend', 'main-test-backend', 'main-build-e2e-publish', 'main-integration-tests', 'main-windows'],
|
enterprise_downstream_pipeline(),
|
||||||
template=failure_template, secret='slack_webhook'
|
notify_pipeline(
|
||||||
)]
|
name = "main-notify",
|
||||||
|
slack_channel = "grafana-ci-notifications",
|
||||||
|
trigger = dict(trigger, status = ["failure"]),
|
||||||
|
depends_on = [
|
||||||
|
"main-test-frontend",
|
||||||
|
"main-test-backend",
|
||||||
|
"main-build-e2e-publish",
|
||||||
|
"main-integration-tests",
|
||||||
|
"main-windows",
|
||||||
|
],
|
||||||
|
template = failure_template,
|
||||||
|
secret = "slack_webhook",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
return pipelines
|
return pipelines
|
||||||
|
|||||||
+126
-57
@@ -1,85 +1,155 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/utils/utils.star',
|
This module returns all pipelines used in the event of a pull request.
|
||||||
'pipeline',
|
It also includes a function generating a PR trigger from a list of included and excluded paths.
|
||||||
)
|
"""
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/test_frontend.star',
|
"scripts/drone/pipelines/test_frontend.star",
|
||||||
'test_frontend',
|
"test_frontend",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/test_backend.star',
|
"scripts/drone/pipelines/test_backend.star",
|
||||||
'test_backend',
|
"test_backend",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/integration_tests.star',
|
"scripts/drone/pipelines/integration_tests.star",
|
||||||
'integration_tests',
|
"integration_tests",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/build.star',
|
"scripts/drone/pipelines/build.star",
|
||||||
'build_e2e',
|
"build_e2e",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/verify_drone.star',
|
"scripts/drone/pipelines/verify_drone.star",
|
||||||
'verify_drone',
|
"verify_drone",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/docs.star',
|
"scripts/drone/pipelines/verify_starlark.star",
|
||||||
'docs_pipelines',
|
"verify_starlark",
|
||||||
'trigger_docs_pr',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/shellcheck.star',
|
"scripts/drone/pipelines/docs.star",
|
||||||
'shellcheck_pipeline',
|
"docs_pipelines",
|
||||||
|
"trigger_docs_pr",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/lint_backend.star',
|
"scripts/drone/pipelines/shellcheck.star",
|
||||||
'lint_backend_pipeline',
|
"shellcheck_pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/pipelines/lint_frontend.star',
|
"scripts/drone/pipelines/lint_backend.star",
|
||||||
'lint_frontend_pipeline',
|
"lint_backend_pipeline",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/pipelines/lint_frontend.star",
|
||||||
|
"lint_frontend_pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
ver_mode = 'pr'
|
ver_mode = "pr"
|
||||||
trigger = {
|
trigger = {
|
||||||
'event': [
|
"event": [
|
||||||
'pull_request',
|
"pull_request",
|
||||||
],
|
],
|
||||||
'paths': {
|
"paths": {
|
||||||
'exclude': [
|
"exclude": [
|
||||||
'*.md',
|
"*.md",
|
||||||
'docs/**',
|
"docs/**",
|
||||||
'latest.json',
|
"latest.json",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def pr_pipelines():
|
||||||
def pr_pipelines(edition):
|
|
||||||
return [
|
return [
|
||||||
verify_drone(get_pr_trigger(include_paths=['scripts/drone/**', '.drone.yml', '.drone.star']), ver_mode),
|
verify_drone(
|
||||||
test_frontend(get_pr_trigger(exclude_paths=['pkg/**', 'packaging/**', 'go.sum', 'go.mod']), ver_mode),
|
get_pr_trigger(
|
||||||
lint_frontend_pipeline(get_pr_trigger(exclude_paths=['pkg/**', 'packaging/**', 'go.sum', 'go.mod']), ver_mode),
|
include_paths = ["scripts/drone/**", ".drone.yml", ".drone.star"],
|
||||||
test_backend(get_pr_trigger(include_paths=['pkg/**', 'packaging/**', '.drone.yml', 'conf/**', 'go.sum', 'go.mod', 'public/app/plugins/**/plugin.json', 'devenv/**']), ver_mode),
|
),
|
||||||
lint_backend_pipeline(get_pr_trigger(include_paths=['pkg/**', 'packaging/**', 'conf/**', 'go.sum', 'go.mod', 'public/app/plugins/**/plugin.json', 'devenv/**']), ver_mode),
|
ver_mode,
|
||||||
build_e2e(trigger, ver_mode, edition),
|
),
|
||||||
integration_tests(get_pr_trigger(include_paths=['pkg/**', 'packaging/**', '.drone.yml', 'conf/**', 'go.sum', 'go.mod', 'public/app/plugins/**/plugin.json']), ver_mode, edition),
|
verify_starlark(
|
||||||
docs_pipelines(edition, ver_mode, trigger_docs_pr()),
|
get_pr_trigger(
|
||||||
|
include_paths = ["scripts/drone/**", ".drone.star"],
|
||||||
|
),
|
||||||
|
ver_mode,
|
||||||
|
),
|
||||||
|
test_frontend(
|
||||||
|
get_pr_trigger(
|
||||||
|
exclude_paths = ["pkg/**", "packaging/**", "go.sum", "go.mod"],
|
||||||
|
),
|
||||||
|
ver_mode,
|
||||||
|
),
|
||||||
|
lint_frontend_pipeline(
|
||||||
|
get_pr_trigger(
|
||||||
|
exclude_paths = ["pkg/**", "packaging/**", "go.sum", "go.mod"],
|
||||||
|
),
|
||||||
|
ver_mode,
|
||||||
|
),
|
||||||
|
test_backend(
|
||||||
|
get_pr_trigger(
|
||||||
|
include_paths = [
|
||||||
|
"pkg/**",
|
||||||
|
"packaging/**",
|
||||||
|
".drone.yml",
|
||||||
|
"conf/**",
|
||||||
|
"go.sum",
|
||||||
|
"go.mod",
|
||||||
|
"public/app/plugins/**/plugin.json",
|
||||||
|
"devenv/**",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ver_mode,
|
||||||
|
),
|
||||||
|
lint_backend_pipeline(
|
||||||
|
get_pr_trigger(
|
||||||
|
include_paths = [
|
||||||
|
"pkg/**",
|
||||||
|
"packaging/**",
|
||||||
|
"conf/**",
|
||||||
|
"go.sum",
|
||||||
|
"go.mod",
|
||||||
|
"public/app/plugins/**/plugin.json",
|
||||||
|
"devenv/**",
|
||||||
|
".bingo/**",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ver_mode,
|
||||||
|
),
|
||||||
|
build_e2e(trigger, ver_mode),
|
||||||
|
integration_tests(
|
||||||
|
get_pr_trigger(
|
||||||
|
include_paths = [
|
||||||
|
"pkg/**",
|
||||||
|
"packaging/**",
|
||||||
|
".drone.yml",
|
||||||
|
"conf/**",
|
||||||
|
"go.sum",
|
||||||
|
"go.mod",
|
||||||
|
"public/app/plugins/**/plugin.json",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
prefix = ver_mode,
|
||||||
|
),
|
||||||
|
docs_pipelines(ver_mode, trigger_docs_pr()),
|
||||||
shellcheck_pipeline(),
|
shellcheck_pipeline(),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_pr_trigger(include_paths = None, exclude_paths = None):
|
||||||
|
"""Generates a trigger filter from the lists of included and excluded path patterns.
|
||||||
|
|
||||||
def get_pr_trigger(include_paths=None, exclude_paths=None):
|
This function is primarily intended to generate a trigger for code changes
|
||||||
paths_ex = ['docs/**', '*.md']
|
as the patterns 'docs/**' and '*.md' are always excluded.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
include_paths: a list of path patterns using the same syntax as gitignore.
|
||||||
|
Changes affecting files matching these path patterns trigger the pipeline.
|
||||||
|
exclude_paths: a list of path patterns using the same syntax as gitignore.
|
||||||
|
Changes affecting files matching these path patterns do not trigger the pipeline.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone trigger.
|
||||||
|
"""
|
||||||
|
paths_ex = ["docs/**", "*.md"]
|
||||||
paths_in = []
|
paths_in = []
|
||||||
if include_paths:
|
if include_paths:
|
||||||
for path in include_paths:
|
for path in include_paths:
|
||||||
@@ -88,12 +158,11 @@ def get_pr_trigger(include_paths=None, exclude_paths=None):
|
|||||||
for path in exclude_paths:
|
for path in exclude_paths:
|
||||||
paths_ex.extend([path])
|
paths_ex.extend([path])
|
||||||
return {
|
return {
|
||||||
'event': [
|
"event": [
|
||||||
'pull_request',
|
"pull_request",
|
||||||
],
|
],
|
||||||
'paths': {
|
"paths": {
|
||||||
'exclude': paths_ex,
|
"exclude": paths_ex,
|
||||||
'include': paths_in,
|
"include": paths_in,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+547
-344
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
This module contains steps and pipelines publishing to AWS Marketplace.
|
||||||
|
"""
|
||||||
|
|
||||||
|
load(
|
||||||
|
"scripts/drone/steps/lib.star",
|
||||||
|
"compile_build_cmd",
|
||||||
|
"fetch_images_step",
|
||||||
|
"publish_image",
|
||||||
|
)
|
||||||
|
load("scripts/drone/vault.star", "from_secret")
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
|
)
|
||||||
|
|
||||||
|
def publish_aws_marketplace_step():
|
||||||
|
return {
|
||||||
|
"name": "publish-aws-marketplace",
|
||||||
|
"image": publish_image,
|
||||||
|
"commands": ["./bin/build publish aws --image grafana/grafana-enterprise --repo grafana-labs/grafanaenterprise --product 422b46fb-bea6-4f27-8bcc-832117bd627e"],
|
||||||
|
"depends_on": ["fetch-images-enterprise"],
|
||||||
|
"environment": {
|
||||||
|
"AWS_REGION": from_secret("aws_region"),
|
||||||
|
"AWS_ACCESS_KEY_ID": from_secret("aws_access_key_id"),
|
||||||
|
"AWS_SECRET_ACCESS_KEY": from_secret("aws_secret_access_key"),
|
||||||
|
},
|
||||||
|
"volumes": [{"name": "docker", "path": "/var/run/docker.sock"}],
|
||||||
|
}
|
||||||
|
|
||||||
|
def publish_aws_marketplace_pipeline(mode):
|
||||||
|
trigger = {
|
||||||
|
"event": ["promote"],
|
||||||
|
"target": [mode],
|
||||||
|
}
|
||||||
|
return [pipeline(
|
||||||
|
name = "publish-aws-marketplace-{}".format(mode),
|
||||||
|
trigger = trigger,
|
||||||
|
steps = [compile_build_cmd(), fetch_images_step("enterprise"), publish_aws_marketplace_step()],
|
||||||
|
edition = "",
|
||||||
|
depends_on = ["publish-docker-enterprise-public"],
|
||||||
|
environment = {"EDITION": "enterprise2"},
|
||||||
|
)]
|
||||||
@@ -1,110 +1,170 @@
|
|||||||
load(
|
"""This module contains the comprehensive build pipeline."""
|
||||||
'scripts/drone/steps/lib.star',
|
|
||||||
'download_grabpl_step',
|
|
||||||
'build_image',
|
|
||||||
'identify_runner_step',
|
|
||||||
'wire_install_step',
|
|
||||||
'yarn_install_step',
|
|
||||||
'build_backend_step',
|
|
||||||
'build_frontend_step',
|
|
||||||
'build_frontend_package_step',
|
|
||||||
'build_plugins_step',
|
|
||||||
'package_step',
|
|
||||||
'grafana_server_step',
|
|
||||||
'e2e_tests_step',
|
|
||||||
'e2e_tests_artifacts',
|
|
||||||
'build_storybook_step',
|
|
||||||
'copy_packages_for_docker_step',
|
|
||||||
'build_docker_images_step',
|
|
||||||
'publish_images_step',
|
|
||||||
'postgres_integration_tests_step',
|
|
||||||
'mysql_integration_tests_step',
|
|
||||||
'redis_integration_tests_step',
|
|
||||||
'memcached_integration_tests_step',
|
|
||||||
'get_windows_steps',
|
|
||||||
'benchmark_ldap_step',
|
|
||||||
'enterprise_downstream_step',
|
|
||||||
'frontend_metrics_step',
|
|
||||||
'store_storybook_step',
|
|
||||||
'release_canary_npm_packages_step',
|
|
||||||
'upload_packages_step',
|
|
||||||
'upload_cdn_step',
|
|
||||||
'verify_gen_cue_step',
|
|
||||||
'verify_gen_jsonnet_step',
|
|
||||||
'test_a11y_frontend_step',
|
|
||||||
'trigger_oss',
|
|
||||||
'betterer_frontend_step',
|
|
||||||
'trigger_test_release',
|
|
||||||
'compile_build_cmd',
|
|
||||||
'cloud_plugins_e2e_tests_step',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"build_backend_step",
|
||||||
|
"build_docker_images_step",
|
||||||
|
"build_frontend_package_step",
|
||||||
|
"build_frontend_step",
|
||||||
|
"build_plugins_step",
|
||||||
|
"build_storybook_step",
|
||||||
|
"cloud_plugins_e2e_tests_step",
|
||||||
|
"compile_build_cmd",
|
||||||
|
"copy_packages_for_docker_step",
|
||||||
|
"download_grabpl_step",
|
||||||
|
"e2e_tests_artifacts",
|
||||||
|
"e2e_tests_step",
|
||||||
|
"enterprise_downstream_step",
|
||||||
|
"frontend_metrics_step",
|
||||||
|
"grafana_server_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"package_step",
|
||||||
|
"publish_images_step",
|
||||||
|
"release_canary_npm_packages_step",
|
||||||
|
"store_storybook_step",
|
||||||
|
"test_a11y_frontend_step",
|
||||||
|
"trigger_oss",
|
||||||
|
"trigger_test_release",
|
||||||
|
"upload_cdn_step",
|
||||||
|
"upload_packages_step",
|
||||||
|
"verify_gen_cue_step",
|
||||||
|
"verify_gen_jsonnet_step",
|
||||||
|
"wire_install_step",
|
||||||
|
"yarn_install_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
def build_e2e(trigger, ver_mode, edition):
|
# @unused
|
||||||
variants = ['linux-amd64', 'linux-amd64-musl', 'darwin-amd64', 'windows-amd64',]
|
def build_e2e(trigger, ver_mode):
|
||||||
|
"""Perform e2e building, testing, and publishing.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
trigger: controls which events can trigger the pipeline execution.
|
||||||
|
ver_mode: used in the naming of the pipeline.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
|
||||||
|
edition = "oss"
|
||||||
|
environment = {"EDITION": edition}
|
||||||
init_steps = [
|
init_steps = [
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
download_grabpl_step(),
|
download_grabpl_step(),
|
||||||
compile_build_cmd(),
|
compile_build_cmd(),
|
||||||
verify_gen_cue_step(edition="oss"),
|
verify_gen_cue_step(),
|
||||||
verify_gen_jsonnet_step(edition="oss"),
|
verify_gen_jsonnet_step(),
|
||||||
wire_install_step(),
|
wire_install_step(),
|
||||||
yarn_install_step(),
|
yarn_install_step(),
|
||||||
]
|
]
|
||||||
|
|
||||||
build_steps = []
|
build_steps = []
|
||||||
if ver_mode == 'pr':
|
variants = None
|
||||||
build_steps.extend([trigger_test_release()])
|
|
||||||
build_steps.extend([enterprise_downstream_step(edition=edition, ver_mode=ver_mode)])
|
|
||||||
build_steps.extend([
|
|
||||||
build_backend_step(edition=edition, ver_mode=ver_mode),
|
|
||||||
build_frontend_step(edition=edition, ver_mode=ver_mode),
|
|
||||||
build_frontend_package_step(edition=edition, ver_mode=ver_mode),
|
|
||||||
build_plugins_step(edition=edition, ver_mode=ver_mode),
|
|
||||||
])
|
|
||||||
if ver_mode == 'main':
|
|
||||||
build_steps.extend([package_step(edition=edition, ver_mode=ver_mode)])
|
|
||||||
elif ver_mode == 'pr':
|
|
||||||
build_steps.extend([package_step(edition=edition, ver_mode=ver_mode, variants=variants)])
|
|
||||||
|
|
||||||
build_steps.extend([
|
if ver_mode == "pr":
|
||||||
grafana_server_step(edition=edition),
|
build_steps.extend(
|
||||||
e2e_tests_step('dashboards-suite', edition=edition),
|
[
|
||||||
e2e_tests_step('smoke-tests-suite', edition=edition),
|
trigger_test_release(),
|
||||||
e2e_tests_step('panels-suite', edition=edition),
|
enterprise_downstream_step(ver_mode = ver_mode),
|
||||||
e2e_tests_step('various-suite', edition=edition),
|
],
|
||||||
cloud_plugins_e2e_tests_step('cloud-plugins-suite', edition=edition, cloud='azure', trigger=trigger_oss),
|
)
|
||||||
e2e_tests_artifacts(edition=edition),
|
|
||||||
build_storybook_step(edition=edition, ver_mode=ver_mode),
|
|
||||||
copy_packages_for_docker_step(),
|
|
||||||
test_a11y_frontend_step(ver_mode=ver_mode, edition=edition),
|
|
||||||
])
|
|
||||||
if ver_mode == 'main':
|
|
||||||
build_steps.extend([
|
|
||||||
store_storybook_step(edition=edition, ver_mode=ver_mode, trigger=trigger_oss),
|
|
||||||
frontend_metrics_step(edition=edition, trigger=trigger_oss)
|
|
||||||
])
|
|
||||||
|
|
||||||
if ver_mode == 'main':
|
variants = [
|
||||||
build_steps.extend([
|
"linux-amd64",
|
||||||
build_docker_images_step(edition=edition, ver_mode=ver_mode, publish=False),
|
"linux-amd64-musl",
|
||||||
build_docker_images_step(edition=edition, ver_mode=ver_mode, ubuntu=True, publish=False),
|
"darwin-amd64",
|
||||||
publish_images_step(edition=edition, ver_mode=ver_mode, mode='', docker_repo='grafana/grafana', trigger=trigger_oss),
|
"windows-amd64",
|
||||||
publish_images_step(edition=edition, ver_mode=ver_mode, mode='', docker_repo='grafana/grafana-oss', trigger=trigger_oss),
|
]
|
||||||
release_canary_npm_packages_step(edition, trigger=trigger_oss),
|
|
||||||
upload_packages_step(edition=edition, ver_mode=ver_mode, trigger=trigger_oss),
|
|
||||||
upload_cdn_step(edition=edition, ver_mode=ver_mode, trigger=trigger_oss)
|
|
||||||
])
|
|
||||||
elif ver_mode == 'pr':
|
|
||||||
build_steps.extend([build_docker_images_step(edition=edition, ver_mode=ver_mode, archs=['amd64', ])])
|
|
||||||
|
|
||||||
publish_suffix = ''
|
build_steps.extend(
|
||||||
if ver_mode == 'main':
|
[
|
||||||
publish_suffix = '-publish'
|
build_backend_step(edition = edition, ver_mode = ver_mode),
|
||||||
|
build_frontend_step(edition = edition, ver_mode = ver_mode),
|
||||||
|
build_frontend_package_step(edition = edition, ver_mode = ver_mode),
|
||||||
|
build_plugins_step(edition = edition, ver_mode = ver_mode),
|
||||||
|
package_step(edition = edition, variants = variants, ver_mode = ver_mode),
|
||||||
|
grafana_server_step(edition = edition),
|
||||||
|
e2e_tests_step("dashboards-suite"),
|
||||||
|
e2e_tests_step("smoke-tests-suite"),
|
||||||
|
e2e_tests_step("panels-suite"),
|
||||||
|
e2e_tests_step("various-suite"),
|
||||||
|
cloud_plugins_e2e_tests_step(
|
||||||
|
"cloud-plugins-suite",
|
||||||
|
cloud = "azure",
|
||||||
|
trigger = trigger_oss,
|
||||||
|
),
|
||||||
|
e2e_tests_artifacts(),
|
||||||
|
build_storybook_step(ver_mode = ver_mode),
|
||||||
|
copy_packages_for_docker_step(),
|
||||||
|
test_a11y_frontend_step(ver_mode = ver_mode),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
if ver_mode == "main":
|
||||||
|
build_steps.extend(
|
||||||
|
[
|
||||||
|
store_storybook_step(trigger = trigger_oss, ver_mode = ver_mode),
|
||||||
|
frontend_metrics_step(trigger = trigger_oss),
|
||||||
|
build_docker_images_step(
|
||||||
|
edition = edition,
|
||||||
|
publish = False,
|
||||||
|
),
|
||||||
|
build_docker_images_step(
|
||||||
|
edition = edition,
|
||||||
|
publish = False,
|
||||||
|
ubuntu = True,
|
||||||
|
),
|
||||||
|
publish_images_step(
|
||||||
|
docker_repo = "grafana",
|
||||||
|
edition = edition,
|
||||||
|
mode = "",
|
||||||
|
trigger = trigger_oss,
|
||||||
|
ver_mode = ver_mode,
|
||||||
|
),
|
||||||
|
publish_images_step(
|
||||||
|
docker_repo = "grafana-oss",
|
||||||
|
edition = edition,
|
||||||
|
mode = "",
|
||||||
|
trigger = trigger_oss,
|
||||||
|
ver_mode = ver_mode,
|
||||||
|
),
|
||||||
|
release_canary_npm_packages_step(trigger = trigger_oss),
|
||||||
|
upload_packages_step(
|
||||||
|
edition = edition,
|
||||||
|
trigger = trigger_oss,
|
||||||
|
ver_mode = ver_mode,
|
||||||
|
),
|
||||||
|
upload_cdn_step(
|
||||||
|
edition = edition,
|
||||||
|
trigger = trigger_oss,
|
||||||
|
ver_mode = ver_mode,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
elif ver_mode == "pr":
|
||||||
|
build_steps.extend(
|
||||||
|
[
|
||||||
|
build_docker_images_step(
|
||||||
|
archs = [
|
||||||
|
"amd64",
|
||||||
|
],
|
||||||
|
edition = edition,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
publish_suffix = ""
|
||||||
|
if ver_mode == "main":
|
||||||
|
publish_suffix = "-publish"
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='{}-build-e2e{}'.format(ver_mode, publish_suffix), edition="oss", trigger=trigger, services=[], steps=init_steps + build_steps,
|
name = "{}-build-e2e{}".format(ver_mode, publish_suffix),
|
||||||
|
edition = "oss",
|
||||||
|
environment = environment,
|
||||||
|
services = [],
|
||||||
|
steps = init_steps + build_steps,
|
||||||
|
trigger = trigger,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,37 +1,32 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns all the pipelines used in the event of documentation changes along with supporting functions.
|
||||||
'build_image',
|
"""
|
||||||
'yarn_install_step',
|
|
||||||
'identify_runner_step',
|
|
||||||
'download_grabpl_step',
|
|
||||||
'lint_frontend_step',
|
|
||||||
'codespell_step',
|
|
||||||
'test_frontend_step',
|
|
||||||
'build_storybook_step',
|
|
||||||
'build_docs_website_step',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/services/services.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'integration_test_services',
|
"build_docs_website_step",
|
||||||
'ldap_service',
|
"build_image",
|
||||||
|
"codespell_step",
|
||||||
|
"download_grabpl_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"yarn_install_step",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/utils/utils.star",
|
||||||
'pipeline',
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
docs_paths = {
|
docs_paths = {
|
||||||
'include': [
|
"include": [
|
||||||
'*.md',
|
"*.md",
|
||||||
'docs/**',
|
"docs/**",
|
||||||
'packages/**/*.md',
|
"packages/**/*.md",
|
||||||
'latest.json',
|
"latest.json",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
def docs_pipelines(edition, ver_mode, trigger):
|
def docs_pipelines(ver_mode, trigger):
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
steps = [
|
steps = [
|
||||||
download_grabpl_step(),
|
download_grabpl_step(),
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
@@ -42,38 +37,42 @@ def docs_pipelines(edition, ver_mode, trigger):
|
|||||||
]
|
]
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='{}-docs'.format(ver_mode), edition=edition, trigger=trigger, services=[], steps=steps,
|
name = "{}-docs".format(ver_mode),
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
services = [],
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|
||||||
def lint_docs():
|
def lint_docs():
|
||||||
return {
|
return {
|
||||||
'name': 'lint-docs',
|
"name": "lint-docs",
|
||||||
'image': build_image,
|
"image": build_image,
|
||||||
'depends_on': [
|
"depends_on": [
|
||||||
'yarn-install',
|
"yarn-install",
|
||||||
],
|
],
|
||||||
'environment': {
|
"environment": {
|
||||||
'NODE_OPTIONS': '--max_old_space_size=8192',
|
"NODE_OPTIONS": "--max_old_space_size=8192",
|
||||||
},
|
},
|
||||||
'commands': [
|
"commands": [
|
||||||
'yarn run prettier:checkDocs',
|
"yarn run prettier:checkDocs",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def trigger_docs_main():
|
def trigger_docs_main():
|
||||||
return {
|
return {
|
||||||
'branch': 'main',
|
"branch": "main",
|
||||||
'event': [
|
"event": [
|
||||||
'push',
|
"push",
|
||||||
],
|
],
|
||||||
'paths': docs_paths,
|
"paths": docs_paths,
|
||||||
}
|
}
|
||||||
|
|
||||||
def trigger_docs_pr():
|
def trigger_docs_pr():
|
||||||
return {
|
return {
|
||||||
'event': [
|
"event": [
|
||||||
'pull_request',
|
"pull_request",
|
||||||
],
|
],
|
||||||
'paths': docs_paths,
|
"paths": docs_paths,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,40 @@
|
|||||||
|
"""
|
||||||
|
This module contains steps and pipelines relating to GitHub.
|
||||||
|
"""
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/steps/lib.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'download_grabpl_step',
|
"compile_build_cmd",
|
||||||
'publish_images_step',
|
"fetch_images_step",
|
||||||
'compile_build_cmd',
|
"publish_image",
|
||||||
'fetch_images_step',
|
|
||||||
'publish_image',
|
|
||||||
)
|
)
|
||||||
|
load("scripts/drone/vault.star", "from_secret")
|
||||||
load('scripts/drone/vault.star', 'from_secret')
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/utils/utils.star",
|
||||||
'pipeline',
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
def publish_github_step():
|
def publish_github_step():
|
||||||
return {
|
return {
|
||||||
'name': 'publish-github',
|
"name": "publish-github",
|
||||||
'image': publish_image,
|
"image": publish_image,
|
||||||
'commands': ['./bin/build publish github --repo $${GH_REGISTRY} --create'],
|
"commands": ["./bin/build publish github --repo $${GH_REGISTRY} --create"],
|
||||||
'depends_on': ['fetch-images-enterprise2'],
|
"depends_on": ["fetch-images-enterprise2"],
|
||||||
'environment': {
|
"environment": {
|
||||||
'GH_TOKEN': from_secret('github_token'),
|
"GH_TOKEN": from_secret("github_token"),
|
||||||
'GH_REGISTRY': from_secret('gh_registry'),
|
"GH_REGISTRY": from_secret("gh_registry"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def publish_github_pipeline(mode):
|
def publish_github_pipeline(mode):
|
||||||
trigger = {
|
trigger = {
|
||||||
'event': ['promote'],
|
"event": ["promote"],
|
||||||
'target': [mode],
|
"target": [mode],
|
||||||
}
|
}
|
||||||
return [pipeline(
|
return [pipeline(
|
||||||
name='publish-github-{}'.format(mode), trigger=trigger, steps=[compile_build_cmd(), fetch_images_step('enterprise2'), publish_github_step()], edition="", environment = {'EDITION': 'enterprise2'}
|
name = "publish-github-{}".format(mode),
|
||||||
),]
|
trigger = trigger,
|
||||||
|
steps = [compile_build_cmd(), fetch_images_step("enterprise2"), publish_github_step()],
|
||||||
|
edition = "",
|
||||||
|
environment = {"EDITION": "enterprise2"},
|
||||||
|
)]
|
||||||
|
|||||||
@@ -1,44 +1,79 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for integration tests.
|
||||||
'identify_runner_step',
|
"""
|
||||||
'download_grabpl_step',
|
|
||||||
'verify_gen_cue_step',
|
|
||||||
'verify_gen_jsonnet_step',
|
|
||||||
'wire_install_step',
|
|
||||||
'postgres_integration_tests_step',
|
|
||||||
'mysql_integration_tests_step',
|
|
||||||
'compile_build_cmd',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/services/services.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'integration_test_services',
|
"compile_build_cmd",
|
||||||
'integration_test_services_volumes',
|
"download_grabpl_step",
|
||||||
'ldap_service',
|
"enterprise_setup_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"mysql_integration_tests_step",
|
||||||
|
"postgres_integration_tests_step",
|
||||||
|
"verify_gen_cue_step",
|
||||||
|
"verify_gen_jsonnet_step",
|
||||||
|
"wire_install_step",
|
||||||
)
|
)
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/services/services.star",
|
||||||
'pipeline',
|
"integration_test_services",
|
||||||
|
"integration_test_services_volumes",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
def integration_tests(trigger, ver_mode, edition):
|
def integration_tests(trigger, prefix, ver_mode = "pr"):
|
||||||
services = integration_test_services(edition)
|
"""Generate a pipeline for integration tests.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
trigger: controls which events can trigger the pipeline execution.
|
||||||
|
prefix: used in the naming of the pipeline.
|
||||||
|
ver_mode: defines the event / origin of this build. In this function, if it is set to pr, then it will attempt to clone grafana-enterprise. Otherwise it has no effect.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
|
|
||||||
|
services = integration_test_services(edition = "oss")
|
||||||
volumes = integration_test_services_volumes()
|
volumes = integration_test_services_volumes()
|
||||||
init_steps = [
|
|
||||||
|
init_steps = []
|
||||||
|
|
||||||
|
verify_step = verify_gen_cue_step()
|
||||||
|
verify_jsonnet_step = verify_gen_jsonnet_step()
|
||||||
|
|
||||||
|
if ver_mode == "pr":
|
||||||
|
# In pull requests, attempt to clone grafana enterprise.
|
||||||
|
init_steps.append(enterprise_setup_step())
|
||||||
|
|
||||||
|
# Ensure that verif_gen_cue happens after we clone enterprise
|
||||||
|
# At the time of writing this, very_gen_cue is depended on by the wire step which is what everything else depends on.
|
||||||
|
verify_step["depends_on"].append("clone-enterprise")
|
||||||
|
verify_jsonnet_step["depends_on"].append("clone-enterprise")
|
||||||
|
|
||||||
|
init_steps += [
|
||||||
download_grabpl_step(),
|
download_grabpl_step(),
|
||||||
compile_build_cmd(),
|
compile_build_cmd(),
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
verify_gen_cue_step(edition="oss"),
|
verify_step,
|
||||||
verify_gen_jsonnet_step(edition="oss"),
|
verify_jsonnet_step,
|
||||||
wire_install_step(),
|
wire_install_step(),
|
||||||
]
|
]
|
||||||
|
|
||||||
test_steps = [
|
test_steps = [
|
||||||
postgres_integration_tests_step(edition=edition, ver_mode=ver_mode),
|
postgres_integration_tests_step(),
|
||||||
mysql_integration_tests_step(edition=edition, ver_mode=ver_mode),
|
mysql_integration_tests_step(),
|
||||||
]
|
]
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='{}-integration-tests'.format(ver_mode), edition="oss", trigger=trigger, services=services, steps=init_steps + test_steps,
|
name = "{}-integration-tests".format(prefix),
|
||||||
volumes=volumes
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
environment = environment,
|
||||||
|
services = services,
|
||||||
|
volumes = volumes,
|
||||||
|
steps = init_steps + test_steps,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,31 +1,60 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for linting backend code.
|
||||||
'identify_runner_step',
|
"""
|
||||||
'wire_install_step',
|
|
||||||
'lint_backend_step',
|
|
||||||
'lint_drone_step',
|
|
||||||
'compile_build_cmd',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"compile_build_cmd",
|
||||||
|
"enterprise_setup_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"lint_backend_step",
|
||||||
|
"lint_drone_step",
|
||||||
|
"wire_install_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
def lint_backend_pipeline(trigger, ver_mode):
|
def lint_backend_pipeline(trigger, ver_mode):
|
||||||
|
"""Generates the pipelines used linting backend code.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
trigger: controls which events can trigger the pipeline execution.
|
||||||
|
ver_mode: used in the naming of the pipeline.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
|
|
||||||
wire_step = wire_install_step()
|
wire_step = wire_install_step()
|
||||||
wire_step.update({ 'depends_on': [] })
|
wire_step.update({"depends_on": []})
|
||||||
|
|
||||||
init_steps = [
|
init_steps = [
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
compile_build_cmd(),
|
compile_build_cmd(),
|
||||||
wire_step,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if ver_mode == "pr":
|
||||||
|
# In pull requests, attempt to clone grafana enterprise.
|
||||||
|
init_steps.append(enterprise_setup_step())
|
||||||
|
wire_step["depends_on"].append("clone-enterprise")
|
||||||
|
|
||||||
|
init_steps.append(wire_step)
|
||||||
|
|
||||||
test_steps = [
|
test_steps = [
|
||||||
lint_backend_step(edition="oss"),
|
lint_backend_step(),
|
||||||
]
|
]
|
||||||
if ver_mode == 'main':
|
|
||||||
test_steps.extend([lint_drone_step()])
|
if ver_mode == "main":
|
||||||
|
test_steps.append(lint_drone_step())
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='{}-lint-backend'.format(ver_mode), edition="oss", trigger=trigger, services=[], steps=init_steps + test_steps,
|
name = "{}-lint-backend".format(ver_mode),
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
services = [],
|
||||||
|
steps = init_steps + test_steps,
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,25 +1,54 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for linting frontend code.
|
||||||
'identify_runner_step',
|
"""
|
||||||
'yarn_install_step',
|
|
||||||
'lint_frontend_step',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"enterprise_setup_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"lint_frontend_step",
|
||||||
|
"yarn_install_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
def lint_frontend_pipeline(trigger, ver_mode):
|
def lint_frontend_pipeline(trigger, ver_mode):
|
||||||
yarn_step = yarn_install_step()
|
"""Generates the pipelines used linting frontend code.
|
||||||
yarn_step.update({ 'depends_on': [] })
|
|
||||||
init_steps = [
|
Args:
|
||||||
|
trigger: controls which events can trigger the pipeline execution.
|
||||||
|
ver_mode: used in the naming of the pipeline.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
|
|
||||||
|
init_steps = []
|
||||||
|
lint_step = lint_frontend_step()
|
||||||
|
|
||||||
|
if ver_mode == "pr":
|
||||||
|
# In pull requests, attempt to clone grafana enterprise.
|
||||||
|
init_steps = [enterprise_setup_step()]
|
||||||
|
# Ensure the lint step happens after the clone-enterprise step
|
||||||
|
|
||||||
|
lint_step["depends_on"].append("clone-enterprise")
|
||||||
|
|
||||||
|
init_steps += [
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
yarn_step,
|
yarn_install_step(),
|
||||||
]
|
]
|
||||||
test_steps = [
|
test_steps = [
|
||||||
lint_frontend_step(),
|
lint_step,
|
||||||
]
|
]
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='{}-lint-frontend'.format(ver_mode), edition="oss", trigger=trigger, services=[], steps=init_steps + test_steps,
|
name = "{}-lint-frontend".format(ver_mode),
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
services = [],
|
||||||
|
steps = init_steps + test_steps,
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,50 +1,97 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for publishing Docker images and its steps.
|
||||||
'download_grabpl_step',
|
"""
|
||||||
'publish_images_step',
|
|
||||||
'compile_build_cmd',
|
|
||||||
'fetch_images_step',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"compile_build_cmd",
|
||||||
|
"download_grabpl_step",
|
||||||
|
"fetch_images_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"publish_images_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def publish_image_steps(edition, mode, docker_repo):
|
def publish_image_steps(edition, mode, docker_repo):
|
||||||
additional_docker_repo = ""
|
"""Generates the steps used for publising Docker images using grabpl.
|
||||||
if edition == 'oss':
|
|
||||||
additional_docker_repo='grafana/grafana-oss'
|
Args:
|
||||||
|
edition: controls which version of an image is fetched in the case of a release.
|
||||||
|
It also controls which publishing implementation is used.
|
||||||
|
If edition == 'oss', it additionally publishes the grafana/grafana-oss repository.
|
||||||
|
mode: uses to control the publishing of security images when mode == 'security'.
|
||||||
|
docker_repo: the Docker image name.
|
||||||
|
It is combined with the 'grafana/' library prefix.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of Drone steps.
|
||||||
|
"""
|
||||||
steps = [
|
steps = [
|
||||||
|
identify_runner_step(),
|
||||||
download_grabpl_step(),
|
download_grabpl_step(),
|
||||||
compile_build_cmd(),
|
compile_build_cmd(),
|
||||||
fetch_images_step(edition),
|
fetch_images_step(edition),
|
||||||
publish_images_step(edition, 'release', mode, docker_repo),
|
publish_images_step(edition, "release", mode, docker_repo),
|
||||||
]
|
]
|
||||||
if additional_docker_repo != "":
|
|
||||||
steps.extend([publish_images_step(edition, 'release', mode, additional_docker_repo)])
|
if edition == "oss":
|
||||||
|
steps.append(
|
||||||
|
publish_images_step(edition, "release", mode, "grafana-oss"),
|
||||||
|
)
|
||||||
|
|
||||||
return steps
|
return steps
|
||||||
|
|
||||||
def publish_image_pipelines_public():
|
def publish_image_pipelines_public():
|
||||||
mode='public'
|
"""Generates the pipeline used for publising public Docker images.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline
|
||||||
|
"""
|
||||||
|
mode = "public"
|
||||||
trigger = {
|
trigger = {
|
||||||
'event': ['promote'],
|
"event": ["promote"],
|
||||||
'target': [mode],
|
"target": [mode],
|
||||||
}
|
}
|
||||||
return [pipeline(
|
return [
|
||||||
name='publish-docker-oss-{}'.format(mode), trigger=trigger, steps=publish_image_steps(edition='oss', mode=mode, docker_repo='grafana/grafana'), edition=""
|
pipeline(
|
||||||
), pipeline(
|
name = "publish-docker-oss-{}".format(mode),
|
||||||
name='publish-docker-enterprise-{}'.format(mode), trigger=trigger, steps=publish_image_steps(edition='enterprise', mode=mode, docker_repo='grafana/grafana-enterprise'), edition=""
|
trigger = trigger,
|
||||||
),]
|
steps = publish_image_steps(edition = "oss", mode = mode, docker_repo = "grafana"),
|
||||||
|
edition = "",
|
||||||
|
environment = {"EDITION": "oss"},
|
||||||
|
),
|
||||||
|
pipeline(
|
||||||
|
name = "publish-docker-enterprise-{}".format(mode),
|
||||||
|
trigger = trigger,
|
||||||
|
steps = publish_image_steps(
|
||||||
|
edition = "enterprise",
|
||||||
|
mode = mode,
|
||||||
|
docker_repo = "grafana-enterprise",
|
||||||
|
),
|
||||||
|
edition = "",
|
||||||
|
environment = {"EDITION": "enterprise"},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
def publish_image_pipelines_security():
|
def publish_image_pipelines_security():
|
||||||
mode='security'
|
mode = "security"
|
||||||
trigger = {
|
trigger = {
|
||||||
'event': ['promote'],
|
"event": ["promote"],
|
||||||
'target': [mode],
|
"target": [mode],
|
||||||
}
|
}
|
||||||
return [pipeline(
|
return [
|
||||||
name='publish-docker-enterprise-{}'.format(mode), trigger=trigger, steps=publish_image_steps(edition='enterprise', mode=mode, docker_repo='grafana/grafana-enterprise'), edition=""
|
pipeline(
|
||||||
),]
|
name = "publish-docker-enterprise-{}".format(mode),
|
||||||
|
trigger = trigger,
|
||||||
|
steps = publish_image_steps(
|
||||||
|
edition = "enterprise",
|
||||||
|
mode = mode,
|
||||||
|
docker_repo = "grafana-enterprise",
|
||||||
|
),
|
||||||
|
edition = "",
|
||||||
|
environment = {"EDITION": "enterprise"},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,48 +1,50 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns a Drone step and pipeline for linting with shellcheck.
|
||||||
'build_image',
|
"""
|
||||||
'compile_build_cmd'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
load("scripts/drone/steps/lib.star", "build_image", "compile_build_cmd")
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/utils/utils.star",
|
||||||
'pipeline',
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
trigger = {
|
trigger = {
|
||||||
'event': [
|
"event": [
|
||||||
'pull_request',
|
"pull_request",
|
||||||
],
|
],
|
||||||
'paths': {
|
"paths": {
|
||||||
'exclude': [
|
"exclude": [
|
||||||
'*.md',
|
"*.md",
|
||||||
'docs/**',
|
"docs/**",
|
||||||
'latest.json',
|
"latest.json",
|
||||||
],
|
|
||||||
'include': [
|
|
||||||
'scripts/**/*.sh'
|
|
||||||
],
|
],
|
||||||
|
"include": ["scripts/**/*.sh"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def shellcheck_step():
|
def shellcheck_step():
|
||||||
return {
|
return {
|
||||||
'name': 'shellcheck',
|
"name": "shellcheck",
|
||||||
'image': build_image,
|
"image": build_image,
|
||||||
'depends_on': [
|
"depends_on": [
|
||||||
'compile-build-cmd',
|
"compile-build-cmd",
|
||||||
],
|
],
|
||||||
'commands': [
|
"commands": [
|
||||||
'./bin/build shellcheck',
|
"./bin/build shellcheck",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
def shellcheck_pipeline():
|
def shellcheck_pipeline():
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
steps = [
|
steps = [
|
||||||
compile_build_cmd(),
|
compile_build_cmd(),
|
||||||
shellcheck_step(),
|
shellcheck_step(),
|
||||||
]
|
]
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='pr-shellcheck', edition="oss", trigger=trigger, services=[], steps=steps,
|
name = "pr-shellcheck",
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
services = [],
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +1,121 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for testing backend code.
|
||||||
'identify_runner_step',
|
"""
|
||||||
'download_grabpl_step',
|
|
||||||
'wire_install_step',
|
|
||||||
'test_backend_step',
|
|
||||||
'test_backend_integration_step',
|
|
||||||
'verify_gen_cue_step',
|
|
||||||
'verify_gen_jsonnet_step',
|
|
||||||
'compile_build_cmd',
|
|
||||||
'clone_enterprise_step',
|
|
||||||
'init_enterprise_step',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"clone_enterprise_step",
|
||||||
|
"compile_build_cmd",
|
||||||
|
"download_grabpl_step",
|
||||||
|
"enterprise_setup_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"init_enterprise_step",
|
||||||
|
"test_backend_integration_step",
|
||||||
|
"test_backend_step",
|
||||||
|
"verify_gen_cue_step",
|
||||||
|
"verify_gen_jsonnet_step",
|
||||||
|
"wire_install_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
|
"with_deps",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_backend(trigger, ver_mode, edition="oss"):
|
def test_backend(trigger, ver_mode):
|
||||||
environment = {'EDITION': edition}
|
"""Generates the pipeline used for testing OSS backend code.
|
||||||
init_steps = []
|
|
||||||
if edition != 'oss':
|
Args:
|
||||||
init_steps.extend([clone_enterprise_step(ver_mode), download_grabpl_step(), init_enterprise_step(ver_mode),])
|
trigger: a Drone trigger for the pipeline.
|
||||||
init_steps.extend([
|
ver_mode: affects the pipeline name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
|
|
||||||
|
steps = []
|
||||||
|
|
||||||
|
verify_step = verify_gen_cue_step()
|
||||||
|
verify_jsonnet_step = verify_gen_jsonnet_step()
|
||||||
|
|
||||||
|
if ver_mode == "pr":
|
||||||
|
# In pull requests, attempt to clone grafana enterprise.
|
||||||
|
steps.append(enterprise_setup_step())
|
||||||
|
|
||||||
|
# Ensure that verif_gen_cue happens after we clone enterprise
|
||||||
|
# At the time of writing this, very_gen_cue is depended on by the wire step which is what everything else depends on.
|
||||||
|
verify_step["depends_on"].append("clone-enterprise")
|
||||||
|
verify_jsonnet_step["depends_on"].append("clone-enterprise")
|
||||||
|
|
||||||
|
steps += [
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
compile_build_cmd(edition),
|
compile_build_cmd(edition = "oss"),
|
||||||
verify_gen_cue_step(edition),
|
verify_step,
|
||||||
verify_gen_jsonnet_step(edition),
|
verify_jsonnet_step,
|
||||||
wire_install_step(),
|
wire_install_step(),
|
||||||
])
|
test_backend_step(),
|
||||||
test_steps = [
|
test_backend_integration_step(),
|
||||||
test_backend_step(edition),
|
|
||||||
test_backend_integration_step(edition),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
pipeline_name = '{}-test-backend'.format(ver_mode)
|
pipeline_name = "{}-test-backend".format(ver_mode)
|
||||||
if ver_mode in ("release-branch", "release"):
|
if ver_mode in ("release-branch", "release"):
|
||||||
pipeline_name = '{}-{}-test-backend'.format(ver_mode, edition)
|
pipeline_name = "{}-{}-test-backend".format(ver_mode, "oss")
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name=pipeline_name, edition=edition, trigger=trigger, services=[], steps=init_steps + test_steps, environment=environment
|
name = pipeline_name,
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_backend_enterprise(trigger, ver_mode, source, edition = "enterprise"):
|
||||||
|
"""Generates the pipeline used for testing backend enterprise code.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
trigger: a Drone trigger for the pipeline.
|
||||||
|
ver_mode: affects the pipeline name.
|
||||||
|
source: controls what revision of enterprise code to test with. The source of the PR, usually.
|
||||||
|
edition: affects the clone step in the pipeline and also affects the pipeline name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
environment = {"EDITION": edition}
|
||||||
|
|
||||||
|
steps = (
|
||||||
|
[
|
||||||
|
clone_enterprise_step(source),
|
||||||
|
download_grabpl_step(),
|
||||||
|
init_enterprise_step(ver_mode),
|
||||||
|
identify_runner_step(),
|
||||||
|
compile_build_cmd(edition),
|
||||||
|
] +
|
||||||
|
with_deps(
|
||||||
|
[
|
||||||
|
verify_gen_cue_step(),
|
||||||
|
verify_gen_jsonnet_step(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"init-enterprise",
|
||||||
|
],
|
||||||
|
) +
|
||||||
|
[
|
||||||
|
wire_install_step(),
|
||||||
|
test_backend_step(),
|
||||||
|
test_backend_integration_step(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
pipeline_name = "{}-test-backend".format(ver_mode)
|
||||||
|
if ver_mode in ("release-branch", "release"):
|
||||||
|
pipeline_name = "{}-{}-test-backend".format(ver_mode, edition)
|
||||||
|
|
||||||
|
return pipeline(
|
||||||
|
name = pipeline_name,
|
||||||
|
edition = edition,
|
||||||
|
trigger = trigger,
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,36 +1,103 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for testing backend code.
|
||||||
'identify_runner_step',
|
"""
|
||||||
'clone_enterprise_step',
|
|
||||||
'init_enterprise_step',
|
|
||||||
'download_grabpl_step',
|
|
||||||
'yarn_install_step',
|
|
||||||
'betterer_frontend_step',
|
|
||||||
'test_frontend_step',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"betterer_frontend_step",
|
||||||
|
"clone_enterprise_step",
|
||||||
|
"download_grabpl_step",
|
||||||
|
"enterprise_setup_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"init_enterprise_step",
|
||||||
|
"test_frontend_step",
|
||||||
|
"yarn_install_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
|
"with_deps",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_frontend(trigger, ver_mode, edition="oss"):
|
def test_frontend(trigger, ver_mode):
|
||||||
environment = {'EDITION': edition}
|
"""Generates the pipeline used for testing frontend code.
|
||||||
init_steps = []
|
|
||||||
if edition != 'oss':
|
Args:
|
||||||
init_steps.extend([clone_enterprise_step(ver_mode), init_enterprise_step(ver_mode),])
|
trigger: a Drone trigger for the pipeline
|
||||||
init_steps.extend([
|
ver_mode: indirectly controls which revision of enterprise code to use.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
|
|
||||||
|
steps = [
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
download_grabpl_step(),
|
download_grabpl_step(),
|
||||||
yarn_install_step(edition),
|
yarn_install_step(),
|
||||||
])
|
betterer_frontend_step(edition = "oss"),
|
||||||
test_steps = [
|
|
||||||
betterer_frontend_step(edition),
|
|
||||||
test_frontend_step(edition),
|
|
||||||
]
|
]
|
||||||
pipeline_name = '{}-test-frontend'.format(ver_mode)
|
|
||||||
|
pipeline_name = "{}-test-frontend".format(ver_mode)
|
||||||
|
|
||||||
|
test_step = test_frontend_step(edition = "oss")
|
||||||
|
|
||||||
|
if ver_mode == "pr":
|
||||||
|
# In pull requests, attempt to clone grafana enterprise.
|
||||||
|
steps.append(enterprise_setup_step())
|
||||||
|
|
||||||
|
# Also, make the test step depend on 'clone-enterprise
|
||||||
|
test_step["depends_on"].append("clone-enterprise")
|
||||||
|
|
||||||
|
steps.append(test_step)
|
||||||
|
|
||||||
|
pipeline_name = "{}-test-frontend".format(ver_mode)
|
||||||
if ver_mode in ("release-branch", "release"):
|
if ver_mode in ("release-branch", "release"):
|
||||||
pipeline_name = '{}-{}-test-frontend'.format(ver_mode, edition)
|
pipeline_name = "{}-oss-test-frontend".format(ver_mode)
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name=pipeline_name, edition=edition, trigger=trigger, services=[], steps=init_steps + test_steps,
|
name = pipeline_name,
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_frontend_enterprise(trigger, ver_mode, source, edition = "enterprise"):
|
||||||
|
"""Generates the pipeline used for testing frontend enterprise code.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
trigger: a Drone trigger for the pipeline.
|
||||||
|
ver_mode: affects the pipeline name.
|
||||||
|
source: controls what revision of Grafana code to test with.
|
||||||
|
edition: affects the clone step in the pipeline and also affects the pipeline name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline.
|
||||||
|
"""
|
||||||
|
environment = {"EDITION": edition}
|
||||||
|
steps = (
|
||||||
|
[
|
||||||
|
clone_enterprise_step(source),
|
||||||
|
init_enterprise_step(ver_mode),
|
||||||
|
identify_runner_step(),
|
||||||
|
download_grabpl_step(),
|
||||||
|
] +
|
||||||
|
with_deps([yarn_install_step()], ["init-enterprise"]) +
|
||||||
|
[
|
||||||
|
betterer_frontend_step(edition),
|
||||||
|
test_frontend_step(edition),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
pipeline_name = "{}-test-frontend".format(ver_mode)
|
||||||
|
if ver_mode in ("release-branch", "release"):
|
||||||
|
pipeline_name = "{}-{}-test-frontend".format(ver_mode, edition)
|
||||||
|
|
||||||
|
return pipeline(
|
||||||
|
name = pipeline_name,
|
||||||
|
edition = edition,
|
||||||
|
trigger = trigger,
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,28 +1,45 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for triggering a downstream pipeline for Grafana Enterprise.
|
||||||
'enterprise_downstream_step',
|
"""
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"enterprise_downstream_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
trigger = {
|
trigger = {
|
||||||
'event': ['push',],
|
"event": [
|
||||||
'branch': 'main',
|
"push",
|
||||||
'paths': {
|
],
|
||||||
'exclude': [
|
"branch": "main",
|
||||||
'*.md',
|
"paths": {
|
||||||
'docs/**',
|
"exclude": [
|
||||||
'latest.json',
|
"*.md",
|
||||||
|
"docs/**",
|
||||||
|
"latest.json",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def enterprise_downstream_pipeline(edition, ver_mode):
|
def enterprise_downstream_pipeline():
|
||||||
steps = [enterprise_downstream_step(edition, ver_mode)]
|
environment = {"EDITION": "oss"}
|
||||||
deps = ['main-build-e2e-publish', 'main-integration-tests']
|
steps = [
|
||||||
|
enterprise_downstream_step(ver_mode = "main"),
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
"main-build-e2e-publish",
|
||||||
|
"main-integration-tests",
|
||||||
|
]
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='main-trigger-downstream', edition=edition, trigger=trigger, services=[], steps=steps, depends_on=deps
|
name = "main-trigger-downstream",
|
||||||
)
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
services = [],
|
||||||
|
steps = steps,
|
||||||
|
depends_on = deps,
|
||||||
|
environment = environment,
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for verifying Drone configuration.
|
||||||
'identify_runner_step',
|
"""
|
||||||
'download_grabpl_step',
|
|
||||||
'lint_drone_step',
|
|
||||||
'compile_build_cmd',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'pipeline',
|
"compile_build_cmd",
|
||||||
|
"download_grabpl_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"lint_drone_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
)
|
)
|
||||||
|
|
||||||
def verify_drone(trigger, ver_mode):
|
def verify_drone(trigger, ver_mode):
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
steps = [
|
steps = [
|
||||||
identify_runner_step(),
|
identify_runner_step(),
|
||||||
download_grabpl_step(),
|
download_grabpl_step(),
|
||||||
@@ -19,5 +23,10 @@ def verify_drone(trigger, ver_mode):
|
|||||||
lint_drone_step(),
|
lint_drone_step(),
|
||||||
]
|
]
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='{}-verify-drone'.format(ver_mode), edition="oss", trigger=trigger, services=[], steps=steps,
|
name = "{}-verify-drone".format(ver_mode),
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
services = [],
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
"""
|
||||||
|
This module returns a Drone pipeline that verifies all Starlark files are linted.
|
||||||
|
"""
|
||||||
|
|
||||||
|
load(
|
||||||
|
"scripts/drone/steps/lib.star",
|
||||||
|
"compile_build_cmd",
|
||||||
|
"download_grabpl_step",
|
||||||
|
"identify_runner_step",
|
||||||
|
"lint_starlark_step",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/utils/utils.star",
|
||||||
|
"pipeline",
|
||||||
|
)
|
||||||
|
|
||||||
|
def verify_starlark(trigger, ver_mode):
|
||||||
|
environment = {"EDITION": "oss"}
|
||||||
|
steps = [
|
||||||
|
identify_runner_step(),
|
||||||
|
download_grabpl_step(),
|
||||||
|
compile_build_cmd(),
|
||||||
|
lint_starlark_step(),
|
||||||
|
]
|
||||||
|
return pipeline(
|
||||||
|
name = "{}-verify-starlark".format(ver_mode),
|
||||||
|
edition = "oss",
|
||||||
|
trigger = trigger,
|
||||||
|
services = [],
|
||||||
|
steps = steps,
|
||||||
|
environment = environment,
|
||||||
|
)
|
||||||
@@ -1,134 +1,41 @@
|
|||||||
load(
|
"""
|
||||||
'scripts/drone/steps/lib.star',
|
This module returns the pipeline used for building Grafana on Windows.
|
||||||
'grabpl_version',
|
"""
|
||||||
'wix_image',
|
|
||||||
'identify_runner_step',
|
|
||||||
)
|
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/utils/utils.star',
|
"scripts/drone/utils/utils.star",
|
||||||
'pipeline',
|
"pipeline",
|
||||||
|
)
|
||||||
|
load(
|
||||||
|
"scripts/drone/steps/lib.star",
|
||||||
|
"get_windows_steps",
|
||||||
)
|
)
|
||||||
|
|
||||||
load('scripts/drone/vault.star', 'from_secret', 'prerelease_bucket', 'github_token')
|
|
||||||
|
|
||||||
def windows(trigger, edition, ver_mode):
|
def windows(trigger, edition, ver_mode):
|
||||||
init_cmds = []
|
"""Generates the pipeline used for building Grafana on Windows.
|
||||||
sfx = ''
|
|
||||||
if edition in ('enterprise', 'enterprise2'):
|
|
||||||
sfx = '-{}'.format(edition)
|
|
||||||
else:
|
|
||||||
init_cmds.extend([
|
|
||||||
'$$ProgressPreference = "SilentlyContinue"',
|
|
||||||
'Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/{}/windows/grabpl.exe -OutFile grabpl.exe'.format(
|
|
||||||
grabpl_version),
|
|
||||||
])
|
|
||||||
steps = [
|
|
||||||
{
|
|
||||||
'name': 'windows-init',
|
|
||||||
'image': wix_image,
|
|
||||||
'commands': init_cmds,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
if (ver_mode == 'main' and (edition not in ('enterprise', 'enterprise2'))) or ver_mode in (
|
|
||||||
'release', 'release-branch',
|
|
||||||
):
|
|
||||||
bucket = '%PRERELEASE_BUCKET%/artifacts/downloads'
|
|
||||||
if ver_mode == 'release':
|
|
||||||
ver_part = '${DRONE_TAG}'
|
|
||||||
dir = 'release'
|
|
||||||
else:
|
|
||||||
dir = 'main'
|
|
||||||
bucket = 'grafana-downloads'
|
|
||||||
build_no = 'DRONE_BUILD_NUMBER'
|
|
||||||
ver_part = '--build-id $$env:{}'.format(build_no)
|
|
||||||
installer_commands = [
|
|
||||||
'$$gcpKey = $$env:GCP_KEY',
|
|
||||||
'[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($$gcpKey)) > gcpkey.json',
|
|
||||||
# gcloud fails to read the file unless converted with dos2unix
|
|
||||||
'dos2unix gcpkey.json',
|
|
||||||
'gcloud auth activate-service-account --key-file=gcpkey.json',
|
|
||||||
'rm gcpkey.json',
|
|
||||||
'cp C:\\App\\nssm-2.24.zip .',
|
|
||||||
]
|
|
||||||
if (ver_mode == 'main' and (edition not in ('enterprise', 'enterprise2'))) or ver_mode in (
|
|
||||||
'release',
|
|
||||||
):
|
|
||||||
installer_commands.extend([
|
|
||||||
'.\\grabpl.exe windows-installer --edition {} {}'.format(edition, ver_part),
|
|
||||||
'$$fname = ((Get-Childitem grafana*.msi -name) -split "`n")[0]',
|
|
||||||
])
|
|
||||||
if ver_mode == 'main':
|
|
||||||
installer_commands.extend([
|
|
||||||
'gsutil cp $$fname gs://{}/{}/{}/'.format(bucket, edition, dir),
|
|
||||||
'gsutil cp "$$fname.sha256" gs://{}/{}/{}/'.format(bucket, edition, dir),
|
|
||||||
])
|
|
||||||
else:
|
|
||||||
installer_commands.extend([
|
|
||||||
'gsutil cp $$fname gs://{}/{}/{}/{}/'.format(bucket, ver_part, edition, dir),
|
|
||||||
'gsutil cp "$$fname.sha256" gs://{}/{}/{}/{}/'.format(bucket, ver_part, edition, dir),
|
|
||||||
])
|
|
||||||
steps.append({
|
|
||||||
'name': 'build-windows-installer',
|
|
||||||
'image': wix_image,
|
|
||||||
'depends_on': [
|
|
||||||
'windows-init',
|
|
||||||
],
|
|
||||||
'environment': {
|
|
||||||
'GCP_KEY': from_secret('gcp_key'),
|
|
||||||
'PRERELEASE_BUCKET': from_secret(prerelease_bucket),
|
|
||||||
'GITHUB_TOKEN': from_secret('github_token')
|
|
||||||
},
|
|
||||||
'commands': installer_commands,
|
|
||||||
})
|
|
||||||
|
|
||||||
if edition in ('enterprise', 'enterprise2'):
|
Args:
|
||||||
if ver_mode == 'release':
|
trigger: a Drone trigger for the pipeline.
|
||||||
committish = '${DRONE_TAG}'
|
edition: controls whether enterprise code is included in the pipeline steps.
|
||||||
elif ver_mode == 'release-branch':
|
ver_mode: controls whether a pre-release or actual release pipeline is generated.
|
||||||
committish = '$$env:DRONE_BRANCH'
|
Also indirectly controls which version of enterprise code is used.
|
||||||
else:
|
|
||||||
committish = '$$env:DRONE_COMMIT'
|
Returns:
|
||||||
# For enterprise, we have to clone both OSS and enterprise and merge the latter into the former
|
Drone pipeline.
|
||||||
download_grabpl_step_cmds = [
|
"""
|
||||||
'$$ProgressPreference = "SilentlyContinue"',
|
environment = {"EDITION": edition}
|
||||||
'Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/{}/windows/grabpl.exe -OutFile grabpl.exe'.format(
|
|
||||||
grabpl_version),
|
|
||||||
]
|
|
||||||
clone_cmds = [
|
|
||||||
'git clone "https://$$env:GITHUB_TOKEN@github.com/grafana/grafana-enterprise.git"',
|
|
||||||
]
|
|
||||||
clone_cmds.extend([
|
|
||||||
'cd grafana-enterprise',
|
|
||||||
'git checkout {}'.format(committish),
|
|
||||||
])
|
|
||||||
steps.insert(0, {
|
|
||||||
'name': 'clone',
|
|
||||||
'image': wix_image,
|
|
||||||
'environment': {
|
|
||||||
'GITHUB_TOKEN': from_secret(github_token),
|
|
||||||
},
|
|
||||||
'commands': download_grabpl_step_cmds + clone_cmds,
|
|
||||||
})
|
|
||||||
steps[1]['depends_on'] = [
|
|
||||||
'clone',
|
|
||||||
]
|
|
||||||
steps[1]['commands'].extend([
|
|
||||||
# Need to move grafana-enterprise out of the way, so directory is empty and can be cloned into
|
|
||||||
'cp -r grafana-enterprise C:\\App\\grafana-enterprise',
|
|
||||||
'rm -r -force grafana-enterprise',
|
|
||||||
'cp grabpl.exe C:\\App\\grabpl.exe',
|
|
||||||
'rm -force grabpl.exe',
|
|
||||||
'C:\\App\\grabpl.exe init-enterprise --github-token $$env:GITHUB_TOKEN C:\\App\\grafana-enterprise',
|
|
||||||
'cp C:\\App\\grabpl.exe grabpl.exe',
|
|
||||||
])
|
|
||||||
if 'environment' in steps[1]:
|
|
||||||
steps[1]['environment'] + {'GITHUB_TOKEN': from_secret(github_token)}
|
|
||||||
else:
|
|
||||||
steps[1]['environment'] = {'GITHUB_TOKEN': from_secret(github_token)}
|
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
name='main-windows', edition=edition, trigger=dict(trigger, repo=['grafana/grafana']),
|
name = "main-windows",
|
||||||
steps=[identify_runner_step('windows')] + steps,
|
edition = edition,
|
||||||
depends_on=['main-test-frontend', 'main-test-backend', 'main-build-e2e-publish', 'main-integration-tests'], platform='windows',
|
trigger = dict(trigger, repo = ["grafana/grafana"]),
|
||||||
|
steps = get_windows_steps(edition, ver_mode),
|
||||||
|
depends_on = [
|
||||||
|
"main-test-frontend",
|
||||||
|
"main-test-backend",
|
||||||
|
"main-build-e2e-publish",
|
||||||
|
"main-integration-tests",
|
||||||
|
],
|
||||||
|
platform = "windows",
|
||||||
|
environment = environment,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,61 +1,66 @@
|
|||||||
|
"""
|
||||||
|
This module has functions for Drone services to be used in pipelines.
|
||||||
|
"""
|
||||||
|
|
||||||
def integration_test_services_volumes():
|
def integration_test_services_volumes():
|
||||||
return [
|
return [
|
||||||
{ 'name': 'postgres', 'temp': { 'medium': 'memory' } },
|
{"name": "postgres", "temp": {"medium": "memory"}},
|
||||||
{ 'name': 'mysql', 'temp': { 'medium': 'memory' }
|
{"name": "mysql", "temp": {"medium": "memory"}},
|
||||||
}]
|
]
|
||||||
|
|
||||||
def integration_test_services(edition):
|
def integration_test_services(edition):
|
||||||
services = [
|
services = [
|
||||||
{
|
{
|
||||||
'name': 'postgres',
|
"name": "postgres",
|
||||||
'image': 'postgres:12.3-alpine',
|
"image": "postgres:12.3-alpine",
|
||||||
'environment': {
|
"environment": {
|
||||||
'POSTGRES_USER': 'grafanatest',
|
"POSTGRES_USER": "grafanatest",
|
||||||
'POSTGRES_PASSWORD': 'grafanatest',
|
"POSTGRES_PASSWORD": "grafanatest",
|
||||||
'POSTGRES_DB': 'grafanatest',
|
"POSTGRES_DB": "grafanatest",
|
||||||
'PGDATA': '/var/lib/postgresql/data/pgdata',
|
"PGDATA": "/var/lib/postgresql/data/pgdata",
|
||||||
},
|
},
|
||||||
'volumes': [{
|
"volumes": [
|
||||||
'name': 'postgres',
|
{"name": "postgres", "path": "/var/lib/postgresql/data/pgdata"},
|
||||||
'path': '/var/lib/postgresql/data/pgdata'
|
],
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'mysql',
|
"name": "mysql",
|
||||||
'image': 'mysql:5.7.39',
|
"image": "mysql:5.7.39",
|
||||||
'environment': {
|
"environment": {
|
||||||
'MYSQL_ROOT_PASSWORD': 'rootpass',
|
"MYSQL_ROOT_PASSWORD": "rootpass",
|
||||||
'MYSQL_DATABASE': 'grafana_tests',
|
"MYSQL_DATABASE": "grafana_tests",
|
||||||
'MYSQL_USER': 'grafana',
|
"MYSQL_USER": "grafana",
|
||||||
'MYSQL_PASSWORD': 'password',
|
"MYSQL_PASSWORD": "password",
|
||||||
},
|
},
|
||||||
'volumes': [{
|
"volumes": [{"name": "mysql", "path": "/var/lib/mysql"}],
|
||||||
'name': 'mysql',
|
|
||||||
'path': '/var/lib/mysql'
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if edition in ('enterprise', 'enterprise2'):
|
if edition in ("enterprise", "enterprise2"):
|
||||||
services.extend([{
|
services.extend(
|
||||||
'name': 'redis',
|
[
|
||||||
'image': 'redis:6.2.1-alpine',
|
{
|
||||||
'environment': {},
|
"name": "redis",
|
||||||
}, {
|
"image": "redis:6.2.1-alpine",
|
||||||
'name': 'memcached',
|
"environment": {},
|
||||||
'image': 'memcached:1.6.9-alpine',
|
},
|
||||||
'environment': {},
|
{
|
||||||
}])
|
"name": "memcached",
|
||||||
|
"image": "memcached:1.6.9-alpine",
|
||||||
|
"environment": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
return services
|
return services
|
||||||
|
|
||||||
def ldap_service():
|
def ldap_service():
|
||||||
return {
|
return {
|
||||||
'name': 'ldap',
|
"name": "ldap",
|
||||||
'image': 'osixia/openldap:1.4.0',
|
"image": "osixia/openldap:1.4.0",
|
||||||
'environment': {
|
"environment": {
|
||||||
'LDAP_ADMIN_PASSWORD': 'grafana',
|
"LDAP_ADMIN_PASSWORD": "grafana",
|
||||||
'LDAP_DOMAIN': 'grafana.org',
|
"LDAP_DOMAIN": "grafana.org",
|
||||||
'SLAPD_ADDITIONAL_MODULES': 'memberof',
|
"SLAPD_ADDITIONAL_MODULES": "memberof",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+1128
-843
File diff suppressed because it is too large
Load Diff
+102
-57
@@ -1,91 +1,136 @@
|
|||||||
|
"""
|
||||||
|
This module contains utility functions for generating Drone pipelines.
|
||||||
|
"""
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/steps/lib.star',
|
"scripts/drone/steps/lib.star",
|
||||||
'download_grabpl_step',
|
"slack_step",
|
||||||
'slack_step',
|
|
||||||
)
|
)
|
||||||
|
load("scripts/drone/vault.star", "pull_secret")
|
||||||
|
|
||||||
load('scripts/drone/vault.star', 'from_secret', 'github_token', 'pull_secret', 'drone_token')
|
failure_template = "Build {{build.number}} failed for commit: <https://github.com/{{repo.owner}}/{{repo.name}}/commit/{{build.commit}}|{{ truncate build.commit 8 }}>: {{build.link}}\nBranch: <https://github.com/{{ repo.owner }}/{{ repo.name }}/commits/{{ build.branch }}|{{ build.branch }}>\nAuthor: {{build.author}}"
|
||||||
|
drone_change_template = "`.drone.yml` and `starlark` files have been changed on the OSS repo, by: {{build.author}}. \nBranch: <https://github.com/{{ repo.owner }}/{{ repo.name }}/commits/{{ build.branch }}|{{ build.branch }}>\nCommit hash: <https://github.com/{{repo.owner}}/{{repo.name}}/commit/{{build.commit}}|{{ truncate build.commit 8 }}>"
|
||||||
failure_template = 'Build {{build.number}} failed for commit: <https://github.com/{{repo.owner}}/{{repo.name}}/commit/{{build.commit}}|{{ truncate build.commit 8 }}>: {{build.link}}\nBranch: <https://github.com/{{ repo.owner }}/{{ repo.name }}/commits/{{ build.branch }}|{{ build.branch }}>\nAuthor: {{build.author}}'
|
|
||||||
drone_change_template = '`.drone.yml` and `starlark` files have been changed on the OSS repo, by: {{build.author}}. \nBranch: <https://github.com/{{ repo.owner }}/{{ repo.name }}/commits/{{ build.branch }}|{{ build.branch }}>\nCommit hash: <https://github.com/{{repo.owner}}/{{repo.name}}/commit/{{build.commit}}|{{ truncate build.commit 8 }}>'
|
|
||||||
|
|
||||||
def pipeline(
|
def pipeline(
|
||||||
name, edition, trigger, steps, services=[], platform='linux', depends_on=[], environment=None, volumes=[],
|
name,
|
||||||
):
|
edition,
|
||||||
if platform != 'windows':
|
trigger,
|
||||||
|
steps,
|
||||||
|
services = [],
|
||||||
|
platform = "linux",
|
||||||
|
depends_on = [],
|
||||||
|
environment = None,
|
||||||
|
volumes = []):
|
||||||
|
"""Generate a Drone Docker pipeline with commonly used values.
|
||||||
|
|
||||||
|
In addition to the parameters provided, it configures:
|
||||||
|
- the use of an image pull secret
|
||||||
|
- a retry count for cloning
|
||||||
|
- a volume 'docker' that can be used to access the Docker socket
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: controls the pipeline name.
|
||||||
|
edition: used to differentiate the pipeline for enterprise builds.
|
||||||
|
trigger: a Drone trigger for the pipeline.
|
||||||
|
steps: the Drone steps for the pipeline.
|
||||||
|
services: auxilliary services used during the pipeline.
|
||||||
|
Defaults to [].
|
||||||
|
platform: abstracts platform specific configuration primarily for different Drone behavior on Windows.
|
||||||
|
Defaults to 'linux'.
|
||||||
|
depends_on: list of pipelines that must have succeeded before this pipeline can start.
|
||||||
|
Defaults to [].
|
||||||
|
environment: environment variables passed through to pipeline steps.
|
||||||
|
Defaults to None.
|
||||||
|
volumes: additional volumes available to be mounted by pipeline steps.
|
||||||
|
Defaults to [].
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Drone pipeline
|
||||||
|
"""
|
||||||
|
if platform != "windows":
|
||||||
platform_conf = {
|
platform_conf = {
|
||||||
'platform': {
|
"platform": {"os": "linux", "arch": "amd64"},
|
||||||
'os': 'linux',
|
|
||||||
'arch': 'amd64'
|
|
||||||
},
|
|
||||||
# A shared cache is used on the host
|
# A shared cache is used on the host
|
||||||
# To avoid issues with parallel builds, we run this repo on single build agents
|
# To avoid issues with parallel builds, we run this repo on single build agents
|
||||||
'node': {
|
"node": {"type": "no-parallel"},
|
||||||
'type': 'no-parallel'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
platform_conf = {
|
platform_conf = {
|
||||||
'platform': {
|
"platform": {
|
||||||
'os': 'windows',
|
"os": "windows",
|
||||||
'arch': 'amd64',
|
"arch": "amd64",
|
||||||
'version': '1809',
|
"version": "1809",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline = {
|
pipeline = {
|
||||||
'kind': 'pipeline',
|
"kind": "pipeline",
|
||||||
'type': 'docker',
|
"type": "docker",
|
||||||
'name': name,
|
"name": name,
|
||||||
'trigger': trigger,
|
"trigger": trigger,
|
||||||
'services': services,
|
"services": services,
|
||||||
'steps': steps,
|
"steps": steps,
|
||||||
'clone': {
|
"clone": {
|
||||||
'retries': 3,
|
"retries": 3,
|
||||||
},
|
},
|
||||||
'volumes': [{
|
"volumes": [
|
||||||
'name': 'docker',
|
{
|
||||||
'host': {
|
"name": "docker",
|
||||||
'path': '/var/run/docker.sock',
|
"host": {
|
||||||
|
"path": "/var/run/docker.sock",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}],
|
],
|
||||||
'depends_on': depends_on,
|
"depends_on": depends_on,
|
||||||
'image_pull_secrets': [pull_secret],
|
"image_pull_secrets": [pull_secret],
|
||||||
}
|
}
|
||||||
if environment:
|
if environment:
|
||||||
pipeline.update({
|
pipeline.update(
|
||||||
'environment': environment,
|
{
|
||||||
})
|
"environment": environment,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
pipeline['volumes'].extend(volumes)
|
pipeline["volumes"].extend(volumes)
|
||||||
pipeline.update(platform_conf)
|
pipeline.update(platform_conf)
|
||||||
|
|
||||||
if edition in ('enterprise', 'enterprise2'):
|
if edition in ("enterprise", "enterprise2"):
|
||||||
# We have a custom clone step for enterprise
|
# We have a custom clone step for enterprise
|
||||||
pipeline['clone'] = {
|
pipeline["clone"] = {
|
||||||
'disable': True,
|
"disable": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
return pipeline
|
return pipeline
|
||||||
|
|
||||||
def notify_pipeline(name, slack_channel, trigger, depends_on=[], template=None, secret=None):
|
def notify_pipeline(
|
||||||
|
name,
|
||||||
|
slack_channel,
|
||||||
|
trigger,
|
||||||
|
depends_on = [],
|
||||||
|
template = None,
|
||||||
|
secret = None):
|
||||||
trigger = dict(trigger)
|
trigger = dict(trigger)
|
||||||
return {
|
return {
|
||||||
'kind': 'pipeline',
|
"kind": "pipeline",
|
||||||
'type': 'docker',
|
"type": "docker",
|
||||||
'platform': {
|
"platform": {
|
||||||
'os': 'linux',
|
"os": "linux",
|
||||||
'arch': 'amd64',
|
"arch": "amd64",
|
||||||
},
|
},
|
||||||
'name': name,
|
"name": name,
|
||||||
'trigger': trigger,
|
"trigger": trigger,
|
||||||
'steps': [
|
"steps": [
|
||||||
slack_step(slack_channel, template, secret),
|
slack_step(slack_channel, template, secret),
|
||||||
],
|
],
|
||||||
'clone': {
|
"clone": {
|
||||||
'retries': 3,
|
"retries": 3,
|
||||||
},
|
},
|
||||||
'depends_on': depends_on,
|
"depends_on": depends_on,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO: this overrides any existing dependencies because we're following the existing logic
|
||||||
|
# it should append to any existing dependencies
|
||||||
|
def with_deps(steps, deps = []):
|
||||||
|
for step in steps:
|
||||||
|
step["depends_on"] = deps
|
||||||
|
return steps
|
||||||
|
|||||||
+68
-53
@@ -1,82 +1,97 @@
|
|||||||
pull_secret = 'dockerconfigjson'
|
"""
|
||||||
github_token = 'github_token'
|
This module returns functions for generating Drone secrets fetched from Vault.
|
||||||
drone_token = 'drone_token'
|
"""
|
||||||
prerelease_bucket = 'prerelease_bucket'
|
pull_secret = "dockerconfigjson"
|
||||||
gcp_upload_artifacts_key = 'gcp_upload_artifacts_key'
|
drone_token = "drone_token"
|
||||||
azure_sp_app_id = 'azure_sp_app_id'
|
prerelease_bucket = "prerelease_bucket"
|
||||||
azure_sp_app_pw = 'azure_sp_app_pw'
|
gcp_upload_artifacts_key = "gcp_upload_artifacts_key"
|
||||||
azure_tenant = 'azure_tenant'
|
azure_sp_app_id = "azure_sp_app_id"
|
||||||
|
azure_sp_app_pw = "azure_sp_app_pw"
|
||||||
|
azure_tenant = "azure_tenant"
|
||||||
|
|
||||||
def from_secret(secret):
|
def from_secret(secret):
|
||||||
return {
|
return {"from_secret": secret}
|
||||||
'from_secret': secret
|
|
||||||
}
|
|
||||||
|
|
||||||
def vault_secret(name, path, key):
|
def vault_secret(name, path, key):
|
||||||
return {
|
return {
|
||||||
'kind': 'secret',
|
"kind": "secret",
|
||||||
'name': name,
|
"name": name,
|
||||||
'get': {
|
"get": {
|
||||||
'path': path,
|
"path": path,
|
||||||
'name': key,
|
"name": key,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def secrets():
|
def secrets():
|
||||||
return [
|
return [
|
||||||
vault_secret(pull_secret, 'secret/data/common/gcr', '.dockerconfigjson'),
|
vault_secret(pull_secret, "secret/data/common/gcr", ".dockerconfigjson"),
|
||||||
vault_secret(github_token, 'infra/data/ci/github/grafanabot', 'pat'),
|
vault_secret("github_token", "infra/data/ci/github/grafanabot", "pat"),
|
||||||
vault_secret(drone_token, 'infra/data/ci/drone', 'machine-user-token'),
|
vault_secret(drone_token, "infra/data/ci/drone", "machine-user-token"),
|
||||||
vault_secret(prerelease_bucket, 'infra/data/ci/grafana/prerelease', 'bucket'),
|
vault_secret(prerelease_bucket, "infra/data/ci/grafana/prerelease", "bucket"),
|
||||||
vault_secret(gcp_upload_artifacts_key, 'infra/data/ci/grafana/releng/artifacts-uploader-service-account', 'credentials.json'),
|
vault_secret(
|
||||||
vault_secret(azure_sp_app_id, 'infra/data/ci/datasources/cpp-azure-resourcemanager-credentials', 'application_id'),
|
gcp_upload_artifacts_key,
|
||||||
vault_secret(azure_sp_app_pw, 'infra/data/ci/datasources/cpp-azure-resourcemanager-credentials', 'application_secret'),
|
"infra/data/ci/grafana/releng/artifacts-uploader-service-account",
|
||||||
vault_secret(azure_tenant, 'infra/data/ci/datasources/cpp-azure-resourcemanager-credentials', 'tenant_id'),
|
"credentials.json",
|
||||||
|
),
|
||||||
|
vault_secret(
|
||||||
|
azure_sp_app_id,
|
||||||
|
"infra/data/ci/datasources/cpp-azure-resourcemanager-credentials",
|
||||||
|
"application_id",
|
||||||
|
),
|
||||||
|
vault_secret(
|
||||||
|
azure_sp_app_pw,
|
||||||
|
"infra/data/ci/datasources/cpp-azure-resourcemanager-credentials",
|
||||||
|
"application_secret",
|
||||||
|
),
|
||||||
|
vault_secret(
|
||||||
|
azure_tenant,
|
||||||
|
"infra/data/ci/datasources/cpp-azure-resourcemanager-credentials",
|
||||||
|
"tenant_id",
|
||||||
|
),
|
||||||
# Package publishing
|
# Package publishing
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'packages_gpg_public_key',
|
"packages_gpg_public_key",
|
||||||
'infra/data/ci/packages-publish/gpg',
|
"infra/data/ci/packages-publish/gpg",
|
||||||
'public-key-b64',
|
"public-key-b64",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'packages_gpg_private_key',
|
"packages_gpg_private_key",
|
||||||
'infra/data/ci/packages-publish/gpg',
|
"infra/data/ci/packages-publish/gpg",
|
||||||
'private-key-b64',
|
"private-key-b64",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'packages_gpg_passphrase',
|
"packages_gpg_passphrase",
|
||||||
'infra/data/ci/packages-publish/gpg',
|
"infra/data/ci/packages-publish/gpg",
|
||||||
'passphrase',
|
"passphrase",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'packages_service_account',
|
"packages_service_account",
|
||||||
'infra/data/ci/packages-publish/service-account',
|
"infra/data/ci/packages-publish/service-account",
|
||||||
'credentials.json',
|
"credentials.json",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'packages_access_key_id',
|
"packages_access_key_id",
|
||||||
'infra/data/ci/packages-publish/bucket-credentials',
|
"infra/data/ci/packages-publish/bucket-credentials",
|
||||||
'AccessID',
|
"AccessID",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'packages_secret_access_key',
|
"packages_secret_access_key",
|
||||||
'infra/data/ci/packages-publish/bucket-credentials',
|
"infra/data/ci/packages-publish/bucket-credentials",
|
||||||
'Secret',
|
"Secret",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'aws_region',
|
"aws_region",
|
||||||
'secret/data/common/aws-marketplace',
|
"secret/data/common/aws-marketplace",
|
||||||
'aws_region',
|
"aws_region",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'aws_access_key_id',
|
"aws_access_key_id",
|
||||||
'secret/data/common/aws-marketplace',
|
"secret/data/common/aws-marketplace",
|
||||||
'aws_access_key_id',
|
"aws_access_key_id",
|
||||||
),
|
),
|
||||||
vault_secret(
|
vault_secret(
|
||||||
'aws_secret_access_key',
|
"aws_secret_access_key",
|
||||||
'secret/data/common/aws-marketplace',
|
"secret/data/common/aws-marketplace",
|
||||||
'aws_secret_access_key',
|
"aws_secret_access_key",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
|
"""
|
||||||
|
This module returns the pipeline used for version branches.
|
||||||
|
"""
|
||||||
|
|
||||||
load(
|
load(
|
||||||
'scripts/drone/events/release.star',
|
"scripts/drone/events/release.star",
|
||||||
'release_pipelines',
|
"enterprise2_pipelines",
|
||||||
|
"enterprise_pipelines",
|
||||||
|
"oss_pipelines",
|
||||||
)
|
)
|
||||||
|
|
||||||
ver_mode = 'release-branch'
|
ver_mode = "release-branch"
|
||||||
|
trigger = {"ref": ["refs/heads/v[0-9]*"]}
|
||||||
|
|
||||||
def version_branch_pipelines():
|
def version_branch_pipelines():
|
||||||
return release_pipelines(ver_mode=ver_mode, trigger={
|
return (
|
||||||
'ref': ['refs/heads/v[0-9]*'],
|
oss_pipelines(ver_mode = ver_mode, trigger = trigger) +
|
||||||
})
|
enterprise_pipelines(ver_mode = ver_mode, trigger = trigger) +
|
||||||
|
enterprise2_pipelines(ver_mode = ver_mode, trigger = trigger)
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user