Skip to content

Commit 87e5a82

Browse files
committed
Migrate to GitHub Actions
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).
1 parent beea2db commit 87e5a82

File tree

9 files changed

+204
-68
lines changed

9 files changed

+204
-68
lines changed

.github/workflows/ci.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# https://docs.github.com/actions/reference/workflow-syntax-for-github-actions
2+
3+
name: CI
4+
5+
on: [push, pull_request]
6+
7+
jobs:
8+
build-and-test:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v2
12+
- uses: actions/setup-node@v2
13+
- run: npm ci
14+
- run: npm run build
15+
- run: npm run lint
16+
- run: npm run test
17+
- uses: actions/upload-artifact@v2
18+
with:
19+
path: dist/
20+
name: chartjs-plugin-deferred
21+
if-no-files-found: error

.github/workflows/publish.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# https://docs.github.com/actions/reference/workflow-syntax-for-github-actions
2+
3+
name: Publish
4+
5+
on:
6+
release:
7+
types: [published]
8+
9+
jobs:
10+
publish-to-npm:
11+
if: github.repository_owner == 'chartjs'
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v2
15+
- uses: actions/setup-node@v1
16+
with:
17+
node-version: 12
18+
registry-url: https://registry.npmjs.org/
19+
- run: npm ci
20+
- run: node scripts/publish-to-npm.js
21+
env:
22+
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

.github/workflows/release.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# https://docs.github.com/actions/reference/workflow-syntax-for-github-actions
2+
3+
name: Release
4+
5+
on: workflow_dispatch
6+
7+
jobs:
8+
create-release:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v2
12+
- uses: actions/setup-node@v2
13+
- run: npm ci
14+
- run: npm run build
15+
- run: npm run bower
16+
- run: npm run package
17+
- run: node scripts/attach-gh-assets.js
18+
env:
19+
# https://github.com/cli/cli/discussions/3029
20+
GITHUB_TOKEN: ${{ secrets.GH_AUTH_TOKEN }}
21+
DEBUG: api
22+
- run: node scripts/create-release-tag.js
23+
env:
24+
GH_AUTH_EMAIL: ${{ secrets.GH_AUTH_EMAIL }}
25+
GH_AUTH_NAME: ${{ secrets.GH_AUTH_NAME }}

.travis.yml

Lines changed: 0 additions & 39 deletions
This file was deleted.

scripts/attach-gh-assets.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// https://hub.github.com/hub-release.1.html
2+
// https://cli.github.com/manual/
3+
/* eslint-disable no-process-exit */
4+
5+
const {run} = require('./utils');
6+
const pkg = require('../package.json');
7+
8+
const TAG = `v${pkg.version}`;
9+
10+
const ASSETS = [
11+
`dist/${pkg.name}.js`,
12+
`dist/${pkg.name}.min.js`,
13+
`dist/${pkg.name}.esm.js`,
14+
`dist/${pkg.name}.tgz`,
15+
`dist/${pkg.name}.zip`,
16+
];
17+
18+
(async() => {
19+
if (!process.env.GITHUB_TOKEN) {
20+
throw new Error('GITHUB_TOKEN environment variable required');
21+
}
22+
if ((await run(`hub release show ${TAG} -f "%T: %S"`)) !== `${TAG}: draft`) {
23+
throw new Error(`Release ${TAG} has already been published.`);
24+
}
25+
26+
// Attach assets to the associated GitHub release.
27+
// Note that the `hub release edit -a ${ASSETS.join(' -a ')} -m "" "${TAG}"`
28+
// command does not allow to overwrite existing assets, so use 'gh' instead.
29+
// See https://github.com/github/hub/issues/2657
30+
await run(`gh release upload ${TAG} ${ASSETS.join(' ')} --clobber`);
31+
32+
})().catch((error) => {
33+
console.error(`Failed to publish to github: ${error.message || error}.`);
34+
process.exit(1);
35+
});

