The following is pseudo-code for a proposed grunt release task.
The task assumes that you're using git
and the default remote is where the release should be pushed to.
There are safety checks to ensure a clean release, and the custom checks can be added by the project using the release task.
None of the following is a suggestion on naming, this is purely an overview of the way I think the release task should work.
The word "task" is heavily abused in the comments. These may not be tasks as defined in Grunt.
task( "release", function() {
// Process the `version` option
// Can be: major, minor, patch, build, or an explicit version number
var version = option( "newversion" );
// Determine the release type
// This may be useful for custom tasks
// For example, you want to perform different tasks for major and minor releases
var releaseType = isSemver( version ) ? "explicit" : version;
// Determine current version number
// Useful for tasks like generating a changelog
var prevVersion = getCurrentVersion();
// Determine the new version number
var newVersion = releaseType === "explicit" ? version : bumpVersion( prevVersion );
// Create an object of release-related properties to pass to all tasks
var settings = {
previous: prevVersion,
version: version,
releaseType: releaseType
};
// Verify the repo is in a clean state
// A release should only occur from a clean checkout
if ( dirtyCheckout() ) {
die();
}
// Run a task that verifies the status of the repo
// This is async and defaults to a success state
// If this fails, the whole process stops
optionalHelper( "checkStatus", settings, cb );
// Update package.json version
// This should be smart and inspect package.json for indentation style
updatePackageJson( version );
// Run a task that performs any custom actions prior to the release
// This is async and defaults to doing nothing
// If this fails, the whole process stops
// NOTE: package.json has the new version at this point, which is
// useful if any other tasks will be reading from that instead of `settings`
optionalHelper( "preprocessRelease", settings, cb );
// Commit all changed files, use the version number as the message
// Don't be stingy, `preprocessRelease` may have modified files as well.
// Add all new/modified files.
commitFilesToGit({ message: version });
// Tag the release, use the version number, with the "v" prefix
// This should be an annotated tag, not a lightweight tag
// `npm version` will check npm config to determine if the tag should be signed,
// this could do something similar, but at a minimum it should be annotated
tag( "v" + version );
// Push to the default remote
push();
pushTags();
// Publish to npm, but only if requested
if ( option( "npm" ) ) {
publishToNpm();
}
// Display version info
// Example: Version <version> was tagged at <date>
showDetails();
Examples of checkStatus
:
- Linting
- Running tests
- Verifying status of AUTHORS.txt
Examples of preprocessRelease
:
- Generating changelog
- Updating README
There should be a grunt-contrib plugin built on top of this which defines the common tasks for grunt-contrib-* plugins. For example, all contrib plugins should generate changelogs in the same format. Ideally contrib plugins would be able to load this higher-level plugin and get a release task with no configuration.