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:
Stephanie Closson 2020-04-02 13:57:33 -06:00 committed by GitHub
parent 06ba5201bb
commit c5252f1b64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 298 additions and 139 deletions

View File

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

View File

@ -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();

View File

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

View File

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

View 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

View File

@ -0,0 +1,7 @@
#!/bin/bash
##
## Common variable declarations
##
DOCKER_IMAGE_NAME="srclosson/grafana-plugin-ci"

View 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"

View 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"
}

View File

@ -0,0 +1,3 @@
#!/bin/bash
source "./deploy-common.sh"

View 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

View File

@ -0,0 +1,8 @@
version: '3'
services:
citest:
image: "circleci/node:12-browsers"
user: root
volumes:
- ../scripts:/home/circleci/scripts
- ../install:/home/circleci/install

View File

@ -0,0 +1,4 @@
#!/bin/bash
# Enter the docker container
docker-compose run citest bash -c "cd /home/circleci; exec bash --login -i"

View File

@ -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,
}); });
}); });

View File

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

View File

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

View File

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