mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-20 06:55:06 -04:00
chore(release): create a github release on new version
This commit is contained in:
parent
85cb0ffabd
commit
dbad7730f9
8 changed files with 356 additions and 819 deletions
6
scripts/getLatestChangelog.mjs
Normal file
6
scripts/getLatestChangelog.mjs
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { readFile } from 'fs/promises';
|
||||
|
||||
const changelogContent = await readFile('./CHANGELOG.md', 'utf-8');
|
||||
const [, lastChangelog] = changelogContent.split(/^## .*$/gm);
|
||||
|
||||
console.log(lastChangelog.trim());
|
57
scripts/release.mjs
Normal file
57
scripts/release.mjs
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { $, argv } from 'zx';
|
||||
import { consola } from 'consola';
|
||||
import { rawCommitsToMarkdown } from './shared/commits.mjs';
|
||||
import { addToChangelog } from './shared/changelog.mjs';
|
||||
|
||||
$.verbose = false;
|
||||
|
||||
const isDryRun = argv['dry-run'] ?? false;
|
||||
|
||||
const now = new Date();
|
||||
const currentShortSha = (await $`git rev-parse --short HEAD`).stdout.trim();
|
||||
|
||||
const calver = now.toISOString().slice(0, 10).replace(/-/g, '.');
|
||||
const version = `${calver}-${currentShortSha}`;
|
||||
|
||||
const { stdout: rawCommits } = await $`git log --pretty=oneline $(git describe --tags --abbrev=0)..HEAD`;
|
||||
|
||||
const markdown = rawCommitsToMarkdown({ rawCommits });
|
||||
|
||||
consola.info(`Changelog: \n\n${markdown}\n\n`);
|
||||
|
||||
if (isDryRun) {
|
||||
consola.info(`[dry-run] Not creating version nor tag`);
|
||||
consola.info('Aborting');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const shouldContinue = await consola.prompt(
|
||||
'This script will create a new version and tag, and update the changelog. Continue?',
|
||||
{
|
||||
type: 'confirm',
|
||||
},
|
||||
);
|
||||
|
||||
if (!shouldContinue) {
|
||||
consola.info('Aborting');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
consola.info('Updating changelog');
|
||||
await addToChangelog({ changelog: markdown, version });
|
||||
consola.success('Changelog updated');
|
||||
|
||||
try {
|
||||
consola.info('Committing changelog changes');
|
||||
await $`git add CHANGELOG.md`;
|
||||
await $`git commit -m "docs(changelog): update changelog for ${version}"`;
|
||||
consola.success('Changelog changes committed');
|
||||
|
||||
consola.info('Creating version and tag');
|
||||
await $`npm version ${version} -m "chore(version): release ${version}"`;
|
||||
consola.info('Npm version released with tag');
|
||||
} catch (error) {
|
||||
consola.error(error);
|
||||
consola.info('Aborting');
|
||||
process.exit(1);
|
||||
}
|
15
scripts/shared/changelog.mjs
Normal file
15
scripts/shared/changelog.mjs
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { readFile, writeFile } from 'fs/promises';
|
||||
|
||||
export { addToChangelog };
|
||||
|
||||
async function addToChangelog({ changelog, version, changelogPath = './CHANGELOG.md' }) {
|
||||
const changelogContent = await readFile(changelogPath, 'utf-8');
|
||||
const versionTitle = `## Version ${version}`;
|
||||
|
||||
if (changelogContent.includes(versionTitle)) {
|
||||
throw new Error(`Version ${version} already exists in the changelog`);
|
||||
}
|
||||
|
||||
const newChangeLogContent = changelogContent.replace('## ', `${versionTitle}\n\n${changelog}\n\n## `);
|
||||
await writeFile(changelogPath, newChangeLogContent, 'utf-8');
|
||||
}
|
54
scripts/shared/commits.mjs
Normal file
54
scripts/shared/commits.mjs
Normal file
|
@ -0,0 +1,54 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
export { rawCommitsToMarkdown };
|
||||
|
||||
const commitScopesToHumanReadable = {
|
||||
build: 'Build system',
|
||||
chore: 'Chores',
|
||||
ci: 'Continuous integration',
|
||||
docs: 'Documentation',
|
||||
feat: 'Features',
|
||||
fix: 'Bug fixes',
|
||||
infra: 'Infrastucture',
|
||||
perf: 'Performance',
|
||||
refactor: 'Refactoring',
|
||||
test: 'Tests',
|
||||
};
|
||||
|
||||
const commitTypesOrder = ['feat', 'fix', 'perf', 'refactor', 'test', 'build', 'ci', 'chore', 'other'];
|
||||
|
||||
const getCommitTypeSortIndex = (type) =>
|
||||
commitTypesOrder.includes(type) ? commitTypesOrder.indexOf(type) : commitTypesOrder.length;
|
||||
|
||||
function parseCommitLine(commit) {
|
||||
const [sha, ...splittedRawMessage] = commit.trim().split(' ');
|
||||
const rawMessage = splittedRawMessage.join(' ');
|
||||
const { type, scope, subject } = /^(?<type>.*?)(\((?<scope>.*)\))?: ?(?<subject>.+)$/.exec(rawMessage)?.groups ?? {};
|
||||
|
||||
return {
|
||||
sha: sha.slice(0, 7),
|
||||
type: type ?? 'other',
|
||||
scope,
|
||||
subject: subject ?? rawMessage,
|
||||
};
|
||||
}
|
||||
|
||||
function commitSectionsToMarkdown({ type, commits }) {
|
||||
return [
|
||||
`### ${commitScopesToHumanReadable[type] ?? _.capitalize(type)}`,
|
||||
...commits.map(({ sha, scope, subject }) => ['-', scope ? `**${scope}**:` : '', subject, `(${sha})`].join(' ')),
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function rawCommitsToMarkdown({ rawCommits }) {
|
||||
return _.chain(rawCommits)
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(parseCommitLine)
|
||||
.groupBy('type')
|
||||
.map((commits, type) => ({ type, commits }))
|
||||
.sortBy(({ type }) => getCommitTypeSortIndex(type))
|
||||
.map(commitSectionsToMarkdown)
|
||||
.join('\n\n')
|
||||
.value();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue