saturn-core-cli 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/publish.js +18 -9
- package/lib/changelog.js +114 -0
- package/package.json +1 -1
package/commands/publish.js
CHANGED
|
@@ -15,6 +15,7 @@ const SATURN_API_TOKEN =
|
|
|
15
15
|
var exec = require("child-process-promise").exec;
|
|
16
16
|
var spawn = require("child-process-promise").spawn;
|
|
17
17
|
const semverInc = require("semver/functions/inc");
|
|
18
|
+
const { buildChangelog } = require("../lib/changelog");
|
|
18
19
|
|
|
19
20
|
async function action(release = "patch", options) {
|
|
20
21
|
try {
|
|
@@ -24,23 +25,30 @@ async function action(release = "patch", options) {
|
|
|
24
25
|
console.log(e.message, e);
|
|
25
26
|
exemptions = [];
|
|
26
27
|
}
|
|
27
|
-
let message = options["message"];
|
|
28
28
|
const packageObj = await fs.readJson(`package.json`);
|
|
29
|
-
//if (version == undefined) {
|
|
30
|
-
//let version = packageObj.version;
|
|
31
|
-
//}
|
|
32
29
|
console.log("Exemptions", exemptions);
|
|
33
30
|
let version = semverInc(packageObj.version, release);
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
if (!version) {
|
|
32
|
+
throw new Error(`Invalid release type "${release}"`);
|
|
33
|
+
}
|
|
34
|
+
let changelog = options.changelog
|
|
35
|
+
? await buildChangelog(packageObj.version)
|
|
36
|
+
: "";
|
|
37
|
+
let description = [options.message, changelog].filter(Boolean).join("\n\n");
|
|
38
|
+
// The map checksums package.json, so the bump must land first; a dry run leaves it alone.
|
|
39
|
+
if (!options.dry) {
|
|
40
|
+
packageObj.version = version;
|
|
41
|
+
await fs.writeJson(`package.json`, packageObj, { spaces: 2 });
|
|
42
|
+
}
|
|
36
43
|
let map = await new mapper({ exemptions: exemptions }).createMap("./");
|
|
37
44
|
console.log("MAP", map);
|
|
38
45
|
if (options.dry) {
|
|
46
|
+
console.log(`DESCRIPTION for ${version}\n${description}`);
|
|
39
47
|
return;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
let core = await getCoreId(packageObj.saturn.core);
|
|
43
|
-
await createInstance(map, core.id, version,
|
|
51
|
+
await createInstance(map, core.id, version, description);
|
|
44
52
|
console.log("DONE");
|
|
45
53
|
await doGitAdd();
|
|
46
54
|
await doGitCommit("SC Publish");
|
|
@@ -219,8 +227,9 @@ function command(prog) {
|
|
|
219
227
|
program = prog;
|
|
220
228
|
program
|
|
221
229
|
.command("publish [release]", { isDefault: true })
|
|
222
|
-
.option("-d, --dry
|
|
223
|
-
.option("-m, --message", "Description of the update", "")
|
|
230
|
+
.option("-d, --dry", "Dry run: print the map and description without publishing", false)
|
|
231
|
+
.option("-m, --message <text>", "Description of the update", "")
|
|
232
|
+
.option("--no-changelog", "Leave the commit changelog out of the description")
|
|
224
233
|
.description("Publish Saturn Version")
|
|
225
234
|
.action(action);
|
|
226
235
|
}
|
package/lib/changelog.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
var execFile = require("child-process-promise").execFile;
|
|
2
|
+
|
|
3
|
+
// Saturn Instance descriptions are stored by the manager; keep them to a readable size.
|
|
4
|
+
const MAX_LENGTH = 20000;
|
|
5
|
+
const MAX_LISTED_FILES = 10;
|
|
6
|
+
const PUBLISH_SUBJECT = /^"?SC Publish"?$/;
|
|
7
|
+
const TRAILER = /^(Co-Authored-By|Signed-off-by):/i;
|
|
8
|
+
|
|
9
|
+
async function git(args) {
|
|
10
|
+
let result = await execFile("git", args, { maxBuffer: 10 * 1024 * 1024 });
|
|
11
|
+
return result.stdout;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function tagExists(tag) {
|
|
15
|
+
try {
|
|
16
|
+
await git(["rev-parse", "-q", "--verify", `refs/tags/${tag}`]);
|
|
17
|
+
return true;
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function resolveBaseTag(previousVersion) {
|
|
24
|
+
if (previousVersion && (await tagExists(previousVersion))) {
|
|
25
|
+
return previousVersion;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
return (await git(["describe", "--tags", "--abbrev=0"])).trim();
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function readCommits(base) {
|
|
35
|
+
let output = await git([
|
|
36
|
+
"log",
|
|
37
|
+
"--no-merges",
|
|
38
|
+
"--reverse",
|
|
39
|
+
"--format=%h%x1f%s%x1f%b%x1e",
|
|
40
|
+
`${base}..HEAD`,
|
|
41
|
+
]);
|
|
42
|
+
return output
|
|
43
|
+
.split("\x1e")
|
|
44
|
+
.map((record) => record.replace(/^\n/, ""))
|
|
45
|
+
.filter((record) => record.trim())
|
|
46
|
+
.map((record) => {
|
|
47
|
+
let [hash, subject, body = ""] = record.split("\x1f");
|
|
48
|
+
return { hash, subject: subject.trim(), body };
|
|
49
|
+
})
|
|
50
|
+
.filter((commit) => !PUBLISH_SUBJECT.test(commit.subject));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function formatCommit(commit) {
|
|
54
|
+
let lines = commit.body.split("\n").filter((line) => !TRAILER.test(line.trim()));
|
|
55
|
+
while (lines.length && !lines[lines.length - 1].trim()) {
|
|
56
|
+
lines.pop();
|
|
57
|
+
}
|
|
58
|
+
while (lines.length && !lines[0].trim()) {
|
|
59
|
+
lines.shift();
|
|
60
|
+
}
|
|
61
|
+
let body = lines.map((line) => (line.trim() ? ` ${line}` : "")).join("\n");
|
|
62
|
+
return body ? `- ${commit.subject}\n${body}` : `- ${commit.subject}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function uncommittedFiles() {
|
|
66
|
+
let output = await git(["status", "--porcelain"]);
|
|
67
|
+
return output
|
|
68
|
+
.split("\n")
|
|
69
|
+
.filter((line) => line.trim())
|
|
70
|
+
.map((line) => line.slice(3).split(" -> ").pop().replace(/^"|"$/g, ""))
|
|
71
|
+
.filter((file) => file !== "package.json");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function formatUncommitted(files) {
|
|
75
|
+
let listed = files.slice(0, MAX_LISTED_FILES).join(", ");
|
|
76
|
+
let more = files.length > MAX_LISTED_FILES ? ` +${files.length - MAX_LISTED_FILES} more` : "";
|
|
77
|
+
return `- Uncommitted changes in: ${listed}${more}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Builds markdown release notes from the commits since the previous published tag, for the
|
|
82
|
+
* Saturn Instance description. Returns "" when there is no tag to compare against.
|
|
83
|
+
*/
|
|
84
|
+
async function buildChangelog(previousVersion) {
|
|
85
|
+
let base = await resolveBaseTag(previousVersion);
|
|
86
|
+
if (!base) {
|
|
87
|
+
console.log("No previous git tag found, skipping changelog");
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let entries = (await readCommits(base)).map(formatCommit);
|
|
92
|
+
let files = await uncommittedFiles();
|
|
93
|
+
if (files.length) {
|
|
94
|
+
entries.push(formatUncommitted(files));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let kept = [];
|
|
98
|
+
let length = 0;
|
|
99
|
+
for (let entry of entries) {
|
|
100
|
+
if (length + entry.length > MAX_LENGTH) {
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
kept.push(entry);
|
|
104
|
+
length += entry.length + 1;
|
|
105
|
+
}
|
|
106
|
+
if (kept.length < entries.length) {
|
|
107
|
+
kept.push(`…and ${entries.length - kept.length} more commits`);
|
|
108
|
+
}
|
|
109
|
+
return kept.join("\n");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
buildChangelog: buildChangelog,
|
|
114
|
+
};
|