@clickview/ship-it 0.0.10 → 0.0.12

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.
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
15
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
16
+ return new (P || (P = Promise))(function (resolve, reject) {
17
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
20
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
21
+ });
22
+ };
23
+ var __generator = (this && this.__generator) || function (thisArg, body) {
24
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
25
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
26
+ function verb(n) { return function (v) { return step([n, v]); }; }
27
+ function step(op) {
28
+ if (f) throw new TypeError("Generator is already executing.");
29
+ while (_) try {
30
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
31
+ if (y = 0, t) op = [op[0] & 2, t.value];
32
+ switch (op[0]) {
33
+ case 0: case 1: t = op; break;
34
+ case 4: _.label++; return { value: op[1], done: false };
35
+ case 5: _.label++; y = op[1]; op = [0]; continue;
36
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
37
+ default:
38
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
39
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
40
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
41
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
42
+ if (t[2]) _.ops.pop();
43
+ _.trys.pop(); continue;
44
+ }
45
+ op = body.call(thisArg, _);
46
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
47
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
48
+ }
49
+ };
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.CreateTestingNotesCommand = void 0;
52
+ require("reflect-metadata");
53
+ var inversify_1 = require("inversify");
54
+ var types_1 = require("../types");
55
+ var CreateTestingNotesCommand = /** @class */ (function () {
56
+ function CreateTestingNotesCommand(validateDescriptionsTask, createTestingNotesTask) {
57
+ this.validateDescriptionsTask = validateDescriptionsTask;
58
+ this.createTestingNotesTask = createTestingNotesTask;
59
+ }
60
+ CreateTestingNotesCommand.prototype.run = function (options) {
61
+ return __awaiter(this, void 0, void 0, function () {
62
+ var cont;
63
+ return __generator(this, function (_a) {
64
+ switch (_a.label) {
65
+ case 0: return [4 /*yield*/, this.validateDescriptionsTask.run(options)];
66
+ case 1:
67
+ cont = _a.sent();
68
+ if (!cont)
69
+ return [2 /*return*/, false];
70
+ return [4 /*yield*/, this.createTestingNotesTask.run(options)];
71
+ case 2: return [2 /*return*/, _a.sent()];
72
+ }
73
+ });
74
+ });
75
+ };
76
+ CreateTestingNotesCommand = __decorate([
77
+ (0, inversify_1.injectable)(),
78
+ __param(0, (0, inversify_1.inject)(types_1.TASKS.ValidateDescriptionsTask)),
79
+ __param(1, (0, inversify_1.inject)(types_1.TASKS.CreateTestingNotesTask)),
80
+ __metadata("design:paramtypes", [Object, Object])
81
+ ], CreateTestingNotesCommand);
82
+ return CreateTestingNotesCommand;
83
+ }());
84
+ exports.CreateTestingNotesCommand = CreateTestingNotesCommand;
@@ -19,6 +19,7 @@ __exportStar(require("./CreateBranchCommand"), exports);
19
19
  __exportStar(require("./CreateMergeRequestCommand"), exports);
20
20
  __exportStar(require("./ListProjectsCommand"), exports);
21
21
  __exportStar(require("./CreateReleaseNotesCommand"), exports);
22
+ __exportStar(require("./CreateTestingNotesCommand"), exports);
22
23
  __exportStar(require("./InstallPackagesCommand"), exports);
23
24
  __exportStar(require("./ReleaseCommand"), exports);
24
25
  __exportStar(require("./StartConsumingProjectBuildsCommand"), exports);
@@ -9,6 +9,7 @@ exports.CommandTypeMapping = {
9
9
  'create-branches': types_1.COMMANDS.CreateBranchCommand,
10
10
  'create-mrs': types_1.COMMANDS.CreateMergeRequestCommand,
11
11
  'create-notes': types_1.COMMANDS.CreateReleaseNotesCommand,
12
+ 'create-testing-notes': types_1.COMMANDS.CreateTestingNotesCommand,
12
13
  'install-packages': types_1.COMMANDS.InstallPackagesCommand,
13
14
  'bump-packages': types_1.COMMANDS.BumpPackagesCommand,
14
15
  'validate-mr': types_1.COMMANDS.ValidateMergeRequestCommand,
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DefaultProjectConfig = void 0;
4
+ exports.DefaultProjectConfig = {
5
+ monorepo: {
6
+ enabled: false,
7
+ validSubProjects: []
8
+ }
9
+ };
@@ -35,6 +35,7 @@ function createContainer(config) {
35
35
  container.bind(types_1.TASKS.CreateMergeRequestTask).to(tasks_1.CreateMergeRequestTask);
36
36
  container.bind(types_1.TASKS.ValidateDescriptionsTask).to(tasks_1.ValidateDescriptionsTask);
37
37
  container.bind(types_1.TASKS.CreateReleaseNotesTask).to(tasks_1.CreateReleaseNotesTask);
38
+ container.bind(types_1.TASKS.CreateTestingNotesTask).to(tasks_1.CreateTestingNotesTask);
38
39
  container.bind(types_1.TASKS.InstallPackagesTask).to(tasks_1.InstallPackagesTask);
39
40
  container.bind(types_1.TASKS.BumpPackagesTask).to(tasks_1.BumpPackagesTask);
40
41
  container.bind(types_1.TASKS.CommitPackageVersionsTask).to(tasks_1.CommitPackageVersionsTask);
@@ -53,6 +54,7 @@ function createContainer(config) {
53
54
  container.bind(types_1.COMMANDS.CreateMergeRequestCommand).to(commands_1.CreateMergeRequestCommand);
54
55
  container.bind(types_1.COMMANDS.ReleaseCommand).to(commands_1.ReleaseCommand);
55
56
  container.bind(types_1.COMMANDS.CreateReleaseNotesCommand).to(commands_1.CreateReleaseNotesCommand);
57
+ container.bind(types_1.COMMANDS.CreateTestingNotesCommand).to(commands_1.CreateTestingNotesCommand);
56
58
  container.bind(types_1.COMMANDS.InstallPackagesCommand).to(commands_1.InstallPackagesCommand);
57
59
  container.bind(types_1.COMMANDS.BumpPackagesCommand).to(commands_1.BumpPackagesCommand);
58
60
  container.bind(types_1.COMMANDS.ValidateMergeRequestCommand).to(commands_1.ValidateMergeRequestCommand);
@@ -71,6 +71,7 @@ var types_1 = require("../types");
71
71
  var api_clients_1 = require("../api-clients");
72
72
  var errors_1 = require("../errors");
73
73
  var utils_1 = require("../utils");
74
+ var ProjectConfig_1 = require("../interfaces/models/ProjectConfig");
74
75
  /**
75
76
  * These are projects that will try to use tags to pull in extra projects
76
77
  */
@@ -79,6 +80,7 @@ var MONOREPO_IDS = [
79
80
  ];
80
81
  var GitLabService = /** @class */ (function () {
81
82
  function GitLabService(apiClient) {
83
+ this.projectConfigCache = {};
82
84
  this.apiClient = apiClient;
83
85
  }
84
86
  GitLabService.prototype.getProjects = function (options) {
@@ -473,6 +475,37 @@ var GitLabService = /** @class */ (function () {
473
475
  });
474
476
  });
475
477
  };
478
+ GitLabService.prototype.getProjectConfig = function (projectId, branchName) {
479
+ return __awaiter(this, void 0, void 0, function () {
480
+ var cacheKey, configFileName, configFile, buff, text, json, projectConfig;
481
+ return __generator(this, function (_a) {
482
+ switch (_a.label) {
483
+ case 0:
484
+ cacheKey = projectId + ':' + branchName;
485
+ if (this.projectConfigCache[cacheKey])
486
+ return [2 /*return*/, this.projectConfigCache[cacheKey]];
487
+ configFileName = '.ship-it.config';
488
+ return [4 /*yield*/, this.apiClient.getFile(projectId, configFileName, branchName)];
489
+ case 1:
490
+ configFile = _a.sent();
491
+ if (!configFile)
492
+ return [2 /*return*/, ProjectConfig_1.DefaultProjectConfig];
493
+ try {
494
+ buff = Buffer.from(configFile.content, 'base64');
495
+ text = buff.toString('utf-8');
496
+ json = JSON.parse(text);
497
+ projectConfig = lodash_1.default.merge({}, ProjectConfig_1.DefaultProjectConfig, json);
498
+ this.projectConfigCache[cacheKey] = projectConfig;
499
+ return [2 /*return*/, projectConfig];
500
+ }
501
+ catch (_b) {
502
+ throw new errors_1.ShipItError("Failed to parse ".concat(configFileName));
503
+ }
504
+ return [2 /*return*/];
505
+ }
506
+ });
507
+ });
508
+ };
476
509
  GitLabService = __decorate([
477
510
  (0, inversify_1.injectable)(),
478
511
  __param(0, (0, inversify_1.inject)(types_1.API_CLIENTS.GitLabApiClient)),
@@ -49,6 +49,7 @@ function setupCommands(program, container) {
49
49
  addMilestoneCommand('create-branches', 'Create release branches for all projects that are part of a milestone');
50
50
  addMilestoneCommand('create-mrs', 'Create merge requests for all projects that are part of a milestone');
51
51
  addMilestoneCommand('create-notes', 'Builds descriptions for all projects that are part of a milestone');
52
+ addMilestoneCommand('create-testing-notes', 'Builds testing notes for all projects that are part of a milestone');
52
53
  addMilestoneCommand('tag-master', 'Tags master for all release MRs that are part of a milestone');
53
54
  program.command('release')
54
55
  .description('Create releases for all projects that are part of a milestone')
@@ -60,7 +60,7 @@ var CreateMergeRequestTask = /** @class */ (function () {
60
60
  }
61
61
  CreateMergeRequestTask.prototype.run = function (options) {
62
62
  return __awaiter(this, void 0, void 0, function () {
63
- var projects, _i, projects_1, project, _a, branch, branchName, mergeRequest, description;
63
+ var projects, _i, projects_1, project, _a, branch, branchName, mergeRequest, projectConfig, description;
64
64
  return __generator(this, function (_b) {
65
65
  switch (_b.label) {
66
66
  case 0:
@@ -71,14 +71,14 @@ var CreateMergeRequestTask = /** @class */ (function () {
71
71
  _i = 0, projects_1 = projects;
72
72
  _b.label = 2;
73
73
  case 2:
74
- if (!(_i < projects_1.length)) return [3 /*break*/, 7];
74
+ if (!(_i < projects_1.length)) return [3 /*break*/, 8];
75
75
  project = projects_1[_i];
76
76
  return [4 /*yield*/, this.service.getNextBranchInfo(project.id, options.version)];
77
77
  case 3:
78
78
  _a = _b.sent(), branch = _a.branch, branchName = _a.branchName;
79
79
  if (!branch) {
80
80
  utils_1.Logger.logError("[".concat(project.title, "]: [").concat(branchName, "] does not exist"));
81
- return [3 /*break*/, 6];
81
+ return [3 /*break*/, 7];
82
82
  }
83
83
  return [4 /*yield*/, this.service.getMergeRequest(project.id, branchName, 'opened')];
84
84
  case 4:
@@ -86,21 +86,24 @@ var CreateMergeRequestTask = /** @class */ (function () {
86
86
  if (mergeRequest) {
87
87
  utils_1.Logger.logWarning("[".concat(project.title, "]: MR already exists"));
88
88
  utils_1.Logger.logInfo(mergeRequest.url);
89
- return [3 /*break*/, 6];
89
+ return [3 /*break*/, 7];
90
90
  }
91
- description = project.id.toString() === utils_1.ProjectIds.MONOREPO_PROJECT_ID ?
91
+ return [4 /*yield*/, this.service.getProjectConfig(project.id, 'dev')];
92
+ case 5:
93
+ projectConfig = _b.sent();
94
+ description = projectConfig.monorepo.enabled ?
92
95
  utils_1.Descriptions.getMonorepoCombinedDescription(project.mergeRequests) :
93
96
  utils_1.Descriptions.getCombinedDescription(project.mergeRequests);
94
97
  return [4 /*yield*/, this.service.createMergeRequest(project.id, branchName, description, options.milestone)];
95
- case 5:
98
+ case 6:
96
99
  mergeRequest = _b.sent();
97
100
  utils_1.Logger.logMessage("[".concat(project.title, "]: MR created"));
98
101
  utils_1.Logger.logInfo(mergeRequest.url);
99
- _b.label = 6;
100
- case 6:
102
+ _b.label = 7;
103
+ case 7:
101
104
  _i++;
102
105
  return [3 /*break*/, 2];
103
- case 7: return [2 /*return*/, true];
106
+ case 8: return [2 /*return*/, true];
104
107
  }
105
108
  });
106
109
  });
@@ -65,7 +65,7 @@ var CreateReleaseNotesTask = /** @class */ (function () {
65
65
  }
66
66
  CreateReleaseNotesTask.prototype.run = function (options) {
67
67
  return __awaiter(this, void 0, void 0, function () {
68
- var projects, combinedDescription, _i, projects_1, project, fileName, description, outputPath_1, outputPath;
68
+ var projects, combinedDescription, _i, projects_1, project, fileName, description, projectConfig, outputPath_1, outputPath;
69
69
  return __generator(this, function (_a) {
70
70
  switch (_a.label) {
71
71
  case 0:
@@ -77,11 +77,14 @@ var CreateReleaseNotesTask = /** @class */ (function () {
77
77
  _i = 0, projects_1 = projects;
78
78
  _a.label = 2;
79
79
  case 2:
80
- if (!(_i < projects_1.length)) return [3 /*break*/, 5];
80
+ if (!(_i < projects_1.length)) return [3 /*break*/, 6];
81
81
  project = projects_1[_i];
82
82
  fileName = "".concat(project.title, ".md");
83
83
  description = '';
84
- if (project.id.toString() === utils_1.ProjectIds.MONOREPO_PROJECT_ID) {
84
+ return [4 /*yield*/, this.service.getProjectConfig(project.id, 'dev')];
85
+ case 3:
86
+ projectConfig = _a.sent();
87
+ if (projectConfig.monorepo.enabled) {
85
88
  description = utils_1.Descriptions.getMonorepoCombinedDescription(project.mergeRequests);
86
89
  }
87
90
  else {
@@ -91,16 +94,16 @@ var CreateReleaseNotesTask = /** @class */ (function () {
91
94
  combinedDescription += utils_1.Descriptions.bumpHeadings(description);
92
95
  outputPath_1 = "./dist/".concat(options.milestone, "/").concat(fileName);
93
96
  return [4 /*yield*/, fs_extra_1.default.outputFile(path_1.default.resolve(outputPath_1), description)];
94
- case 3:
95
- _a.sent();
96
- _a.label = 4;
97
97
  case 4:
98
+ _a.sent();
99
+ _a.label = 5;
100
+ case 5:
98
101
  _i++;
99
102
  return [3 /*break*/, 2];
100
- case 5:
103
+ case 6:
101
104
  outputPath = "./dist/".concat(options.milestone, "/Release Notes.md");
102
105
  return [4 /*yield*/, fs_extra_1.default.outputFile(path_1.default.resolve(outputPath), combinedDescription)];
103
- case 6:
106
+ case 7:
104
107
  _a.sent();
105
108
  utils_1.Logger.logMessage('Created file');
106
109
  utils_1.Logger.logInfo("".concat(path_1.default.resolve(outputPath), "\n"));
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
15
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
16
+ return new (P || (P = Promise))(function (resolve, reject) {
17
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
20
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
21
+ });
22
+ };
23
+ var __generator = (this && this.__generator) || function (thisArg, body) {
24
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
25
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
26
+ function verb(n) { return function (v) { return step([n, v]); }; }
27
+ function step(op) {
28
+ if (f) throw new TypeError("Generator is already executing.");
29
+ while (_) try {
30
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
31
+ if (y = 0, t) op = [op[0] & 2, t.value];
32
+ switch (op[0]) {
33
+ case 0: case 1: t = op; break;
34
+ case 4: _.label++; return { value: op[1], done: false };
35
+ case 5: _.label++; y = op[1]; op = [0]; continue;
36
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
37
+ default:
38
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
39
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
40
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
41
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
42
+ if (t[2]) _.ops.pop();
43
+ _.trys.pop(); continue;
44
+ }
45
+ op = body.call(thisArg, _);
46
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
47
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
48
+ }
49
+ };
50
+ var __importDefault = (this && this.__importDefault) || function (mod) {
51
+ return (mod && mod.__esModule) ? mod : { "default": mod };
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.CreateTestingNotesTask = void 0;
55
+ require("reflect-metadata");
56
+ var inversify_1 = require("inversify");
57
+ var path_1 = __importDefault(require("path"));
58
+ var fs_extra_1 = __importDefault(require("fs-extra"));
59
+ var types_1 = require("../types");
60
+ var services_1 = require("../services");
61
+ var utils_1 = require("../utils");
62
+ var Csv_1 = require("../utils/Csv");
63
+ var CreateTestingNotesTask = /** @class */ (function () {
64
+ function CreateTestingNotesTask(service) {
65
+ this.service = service;
66
+ }
67
+ CreateTestingNotesTask.prototype.run = function (options) {
68
+ return __awaiter(this, void 0, void 0, function () {
69
+ var projects, projectTestingNotes, _i, projects_1, project, description, _a, _b, mr, outputPath, error_1, csv;
70
+ return __generator(this, function (_c) {
71
+ switch (_c.label) {
72
+ case 0:
73
+ utils_1.Logger.logTask('Creating testing notes');
74
+ return [4 /*yield*/, this.service.getProjects(options)];
75
+ case 1:
76
+ projects = _c.sent();
77
+ projectTestingNotes = [];
78
+ for (_i = 0, projects_1 = projects; _i < projects_1.length; _i++) {
79
+ project = projects_1[_i];
80
+ description = '';
81
+ for (_a = 0, _b = project.mergeRequests; _a < _b.length; _a++) {
82
+ mr = _b[_a];
83
+ if (project.id.toString() === utils_1.ProjectIds.MONOREPO_PROJECT_ID) {
84
+ description = utils_1.Descriptions.getMonorepoCombinedDescription([mr]);
85
+ }
86
+ else {
87
+ description = utils_1.Descriptions.getCombinedDescription([mr]);
88
+ }
89
+ projectTestingNotes.push({
90
+ projectName: project.title,
91
+ mrTitle: mr.title,
92
+ mrAuthor: mr.author,
93
+ mrAssignee: mr.assignee,
94
+ mrUrl: mr.url,
95
+ notes: utils_1.Descriptions.bumpHeadings(description).trim()
96
+ });
97
+ }
98
+ }
99
+ outputPath = path_1.default.resolve("./dist/".concat(options.milestone));
100
+ _c.label = 2;
101
+ case 2:
102
+ _c.trys.push([2, 4, , 6]);
103
+ return [4 /*yield*/, fs_extra_1.default.access(outputPath)];
104
+ case 3:
105
+ _c.sent();
106
+ return [3 /*break*/, 6];
107
+ case 4:
108
+ error_1 = _c.sent();
109
+ return [4 /*yield*/, fs_extra_1.default.ensureDir(outputPath)];
110
+ case 5:
111
+ _c.sent();
112
+ return [3 /*break*/, 6];
113
+ case 6:
114
+ csv = new Csv_1.CsvFile({
115
+ headers: ['projectName', 'mrTitle', 'mrAuthor', 'mrAssignee', 'mrUrl', 'notes'],
116
+ path: path_1.default.resolve(outputPath, "".concat(options.milestone, " Testing Notes.csv")),
117
+ });
118
+ return [4 /*yield*/, csv.create(projectTestingNotes)];
119
+ case 7:
120
+ _c.sent();
121
+ utils_1.Logger.logMessage('Created file');
122
+ utils_1.Logger.logInfo("".concat(path_1.default.resolve(outputPath), "\n"));
123
+ return [2 /*return*/, true];
124
+ }
125
+ });
126
+ });
127
+ };
128
+ CreateTestingNotesTask = __decorate([
129
+ (0, inversify_1.injectable)(),
130
+ __param(0, (0, inversify_1.inject)(types_1.SERVICES.GitLabService)),
131
+ __metadata("design:paramtypes", [services_1.GitLabService])
132
+ ], CreateTestingNotesTask);
133
+ return CreateTestingNotesTask;
134
+ }());
135
+ exports.CreateTestingNotesTask = CreateTestingNotesTask;
@@ -65,45 +65,75 @@ var ValidateDescriptionsTask = /** @class */ (function () {
65
65
  ValidateDescriptionsTask.prototype.run = function (options) {
66
66
  var _a;
67
67
  return __awaiter(this, void 0, void 0, function () {
68
- var projects, cont, _i, projects_1, project, invalidMrs, mergeRequestsTargetingDev, _b, mergeRequestsTargetingDev_1, mr, isMonorepo, isMrValid, groupedByUser, key, _c, _d, mr;
69
- return __generator(this, function (_e) {
70
- switch (_e.label) {
68
+ var projects, cont, _loop_1, this_1, _i, projects_1, project;
69
+ return __generator(this, function (_b) {
70
+ switch (_b.label) {
71
71
  case 0:
72
72
  utils_1.Logger.logTask('Validating descriptions');
73
73
  return [4 /*yield*/, this.service.getProjects(options)];
74
74
  case 1:
75
- projects = _e.sent();
75
+ projects = _b.sent();
76
76
  cont = true;
77
- for (_i = 0, projects_1 = projects; _i < projects_1.length; _i++) {
78
- project = projects_1[_i];
79
- invalidMrs = [];
80
- mergeRequestsTargetingDev = project.mergeRequests.filter(function (mergeRequest) {
81
- return mergeRequest.targetBranch === 'dev';
82
- });
83
- for (_b = 0, mergeRequestsTargetingDev_1 = mergeRequestsTargetingDev; _b < mergeRequestsTargetingDev_1.length; _b++) {
84
- mr = mergeRequestsTargetingDev_1[_b];
85
- isMonorepo = project.id.toString() === utils_1.ProjectIds.MONOREPO_PROJECT_ID;
86
- isMrValid = isMonorepo ?
87
- utils_1.Descriptions.isMonorepoDescriptionValid(mr.description) :
88
- utils_1.Descriptions.isDescriptionValid(mr.description);
89
- if (isMonorepo && !((_a = mr.labels) === null || _a === void 0 ? void 0 : _a.length))
90
- isMrValid = false;
91
- if (!isMrValid)
92
- invalidMrs.push(mr);
93
- }
94
- if (invalidMrs.length) {
95
- utils_1.Logger.logError("\n[".concat(project.title, "] has invalid MRs"));
96
- groupedByUser = lodash_1.default.groupBy(invalidMrs, function (mr) { return mr.author; });
97
- for (key in groupedByUser) {
98
- utils_1.Logger.logMessage(key);
99
- for (_c = 0, _d = groupedByUser[key]; _c < _d.length; _c++) {
100
- mr = _d[_c];
101
- utils_1.Logger.logMessage("- ".concat(mr.url));
102
- }
77
+ _loop_1 = function (project) {
78
+ var invalidMrs, targetBranch, mergeRequestsTargetingDev, projectConfig, isMonorepo, _c, mergeRequestsTargetingDev_1, mr, errors, isMrValid, groupedByUser, key, _d, _e, _f, mr, errors, _g, errors_1, error;
79
+ return __generator(this, function (_h) {
80
+ switch (_h.label) {
81
+ case 0:
82
+ invalidMrs = [];
83
+ targetBranch = 'dev';
84
+ mergeRequestsTargetingDev = project.mergeRequests.filter(function (mergeRequest) {
85
+ return mergeRequest.targetBranch === targetBranch;
86
+ });
87
+ return [4 /*yield*/, this_1.service.getProjectConfig(project.id, targetBranch)];
88
+ case 1:
89
+ projectConfig = _h.sent();
90
+ isMonorepo = project.id.toString() === utils_1.ProjectIds.MONOREPO_PROJECT_ID;
91
+ for (_c = 0, mergeRequestsTargetingDev_1 = mergeRequestsTargetingDev; _c < mergeRequestsTargetingDev_1.length; _c++) {
92
+ mr = mergeRequestsTargetingDev_1[_c];
93
+ errors = utils_1.Descriptions.validate(mr.description, projectConfig);
94
+ isMrValid = errors.length === 0;
95
+ if (isMonorepo && !((_a = mr.labels) === null || _a === void 0 ? void 0 : _a.length))
96
+ isMrValid = false;
97
+ if (!isMrValid)
98
+ invalidMrs.push([mr, errors]);
99
+ }
100
+ if (invalidMrs.length) {
101
+ utils_1.Logger.logError("\n[".concat(project.title, "] has invalid MRs"));
102
+ groupedByUser = lodash_1.default.groupBy(invalidMrs, function (_a) {
103
+ var mr = _a[0];
104
+ return mr.author;
105
+ });
106
+ for (key in groupedByUser) {
107
+ utils_1.Logger.logMessage(key);
108
+ for (_d = 0, _e = groupedByUser[key]; _d < _e.length; _d++) {
109
+ _f = _e[_d], mr = _f[0], errors = _f[1];
110
+ utils_1.Logger.logMessage("- ".concat(mr.url));
111
+ for (_g = 0, errors_1 = errors; _g < errors_1.length; _g++) {
112
+ error = errors_1[_g];
113
+ utils_1.Logger.logMessage(" - ".concat(error));
114
+ }
115
+ }
116
+ }
117
+ cont = false;
118
+ }
119
+ return [2 /*return*/];
103
120
  }
104
- cont = false;
105
- }
106
- }
121
+ });
122
+ };
123
+ this_1 = this;
124
+ _i = 0, projects_1 = projects;
125
+ _b.label = 2;
126
+ case 2:
127
+ if (!(_i < projects_1.length)) return [3 /*break*/, 5];
128
+ project = projects_1[_i];
129
+ return [5 /*yield**/, _loop_1(project)];
130
+ case 3:
131
+ _b.sent();
132
+ _b.label = 4;
133
+ case 4:
134
+ _i++;
135
+ return [3 /*break*/, 2];
136
+ case 5:
107
137
  if (cont)
108
138
  utils_1.Logger.logSuccess('All MR descriptions are valid');
109
139
  return [2 /*return*/, cont];
@@ -62,7 +62,7 @@ var ValidateMergeRequestTask = /** @class */ (function () {
62
62
  ValidateMergeRequestTask.prototype.run = function (options) {
63
63
  var _a;
64
64
  return __awaiter(this, void 0, void 0, function () {
65
- var project, mergeRequestId, mergeRequest, isMonorepo, isDescriptionValid;
65
+ var project, mergeRequestId, mergeRequest, isMonorepo, projectConfig, isDescriptionValid;
66
66
  return __generator(this, function (_b) {
67
67
  switch (_b.label) {
68
68
  case 0:
@@ -91,9 +91,10 @@ var ValidateMergeRequestTask = /** @class */ (function () {
91
91
  Logger_1.Logger.logError('Monorepo MRs must have labels');
92
92
  return [2 /*return*/, false];
93
93
  }
94
- isDescriptionValid = isMonorepo ?
95
- utils_1.Descriptions.isMonorepoDescriptionValid(mergeRequest.description) :
96
- utils_1.Descriptions.isDescriptionValid(mergeRequest.description);
94
+ return [4 /*yield*/, this.service.getProjectConfig(project.id, mergeRequest.targetBranch)];
95
+ case 3:
96
+ projectConfig = _b.sent();
97
+ isDescriptionValid = utils_1.Descriptions.validate(mergeRequest.description, projectConfig).length === 0;
97
98
  if (!isDescriptionValid) {
98
99
  Logger_1.Logger.logError('Merge request description is invalid');
99
100
  return [2 /*return*/, false];
@@ -20,6 +20,7 @@ __exportStar(require("./CommitPackageVersionsTask"), exports);
20
20
  __exportStar(require("./CreateBranchTask"), exports);
21
21
  __exportStar(require("./CreateMergeRequestTask"), exports);
22
22
  __exportStar(require("./CreateReleaseNotesTask"), exports);
23
+ __exportStar(require("./CreateTestingNotesTask"), exports);
23
24
  __exportStar(require("./InstallPackagesTask"), exports);
24
25
  __exportStar(require("./StartConsumingProjectBuildsTask"), exports);
25
26
  __exportStar(require("./StartMonorepoBuildTask"), exports);
package/lib/src/types.js CHANGED
@@ -22,6 +22,7 @@ exports.TASKS = {
22
22
  CreateMergeRequestTask: Symbol.for('CreateMergeRequestTask'),
23
23
  ValidateDescriptionsTask: Symbol.for('ValidateDescriptionsTask'),
24
24
  CreateReleaseNotesTask: Symbol.for('CreateReleaseNotesTask'),
25
+ CreateTestingNotesTask: Symbol.for('CreateTestingNotesTask'),
25
26
  InstallPackagesTask: Symbol.for('InstallPackagesTask'),
26
27
  BumpPackagesTask: Symbol.for('BumpPackagesTask'),
27
28
  CommitPackageVersionsTask: Symbol.for('CommitPackageVersionsTask'),
@@ -38,6 +39,7 @@ exports.COMMANDS = {
38
39
  CreateBranchCommand: Symbol.for('CreateBranchCommand'),
39
40
  CreateMergeRequestCommand: Symbol.for('CreateMergeRequestCommand'),
40
41
  CreateReleaseNotesCommand: Symbol.for('CreateReleaseNotesCommand'),
42
+ CreateTestingNotesCommand: Symbol.for('CreateTestingNotesCommand'),
41
43
  InstallPackagesCommand: Symbol.for('InstallPackagesCommand'),
42
44
  BumpPackagesCommand: Symbol.for('BumpPackagesCommand'),
43
45
  ValidateMergeRequestCommand: Symbol.for('ValidateMergeRequestCommand'),
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.CsvFile = void 0;
18
+ var format_1 = require("@fast-csv/format");
19
+ var fs_extra_1 = __importDefault(require("fs-extra"));
20
+ var CsvFile = /** @class */ (function () {
21
+ function CsvFile(opts) {
22
+ this.headers = opts.headers;
23
+ this.path = opts.path;
24
+ this.writeOpts = { headers: this.headers, includeEndRowDelimiter: true };
25
+ }
26
+ CsvFile.write = function (stream, rows, options) {
27
+ return new Promise(function (res, rej) {
28
+ (0, format_1.writeToStream)(stream, rows, options)
29
+ .on('error', function (err) { return rej(err); })
30
+ .on('finish', function () { return res(); });
31
+ });
32
+ };
33
+ CsvFile.prototype.create = function (rows) {
34
+ return CsvFile.write(fs_extra_1.default.createWriteStream(this.path), rows, __assign({}, this.writeOpts));
35
+ };
36
+ CsvFile.prototype.append = function (rows) {
37
+ return CsvFile.write(fs_extra_1.default.createWriteStream(this.path, { flags: 'a' }), rows, __assign(__assign({}, this.writeOpts), {
38
+ // dont write the headers when appending
39
+ writeHeaders: false }));
40
+ };
41
+ CsvFile.prototype.read = function () {
42
+ var _this = this;
43
+ return new Promise(function (res, rej) {
44
+ fs_extra_1.default.readFile(_this.path, function (err, contents) {
45
+ if (err) {
46
+ return rej(err);
47
+ }
48
+ return res(contents);
49
+ });
50
+ });
51
+ };
52
+ return CsvFile;
53
+ }());
54
+ exports.CsvFile = CsvFile;
@@ -1,67 +1,46 @@
1
1
  "use strict";
2
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
- if (ar || !(i in from)) {
5
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
- ar[i] = from[i];
7
- }
8
- }
9
- return to.concat(ar || Array.prototype.slice.call(from));
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.Descriptions = void 0;
13
- var VALID_HEADINGS = {
14
- 'dependencies': true,
15
- 'before release': true,
16
- 'customer changes': true,
17
- 'code changes': true,
18
- 'testing': true,
19
- 'notes': true,
20
- 'other': true
21
- };
22
- var VALID_MONOREPO_HEADINGS = {
23
- 'common': true,
24
- 'curator': true,
25
- 'library editor': true,
26
- 'lite': true,
27
- 'online': true,
28
- 'shared': true,
29
- 'styles': true,
30
- 'player': true,
31
- 'reports': true,
32
- 'analytics': true,
33
- 'tooling': true,
34
- 'testing': true,
35
- 'dependencies': true,
36
- 'notes': true,
37
- 'monorepo': true,
38
- 'before release': true
4
+ var Headings = {
5
+ BeforeRelease: 'Before release',
6
+ Dependencies: 'Dependencies',
7
+ CodeChanges: 'Code changes',
8
+ CustomerChanges: 'Customer changes',
9
+ Testing: 'Testing',
10
+ Notes: 'Notes'
39
11
  };
40
- /**
41
- * Most of the ordering here doesn't matter, BUT "before release" and "dependencies" should always be
42
- * at the top so that they're more visible to whoever is managing the release.
43
- */
12
+ var BASE_VALID_HEADINGS = [
13
+ Headings.BeforeRelease,
14
+ Headings.Dependencies,
15
+ Headings.Testing,
16
+ Headings.Notes
17
+ ];
18
+ var PROJECT_VALID_HEADINGS = BASE_VALID_HEADINGS.concat([
19
+ Headings.CustomerChanges,
20
+ Headings.CodeChanges
21
+ ]);
22
+ var PROJECT_REQUIRED_HEADINGS = [
23
+ Headings.Testing
24
+ ];
44
25
  var HEADING_ORDER = [
45
- 'before release',
46
- 'dependencies',
47
- 'notes',
48
- 'other',
49
- 'customer changes',
50
- 'code changes',
51
- 'lite',
52
- 'library editor',
53
- 'online',
54
- 'reports',
55
- 'curator',
56
- 'player',
57
- 'shared',
58
- 'analytics',
59
- 'styles',
60
- 'common',
61
- 'monorepo',
62
- 'tooling',
63
- 'testing'
26
+ Headings.BeforeRelease,
27
+ Headings.Dependencies,
28
+ Headings.CustomerChanges,
29
+ Headings.CodeChanges,
30
+ '*',
31
+ Headings.Testing,
32
+ Headings.Notes,
64
33
  ];
34
+ function headingTransformer(heading) {
35
+ // Fix casing of known headings
36
+ var lowerHeading = heading.toLowerCase();
37
+ for (var i = 0; i < PROJECT_VALID_HEADINGS.length; i++) {
38
+ if (PROJECT_VALID_HEADINGS[i].toLowerCase() === lowerHeading)
39
+ return PROJECT_VALID_HEADINGS[i];
40
+ }
41
+ // No transform
42
+ return heading;
43
+ }
65
44
  function toObject(lines, headingPrefix) {
66
45
  var obj = {};
67
46
  var currentHeading = 'other';
@@ -72,7 +51,7 @@ function toObject(lines, headingPrefix) {
72
51
  continue;
73
52
  if (line.startsWith(headingPrefix + ' ')) {
74
53
  // TODO: Potentially add heading transforms to capture multiple variants
75
- currentHeading = line.toLowerCase().replace(headingPrefix, '').trim();
54
+ currentHeading = headingTransformer(line.replace(headingPrefix, '').trim());
76
55
  continue;
77
56
  }
78
57
  if (!obj[currentHeading])
@@ -95,47 +74,85 @@ function toObject(lines, headingPrefix) {
95
74
  * - Josh
96
75
  */
97
76
  function orderDescriptionHeadings(headings) {
98
- var orderForIndexVals = __spreadArray([], HEADING_ORDER, true).reverse();
77
+ // Get the index of our wildcard where we put all the other headings into
78
+ var starIndex = HEADING_ORDER.indexOf('*');
79
+ if (starIndex === -1)
80
+ starIndex = HEADING_ORDER.length;
99
81
  return headings.sort(function (a, b) {
100
- var aIndex = -orderForIndexVals.indexOf(a);
101
- var bIndex = -orderForIndexVals.indexOf(b);
82
+ var aIndex = HEADING_ORDER.indexOf(a);
83
+ var bIndex = HEADING_ORDER.indexOf(b);
84
+ // Do normal sort logic if both are missing from heading order
85
+ if (aIndex === -1 && bIndex === -1) {
86
+ if (a < b)
87
+ return -1;
88
+ if (a > b)
89
+ return 1;
90
+ return 0;
91
+ }
92
+ if (aIndex === -1)
93
+ aIndex = starIndex;
94
+ if (bIndex === -1)
95
+ bIndex = starIndex;
102
96
  return aIndex - bIndex;
103
97
  });
104
98
  }
105
99
  exports.Descriptions = {
106
- isDescriptionValid: function (description, headingPrefix, checkForTesting) {
107
- if (headingPrefix === void 0) { headingPrefix = '#'; }
108
- if (checkForTesting === void 0) { checkForTesting = true; }
109
- if (!description.trim())
110
- return false;
111
- var obj = toObject(description.split('\n'), headingPrefix);
112
- var keys = Object.keys(obj);
113
- if (!(keys === null || keys === void 0 ? void 0 : keys.length))
114
- return false;
115
- if (keys.some(function (k) { return !VALID_HEADINGS[k]; }))
116
- return false;
117
- if (checkForTesting && obj['testing'] === undefined)
118
- return false;
119
- return true;
120
- },
121
- isMonorepoDescriptionValid: function (description) {
122
- if (!description.trim())
123
- return false;
100
+ validate: function (description, projectConfig) {
101
+ var validHeadings;
102
+ // If we are a monorepo, add in the valid sub project headings
103
+ if (projectConfig.monorepo.enabled) {
104
+ var subProjects = projectConfig.monorepo.validSubProjects;
105
+ validHeadings = BASE_VALID_HEADINGS.concat(subProjects);
106
+ }
107
+ else {
108
+ validHeadings = PROJECT_VALID_HEADINGS;
109
+ }
110
+ // Parse description
124
111
  var obj = toObject(description.split('\n'), '#');
125
- var keys = Object.keys(obj);
126
- if (!(keys === null || keys === void 0 ? void 0 : keys.length))
127
- return false;
128
- if (keys.some(function (k) { return !VALID_MONOREPO_HEADINGS[k]; }))
129
- return false;
130
- if (obj['testing'] === undefined)
131
- return false;
132
- var isValid = Object.keys(obj).every(function (key) {
133
- if (key === 'dependencies' || key === 'testing')
134
- return true;
135
- var subValid = exports.Descriptions.isDescriptionValid(obj[key], '##', false);
136
- return subValid;
112
+ var errors = this.validateProject(obj, {
113
+ validSections: validHeadings,
114
+ requiredSections: PROJECT_REQUIRED_HEADINGS
137
115
  });
138
- return isValid;
116
+ if (!projectConfig.monorepo.enabled)
117
+ return errors;
118
+ var _loop_1 = function (subProject) {
119
+ // Ignore known headings
120
+ if (PROJECT_VALID_HEADINGS.indexOf(subProject) !== -1)
121
+ return "continue";
122
+ var subObj = toObject(obj[subProject].split('\n'), '##');
123
+ var subErrors = this_1.validateProject(subObj, {
124
+ validSections: PROJECT_VALID_HEADINGS,
125
+ requiredSections: []
126
+ });
127
+ errors = errors.concat(subErrors.map(function (x) { return "[".concat(subProject, "] ") + x; }));
128
+ };
129
+ var this_1 = this;
130
+ // If monorepo we need to check the sub projects are valid
131
+ for (var subProject in obj) {
132
+ _loop_1(subProject);
133
+ }
134
+ return errors;
135
+ },
136
+ validateProject: function (parsedDescription, options) {
137
+ // Parse description
138
+ var headings = Object.keys(parsedDescription);
139
+ // Must have at least one heading
140
+ if (headings.length < 1)
141
+ return ['Must have at least one section'];
142
+ var errors = [];
143
+ // Ensure all the headings are valid
144
+ for (var _i = 0, headings_1 = headings; _i < headings_1.length; _i++) {
145
+ var heading = headings_1[_i];
146
+ if (options.validSections.indexOf(heading) === -1)
147
+ errors.push("Invalid section: ".concat(heading));
148
+ }
149
+ // Ensure we have all required headings
150
+ for (var _a = 0, _b = options.requiredSections; _a < _b.length; _a++) {
151
+ var requiredSection = _b[_a];
152
+ if (parsedDescription[requiredSection] === undefined)
153
+ errors.push("Missing section: ".concat(requiredSection));
154
+ }
155
+ return errors;
139
156
  },
140
157
  getCombinedDescription: function (mergeRequests, headingPrefix) {
141
158
  if (headingPrefix === void 0) { headingPrefix = '#'; }
@@ -143,7 +160,7 @@ exports.Descriptions = {
143
160
  .filter(function (mr) { return mr.status === 'merged'; })
144
161
  .map(function (mr) { return toObject(mr.description.split('\n'), headingPrefix); });
145
162
  var obj = {};
146
- var _loop_1 = function (descriptionObj) {
163
+ var _loop_2 = function (descriptionObj) {
147
164
  Object.keys(descriptionObj).forEach(function (key) {
148
165
  if (!obj[key])
149
166
  obj[key] = '';
@@ -152,16 +169,16 @@ exports.Descriptions = {
152
169
  };
153
170
  for (var _i = 0, descriptionObjs_1 = descriptionObjs; _i < descriptionObjs_1.length; _i++) {
154
171
  var descriptionObj = descriptionObjs_1[_i];
155
- _loop_1(descriptionObj);
172
+ _loop_2(descriptionObj);
156
173
  }
157
174
  var description = '';
158
175
  var orderedHeadings = orderDescriptionHeadings(Object.keys(obj));
159
176
  orderedHeadings.forEach(function (key) {
160
- if (key === 'notes')
177
+ if (key === Headings.Notes)
161
178
  return;
162
179
  if (!obj[key])
163
180
  return;
164
- description += '\n' + headingPrefix + ' ' + key.charAt(0).toUpperCase() + key.slice(1) + '\n';
181
+ description += '\n' + headingPrefix + ' ' + key + '\n';
165
182
  description += obj[key];
166
183
  });
167
184
  return description;
@@ -173,7 +190,7 @@ exports.Descriptions = {
173
190
  .filter(function (mr) { return mr.status === 'merged'; })
174
191
  .map(function (mr) { return toObject(mr.description.split('\n'), '#'); });
175
192
  var combinedObj = {};
176
- var _loop_2 = function (descriptionObj) {
193
+ var _loop_3 = function (descriptionObj) {
177
194
  Object.keys(descriptionObj).forEach(function (key) {
178
195
  if (!combinedObj[key])
179
196
  combinedObj[key] = {};
@@ -189,18 +206,18 @@ exports.Descriptions = {
189
206
  // For each property in each MR object, calculate it's H2 heading objects
190
207
  for (var _i = 0, descriptionObjs_2 = descriptionObjs; _i < descriptionObjs_2.length; _i++) {
191
208
  var descriptionObj = descriptionObjs_2[_i];
192
- _loop_2(descriptionObj);
209
+ _loop_3(descriptionObj);
193
210
  }
194
211
  var orderedHeadings = orderDescriptionHeadings(Object.keys(combinedObj));
195
212
  // Build our description
196
213
  var description = '';
197
214
  orderedHeadings.forEach(function (key) {
198
- if (key === 'notes')
215
+ if (key === Headings.Notes)
199
216
  return;
200
- description += '\n# ' + key.charAt(0).toUpperCase() + key.slice(1) + '\n';
217
+ description += '\n# ' + key + '\n';
201
218
  Object.keys(combinedObj[key]).forEach(function (subKey) {
202
- if (key !== 'dependencies' && key !== 'testing')
203
- description += '\n## ' + subKey.charAt(0).toUpperCase() + subKey.slice(1) + '\n';
219
+ if (key !== Headings.Dependencies && key !== Headings.Testing)
220
+ description += '\n## ' + subKey + '\n';
204
221
  description += combinedObj[key][subKey];
205
222
  });
206
223
  });
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@clickview/ship-it",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Release Manager",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
7
7
  "ship-it": "./lib/src/index.js"
8
8
  },
9
9
  "scripts": {
10
- "start": "npm run lint && ts-node --files src/index.ts",
10
+ "start": "npm run lint && ts-node --files src/index.ts",
11
11
  "build": "npm run lint && tsc -p . && tsc-alias -p tsconfig.json",
12
12
  "lint": "eslint . --ext .ts"
13
13
  },
@@ -21,6 +21,7 @@
21
21
  "@gitbeaker/node": "35.6.0",
22
22
  "chalk": "4.1.2",
23
23
  "commander": "9.1.0",
24
+ "fast-csv": "4.3.6",
24
25
  "fs-extra": "10.0.1",
25
26
  "inversify": "6.0.1",
26
27
  "lodash": "4.17.21",