@clickview/ship-it 0.0.5 → 0.0.6-rc.1

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/README.md CHANGED
@@ -1 +1,32 @@
1
- TODO: Write an actual readme
1
+ # Ship It
2
+
3
+ ## Prerequisites
4
+
5
+ * NodeJS (and npm)
6
+ * Access to the ClickView organization on [npm](https://www.npmjs.com). You will need to add an npm auth token to a global or local `.npmrc` file
7
+ * Add the `Ship It` user as a `Developer` to each GitLab project you would like to manage using the Ship It CLI
8
+
9
+ ## Getting Started
10
+
11
+ ```
12
+ git clone https://gitlab.cvinternal.net/front-end/ship-it.git
13
+ cd ship-it
14
+ npm install
15
+ ```
16
+
17
+ After installation, you can run `npm run start -- help` for a list of Shit Commands.
18
+
19
+ ## Commands
20
+
21
+ The available commands are listed below. If you run into issues check that you have met all the [prerequisites](#prerequisites) first.
22
+
23
+ ### Status
24
+
25
+ * Command: `npm run start -- status -p [projectId] -m [milestone]`
26
+ * Example: `npm run start -- status -p 887 -m T3`
27
+
28
+ Get the status of all MRs in a milestone. You can run this command at any time to check whether a project's miletone is ready for release.
29
+
30
+ You can find your numeric project id from your project page on GitLab.
31
+
32
+
@@ -55,6 +55,8 @@ var node_1 = require("@gitbeaker/node");
55
55
  var types_1 = require("../../types");
56
56
  var errors_1 = require("../../errors");
57
57
  var GitLabMapper_1 = require("./GitLabMapper");
58
+ var GroupIds_1 = require("../../utils/GroupIds");
59
+ var GitLabMemberIds_1 = require("../../constants/GitLabMemberIds");
58
60
  var GitLabApiClient = /** @class */ (function () {
59
61
  function GitLabApiClient(config) {
60
62
  this.config = config;
@@ -306,7 +308,8 @@ var GitLabApiClient = /** @class */ (function () {
306
308
  switch (_a.label) {
307
309
  case 0: return [4 /*yield*/, this.client.MergeRequests.create(projectId, sourceBranch, targetBranch, title, {
308
310
  description: description,
309
- milestoneId: milestone.id
311
+ milestoneId: milestone.id,
312
+ assigneeId: GitLabMemberIds_1.GitLabMemberIds.SHIP_IT
310
313
  })];
311
314
  case 1:
312
315
  mergeRequest = _a.sent();
@@ -364,13 +367,19 @@ var GitLabApiClient = /** @class */ (function () {
364
367
  };
365
368
  GitLabApiClient.prototype.getMilestone = function (projectId, milestoneName) {
366
369
  return __awaiter(this, void 0, void 0, function () {
367
- var milestones, milestone;
370
+ var groupMilestones, milestone, projectMilestones;
368
371
  return __generator(this, function (_a) {
369
372
  switch (_a.label) {
370
- case 0: return [4 /*yield*/, this.client.ProjectMilestones.all(projectId)];
373
+ case 0: return [4 /*yield*/, this.client.GroupMilestones.all(GroupIds_1.GroupIds.CLICKVIEW)];
371
374
  case 1:
372
- milestones = _a.sent();
373
- milestone = milestones.find(function (milestone) { return milestone.title === milestoneName; });
375
+ groupMilestones = _a.sent();
376
+ milestone = groupMilestones.find(function (milestone) { return milestone.title === milestoneName; });
377
+ if (milestone)
378
+ return [2 /*return*/, GitLabMapper_1.GitLabMapper.milestone(milestone)];
379
+ return [4 /*yield*/, this.client.ProjectMilestones.all(projectId)];
380
+ case 2:
381
+ projectMilestones = _a.sent();
382
+ milestone = projectMilestones.find(function (milestone) { return milestone.title === milestoneName; });
374
383
  if (!milestone)
375
384
  return [2 /*return*/, null];
376
385
  return [2 /*return*/, GitLabMapper_1.GitLabMapper.milestone(milestone)];
@@ -53,15 +53,29 @@ require("reflect-metadata");
53
53
  var inversify_1 = require("inversify");
54
54
  var types_1 = require("../types");
55
55
  var StatusCommand = /** @class */ (function () {
56
- function StatusCommand(validateTask) {
56
+ function StatusCommand(validateTask, validateDescriptionsTask, validateCommitsTask) {
57
57
  this.validateTask = validateTask;
58
+ this.validateDescriptionsTask = validateDescriptionsTask;
59
+ this.validateCommitsTask = validateCommitsTask;
58
60
  }
59
61
  StatusCommand.prototype.run = function (options) {
60
62
  return __awaiter(this, void 0, void 0, function () {
63
+ var cont;
61
64
  return __generator(this, function (_a) {
62
65
  switch (_a.label) {
63
66
  case 0: return [4 /*yield*/, this.validateTask.run(options)];
64
- case 1: return [2 /*return*/, _a.sent()];
67
+ case 1:
68
+ cont = _a.sent();
69
+ // Check if we want to continue with inquirer?
70
+ if (!cont)
71
+ return [2 /*return*/, false];
72
+ return [4 /*yield*/, this.validateDescriptionsTask.run(options)];
73
+ case 2:
74
+ cont = _a.sent();
75
+ if (!cont)
76
+ return [2 /*return*/, false];
77
+ return [4 /*yield*/, this.validateCommitsTask.run(options)];
78
+ case 3: return [2 /*return*/, _a.sent()];
65
79
  }
66
80
  });
67
81
  });
@@ -69,7 +83,9 @@ var StatusCommand = /** @class */ (function () {
69
83
  StatusCommand = __decorate([
70
84
  (0, inversify_1.injectable)(),
71
85
  __param(0, (0, inversify_1.inject)(types_1.TASKS.ValidateTask)),
72
- __metadata("design:paramtypes", [Object])
86
+ __param(1, (0, inversify_1.inject)(types_1.TASKS.ValidateDescriptionsTask)),
87
+ __param(2, (0, inversify_1.inject)(types_1.TASKS.ValidateCommitsTask)),
88
+ __metadata("design:paramtypes", [Object, Object, Object])
73
89
  ], StatusCommand);
74
90
  return StatusCommand;
75
91
  }());
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitLabMemberIds = void 0;
4
+ exports.GitLabMemberIds = {
5
+ SHIP_IT: 68
6
+ };
@@ -60,32 +60,38 @@ var ValidateCommitsTask = /** @class */ (function () {
60
60
  }
61
61
  ValidateCommitsTask.prototype.run = function (options) {
62
62
  return __awaiter(this, void 0, void 0, function () {
63
- var projects, cont, _i, projects_1, project, tag, devCommits, shouldCherryPick;
64
- return __generator(this, function (_a) {
65
- switch (_a.label) {
63
+ var projects, cont, _i, projects_1, project, _a, branch, tag, devCommits, shouldCherryPick;
64
+ return __generator(this, function (_b) {
65
+ switch (_b.label) {
66
66
  case 0:
67
67
  utils_1.Logger.logTask('Validating dev commits');
68
68
  return [4 /*yield*/, this.service.getProjects(options)];
69
69
  case 1:
70
- projects = _a.sent();
70
+ projects = _b.sent();
71
71
  cont = true;
72
72
  _i = 0, projects_1 = projects;
73
- _a.label = 2;
73
+ _b.label = 2;
74
74
  case 2:
75
75
  if (!(_i < projects_1.length)) return [3 /*break*/, 6];
76
76
  project = projects_1[_i];
77
77
  return [4 /*yield*/, this.service.getNextBranchInfo(project.id, options.version)];
78
78
  case 3:
79
- tag = (_a.sent()).tag;
79
+ _a = _b.sent(), branch = _a.branch, tag = _a.tag;
80
+ /**
81
+ * If the release branch already exists, this can be skipped as this
82
+ * validation is only required when creating a new release
83
+ */
84
+ if (branch)
85
+ return [3 /*break*/, 5];
80
86
  return [4 /*yield*/, this.service.getDevCommitsSince(project.id, tag.target)];
81
87
  case 4:
82
- devCommits = _a.sent();
88
+ devCommits = _b.sent();
83
89
  shouldCherryPick = utils_1.Commits.shouldCherryPick(project, devCommits);
84
90
  if (shouldCherryPick) {
85
91
  utils_1.Logger.logError("[".concat(project.title, "]: Requires cherrypicking"));
86
92
  cont = false;
87
93
  }
88
- _a.label = 5;
94
+ _b.label = 5;
89
95
  case 5:
90
96
  _i++;
91
97
  return [3 /*break*/, 2];
@@ -75,7 +75,7 @@ var ValidateTask = /** @class */ (function () {
75
75
  }
76
76
  ValidateTask.prototype.run = function (options) {
77
77
  return __awaiter(this, void 0, void 0, function () {
78
- var projects, cont, _loop_1, _i, projects_1, project;
78
+ var projects, cont, _loop_1, this_1, _i, projects_1, project;
79
79
  return __generator(this, function (_a) {
80
80
  switch (_a.label) {
81
81
  case 0:
@@ -86,75 +86,137 @@ var ValidateTask = /** @class */ (function () {
86
86
  utils_1.Logger.logMessage("Found ".concat(projects.length, " projects that need to be released"));
87
87
  cont = true;
88
88
  _loop_1 = function (project) {
89
- var groupedMRs = lodash_1.default.groupBy(project.mergeRequests, function (mr) { return mr.status; });
90
- var count = Object.keys(groupedMRs).reduce(function (prev, current) {
91
- var _a;
92
- return __assign(__assign({}, prev), (_a = {}, _a[current] = groupedMRs[current].length, _a));
93
- }, {});
94
- var ready = !count.opened || count.opened === 0;
95
- /**
96
- * Any MRs that are not targeting dev should not have a milestone
97
- */
98
- var nonDevMrs = project.mergeRequests.filter(function (mr) { return mr.targetBranch !== 'dev'; });
99
- if (nonDevMrs.length)
100
- ready = false;
101
- if (!ready)
102
- cont = false;
103
- if (ready) {
104
- utils_1.Logger.logSuccess("[".concat(project.title, "] READY"));
105
- }
106
- else {
107
- var message = "[".concat(project.title, "] NOT READY");
108
- if (count.opened)
109
- message += " Contains ".concat(count.opened, " Open MR(s)");
110
- if (nonDevMrs)
111
- message += " Contains ".concat(nonDevMrs.length, " MR(s) not targeting dev");
112
- utils_1.Logger.logError(message);
113
- }
89
+ var groupedMRs, count, ready, wrongTargetMrs, message;
90
+ return __generator(this, function (_b) {
91
+ switch (_b.label) {
92
+ case 0:
93
+ groupedMRs = lodash_1.default.groupBy(project.mergeRequests, function (mr) { return mr.status; });
94
+ count = Object.keys(groupedMRs).reduce(function (prev, current) {
95
+ var _a;
96
+ return __assign(__assign({}, prev), (_a = {}, _a[current] = groupedMRs[current].length, _a));
97
+ }, {});
98
+ ready = !count.opened || count.opened === 0;
99
+ return [4 /*yield*/, this_1.getMRsTargetingWrongBranch(project, options.version)];
100
+ case 1:
101
+ wrongTargetMrs = _b.sent();
102
+ if (wrongTargetMrs.length)
103
+ ready = false;
104
+ if (!ready)
105
+ cont = false;
106
+ if (ready) {
107
+ utils_1.Logger.logSuccess("[".concat(project.title, "] READY"));
108
+ }
109
+ else {
110
+ message = "[".concat(project.title, "] NOT READY");
111
+ if (count.opened)
112
+ message += " Contains ".concat(count.opened, " Open MR(s)");
113
+ if (wrongTargetMrs)
114
+ message += " Contains ".concat(wrongTargetMrs.length, " MR(s) not targeting dev or release branch");
115
+ utils_1.Logger.logError(message);
116
+ }
117
+ return [2 /*return*/];
118
+ }
119
+ });
114
120
  };
115
- for (_i = 0, projects_1 = projects; _i < projects_1.length; _i++) {
116
- project = projects_1[_i];
117
- _loop_1(project);
118
- }
119
- if (!cont) {
120
- this.logNotReady(projects);
121
- return [2 /*return*/, false];
122
- }
121
+ this_1 = this;
122
+ _i = 0, projects_1 = projects;
123
+ _a.label = 2;
124
+ case 2:
125
+ if (!(_i < projects_1.length)) return [3 /*break*/, 5];
126
+ project = projects_1[_i];
127
+ return [5 /*yield**/, _loop_1(project)];
128
+ case 3:
129
+ _a.sent();
130
+ _a.label = 4;
131
+ case 4:
132
+ _i++;
133
+ return [3 /*break*/, 2];
134
+ case 5:
135
+ if (!!cont) return [3 /*break*/, 7];
136
+ return [4 /*yield*/, this.logNotReady(projects, options.version)];
137
+ case 6:
138
+ _a.sent();
139
+ return [2 /*return*/, false];
140
+ case 7:
123
141
  utils_1.Logger.logSuccess('\nRelease is ready to go out');
124
142
  return [2 /*return*/, true];
125
143
  }
126
144
  });
127
145
  });
128
146
  };
129
- ValidateTask.prototype.logNotReady = function (projects) {
130
- utils_1.Logger.logError("\nThis release is NOT READY to go out, here are the outstanding MRs: \n");
131
- var allNotReadyMrs = [];
132
- var allNonDevMrs = [];
133
- for (var _i = 0, projects_2 = projects; _i < projects_2.length; _i++) {
134
- var project = projects_2[_i];
135
- var notReadyMrs = project.mergeRequests.filter(function (mr) { return mr.status === 'opened'; });
136
- var nonDevMrs = project.mergeRequests.filter(function (mr) { return mr.targetBranch !== 'dev'; });
137
- if (notReadyMrs.length)
138
- allNotReadyMrs.push.apply(allNotReadyMrs, notReadyMrs);
139
- if (nonDevMrs.length)
140
- allNonDevMrs.push.apply(allNonDevMrs, nonDevMrs);
141
- }
142
- var groupedByUser = lodash_1.default.groupBy(allNotReadyMrs, function (mr) { return mr.assignee; });
143
- for (var key in groupedByUser) {
144
- var name = key;
145
- if (!name || name === 'undefined')
146
- name = 'No Assignee';
147
- utils_1.Logger.logMessage(name);
148
- for (var _a = 0, _b = groupedByUser[key]; _a < _b.length; _a++) {
149
- var mr = _b[_a];
150
- utils_1.Logger.logMessage("- ".concat(mr.url));
151
- }
152
- }
153
- if (allNonDevMrs.length) {
154
- utils_1.Logger.logMessage('\nMRs that are not targeting dev\n');
155
- allNonDevMrs.forEach(function (mr) { return utils_1.Logger.logError("- ".concat(mr.url)); });
156
- }
157
- utils_1.Logger.logMessage('\n');
147
+ ValidateTask.prototype.logNotReady = function (projects, version) {
148
+ return __awaiter(this, void 0, void 0, function () {
149
+ var allNotReadyMrs, allWrongTargetMrs, _i, projects_2, project, notReadyMrs, wrongTargetMrs, groupedByUser, key, name, _a, _b, mr;
150
+ return __generator(this, function (_c) {
151
+ switch (_c.label) {
152
+ case 0:
153
+ utils_1.Logger.logError("\nThis release is NOT READY to go out, here are the outstanding MRs: \n");
154
+ allNotReadyMrs = [];
155
+ allWrongTargetMrs = [];
156
+ _i = 0, projects_2 = projects;
157
+ _c.label = 1;
158
+ case 1:
159
+ if (!(_i < projects_2.length)) return [3 /*break*/, 4];
160
+ project = projects_2[_i];
161
+ notReadyMrs = project.mergeRequests.filter(function (mr) { return mr.status === 'opened'; });
162
+ return [4 /*yield*/, this.getMRsTargetingWrongBranch(project, version)];
163
+ case 2:
164
+ wrongTargetMrs = _c.sent();
165
+ if (notReadyMrs.length)
166
+ allNotReadyMrs.push.apply(allNotReadyMrs, notReadyMrs);
167
+ if (wrongTargetMrs.length)
168
+ allWrongTargetMrs.push.apply(allWrongTargetMrs, wrongTargetMrs);
169
+ _c.label = 3;
170
+ case 3:
171
+ _i++;
172
+ return [3 /*break*/, 1];
173
+ case 4:
174
+ groupedByUser = lodash_1.default.groupBy(allNotReadyMrs, function (mr) { return mr.assignee; });
175
+ for (key in groupedByUser) {
176
+ name = key;
177
+ if (!name || name === 'undefined')
178
+ name = 'No Assignee';
179
+ utils_1.Logger.logMessage(name);
180
+ for (_a = 0, _b = groupedByUser[key]; _a < _b.length; _a++) {
181
+ mr = _b[_a];
182
+ utils_1.Logger.logMessage("- ".concat(mr.url));
183
+ }
184
+ }
185
+ if (allWrongTargetMrs.length) {
186
+ utils_1.Logger.logMessage('\nMRs that are not targeting dev or release branch\n');
187
+ allWrongTargetMrs.forEach(function (mr) { return utils_1.Logger.logError("- ".concat(mr.url)); });
188
+ }
189
+ utils_1.Logger.logMessage('\n');
190
+ return [2 /*return*/];
191
+ }
192
+ });
193
+ });
194
+ };
195
+ /**
196
+ * Finds any MRs with the milestone that are either not targeting dev
197
+ * or the release branch if one is already made
198
+ */
199
+ ValidateTask.prototype.getMRsTargetingWrongBranch = function (project, version) {
200
+ return __awaiter(this, void 0, void 0, function () {
201
+ var nonDevMrs, _a, premadeRelease, releaseName, nonDevAndReleaseMrs;
202
+ return __generator(this, function (_b) {
203
+ switch (_b.label) {
204
+ case 0:
205
+ nonDevMrs = project.mergeRequests.filter(function (mr) {
206
+ return mr.targetBranch !== 'dev';
207
+ });
208
+ if (!nonDevMrs.length)
209
+ return [2 /*return*/, []];
210
+ return [4 /*yield*/, this.service.getNextBranchInfo(project.id, version)];
211
+ case 1:
212
+ _a = _b.sent(), premadeRelease = _a.branch, releaseName = _a.branchName;
213
+ if (!premadeRelease)
214
+ return [2 /*return*/, nonDevMrs];
215
+ nonDevAndReleaseMrs = nonDevMrs.filter(function (mr) { return mr.targetBranch !== releaseName; });
216
+ return [2 /*return*/, nonDevAndReleaseMrs];
217
+ }
218
+ });
219
+ });
158
220
  };
159
221
  ValidateTask = __decorate([
160
222
  (0, inversify_1.injectable)(),
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GroupIds = void 0;
4
+ exports.GroupIds = {
5
+ CLICKVIEW: 1069
6
+ };
@@ -8,7 +8,10 @@ exports.PROJECT_NAMES = {
8
8
  curator: '62',
9
9
  cloud: '534',
10
10
  reports: '970',
11
- lite: '822'
11
+ lite: '822',
12
+ android: '887',
13
+ integrationsapi: '850',
14
+ auth: '54'
12
15
  };
13
16
  exports.ProjectIds = {
14
17
  MONOREPO_PROJECT_ID: '798',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clickview/ship-it",
3
- "version": "0.0.5",
3
+ "version": "0.0.6-rc.1",
4
4
  "description": "Release Manager",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {