-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathversion-control.js
More file actions
executable file
·688 lines (543 loc) · 24.6 KB
/
Copy pathversion-control.js
File metadata and controls
executable file
·688 lines (543 loc) · 24.6 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
#!/usr/bin/env node
import { normalize } from 'path';
import { exec, execSync } from 'child_process';
import * as windowsize from 'window-size';
import { readFileSync, writeFileSync } from 'fs';
import {
run_command_sync,
run_command_sync_to_console,
combine_params,
} from 'rad-scripts';
const unknown_version = 'unknown version';
//=========== git_version_valid: tests to see if a version is valid ============
export const git_version_valid = version => {
if ( version == null )
return false;
// If this doesn't start with a number then a dot, we won't know what to do...
if ( version.match( /^[0-9]\./ ) == null )
return false;
return true;
}
// =========== git_version: gets the git version, using [git describe], which includes tag, commit count, and current hash prefix, as a string ============
export const git_version = () => {
let desc = run_command_sync( 'git describe --always --tags' ).trim();
if ( !git_version_valid( desc ) ) {
console.log( "No semantic version tag found, creating 0.0.0..." );
const tagattempt = run_command_sync( 'git tag -a -m "rad-scripts auto-created initial tag" 0.0.0' );
desc = run_command_sync( 'git describe --always --tags' ).trim();
// If we still don't have a valid version, it's likely that the repo has just been created.
// The user will need to commit first to create HEAD.
// We COULD try committing... but that is fraught with peril to do right here...
if ( !git_version_valid( desc ) ) {
console.log( "Unable to tag - perhaps you need to make an initial commit first to actually create HEAD.\nOutput:\n" + tagattempt + "\n" );
return unknown_version;
}
}
return desc;
}
// =========== git_version_clean: gets the git version stripped to MAJOR.MINOR.PATCH ============
export const git_version_clean = () => {
const desc = git_version();
if ( desc == unknown_version ) return desc;
const tokens = desc.match( /(^[0-9]*\.[0-9]*\.[0-9]*)/ );
if ( tokens != null )
return tokens[ 1 ];
return desc;
}
//=========== git_changes: gets any changes in the current folder; returns blank if none ============
export const git_changes = folder => {
// NOTE: rebase pull will take care of recent commits that have not been pushed yet.
const changes = run_command_sync( `cd ${folder} && git status -uno --porcelain` );
return changes;
}
//=========== git_remote_changes: returns if remote changes exist, blank if none ============
// NOTE we exit on error. Need to stop and let the user fix connectivity before we plow ahead.
export const git_remote_changes = folder => {
const updateOkay = run_command_sync( `cd ${folder} && git remote update >/dev/null 2>&1 || echo fail` ).trim();
if ( updateOkay === 'fail' ) {
console.log( `[git remote update] failed, please check your git remote connectivity.` );
process.exit( 1 );
}
return run_command_sync( `cd ${folder} && git log HEAD..HEAD@{u} --oneline` );
}
// NOTE: These are used by git-sync to determine the "next" version.
// =========== git_next_major ============
export const next_major = desc => {
const tokens = desc.match( /([0-9]*)\..*/ );
if ( tokens == null ) return unknown_version;
const major = parseInt( tokens[ 1 ] ) + 1;
if ( major == null ) return unknown_version;
return major + ".0.0";
}
export const git_next_major = () => {
const desc = git_version();
if ( desc == unknown_version ) return desc;
return next_major( desc );
}
// =========== git_next_minor ============
export const next_minor = desc => {
const tokens = desc.match( /([0-9]*)\.([0-9]*)/ );
if ( tokens == null ) return unknown_version;
const major = tokens[ 1 ];
const minor = parseInt( tokens[ 2 ] ) + 1;
if ( major == null || minor == null ) return unknown_version;
return major + "." + minor + ".0";
}
export const git_next_minor = () => {
const desc = git_version();
if ( desc == unknown_version ) return desc;
return next_minor( desc );
}
// =========== git_next_patch ============
export const next_patch = desc => {
const tokens = desc.match( /([0-9]*)\.([0-9]*)\.([0-9]*)/ );
if ( tokens == null ) return unknown_version;
const major = tokens[ 1 ];
const minor = tokens[ 2 ];
const patch = parseInt( tokens[ 3 ] ) + 1;
if ( major == null || minor == null || patch == null ) return unknown_version;
return major + "." + minor + "." + patch;
}
export const git_next_patch = () => {
const desc = git_version();
if ( desc == unknown_version ) return desc;
return next_patch( desc );
}
// =========== git_next_build (DEPRECATED in most use cases): gets the git version, then strips hash and increments the commit count by one ============
export const next_build = desc => {
// First we check to see if we are sitting right on a tag, eg [1.2.3]. If so, return [1.2.3-1].
let tokens = desc.match( /(^[0-9]*\.[0-9]*\.[0-9]*$)/ );
if ( tokens != null )
return tokens[ 1 ] + "-1";
tokens = desc.match( /(^[0-9]*\.[0-9]*\.[0-9]*)-([0-9]+)/ );
if ( tokens == null || tokens[ 2 ] == null )
return unknown_version;
// Now turn [1.2.3-4-g#######] into [1.2.3-5]...
const build = parseInt( tokens[ 2 ] ) + 1;
return tokens[ 1 ] + "-" + build;
}
export const git_next_build = () => {
const desc = git_version();
if ( desc === unknown_version ) return desc;
return next_build( desc );
}
// =========== get_npm_adjusted_version ============
export const get_npm_adjusted_version = version => {
// We are given a version that we are about to apply.
// Before we do so, for node modules, we will want to ensure
// that the new version is actually higher than any
// npm module version in package.json.
// Most of the time this isn't a problem, and we simply return the version we were given.
// But if there were versions that were manually published, we don't want to clash.
const filename = 'package.json';
try {
const packageFileString = readFileSync( filename, 'utf8' );
const p = JSON.parse( packageFileString );
const packageVersion = p.version;
const packageTokens = packageVersion.match( /([0-9]*)\.([0-9]*)\.([0-9]*).*/ );
const versionTokens = version.match( /([0-9]*)\.([0-9]*)\.([0-9]*).*/ );
if (
parseInt( packageTokens[ 1 ] ) > parseInt( versionTokens[ 1 ] )
|| (
parseInt( packageTokens[ 1 ] ) === parseInt( versionTokens[ 1 ] )
&& parseInt( packageTokens[ 2 ] ) > parseInt( versionTokens[ 2 ] )
) || (
parseInt( packageTokens[ 1 ] ) === parseInt( versionTokens[ 1 ] )
&& parseInt( packageTokens[ 2 ] ) === parseInt( versionTokens[ 2 ] )
&& parseInt( packageTokens[ 3 ] ) >= parseInt( versionTokens[ 3 ] )
)
) {
const adjustedVersion = `${packageTokens[ 1 ]}.${packageTokens[ 2 ]}.${parseInt( packageTokens[ 3 ] ) + 1}`;
console.log( `The npm package version [${packageVersion}] is greater than the next git tag (${version}).` );
console.log( `Target version has been incremented to ${adjustedVersion}.` );
return adjustedVersion;
}
}
catch ( err ) {
console.log( `get_npm_adjusted_version error:\n${err}\n` );
process.exit( 1 );
}
return version;
}
// =========== git_sync ============
// NOTE: This follows the rad-scripts mantra of semver-tagging every push.
//
// We consider the following flows here.
//
// 1) commit, pull --rebase, determine "next" version, stamp, commit, tag, push, publish
// This process is thorough but would often result in two commits.
// Also, if you committed local changes somewhere else they'll be screwed by rebase
// (but that would be uncommon).
// See http://stackoverflow.com/questions/2472254/when-should-i-use-git-pull-rebase
//
// 2) pull, determine "next" version, stamp, commit, tag, push, publish
// Best practice is to pull before starting work, and finish before others push. Not always possible. :-)
// So this process can result in merges when there were remote changes - but that's the cost of doing business.
// The problem is the pull - it won't happen if changes are not committed first.
//
// 3) determine "next" version using local and remote tags, stamp, commit, pull --rebase, tag, push, publish
// This process is does everything we need.
// The difficulty is in implementing the first step.
//
// 4) stash, pull --rebase, stash pop, determine "next" version, stamp, commit, tag, push, publish
// This is just as good as 3 and is easier. It does everything we need, well, for the typical commit.
//
// We will go with the fourth.
//
export const git_sync = ( folder, tag_params, stamp_callback_function ) => {
let blip = "";
try {
process.chdir( normalize( folder ) );
let changes = git_changes( folder );
let remote_changes = git_remote_changes( folder );
if ( changes ) {
changes = ( changes.length > 0 );
}
if ( remote_changes ) {
remote_changes = ( remote_changes.length > 0 );
}
const any_changes = changes || remote_changes;
// Currently we bail out before printing "---" blip, as it's fairly chatty.
// --force skips this bailout so stamp callbacks can create changes to commit.
if ( !any_changes && !tag_params.force ) {
// There may be more to do after we return, doh!
// process.exit(0);
return 0;
}
// Build blip.
if ( changes && remote_changes && !tag_params.pull_only ) { blip = '<=>'; }
else if ( ( changes || tag_params.force ) && !tag_params.pull_only ) { blip = '>>>'; }
else if ( remote_changes ) { blip = '<<<'; }
else { blip = '---'; }
// We can't get the version here because we haven't done a pull yet and we don't yet know what it will be.
// if (git_version_valid(version) ) { blip += ' ['+version+']'; }
console.log( '----------------------------------' );
console.log( blip + ' ' + folder );
console.log( '----------------------------------' );
// If comment is anything other than blank, build a proper comment format that we can slap on the end of cmd.
let comment = tag_params.comment;
if ( comment.length > 0 ) {
comment = " -m \"" + comment + "\"";
}
if ( changes && remote_changes ) {
// Why did we originally use --keep-index here?
// run_command_quietly('git stash --keep-index');
run_command_sync_to_console( 'git stash' );
}
// See note in function header regarding --rebase
if ( remote_changes ) {
run_command_sync_to_console( 'git pull --rebase' );
}
if ( changes && remote_changes ) {
run_command_sync_to_console( 'git stash pop' );
}
// We are now ready to push. Bail out if we only wanted pull.
if ( tag_params.pull_only )
return 0;
if ( changes || tag_params.force ) {
if ( tag_params.notag ) {
// Just commit, no tag work at all.
run_command_sync_to_console( 'git commit -a' + comment );
} else {
// Now we can get the "next" version.
// We had to wait until after the pull,
// since there may have been newer REMOTE version tags.
let version;
if ( tag_params.major ) { version = git_next_major(); }
else if ( tag_params.minor ) { version = git_next_minor(); }
else { version = git_next_patch(); }
if ( !git_version_valid( version ) ) {
console.log( "Can't determine 'next' version of current tag..." );
process.exit( 1 );
}
// Here is where we would do any version stamping into whatever product or app we are supporting.
// This is very app-specific, so we expect an (optional) callback function to get it done, if desired.
// See docs or node modules like rad-scripts for more info.
if ( stamp_callback_function ) {
// We don't want to throw an error, so we pass null for the error argument
// See: http://stackoverflow.com/questions/19739755/nodejs-callbacks-simple-example
const cbResult = stamp_callback_function( null, version );
// Guard: if callback forgot to return version, don't clobber it with undefined.
if ( cbResult !== undefined ) {
version = cbResult;
}
}
// Make sure your editor waits before returning if you want to be able to provide comments on the fly.
// TODO get on-the-fly commit message and use as the tag message. Right now we prompt twice.
// Commit
run_command_sync_to_console( 'git commit -a' + comment );
// Tag
run_command_sync_to_console( 'git tag -a' + comment + ' ' + version );
}
}
// Always push in case we already committed something
// You should really make [--follow-tags] the default via push.followTags
run_command_sync_to_console( 'git push --follow-tags' );
// Erp... this is causing failure in scripts. We need to return 0 on success.
// Return true if there were changes.
// return changes;
return 0;
}
catch ( err ) {
// NOTE: this is VERY noisy...
console.log( err );
// If blip is not set, we had an earlier error in just trying to connect to the repo.
if ( blip == "" ) {
console.log( '----------------------------------' );
console.log( "*** [" + folder + "] WARNING: git-sync could not connect to this repo..." );
console.log( '----------------------------------' );
} else {
console.log( "*** [" + folder + "] WARNING: git-sync did not complete, check repo for conflicts..." );
console.log( '----------------------------------' );
}
return -1;
}
}
// =========== git_clone: clones a repo ============
export const git_clone = ( remote_repo, local_folder, sync ) => {
// Make sure the task specifies the full target folder since these may be called async.
// i.e., don't use process.cwd()...
const cmd1 = `git clone "${remote_repo}" "${local_folder}"`;
const e = sync ? execSync : exec;
e( cmd1, function ( error, stdout, stderr ) {
if ( stderr ) {
if ( stdout.length > 0 ) console.log( stdout );
console.log( stderr );
} else {
console.log( "cloned: " + local_folder );
}
} );
}
// =========== git_tag_list: list tags with message, user and timestamp (matching git_log style) ============
export const git_tag_list = tag_params => {
const { width, height } = windowsize.default || { width: 120, height: 40 };
const cols = width - 2;
let head = 10;
if ( tag_params.comment != null && tag_params.comment.length )
head = tag_params.comment
run_command_sync_to_console(
`git for-each-ref --sort=-version:refname refs/tags/ `
+ `--format="%(refname:short)\t%(creatordate:relative)\t%(subject)\t%(if)%(taggername)%(then)%(taggername)%(else)%(authorname)%(end)" `
+ `| head -${head} `
+ `| awk -F'\\t' -v cols=${cols} '`
+ `{ t[NR]=$1; d[NR]=$2; s[NR]=$3; w[NR]=$4; `
+ `if(length($1)>mt) mt=length($1); if(length($2)>md) md=length($2); if(length($4)>mw) mw=length($4); n=NR } `
+ `END { co=cols-mt-md-mw-3; if(co<1) co=1; `
+ `for(i=1;i<=n;i++) printf "%-*s \\033[34m%*s\\033[0m %-*.*s \\033[37m%*s\\033[0m\\n", mt, t[i], md, d[i], co, co, s[i], mw, w[i] }'`
);
}
// =========== git_branchlog: show a concise branch merge history ============
export const git_branchlog = tag_params => {
// branches, prettified; see here:
// https://stackoverflow.com/questions/1838873/visualizing-branch-topology-in-git
let cmd = "git log --graph --oneline"
// by default we simplify
// if requested, don't simplify (ie show all commits)
if ( !tag_params.with_commits )
cmd += " --simplify-by-decoration"
// You can specify another branch, OR you can specify --all
if ( tag_params.all )
cmd += " --all"
else if ( tag_params.branch != null && tag_params.branch.length )
cmd += " " + tag_params.branch
run_command_sync_to_console( cmd );
}
// =========== git_log: concise pretty log ============
export const git_log = tag_params => {
// Getting terminal size is nasty, so use a package that works "often" but not always, sigh.
const { width, height } = windowsize.default || { width: 120, height: 40 };
const cols = width - 2;
let head = height - 2;
if ( tag_params.comment != null && tag_params.comment.length )
head = tag_params.comment
let branch = ""
if ( tag_params.branch != null && tag_params.branch.length )
branch = tag_params.branch
// get log, prettified; see here:
// http://stackoverflow.com/questions/1441010/the-shortest-possible-output-from-git-log-containing-author-and-date
run_command_sync_to_console(
`git log ${branch} --format="%h%x09%ad%x09%s%x09%D%x09%an" --date=relative -${head} `
+ `| awk -F'\\t' -v cols=${cols} '`
+ `{ h[NR]=$1; t[NR]=$2; s[NR]=$3; w[NR]=$5; `
+ `dp=""; split($4,dc,", "); for(j in dc) if(dc[j]~/^tag: /) { if(dp!="") dp=dp", "; dp=dp substr(dc[j],6) }; d[NR]=dp; `
+ `if(length($1)>mh) mh=length($1); if(length($2)>mt) mt=length($2); if(length(dp)>md) md=length(dp); if(length($5)>mw) mw=length($5); n=NR } `
+ `END { co=cols-mh-mt-mw-3-(md>0?md+1:0); if(co<1) co=1; `
+ `for(i=1;i<=n;i++) printf "%*s \\033[34m%*s\\033[0m %-*.*s%s \\033[37m%*s\\033[0m\\n", mh, h[i], mt, t[i], co, co, s[i], (md>0?sprintf(" \\033[31m%*s\\033[0m",md,d[i]):""), mw, w[i] }'`
);
}
//=========== git_skip: tell git to start ignoring upstream and local changes to the given file ============
export const git_skip = file => {
run_command_sync_to_console( `git update-index --skip-worktree "${file}"` );
}
//=========== git_noskip: tell git to stop ignoring upstream and local changes to the given file ============
export const git_noskip = file => {
run_command_sync_to_console( `git update-index --no-skip-worktree "${file}"` );
}
//=========== git_skiplist: list the files for which git is currently ignoring upstream and local changes ============
export const git_skiplist = () => {
try {
run_command_sync_to_console( "git ls-files -v . | grep ^S" );
}
catch ( err ) {
}
}
//=========== git_folder_from_url: extract top level folder name ============
export const git_folder_from_url = url => {
// Get project name out of this:
// ssh://user@me.com:1000/subdirs/folder.git
const git_regex = "/([a-zA-Z0-9-]+)([.]git)?$";
const greg_result = url.match( git_regex );
if ( greg_result && greg_result[ 1 ] )
return greg_result[ 1 ];
else
return "unknown";
}
// =========== parse_tag_parameters: utility commonly needed to parse tag-based command line parameters ============
export const parse_tag_parameters = ( argv, noslice ) => {
// Typical node argv sets include [#path#/node #path#/node_cmd param1 param2 ...]
// By default, we slice off the first two, but some callers do that themselves.
let args;
if ( noslice )
args = argv;
else
args = argv.slice( 2 );
let major = 0;
let minor = 0;
let pull_only = 0;
let force = 0;
let with_commits = 0;
let all = 0;
let branch = "";
// Check for "first" params.
if ( args[ 0 ] == '--major' || args[ 0 ] == '-j' ) { major = 1; args = args.slice( 1 ); }
else if ( args[ 0 ] == '--minor' || args[ 0 ] == '-n' ) { minor = 1; args = args.slice( 1 ); }
else if ( args[ 0 ] == '--pull-only' || args[ 0 ] == '-p' ) { pull_only = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--force' || args[ 0 ] == '-f' ) { force = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--branch' || args[ 0 ] == '-b' ) { branch = args[ 1 ]; args = args.slice( 2 ); }
if ( args[ 0 ] == '--with-commits' || args[ 0 ] == '-c' ) { with_commits = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--all' || args[ 0 ] == '-a' ) { all = 1; args = args.slice( 1 ); }
// Do it again to handle more slot ordering. Hackery.
if ( args[ 0 ] == '--force' || args[ 0 ] == '-f' ) { force = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--branch' || args[ 0 ] == '-b' ) { branch = args[ 1 ]; args = args.slice( 2 ); }
if ( args[ 0 ] == '--with-commits' || args[ 0 ] == '-c' ) { with_commits = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--all' || args[ 0 ] == '-a' ) { all = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--force' || args[ 0 ] == '-f' ) { force = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--branch' || args[ 0 ] == '-b' ) { branch = args[ 1 ]; args = args.slice( 2 ); }
if ( args[ 0 ] == '--with-commits' || args[ 0 ] == '-c' ) { with_commits = 1; args = args.slice( 1 ); }
if ( args[ 0 ] == '--all' || args[ 0 ] == '-a' ) { all = 1; args = args.slice( 1 ); }
// We used to actually get the version here.
// The reason we CAN'T is that there may be newer REMOTE version tags that we haven't pulled at this time.
// We need to determine the actual next version LATER in git-sync.
const comment = combine_params( args );
return {
"major": major,
"minor": minor,
"pull_only": pull_only,
"force": force,
"comment": comment,
"branch": branch,
"with_commits": with_commits,
"all": all,
};
}
// =========== npm_update_version ============
export const npm_update_version = version => {
const filename = 'package.json';
try {
// We know we have an npm package.
// Ensure the version increment exceeds the last published npm package version.
const adjustedVersion = get_npm_adjusted_version( version );
console.log( 'Stamping version [' + adjustedVersion + '] into [' + filename + ']...' );
const origversion = readFileSync( filename, 'utf-8' );
// "version": "1.3.0", ==> "version": "###version###",
const newversion = origversion.replace( /\"version\".*/, '\"version\": \"' + adjustedVersion + '\",' );
writeFileSync( filename, newversion, 'utf-8' );
// console.log(filename + " was updated...");
// ALWAYS update dependencies.
// This is an opinionated choice, it will break you faster, but get you fixed faster as well.
// It is also used here to update our new version in the package-lock.json file.
console.log( 'Updating ALL dependencies...' );
run_command_sync_to_console( "npm update" );
return adjustedVersion;
}
catch ( err ) {
console.log( filename + ' could not be updated: ' + err );
process.exit( 1 );
}
}
// =========== svn_last_changed_rev: gets the SVN "last changed rev" for the current folder, as a string ============
export const svn_last_changed_rev = () => {
const svn_info = run_command_sync( "svn info" );
// extract the "Last Changed Rev"
const regx = /^Last Changed Rev: (.*)$/gm;
const array_result = regx.exec( svn_info );
// return the first group result ([0] contains the whole result)
return array_result[ 1 ];
}
// =========== svn_rev: gets the SVN current revision for the current repo, as a string ============
export const svn_rev = () => {
const svn_info = run_command_sync( "svn info" );
// extract the "Last Changed Rev"
const regx = /^Revision: (.*)$/gm;
const array_result = regx.exec( svn_info );
// return the first group result ([0] contains the whole result)
return array_result[ 1 ];
}
// ============ build_semantic_version: builds "next" historical semver, with validation using stored result ===============
export const build_semantic_version = ( major, minor, patch, build, lastVersionFolder ) => {
process.chdir( lastVersionFolder );
let m = parseInt( readFileSync( 'major.txt', 'utf-8' ) );
let n = parseInt( readFileSync( 'minor.txt', 'utf-8' ) );
let p = parseInt( readFileSync( 'patch.txt', 'utf-8' ) );
let b = parseInt( readFileSync( 'build.txt', 'utf-8' ) );
// Compare to parameters
// If different, adjust and save
let m2 = major;
let n2 = minor;
let p2 = patch;
let b2 = build;
if ( m2 != m ) {
// Validate
if (
m2 != m + 1
|| n2 != 0
|| p2 != 0
) {
console.log( 'New major version provided incorrectly: old(' + m + '.' + n + '.' + p + '.' + b + ") new(" + m2 + '.' + n2 + '.' + p2 + '.' + b2 + ')' );
process.exit( 1 );
}
// Reset n p
m = m2;
n = 0;
p = 0;
writeFileSync( 'major.txt', m, 'utf-8' );
writeFileSync( 'minor.txt', n, 'utf-8' );
writeFileSync( 'patch.txt', p, 'utf-8' );
} else if ( n2 != n ) {
// Validate
if (
n2 != n + 1
|| p2 != 0
) {
console.log( 'New minor version provided incorrectly: old(' + m + '.' + n + '.' + p + '.' + b + ") new(" + m2 + '.' + n2 + '.' + p2 + '.' + b2 + ')' );
process.exit( 1 );
}
// Reset p
n = n2;
p = 0;
writeFileSync( 'minor.txt', n, 'utf-8' );
writeFileSync( 'patch.txt', p, 'utf-8' );
} else if ( p2 != p ) {
// Validate
if ( p2 != p + 1 ) {
console.log( 'New patch version provided incorrectly: old(' + m + '.' + n + '.' + p + '.' + b + ") new(" + m2 + '.' + n2 + '.' + p2 + '.' + b + ')' );
process.exit( 1 );
}
p = p2;
writeFileSync( 'patch.txt', p, 'utf-8' );
}
// Write the new build version.
b = b2;
writeFileSync( 'build.txt', b, 'utf-8' );
return m + '.' + n + '.' + p + '.' + b;
}