mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Toolkit: simplify the plugin ci docker image (#23267)
* removing src dir on publish * Moved from binary to native typescript 1. Moved to a native typescrpt github publish using the existing github client. 2. Change dist.js to detect running in a linked environment. Todo: Optimize docker image for build size. * Optimized build of docker container Much smaller. From 5.47 gb to 2.88 * Feedback from discussion with Ryan - Added gget for getting grafana versions - Added infrastructure for testing - Uploaded new docker image * Fixed typo... Not sure what happened there :) * Added command to download canary * small fix for displaying versions in help * Removed --dev option Should really just rename version to (ex: 1.2.0-dev) * removing src dir on publish * Moved from binary to native typescript 1. Moved to a native typescrpt github publish using the existing github client. 2. Change dist.js to detect running in a linked environment. Todo: Optimize docker image for build size. * Optimized build of docker container Much smaller. From 5.47 gb to 2.88 * Feedback from discussion with Ryan - Added gget for getting grafana versions - Added infrastructure for testing - Uploaded new docker image * Fixed typo... Not sure what happened there :) * Added command to download canary * small fix for displaying versions in help * Removed --dev option Should really just rename version to (ex: 1.2.0-dev)
This commit is contained in:
parent
06ba5201bb
commit
c5252f1b64
@ -34,6 +34,7 @@ export interface PluginMeta<T extends KeyValue = {}> {
|
|||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
defaultNavUrl?: string;
|
defaultNavUrl?: string;
|
||||||
hasUpdate?: boolean;
|
hasUpdate?: boolean;
|
||||||
|
enterprise?: boolean;
|
||||||
latestVersion?: string;
|
latestVersion?: string;
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
// This bin is used for cli installed from npm
|
const fs = require('fs');
|
||||||
|
|
||||||
require('../src/cli/index.js').run();
|
entrypoint = () => {
|
||||||
|
const defaultEntryPoint = '../src/cli/index.js';
|
||||||
|
// We are running in dev mode. Don't use compiled binaries, rather use the dev entrypoint.
|
||||||
|
if (fs.existsSync(`${process.env['HOME']}/.config/yarn/link/@grafana/toolkit`)) {
|
||||||
|
console.log('Running in linked mode');
|
||||||
|
return `${__dirname}/grafana-toolkit.js`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are using npx, and a relative path does not find index.js
|
||||||
|
if (!fs.existsSync(defaultEntryPoint) && fs.existsSync(`${__dirname}/../dist/src/cli/index.js`)) {
|
||||||
|
return `${__dirname}/../dist/src/cli/index.js`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The default entrypoint must exist, return it now.
|
||||||
|
return defaultEntryPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
require(entrypoint()).run();
|
||||||
|
@ -1,51 +1,6 @@
|
|||||||
FROM circleci/node:12-browsers
|
FROM circleci/node:12-browsers
|
||||||
USER root
|
USER root
|
||||||
WORKDIR /tmp
|
ADD scripts scripts
|
||||||
|
WORKDIR scripts
|
||||||
# Install Go
|
RUN ./deploy.sh
|
||||||
ADD https://dl.google.com/go/go1.14.linux-amd64.tar.gz /tmp
|
ADD install/gget /usr/local/bin/gget
|
||||||
RUN echo 08df79b46b0adf498ea9f320a0f23d6ec59e9003660b4c9c1ce8e5e2c6f823ca go1.14.linux-amd64.tar.gz | sha256sum --check --status
|
|
||||||
RUN tar -C /usr/local -xf go1.14.linux-amd64.tar.gz
|
|
||||||
|
|
||||||
# Install golangci-lint
|
|
||||||
ADD https://github.com/golangci/golangci-lint/releases/download/v1.23.7/golangci-lint-1.23.7-linux-amd64.tar.gz /tmp
|
|
||||||
RUN echo 34df1794a2ea8e168b3c98eed3cc0f3e13ed4cba735e4e40ef141df5c41bc086 golangci-lint-1.23.7-linux-amd64.tar.gz | sha256sum --check --status
|
|
||||||
RUN tar xf golangci-lint-1.23.7-linux-amd64.tar.gz
|
|
||||||
RUN mv golangci-lint-1.23.7-linux-amd64/golangci-lint /usr/local/bin
|
|
||||||
RUN ln -s /usr/local/go/bin/go /usr/local/bin/go
|
|
||||||
RUN ln -s /usr/local/go/bin/gofmt /usr/local/bin/gofmt
|
|
||||||
RUN chmod 755 /usr/local/bin/golangci-lint
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN apt-get update -y && apt-get install -y adduser libfontconfig1 locate && /bin/rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install code climate
|
|
||||||
ADD https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 /usr/local/bin/cc-test-reporter
|
|
||||||
RUN echo 38f2442892027f61a07f52c845818750261b2ba58bffb043a582495339d37c05 /usr/local/bin/cc-test-reporter | sha256sum --check --status
|
|
||||||
RUN chmod +x /usr/local/bin/cc-test-reporter
|
|
||||||
|
|
||||||
# Download, but don't install previous grafana releases
|
|
||||||
RUN mkdir -pv /usr/local/grafana/deb
|
|
||||||
ADD https://dl.grafana.com/oss/release/grafana_6.6.2_amd64.deb /usr/local/grafana/deb
|
|
||||||
ADD https://dl.grafana.com/oss/release/grafana_6.5.3_amd64.deb /usr/local/grafana/deb
|
|
||||||
ADD https://dl.grafana.com/oss/release/grafana_6.4.5_amd64.deb /usr/local/grafana/deb
|
|
||||||
ADD https://dl.grafana.com/oss/release/grafana_6.3.7_amd64.deb /usr/local/grafana/deb
|
|
||||||
|
|
||||||
# Perform user specific initialization
|
|
||||||
USER circleci
|
|
||||||
RUN mkdir -pv ${HOME}/plugin ${HOME}/go/bin ${HOME}/bin ${HOME}/src ${HOME}/tmp
|
|
||||||
|
|
||||||
# Install grafana release with yarn
|
|
||||||
RUN git clone https://github.com/grafana/grafana.git ${HOME}/src/grafana
|
|
||||||
WORKDIR /home/circleci/src/grafana
|
|
||||||
RUN git checkout tags/v$(curl -s https://raw.githubusercontent.com/grafana/grafana/master/latest.json | jq -r '.stable')
|
|
||||||
RUN yarn cache clean && yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
# Install Mage
|
|
||||||
RUN git clone https://github.com/magefile/mage.git ${HOME}/src/mage
|
|
||||||
WORKDIR /home/circleci/src/mage
|
|
||||||
RUN go run bootstrap.go
|
|
||||||
|
|
||||||
ENV PATH /home/circleci/go/bin:/usr/local/go/bin:/home/circleci/.local/bin:/home/circleci/bin:${PATH}
|
|
||||||
WORKDIR /home/circleci/plugin
|
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ The home directory will be `/home/circleci`
|
|||||||
|
|
||||||
All of the above directories are in the path, so there is no need to specify fully qualified paths.
|
All of the above directories are in the path, so there is no need to specify fully qualified paths.
|
||||||
|
|
||||||
## Grafana source
|
## Grafana
|
||||||
- Installed in `/home/circleci/src/grafana`
|
- Installed in `/home/circleci/src/grafana`
|
||||||
- `yarn install` has been run
|
- `yarn install` has been run
|
||||||
|
|
||||||
@ -47,5 +47,15 @@ To test, your CircleCI config will need a run section with something similar to
|
|||||||
# Building
|
# Building
|
||||||
To build, cd to `<srcroot>/packages/grafana-toolkit/docker/grafana-plugin-ci`
|
To build, cd to `<srcroot>/packages/grafana-toolkit/docker/grafana-plugin-ci`
|
||||||
```
|
```
|
||||||
docker build .
|
./build.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Developing/Testing
|
||||||
|
To test, you should have docker-compose installed.
|
||||||
|
```
|
||||||
|
cd test
|
||||||
|
./start.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
You will be in /home/circleci/test with the buildscripts installed to the local directory.
|
||||||
|
Do your edits/run tests. When saving, your edits will be available in the container immediately.
|
8
packages/grafana-toolkit/docker/grafana-plugin-ci/build.sh
Executable file
8
packages/grafana-toolkit/docker/grafana-plugin-ci/build.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
output=$(docker build . | tee /dev/tty)
|
||||||
|
hash=$(echo "$output" | tail -1 | sed -ne "s/^Successfully built \(.*\)/\1/p")
|
||||||
|
docker tag "$hash" $DOCKER_IMAGE_NAME:latest
|
||||||
|
docker push $DOCKER_IMAGE_NAME:latest
|
||||||
|
|
7
packages/grafana-toolkit/docker/grafana-plugin-ci/common.sh
Executable file
7
packages/grafana-toolkit/docker/grafana-plugin-ci/common.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
##
|
||||||
|
## Common variable declarations
|
||||||
|
##
|
||||||
|
|
||||||
|
DOCKER_IMAGE_NAME="srclosson/grafana-plugin-ci"
|
63
packages/grafana-toolkit/docker/grafana-plugin-ci/install/gget
Executable file
63
packages/grafana-toolkit/docker/grafana-plugin-ci/install/gget
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
##
|
||||||
|
# gget
|
||||||
|
# A script to get and install grafana versions
|
||||||
|
# for usage information see "show_help" below.
|
||||||
|
#
|
||||||
|
|
||||||
|
latest=$(curl -s 'https://raw.githubusercontent.com/grafana/grafana/master/latest.json' | jq -r '.stable')
|
||||||
|
canary=$(curl -s "https://grafana.com/api/grafana/versions" | jq ".items[0].version" | tr -d '"')
|
||||||
|
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: gget <version>"
|
||||||
|
echo ""
|
||||||
|
echo "where <version> can be:"
|
||||||
|
echo " 1) A version from https://grafana.com/grafana/download (ex x.y.z)"
|
||||||
|
echo " 2) latest (currently $latest)"
|
||||||
|
echo " 3) canary (currently $canary)"
|
||||||
|
echo ""
|
||||||
|
echo " -h, --help: Display this help message"
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
opts=$(getopt -o h --long help -n 'gget' -- "$@")
|
||||||
|
[ $? -eq 0 ] || {
|
||||||
|
show_help
|
||||||
|
}
|
||||||
|
|
||||||
|
eval set -- "$opts"
|
||||||
|
while true; do
|
||||||
|
case "$1" in
|
||||||
|
-h | --help)
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -z "$1" ] && show_help
|
||||||
|
|
||||||
|
# Make sure the script is being run as root
|
||||||
|
if [ $EUID -ne 0 ]; then
|
||||||
|
echo "This script must be run as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
##
|
||||||
|
# MAIN
|
||||||
|
#
|
||||||
|
# Enough setup, let's actually do something
|
||||||
|
#
|
||||||
|
version=$1
|
||||||
|
[ "$version" == "latest" ] && version="$latest"
|
||||||
|
[ "$version" == "canary" ] && version="$canary"
|
||||||
|
wget "https://dl.grafana.com/oss/release/grafana_${version}_amd64.deb" -O "/tmp/grafana_${version}_amd64.deb"
|
||||||
|
dpkg -i "/tmp/grafana_${version}_amd64.deb" && /bin/rm -rfv "/tmp/grafana_${version}_amd64.deb"
|
38
packages/grafana-toolkit/docker/grafana-plugin-ci/scripts/deploy-common.sh
Executable file
38
packages/grafana-toolkit/docker/grafana-plugin-ci/scripts/deploy-common.sh
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
##
|
||||||
|
# Script to deploy a docker image. Must return exit code 0
|
||||||
|
#
|
||||||
|
do_exit() {
|
||||||
|
message="$1"
|
||||||
|
exit_code="$2"
|
||||||
|
|
||||||
|
echo "$message"
|
||||||
|
exit $exit_code
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Get file, get's a file, validates the SHA
|
||||||
|
# @param filename
|
||||||
|
# @param expected sha value
|
||||||
|
# @returns 0 if successful, -1 of checksum validation failed.
|
||||||
|
#
|
||||||
|
get_file () {
|
||||||
|
[ -n "$1" ] && url=$1 || do_exit "url required" -1
|
||||||
|
[ -n "$2" ] && dest=$2 || do_exit "destination required" -2
|
||||||
|
sha=$3
|
||||||
|
file=$(basename $dest)
|
||||||
|
|
||||||
|
wget "$url" -O "$dest"
|
||||||
|
if [ -n "$sha" ]; then
|
||||||
|
echo "$sha $dest" | sha256sum --check --status || do_exit "Checksum validation failed for $file. Exiting" -1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
untar_file () {
|
||||||
|
[ -n "$1" ] && src=$1 || do_exit "src required" -1
|
||||||
|
[ -n "$2" ] && dest=$2 || dest="/usr/local"
|
||||||
|
|
||||||
|
tar -C "$dest" -xf "$src" && /bin/rm -rf "$src"
|
||||||
|
}
|
3
packages/grafana-toolkit/docker/grafana-plugin-ci/scripts/deploy-user.sh
Executable file
3
packages/grafana-toolkit/docker/grafana-plugin-ci/scripts/deploy-user.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
source "./deploy-common.sh"
|
||||||
|
|
43
packages/grafana-toolkit/docker/grafana-plugin-ci/scripts/deploy.sh
Executable file
43
packages/grafana-toolkit/docker/grafana-plugin-ci/scripts/deploy.sh
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
source "./deploy-common.sh"
|
||||||
|
|
||||||
|
# Install Go
|
||||||
|
filename="go1.14.linux-amd64.tar.gz"
|
||||||
|
get_file "https://dl.google.com/go/$filename" "/tmp/$filename" "08df79b46b0adf498ea9f320a0f23d6ec59e9003660b4c9c1ce8e5e2c6f823ca"
|
||||||
|
untar_file "/tmp/$filename"
|
||||||
|
|
||||||
|
|
||||||
|
# Install golangci-lint
|
||||||
|
filename="golangci-lint-1.23.7-linux-amd64.tar.gz"
|
||||||
|
get_file "https://github.com/golangci/golangci-lint/releases/download/v1.23.7/$filename" \
|
||||||
|
"/tmp/$filename" \
|
||||||
|
"34df1794a2ea8e168b3c98eed3cc0f3e13ed4cba735e4e40ef141df5c41bc086"
|
||||||
|
untar_file "/tmp/$filename"
|
||||||
|
chmod 755 /usr/local/bin/golangci-lint
|
||||||
|
ln -s /usr/local/golangci-lint-1.23.7-linux-amd64/golangci-lint /usr/local/bin/golangci-lint
|
||||||
|
ln -s /usr/local/go/bin/go /usr/local/bin/go
|
||||||
|
ln -s /usr/local/go/bin/gofmt /usr/local/bin/gofmt
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
apt-get update -y && apt-get install -y adduser libfontconfig1 locate && /bin/rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install code climate
|
||||||
|
get_file "https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64" \
|
||||||
|
"/usr/local/bin/cc-test-reporter" \
|
||||||
|
"38f2442892027f61a07f52c845818750261b2ba58bffb043a582495339d37c05"
|
||||||
|
chmod +x /usr/local/bin/cc-test-reporter
|
||||||
|
|
||||||
|
# Install Mage
|
||||||
|
mkdir -pv /tmp/mage $HOME/go/bin
|
||||||
|
git clone https://github.com/magefile/mage.git /tmp/mage
|
||||||
|
pushd /tmp/mage && go run bootstrap.go && popd
|
||||||
|
mv $HOME/go/bin/mage /usr/local/bin
|
||||||
|
# Cleanup after yourself
|
||||||
|
/bin/rm -rf /tmp/mage
|
||||||
|
/bin/rm -rf $HOME/go
|
||||||
|
|
||||||
|
# Perform user specific initialization
|
||||||
|
sudo -u circleci ./deploy-user.sh
|
||||||
|
|
||||||
|
# Get the size down
|
||||||
|
/bin/rm -rf /var/lib/apt/lists
|
@ -0,0 +1,8 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
citest:
|
||||||
|
image: "circleci/node:12-browsers"
|
||||||
|
user: root
|
||||||
|
volumes:
|
||||||
|
- ../scripts:/home/circleci/scripts
|
||||||
|
- ../install:/home/circleci/install
|
4
packages/grafana-toolkit/docker/grafana-plugin-ci/test/start.sh
Executable file
4
packages/grafana-toolkit/docker/grafana-plugin-ci/test/start.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Enter the docker container
|
||||||
|
docker-compose run citest bash -c "cd /home/circleci; exec bash --login -i"
|
@ -200,14 +200,12 @@ export const run = (includeInternalScripts = false) => {
|
|||||||
.option('--dryrun', 'Do a dry run only', false)
|
.option('--dryrun', 'Do a dry run only', false)
|
||||||
.option('--verbose', 'Print verbose', false)
|
.option('--verbose', 'Print verbose', false)
|
||||||
.option('--commitHash <hashKey>', 'Specify the commit hash')
|
.option('--commitHash <hashKey>', 'Specify the commit hash')
|
||||||
.option('--recreate', 'Recreate the release if already present')
|
.description('Publish to github')
|
||||||
.description('Publish to github ... etc etc etc')
|
|
||||||
.action(async cmd => {
|
.action(async cmd => {
|
||||||
await execTask(githubPublishTask)({
|
await execTask(githubPublishTask)({
|
||||||
dryrun: cmd.dryrun,
|
dryrun: cmd.dryrun,
|
||||||
verbose: cmd.verbose,
|
verbose: cmd.verbose,
|
||||||
commitHash: cmd.commitHash,
|
commitHash: cmd.commitHash,
|
||||||
recreate: cmd.recreate,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import { GitHubRelease } from '../utils/githubRelease';
|
|||||||
import { getPluginId } from '../../config/utils/getPluginId';
|
import { getPluginId } from '../../config/utils/getPluginId';
|
||||||
import { getCiFolder } from '../../plugins/env';
|
import { getCiFolder } from '../../plugins/env';
|
||||||
import { useSpinner } from '../utils/useSpinner';
|
import { useSpinner } from '../utils/useSpinner';
|
||||||
|
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -20,10 +19,11 @@ const releaseNotes = async (): Promise<string> => {
|
|||||||
const checkoutBranch = async (branchName: string): Promise<Command> => {
|
const checkoutBranch = async (branchName: string): Promise<Command> => {
|
||||||
const currentBranch = await execa.shell(`git rev-parse --abbrev-ref HEAD`);
|
const currentBranch = await execa.shell(`git rev-parse --abbrev-ref HEAD`);
|
||||||
const branchesAvailable = await execa.shell(
|
const branchesAvailable = await execa.shell(
|
||||||
`(git branch -a | grep ${branchName} | grep -v remote) || echo 'No release found'`
|
`(git branch -a | grep "${branchName}$" | grep -v remote) || echo 'No release found'`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (currentBranch.stdout !== branchName) {
|
if (currentBranch.stdout !== branchName) {
|
||||||
|
console.log('available', branchesAvailable.stdout.trim());
|
||||||
if (branchesAvailable.stdout.trim() === branchName) {
|
if (branchesAvailable.stdout.trim() === branchName) {
|
||||||
return ['git', ['checkout', branchName]];
|
return ['git', ['checkout', branchName]];
|
||||||
} else {
|
} else {
|
||||||
@ -61,27 +61,28 @@ const prepareRelease = useSpinner<any>('Preparing release', async ({ dryrun, ver
|
|||||||
const distDir = path.resolve(ciDir, 'dist');
|
const distDir = path.resolve(ciDir, 'dist');
|
||||||
const distContentDir = path.resolve(distDir, getPluginId());
|
const distContentDir = path.resolve(distDir, getPluginId());
|
||||||
const pluginJsonFile = path.resolve(distContentDir, 'plugin.json');
|
const pluginJsonFile = path.resolve(distContentDir, 'plugin.json');
|
||||||
const pluginVersion = getPluginJson(pluginJsonFile).info.version;
|
const pluginJson = getPluginJson(pluginJsonFile);
|
||||||
const GIT_EMAIL = 'eng@grafana.com';
|
const GIT_EMAIL = 'eng@grafana.com';
|
||||||
const GIT_USERNAME = 'CircleCI Automation';
|
const GIT_USERNAME = 'CircleCI Automation';
|
||||||
|
|
||||||
const githubPublishScript: Command = [
|
const githubPublishScript: Command = [
|
||||||
['git', ['config', 'user.email', GIT_EMAIL]],
|
['git', ['config', 'user.email', GIT_EMAIL]],
|
||||||
['git', ['config', 'user.name', GIT_USERNAME]],
|
['git', ['config', 'user.name', GIT_USERNAME]],
|
||||||
await checkoutBranch(`release-${pluginVersion}`),
|
await checkoutBranch(`release-${pluginJson.info.version}`),
|
||||||
['cp', ['-rf', distContentDir, 'dist'], { dryrun }],
|
['cp', ['-rf', distContentDir, 'dist']],
|
||||||
['git', ['add', '--force', distDir], { dryrun }],
|
['git', ['add', '--force', distDir], { dryrun }],
|
||||||
['git', ['add', '--force', 'dist'], { dryrun }],
|
['git', ['add', '--force', 'dist'], { dryrun }],
|
||||||
|
['/bin/rm', ['-rf', 'src'], { enterprise: true }],
|
||||||
[
|
[
|
||||||
'git',
|
'git',
|
||||||
['commit', '-m', `automated release ${pluginVersion} [skip ci]`],
|
['commit', '-m', `automated release ${pluginJson.info.version} [skip ci]`],
|
||||||
{
|
{
|
||||||
dryrun,
|
dryrun,
|
||||||
okOnError: [/nothing to commit/g, /nothing added to commit/g, /no changes added to commit/g],
|
okOnError: [/nothing to commit/g, /nothing added to commit/g, /no changes added to commit/g],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
['git', ['tag', '-f', pluginVersion]],
|
['git', ['tag', '-f', pluginJson.info.version]],
|
||||||
['git', ['push', '-f', 'origin', `release-${pluginVersion}`], { dryrun }],
|
['git', ['push', '-f', 'origin', `release-${pluginJson.info.version}`], { dryrun }],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let line of githubPublishScript) {
|
for (let line of githubPublishScript) {
|
||||||
@ -98,6 +99,11 @@ const prepareRelease = useSpinner<any>('Preparing release', async ({ dryrun, ver
|
|||||||
if (opts['dryrun']) {
|
if (opts['dryrun']) {
|
||||||
line[1].push('--dry-run');
|
line[1].push('--dry-run');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pluginJson.enterprise && !opts['enterprise']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const { stdout } = await execa(command, args);
|
const { stdout } = await execa(command, args);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
console.log(stdout);
|
console.log(stdout);
|
||||||
@ -129,19 +135,18 @@ const prepareRelease = useSpinner<any>('Preparing release', async ({ dryrun, ver
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface GithubPluglishReleaseOptions {
|
interface GithubPublishReleaseOptions {
|
||||||
commitHash?: string;
|
commitHash?: string;
|
||||||
recreate?: boolean;
|
|
||||||
githubToken: string;
|
githubToken: string;
|
||||||
gitRepoOwner: string;
|
gitRepoOwner: string;
|
||||||
gitRepoName: string;
|
gitRepoName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createRelease = useSpinner<GithubPluglishReleaseOptions>(
|
const createRelease = useSpinner<GithubPublishReleaseOptions>(
|
||||||
'Creating release',
|
'Creating release',
|
||||||
async ({ commitHash, recreate, githubToken, gitRepoName, gitRepoOwner }) => {
|
async ({ commitHash, githubToken, gitRepoName, gitRepoOwner }) => {
|
||||||
const gitRelease = new GitHubRelease(githubToken, gitRepoOwner, gitRepoName, await releaseNotes(), commitHash);
|
const gitRelease = new GitHubRelease(githubToken, gitRepoOwner, gitRepoName, await releaseNotes(), commitHash);
|
||||||
return gitRelease.release(recreate || false);
|
return gitRelease.release();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -149,10 +154,10 @@ export interface GithubPublishOptions {
|
|||||||
dryrun?: boolean;
|
dryrun?: boolean;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
commitHash?: string;
|
commitHash?: string;
|
||||||
recreate?: boolean;
|
dev?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const githubPublishRunner: TaskRunner<GithubPublishOptions> = async ({ dryrun, verbose, commitHash, recreate }) => {
|
const githubPublishRunner: TaskRunner<GithubPublishOptions> = async ({ dryrun, verbose, commitHash }) => {
|
||||||
if (!process.env['CIRCLE_REPOSITORY_URL']) {
|
if (!process.env['CIRCLE_REPOSITORY_URL']) {
|
||||||
throw `The release plugin requires you specify the repository url as environment variable CIRCLE_REPOSITORY_URL`;
|
throw `The release plugin requires you specify the repository url as environment variable CIRCLE_REPOSITORY_URL`;
|
||||||
}
|
}
|
||||||
@ -172,7 +177,6 @@ const githubPublishRunner: TaskRunner<GithubPublishOptions> = async ({ dryrun, v
|
|||||||
|
|
||||||
await createRelease({
|
await createRelease({
|
||||||
commitHash,
|
commitHash,
|
||||||
recreate,
|
|
||||||
githubToken,
|
githubToken,
|
||||||
gitRepoOwner: parsedUrl.owner,
|
gitRepoOwner: parsedUrl.owner,
|
||||||
gitRepoName: parsedUrl.name,
|
gitRepoName: parsedUrl.name,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
const grafanaURL = 'https://api.github.com/repos/grafana/grafana';
|
const grafanaURL = (repo: string) => `https://api.github.com/repos/grafana/${repo}`;
|
||||||
const enterpriseURL = 'https://api.github.com/repos/grafana/grafana-enterprise';
|
const enterpriseURL = 'https://api.github.com/repos/grafana/grafana-enterprise';
|
||||||
|
|
||||||
// Encapsulates the creation of a client for the Github API
|
// Encapsulates the creation of a client for the Github API
|
||||||
@ -14,17 +14,18 @@ const enterpriseURL = 'https://api.github.com/repos/grafana/grafana-enterprise';
|
|||||||
interface GithubClientProps {
|
interface GithubClientProps {
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
enterprise?: boolean;
|
enterprise?: boolean;
|
||||||
|
repo?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GithubClient {
|
class GithubClient {
|
||||||
client: AxiosInstance;
|
client: AxiosInstance;
|
||||||
|
|
||||||
constructor({ required = false, enterprise = false }: GithubClientProps = {}) {
|
constructor({ required = false, enterprise = false, repo = 'grafana' }: GithubClientProps = {}) {
|
||||||
const username = process.env.GITHUB_USERNAME;
|
const username = process.env.GITHUB_USERNAME;
|
||||||
const token = process.env.GITHUB_ACCESS_TOKEN;
|
const token = process.env.GITHUB_ACCESS_TOKEN;
|
||||||
|
|
||||||
const clientConfig: AxiosRequestConfig = {
|
const clientConfig: AxiosRequestConfig = {
|
||||||
baseURL: enterprise ? enterpriseURL : grafanaURL,
|
baseURL: enterprise ? enterpriseURL : grafanaURL(repo),
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,19 +2,22 @@ import { getPluginId } from '../../config/utils/getPluginId';
|
|||||||
import { getPluginJson } from '../../config/utils/pluginValidation';
|
import { getPluginJson } from '../../config/utils/pluginValidation';
|
||||||
import { getCiFolder } from '../../plugins/env';
|
import { getCiFolder } from '../../plugins/env';
|
||||||
import path = require('path');
|
import path = require('path');
|
||||||
|
import fs = require('fs');
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import execa = require('execa');
|
// import execa = require('execa');
|
||||||
|
import GithubClient from './githubClient';
|
||||||
|
import { AxiosResponse } from 'axios';
|
||||||
|
|
||||||
const ghrPlatform = (): string => {
|
const resolveContentType = (extension: string): string => {
|
||||||
switch (process.platform) {
|
switch (extension) {
|
||||||
case 'win32':
|
case 'zip':
|
||||||
return 'windows';
|
return 'application/zip';
|
||||||
case 'darwin':
|
case 'json':
|
||||||
return 'darwin';
|
return 'application/json';
|
||||||
case 'linux':
|
case 'sha1':
|
||||||
return 'linux';
|
return 'text/plain';
|
||||||
default:
|
default:
|
||||||
return process.platform;
|
return 'application/octet-stream';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,6 +27,7 @@ class GitHubRelease {
|
|||||||
repository: string;
|
repository: string;
|
||||||
releaseNotes: string;
|
releaseNotes: string;
|
||||||
commitHash?: string;
|
commitHash?: string;
|
||||||
|
git: GithubClient;
|
||||||
|
|
||||||
constructor(token: string, username: string, repository: string, releaseNotes: string, commitHash?: string) {
|
constructor(token: string, username: string, repository: string, releaseNotes: string, commitHash?: string) {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
@ -31,36 +35,37 @@ class GitHubRelease {
|
|||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.releaseNotes = releaseNotes;
|
this.releaseNotes = releaseNotes;
|
||||||
this.commitHash = commitHash;
|
this.commitHash = commitHash;
|
||||||
|
|
||||||
|
this.git = new GithubClient({
|
||||||
|
repo: repository,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async publishAssets(srcLocation: string, destUrl: string) {
|
||||||
* Get the ghr binary to perform the release
|
// Add the assets. Loop through files in the ci/dist folder and upload each asset.
|
||||||
*/
|
fs.readdir(srcLocation, (err: NodeJS.ErrnoException | null, files: string[]) => {
|
||||||
private async getGhr(): Promise<string> {
|
if (err) {
|
||||||
const GHR_VERSION = '0.13.0';
|
throw err;
|
||||||
const GHR_ARCH = process.arch === 'x64' ? 'amd64' : '386';
|
|
||||||
const GHR_PLATFORM = ghrPlatform();
|
|
||||||
const GHR_EXTENSION = process.platform === 'linux' ? 'tar.gz' : 'zip';
|
|
||||||
const outName = `./ghr.${GHR_EXTENSION}`;
|
|
||||||
const archiveName = `ghr_v${GHR_VERSION}_${GHR_PLATFORM}_${GHR_ARCH}`;
|
|
||||||
const exeName = process.platform === 'linux' ? 'ghr' : 'ghr.exe';
|
|
||||||
const exeNameFullPath = path.resolve(process.cwd(), archiveName, exeName);
|
|
||||||
const ghrUrl = `https://github.com/tcnksm/ghr/releases/download/v${GHR_VERSION}/${archiveName}.${GHR_EXTENSION}`;
|
|
||||||
await execa('wget', [ghrUrl, `--output-document=${outName}`]);
|
|
||||||
if (GHR_EXTENSION === 'tar.gz') {
|
|
||||||
await execa('tar', ['zxvf', outName]);
|
|
||||||
} else {
|
|
||||||
await execa('unzip', ['-p', outName]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
files.forEach(async (file: string) => {
|
||||||
await execa('chmod', ['755', exeNameFullPath]);
|
const fileStat = fs.statSync(`${srcLocation}/${file}`);
|
||||||
|
const fileData = fs.readFileSync(`${srcLocation}/${file}`);
|
||||||
|
try {
|
||||||
|
await this.git.client.post(`${destUrl}?name=${file}`, fileData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': resolveContentType(path.extname(file)),
|
||||||
|
'Content-Length': fileStat.size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (reason) {
|
||||||
|
console.log('Could not post', reason);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return exeNameFullPath;
|
async release() {
|
||||||
}
|
|
||||||
|
|
||||||
async release(recreate: boolean) {
|
|
||||||
const ciDir = getCiFolder();
|
const ciDir = getCiFolder();
|
||||||
const distDir = path.resolve(ciDir, 'dist');
|
const distDir = path.resolve(ciDir, 'dist');
|
||||||
const distContentDir = path.resolve(distDir, getPluginId());
|
const distContentDir = path.resolve(distDir, getPluginId());
|
||||||
@ -69,37 +74,31 @@ class GitHubRelease {
|
|||||||
const PUBLISH_DIR = path.resolve(getCiFolder(), 'packages');
|
const PUBLISH_DIR = path.resolve(getCiFolder(), 'packages');
|
||||||
const commitHash = this.commitHash || pluginInfo.build?.hash;
|
const commitHash = this.commitHash || pluginInfo.build?.hash;
|
||||||
|
|
||||||
// Get the ghr binary according to platform
|
try {
|
||||||
const ghrExe = await this.getGhr();
|
const latestRelease: AxiosResponse<any> = await this.git.client.get('releases/latest');
|
||||||
|
|
||||||
if (!commitHash) {
|
// Re-release if the version is the same as an existing release
|
||||||
throw 'The release plugin was not able to locate a commithash for release. Either build using the ci, or specify the commit hash with --commitHash <value>';
|
if (latestRelease.data.tag_name === `v${pluginInfo.version}`) {
|
||||||
|
await this.git.client.delete(`releases/${latestRelease.data.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const args = [
|
// Now make the release
|
||||||
'-t',
|
const newReleaseResponse = await this.git.client.post('releases', {
|
||||||
this.token,
|
tag_name: `v${pluginInfo.version}`,
|
||||||
'-u',
|
target_commitish: commitHash,
|
||||||
this.username,
|
name: `v${pluginInfo.version}`,
|
||||||
'-r',
|
body: this.releaseNotes,
|
||||||
this.repository, // should override --- may not be the same
|
draft: false,
|
||||||
'-c',
|
prerelease: false,
|
||||||
commitHash,
|
});
|
||||||
'-n',
|
|
||||||
`${this.repository}_v${pluginInfo.version}`,
|
this.publishAssets(
|
||||||
'-b',
|
|
||||||
this.releaseNotes,
|
|
||||||
`v${pluginInfo.version}`,
|
|
||||||
PUBLISH_DIR,
|
PUBLISH_DIR,
|
||||||
];
|
`https://uploads.github.com/repos/${this.username}/${this.repository}/releases/${newReleaseResponse.data.id}/assets`
|
||||||
|
);
|
||||||
if (recreate) {
|
} catch (reason) {
|
||||||
args.splice(12, 0, '-recreate');
|
console.error('error', reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { stdout } = await execa(ghrExe, args);
|
|
||||||
|
|
||||||
console.log(stdout);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user