changelog-guru
Version:
Git changelog generator
153 lines (152 loc) • 8.85 kB
JavaScript
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Builder_config, _Builder_package, _Builder_state;
import { promises as fs } from 'fs';
import { Package } from 'package-json-helper';
import { Dependencies, Restriction } from 'package-json-helper/types/package';
import path from 'path';
import TaskTree from 'tasktree-cli';
import md from '../utils/markdown.js';
import { findSame } from '../utils/text.js';
import { GitServiceProvider } from './Config.js';
import Commit from './entities/Commit.js';
import Message from './entities/Message.js';
import Section from './entities/Section.js';
import GitHubProvider from './providers/GitHubProvider.js';
import GitLabProvider from './providers/GitLabProvider.js';
import State from './State.js';
class Builder {
constructor(config) {
_Builder_config.set(this, void 0);
_Builder_package.set(this, void 0);
_Builder_state.set(this, void 0);
__classPrivateFieldSet(this, _Builder_config, config, "f");
__classPrivateFieldSet(this, _Builder_package, new Package(), "f");
}
async build() {
await __classPrivateFieldGet(this, _Builder_config, "f").init();
await __classPrivateFieldGet(this, _Builder_package, "f").read();
if (__classPrivateFieldGet(this, _Builder_package, "f").repository?.url) {
const provider = new {
[GitServiceProvider.GitHub]: GitHubProvider,
[GitServiceProvider.GitLab]: GitLabProvider,
}[__classPrivateFieldGet(this, _Builder_config, "f").provider](__classPrivateFieldGet(this, _Builder_package, "f").repository.url, __classPrivateFieldGet(this, _Builder_config, "f").branch);
await this.read(provider);
await this.write(provider);
}
else {
TaskTree.fail('Package repository url is not defined!');
}
}
async bumpPackage(provider) {
if (__classPrivateFieldGet(this, _Builder_config, "f").bump && __classPrivateFieldGet(this, _Builder_package, "f").version && __classPrivateFieldGet(this, _Builder_state, "f")) {
const task = TaskTree.add('Updating package version');
const date = await provider.getLastChangeDate(true);
const { version: prevVersion } = await provider.getCurrentPackage(date);
const { version } = __classPrivateFieldGet(this, _Builder_package, "f");
if (prevVersion && prevVersion !== version) {
task.skip(`Package version is already changed from {bold ${prevVersion}(${provider.branch.dev})} to {bold ${version}}`);
}
else {
const [major, minor, patch] = __classPrivateFieldGet(this, _Builder_state, "f").changesLevels;
if (major || minor || patch) {
__classPrivateFieldGet(this, _Builder_package, "f").bump({ major, minor, patch });
await __classPrivateFieldGet(this, _Builder_package, "f").save();
task.complete(`Package version updated to {bold ${__classPrivateFieldGet(this, _Builder_package, "f").version}}`);
}
else {
task.skip('Package version does not change');
}
}
task.clear();
}
}
async read(provider) {
const stage = TaskTree.add('Loading repository changes...');
try {
const date = await provider.getLastChangeDate();
const commits = await provider.getCommits(date);
const previousPackage = await provider.getPreviousPackage(date);
if (__classPrivateFieldGet(this, _Builder_package, "f").license) {
const state = new State(__classPrivateFieldGet(this, _Builder_package, "f").license, previousPackage.license);
[...Object.values(Dependencies), ...Object.values(Restriction)].forEach(name => {
state.addChanges(name, __classPrivateFieldGet(this, _Builder_package, "f").getChanges(name, previousPackage));
});
commits.forEach(commit => state.addCommit(commit));
__classPrivateFieldSet(this, _Builder_state, state, "f");
stage.clear();
stage.log(`Branch {bold ${__classPrivateFieldGet(this, _Builder_config, "f").branch}} last changes at: {bold ${date.toLocaleString()}}`);
stage.log(`{bold ${commits.length}} commits loaded`);
stage.complete('Release information:');
}
else {
stage.fail('Package license is not defined');
}
}
catch (error) {
stage.error(error, true);
}
}
renderCommits(commits) {
const groups = new Map();
commits.forEach(commit => {
const subject = findSame(commit.subject, [...groups.keys()]) ?? commit.subject;
const { accents, links } = groups.get(subject) ?? { subject, accents: new Set(), links: [] };
commit.accents.forEach(accent => accents.add(accent));
links.push(md.commit(commit.shortName, commit.url));
groups.set(commit.subject, { subject, accents, links });
});
return [
...[...groups.values()].map(({ subject, accents, links }) => md.list([
accents.size ? md.strong(`[${[...accents.values()].map(md.capitalize).join(', ')}]`) : '',
md.capitalize(subject),
...links,
]
.filter(Boolean)
.join(' '))),
'',
];
}
renderSection(section, level = 1) {
const sections = section.sections.filter(Section.filter);
const commits = section.commits.filter(Commit.filter);
const messages = section.messages.filter(Message.filter);
const output = section.isDetails ? [md.summary(section.title)] : [md.title(section.title, level)];
if (messages.length)
output.push(...messages.map(message => message.text), '');
if (sections.length)
output.push(...sections.map(subsection => this.renderSection(subsection, level + 1)));
if (sections.length && commits.length)
output.push(md.title('Others', level + 1));
if (commits.length)
output.push(...this.renderCommits(commits));
return section.isDetails ? md.details(output.join('\n')) : output.join('\n');
}
async write(provider) {
if (__classPrivateFieldGet(this, _Builder_state, "f")) {
const task = TaskTree.add('Generate changelog...');
__classPrivateFieldGet(this, _Builder_state, "f").updateCommitsChangeLevel(__classPrivateFieldGet(this, _Builder_config, "f").types);
__classPrivateFieldGet(this, _Builder_state, "f").ignore(__classPrivateFieldGet(this, _Builder_config, "f").exclusions);
await __classPrivateFieldGet(this, _Builder_state, "f").modify(__classPrivateFieldGet(this, _Builder_config, "f").rules);
const data = __classPrivateFieldGet(this, _Builder_state, "f").sections.map(subsection => this.renderSection(subsection));
const filePath = path.resolve(process.cwd(), __classPrivateFieldGet(this, _Builder_config, "f").filePath);
if (__classPrivateFieldGet(this, _Builder_state, "f").authors) {
data.push(md.contributors(__classPrivateFieldGet(this, _Builder_state, "f").authors.map(({ name, avatar, url }) => md.image(name, avatar, url))), '');
}
await fs.writeFile(filePath, data.join('\n'));
await this.bumpPackage(provider);
task.complete('Changelog generated!');
}
}
}
_Builder_config = new WeakMap(), _Builder_package = new WeakMap(), _Builder_state = new WeakMap();
export default Builder;