Skip to content

Commit

Permalink
Migrate to GitHub Actions
Browse files Browse the repository at this point in the history
Better release workflow which doesn't rely anymore on a release branch
but instead must be manually triggered from the GH Actions panel for a
specific branch. A tag is automatically created for the version in the
"package.json" file and will be pushed with dist files. Assets (*.zip,
*.tgz, dist/*.js) are attached to the release notes, which must exist
in a "draft" state for the release workflow to success.

Publishing to npm now happens when a GH release is published, which is
not anymore automatic when the Git tag is created. This allows a final
review of the release notes, tag and assets. When publishing to npm, a
tag is calculated based on existing npm tags and can be either "next",
"dev", "latest" or "untagged". See "scripts/utils.js" for details.

Finally, rewrite all scripts to JavaScript (no more bash scripts).
  • Loading branch information
simonbrunel committed Mar 7, 2021
1 parent 9586e39 commit a8b51cb
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 78 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# https://docs.github.com/actions/reference/workflow-syntax-for-github-actions

name: CI

on: [push, pull_request]

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: npm run build
- run: npm run lint
- name: Run tests
uses: GabrielBB/xvfb-action@v1
with:
run: npm run test
- uses: paambaati/[email protected]
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
- uses: actions/upload-artifact@v2
with:
path: dist/
name: chartjs-plugin-datalabels
if-no-files-found: error
19 changes: 19 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# https://docs.github.com/actions/reference/workflow-syntax-for-github-actions

name: Publish

on:
release:
types: [published]

jobs:
publish-to-npm:
if: github.repository_owner == 'chartjs'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: node scripts/publish-to-npm.js
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# https://docs.github.com/actions/reference/workflow-syntax-for-github-actions

name: Release

on: workflow_dispatch

jobs:
create-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: npm run build
- run: npm run bower
- run: npm run package
- run: node scripts/attach-gh-assets.js
env:
# https://github.com/cli/cli/discussions/3029
GITHUB_TOKEN: ${{ secrets.GH_AUTH_TOKEN }}
DEBUG: api
- run: node scripts/create-release-tag.js
env:
GH_AUTH_EMAIL: ${{ secrets.GH_AUTH_EMAIL }}
GH_AUTH_NAME: ${{ secrets.GH_AUTH_NAME }}
49 changes: 0 additions & 49 deletions .travis.yml

This file was deleted.

34 changes: 34 additions & 0 deletions scripts/attach-gh-assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// https://hub.github.com/hub-release.1.html
// https://cli.github.com/manual/
/* eslint-disable no-process-exit */

const {run} = require('./utils');
const pkg = require('../package.json');

const TAG = `v${pkg.version}`;

const ASSETS = [
`dist/${pkg.name}.js`,
`dist/${pkg.name}.min.js`,
`dist/${pkg.name}.tgz`,
`dist/${pkg.name}.zip`,
];

(async() => {
if (!process.env.GITHUB_TOKEN) {
throw new Error('GITHUB_TOKEN environment variable required');
}
if ((await run(`hub release show ${TAG} -f "%T: %S"`)) !== `${TAG}: draft`) {
throw new Error(`Release ${TAG} has already been published.`);
}

// Attach assets to the associated GitHub release.
// Note that the `hub release edit -a ${ASSETS.join(' -a ')} -m "" "${TAG}"`
// command does not allow to overwrite existing assets, so use 'gh' instead.
// See https://github.com/github/hub/issues/2657
await run(`gh release upload ${TAG} ${ASSETS.join(' ')} --clobber`);

})().catch((error) => {
console.error(`Failed to publish to github: ${error.message || error}.`);
process.exit(1);
});
36 changes: 36 additions & 0 deletions scripts/create-release-tag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* eslint-disable no-process-exit */

const {run} = require('./utils');
const pkg = require('../package.json');

const TAG = `v${pkg.version}`;
const TAG_FILES = [
`dist/${pkg.name}.js`,
`dist/${pkg.name}.min.js`,
'bower.json',
];

(async() => {
if (!process.env.GH_AUTH_EMAIL) {
throw new Error('GH_AUTH_EMAIL environment variable required');
}
if (!process.env.GH_AUTH_NAME) {
throw new Error('GH_AUTH_NAME environment variable required');
}
if (await run(`git ls-remote origin refs/tags/${TAG}`)) {
throw new Error(`Git tag ${TAG} already exists`);
}

// Tag a detached branch containing the dist (and bower) files.
await run(`git config --global user.email "${process.env.GH_AUTH_EMAIL}"`);
await run(`git config --global user.name "${process.env.GH_AUTH_NAME}"`);
await run('git checkout --detach --quiet');
await run(`git add -f ${TAG_FILES.join(' ')}`);
await run(`git commit -m "Release ${TAG}"`);
await run(`git tag -a "${TAG}" -m "Version ${pkg.version}"`);
await run(`git push origin refs/tags/${TAG}`);

})().catch((error) => {
console.error(`Failed to create release tag: ${error.message || error}.`);
process.exit(1);
});
23 changes: 23 additions & 0 deletions scripts/publish-to-npm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* eslint-disable no-process-exit */
/* eslint-disable no-console */

const {run, semtag} = require('./utils');
const {version} = require('../package.json');

(async() => {
const tags = (await run('npm dist-tag ls')).split('\n').reduce((acc, line) => {
const matches = (/^([^:]+): (.+)$/).exec(line);
acc[matches[1]] = matches[2];
return acc;
}, {});

const tag = semtag(tags, version);

console.info(`Publishing version ${version} (@${tag})`);

await run(`npm publish --tag ${tag}`);

})().catch((error) => {
console.error(`Failed to publish to npm: ${error.message || error}.`);
process.exit(1);
});
29 changes: 0 additions & 29 deletions scripts/release.sh

This file was deleted.

41 changes: 41 additions & 0 deletions scripts/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const {exec} = require('child_process');
const semver = require('semver');

module.exports = {
run: (cmd) => new Promise((resolve, reject) => {
exec(cmd, {}, (error, stdout, stderr) => {
if (error) {
reject(stderr.trim());
} else {
resolve(stdout.trim());
}
});
}),

/**
* Returns, based on existing npm `tags`, the tag under which to publish the given `version`.
*/
semtag: (tags, version) => {
const {latest} = tags;

// Versions prior to 'latest' are marked 'untagged'.
if (latest && semver.gte(latest, version)) {
return 'untagged';
}

// Full versions greater than 'latest' become the new 'latest'.
if (!semver.prerelease(version)) {
return 'latest';
}

// Pre-versions for the same 'latest' major version are tagged 'dev', else are
// tagged 'next' for a greater major version. However, if the tag already exists
// with a greater version, the version to publish is marked 'untagged'.
const tag = latest && semver.major(latest) < semver.major(version) ? 'next' : 'dev';
if (tags[tag] && semver.lte(version, tags[tag])) {
return 'untagged';
}

return tag;
}
};

0 comments on commit a8b51cb

Please sign in to comment.