scripts/create-release-tag.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* eslint-disable no-process-exit */
2+
3+
const {run} = require('./utils');
4+
const pkg = require('../package.json');
5+
6+
const TAG = `v${pkg.version}`;
7+
const TAG_FILES = [
8+
`dist/${pkg.name}.js`,
9+
`dist/${pkg.name}.min.js`,
10+
`dist/${pkg.name}.esm.js`,
11+
'bower.json',
12+
];
13+
14+
(async() => {
15+
if (!process.env.GH_AUTH_EMAIL) {
16+
throw new Error('GH_AUTH_EMAIL environment variable required');
17+
}
18+
if (!process.env.GH_AUTH_NAME) {
19+
throw new Error('GH_AUTH_NAME environment variable required');
20+
}
21+
if (await run(`git ls-remote origin refs/tags/${TAG}`)) {
22+
throw new Error(`Git tag ${TAG} already exists`);
23+
}
24+
25+
// Tag a detached branch containing the dist (and bower) files.
26+
await run(`git config --global user.email "${process.env.GH_AUTH_EMAIL}"`);
27+
await run(`git config --global user.name "${process.env.GH_AUTH_NAME}"`);
28+
await run('git checkout --detach --quiet');
29+
await run(`git add -f ${TAG_FILES.join(' ')}`);
30+
await run(`git commit -m "Release ${TAG}"`);
31+
await run(`git tag -a "${TAG}" -m "Version ${pkg.version}"`);
32+
await run(`git push origin refs/tags/${TAG}`);
33+
34+
})().catch((error) => {
35+
console.error(`Failed to create release tag: ${error.message || error}.`);
36+
process.exit(1);
37+
});

scripts/publish-to-npm.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* eslint-disable no-process-exit */
2+
/* eslint-disable no-console */
3+
4+
const {run, semtag} = require('./utils');
5+
const {version} = require('../package.json');
6+
7+
(async() => {
8+
const tags = (await run('npm dist-tag ls')).split('\n').reduce((acc, line) => {
9+
const matches = (/^([^:]+): (.+)$/).exec(line);
10+
acc[matches[1]] = matches[2];
11+
return acc;
12+
}, {});
13+
14+
const tag = semtag(tags, version);
15+
16+
console.info(`Publishing version ${version} (@${tag})`);
17+
18+
await run(`npm publish --tag ${tag}`);
19+
20+
})().catch((error) => {
21+
console.error(`Failed to publish to npm: ${error.message || error}.`);
22+
process.exit(1);
23+
});

scripts/release.sh

Lines changed: 0 additions & 29 deletions
This file was deleted.

scripts/utils.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const {exec} = require('child_process');
2+
const semver = require('semver');
3+
4+
module.exports = {
5+
run: (cmd) => new Promise((resolve, reject) => {
6+
exec(cmd, {}, (error, stdout, stderr) => {
7+
if (error) {
8+
reject(stderr.trim());
9+
} else {
10+
resolve(stdout.trim());
11+
}
12+
});
13+
}),
14+
15+
/**
16+
* Returns, based on existing npm `tags`, the tag under which to publish the given `version`.
17+
*/
18+
semtag: (tags, version) => {
19+
const {latest} = tags;
20+
21+
// Versions prior to 'latest' are marked 'untagged'.
22+
if (latest && semver.gte(latest, version)) {
23+
return 'untagged';
24+
}
25+
26+
// Full versions greater than 'latest' become the new 'latest'.
27+
if (!semver.prerelease(version)) {
28+
return 'latest';
29+
}
30+
31+
// Pre-versions for the same 'latest' major version are tagged 'dev', else are
32+
// tagged 'next' for a greater major version. However, if the tag already exists
33+
// with a greater version, the version to publish is marked 'untagged'.
34+
const tag = latest && semver.major(latest) < semver.major(version) ? 'next' : 'dev';
35+
if (tags[tag] && semver.lte(version, tags[tag])) {
36+
return 'untagged';
37+
}
38+
39+
return tag;
40+
}
41+
};

0 commit comments

Comments
 (0)