Skip to content

Instantly share code, notes, and snippets.

@pvdlg
Last active December 3, 2019 04:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pvdlg/6b19e529ee5c1a20645675a44e5b3239 to your computer and use it in GitHub Desktop.
Save pvdlg/6b19e529ee5c1a20645675a44e5b3239 to your computer and use it in GitHub Desktop.
semantic-release beta migration

semantic-release beta migration

This is a script to migrate your repository in order to support semantic-release version that includes semantic-release/semantic-release#1368 It will colllect the state information (which version has been released on which channel) based on tags and give you the commadn to run to safe this state with Git note.

This is only useful if were using a previous beta version of semantic-release.

This will not run any command on your repo other than git tag. It will display the command you have to run in your local Git repo to do the migration. Be careful and double check each command before running it!

Install

Make sure the NODE_PATH environment is set and point to your global node_modules. You can obtain this path with npm list -g | head -1.

For example:

$ npm list -g | head -1
=> /usr/local/lib

$ export NODE_PATH=/usr/local/lib/node_modules

Then install the script dependencies:

npm install -g lodash execa semver

Configuration

Copy the semantic-release-migration.js script from this Gist anywhere on your machine (for example ~/semantic-release-migration.js) and edit it. Change the values for:

  • REPO_PATH to the local path of the repository you want to migrate
  • TAG_FORMAT to your configuration of the tagFormat option

Running the migration

Execute the script with node semantic-release-migration.js

The script will list the commands to run in your repo:

  • Commands to run to create new tags and add notes
  • Commands to push the tags and notes to the remote repo
  • Commands to delete unnecessary tags
  • GitHub releases to modify
  • Commands to push the deleted tags
const execa = require('execa');
const {template, escapeRegExp} = require('lodash');
const semver = require('semver');
// TODO replace by the local path of your repo
const REPO_PATH = '/Users/pvdlg/git/@semantic-release/semantic-release';
// TODO: Replace with yours if you have a custom one
const TAG_FORMAT = `v\${version}`;
const tagRegexp = `^${escapeRegExp(template(TAG_FORMAT)({version: ' '})).replace(' ', '(.[^@]+)@?(.+)?')}`;
(async () => {
const allTags = await getTags(REPO_PATH);
const versions = allTags.reduce((versions, tag) => {
const [, version, channel = null] = tag.match(tagRegexp) || [];
if (version && semver.valid(semver.clean(version))) {
return {
...versions,
[version]: versions[version]
? {...versions[version], channels: [...versions[version].channels, channel]}
: {gitTag: tag, channels: [channel]},
};
}
return versions;
}, {});
const tagsToDelete = [];
console.log('--- Commands to run to create new tags and add notes ---');
for (const [version, {gitTag, channels}] of Object.entries(versions)) {
if (channels.includes(null) && channels.length > 1) {
console.log(`git notes --ref semantic-release add -m '${JSON.stringify({channels})}' ${gitTag}`);
}
if (!channels.includes(null) && channels.length > 0) {
const newTag = template(TAG_FORMAT)({version});
tagsToDelete.push({oldTag: gitTag, newTag});
console.log(`git tag ${newTag} ${gitTag}`);
console.log(`git notes --ref semantic-release add -m '${JSON.stringify({channels})}' ${newTag}`);
}
}
console.log('\n\n--- Commands to push the tags and notes ---');
console.log('git push --tags');
console.log('git push origin refs/notes/semantic-release');
console.log('\n\n--- Commands to delete unnecessary tags ---');
for (const {oldTag} of tagsToDelete) {
console.log(`git tag -d ${oldTag}`);
}
console.log('\n\n!!!!! IMPORTANT !!!!!');
console.log('If you use GitHub release update the following to change the tag referenced by the release');
for (const {oldTag, newTag} of tagsToDelete) {
console.log(`Update release ${oldTag} to refer to the tag ${newTag}`);
}
console.log('\n\n--- Commands to delete the remote tags ---');
for (const {oldTag} of tagsToDelete) {
console.log(`git push origin --delete ${oldTag}`);
}
})();
async function getTags(cwd) {
return (await execa('git', ['tag'], {cwd})).stdout
.split('\n')
.map(tag => tag.trim())
.filter(Boolean);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment