@adinsure-ops/ops-cli 4.0.0-rc6

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.
Files changed (71) hide show
  1. package/CHANGELOGS.md +55 -0
  2. package/LICENSE +1 -0
  3. package/README.md +576 -0
  4. package/bin/run +5 -0
  5. package/bin/run.cmd +3 -0
  6. package/lib/command.base.d.ts +17 -0
  7. package/lib/command.base.jira.d.ts +11 -0
  8. package/lib/command.base.jira.js +37 -0
  9. package/lib/command.base.js +73 -0
  10. package/lib/commands/doctor.d.ts +54 -0
  11. package/lib/commands/doctor.js +311 -0
  12. package/lib/commands/download/client.d.ts +18 -0
  13. package/lib/commands/download/client.js +72 -0
  14. package/lib/commands/download/identity-server.d.ts +18 -0
  15. package/lib/commands/download/identity-server.js +72 -0
  16. package/lib/commands/download/platform.d.ts +18 -0
  17. package/lib/commands/download/platform.js +72 -0
  18. package/lib/commands/download/scheduler.d.ts +18 -0
  19. package/lib/commands/download/scheduler.js +72 -0
  20. package/lib/commands/download/server.d.ts +18 -0
  21. package/lib/commands/download/server.js +72 -0
  22. package/lib/commands/download/studio.d.ts +20 -0
  23. package/lib/commands/download/studio.js +89 -0
  24. package/lib/commands/gitlab/next-nightly-tag.d.ts +30 -0
  25. package/lib/commands/gitlab/next-nightly-tag.js +171 -0
  26. package/lib/commands/jira/issue.d.ts +17 -0
  27. package/lib/commands/jira/issue.js +31 -0
  28. package/lib/commands/jira/labels.d.ts +22 -0
  29. package/lib/commands/jira/labels.js +70 -0
  30. package/lib/commands/log/add.d.ts +17 -0
  31. package/lib/commands/log/add.js +107 -0
  32. package/lib/commands/log/generate.d.ts +22 -0
  33. package/lib/commands/log/generate.js +155 -0
  34. package/lib/commands/log/validate.d.ts +11 -0
  35. package/lib/commands/log/validate.js +58 -0
  36. package/lib/commands/login.d.ts +23 -0
  37. package/lib/commands/login.js +144 -0
  38. package/lib/commands/npm/check.publish.d.ts +17 -0
  39. package/lib/commands/npm/check.publish.js +78 -0
  40. package/lib/commands/npm/publish.d.ts +23 -0
  41. package/lib/commands/npm/publish.js +163 -0
  42. package/lib/commands/prepare-content.d.ts +29 -0
  43. package/lib/commands/prepare-content.js +386 -0
  44. package/lib/commands/sql.d.ts +24 -0
  45. package/lib/commands/sql.js +147 -0
  46. package/lib/commands/translate.d.ts +37 -0
  47. package/lib/commands/translate.js +149 -0
  48. package/lib/commands/version.d.ts +48 -0
  49. package/lib/commands/version.js +267 -0
  50. package/lib/config.d.ts +7 -0
  51. package/lib/config.js +9 -0
  52. package/lib/hooks/init/version-override.d.ts +2 -0
  53. package/lib/hooks/init/version-override.js +15 -0
  54. package/lib/index.d.ts +1 -0
  55. package/lib/index.js +4 -0
  56. package/lib/lib/command.d.ts +9 -0
  57. package/lib/lib/command.js +71 -0
  58. package/lib/lib/npm.d.ts +15 -0
  59. package/lib/lib/npm.js +79 -0
  60. package/lib/lib/npmrc.d.ts +17 -0
  61. package/lib/lib/npmrc.js +44 -0
  62. package/lib/security/cache.d.ts +7 -0
  63. package/lib/security/cache.js +33 -0
  64. package/lib/security/context.d.ts +58 -0
  65. package/lib/security/context.js +224 -0
  66. package/lib/types/changelog.types.d.ts +6 -0
  67. package/lib/types/changelog.types.js +2 -0
  68. package/lib/types/npm.types.d.ts +34 -0
  69. package/lib/types/npm.types.js +2 -0
  70. package/oclif.manifest.json +1 -0
  71. package/package.json +118 -0
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const command_1 = require("@oclif/command");
4
+ const chalk_1 = require("chalk");
5
+ const cli_ux_1 = require("cli-ux");
6
+ const command_base_1 = require("../../command.base");
7
+ const npm_1 = require("../../lib/npm");
8
+ class NpmCheckPublish extends command_base_1.default {
9
+ async checkPackagesExists(packages, allPackages, version) {
10
+ let errorCount = 0;
11
+ for (const pkg of packages) {
12
+ cli_ux_1.default.action.start(`${pkg.name}@${version}`, undefined, { stdout: true });
13
+ let matchedPackage = allPackages.value.find(azurePackage => azurePackage.name === pkg.name);
14
+ if (!matchedPackage) {
15
+ cli_ux_1.default.action.stop(`${chalk_1.default.red('package missing')}`);
16
+ errorCount++;
17
+ continue;
18
+ }
19
+ let matchVersion = matchedPackage.versions.find(azurePackageVersion => azurePackageVersion.version === version);
20
+ if (!matchVersion) {
21
+ cli_ux_1.default.action.stop(`${chalk_1.default.red('version missing')}`);
22
+ errorCount++;
23
+ continue;
24
+ }
25
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('exists')}`);
26
+ }
27
+ if (errorCount > 0) {
28
+ throw new Error(`${errorCount} packages or versions missing!`);
29
+ }
30
+ }
31
+ async run() {
32
+ try {
33
+ const { flags } = this.parse(NpmCheckPublish);
34
+ let npmContext = new npm_1.default();
35
+ cli_ux_1.default.action.start('Parsing packages to check', undefined, { stdout: true });
36
+ const packages = await npmContext.packageList(flags.package, flags.exclude, this);
37
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('done')}`);
38
+ cli_ux_1.default.action.start('Getting list of available packages', undefined, { stdout: true });
39
+ const allPackages = JSON.parse(await npmContext.getAllNpmPackages(flags.pat));
40
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('done')}`);
41
+ await this.checkPackagesExists(packages, allPackages, flags.version);
42
+ cli_ux_1.default.action.stop('success');
43
+ }
44
+ catch (err) {
45
+ cli_ux_1.default.action.stop('error');
46
+ this.error(`${err.message}`);
47
+ }
48
+ }
49
+ }
50
+ exports.default = NpmCheckPublish;
51
+ NpmCheckPublish.aliases = ['npm:check-publish'];
52
+ NpmCheckPublish.description = 'check if npm packages was published';
53
+ NpmCheckPublish.usage = 'npm:check-publish [options]';
54
+ NpmCheckPublish.examples = [
55
+ '$ ops npm:check-publish -v 6.0.1',
56
+ '$ ops npm:check-publish -p @adinsure/* -v 6.0.0',
57
+ '$ ops npm:check-publish -p @adinsure/* -x @adisure/demo -v 6.0.0'
58
+ ];
59
+ NpmCheckPublish.flags = {
60
+ package: command_1.flags.string({
61
+ char: 'p',
62
+ description: 'package name filter you want to check',
63
+ multiple: true
64
+ }),
65
+ exclude: command_1.flags.string({
66
+ char: 'x',
67
+ description: 'exclude packages from filter',
68
+ multiple: true
69
+ }),
70
+ version: command_1.flags.string({
71
+ char: 'v',
72
+ description: 'version we want to check if published',
73
+ required: true
74
+ }),
75
+ pat: command_1.flags.string({
76
+ description: 'PAT token or AZURE_DEVOPS_EXT_PAT environment variable'
77
+ }),
78
+ };
@@ -0,0 +1,23 @@
1
+ import { flags } from '@oclif/command';
2
+ import CommandBase from '../../command.base';
3
+ import { AzurePackageArray, NpmPackage } from '../../types/npm.types';
4
+ export default class NpmPublish extends CommandBase {
5
+ static aliases: string[];
6
+ static description: string;
7
+ static usage: string;
8
+ static examples: string[];
9
+ static flags: {
10
+ package: flags.IOptionFlag<string[]>;
11
+ exclude: flags.IOptionFlag<string[]>;
12
+ version: flags.IOptionFlag<string>;
13
+ pat: flags.IOptionFlag<string | undefined>;
14
+ };
15
+ private cp;
16
+ publishPackage(pkg: NpmPackage, cmd?: string[]): Promise<{
17
+ data: string;
18
+ error: string;
19
+ }>;
20
+ checkPackageCanPublish(pkg: NpmPackage, allPackages: AzurePackageArray, version: string): Promise<boolean>;
21
+ publishPackages(packages: NpmPackage[], allPackages: AzurePackageArray, version: string): Promise<void>;
22
+ run(): Promise<void>;
23
+ }
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const command_1 = require("@oclif/command");
5
+ const chalk_1 = require("chalk");
6
+ const child_process_1 = require("child_process");
7
+ const cli_ux_1 = require("cli-ux");
8
+ const command_base_1 = require("../../command.base");
9
+ const npm_1 = require("../../lib/npm");
10
+ class NpmPublish extends command_base_1.default {
11
+ async publishPackage(pkg, cmd = ['yarn', 'publish']) {
12
+ var e_1, _a, e_2, _b;
13
+ let sh;
14
+ let args;
15
+ // cross platform compatibility
16
+ if (process.platform === 'win32') {
17
+ sh = 'cmd';
18
+ args = ['/c'].concat(cmd);
19
+ }
20
+ else {
21
+ [sh, ...args] = cmd;
22
+ }
23
+ try {
24
+ this.cp = child_process_1.spawn(sh, args, {
25
+ cwd: pkg.path,
26
+ env: Object.assign(Object.assign({}, process.env), process.stdout.isTTY ? { FORCE_COLOR: process.env.FORCE_COLOR || '1' } : {}),
27
+ stdio: 'pipe'
28
+ });
29
+ let data = '';
30
+ try {
31
+ for (var _c = tslib_1.__asyncValues(this.cp.stdout), _d; _d = await _c.next(), !_d.done;) {
32
+ const chunk = _d.value;
33
+ data += chunk;
34
+ }
35
+ }
36
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
37
+ finally {
38
+ try {
39
+ if (_d && !_d.done && (_a = _c.return)) await _a.call(_c);
40
+ }
41
+ finally { if (e_1) throw e_1.error; }
42
+ }
43
+ let error = '';
44
+ try {
45
+ for (var _e = tslib_1.__asyncValues(this.cp.stderr), _f; _f = await _e.next(), !_f.done;) {
46
+ const chunk = _f.value;
47
+ error += chunk;
48
+ }
49
+ }
50
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
51
+ finally {
52
+ try {
53
+ if (_f && !_f.done && (_b = _e.return)) await _b.call(_e);
54
+ }
55
+ finally { if (e_2) throw e_2.error; }
56
+ }
57
+ const exitCode = await new Promise((resolve, _reject) => {
58
+ this.cp.on('close', resolve);
59
+ });
60
+ if (exitCode) {
61
+ throw new Error(`subprocess error exit ${exitCode}, ${error}`);
62
+ }
63
+ return { data, error };
64
+ }
65
+ catch (err) {
66
+ throw new Error(err.message);
67
+ }
68
+ }
69
+ async checkPackageCanPublish(pkg, allPackages, version) {
70
+ this.log('');
71
+ cli_ux_1.default.action.start(`${pkg.name}@${pkg.version}`, undefined, { stdout: true });
72
+ let matchedPackage = allPackages.value.find(azurePackage => azurePackage.name === pkg.name);
73
+ if (pkg.version !== version) {
74
+ this.warn(`${pkg.name}@${pkg.version} doesn't match desired publish version!`);
75
+ cli_ux_1.default.action.stop(chalk_1.default.red(`version doesn't match version ${version}`));
76
+ throw new Error(`Version in package.json doesn't match desired published version`);
77
+ }
78
+ if (!matchedPackage) {
79
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('new package')}`);
80
+ cli_ux_1.default.action.start(`publish new package ${pkg.name}@${pkg.version} from ${pkg.jsonPath}`, undefined, { stdout: true });
81
+ await this.publishPackage(pkg);
82
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('done')}`);
83
+ return true;
84
+ }
85
+ let matchVersion = matchedPackage.versions.find(azurePackageVersion => azurePackageVersion.version === pkg.version);
86
+ if (!matchVersion) {
87
+ cli_ux_1.default.action.stop(`${chalk_1.default.yellow('version missing')}`);
88
+ cli_ux_1.default.action.start(`publish new version ${pkg.name}@${pkg.version} from ${pkg.jsonPath}`, undefined, { stdout: true });
89
+ await this.publishPackage(pkg);
90
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('done')}`);
91
+ return true;
92
+ }
93
+ this.warn(`${pkg.name}@${pkg.version} already exists`);
94
+ cli_ux_1.default.action.stop(`${chalk_1.default.blue('skipping')}`);
95
+ return false;
96
+ }
97
+ async publishPackages(packages, allPackages, version) {
98
+ let errorCount = 0;
99
+ this.log(`publishing ${packages.length} packages:`);
100
+ this.log(packages.map(pkg => pkg.name).toString());
101
+ for (const pkg of packages) {
102
+ try {
103
+ await this.checkPackageCanPublish(pkg, allPackages, version);
104
+ }
105
+ catch (_a) {
106
+ errorCount++;
107
+ continue;
108
+ }
109
+ }
110
+ if (errorCount > 0) {
111
+ throw new Error(`${errorCount} with Errors!`);
112
+ }
113
+ }
114
+ async run() {
115
+ try {
116
+ const { flags } = this.parse(NpmPublish);
117
+ let npmContext = new npm_1.default();
118
+ cli_ux_1.default.action.start('Parsing packages to check', undefined, { stdout: true });
119
+ const packages = await npmContext.packageList(flags.package, flags.exclude, this);
120
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('done')}`);
121
+ cli_ux_1.default.action.start('Getting list of published packages', undefined, { stdout: true });
122
+ const allPackages = JSON.parse(await npmContext.getAllNpmPackages(flags.pat));
123
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('done')}`);
124
+ await this.publishPackages(packages, allPackages, flags.version);
125
+ cli_ux_1.default.action.stop('success');
126
+ }
127
+ catch (err) {
128
+ cli_ux_1.default.action.stop('error');
129
+ this.error(`${err.message}`);
130
+ }
131
+ }
132
+ }
133
+ exports.default = NpmPublish;
134
+ NpmPublish.aliases = ['npm:publish'];
135
+ NpmPublish.description = 'Publish npm packages';
136
+ NpmPublish.usage = 'npm:publish [options]';
137
+ NpmPublish.examples = [
138
+ '$ ops npm:publish -v 15.0.0',
139
+ '$ ops npm:publish -v 15.0.0',
140
+ '$ ops npm:publish -p @adinsure-tooling/* -v 15.0.0',
141
+ '$ ops npm:publish -p @adinsure-tooling/* -x @adisure-tooling/studio-services -v 6.0.0'
142
+ ];
143
+ NpmPublish.flags = {
144
+ package: command_1.flags.string({
145
+ char: 'p',
146
+ description: 'package name filter you want to check',
147
+ multiple: true
148
+ }),
149
+ exclude: command_1.flags.string({
150
+ char: 'x',
151
+ description: 'exclude packages from filter',
152
+ multiple: true
153
+ }),
154
+ version: command_1.flags.string({
155
+ char: 'v',
156
+ description: 'version we want to check if published',
157
+ required: true
158
+ }),
159
+ pat: command_1.flags.string({
160
+ description: 'PAT token or AZURE_DEVOPS_EXT_PAT environment variable',
161
+ env: 'AZURE_DEVOPS_EXT_PAT'
162
+ }),
163
+ };
@@ -0,0 +1,29 @@
1
+ import { flags } from '@oclif/command';
2
+ import CommandBase from '../command.base';
3
+ interface Transformation {
4
+ name: string;
5
+ srcPath: string;
6
+ transform(): void;
7
+ }
8
+ interface DotfileLine {
9
+ prefix: string;
10
+ source: string;
11
+ transformData: string;
12
+ }
13
+ export default class PrepareContent extends CommandBase {
14
+ static readonly dotfile = ".opsprepare";
15
+ static description: string;
16
+ static usage: string;
17
+ static examples: string[];
18
+ static flags: {
19
+ destination: flags.IOptionFlag<string>;
20
+ source: flags.IOptionFlag<string>;
21
+ };
22
+ parseDotfileLine(line: string, sourceDirectory: string): Promise<DotfileLine>;
23
+ readDotfile(sourceDirectory: string): Promise<DotfileLine[]>;
24
+ getTransformation(lineData: DotfileLine, baseSourcedir: string, baseDestinationDir: string): Promise<Transformation>;
25
+ prepareTransformations(linesData: DotfileLine[], baseSourceDir: string, baseDestinationDir: string): Promise<Transformation[]>;
26
+ runTransformations(transformations: Transformation[]): Promise<void>;
27
+ run(): Promise<void>;
28
+ }
29
+ export {};
@@ -0,0 +1,386 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const command_1 = require("@oclif/command");
4
+ const chalk_1 = require("chalk");
5
+ const cli_ux_1 = require("cli-ux");
6
+ const fs = require("fs-extra");
7
+ const path = require("path");
8
+ const command_base_1 = require("../command.base");
9
+ class CopyTransformation {
10
+ constructor(srcPath, dstPath) {
11
+ this.name = this.constructor.name;
12
+ this.srcPath = srcPath;
13
+ this.dstPath = dstPath;
14
+ }
15
+ transform() {
16
+ try {
17
+ fs.accessSync(this.srcPath, fs.constants.R_OK);
18
+ }
19
+ catch (err) {
20
+ if (err.code === 'ENOENT') {
21
+ throw new Error(`${this.name}: source file does not exist <${this.srcPath}>`);
22
+ }
23
+ else {
24
+ throw new Error(`${this.name}: ${err} <${this.srcPath}>`);
25
+ }
26
+ }
27
+ cli_ux_1.default.log(`Copying from ${this.srcPath} to ${this.dstPath}`);
28
+ try {
29
+ fs.copySync(this.srcPath, this.dstPath, { overwrite: true });
30
+ }
31
+ catch (err) {
32
+ throw new Error(`${this.name}: ${err} <${this.srcPath}>`);
33
+ }
34
+ }
35
+ }
36
+ class JavascriptTransformation {
37
+ constructor(srcPath, dstPath, javascriptFile, functionName) {
38
+ this.name = this.constructor.name;
39
+ this.srcPath = srcPath;
40
+ this.dstPath = dstPath;
41
+ this.jsFile = path.resolve(javascriptFile);
42
+ this.functionName = functionName;
43
+ }
44
+ importTransformationModule() {
45
+ try {
46
+ return require(this.jsFile);
47
+ }
48
+ catch (err) {
49
+ if (err.code === 'MODULE_NOT_FOUND') {
50
+ throw new Error(`${this.name}: module file ${this.jsFile} not found <${this.srcPath}>`);
51
+ }
52
+ else if (err instanceof SyntaxError) {
53
+ throw new Error(`${this.name}: ${err} in \'${this.jsFile}\' <${this.srcPath}>`);
54
+ }
55
+ throw new Error(`${this.name}: ${err} <${this.srcPath}>`);
56
+ }
57
+ }
58
+ executeTransformationFunction(transformationModule) {
59
+ try {
60
+ let result = transformationModule[this.functionName](this.srcPath);
61
+ if (typeof (result) !== 'string') {
62
+ throw new Error(`${this.name}: transformation functions must return string, ${this.functionName} returned ${typeof (result)} <${this.srcPath}>`);
63
+ }
64
+ return result;
65
+ }
66
+ catch (err) {
67
+ if (err instanceof TypeError) {
68
+ throw new Error(`${this.name}: invalid function \'${this.functionName}\' in ${this.jsFile} <${this.srcPath}>`);
69
+ }
70
+ /*
71
+ Rethrow anything errors that were thrown in the above try block
72
+ */
73
+ if (err.message && err.message.search(`${this.name}`.length > 0)) {
74
+ throw err;
75
+ }
76
+ throw new Error(`${this.name}: ${err} <${this.srcPath}>`);
77
+ }
78
+ }
79
+ transform() {
80
+ // Check if source exists, if not, issue a warning
81
+ try {
82
+ fs.accessSync(this.srcPath);
83
+ }
84
+ catch (err) {
85
+ if (err.code === 'ENOENT') {
86
+ let errMsg = `${this.name}: source does not exist, relying on transformation to find proper source file <${this.srcPath}>`;
87
+ cli_ux_1.default.log(`${chalk_1.default.yellow(errMsg)}`);
88
+ }
89
+ else {
90
+ throw new Error(`${this.name}: ${err} <${this.srcPath}>`);
91
+ }
92
+ }
93
+ cli_ux_1.default.log(`Transforming from ${this.srcPath} to ${this.dstPath} using ${this.jsFile} function ${this.functionName}`);
94
+ // Import transformation module
95
+ let transModule = this.importTransformationModule();
96
+ // Execute transformation function
97
+ let transResult = this.executeTransformationFunction(transModule);
98
+ // Write output to destination file
99
+ try {
100
+ fs.outputFileSync(this.dstPath, transResult, { encoding: 'utf-8', mode: 0o644, flag: 'w' });
101
+ }
102
+ catch (err) {
103
+ throw new Error(`${this.name}: ${err} <${this.srcPath}>`);
104
+ }
105
+ }
106
+ }
107
+ class RemovalTransformation {
108
+ constructor(srcPath) {
109
+ this.name = this.constructor.name;
110
+ this.srcPath = srcPath;
111
+ }
112
+ transform() {
113
+ try {
114
+ fs.accessSync(this.srcPath, fs.constants.W_OK);
115
+ cli_ux_1.default.log(`Removing ${this.srcPath}.`);
116
+ fs.removeSync(this.srcPath);
117
+ }
118
+ catch (err) {
119
+ if (err.code === 'ENOENT') {
120
+ let errMsg = `${this.name}: target does not exist, skipping removal <${this.srcPath}>`;
121
+ cli_ux_1.default.log(`${chalk_1.default.yellow(errMsg)}`);
122
+ }
123
+ else {
124
+ throw new Error(`${this.name}: ${err} <${this.srcPath}>`);
125
+ }
126
+ }
127
+ }
128
+ }
129
+ class PrepareContent extends command_base_1.default {
130
+ async parseDotfileLine(line, sourceDirectory) {
131
+ const re = RegExp('^([!#]{1})?(.+?)({.*?})?$');
132
+ let m = line.match(re);
133
+ let dotfileLine = {
134
+ prefix: m[1],
135
+ source: path.join(sourceDirectory, path.normalize(m[2].trim())),
136
+ transformData: m[3]
137
+ };
138
+ /*
139
+ Sanity check on source file name. Should not contain "{", ":", or "}" characters
140
+ */
141
+ const valRe = RegExp('[{:}]+');
142
+ let vm = dotfileLine.source.match(valRe);
143
+ if (vm !== null) {
144
+ throw new SyntaxError(`<${PrepareContent.dotfile}> source file name '${dotfileLine.source}' contains invalid character '${vm[0]}'`);
145
+ }
146
+ return dotfileLine;
147
+ }
148
+ async readDotfile(sourceDirectory) {
149
+ let file_content;
150
+ try {
151
+ file_content = fs.readFileSync(path.join(sourceDirectory, PrepareContent.dotfile), 'utf-8');
152
+ }
153
+ catch (err) {
154
+ if (err.code === 'ENOENT') {
155
+ let errMsg = `.opsprepare file not found in ${path.resolve(sourceDirectory)}`;
156
+ throw new Error(errMsg);
157
+ }
158
+ throw new Error(err.message);
159
+ }
160
+ let lines = file_content.split(/\r?\n/).filter(line => line.length !== 0);
161
+ const lineParse = lines.map(line => {
162
+ return this.parseDotfileLine(line.trim(), sourceDirectory);
163
+ });
164
+ const parsedLines = Promise.all(lineParse).then(lines => lines.filter(line => line.prefix !== '#'));
165
+ return parsedLines;
166
+ }
167
+ async getTransformation(lineData, baseSourcedir, baseDestinationDir) {
168
+ const targetPath = path.join(baseDestinationDir, lineData.source);
169
+ /*
170
+ Anything prefixed with ! is a removal
171
+ */
172
+ if (lineData.prefix === '!') {
173
+ return new RemovalTransformation(targetPath);
174
+ }
175
+ /*
176
+ In case transformation data is present, prepare transformations based on requested plugin.
177
+ */
178
+ if (lineData.transformData) {
179
+ const re = RegExp('^{(.+?):.*}$');
180
+ const transformType = lineData.transformData.match(re)[1];
181
+ switch (transformType) {
182
+ case 'cp': {
183
+ const rePath = RegExp('^{cp:([^:]+)}$');
184
+ const mPath = lineData.transformData.match(rePath);
185
+ if (!mPath) {
186
+ throw new SyntaxError(`<${PrepareContent.dotfile}> syntax '${lineData.transformData}' is invalid for 'cp' transformation type`);
187
+ }
188
+ const tPath = path.join(baseDestinationDir, path.dirname(lineData.source), mPath[1]);
189
+ return new CopyTransformation(lineData.source, tPath);
190
+ }
191
+ case 'js': {
192
+ /* TODO: Some sanity checking will be required after regex matching
193
+ to make sure everything was matched and is defined
194
+ */
195
+ // Parse transformation data
196
+ const reData = RegExp('^{js:(.+?):(.+)}$');
197
+ const mData = lineData.transformData.match(reData);
198
+ if (!mData) {
199
+ throw new SyntaxError(`<${PrepareContent.dotfile}> syntax '${lineData.transformData}' is invalid for 'js' transformation type`);
200
+ }
201
+ const jsFile = path.join(baseSourcedir, mData[1]);
202
+ const jsFunc = mData[2];
203
+ // File path absolute. Should it be relative to the transformation function?
204
+ const filePath = path.resolve(lineData.source);
205
+ return new JavascriptTransformation(filePath, targetPath, jsFile, jsFunc);
206
+ }
207
+ default: {
208
+ const p = lineData.prefix ? lineData.prefix : '';
209
+ const s = lineData.source;
210
+ const t = lineData.transformData ? lineData.transformData : '';
211
+ this.error(`No valid transformation can be extrapolated from ${p}${s}${t}`);
212
+ }
213
+ }
214
+ }
215
+ /*
216
+ Return default transformation
217
+ */
218
+ return new CopyTransformation(lineData.source, targetPath);
219
+ }
220
+ async prepareTransformations(linesData, baseSourceDir, baseDestinationDir) {
221
+ const transformations = linesData.map(line => {
222
+ return this.getTransformation(line, baseSourceDir, baseDestinationDir);
223
+ });
224
+ return Promise.all(transformations);
225
+ }
226
+ /*
227
+ This function divides transformations into execution groups based on their class
228
+ and runs transformations for each group
229
+ */
230
+ async runTransformations(transformations) {
231
+ let copyTransformList = [];
232
+ let modlueTransformList = [];
233
+ let excludeList = [];
234
+ // Sort transformation into two lists
235
+ transformations.forEach(t => {
236
+ if (t instanceof CopyTransformation) {
237
+ copyTransformList.push(t);
238
+ }
239
+ else if (t instanceof RemovalTransformation) {
240
+ excludeList.push(t);
241
+ }
242
+ else {
243
+ modlueTransformList.push(t);
244
+ }
245
+ });
246
+ const t = async (transformation) => {
247
+ try {
248
+ transformation.transform();
249
+ }
250
+ catch (err) {
251
+ return Promise.reject(err.message);
252
+ }
253
+ };
254
+ const doCopyTransform = copyTransformList.map(t);
255
+ const doModuleTransform = modlueTransformList.map(t);
256
+ const doExclude = excludeList.map(t);
257
+ /* Copy first, then transform and finally remove files. This should
258
+ ensure that transformations can overwrite previous copies. Removals
259
+ can still erase transformations though. If needed, we can remove
260
+ before transforming.
261
+ */
262
+ await Promise.all(doCopyTransform);
263
+ await Promise.all(doModuleTransform);
264
+ await Promise.all(doExclude);
265
+ }
266
+ /*
267
+ Validates file system on source repository by checking if files or directories exist
268
+ */
269
+ /*
270
+ async validate(arr: string[][], source: string): Promise<boolean> {
271
+ //this.log(`${chalk.blue('Validating if files and directories exist.')}`);
272
+ cli.action.start(`${chalk.blue('Validating if files and directories exist')}`, '', {stdout: true});
273
+ for (let a of arr[0]) {
274
+ let element_path = path.join(source, a);
275
+ if(!(fs.existsSync(path.join(element_path)))) {
276
+ this.log(`${chalk.red('File or directory: ' + path.join(element_path) + ' could not be found')}`);
277
+ return false;
278
+ }
279
+ }
280
+ for (let a of arr[1]) {
281
+ let element_path = path.join(source, a);
282
+ if(!(fs.existsSync(element_path))) {
283
+ this.log(`${chalk.red('File or directory: ' + element_path + ' could not be found')}`);
284
+ return false;
285
+ }
286
+ }
287
+
288
+ //this.log(`${chalk.green('Validation done.')}`);
289
+ cli.action.stop(`${chalk.green('done')}`);
290
+ return true;
291
+ }
292
+ */
293
+ /*
294
+ This function copies elements and removes excluded ones.
295
+ */
296
+ /*
297
+ async copyWorkspace(arr: string[][], dest: string, source: string): Promise<any> {
298
+ if (await this.validate(arr, source)) {
299
+ cli.action.start(`${chalk.blue('Preparing content')}`, '', {stdout: true});
300
+ arr[0].forEach(a => {
301
+ this.log('Copying: ', path.join(source, a));
302
+ fs.copySync(path.join(source, a), path.join(dest, a), {overwrite: true});
303
+ });
304
+ this.log(`${chalk.green('Copying done.')}`);
305
+ this.log(`${chalk.blue('Removing excluded elements.')}`);
306
+ arr[1].forEach(a => {
307
+ let curPath = path.join(dest, a);
308
+ if (fs.pathExistsSync(curPath)) {
309
+ if (fs.lstatSync(curPath).isFile()) {
310
+ try {
311
+ fs.removeSync(curPath);
312
+ this.log('Removing file: ', curPath);
313
+ } catch (error) {
314
+ cli.action.stop(`${chalk.red('failed')}`);
315
+ this.error(error.message);
316
+ }
317
+ } else if (fs.lstatSync(curPath).isDirectory()) {
318
+ try {
319
+ fs.removeSync(curPath);
320
+ this.log('Removing dir: ', curPath);
321
+ } catch (error) {
322
+ cli.action.stop(`${chalk.red('failed')}`);
323
+ this.error(error.message);
324
+ }
325
+ } else {
326
+ cli.action.stop(`${chalk.red('error')}`);
327
+ this.error('Type not file or directory');
328
+ }
329
+ }
330
+ });
331
+ this.log(`${chalk.green('Removing done.')}`);
332
+ cli.action.stop(`${chalk.green('done')}`);
333
+ } else {
334
+ cli.action.stop(`${chalk.red('error')}`);
335
+ this.error('Content validation failed.');
336
+ }
337
+ }
338
+ */
339
+ async run() {
340
+ const { flags } = this.parse(PrepareContent);
341
+ // read the flags and set paths relative to execution directory
342
+ let source = path.relative(process.cwd(), flags.source);
343
+ source = source ? source : '.';
344
+ let dest = flags.destination;
345
+ try {
346
+ let dotfileLines = await this.readDotfile(source);
347
+ this.log(`${chalk_1.default.blue('Content transformation started.')}`);
348
+ let transformations = await this.prepareTransformations(dotfileLines, source, dest);
349
+ await this.runTransformations(transformations);
350
+ this.log(`${chalk_1.default.green('Content prepared at: ', dest)}`);
351
+ }
352
+ catch (err) {
353
+ this.log(`${chalk_1.default.red(err)}`);
354
+ /*
355
+ In test mode, exit with status 0
356
+ */
357
+ if (process.env.OPS_TEST_MODE === 'true') {
358
+ this.exit(0);
359
+ }
360
+ this.exit(1);
361
+ }
362
+ }
363
+ }
364
+ exports.default = PrepareContent;
365
+ PrepareContent.dotfile = '.opsprepare';
366
+ PrepareContent.description = `copies files as described in ${PrepareContent.dotfile} which is at root of source directory`;
367
+ PrepareContent.usage = 'prepare-content -d <destination> [-s <source>]';
368
+ PrepareContent.examples = [
369
+ `$ ops prepare-content -d .\\my_workspace`,
370
+ `$ ops prepare-content -d .\\my_workspace -s .\\my_repository`,
371
+ `$ ops prepare-content -d C:\\git\\my_workspace`,
372
+ `$ ops prepare-content -d C:\\git\\my_workspace -s C:\\git\\my_repository\\my_repository`
373
+ ];
374
+ PrepareContent.flags = {
375
+ destination: command_1.flags.string({
376
+ char: 'd',
377
+ description: 'where to copy the workspace files',
378
+ required: true
379
+ }),
380
+ source: command_1.flags.string({
381
+ char: 's',
382
+ description: '[optional] source directory, default: current dir',
383
+ required: false,
384
+ default: '.'
385
+ })
386
+ };