@getik-public/cli 1.3.0-beta1 → 1.3.0

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/CHANGELOG.md CHANGED
@@ -1,7 +1,5 @@
1
- ### v1.3.0-beta1
2
- Added new features:
3
- - new script: `getik-cli increment-version`(only for mobile for now)
4
- - extended `getik-cli mobile-build` script to build only angular and zip it for OTA feature.
1
+ ### v1.3.0
2
+ Added prebuild checks before any production builds for store
5
3
 
6
4
 
7
5
  ### v1.2.1
package/bin/index.js CHANGED
@@ -4,14 +4,12 @@ import { program } from 'commander';
4
4
  import chalk from 'chalk';
5
5
  import figlet from 'figlet';
6
6
 
7
- import { incrementVersion } from '../src/increment-version.js';
8
7
  import { mobileBuild } from '../src/mobile-build.js';
9
8
  import { uploadToGetikCloud } from '../src/upload-to-getik-cloud.js';
10
9
 
11
10
 
12
11
  console.log(chalk.green(figlet.textSync('Getik CLI', {horizontalLayout: 'full'})));
13
12
 
14
- incrementVersion();
15
13
  mobileBuild();
16
14
  uploadToGetikCloud();
17
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getik-public/cli",
3
- "version": "1.3.0-beta1",
3
+ "version": "1.3.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -19,7 +19,7 @@ async function applyPatchersForExternalNpmPackages() {
19
19
  for (const filename of patchesInFolder) {
20
20
  if (filename.indexOf(filenameEndsWith) === filename.length - filenameEndsWith.length) {
21
21
  let pathToFile = path.join(process.cwd(), patchesFolderName, filename);
22
- if (process.platform === "win32") {
22
+ if (process.platform === 'win32') {
23
23
  pathToFile = path.join('file:\\', pathToFile);
24
24
  }
25
25
  const patcherImport = await import(pathToFile);
@@ -65,7 +65,7 @@ async function applyPatchersForExternalNpmPackages() {
65
65
  }
66
66
 
67
67
 
68
- function readVersionsFromPackageJson(options) {
68
+ function readVersionsFromPackageJson() {
69
69
  console.log('Checking versions in package.json file...');
70
70
  const packageJsonBuffer = fs.readFileSync(path.join(process.cwd(), 'package.json'));
71
71
  const packageJson = JSON.parse(packageJsonBuffer);
@@ -88,34 +88,15 @@ function readVersionsFromPackageJson(options) {
88
88
  const zTransformed = (z < 10) ? `0${z}` : z;
89
89
  const versionCode = `${x}${yTransformed}${zTransformed}`;
90
90
 
91
- const env = (options.environment.charAt(0).toUpperCase() + options.environment.slice(1));
92
- const otaVersionPropertyName = `otaVersion${env.split('Debug')[0]}`;
93
- const otaVersionMessage = packageJson[otaVersionPropertyName] ? ` , ${otaVersionPropertyName} = ${packageJson[otaVersionPropertyName]}.` : '.';
94
-
95
- console.log(`Extracted versions: versionName = ${versionName}, versionCode = ${versionCode}${otaVersionMessage}`);
91
+ console.log(`Extracted versions: versionName = \x1b[32m${versionName}\x1b[0m, versionCode = \x1b[32m${versionCode}\x1b[0m.`);
96
92
 
97
93
  return {
98
94
  versionName: versionName,
99
95
  versionCode: versionCode,
100
- ota: packageJson[otaVersionPropertyName],
101
96
  }
102
97
  }
103
98
 
104
99
 
105
- function makeVersionsFileInTypescript(versions) {
106
- const pathToVersionsFile = path.join(process.cwd(), 'src', 'environments', 'versions.ts');
107
- if (fs.existsSync(pathToVersionsFile)) {
108
- fs.rmSync(pathToVersionsFile);
109
- }
110
- const versionsFileContent = `export const versions = {
111
- ota: ${versions.ota},
112
- native: '${versions.versionName}',
113
- };
114
- `;
115
- fs.writeFileSync(pathToVersionsFile, versionsFileContent);
116
- }
117
-
118
-
119
100
  function checkKeystorePropertiesFile() {
120
101
  const pathToKeystoreProperties = path.join(process.cwd(), 'android', 'keystore.properties');
121
102
 
@@ -203,19 +184,6 @@ function checkPatcherForPackageMatch(patcher) {
203
184
  }
204
185
 
205
186
 
206
- function createCommandsForOTA(options, versions) {
207
- cleanBuildFolder(options);
208
- if (!versions.ota) {
209
- throw new Error(`You are trying to build app for OTA but OTA version not found. Make sure you have defined properties "otaVersion<ENVIRONMENT>" for every environment in "package.json".`);
210
- }
211
- const buildAngular = `ng build --configuration=${options.environment}`;
212
- const createZip = `zip -q -r ./${buildFolder}/ota/www-${versions.versionName}-${versions.ota}.zip ./www`;
213
- const commands = [buildAngular, createZip];
214
-
215
- return commands;
216
- }
217
-
218
-
219
187
  function createCommandsForAndroid(options) {
220
188
  const isWindows = (process.platform === 'win32');
221
189
  const capitalizedEnvironment = (options.environment.charAt(0).toUpperCase() + options.environment.slice(1));
@@ -228,7 +196,7 @@ function createCommandsForAndroid(options) {
228
196
 
229
197
  function createCommandsForIos(options) {
230
198
  const workspace = './App/App.xcworkspace';
231
- const debugMode = (options.environment.indexOf("Debug") >= 0);
199
+ const debugMode = (options.environment.indexOf('Debug') >= 0);
232
200
  const config = (debugMode ? 'Debug' : 'Release');
233
201
  const environment = (options.environment.split('Debug')[0]);
234
202
  const archive = `./build/archive/${environment}.xcarchive`;
@@ -261,7 +229,7 @@ function createCommandsForIos(options) {
261
229
 
262
230
 
263
231
  function cleanBuildFolder(options) {
264
- const platformBuildFolder = `${buildFolder}/${options.ota ? 'ota' : options.platform}`;
232
+ const platformBuildFolder = `${buildFolder}/${options.platform}`;
265
233
  if (fs.existsSync(buildFolder)) {
266
234
  fs.rmSync(buildFolder, {recursive: true});
267
235
  }
@@ -375,6 +343,20 @@ function runCliCommand(command, callback, path) {
375
343
  }
376
344
 
377
345
 
346
+ function runCliCommandSilent(command, callback, path) {
347
+ callback = callback || function() {};
348
+ const ls = spawn(command, [], {shell: true, env: { ...process.env, FORCE_COLOR: true }, cwd: path || ''});
349
+ const output = [];
350
+ ls.stdout.on('data', (data) => {
351
+ output.push(data);
352
+ });
353
+
354
+ ls.on('close', (code) => {
355
+ callback(code, output.toString());
356
+ });
357
+ }
358
+
359
+
378
360
  function runCliCommandList(list, path, callback) {
379
361
  if (list.length === 0) {
380
362
  return;
@@ -389,45 +371,238 @@ function runCliCommandList(list, path, callback) {
389
371
  }
390
372
 
391
373
 
374
+ function applyReleaseBuildChecks(versions, options, callback) {
375
+ const debugMode = (options.environment.indexOf('Debug') >= 0);
376
+ if (debugMode) {
377
+ callback()
378
+
379
+ return;
380
+ }
381
+
382
+ console.log('----------------------------------------------------------------------------------------------------------------------');
383
+ if (options.force) {
384
+ console.log('\x1b[31mWARNING: All checks before release build are skipped! Never use "--force" when uploading build to store! \x1b[0m');
385
+ console.log('----------------------------------------------------------------------------------------------------------------------');
386
+ callback();
387
+
388
+ return;
389
+ }
390
+
391
+ console.log('RUNNING CHECKS BEFORE PRODUCTION BUILD...');
392
+ let checkFailed = false;
393
+
394
+ console.log('');
395
+ checkForUncommitedFiles((checkForUncommitedFilesStatus) => {
396
+ checkFailed = (checkFailed || checkForUncommitedFilesStatus);
397
+
398
+ console.log('');
399
+ checkRemoteBranch((checkRemoteBranchStatus) => {
400
+ checkFailed = (checkFailed || checkRemoteBranchStatus);
401
+
402
+ console.log('');
403
+ checkEnvironmentToBranchScheme(versions, options, (checkEnvironmentToBranchSchemeStatus) => {
404
+ checkFailed = (checkFailed || checkEnvironmentToBranchSchemeStatus);
405
+
406
+ console.log('');
407
+ checkVersionInCommit(versions, (checkVersionInCommitStatus) => {
408
+ checkFailed = (checkFailed || checkVersionInCommitStatus);
409
+
410
+ console.log('');
411
+ checkLintErrors((checkLintErrorsStatus) => {
412
+ checkFailed = (checkFailed || checkLintErrorsStatus);
413
+
414
+ console.log('');
415
+ console.log('END "RUNNING CHECKS BEFORE PRODUCTION BUILD..."');
416
+ console.log('----------------------------------------------------------------------------------------------------------------------');
417
+ if (checkFailed) {
418
+ throw new Error('Some prebuild checks failed, see logs to find out which ones.');
419
+ }
420
+ callback();
421
+ });
422
+ });
423
+ });
424
+ });
425
+ });
426
+ }
427
+
428
+
429
+ function checkForUncommitedFiles(callback) {
430
+ console.log('- Check if branch is clear. No uncommited changes are allowed.');
431
+ const cliCommand = 'git status -u --porcelain';
432
+ runCliCommandSilent(cliCommand, (code, output) => {
433
+ let checkFailed = false;
434
+ if (code !== 0) {
435
+ console.log('\x1b[31m FAILED! "git status" command failed. \x1b[0m');
436
+ checkFailed = true;
437
+ } else if (output.length > 0) {
438
+ console.log('\x1b[31m FAILED! You have uncommited changes. \x1b[0m');
439
+ checkFailed = true;
440
+ } else {
441
+ console.log('\x1b[32m PASSED! \x1b[0m');
442
+ }
443
+ callback(checkFailed);
444
+ });
445
+ }
446
+
447
+
448
+ function checkRemoteBranch(callback) {
449
+ console.log('- Check if local branch is up to date with remote branch.');
450
+ const cliGetCurrentBranchName = 'git rev-parse --abbrev-ref HEAD';
451
+ runCliCommandSilent(cliGetCurrentBranchName, (code, branchName) => {
452
+ if (code !== 0) {
453
+ console.log('\x1b[31m FAILED! "git rev-parse" command failed. \x1b[0m');
454
+ callback(true);
455
+ } else {
456
+ branchName = branchName.trim();
457
+ const cliGitFetch = `git fetch origin ${branchName}`;
458
+ runCliCommandSilent(cliGitFetch, (code) => {
459
+ if (code !== 0) {
460
+ console.log('\x1b[31m FAILED! "git fetch" command failed. \x1b[0m');
461
+ callback(true);
462
+ } else {
463
+ const cliGitDiff = `git diff origin/${branchName} ${branchName} --name-only`;
464
+ runCliCommandSilent(cliGitDiff, (code, diffData) => {
465
+ if (code !== 0) {
466
+ console.log('\x1b[31m FAILED! "git diff" command failed. \x1b[0m');
467
+ callback(true);
468
+ } else if (diffData.length > 0) {
469
+ console.log('\x1b[31m FAILED! Local branch is not up to date with remote branch. \x1b[0m');
470
+ callback(true);
471
+ } else {
472
+ console.log('\x1b[32m PASSED! \x1b[0m');
473
+ callback(false);
474
+ }
475
+ });
476
+ }
477
+ });
478
+ }
479
+ });
480
+ }
481
+
482
+
483
+ function checkEnvironmentToBranchScheme(versions, options, callback) {
484
+ console.log('- Check if build for selected environment can be made from current branch.');
485
+
486
+ const cliGetCurrentBranchName = 'git rev-parse --abbrev-ref HEAD';
487
+ runCliCommandSilent(cliGetCurrentBranchName, (code, branchName) => {
488
+ if (code !== 0) {
489
+ console.log('\x1b[31m FAILED! "git rev-parse" command failed. \x1b[0m');
490
+ callback(true);
491
+ } else {
492
+ branchName = branchName.trim();
493
+ if (options.environment === 'getik') {
494
+ if (branchName === 'develop') {
495
+ console.log('\x1b[32m PASSED! \x1b[0m');
496
+ callback(false);
497
+ } else {
498
+ console.log('\x1b[31m FAILED! You can build for "getik" environment only from "develop". \x1b[0m');
499
+ callback(true);
500
+ }
501
+ } else if (options.environment === 'qa') {
502
+ const requiredBranchName = `release/${versions.versionName.substring(0, versions.versionName.length - 2)}x`;
503
+ if (branchName === requiredBranchName) {
504
+ console.log('\x1b[32m PASSED! \x1b[0m');
505
+ callback(false);
506
+ } else {
507
+ console.log(`\x1b[31m FAILED! You can build for "qa" environment only from "${requiredBranchName}". \x1b[0m`);
508
+ callback(true);
509
+ }
510
+ } else if (options.environment === 'preprod' || options.environment === 'prod') {
511
+ if (branchName === 'master') {
512
+ console.log('\x1b[32m PASSED! \x1b[0m');
513
+ callback(false);
514
+ } else {
515
+ console.log(`\x1b[31m FAILED! You can build for "${options.environment}" environment only from "master". \x1b[0m`);
516
+ callback(true);
517
+ }
518
+ } else {
519
+ console.log('\x1b[32m PASSED! \x1b[0m');
520
+ callback(false);
521
+ }
522
+ }
523
+ });
524
+ }
525
+
526
+
527
+ function checkVersionInCommit(versions, callback) {
528
+ console.log('- Check if latest commit is a version update commit and it is the same as in "package.json".');
529
+ const cliCommand = 'git log -1 --pretty=%B';
530
+ runCliCommandSilent(cliCommand, (code, commitMessage) => {
531
+ commitMessage = commitMessage.trim();
532
+ let checkFailed = false;
533
+ if (code !== 0) {
534
+ console.log('\x1b[31m FAILED! "git log" command failed. \x1b[0m');
535
+ checkFailed = true;
536
+ } else {
537
+ const expectedMessage = `APP VERSION UPDATE: versionName: ${versions.versionName}`;
538
+ if (commitMessage === expectedMessage) {
539
+ console.log('\x1b[32m PASSED! \x1b[0m');
540
+ checkFailed = false;
541
+ } else {
542
+ console.log('\x1b[31m FAILED! Version in "package.json" is not the same as in commit message. \x1b[0m');
543
+ checkFailed = true;
544
+ }
545
+ }
546
+ callback(checkFailed);
547
+ });
548
+ }
549
+
550
+
551
+ function checkLintErrors(callback) {
552
+ console.log('- Check for lint errors.');
553
+ const P = ['\\', '|', '/', '-'];
554
+ let x = 0;
555
+ const ref = setInterval(() => {
556
+ process.stdout.write('\r' + P[x++]);
557
+ x &= 3;
558
+ }, 250);
559
+ const cliCommand = 'npm run lint';
560
+ runCliCommandSilent(cliCommand, (code, output) => {
561
+ clearInterval(ref);
562
+ process.stdout.write('\r');
563
+ let checkFailed = false;
564
+ if (code !== 0) {
565
+ console.log('\x1b[31m FAILED! There are "lint" errors. \x1b[0m');
566
+ checkFailed = true;
567
+ } else {
568
+ console.log('\x1b[32m PASSED! \x1b[0m');
569
+ }
570
+ callback(checkFailed);
571
+ });
572
+ }
573
+
574
+
392
575
  export const mobileBuild = () => {
393
576
  program
394
577
  .command('mobile-build')
578
+ .requiredOption('-p, --platform <type>', 'Platform: android, ios')
395
579
  .requiredOption('-e, --environment <type>', 'Environment: getik, getikDebug')
396
- .option('-p, --platform <type>', 'Platform: android, ios')
397
580
  .option('--syncOnly', 'Apply capacitor sync only, without platform build')
398
- .option('--ota', 'Only build files for OTA update, not full application build')
399
581
  .option('--aab', 'Android platform only, final build as AAB')
400
582
  .option('--upload', 'iOS platform only, upload directly to AppStore')
401
- .action(async (options) => {
583
+ .option('--force', 'Skip all checks for builds of type release')
584
+ .action((options) => {
402
585
  console.log('INPUT OPTIONS: ', options);
403
- const versions = readVersionsFromPackageJson(options);
404
- makeVersionsFileInTypescript(versions);
405
-
406
- if (options.ota) {
407
- const otaCliCommands = createCommandsForOTA(options, versions);
408
- runCliCommandList(otaCliCommands, undefined, () => {
409
- console.log('ZIP file for OTA update created, check folder: ./build/ota/');
410
- });
411
-
412
- return;
413
- }
414
-
415
586
  const cliCommands = createCliCommands(options);
416
-
417
- if (options.platform === 'android') {
418
- checkKeystorePropertiesFile();
419
- applyVersionForAndroid(versions);
420
- } else if (options.platform === 'ios') {
421
- checkSensitiveDataJsonFile();
422
- applyVersionForIos(versions);
423
- }
424
- await applyPatchersForExternalNpmPackages();
425
- runCliCommand(cliCommands.buildAngular, function () {
426
- runCliCommand(cliCommands.capacitorSync(), function () {
427
- runCliCommandList(cliCommands.buildApp, options.platform, () => {
428
- setTimeout(() => {
429
- copyFinalBuildToRootFolder(options);
430
- }, 100);
587
+ const versions = readVersionsFromPackageJson();
588
+
589
+ applyReleaseBuildChecks(versions, options, () => {
590
+ if (options.platform === 'android') {
591
+ checkKeystorePropertiesFile();
592
+ applyVersionForAndroid(versions);
593
+ } else if (options.platform === 'ios') {
594
+ checkSensitiveDataJsonFile();
595
+ applyVersionForIos(versions);
596
+ }
597
+ applyPatchersForExternalNpmPackages().then(() => {
598
+ runCliCommand(cliCommands.buildAngular, function () {
599
+ runCliCommand(cliCommands.capacitorSync(), function () {
600
+ runCliCommandList(cliCommands.buildApp, options.platform, () => {
601
+ setTimeout(() => {
602
+ copyFinalBuildToRootFolder(options);
603
+ }, 100);
604
+ });
605
+ });
431
606
  });
432
607
  });
433
608
  });
@@ -1,141 +0,0 @@
1
- import { program } from 'commander';
2
- import { spawn } from 'child_process';
3
- import fs from 'fs';
4
- import path from 'path';
5
-
6
-
7
- function incrementMobileVersions(type, environment) {
8
- const packageJsonBuffer = fs.readFileSync(path.join(process.cwd(), 'package.json'));
9
- const packageJson = JSON.parse(packageJsonBuffer);
10
-
11
- const allPackageJsonProperties = Object.keys(packageJson);
12
- const otaVersionProperties = [];
13
- if (environment) {
14
- const env = (environment.charAt(0).toUpperCase() + environment.slice(1));
15
- const versionPropertyName = `otaVersion${env.split('Debug')[0]}`;
16
- const found = allPackageJsonProperties.find((property) => {
17
- return (property === versionPropertyName);
18
- });
19
- if (found) {
20
- otaVersionProperties.push(versionPropertyName);
21
- }
22
- } else {
23
- const filtered = allPackageJsonProperties.filter((property) => {
24
- const name = 'otaVersion';
25
-
26
- return (property.indexOf(name) === 0) && (property.length > name.length);
27
- });
28
- otaVersionProperties.push(...filtered);
29
-
30
- }
31
-
32
- if (otaVersionProperties.length === 0) {
33
- console.log(`WARNING: OTA version${environment ? 'for ' + environment : ''} not found in package.json. If project doesn't have OTA update ignore this warning. If project has OTA update feature, then make sure every environment has specific property with version defined in package.json`);
34
- } else {
35
- otaVersionProperties.forEach((propertyName) => {
36
- packageJson[propertyName]++;
37
- });
38
- }
39
-
40
- if (type === 'ota') {
41
- if (otaVersionProperties.length === 0) {
42
- console.log(`OTA version not incremented, no property found in package.json.`);
43
- }
44
- fs.writeFileSync(path.join(process.cwd(), 'package.json'), JSON.stringify(packageJson, null, 2));
45
- createCommit(packageJson, otaVersionProperties);
46
-
47
- return;
48
- }
49
-
50
- const splitVersion = packageJson.version.split('.');
51
- let x = parseInt(splitVersion[0], 10);
52
- let y = parseInt(splitVersion[1], 10);
53
- let z = parseInt(splitVersion[2], 10);
54
-
55
- if (type === 'major') {
56
- x++;
57
- y = 0;
58
- z = 0;
59
- } else if (type === 'minor') {
60
- y++;
61
- z = 0;
62
- } else if (type === 'patch') {
63
- z++;
64
- } else {
65
- console.log('Invalid version increment type. Options available: major, minor, patch, ota');
66
- }
67
-
68
- packageJson.version = `${x}.${y}.${z}`;
69
-
70
- fs.writeFileSync(path.join(process.cwd(), 'package.json'), JSON.stringify(packageJson, null, 2));
71
-
72
- const packageLockJsonBuffer = fs.readFileSync(path.join(process.cwd(), 'package-lock.json'));
73
- const packageLockJson = JSON.parse(packageLockJsonBuffer);
74
- packageLockJson.version = `${x}.${y}.${z}`;
75
- packageLockJson.packages[''].version = `${x}.${y}.${z}`;
76
- fs.writeFileSync(path.join(process.cwd(), 'package-lock.json'), JSON.stringify(packageLockJson, null, 2));
77
-
78
- createCommit(packageJson, otaVersionProperties);
79
- }
80
-
81
-
82
- function createCommit(packageJsonRef, otaVersionProperties) {
83
- let otaVersionMessage = '';
84
- otaVersionProperties.forEach((property) => {
85
- otaVersionMessage += `; ${property}: ${packageJsonRef[property]}`;
86
- });
87
- const message = `APP VERSION UPDATE: versionName: ${packageJsonRef.version}${otaVersionMessage}.`;
88
-
89
- const cliCommand = `git commit -a -m "${message}"`;
90
- const ls = spawn(cliCommand, [], {shell: true, env: { ...process.env, FORCE_COLOR: true }, cwd: ''});
91
-
92
- ls.on('close', (code) => {
93
- if (code !== 0) {
94
- console.log('\x1b[31m');
95
- throw new Error(`Command FAILED: ${cliCommand}`);
96
- } else {
97
- console.log(`A new commit was added with message "${message}"`);
98
- }
99
- });
100
- }
101
-
102
-
103
- function gitCheckIfCleanRepo(callback) {
104
- const cliCommand = 'git status --porcelain';
105
- const ls = spawn(cliCommand, [], {shell: true, env: { ...process.env, FORCE_COLOR: true }, cwd: ''});
106
- const output = [];
107
- ls.stdout.on('data', (data) => {
108
- output.push(data);
109
- });
110
-
111
- ls.on('close', (code) => {
112
- if (code !== 0) {
113
- console.log('\x1b[31m');
114
- throw new Error(`Command FAILED: ${cliCommand}`);
115
- } else if (output.length > 0) {
116
- console.log('\x1b[31m');
117
- throw new Error('You have uncommited changes. Commit or clear changes before running this command.');
118
- } else {
119
- callback();
120
- }
121
- });
122
- }
123
-
124
-
125
- export const incrementVersion = () => {
126
- program
127
- .command('increment-version')
128
- .requiredOption('-t, --type <type>', 'Type: major - 3.x.x -> 4.x.x; minor - 3.1.x -> 3.2.x; patch - 3.1.0 -> 3.1.1; ota - this is done by default in other types.')
129
- .requiredOption('-p, --project <type>', 'Project: mobile')
130
- .option('-e, --environment <type>', 'Environment: getik, getikDebug')
131
- .action((options) => {
132
- console.log('INPUT OPTIONS: ', options);
133
- gitCheckIfCleanRepo(function() {
134
- if (options.project === 'mobile') {
135
- incrementMobileVersions(options.type, options.environment);
136
- } else {
137
- console.log('Other project types are not supported yet, now only "mobile" is available.');
138
- }
139
- });
140
- });
141
- };