File size: 3,053 Bytes
11486ce
 
 
 
 
 
 
 
67447a4
11486ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env node

import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';

const REPO_ROOT = fileURLToPath(new URL('..', import.meta.url));
const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
const CHANGELOG_BASE_URL = 'https://github.com/MisonL/visual-journal';

function readText(path) {
    return readFileSync(join(REPO_ROOT, path), 'utf8');
}

function readJson(path) {
    return JSON.parse(readText(path));
}

function escapeRegExp(value) {
    return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

function readReadmeBadgeVersion(readme) {
    const match = readme.match(/!\[Version\]\(https:\/\/img\.shields\.io\/badge\/version-(.+?)-blue\)/);
    return match?.[1];
}

function addCheck(checks, name, ok, details = {}) {
    checks.push({ name, status: ok ? 'pass' : 'fail', ...details });
}

function buildChecks() {
    const packageJson = readJson('package.json');
    const packageLock = readJson('package-lock.json');
    const readme = readText('README.md');
    const changelog = readText('CHANGELOG.md');
    const version = packageJson.version;
    const checks = [];

    addCheck(checks, 'package-version-semver', SEMVER_PATTERN.test(version), { version });
    addCheck(checks, 'package-lock-root-version', packageLock.version === version, {
        expected: version,
        actual: packageLock.version
    });
    addCheck(checks, 'package-lock-package-version', packageLock.packages?.['']?.version === version, {
        expected: version,
        actual: packageLock.packages?.['']?.version
    });
    addCheck(checks, 'readme-version-badge', readReadmeBadgeVersion(readme) === version, {
        expected: version,
        actual: readReadmeBadgeVersion(readme) || null
    });
    addCheck(checks, 'changelog-unreleased-section', /^## \[未发布\]$/m.test(changelog));
    addCheck(checks, 'changelog-current-version-section', hasChangelogVersionSection(changelog, version), { version });
    addCheck(checks, 'changelog-unreleased-link', hasUnreleasedLink(changelog, version), { version });
    addCheck(checks, 'changelog-current-version-link', hasVersionLink(changelog, version), { version });

    return checks;
}

function hasChangelogVersionSection(changelog, version) {
    return new RegExp(`^## \\[${escapeRegExp(version)}\\] - \\d{4}-\\d{2}-\\d{2}$`, 'm').test(changelog);
}

function hasUnreleasedLink(changelog, version) {
    const expected = `[未发布]: ${CHANGELOG_BASE_URL}/compare/v${version}...HEAD`;
    return changelog.split(/\r?\n/).includes(expected);
}

function hasVersionLink(changelog, version) {
    return new RegExp(`^\\[${escapeRegExp(version)}\\]: ${escapeRegExp(CHANGELOG_BASE_URL)}/compare/.+v${escapeRegExp(version)}$`, 'm').test(changelog);
}

function main() {
    const checks = buildChecks();
    const ok = checks.every((check) => check.status === 'pass');
    console.log(JSON.stringify({ ok, checks }, null, 2));
    if (!ok) process.exit(1);
}

main();