@node-core/utils 4.0.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.
Files changed (98) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +158 -0
  3. package/bin/get-metadata.js +11 -0
  4. package/bin/git-node.js +30 -0
  5. package/bin/ncu-ci.js +600 -0
  6. package/bin/ncu-config.js +101 -0
  7. package/bin/ncu-team.js +76 -0
  8. package/components/git/backport.js +70 -0
  9. package/components/git/epilogue.js +18 -0
  10. package/components/git/land.js +223 -0
  11. package/components/git/metadata.js +94 -0
  12. package/components/git/release.js +99 -0
  13. package/components/git/security.js +35 -0
  14. package/components/git/status.js +32 -0
  15. package/components/git/sync.js +24 -0
  16. package/components/git/v8.js +121 -0
  17. package/components/git/vote.js +84 -0
  18. package/components/git/wpt.js +87 -0
  19. package/components/metadata.js +49 -0
  20. package/lib/auth.js +133 -0
  21. package/lib/backport_session.js +302 -0
  22. package/lib/cache.js +107 -0
  23. package/lib/cherry_pick.js +304 -0
  24. package/lib/ci/build-types/benchmark_run.js +72 -0
  25. package/lib/ci/build-types/citgm_build.js +194 -0
  26. package/lib/ci/build-types/citgm_comparison_build.js +174 -0
  27. package/lib/ci/build-types/commit_build.js +112 -0
  28. package/lib/ci/build-types/daily_build.js +24 -0
  29. package/lib/ci/build-types/fanned_build.js +87 -0
  30. package/lib/ci/build-types/health_build.js +63 -0
  31. package/lib/ci/build-types/job.js +114 -0
  32. package/lib/ci/build-types/linter_build.js +35 -0
  33. package/lib/ci/build-types/normal_build.js +89 -0
  34. package/lib/ci/build-types/pr_build.js +101 -0
  35. package/lib/ci/build-types/test_build.js +186 -0
  36. package/lib/ci/build-types/test_run.js +41 -0
  37. package/lib/ci/ci_failure_parser.js +325 -0
  38. package/lib/ci/ci_type_parser.js +203 -0
  39. package/lib/ci/ci_utils.js +106 -0
  40. package/lib/ci/failure_aggregator.js +152 -0
  41. package/lib/ci/jenkins_constants.js +28 -0
  42. package/lib/ci/run_ci.js +120 -0
  43. package/lib/cli.js +192 -0
  44. package/lib/collaborators.js +140 -0
  45. package/lib/config.js +72 -0
  46. package/lib/figures.js +7 -0
  47. package/lib/file.js +43 -0
  48. package/lib/github/templates/next-security-release.md +97 -0
  49. package/lib/github/tree.js +162 -0
  50. package/lib/landing_session.js +506 -0
  51. package/lib/links.js +123 -0
  52. package/lib/mergeable_state.js +3 -0
  53. package/lib/metadata_gen.js +61 -0
  54. package/lib/pr_checker.js +605 -0
  55. package/lib/pr_data.js +115 -0
  56. package/lib/pr_summary.js +62 -0
  57. package/lib/prepare_release.js +772 -0
  58. package/lib/prepare_security.js +117 -0
  59. package/lib/proxy.js +21 -0
  60. package/lib/queries/DefaultBranchRef.gql +8 -0
  61. package/lib/queries/LastCommit.gql +16 -0
  62. package/lib/queries/PR.gql +37 -0
  63. package/lib/queries/PRComments.gql +27 -0
  64. package/lib/queries/PRCommits.gql +45 -0
  65. package/lib/queries/PRs.gql +25 -0
  66. package/lib/queries/Reviews.gql +23 -0
  67. package/lib/queries/SearchIssue.gql +51 -0
  68. package/lib/queries/Team.gql +22 -0
  69. package/lib/queries/TreeEntries.gql +12 -0
  70. package/lib/queries/VotePRInfo.gql +28 -0
  71. package/lib/release/utils.js +53 -0
  72. package/lib/request.js +185 -0
  73. package/lib/review_state.js +5 -0
  74. package/lib/reviews.js +178 -0
  75. package/lib/run.js +106 -0
  76. package/lib/session.js +415 -0
  77. package/lib/sync_session.js +15 -0
  78. package/lib/team_info.js +95 -0
  79. package/lib/update-v8/applyNodeChanges.js +49 -0
  80. package/lib/update-v8/backport.js +258 -0
  81. package/lib/update-v8/commitUpdate.js +26 -0
  82. package/lib/update-v8/common.js +35 -0
  83. package/lib/update-v8/constants.js +86 -0
  84. package/lib/update-v8/index.js +56 -0
  85. package/lib/update-v8/majorUpdate.js +171 -0
  86. package/lib/update-v8/minorUpdate.js +105 -0
  87. package/lib/update-v8/updateMaintainingDependencies.js +34 -0
  88. package/lib/update-v8/updateV8Clone.js +53 -0
  89. package/lib/update-v8/updateVersionNumbers.js +122 -0
  90. package/lib/update-v8/util.js +62 -0
  91. package/lib/user.js +4 -0
  92. package/lib/user_status.js +5 -0
  93. package/lib/utils.js +66 -0
  94. package/lib/verbosity.js +26 -0
  95. package/lib/voting_session.js +136 -0
  96. package/lib/wpt/index.js +243 -0
  97. package/lib/wpt/templates/README.md +16 -0
  98. package/package.json +69 -0
