mirror of
https://github.com/laurent22/joplin.git
synced 2024-11-24 08:12:24 +02:00
256 lines
6.8 KiB
JavaScript
256 lines
6.8 KiB
JavaScript
"use strict"
|
|
|
|
// Supported commit formats:
|
|
|
|
// (Desktop|Mobile|Android|iOS[CLI): (New|Improved|Fixed): Some message..... (#ISSUE)
|
|
|
|
require('app-module-path').addPath(__dirname + '/../ReactNativeClient');
|
|
|
|
const rootDir = __dirname + '/..';
|
|
const { basename, dirname, filename, fileExtension } = require(rootDir + '/ReactNativeClient/lib/path-utils.js');
|
|
const fs = require('fs-extra');
|
|
const { execCommand } = require('./tool-utils.js');
|
|
const { sprintf } = require('sprintf-js');
|
|
|
|
async function gitTags() {
|
|
const r = await execCommand('git tag --format="%(objectname) %(refname:short)" --sort=-creatordate');
|
|
|
|
const output = [];
|
|
const lines = r.split('\n');
|
|
for (const line of lines) {
|
|
const s = line.split(' ');
|
|
if (s.length !== 2) throw new Error('Unexpected log line format: ' + line);
|
|
output.push({
|
|
hash: s[0].trim(),
|
|
name: s[1].trim(),
|
|
});
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
async function gitLog(sinceTag) {
|
|
let lines = await execCommand('git log --pretty=format:"%H:%s" ' + sinceTag + '..HEAD');
|
|
lines = lines.split('\n');
|
|
|
|
const output = [];
|
|
for (const line of lines) {
|
|
const splitted = line.split(':');
|
|
const commit = splitted[0];
|
|
const message = line.substr(commit.length + 1).trim();;
|
|
|
|
output.push({
|
|
commit: commit,
|
|
message: message,
|
|
});
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
async function gitLogSinceTag(logs, tagHash) {
|
|
const output = [];
|
|
let found = false;
|
|
|
|
for (const log of logs) {
|
|
if (log.commit === tagHash) {
|
|
found = true;
|
|
break;
|
|
}
|
|
output.push(log);
|
|
}
|
|
|
|
if (!found) throw new Error('Could not find tag hash: ' + tagHash);
|
|
|
|
return output;
|
|
}
|
|
|
|
function platformFromTag(tagName) {
|
|
if (tagName.indexOf('v') === 0) return 'desktop';
|
|
if (tagName.indexOf('android') >= 0) return 'android';
|
|
if (tagName.indexOf('ios') >= 0) return 'ios';
|
|
if (tagName.indexOf('clipper') === 0) return 'clipper';
|
|
if (tagName.indexOf('cli') === 0) return 'cli';
|
|
throw new Error('Could not determine platform from tag: ' + tagName);
|
|
}
|
|
|
|
function filterLogs(logs, platform) {
|
|
const output = [];
|
|
const revertedLogs = [];
|
|
|
|
for (const log of logs) {
|
|
|
|
// Save to an array any commit that has been reverted, and exclude
|
|
// these from the final output array.
|
|
const revertMatches = log.message.split('\n')[0].trim().match(/^Revert "(.*?)"$/);
|
|
if (revertMatches && revertMatches.length >= 2) {
|
|
revertedLogs.push(revertMatches[1]);
|
|
continue;
|
|
}
|
|
|
|
if (revertedLogs.indexOf(log.message) >= 0) continue;
|
|
|
|
let prefix = log.message.trim().toLowerCase().split(':');
|
|
if (prefix.length <= 1) continue;
|
|
prefix = prefix[0].split(',').map(s => s.trim());
|
|
|
|
let addIt = false;
|
|
|
|
if (prefix.indexOf('all') >= 0 && platform !== 'clipper') addIt = true;
|
|
if ((platform === 'android' || platform === 'ios') && prefix.indexOf('mobile') >= 0) addIt = true;
|
|
if (platform === 'android' && prefix.indexOf('android') >= 0) addIt = true;
|
|
if (platform === 'ios' && prefix.indexOf('ios') >= 0) addIt = true;
|
|
if (platform === 'desktop' && prefix.indexOf('desktop') >= 0) addIt = true;
|
|
if (platform === 'cli' && prefix.indexOf('cli') >= 0) addIt = true;
|
|
if (platform === 'clipper' && prefix.indexOf('clipper') >= 0) addIt = true;
|
|
|
|
if (addIt) output.push(log);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
function formatCommitMessage(msg) {
|
|
let output = '';
|
|
|
|
const splitted = msg.split(':');
|
|
|
|
const isPlatformPrefix = prefix => {
|
|
prefix = prefix.split(',').map(p => p.trim().toLowerCase());
|
|
for (const p of prefix) {
|
|
if (['android', 'mobile', 'ios', 'desktop', 'cli', 'clipper', 'all'].indexOf(p) >= 0) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (splitted.length) {
|
|
const platform = splitted[0].trim().toLowerCase();
|
|
if (isPlatformPrefix(platform)) {
|
|
splitted.splice(0, 1);
|
|
}
|
|
|
|
output = splitted.join(':');
|
|
}
|
|
|
|
output = output.split('\n')[0].trim();
|
|
|
|
const detectType = msg => {
|
|
msg = msg.trim().toLowerCase();
|
|
|
|
if (msg.indexOf('fix') === 0) return 'fixed';
|
|
if (msg.indexOf('add') === 0) return 'new';
|
|
if (msg.indexOf('change') === 0) return 'improved';
|
|
if (msg.indexOf('update') === 0) return 'improved';
|
|
if (msg.indexOf('improve') === 0) return 'improved';
|
|
|
|
return 'improved';
|
|
}
|
|
|
|
const parseCommitMessage = (msg) => {
|
|
const parts = msg.split(':');
|
|
const defaultType = 'improved';
|
|
|
|
if (parts.length === 1) {
|
|
return {
|
|
type: detectType(msg),
|
|
message: msg.trim(),
|
|
};
|
|
}
|
|
|
|
let t = parts[0].trim().toLowerCase();
|
|
|
|
parts.splice(0, 1);
|
|
let message = parts.join(':').trim();
|
|
|
|
let type = null;
|
|
|
|
// eg. "All: Resolves #712: New: Support for note history (#1415)"
|
|
// "Resolves" doesn't tell us if it's new or improved so check the
|
|
// third token (which in this case is "new").
|
|
if (t.indexOf('resolves') === 0 && ['new', 'improved', 'fixed'].indexOf(parts[0].trim().toLowerCase()) >= 0) {
|
|
t = parts[0].trim().toLowerCase();
|
|
parts.splice(0, 1);
|
|
message = parts.join(':').trim();
|
|
}
|
|
|
|
if (t.indexOf('fix') === 0) type = 'fixed';
|
|
if (t.indexOf('new') === 0) type = 'new';
|
|
if (t.indexOf('improved') === 0) type = 'improved';
|
|
|
|
if (!type) type = detectType(message);
|
|
|
|
let issueNumber = output.match(/#(\d+)/);
|
|
issueNumber = issueNumber && issueNumber.length >= 2 ? issueNumber[1] : null;
|
|
|
|
return {
|
|
type: type,
|
|
message: message,
|
|
issueNumber: issueNumber,
|
|
};
|
|
}
|
|
|
|
const commitMessage = parseCommitMessage(output);
|
|
|
|
output = capitalizeFirstLetter(commitMessage.type) + ': ' + capitalizeFirstLetter(commitMessage.message);
|
|
if (commitMessage.issueNumber) {
|
|
const formattedIssueNum = '(#' + commitMessage.issueNumber + ')'
|
|
if (output.indexOf(formattedIssueNum) < 0) output += ' ' + formattedIssueNum;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
function createChangeLog(logs) {
|
|
const output = [];
|
|
|
|
for (const log of logs) {
|
|
output.push(formatCommitMessage(log.message));
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
function capitalizeFirstLetter(string) {
|
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
}
|
|
|
|
async function main() {
|
|
const argv = require('yargs').argv;
|
|
if (!argv._.length) throw new Error('Tag name must be specified');
|
|
|
|
const sinceTagName = argv._[0];
|
|
const platform = platformFromTag(sinceTagName);
|
|
|
|
const logsSinceTags = await gitLog(sinceTagName);
|
|
const filteredLogs = filterLogs(logsSinceTags, platform);
|
|
|
|
let changelog = createChangeLog(filteredLogs);
|
|
|
|
const changelogFixes = [];
|
|
const changelogImproves = [];
|
|
const changelogNews = [];
|
|
|
|
for (const l of changelog) {
|
|
if (l.indexOf('Fix') === 0) {
|
|
changelogFixes.push(l);
|
|
} else if (l.indexOf('Improve') === 0) {
|
|
changelogImproves.push(l);
|
|
} else if (l.indexOf('New') === 0) {
|
|
changelogNews.push(l);
|
|
} else {
|
|
throw new Error('Invalid changelog line: ' + l);
|
|
}
|
|
}
|
|
|
|
changelog = [].concat(changelogNews).concat(changelogImproves).concat(changelogFixes);
|
|
|
|
const changelogString = changelog.map(l => '- ' + l);
|
|
console.info(changelogString.join('\n'));
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error('Fatal error');
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|