2019-07-30 09:35:42 +02:00
|
|
|
/* eslint-disable require-atomic-updates */
|
|
|
|
|
2018-03-28 19:41:14 +02:00
|
|
|
const fetch = require('node-fetch');
|
2021-12-19 19:24:00 +02:00
|
|
|
const { writeFile, readFile, pathExists } = require('fs-extra');
|
2020-11-07 17:59:37 +02:00
|
|
|
const { dirname } = require('@joplin/lib/path-utils');
|
|
|
|
const markdownUtils = require('@joplin/lib/markdownUtils').default;
|
2021-12-19 09:53:19 +02:00
|
|
|
const yargParser = require('yargs-parser');
|
2021-12-19 19:24:00 +02:00
|
|
|
const { stripOffFrontMatter } = require('./website/utils/frontMatter');
|
|
|
|
const dayjs = require('dayjs');
|
|
|
|
dayjs.extend(require('dayjs/plugin/utc'));
|
2018-03-28 19:41:14 +02:00
|
|
|
|
2020-11-06 23:52:24 +02:00
|
|
|
const rootDir = dirname(dirname(__dirname));
|
2021-12-19 19:24:00 +02:00
|
|
|
const statsFilePath = `${rootDir}/readme/stats.md`;
|
2018-03-28 19:41:14 +02:00
|
|
|
|
|
|
|
function endsWith(str, suffix) {
|
|
|
|
return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
function downloadCounts(release) {
|
|
|
|
const output = {
|
|
|
|
mac_count: 0,
|
|
|
|
windows_count: 0,
|
|
|
|
linux_count: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (let i = 0; i < release.assets.length; i++) {
|
|
|
|
const asset = release.assets[i];
|
|
|
|
const n = asset.name;
|
|
|
|
if (endsWith(n, '-mac.zip') || endsWith(n, '.dmg')) {
|
|
|
|
output.mac_count += asset.download_count;
|
|
|
|
} else if (endsWith(n, '.AppImage') || endsWith(n, '.snap')) {
|
|
|
|
output.linux_count += asset.download_count;
|
|
|
|
} else if (endsWith(n, '.exe')) {
|
|
|
|
output.windows_count += asset.download_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
output.total_count = output.mac_count + output.linux_count + output.windows_count;
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
function createChangeLog(releases) {
|
|
|
|
const output = [];
|
|
|
|
|
|
|
|
output.push('# Joplin changelog');
|
|
|
|
|
|
|
|
for (let i = 0; i < releases.length; i++) {
|
|
|
|
const r = releases[i];
|
2020-03-14 01:46:14 +02:00
|
|
|
const s = [];
|
2021-05-04 13:34:32 +02:00
|
|
|
const preReleaseString = r.prerelease ? ' (Pre-release)' : '';
|
|
|
|
s.push(`## ${r.tag_name}${preReleaseString} - ${r.published_at}`);
|
2018-03-28 19:41:14 +02:00
|
|
|
s.push('');
|
2020-03-14 01:46:14 +02:00
|
|
|
const body = r.body.replace(/#(\d+)/g, '[#$1](https://github.com/laurent22/joplin/issues/$1)');
|
2018-03-28 19:41:14 +02:00
|
|
|
s.push(body);
|
|
|
|
output.push(s.join('\n'));
|
|
|
|
}
|
|
|
|
|
|
|
|
return output.join('\n\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
async function main() {
|
2021-12-19 09:53:19 +02:00
|
|
|
const argv = yargParser(process.argv);
|
|
|
|
const types = argv.types ? argv.types.split(',') : ['stats', 'changelog'];
|
2021-12-19 19:24:00 +02:00
|
|
|
const updateIntervalDays = argv.updateInterval ? argv.updateInterval : 0; // in days
|
|
|
|
const updateInterval = updateIntervalDays * 86400000; // in days
|
|
|
|
|
|
|
|
let updateStats = types.includes('stats');
|
|
|
|
const updateChangelog = types.includes('changelog');
|
|
|
|
|
|
|
|
if (updateStats && await pathExists(statsFilePath)) {
|
|
|
|
const md = await readFile(statsFilePath, 'utf8');
|
|
|
|
const info = stripOffFrontMatter(md);
|
|
|
|
if (!info.updated) throw new Error('Missing front matter property: updated');
|
|
|
|
|
|
|
|
if (info.updated.getTime() + updateInterval > Date.now()) {
|
|
|
|
console.info(`Skipping stat update because the file (from ${info.updated.toString()}) is not older than ${updateIntervalDays} days`);
|
|
|
|
updateStats = false;
|
|
|
|
} else {
|
|
|
|
console.info(`Proceeding with stat update because the file (from ${info.updated.toString()}) is older than ${updateIntervalDays} days`);
|
|
|
|
}
|
|
|
|
}
|
2021-12-19 09:53:19 +02:00
|
|
|
|
2021-12-19 19:24:00 +02:00
|
|
|
console.info(`Building docs: updateChangelog: ${updateChangelog}; updateStats: ${updateStats}`);
|
|
|
|
if (!updateStats && !updateChangelog) {
|
|
|
|
console.info('Nothing to do.');
|
|
|
|
return;
|
|
|
|
}
|
2021-12-19 09:53:19 +02:00
|
|
|
|
2018-03-28 19:41:14 +02:00
|
|
|
const rows = [];
|
|
|
|
|
|
|
|
const totals = {
|
|
|
|
windows_count: 0,
|
|
|
|
mac_count: 0,
|
|
|
|
linux_count: 0,
|
|
|
|
};
|
|
|
|
|
2019-01-12 02:01:58 +02:00
|
|
|
const processReleases = (releases) => {
|
|
|
|
for (let i = 0; i < releases.length; i++) {
|
|
|
|
const release = releases[i];
|
|
|
|
if (!release.tag_name.match(/^v\d+\.\d+\.\d+$/)) continue;
|
|
|
|
if (release.draft) continue;
|
2019-07-30 09:35:42 +02:00
|
|
|
|
2019-01-12 02:01:58 +02:00
|
|
|
let row = {};
|
|
|
|
row = Object.assign(row, downloadCounts(release));
|
2019-09-19 23:51:18 +02:00
|
|
|
row.tag_name = `[${release.tag_name}](https://github.com/laurent22/joplin/releases/tag/${release.tag_name})`;
|
2019-01-12 02:01:58 +02:00
|
|
|
row.published_at = release.published_at;
|
|
|
|
row.body = release.body;
|
2021-05-04 13:34:32 +02:00
|
|
|
row.prerelease = release.prerelease;
|
2019-01-12 02:01:58 +02:00
|
|
|
|
|
|
|
totals.windows_count += row.windows_count;
|
|
|
|
totals.mac_count += row.mac_count;
|
|
|
|
totals.linux_count += row.linux_count;
|
|
|
|
|
|
|
|
rows.push(row);
|
|
|
|
}
|
2019-07-30 09:35:42 +02:00
|
|
|
};
|
2019-01-12 02:01:58 +02:00
|
|
|
|
|
|
|
console.info('Build stats: Downloading releases info...');
|
|
|
|
|
|
|
|
const baseUrl = 'https://api.github.com/repos/laurent22/joplin/releases?page=';
|
2021-12-19 19:24:00 +02:00
|
|
|
|
2019-01-12 02:01:58 +02:00
|
|
|
let pageNum = 1;
|
|
|
|
while (true) {
|
2019-09-19 23:51:18 +02:00
|
|
|
console.info(`Build stats: Page ${pageNum}`);
|
|
|
|
const response = await fetch(`${baseUrl}${pageNum}`);
|
2019-01-12 02:01:58 +02:00
|
|
|
const releases = await response.json();
|
|
|
|
if (!releases || !releases.length) break;
|
|
|
|
processReleases(releases);
|
|
|
|
pageNum++;
|
2018-03-28 19:41:14 +02:00
|
|
|
}
|
|
|
|
|
2021-12-19 19:24:00 +02:00
|
|
|
if (updateChangelog) {
|
2021-12-19 09:53:19 +02:00
|
|
|
console.info('Build stats: Updating changelog...');
|
|
|
|
const changelogText = createChangeLog(rows);
|
2021-12-19 19:24:00 +02:00
|
|
|
await writeFile(`${rootDir}/readme/changelog.md`, changelogText);
|
2021-12-19 09:53:19 +02:00
|
|
|
}
|
|
|
|
|
2021-12-19 19:24:00 +02:00
|
|
|
if (!updateStats) return;
|
2021-12-19 09:53:19 +02:00
|
|
|
|
|
|
|
console.info('Build stats: Updating stats...');
|
2018-03-28 19:41:14 +02:00
|
|
|
|
|
|
|
const grandTotal = totals.windows_count + totals.mac_count + totals.linux_count;
|
|
|
|
totals.windows_percent = totals.windows_count / grandTotal;
|
|
|
|
totals.mac_percent = totals.mac_count / grandTotal;
|
|
|
|
totals.linux_percent = totals.linux_count / grandTotal;
|
|
|
|
|
2019-01-12 02:01:58 +02:00
|
|
|
const formatter = new Intl.NumberFormat('en-US', { style: 'decimal' });
|
|
|
|
|
2018-03-28 19:41:14 +02:00
|
|
|
const totalsMd = [
|
2019-01-12 02:01:58 +02:00
|
|
|
{ name: 'Total Windows downloads', value: formatter.format(totals.windows_count) },
|
|
|
|
{ name: 'Total macOs downloads', value: formatter.format(totals.mac_count) },
|
|
|
|
{ name: 'Total Linux downloads', value: formatter.format(totals.linux_count) },
|
2019-09-19 23:51:18 +02:00
|
|
|
{ name: 'Windows %', value: `${Math.round(totals.windows_percent * 100)}%` },
|
|
|
|
{ name: 'macOS %', value: `${Math.round(totals.mac_percent * 100)}%` },
|
|
|
|
{ name: 'Linux %', value: `${Math.round(totals.linux_percent * 100)}%` },
|
2018-03-28 19:41:14 +02:00
|
|
|
];
|
|
|
|
|
2019-01-12 02:01:58 +02:00
|
|
|
for (let i = 0; i < rows.length; i++) {
|
2021-05-04 13:34:32 +02:00
|
|
|
rows[i].tag_name = rows[i].prerelease ? `${rows[i].tag_name} (p)` : rows[i].tag_name;
|
2019-01-12 02:01:58 +02:00
|
|
|
rows[i].mac_count = formatter.format(rows[i].mac_count);
|
|
|
|
rows[i].windows_count = formatter.format(rows[i].windows_count);
|
|
|
|
rows[i].linux_count = formatter.format(rows[i].linux_count);
|
|
|
|
rows[i].total_count = formatter.format(rows[i].total_count);
|
|
|
|
}
|
|
|
|
|
2021-12-19 19:24:00 +02:00
|
|
|
const statsMd = [
|
|
|
|
'---',
|
|
|
|
`updated: ${dayjs.utc().format()}`,
|
|
|
|
'---',
|
|
|
|
'',
|
|
|
|
'# Joplin statistics',
|
|
|
|
'',
|
|
|
|
markdownUtils.createMarkdownTable([
|
|
|
|
{ name: 'name', label: 'Name' },
|
|
|
|
{ name: 'value', label: 'Value' },
|
|
|
|
], totalsMd),
|
|
|
|
'',
|
|
|
|
'(p) Indicates pre-releases',
|
|
|
|
'',
|
|
|
|
markdownUtils.createMarkdownTable([
|
|
|
|
{ name: 'tag_name', label: 'Version' },
|
|
|
|
{ name: 'published_at', label: 'Date' },
|
|
|
|
{ name: 'windows_count', label: 'Windows' },
|
|
|
|
{ name: 'mac_count', label: 'macOS' },
|
|
|
|
{ name: 'linux_count', label: 'Linux' },
|
|
|
|
{ name: 'total_count', label: 'Total' },
|
|
|
|
], rows),
|
|
|
|
];
|
2018-03-28 19:41:14 +02:00
|
|
|
|
2021-12-19 19:24:00 +02:00
|
|
|
const statsText = statsMd.join('\n');
|
|
|
|
await writeFile(statsFilePath, statsText);
|
2018-03-28 19:41:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
main().catch((error) => {
|
|
|
|
console.error('Fatal error');
|
|
|
|
console.error(error);
|
|
|
|
process.exit(1);
|
2019-07-30 09:35:42 +02:00
|
|
|
});
|