@@ -0,0 +1,325 @@
1
+ function unique(arr) {
2
+ return Array.from(new Set(arr).values());
3
+ }
4
+
5
+ function pickContext(matches, text, {
6
+ index = 0, // which one in the matches should be picked
7
+ contextBefore = 0,
8
+ contextAfter = 0
9
+ }) {
10
+ if (index < 0) { index = matches.length + index; }
11
+ const match = matches[index];
12
+
13
+ const offset = text.indexOf(match);
14
+ let after = offset + match.length;
15
+ for (let i = 0; i < contextAfter; ++i) {
16
+ const next = text.indexOf('\n', after + 1);
17
+ after = next > 0 ? next : after;
18
+ }
19
+ let before = offset;
20
+ for (let i = 0; i < contextBefore; ++i) {
21
+ const next = text.lastIndexOf('\n', before - 1);
22
+ before = next > 0 ? next : before;
23
+ }
24
+
25
+ return text.slice(before, after);
26
+ }
27
+
28
+ const BUILD_FAILURE = 'BUILD_FAILURE';
29
+ const JS_TEST_FAILURE = 'JS_TEST_FAILURE';
30
+ const CC_TEST_FAILURE = 'CC_TEST_FAILURE';
31
+ const JENKINS_FAILURE = 'JENKINS_FAILURE';
32
+ const GIT_FAILURE = 'GIT_FAILURE';
33
+ const NCU_FAILURE = 'NCU_FAILURE';
34
+ const RESUME_FAILURE = 'RESUME_FAILURE';
35
+ const INFRA_FAILURE = 'INFRA_FAILURE';
36
+
37
+ const FAILURE_TYPES = {
38
+ BUILD_FAILURE, JS_TEST_FAILURE, CC_TEST_FAILURE,
39
+ JENKINS_FAILURE, GIT_FAILURE, NCU_FAILURE, RESUME_FAILURE,
40
+ INFRA_FAILURE
41
+ };
42
+
43
+ class CIResult {
44
+ constructor(ctx, reason) {
45
+ this.url = ctx.url || ctx.consoleUIUrl || ctx.jobUrl;
46
+ this.builtOn = ctx.builtOn;
47
+ this.reason = reason;
48
+ // Default: the first line is the highlight, we will slice
49
+ // the context to make it so.
50
+ // TODO: better highlights
51
+ this.highlight = 0;
52
+ }
53
+ }
54
+
55
+ // Usually need a fix to the build files
56
+ class BuildFailure extends CIResult {
57
+ constructor(ctx, reason) {
58
+ super(ctx, reason);
59
+ this.type = BUILD_FAILURE;
60
+ }
61
+ }
62
+
63
+ // Usually needs to fix something in the Jenkins agent (or just restart it)
64
+ class InfraFailure extends CIResult {
65
+ constructor(ctx, reason) {
66
+ super(ctx, reason);
67
+ this.type = INFRA_FAILURE;
68
+ }
69
+ }
70
+
71
+ // Usually needs a fix in the test or the core
72
+ class JSTestFailure extends CIResult {
73
+ constructor(ctx, reason) {
74
+ super(ctx, reason);
75
+ this.type = JS_TEST_FAILURE;
76
+ // Example: not ok 749 parallel/test-http-readable-data-event
77
+ this.file = this.reason.split('\n')[this.highlight].split(' ').pop();
78
+ this.severity = this.reason.match(/^\s+severity: (\w+)/m)[1];
79
+ }
80
+ }
81
+
82
+ // Usually needs a fix in the test or the core
83
+ class CCTestFailure extends CIResult {
84
+ constructor(ctx, reason) {
85
+ super(ctx, reason);
86
+ this.type = CC_TEST_FAILURE;
87
+ }
88
+ }
89
+
90
+ // Usually needs someone to log into the machines and fix it
91
+ class JenkinsFailure extends CIResult {
92
+ constructor(ctx, reason) {
93
+ super(ctx, reason);
94
+ this.type = JENKINS_FAILURE;
95
+ }
96
+ }
97
+
98
+ // Usually need a fix to the build scripts or in workers
99
+ class GitFailure extends CIResult {
100
+ constructor(ctx, reason) {
101
+ super(ctx, reason);
102
+ this.type = GIT_FAILURE;
103
+ }
104
+ }
105
+
106
+ // Failures in this tool, we wrap them to avoid exceptions when
107
+ // walking the CI
108
+ class NCUFailure extends CIResult {
109
+ constructor(ctx, reason) {
110
+ super(ctx, reason);
111
+ this.type = NCU_FAILURE;
112
+ }
113
+ }
114
+
115
+ // Refs: https://github.com/nodejs/build/issues/1496
116
+ class ResumeFailure extends CIResult {
117
+ constructor(ctx, reason) {
118
+ super(ctx, reason);
119
+ this.type = RESUME_FAILURE;
120
+ }
121
+ }
122
+
123
+ function failureMatcher(Failure, patterns, ctx, text) {
124
+ for (const pattern of patterns) {
125
+ const matches = text.match(pattern.pattern);
126
+ if (!matches) {
127
+ continue;
128
+ }
129
+ const reason = pickContext(matches, text, pattern.context).trim();
130
+ return [new Failure(ctx, reason)];
131
+ }
132
+ return null;
133
+ }
134
+
135
+ // The elements are ranked by priority
136
+ const FAILURE_FILTERS = [{
137
+ // NOTE(mmarchini): infra-related issues should have the highest priority, as
138
+ // they can cause other issues to happen.
139
+ filter(ctx, text) {
140
+ const patterns = [{
141
+ pattern: /Read-only file system/g,
142
+ context: { index: 0, contextBefore: 1, contextAfter: 0 }
143
+ },
144
+ {
145
+ pattern: /Device or resource busy/g,
146
+ context: { index: 0, contextBefore: 1, contextAfter: 0 }
147
+ },
148
+ {
149
+ pattern: /There is not enough space in the file system./g,
150
+ context: { index: 0, contextBefore: 1, contextAfter: 0 }
151
+ }
152
+ ];
153
+ return failureMatcher(InfraFailure, patterns, ctx, text);
154
+ }
155
+ }, {
156
+ // TODO: match indentation to avoid skipping context with '...'
157
+ filter(ctx, text) {
158
+ const pattern = /^not ok \d+[\s\S]+? {2}\.\.\.\r?\n/mg;
159
+ const matches = text.match(pattern);
160
+ if (!matches) {
161
+ return null;
162
+ }
163
+ const nonFlaky = matches.filter((m) => !m.includes('# TODO :'));
164
+ if (!nonFlaky.length) {
165
+ return null;
166
+ }
167
+ return unique(nonFlaky).map(
168
+ match => new JSTestFailure(ctx, match)
169
+ );
170
+ }
171
+ }, {
172
+ filter(ctx, text) {
173
+ const patterns = [{
174
+ pattern: /\[ {2}FAILED {2}\].+/g,
175
+ context: { index: 0, contextBefore: 5, contextAfter: 0 }
176
+ }];
177
+ return failureMatcher(CCTestFailure, patterns, ctx, text);
178
+ }
179
+ }, {
180
+ // VS compilation error
181
+ filter(ctx, text) {
182
+ const patterns = [{
183
+ pattern: /error C\d+:/mg,
184
+ context: { index: 0, contextBefore: 0, contextAfter: 5 }
185
+ }];
186
+ return failureMatcher(BuildFailure, patterns, ctx, text);
187
+ }
188
+ }, {
189
+ filter(ctx, text) {
190
+ const patterns = [{
191
+ pattern: /java\.io\.IOException.+/g,
192
+ context: { index: -1, contextBefore: 0, contextAfter: 5 }
193
+ }, {
194
+ pattern: /Build timed out/g,
195
+ context: { index: 0, contextBefore: 0, contextAfter: 1 }
196
+ }];
197
+ return failureMatcher(JenkinsFailure, patterns, ctx, text);
198
+ }
199
+ }, {
200
+ filter(ctx, text) {
201
+ const patterns = [{
202
+ pattern:
203
+ /Changes not staged for commit:[\s\S]+no changes added to commit/mg,
204
+ context: { index: 0, contextBefore: 0, contextAfter: 0 }
205
+ }, {
206
+ pattern:
207
+ // eslint-disable-next-line max-len
208
+ /error: Your local changes to the following files[\s\S]+Failed to merge in the changes./g,
209
+ context: { index: 0, contextBefore: 0, contextAfter: 0 }
210
+ }, {
211
+ pattern: /warning: failed to remove .+/g,
212
+ context: { index: 0, contextBefore: 0, contextAfter: 0 }
213
+ }];
214
+ return failureMatcher(GitFailure, patterns, ctx, text);
215
+ }
216
+ }, {
217
+ filter(ctx, text) {
218
+ const patterns = [{
219
+ pattern: /ERROR: Error fetching .+/g,
220
+ context: { index: 0, contextBefore: 0, contextAfter: 5 }
221
+ }, {
222
+ pattern: /hudson\.plugins\.git\.GitException+/g,
223
+ context: { index: 0, contextBefore: 0, contextAfter: 5 }
224
+ }, {
225
+ pattern: /Cannot rebase: .+/g,
226
+ context: { index: 0, contextBefore: 0, contextAfter: 1 }
227
+ }];
228
+ return failureMatcher(GitFailure, patterns, ctx, text);
229
+ }
230
+ }, {
231
+ filter(ctx, text) {
232
+ const patterns = [{
233
+ pattern: /sh: line /g,
234
+ context: { index: 0, contextBefore: 0, contextAfter: 1 }
235
+ }, {
236
+ pattern: /fatal error:/g,
237
+ context: { index: 0, contextBefore: 0, contextAfter: 1 }
238
+ }, {
239
+ pattern: /dtrace: failed to compile script/g,
240
+ context: { index: 0, contextBefore: 0, contextAfter: 1 }
241
+ }, {
242
+ pattern: /ERROR: .+/g,
243
+ // Pick the last one
244
+ context: { index: -1, contextBefore: 0, contextAfter: 5 }
245
+ }, {
246
+ // Pick the first one
247
+ pattern: /Error: .+/g,
248
+ context: { index: 0, contextBefore: 0, contextAfter: 5 }
249
+ }];
250
+ return failureMatcher(BuildFailure, patterns, ctx, text);
251
+ }
252
+ }, {
253
+ filter(ctx, text) {
254
+ const pattern = /fatal: .+/g;
255
+ const matches = text.match(pattern);
256
+ if (!matches) {
257
+ return null;
258
+ }
259
+ const reason = unique(matches).join('\n');
260
+ return [new BuildFailure(ctx, reason)];
261
+ }
262
+ }, {
263
+ filter(ctx, text) {
264
+ const patterns = [{
265
+ pattern: /FATAL: .+/g,
266
+ context: { index: -1, contextBefore: 0, contextAfter: 5 }
267
+ }, {
268
+ pattern: /make.*: write error/mg,
269
+ context: { index: 0, contextBefore: 0, contextAfter: 3 }
270
+ }, {
271
+ pattern: /error: .+/g,
272
+ context: { index: 0, contextBefore: 0, contextAfter: 5 }
273
+ }, {
274
+ pattern: /Makefile:.+failed/g,
275
+ context: { index: 0, contextBefore: 0, contextAfter: 5 }
276
+ }, {
277
+ pattern: /make.*: .+ Error \d.*/g,
278
+ context: { index: 0, contextBefore: 0, contextAfter: 3 }
279
+ }, {
280
+ pattern: /warning: failed .+/g,
281
+ context: { index: 0, contextBefore: 0, contextAfter: 3 }
282
+ }];
283
+ return failureMatcher(BuildFailure, patterns, ctx, text);
284
+ }
285
+ }];
286
+
287
+ export default class CIFailureParser {
288
+ constructor(ctx, text) {
289
+ this.ctx = ctx;
290
+ this.text = text;
291
+ }
292
+
293
+ parse() {
294
+ const text = this.text;
295
+ for (const { filter } of FAILURE_FILTERS) {
296
+ const result = filter(this.ctx, text);
297
+ // TODO: we may want to concat certain types of failures
298
+ if (result) {
299
+ return result;
300
+ }
301
+ }
302
+ return null;
303
+ }
304
+ }
305
+
306
+ CIFailureParser.FAILURE_TYPES = FAILURE_TYPES;
307
+ CIFailureParser.FAILURE_CONSTRUCTORS = {
308
+ BUILD_FAILURE: BuildFailure,
309
+ JENKINS_FAILURE: JenkinsFailure,
310
+ JS_TEST_FAILURE: JSTestFailure,
311
+ CC_TEST_FAILURE: CCTestFailure,
312
+ GIT_FAILURE: GitFailure,
313
+ NCU_FAILURE: NCUFailure,
314
+ RESUME_FAILURE: ResumeFailure
315
+ };
316
+ CIFailureParser.CIResult = CIResult;
317
+ CIFailureParser.FAILURE_TYPES_NAME = {
318
+ BUILD_FAILURE: 'Build Failure',
319
+ JENKINS_FAILURE: 'Jenkins Failure',
320
+ JS_TEST_FAILURE: 'JSTest Failure',
321
+ CC_TEST_FAILURE: 'CCTest Failure',
322
+ GIT_FAILURE: 'Git Failure',
323
+ NCU_FAILURE: 'node-core-utils failure',
324
+ RESUME_FAILURE: 'resume failure'
325
+ };
@@ -0,0 +1,203 @@
1
+ import { parsePRFromURL } from '../links.js';
2
+ import PRData from '../pr_data.js';
3
+ import { ascending } from '../utils.js';
4
+
5
+ const CI_URL_RE = /\/\/ci\.nodejs\.org(\S+)/mg;
6
+ export const CI_DOMAIN = 'ci.nodejs.org';
7
+
8
+ // constants
9
+ const CITGM = 'CITGM';
10
+ const CITGM_NOBUILD = 'CITGM_NOBUILD';
11
+ const PR = 'PR';
12
+ const COMMIT = 'COMMIT';
13
+ const BENCHMARK = 'BENCHMARK';
14
+ const LIBUV = 'LIBUV';
15
+ const NOINTL = 'NOINTL';
16
+ const V8 = 'V8';
17
+ const LINTER = 'LINTER';
18
+ const DAILY_MASTER = 'DAILY_MASTER';
19
+
20
+ const CI_TYPE_ENUM = {
21
+ FULL_CI: 1 << 0,
22
+ JOB_CI: 1 << 2
23
+ };
24
+
25
+ export const CI_PROVIDERS = {
26
+ GITHUB: 'github-check',
27
+ NODEJS: 'nodejs'
28
+ };
29
+
30
+ const { JOB_CI, FULL_CI } = CI_TYPE_ENUM;
31
+
32
+ export const CI_TYPES = new Map([
33
+ [CITGM, {
34
+ name: 'CITGM',
35
+ jobName: 'citgm-smoker',
36
+ pattern: /job\/citgm-smoker\/(\d+)/,
37
+ type: JOB_CI
38
+ }],
39
+ [CITGM_NOBUILD, {
40
+ name: 'CITGM',
41
+ jobName: 'citgm-smoker-nobuild',
42
+ pattern: /job\/citgm-smoker-nobuild\/(\d+)/,
43
+ type: JOB_CI
44
+ }],
45
+ [PR, {
46
+ name: 'Full PR',
47
+ jobName: 'node-test-pull-request',
48
+ pattern: /job\/node-test-pull-request\/(\d+)/,
49
+ type: JOB_CI | FULL_CI
50
+ }],
51
+ [COMMIT, {
52
+ name: 'Full Commit',
53
+ jobName: 'node-test-commit',
54
+ pattern: /job\/node-test-commit\/(\d+)/,
55
+ type: JOB_CI | FULL_CI
56
+ }],
57
+ [BENCHMARK, {
58
+ name: 'Benchmark',
59
+ jobName: 'benchmark-node-micro-benchmarks',
60
+ pattern: /job\/benchmark-node-micro-benchmarks\/(\d+)/,
61
+ type: JOB_CI
62
+ }],
63
+ [LIBUV, {
64
+ name: 'libuv',
65
+ jobName: 'libuv-test-commit',
66
+ pattern: /job\/libuv-test-commit\/(\d+)/,
67
+ type: JOB_CI
68
+ }],
69
+ [NOINTL, {
70
+ name: 'No Intl',
71
+ jobName: 'node-test-commit-nointl',
72
+ pattern: /job\/node-test-commit-nointl\/(\d+)/,
73
+ type: JOB_CI
74
+ }],
75
+ [V8, {
76
+ name: 'V8',
77
+ jobName: 'node-test-commit-v8-linux',
78
+ pattern: /job\/node-test-commit-v8-linux\/(\d+)/,
79
+ type: JOB_CI
80
+ }],
81
+ [LINTER, {
82
+ name: 'Linter',
83
+ jobName: 'node-test-linter',
84
+ pattern: /job\/node-test-linter\/(\d+)/,
85
+ type: JOB_CI
86
+ }],
87
+ [DAILY_MASTER, {
88
+ name: 'Node Daily Master',
89
+ jobName: 'node-daily-master',
90
+ pattern: /job\/node-daily-master\/(\d+)/,
91
+ type: JOB_CI
92
+ }]
93
+ ]);
94
+
95
+ export function isFullCI(key) {
96
+ const data = CI_TYPES.get(key);
97
+ if (!data) {
98
+ return false;
99
+ }
100
+ return !!(data.type & FULL_CI);
101
+ }
102
+
103
+ // Given a ci.nodejs.org/*** link, parse the job type and ID
104
+ export function parseJobFromURL(url) {
105
+ if (typeof url !== 'string') {
106
+ return undefined;
107
+ }
108
+
109
+ for (const [type, info] of CI_TYPES) {
110
+ const match = url.match(info.pattern);
111
+ if (match) {
112
+ return {
113
+ link: url,
114
+ jobid: parseInt(match[1]),
115
+ type
116
+ };
117
+ }
118
+ }
119
+
120
+ return undefined;
121
+ }
122
+
123
+ /**
124
+ * Parse links of CI Jobs posted in a GitHub thread
125
+ */
126
+ export class JobParser {
127
+ /**
128
+ * @param {{bodyText: string, publishedAt: string}[]} thread
129
+ */
130
+ constructor(thread) {
131
+ this.thread = thread.sort(
132
+ (a, b) => ascending(a.publishedAt, b.publishedAt)
133
+ );
134
+ }
135
+
136
+ /**
137
+ * @returns {Map<string, {link: string, date: string, jobid: number}>}
138
+ */
139
+ parse() {
140
+ const thread = this.thread;
141
+ const result = new Map();
142
+ for (const c of thread) {
143
+ const text = c.bodyText;
144
+ if (!text.includes(CI_DOMAIN)) continue;
145
+ const jobs = this.parseText(text);
146
+ for (const job of jobs) {
147
+ // Always take the last one
148
+ // TODO(joyeecheung): exlcude links wrapped in `<del>`
149
+ result.set(job.type, {
150
+ link: job.link,
151
+ date: c.publishedAt,
152
+ jobid: job.jobid
153
+ });
154
+ }
155
+ }
156
+ return result;
157
+ }
158
+
159
+ /**
160
+ * @param {string} text
161
+ * @returns {{link: string, jobid: number, type: string}}
162
+ */
163
+ parseText(text) {
164
+ const links = text.match(CI_URL_RE);
165
+ if (!links) {
166
+ return [];
167
+ }
168
+
169
+ const result = [];
170
+ for (const link of links) {
171
+ const parsed = parseJobFromURL(`https:${link}`);
172
+ if (parsed) {
173
+ result.push(parsed);
174
+ }
175
+ }
176
+
177
+ return result;
178
+ }
179
+ }
180
+
181
+ JobParser.fromPR = async function(url, cli, request) {
182
+ const argv = parsePRFromURL(url);
183
+ if (!argv) {
184
+ return undefined;
185
+ }
186
+ const data = new PRData(argv, cli, request);
187
+ await data.getThreadData();
188
+ const thread = data.getThread();
189
+ return new JobParser(thread);
190
+ };
191
+
192
+ export const CI_TYPES_KEYS = {
193
+ CITGM,
194
+ CITGM_NOBUILD,
195
+ PR,
196
+ COMMIT,
197
+ BENCHMARK,
198
+ LIBUV,
199
+ V8,
200
+ NOINTL,
201
+ LINTER,
202
+ DAILY_MASTER
203
+ };
@@ -0,0 +1,106 @@
1
+ import qs from 'node:querystring';
2
+
3
+ import {
4
+ CI_DOMAIN,
5
+ parseJobFromURL,
6
+ CI_TYPES
7
+ } from './ci_type_parser.js';
8
+
9
+ export const statusType = {
10
+ SUCCESS: 'SUCCESS',
11
+ FAILURE: 'FAILURE',
12
+ ABORTED: 'ABORTED',
13
+ UNSTABLE: 'UNSTABLE'
14
+ };
15
+
16
+ export function getPath(url) {
17
+ return url.replace(`https://${CI_DOMAIN}/`, '').replace('api/json', '');
18
+ }
19
+
20
+ export function getNodeName(url) {
21
+ const re = /\/nodes=(.+?)\//;
22
+ if (re.test(url)) {
23
+ return url.match(re)[1];
24
+ }
25
+ const parts = url.split('/');
26
+ return parts[parts.length - 3];
27
+ }
28
+
29
+ export function fold(summary, code) {
30
+ const dataBlock = '```\n' + code + '\n```';
31
+ const summaryBlock = `\n<summary>${summary}</summary>\n`;
32
+ return `<details>${summaryBlock}\n${dataBlock}\n</details>`;
33
+ }
34
+
35
+ export function pad(any, length) {
36
+ return (any + '').padEnd(length);
37
+ }
38
+
39
+ export function markdownRow(...args) {
40
+ let result = '';
41
+ for (const item of args) {
42
+ result += `| ${item} `;
43
+ }
44
+ return result + '|\n';
45
+ }
46
+
47
+ function filterBuild(builds, type) {
48
+ return builds
49
+ .filter(build => build.result === type)
50
+ .map(build => parseJobFromURL(build.url));
51
+ }
52
+
53
+ export async function listBuilds(cli, request, type, since) {
54
+ // assert(type === COMMIT || type === PR)
55
+ const { jobName } = CI_TYPES.get(type);
56
+ const tree = 'builds[url,result,timestamp]';
57
+ const url = `https://${CI_DOMAIN}/job/${jobName}/api/json?tree=${qs.escape(tree)}`;
58
+
59
+ cli.startSpinner(`Querying ${url}`);
60
+
61
+ const result = await request.json(url);
62
+ let builds = result.builds;
63
+ if (since) {
64
+ builds = builds.filter(build => build.timestamp > since);
65
+ }
66
+ const failed = filterBuild(builds, statusType.FAILURE);
67
+ const aborted = filterBuild(builds, statusType.ABORTED);
68
+ const pending = filterBuild(builds, null);
69
+ const unstable = filterBuild(builds, statusType.UNSTABLE);
70
+ const success = filterBuild(builds, statusType.SUCCESS);
71
+ cli.stopSpinner('Done');
72
+
73
+ return {
74
+ success,
75
+ failed,
76
+ aborted,
77
+ pending,
78
+ unstable,
79
+ count: builds.length
80
+ };
81
+ }
82
+
83
+ export function getHighlight(f) {
84
+ if (!f.reason) {
85
+ f.reason = 'failure not found';
86
+ return f.reason;
87
+ }
88
+ return f.reason.split('\n')[f.highlight]
89
+ .replace(/not ok \d+ /, '')
90
+ .replace(
91
+ /JNLP4-connect connection from \S+/, 'JNLP4-connect connection from ...'
92
+ )
93
+ .replace(/FATAL: Could not checkout \w+/, 'FATAL: Could not checkout ...')
94
+ .replace(
95
+ /error: pathspec .+ did not match any file\(s\) known to git/,
96
+ 'error: pathspec ... did not match any file(s) known to git')
97
+ .replace(
98
+ /failed: no workspace for .+/,
99
+ 'failed: no workspace for ...'
100
+ )
101
+ .replace(
102
+ /fatal: loose object \w+ \(stored in .git\/objects\/.+\) is corrupt/,
103
+ 'fatal: loose object ... (stored in .git/objects/...) is corrupt')
104
+ .replace(/hudson\.plugins\.git\.GitException: /, '')
105
+ .replace(/java\.io\.IOException: /, '');
106
+ }