@adinsure-ops/ops-cli 4.1.0 → 4.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/CHANGELOGS.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelogs
2
2
 
3
+ ## 4.3.0: 2022-07-27
4
+
5
+ - added command `npm:dependency-update` to update dependencies on packages in workspace defined by filter
6
+ - added command `nuget:dependency-update` to update dependencies on packages in workspace defined by filter
7
+ - improve error handling in translation fetching
8
+ - improve warning output when npm publish fails
9
+
10
+ ## 4.2.0: 2022-07-15
11
+
12
+ - added command `gitlab:get-tag-pipeline` to track pipeline status and wait for pipeline to finish
13
+ - added `--outputVersionOnly` to `gitlab:next-nightly-tag` to output only version
14
+
3
15
  ## 4.1.0: 2022-06-15
4
16
 
5
17
  - `vsix` file is removed after installation when `-i` flag is used
package/README.md CHANGED
@@ -2,22 +2,11 @@
2
2
 
3
3
  Operations CLI for supporting AdInsure development processes.
4
4
 
5
- # Latest version
6
-
7
- 4.0.0
5
+ https://www.npmjs.com/package/@adinsure-ops/ops-cli
8
6
 
9
7
  ## Install
10
8
 
11
- OPS CLI can be downloaded and installed using installer.
12
- For versions check [tags](https://git.adacta-fintech.com/ops/ops-cli/-/tags)
13
- or [download a JSON](https://adinsure.blob.core.windows.net/ops-cli/version) containing version and other information.
14
-
15
- | Platform| Link|
16
- |:---|:---|
17
- |Windows 64-bit|https://adinsure.blob.core.windows.net/ops-cli/win/ops-v4.0.0-x64.exe|
18
- |Debian 64-bit |https://adinsure.blob.core.windows.net/ops-cli/deb/ops_4.0.0-1_amd64.deb|
19
-
20
-
9
+ `npm install -g @adinsure-ops/ops-cli`
21
10
 
22
11
  ## CLI development
23
12
 
@@ -45,6 +34,7 @@ You can run and debug commands directly from terminal by running `ops [command]`
45
34
  * [`ops download:scheduler <flags>`](#ops-download-scheduler-flags)
46
35
  * [`ops download:server <flags>`](#ops-download-server-flags)
47
36
  * [`ops download:studio <flags>`](#ops-download-studio-flags)
37
+ * [`ops gitlab:get-tag-pipeline`](#ops-gitlab-get-tag-pipeline)
48
38
  * [`ops gitlab:next-nightly-tag`](#ops-gitlab-next-nightly-tag)
49
39
  * [`ops log <component> <issue> [options]`](#ops-log-component-issue-options)
50
40
  * [`ops log:gen [options]`](#ops-loggen-options)
@@ -52,6 +42,8 @@ You can run and debug commands directly from terminal by running `ops [command]`
52
42
  * [`ops login`](#ops-login)
53
43
  * [`ops npm:check-publish`](#ops-npm-check-publish)
54
44
  * [`ops npm:publish`](#ops-npm-publish)
45
+ * [`ops npm:dependency-update`](#ops-npm-dependency-update)
46
+ * [`ops nuget:dependency-update`](#ops-nuget-dependency-update)
55
47
  * [`ops prepare-content`](#ops-prepare-content)
56
48
  * [`ops sql <type> <module> [flags]`](#ops-sql-type-module-flags)
57
49
  * [`ops translate`](#ops-translate)
@@ -210,6 +202,26 @@ EXAMPLES
210
202
  $ ops download:studio -v 15.0.0 -i
211
203
  ```
212
204
 
205
+ ## `ops gitlab:get-tag-pipeline`
206
+
207
+ get pipeline status for tag
208
+
209
+ ```
210
+ USAGE
211
+ $ ops gitlab:get-tag-pipeline <tag>
212
+
213
+ ARGUMENTS
214
+ TAG Tag
215
+
216
+ OPTIONS
217
+ --delay=delay [default: 5] Delay of check in seconds (defaults to 5 seconds)
218
+ --host=host (required) [default: https://git.adacta-fintech.com] Server hostname
219
+ --pat=pat (required) Token from user that has permissions to list and create tags
220
+ --project=project (required) [default: 413] Project ID
221
+ --timeout=timeout [default: 120] Timeout for wait command in seconds (defaults to 120 seconds)
222
+ --wait Wait for pipeline to finish
223
+ ```
224
+
213
225
  ## `ops gitlab:next-nightly-tag`
214
226
 
215
227
  creates new gitlab tag
@@ -404,6 +416,43 @@ EXAMPLES
404
416
  $ ops npm:publish -p @adinsure-tooling/* -x @adisure-tooling/studio-services -v 6.0.0
405
417
  ```
406
418
 
419
+ ## `ops npm:dependency-update`
420
+
421
+ update npm dependencies per package filter
422
+
423
+ ```
424
+ USAGE
425
+ $ ops npm:dependency-update <type> [flags]
426
+
427
+ ARGUMENTS
428
+ VERSION Type of release
429
+
430
+ OPTIONS
431
+ --exclude=exclude exclude directories where to search for package.json
432
+ --filter=filter (required) regular expression for which NPM packages to update
433
+
434
+ EXAMPLE
435
+ $ ops npm:dependency-update 3.4.3 --filter @adinsure/*
436
+ ```
437
+ ## `ops nuget:dependency-update`
438
+
439
+ update nuget dependencies per package filter
440
+
441
+ ```
442
+ USAGE
443
+ $ ops nuget:dependency-update <type> [flags]
444
+
445
+ ARGUMENTS
446
+ VERSION Type of release
447
+
448
+ OPTIONS
449
+ --exclude=exclude exclude directories where to search for csproj files
450
+ --filter=filter (required) regular expression for which NuGet packages to update
451
+
452
+ EXAMPLE
453
+ $ ops nuget:dependency-update 3.4.3 --filter Adacta.AdInsure --exclude Scheduler
454
+ ```
455
+
407
456
  ## `ops prepare-content -d <destination> -s [source]`
408
457
 
409
458
  creates a directory/file structure from `/source` to `/destination</source>` as defined in the `.opsprepare` file. Actual
@@ -0,0 +1,17 @@
1
+ import { flags } from '@oclif/command';
2
+ import CommandBase from '../../command.base';
3
+ export default class DockerUpdateImageVersion extends CommandBase {
4
+ static description: string;
5
+ static usage: string;
6
+ static examples: string[];
7
+ static args: {
8
+ name: string;
9
+ description: string;
10
+ required: boolean;
11
+ }[];
12
+ static flags: {
13
+ services: flags.IOptionFlag<string[]>;
14
+ 'file-path': flags.IOptionFlag<string>;
15
+ };
16
+ run(): Promise<void>;
17
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const command_1 = require("@oclif/command");
4
+ const fs = require("fs-extra");
5
+ const yaml_1 = require("yaml");
6
+ const command_base_1 = require("../../command.base");
7
+ class DockerUpdateImageVersion extends command_base_1.default {
8
+ async run() {
9
+ const { args, flags } = this.parse(DockerUpdateImageVersion);
10
+ try {
11
+ let parsedYaml = yaml_1.parse(fs.readFileSync(flags['file-path'], 'utf8'));
12
+ for (let service of flags.services) {
13
+ let image = parsedYaml.services[service].image.split(':');
14
+ image[1] = args.version;
15
+ parsedYaml.services[service].image = image.join(':');
16
+ }
17
+ fs.writeFileSync(flags['file-path'], yaml_1.stringify(parsedYaml));
18
+ }
19
+ catch (err) {
20
+ this.error(err.message);
21
+ }
22
+ }
23
+ }
24
+ exports.default = DockerUpdateImageVersion;
25
+ DockerUpdateImageVersion.description = 'update docker image version docker compose file';
26
+ DockerUpdateImageVersion.usage = 'docker:update-image-version <tag>';
27
+ DockerUpdateImageVersion.examples = [
28
+ `$ ops docker:update-image-version 17.0.0 --service server client`
29
+ ];
30
+ DockerUpdateImageVersion.args = [
31
+ {
32
+ name: 'version',
33
+ description: 'version',
34
+ required: true
35
+ }
36
+ ];
37
+ DockerUpdateImageVersion.flags = {
38
+ services: command_1.flags.string({
39
+ required: true,
40
+ description: 'list of services to update',
41
+ multiple: true
42
+ }),
43
+ 'file-path': command_1.flags.string({
44
+ default: './docker-compose.yml',
45
+ description: 'list of services to update'
46
+ })
47
+ };
@@ -0,0 +1,23 @@
1
+ import { flags } from '@oclif/command';
2
+ import CommandBase from '../../command.base';
3
+ import GitLab from '../../lib/gitlab';
4
+ export default class GitlabGetTagPipeline extends CommandBase {
5
+ static description: string;
6
+ static usage: string;
7
+ static examples: string[];
8
+ static args: {
9
+ name: string;
10
+ description: string;
11
+ required: boolean;
12
+ }[];
13
+ static flags: {
14
+ pat: flags.IOptionFlag<string>;
15
+ host: flags.IOptionFlag<string>;
16
+ project: flags.IOptionFlag<string>;
17
+ wait: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
18
+ timeout: flags.IOptionFlag<string>;
19
+ delay: flags.IOptionFlag<string>;
20
+ };
21
+ waitPipelineStatus(gitlab: GitLab, tag: string, timeout: number, delay: number): Promise<string>;
22
+ run(): Promise<void>;
23
+ }
@@ -0,0 +1,143 @@
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 command_base_1 = require("../../command.base");
6
+ const gitlab_1 = require("../../lib/gitlab");
7
+ class GitlabGetTagPipeline extends command_base_1.default {
8
+ async waitPipelineStatus(gitlab, tag, timeout, delay) {
9
+ return new Promise(async (resolve, reject) => {
10
+ let time = 0;
11
+ try {
12
+ let status = await gitlab.getTagPipelineStatus(tag);
13
+ switch (status) {
14
+ case 'unknown': {
15
+ reject(new Error(`Pipeline or tag does not exist!`));
16
+ return;
17
+ }
18
+ case 'failed': {
19
+ reject(new Error(`Pipeline failed!`));
20
+ return;
21
+ }
22
+ case 'canceled': {
23
+ reject(new Error(`Pipeline canceled!`));
24
+ return;
25
+ }
26
+ case 'skipped': {
27
+ reject(new Error(`Pipeline skipped!`));
28
+ return;
29
+ }
30
+ case 'success': {
31
+ resolve(`Pipeline passed successfully!`);
32
+ return;
33
+ }
34
+ }
35
+ }
36
+ catch (err) {
37
+ reject(new Error(err.message));
38
+ return;
39
+ }
40
+ const interval = setInterval(async () => {
41
+ if (time >= timeout) {
42
+ reject(new Error('Timeout waiting pipeline'));
43
+ clearInterval(interval);
44
+ }
45
+ time += delay;
46
+ try {
47
+ let status = await gitlab.getTagPipelineStatus(tag);
48
+ switch (status) {
49
+ case 'unknown': {
50
+ reject(new Error(`Pipeline or tag does not exist!`));
51
+ clearInterval(interval);
52
+ break;
53
+ }
54
+ case 'failed': {
55
+ reject(new Error(`Pipeline failed!`));
56
+ clearInterval(interval);
57
+ break;
58
+ }
59
+ case 'canceled': {
60
+ reject(new Error(`Pipeline canceled!`));
61
+ clearInterval(interval);
62
+ break;
63
+ }
64
+ case 'skipped': {
65
+ reject(new Error(`Pipeline skipped!`));
66
+ clearInterval(interval);
67
+ break;
68
+ }
69
+ case 'success': {
70
+ resolve(`Pipeline passed successfully!`);
71
+ clearInterval(interval);
72
+ }
73
+ }
74
+ }
75
+ catch (err) {
76
+ reject(new Error(err.message));
77
+ clearInterval(interval);
78
+ }
79
+ }, delay * 1000);
80
+ });
81
+ }
82
+ async run() {
83
+ const { args, flags } = this.parse(GitlabGetTagPipeline);
84
+ const gitlab = new gitlab_1.default(flags.host, flags.project, flags.pat);
85
+ if (!flags.wait) {
86
+ let status = await gitlab.getTagPipelineStatus(args.tag);
87
+ return this.log(`${chalk_1.default.green(status)}`);
88
+ }
89
+ else {
90
+ try {
91
+ let status = await this.waitPipelineStatus(gitlab, args.tag, parseInt(flags.timeout, 10), parseInt(flags.delay, 10));
92
+ this.log(status);
93
+ }
94
+ catch (err) {
95
+ this.error(err.message);
96
+ }
97
+ }
98
+ }
99
+ }
100
+ exports.default = GitlabGetTagPipeline;
101
+ GitlabGetTagPipeline.description = 'get pipeline status for tag';
102
+ GitlabGetTagPipeline.usage = 'gitlab:get-tag-pipeline <tag>';
103
+ GitlabGetTagPipeline.examples = [
104
+ `$ ops gitlab:get-tag-pipeline 17.0.0`
105
+ ];
106
+ GitlabGetTagPipeline.args = [
107
+ {
108
+ name: 'tag',
109
+ description: 'Tag',
110
+ required: true
111
+ }
112
+ ];
113
+ GitlabGetTagPipeline.flags = {
114
+ pat: command_1.flags.string({
115
+ required: true,
116
+ env: 'PRIVATE_TOKEN',
117
+ description: 'Token from user that has permissions to list and create tags'
118
+ }),
119
+ host: command_1.flags.string({
120
+ required: true,
121
+ default: 'https://git.adacta-fintech.com',
122
+ env: 'CI_SERVER_URL',
123
+ description: 'Server hostname'
124
+ }),
125
+ project: command_1.flags.string({
126
+ required: true,
127
+ default: '413',
128
+ env: 'CI_PROJECT_ID',
129
+ description: 'Project ID'
130
+ }),
131
+ wait: command_1.flags.boolean({
132
+ description: 'Wait for pipeline to finish',
133
+ default: false
134
+ }),
135
+ timeout: command_1.flags.string({
136
+ default: '120',
137
+ description: 'Timeout for wait command in seconds (defaults to 120 seconds)'
138
+ }),
139
+ delay: command_1.flags.string({
140
+ default: '5',
141
+ description: 'Delay of check in seconds (defaults to 5 seconds)'
142
+ })
143
+ };
@@ -1,5 +1,4 @@
1
1
  import { flags } from '@oclif/command';
2
- import * as semver from 'semver';
3
2
  import CommandBase from '../../command.base';
4
3
  export default class GitlabNextNightlyTag extends CommandBase {
5
4
  static description: string;
@@ -14,16 +13,8 @@ export default class GitlabNextNightlyTag extends CommandBase {
14
13
  host: flags.IOptionFlag<string>;
15
14
  project: flags.IOptionFlag<string>;
16
15
  reference: flags.IOptionFlag<string>;
16
+ outputVersionOnly: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
17
17
  dryRun: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
18
18
  };
19
- private readonly apiBase;
20
- /**
21
- * Try to figure out latest available version already created
22
- */
23
- createNewTag(url: string, pat: string, tag_name: string, ref: string): Promise<void>;
24
- /**
25
- * Try to figure out latest available version already created
26
- */
27
- getLatestVersion(url: string, pat: string, searchVersion: string, prefix?: string): Promise<semver.SemVer>;
28
19
  run(): Promise<undefined>;
29
20
  }
@@ -1,81 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const command_1 = require("@oclif/command");
4
- const axios_1 = require("axios");
5
4
  const chalk_1 = require("chalk");
6
5
  const cli_ux_1 = require("cli-ux");
7
6
  const semver = require("semver");
8
7
  const command_base_1 = require("../../command.base");
8
+ const gitlab_1 = require("../../lib/gitlab");
9
9
  class GitlabNextNightlyTag extends command_base_1.default {
10
- constructor() {
11
- super(...arguments);
12
- this.apiBase = '/api/v4/projects';
13
- }
14
- /**
15
- * Try to figure out latest available version already created
16
- */
17
- async createNewTag(url, pat, tag_name, ref) {
18
- try {
19
- await axios_1.default.post(`${url}`, {
20
- tag_name,
21
- ref
22
- }, {
23
- headers: {
24
- Authorization: `Bearer ${pat}`,
25
- }
26
- });
27
- }
28
- catch (err) {
29
- throw new Error(err);
30
- }
31
- return;
32
- }
33
- /**
34
- * Try to figure out latest available version already created
35
- */
36
- async getLatestVersion(url, pat, searchVersion, prefix = '') {
37
- let versions = [];
38
- try {
39
- let page = 1;
40
- let totalPages = 1;
41
- do {
42
- let response = await axios_1.default.get(`${url}`, {
43
- headers: {
44
- Authorization: `Bearer ${pat}`,
45
- },
46
- params: {
47
- search: `^${prefix}v${searchVersion}`,
48
- per_page: 100,
49
- page
50
- }
51
- });
52
- response.data.forEach((tag) => {
53
- const regex = new RegExp(`${prefix}(.*)`);
54
- let searchTag = tag;
55
- let match = tag.name.match(regex);
56
- if (match[1]) {
57
- searchTag = match[1];
58
- }
59
- let semanticVersion = semver.parse(searchTag, { includePrerelease: true });
60
- if (semanticVersion && semanticVersion.prerelease.length === 0) {
61
- versions.push(semanticVersion);
62
- // ignore versions that that doesn't have number for prerelease identifier (skip qa and test prereleases)
63
- }
64
- else if (semanticVersion && semanticVersion.prerelease.length === 2 && /^[0-9]+$/.test(semanticVersion.prerelease[1].toString())) {
65
- versions.push(semanticVersion);
66
- }
67
- });
68
- totalPages = parseInt(response.headers['x-total-pages'], 10);
69
- page++;
70
- } while (page <= totalPages);
71
- }
72
- catch (err) {
73
- this.error(err.message);
74
- }
75
- return semver.rsort(versions)[0];
76
- }
77
10
  async run() {
78
11
  const { args, flags } = this.parse(GitlabNextNightlyTag);
12
+ const gitlab = new gitlab_1.default(flags.host, flags.project, flags.pat);
79
13
  const re = /^release\/(\w+\-)?((\d+)(\.\d+)?)$/;
80
14
  let prefix = '';
81
15
  let inputVersion = args.version;
@@ -86,12 +20,16 @@ class GitlabNextNightlyTag extends command_base_1.default {
86
20
  }
87
21
  inputVersion = match[2];
88
22
  }
89
- const urlPath = `${this.apiBase}/${flags.project}/repository/tags`;
90
23
  let version = semver.parse(inputVersion);
91
24
  let nextVersion = null;
92
25
  // if version is not parsable try to find something that starts with this version
93
26
  if (!version) {
94
- version = await this.getLatestVersion(`${flags.host}${urlPath}`, flags.pat, inputVersion, prefix);
27
+ try {
28
+ version = await gitlab.getLatestVersion(inputVersion, prefix);
29
+ }
30
+ catch (err) {
31
+ this.error(err.message);
32
+ }
95
33
  }
96
34
  // still version does not exists we will try to parse it with additional 0 as patch version
97
35
  if (!version) {
@@ -105,10 +43,18 @@ class GitlabNextNightlyTag extends command_base_1.default {
105
43
  if (!version) {
106
44
  return this.error(`${chalk_1.default.red('Version in incorrect format')}`);
107
45
  }
108
- cli_ux_1.default.action.start('Calculating next prerelease test version', undefined, { stdout: true });
46
+ if (!flags.outputVersionOnly) {
47
+ cli_ux_1.default.action.start('Calculating next prerelease test version', undefined, { stdout: true });
48
+ }
109
49
  const date = new Date();
110
50
  const prereleaseDate = `${date.getFullYear()}${('0' + (date.getMonth() + 1)).slice(-2)}`;
111
- let lastVersion = await this.getLatestVersion(`${flags.host}${urlPath}`, flags.pat, version.version, prefix);
51
+ let lastVersion = null;
52
+ try {
53
+ lastVersion = await gitlab.getLatestVersion(version.version, prefix);
54
+ }
55
+ catch (err) {
56
+ this.error(err.message);
57
+ }
112
58
  if (lastVersion) {
113
59
  nextVersion = `v${semver.inc(lastVersion, 'prerelease', prereleaseDate)}`;
114
60
  }
@@ -118,9 +64,19 @@ class GitlabNextNightlyTag extends command_base_1.default {
118
64
  if (prefix) {
119
65
  nextVersion = `${prefix}${nextVersion}`;
120
66
  }
121
- cli_ux_1.default.action.stop(`${chalk_1.default.green(nextVersion)}`);
67
+ if (!flags.outputVersionOnly) {
68
+ cli_ux_1.default.action.stop(`${chalk_1.default.green(nextVersion)}`);
69
+ }
70
+ else {
71
+ this.log(`${nextVersion}`);
72
+ }
122
73
  if (!flags.dryRun) {
123
- await this.createNewTag(`${flags.host}${urlPath}`, flags.pat, nextVersion, flags.reference);
74
+ try {
75
+ await gitlab.createNewTag(nextVersion, flags.reference);
76
+ }
77
+ catch (err) {
78
+ this.error(err.message);
79
+ }
124
80
  }
125
81
  else {
126
82
  this.warn(`This is only dry run. no new tag will was created!`);
@@ -162,6 +118,10 @@ GitlabNextNightlyTag.flags = {
162
118
  env: 'CI_COMMIT_REF_NAME',
163
119
  description: 'Reference to create tag on (branch, commit, tag)'
164
120
  }),
121
+ outputVersionOnly: command_1.flags.boolean({
122
+ description: `output only version instead of pretty output`,
123
+ default: false
124
+ }),
165
125
  dryRun: command_1.flags.boolean({
166
126
  description: `Only printout version and don't create it`,
167
127
  default: false
@@ -0,0 +1,23 @@
1
+ import { flags } from '@oclif/command';
2
+ import CommandBase from '../../command.base';
3
+ import { NpmPackage } from '../../types/npm.types';
4
+ export default class NpmDependencyUpdate extends CommandBase {
5
+ static description: string;
6
+ static usage: string;
7
+ static examples: string[];
8
+ static args: {
9
+ name: string;
10
+ required: boolean;
11
+ description: string;
12
+ }[];
13
+ static flags: {
14
+ filter: flags.IOptionFlag<string[]>;
15
+ exclude: flags.IOptionFlag<string[]>;
16
+ force: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
17
+ };
18
+ /**
19
+ * Update dependencies in package.json files for @adinsure packages
20
+ */
21
+ updateDependencies(newVersion: string, filter: string[] | undefined, packages: NpmPackage[], force?: boolean): Promise<void>;
22
+ run(): Promise<undefined>;
23
+ }
@@ -0,0 +1,113 @@
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 minimatch = require("minimatch");
8
+ const semver = require("semver");
9
+ const command_base_1 = require("../../command.base");
10
+ const command_2 = require("../../lib/command");
11
+ const npm_1 = require("../../lib/npm");
12
+ class NpmDependencyUpdate extends command_base_1.default {
13
+ /**
14
+ * Update dependencies in package.json files for @adinsure packages
15
+ */
16
+ async updateDependencies(newVersion, filter = ['**/*'], packages, force = false) {
17
+ // Find all package.json files that are not in node modules
18
+ for (const path of packages) {
19
+ try {
20
+ let data = await fs.readJSON(path.jsonPath);
21
+ let updatedKeys = [];
22
+ if (data.hasOwnProperty('dependencies')) {
23
+ for (const [key, value] of Object.entries(data.dependencies)) {
24
+ let currentVersion = semver.valid(String(value));
25
+ if (filter.some(pkg => minimatch(key, pkg))) {
26
+ if (currentVersion && semver.gt(currentVersion, newVersion) && !force) {
27
+ this.warn(`Lower of same version for dependency ${key} updated in file ${path.jsonPath}: ${newVersion} vs. ${currentVersion} is ${semver.gt(newVersion, currentVersion)}`);
28
+ }
29
+ else {
30
+ data.dependencies[key] = newVersion;
31
+ updatedKeys.push(key);
32
+ }
33
+ }
34
+ }
35
+ fs.writeFileSync(path.jsonPath, JSON.stringify(data, null, 4));
36
+ if (updatedKeys.length > 0) {
37
+ this.log(`Dependencies ${updatedKeys} updated in file ${path.jsonPath}`);
38
+ }
39
+ }
40
+ if (data.hasOwnProperty('devDependencies')) {
41
+ for (const [key, value] of Object.entries(data.devDependencies)) {
42
+ let currentVersion = semver.valid(String(value));
43
+ if (filter.some(pkg => minimatch(key, pkg))) {
44
+ if (currentVersion && semver.gt(currentVersion, newVersion) && !force) {
45
+ this.warn(`Lower of same version for devDependency ${key} updated in file ${path.jsonPath}: ${newVersion} vs. ${currentVersion} is ${semver.gt(newVersion, currentVersion)}`);
46
+ }
47
+ else {
48
+ data.devDependencies[key] = newVersion;
49
+ updatedKeys.push(key);
50
+ }
51
+ }
52
+ }
53
+ fs.writeFileSync(path.jsonPath, JSON.stringify(data, null, 4));
54
+ if (updatedKeys.length > 0) {
55
+ this.log(`devDependencies ${updatedKeys} updated in file ${path.jsonPath}`);
56
+ }
57
+ }
58
+ }
59
+ catch (err) {
60
+ this.warn(err.message);
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ async run() {
66
+ const { args, flags } = this.parse(NpmDependencyUpdate);
67
+ let newVersion = semver.valid(args.version);
68
+ let npmContext = new npm_1.default();
69
+ let command = new command_2.default();
70
+ // Stop if version invalid
71
+ if (!newVersion) {
72
+ return this.error(`${chalk_1.default.red('Version in incorrect format')}`);
73
+ }
74
+ const packages = await npmContext.packageList(['**/*'], [''], this);
75
+ try {
76
+ await this.updateDependencies(newVersion, flags.filter, packages, flags.force);
77
+ cli_ux_1.default.action.start(`running 'yarn install'`, undefined, { stdout: true });
78
+ await command.runCommand(['yarn', 'install']);
79
+ cli_ux_1.default.action.stop(`${chalk_1.default.green('done')}`);
80
+ }
81
+ catch (err) {
82
+ this.error(err.message);
83
+ }
84
+ }
85
+ }
86
+ exports.default = NpmDependencyUpdate;
87
+ NpmDependencyUpdate.description = 'update npm dependencies per package filter';
88
+ NpmDependencyUpdate.usage = 'npm:dependency-update <type> [flags]';
89
+ NpmDependencyUpdate.examples = [
90
+ `$ ops npm:dependency-update 3.4.3 --filter @adinsure/*`
91
+ ];
92
+ NpmDependencyUpdate.args = [
93
+ {
94
+ name: 'version',
95
+ required: true,
96
+ description: 'Type of release'
97
+ }
98
+ ];
99
+ NpmDependencyUpdate.flags = {
100
+ filter: command_1.flags.string({
101
+ description: 'regular expression for which NPM packages to update',
102
+ required: true,
103
+ multiple: true
104
+ }),
105
+ exclude: command_1.flags.string({
106
+ description: 'exclude directories where to search for package.json',
107
+ multiple: true
108
+ }),
109
+ force: command_1.flags.boolean({
110
+ description: 'force update of version regardless of lower vs higher version check',
111
+ default: false
112
+ })
113
+ };