UNPKG

13.3 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || function () {
3 __assign = Object.assign || function(t) {
4 for (var s, i = 1, n = arguments.length; i < n; i++) {
5 s = arguments[i];
6 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 t[p] = s[p];
8 }
9 return t;
10 };
11 return __assign.apply(this, arguments);
12};
13Object.defineProperty(exports, "__esModule", { value: true });
14var Fs = require("fs-extra");
15var Path = require("path");
16var ReadlineSync = require("readline-sync");
17var semver = require("semver");
18var Tmp = require("tmp");
19var git_1 = require("./git");
20var paths_1 = require("./paths");
21var release_1 = require("./release");
22var utils_1 = require("./utils");
23var defaultDumpFileName = 'tutorial.json';
24var headEnd = '[//]: # (head-end)\n';
25var footStart = '[//]: # (foot-start)\n';
26// Dumps tutorial into a JSON file
27// Output path defaults to cwd
28function dumpProject(out, options) {
29 if (out === void 0) { out = utils_1.Utils.cwd(); }
30 if (options === void 0) { options = {}; }
31 if (out instanceof Object && !(out instanceof String)) {
32 options = out;
33 out = utils_1.Utils.cwd();
34 }
35 options = __assign({ filter: options.filter, reject: options.reject }, options);
36 // Output path is relative to cwd
37 out = Path.resolve(utils_1.Utils.cwd(), out);
38 // If provided output path is a dir assume the dump file should be created inside of it
39 if (utils_1.Utils.exists(out, 'dir')) {
40 out = Path.join(out, defaultDumpFileName);
41 }
42 if (utils_1.Utils.exists(out, 'file')) {
43 options.override = options.override || ReadlineSync.keyInYN([
44 'Output path already exists.',
45 'Would you like to override it and continue?',
46 ].join('\n'));
47 if (!options.override) {
48 return;
49 }
50 }
51 console.log();
52 console.log("Dumping into " + out + "...");
53 console.log();
54 // Will recursively ensure dirs as well
55 Fs.ensureFileSync(out);
56 // Run command once
57 var tags = git_1.Git([
58 'log', '--tags', '--simplify-by-decoration', '--pretty=format:%ci %d'
59 ]).split('\n')
60 .filter(Boolean)
61 .map(function (line) {
62 return line.match(/^([^(]+) \(.*tag: ([^@]+@\d+\.\d+\.\d+).*\)$/) ||
63 line.match(/^([^(]+) \(.*tag: ([^@]+@next).*\)$/);
64 })
65 .filter(Boolean)
66 .map(function (_a) {
67 var str = _a[0], date = _a[1], name = _a[2];
68 return ({
69 date: date,
70 name: name,
71 });
72 })
73 .sort(function (a, b) {
74 return new Date(a.date) > new Date(b.date) ? -1 : 1;
75 });
76 var branchNames = tags
77 .map(function (tag) {
78 return tag.name.split('@')[0];
79 })
80 .reduce(function (prev, branchName) {
81 if (!prev.includes(branchName)) {
82 prev.push(branchName);
83 }
84 return prev;
85 }, []);
86 if (options.filter) {
87 branchNames = branchNames.filter(function (branchName) {
88 return options.filter.includes(branchName);
89 });
90 }
91 if (options.reject) {
92 branchNames = branchNames.filter(function (branchName) {
93 return !options.reject.includes(branchName);
94 });
95 }
96 var pack = Fs.readJsonSync(paths_1.Paths.npm.package);
97 // TODO: Update test data
98 // Will be defined per branch for compatibility reasons
99 var repoUrl = (typeof pack.repository === 'string' ? pack.repository :
100 typeof pack.repository === 'object' ? pack.repository.url :
101 '').replace(/\.git$/, '');
102 var dump = branchNames.map(function (branchName) {
103 var historyBranchName = branchName + "-history";
104 // Check if branch exists
105 try {
106 git_1.Git(['rev-parse', historyBranchName]);
107 // If not, create it
108 }
109 catch (e) {
110 git_1.Git.print(['branch', '--track', historyBranchName, "remotes/origin/" + historyBranchName]);
111 }
112 // Run command once
113 var releaseTags = tags
114 .filter(function (tag) {
115 return tag.name.match(branchName);
116 })
117 .map(function (tag) { return ({
118 date: tag.date,
119 version: tag.name.split('@').pop(),
120 }); });
121 var releases = releaseTags.map(function (releaseTag, releaseIndex) {
122 var prevReleaseTag = releaseTags[releaseIndex + 1] || {};
123 var tagName = branchName + "@" + releaseTag.version;
124 var tagRevision = git_1.Git(['rev-parse', tagName]);
125 var historyRevision = git_1.Git([
126 'log', historyBranchName, "--grep=^" + tagName + ":", '--format=%H',
127 ]).split('\n')
128 .filter(Boolean)
129 .pop();
130 // Instead of printing diff to stdout we will receive it as a buffer
131 var changesDiff = release_1.Release.diff(prevReleaseTag.version, releaseTag.version, null, {
132 branch: branchName,
133 pipe: true
134 });
135 var manuals = Fs
136 .readdirSync(paths_1.Paths.manuals.views)
137 // There might also be transformed manuals inside nested dirs. If we will take
138 // these dirs into an account there will be additional unexpected manuals in the
139 // formed dump file
140 .filter(function (fileName) { return /\.md$/.test(fileName); })
141 .sort(utils_1.Utils.naturalSort)
142 .map(function (manualName, stepIndex) {
143 var format = '%H %s';
144 var stepLog;
145 var manualPath;
146 // Step
147 if (stepIndex) {
148 manualPath = Path.resolve(paths_1.Paths.manuals.views, manualName);
149 stepLog = git_1.Git([
150 'log', tagRevision, "--grep=^Step " + stepIndex + ":", "--format=" + format,
151 ]);
152 }
153 else {
154 manualPath = paths_1.Paths.readme;
155 stepLog = git_1.Git([
156 'log', git_1.Git.rootHash(tagRevision), "--format=" + format,
157 ]);
158 }
159 manualPath = Path.relative(utils_1.Utils.cwd(), manualPath);
160 stepLog = stepLog.split(' ');
161 var stepRevision = stepLog.shift();
162 var manualTitle = stepLog.join(' ');
163 // Removing header and footer, since the view should be used externally on a
164 // different host which will make sure to show these two
165 var manualView = git_1.Git(['show', stepRevision + ":" + manualPath]);
166 if (manualView.includes(headEnd)) {
167 manualView = manualView
168 .split(headEnd)
169 .slice(1)
170 .join(headEnd);
171 }
172 if (manualView.includes(footStart)) {
173 manualView = manualView
174 .split(footStart)
175 .slice(0, -1)
176 .join(footStart);
177 }
178 manualView = manualView.trim();
179 return {
180 manualTitle: manualTitle,
181 stepRevision: stepRevision,
182 manualView: manualView,
183 };
184 });
185 return {
186 releaseVersion: releaseTag.version,
187 releaseDate: releaseTag.date,
188 tagName: tagName,
189 tagRevision: tagRevision,
190 historyRevision: historyRevision,
191 changesDiff: changesDiff,
192 manuals: manuals,
193 };
194 });
195 return {
196 repoUrl: repoUrl,
197 branchName: branchName,
198 historyBranchName: historyBranchName,
199 releases: releases,
200 };
201 });
202 Fs.writeJsonSync(out, dump, { spaces: 2 });
203 console.log();
204 console.log('Dump finished.');
205 console.log();
206}
207// TODO: Make client calculate the diff on a service worker
208// or serve the created HTML file (using SSR)
209function diffReleases(dump, srcTag, dstTag) {
210 var _a = srcTag.split('@'), srcBranchName = _a[0], srcReleaseVersion = _a[1];
211 var _b = dstTag.split('@'), dstBranchName = _b[0], dstReleaseVersion = _b[1];
212 if (!srcReleaseVersion && !dstReleaseVersion) {
213 srcReleaseVersion = srcBranchName;
214 dstReleaseVersion = dstBranchName;
215 srcBranchName = null;
216 dstBranchName = null;
217 }
218 if (semverEq(srcReleaseVersion, dstReleaseVersion)) {
219 return '';
220 }
221 // Test result will be used later on
222 var reversed = semverGt(srcReleaseVersion, dstReleaseVersion);
223 if (reversed) {
224 var temp = void 0;
225 temp = srcReleaseVersion;
226 srcReleaseVersion = dstReleaseVersion;
227 dstReleaseVersion = temp;
228 temp = srcBranchName;
229 srcBranchName = dstBranchName;
230 dstBranchName = temp;
231 }
232 // If an FS path was provided
233 if (typeof dump === 'string' || dump instanceof String) {
234 // Resolving path relative to cwd
235 // Note that this is the process cwd and not the project cwd
236 dump = Path.resolve(process.cwd(), dump);
237 // Parsing JSON
238 dump = Fs.readJSONSync(dump);
239 }
240 var srcDir = buildRelease(dump, srcReleaseVersion, srcBranchName);
241 var dstDir = buildRelease(dump, dstReleaseVersion, dstBranchName);
242 Fs.removeSync(srcDir.name + "/.git");
243 Fs.copySync(dstDir.name + "/.git", srcDir.name + "/.git");
244 var diff = utils_1.Utils.scopeEnv(function () {
245 git_1.Git(['add', '.']);
246 try {
247 git_1.Git(['commit', '-m', dstReleaseVersion]);
248 // No changes were made between releases
249 // Probably due to missing versions of submodules
250 }
251 catch (e) {
252 return '';
253 }
254 return reversed
255 ? git_1.Git(['diff', 'HEAD^', 'HEAD'])
256 : git_1.Git(['diff', 'HEAD', 'HEAD^']);
257 }, {
258 TORTILLA_CWD: srcDir.name
259 });
260 srcDir.removeCallback();
261 dstDir.removeCallback();
262 return postTransformDiff(diff);
263}
264function buildRelease(dump, releaseVersion, branchName) {
265 // If no branch was provided, assuming this is a chunk
266 var chunk = branchName ? dump.find(function (c) { return c.branchName === branchName; }) : dump;
267 var releaseIndex = chunk.releases.findIndex(function (r) { return r.releaseVersion === releaseVersion; });
268 // Most recent release would come LAST
269 var releases = chunk.releases.slice(releaseIndex - chunk.releases.length).reverse();
270 var diffs = releases.map(function (r) { return r.changesDiff; }).filter(Boolean).map(preTransformDiff);
271 var dir = Tmp.dirSync({ unsafeCleanup: true });
272 utils_1.Utils.scopeEnv(function () {
273 git_1.Git(['init']);
274 diffs.forEach(function (diff) {
275 try {
276 git_1.Git(['apply'], {
277 input: diff
278 });
279 }
280 catch (e) {
281 e.message += " (version " + releaseVersion + ")";
282 throw e;
283 }
284 });
285 git_1.Git(['add', '.']);
286 git_1.Git(['commit', '-m', releaseVersion]);
287 }, {
288 TORTILLA_CWD: dir.name
289 });
290 return dir;
291}
292// TODO: Add tests
293// Turns binary files into placeholders so diff can be applied
294function preTransformDiff(diff) {
295 return diff
296 .replace(/Binary files \/dev\/null and b\/([^ ]+) differ/g, [
297 '--- /dev/null',
298 '+++ b/$1',
299 '@@ -0,0 +1 @@',
300 '+__tortilla_bin__',
301 ].join('\n'))
302 .replace(/Binary files a\/([^ ]+) and \/dev\/null differ/g, [
303 '--- a/$1',
304 '+++ /dev/null',
305 '@@ -1 +0,0 @@',
306 '-__tortilla_bin__',
307 ].join('\n'))
308 .replace(/Binary files a\/([^ ]+) and b\/([^ ]+) differ/g, [
309 '--- a/$1',
310 '+++ b/$2',
311 '@@ -1 +1 @@',
312 '-__tortilla_bin__',
313 '+__tortilla_bin__',
314 ].join('\n'));
315}
316// Turns placeholders into binary files so diff can be loyal
317function postTransformDiff(diff) {
318 return diff
319 .replace(/--- \/dev\/null\n\+\+\+ b\/(.+)\n@@ -0,0 \+1 @@\n\+__tortilla_bin__/g, 'Binary files /dev/null and b/$1 differ')
320 .replace(/--- a\/(.+)\n\+\+\+ \/dev\/null\n@@ -1 \+0,0 @@\n-__tortilla_bin__/g, 'Binary files a/$1 and /dev/null differ')
321 .replace(/--- a\/(.+)\n\+\+\+ b\/(.+)\n@@ -1 \+1 @@\n-__tortilla_bin__\n\+__tortilla_bin__/g, 'Binary files a/$1 and b/$2 differ');
322}
323// Add vNext to semver.eq()
324function semverEq(src, dst) {
325 if (src === 'next' && dst === 'next') {
326 return true;
327 }
328 if (src === 'next') {
329 return false;
330 }
331 if (dst === 'next') {
332 return false;
333 }
334 return semver.eq(src, dst);
335}
336// Add vNext to semver.gt()
337function semverGt(src, dst) {
338 if (src === 'next' && dst === 'next') {
339 return false;
340 }
341 if (src === 'next') {
342 return true;
343 }
344 if (dst === 'next') {
345 return false;
346 }
347 return semver.gt(src, dst);
348}
349exports.Dump = {
350 create: dumpProject,
351 diffReleases: diffReleases
352};
353//# sourceMappingURL=dump.js.map
\No newline at end of file