-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Docs: Update and refactor release workflow recipe (#2498)
- Loading branch information
Showing
1 changed file
with
94 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,100 @@ | ||
# Automate release workflow | ||
<!-- front-matter | ||
id: automate-releases | ||
title: Automate Releases | ||
hide_title: true | ||
sidebar_label: Automate Releases | ||
--> | ||
|
||
# Automate Releases | ||
|
||
If your project follows a semantic versioning, it may be a good idea to automatize the steps needed to do a release. | ||
Below you have a simple recipe that bumps the project version, commits the changes to git and creates a new tag. | ||
|
||
``` javascript | ||
|
||
var gulp = require('gulp'); | ||
var conventionalChangelog = require('gulp-conventional-changelog'); | ||
var conventionalGithubReleaser = require('conventional-github-releaser'); | ||
var bump = require('gulp-bump'); | ||
var log = require('gulplog'); | ||
var git = require('gulp-git'); | ||
var fs = require('fs'); | ||
|
||
gulp.task('changelog', function () { | ||
return gulp.src('CHANGELOG.md', { | ||
buffer: false | ||
}) | ||
.pipe(conventionalChangelog({ | ||
preset: 'angular' // Or to any other commit message convention you use. | ||
})) | ||
.pipe(gulp.dest('./')); | ||
}); | ||
|
||
gulp.task('github-release', function(done) { | ||
conventionalGithubReleaser({ | ||
type: "oauth", | ||
token: 'abcdefghijklmnopqrstuvwxyz1234567890' // change this to your own GitHub token or use an environment variable | ||
}, { | ||
preset: 'angular' // Or to any other commit message convention you use. | ||
}, done); | ||
}); | ||
|
||
gulp.task('bump-version', function () { | ||
// We hardcode the version change type to 'patch' but it may be a good idea to | ||
// use minimist (https://www.npmjs.com/package/minimist) to determine with a | ||
// command argument whether you are doing a 'major', 'minor' or a 'patch' change. | ||
return gulp.src(['./bower.json', './package.json']) | ||
.pipe(bump({type: "patch"}).on('error', log.error)) | ||
.pipe(gulp.dest('./')); | ||
}); | ||
|
||
gulp.task('commit-changes', function () { | ||
return gulp.src('.') | ||
.pipe(git.add()) | ||
.pipe(git.commit('[Prerelease] Bumped version number')); | ||
}); | ||
|
||
gulp.task('push-changes', function (done) { | ||
git.push('origin', 'master', done); | ||
}); | ||
|
||
gulp.task('create-new-tag', function (done) { | ||
var version = getPackageJsonVersion(); | ||
git.tag(version, 'Created Tag for version: ' + version, function (error) { | ||
if (error) { | ||
return done(error); | ||
} | ||
git.push('origin', 'master', {args: '--tags'}, done); | ||
The recipe below bumps the project version, commits the changes to git and creates a new GitHub release. | ||
|
||
For publishing a GitHub release you'll need to [create a personal access token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token) and add it to your project. However, we don't want to commit it, so we'll use [`dotenv`](https://www.npmjs.com/package/dotenv) to load it from a git-ignored `.env` file: | ||
|
||
``` | ||
GH_TOKEN=ff34885... | ||
``` | ||
|
||
Don't forget to add `.env` to your `.gitignore`. | ||
|
||
Next, install all the necessary dependencies for this recipe: | ||
|
||
```sh | ||
npm install --save-dev conventional-recommended-bump conventional-changelog-cli conventional-github-releaser dotenv execa | ||
``` | ||
|
||
Based on your environment, setup and preferences, your release workflow might look something like this: | ||
|
||
``` js | ||
const gulp = require('gulp'); | ||
const conventionalRecommendedBump = require('conventional-recommended-bump'); | ||
const conventionalGithubReleaser = require('conventional-github-releaser'); | ||
const execa = require('execa'); | ||
const fs = require('fs'); | ||
const { promisify } = require('util'); | ||
const dotenv = require('dotenv'); | ||
|
||
// load environment variables | ||
const result = dotenv.config(); | ||
|
||
if (result.error) { | ||
throw result.error; | ||
} | ||
|
||
// Conventional Changelog preset | ||
const preset = 'angular'; | ||
// print output of commands into the terminal | ||
const stdio = 'inherit'; | ||
|
||
async function bumpVersion() { | ||
// get recommended version bump based on commits | ||
const { releaseType } = await promisify(conventionalRecommendedBump)({ preset }); | ||
// bump version without committing and tagging | ||
await execa('npm', ['version', releaseType, '--no-git-tag-version'], { | ||
stdio, | ||
}); | ||
} | ||
|
||
async function changelog() { | ||
await execa( | ||
'npx', | ||
[ | ||
'conventional-changelog', | ||
'--preset', | ||
preset, | ||
'--infile', | ||
'CHANGELOG.md', | ||
'--same-file', | ||
], | ||
{ stdio } | ||
); | ||
} | ||
|
||
async function commitTagPush() { | ||
// even though we could get away with "require" in this case, we're taking the safe route | ||
// because "require" caches the value, so if we happen to use "require" again somewhere else | ||
// we wouldn't get the current value, but the value of the last time we called "require" | ||
const { version } = JSON.parse(await promisify(fs.readFile)('package.json')); | ||
const commitMsg = `chore: release ${version}`; | ||
await execa('git', ['add', '.'], { stdio }); | ||
await execa('git', ['commit', '--message', commitMsg], { stdio }); | ||
await execa('git', ['tag', `v${version}`], { stdio }); | ||
await execa('git', ['push', '--follow-tags'], { stdio }); | ||
} | ||
|
||
function getPackageJsonVersion () { | ||
// We parse the json file instead of using require because require caches | ||
// multiple calls so the version number won't be updated | ||
return JSON.parse(fs.readFileSync('./package.json', 'utf8')).version; | ||
}; | ||
}); | ||
|
||
gulp.task('release', gulp.series( | ||
'bump-version', | ||
'changelog', | ||
'commit-changes', | ||
'push-changes', | ||
'create-new-tag', | ||
'github-release' | ||
)); | ||
function githubRelease(done) { | ||
conventionalGithubReleaser( | ||
{ type: 'oauth', token: process.env.GH_TOKEN }, | ||
{ preset }, | ||
done | ||
); | ||
} | ||
|
||
exports.release = gulp.series( | ||
bumpVersion, | ||
changelog, | ||
commitTagPush, | ||
githubRelease | ||
); | ||
``` |