-
Notifications
You must be signed in to change notification settings - Fork 1
/
build.js
executable file
·142 lines (121 loc) · 3.4 KB
/
build.js
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env node
const { execFile } = require('child_process');
const async = require('async');
const diagnostics = require('diagnostics');
const { runCommands, pushTags } = require('./run');
const isMaxBuffer = /maxBuffer exceeded/;
const isVersionBump = /^\+ "version": "([^"]+)"/;
const debug = {
ver: diagnostics('git-semver2-tag:ver'),
skip: diagnostics('git-semver2-tag:skip')
};
/**
* Lists all git tags for the current repository
*/
function listTags(done) {
execFile('git', ['tag'], function (err, stdout) {
if (err) { return done(err); }
done(null, stdout.split('\n').filter(Boolean));
});
}
/**
* List all SHAs that may have a potential version. That is:
* all SHAs where package.json was changes.
*/
function listPotentialVersionShas(done) {
execFile('git', ['--no-pager', 'log', '--format=format:%H', 'package.json'], function (err, stdout) {
if (err) { return done(err); }
done(null, stdout.split('\n'));
});
}
/**
* Get the version the specified SHA represents if it exists
* by looking for a line in the diff of the form:
*
* + "version": "4.5.1"
* - "version": "4.5.0"
*
*/
function getShaVersion(sha, done) {
execFile('git', ['show', sha], function (err, stdout) {
if (err) {
if (isMaxBuffer.test(err.message)) {
debug.skip('Ignored error %s for: %s', err.message, sha);
return done();
}
return done(err);
}
const versionLine = stdout.split('\n')
.find(line => isVersionBump.test(line))
if (!versionLine) {
debug.skip('No version bump in SHA: %s', sha);
return done();
}
const [, version] = isVersionBump.exec(versionLine);
debug.ver('Found version %s in %s %s', version, sha, versionLine);
done(null, {
version,
line: versionLine,
stdout,
sha
});
});
}
/**
* Filters the specified information in the `repo` for only missing
* versions.
*/
function filterMissingVersions(repo, done) {
async.mapLimit(repo.shas, 20, getShaVersion, function (err, versions) {
if (err) { throw err; }
const tagLookup = repo.tags.reduce((acc, tag) => {
acc[tag] = true;
return acc;
}, {});
versions = versions.filter(ver => {
if (!ver) { return; }
if (tagLookup[ver.version]) {
console.log('Skipping existing version: %s', ver.version);
return false;
}
return true;
});
console.log('\n## Found missing git tags');
if (versions.length) {
console.log('[\n%s\n]', versions.map(v => ` ${v.version}`).join(',\n'));
} else {
console.log('[NONE]\n');
}
done(null, versions);
});
}
function createGitTags(versions, done) {
if (!versions || !versions.length) {
return done();
}
const commands = versions.map(ver => {
return `git tag -a '${ver.version}' -m 'Version ${ver.version}' ${ver.sha}`;
});
runCommands('\n## Creating git tags', commands, err => {
if (err) { return done(err) }
pushTags(done);
});
}
console.log('## Reading package.json git history')
async.parallel({
shas: listPotentialVersionShas,
tags: listTags
}, function (err, repo) {
if (err) { throw err; }
async.waterfall([
async.apply(filterMissingVersions, repo),
createGitTags
], err => {
if (err) { throw err; }
if (process.env.DRY) {
console.log('DRY run completed. No git commands run.');
return;
}
console.log('Historical git tags created');
});
});