@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,63 @@
1
+ import { listBuilds, pad } from '../ci_utils.js';
2
+
3
+ const kHealthKeys = [
4
+ 'success',
5
+ 'pending',
6
+ 'aborted',
7
+ 'failed',
8
+ 'unstable'
9
+ ];
10
+
11
+ class Health {
12
+ constructor(builds) {
13
+ for (const key of kHealthKeys) {
14
+ this[key] = builds[key].length;
15
+ this.count = builds.count;
16
+ }
17
+ }
18
+
19
+ // Produces a row for https://github.com/nodejs/reliability#ci-health-history
20
+ formatAsMarkdown() {
21
+ const { success, pending, aborted, failed, unstable, count } = this;
22
+ const rate = `${(success / (count - pending - aborted) * 100).toFixed(2)}%`;
23
+ // eslint-disable-next-line max-len
24
+ let result = '| UTC Time | RUNNING | SUCCESS | UNSTABLE | ABORTED | FAILURE | Green Rate |\n';
25
+ // eslint-disable-next-line max-len
26
+ result += '| ---------------- | ------- | ------- | -------- | ------- | ------- | ---------- |\n';
27
+ const time = new Date().toISOString().slice(0, 16).replace('T', ' ');
28
+ result += `| ${time} | ${pad(pending, 7)} | ${pad(success, 8)}|`;
29
+ result += ` ${pad(unstable, 8)} | ${pad(aborted, 7)} | ${pad(failed, 7)} |`;
30
+ result += ` ${pad(rate, 10)} |\n`;
31
+ return result;
32
+ }
33
+ }
34
+
35
+ export class HealthBuild {
36
+ constructor(cli, request, ciType, builds) {
37
+ this.cli = cli;
38
+ this.request = request;
39
+ this.type = 'health';
40
+ this.ciType = ciType;
41
+ this.builds = builds;
42
+ this.name = 'health';
43
+ }
44
+
45
+ async getResults() {
46
+ if (!this.builds) {
47
+ this.builds = await listBuilds(this.cli, this.request, this.ciType);
48
+ }
49
+ this.health = new Health(this.builds);
50
+ }
51
+
52
+ formatAsJson() {
53
+ return this.health;
54
+ }
55
+
56
+ formatAsMarkdown() {
57
+ return this.health.formatAsMarkdown();
58
+ }
59
+
60
+ display() {
61
+ this.cli.log(this.formatAsMarkdown());
62
+ }
63
+ }
@@ -0,0 +1,114 @@
1
+ import qs from 'node:querystring';
2
+
3
+ import { CI_DOMAIN } from '../ci_type_parser.js';
4
+ import Cache from '../../cache.js';
5
+ import CIFailureParser from '../ci_failure_parser.js';
6
+
7
+ const {
8
+ FAILURE_TYPES: { NCU_FAILURE },
9
+ FAILURE_CONSTRUCTORS: {
10
+ [NCU_FAILURE]: NCUFailure
11
+ },
12
+ CIResult
13
+ } = CIFailureParser;
14
+
15
+ export class Job {
16
+ constructor(cli, request, path, tree) {
17
+ this.cli = cli;
18
+ this.request = request;
19
+ this.path = path;
20
+ this.tree = tree;
21
+ }
22
+
23
+ get jobUrl() {
24
+ const { path } = this;
25
+ return `https://${CI_DOMAIN}/${path}`;
26
+ }
27
+
28
+ get apiUrl() {
29
+ const { tree, jobUrl } = this;
30
+ const query = tree ? `?tree=${qs.escape(tree)}` : '';
31
+ return `${jobUrl}api/json${query}`;
32
+ }
33
+
34
+ get consoleUrl() {
35
+ const { path } = this;
36
+ return `https://${CI_DOMAIN}/${path}consoleText`;
37
+ }
38
+
39
+ get consoleUIUrl() {
40
+ const { path } = this;
41
+ return `https://${CI_DOMAIN}/${path}console`;
42
+ }
43
+
44
+ async getBuildData(type = 'Build') {
45
+ const { cli, path } = this;
46
+ cli.startSpinner(`Querying data for ${path}`);
47
+ const data = await this.getAPIData();
48
+ cli.stopSpinner(`${type} data downloaded`);
49
+ return data;
50
+ }
51
+
52
+ getCause(actions) {
53
+ if (actions && actions.find(item => item.causes)) {
54
+ const action = actions.find(item => item.causes);
55
+ return action.causes[0];
56
+ }
57
+ }
58
+
59
+ async getAPIData() {
60
+ const { apiUrl, cli, request, path } = this;
61
+ cli.updateSpinner(`Querying API for ${path}`);
62
+ return request.json(apiUrl);
63
+ }
64
+
65
+ async getConsoleText() {
66
+ const { cli, consoleUrl, request, path } = this;
67
+ cli.updateSpinner(`Querying console text for ${path}`);
68
+ const data = await request.text(consoleUrl);
69
+ return data.replace(/\r/g, '');
70
+ }
71
+
72
+ getCacheKey() {
73
+ return this.path
74
+ .replace(/job\//, '')
75
+ .replace(/\//g, '-')
76
+ .replace(/-$/, '');
77
+ }
78
+
79
+ async parseConsoleText() {
80
+ let text;
81
+ try {
82
+ text = await this.getConsoleText();
83
+ } catch (err) {
84
+ this.failures = [
85
+ new NCUFailure({
86
+ url: this.consoleUrl, builtOn: this.builtOn
87
+ }, err.message)
88
+ ];
89
+ return this.failures;
90
+ }
91
+
92
+ const parser = new CIFailureParser(this, text);
93
+ let results = parser.parse();
94
+ if (!results) {
95
+ results = [
96
+ new CIResult({ url: this.jobUrl, builtOn: this.builtOn }, 'Unknown')
97
+ ];
98
+ }
99
+
100
+ this.failures = results;
101
+ return results;
102
+ }
103
+ }
104
+
105
+ // TODO(joyeecheung): do not cache pending jobs
106
+ export const jobCache = new Cache();
107
+ jobCache.wrap(Job, {
108
+ getConsoleText() {
109
+ return { key: this.getCacheKey(), ext: '.txt' };
110
+ },
111
+ getAPIData() {
112
+ return { key: this.getCacheKey(), ext: '.json' };
113
+ }
114
+ });
@@ -0,0 +1,35 @@
1
+ import { LINTER_TREE } from '../jenkins_constants.js';
2
+ import CIFailureParser from '../ci_failure_parser.js';
3
+ import { Job } from './job.js';
4
+
5
+ const {
6
+ FAILURE_TYPES: { NCU_FAILURE },
7
+ FAILURE_CONSTRUCTORS: {
8
+ [NCU_FAILURE]: NCUFailure
9
+ }
10
+ } = CIFailureParser;
11
+
12
+ export class LinterBuild extends Job {
13
+ constructor(cli, request, jobName, id) {
14
+ const path = `job/${jobName}/${id}/`;
15
+ const tree = LINTER_TREE;
16
+ super(cli, request, path, tree);
17
+
18
+ this.failures = [];
19
+ this.builtOn = undefined;
20
+ }
21
+
22
+ async getResults() {
23
+ let data;
24
+ try {
25
+ data = await this.getAPIData();
26
+ } catch (err) {
27
+ this.failures = [
28
+ new NCUFailure(this, err.message)
29
+ ];
30
+ return this.failures;
31
+ }
32
+ this.builtOn = data.builtOn;
33
+ return this.parseConsoleText();
34
+ }
35
+ }
@@ -0,0 +1,89 @@
1
+ import { statusType } from '../ci_utils.js';
2
+ import { flatten } from '../../utils.js';
3
+ import { BUILD_TREE } from '../jenkins_constants.js';
4
+ import CIFailureParser from '../ci_failure_parser.js';
5
+ import { Job } from './job.js';
6
+ import { TestRun } from './test_run.js';
7
+
8
+ const {
9
+ FAILURE_TYPES: {
10
+ BUILD_FAILURE,
11
+ NCU_FAILURE
12
+ },
13
+ FAILURE_CONSTRUCTORS: {
14
+ [BUILD_FAILURE]: BuildFailure,
15
+ [NCU_FAILURE]: NCUFailure
16
+ }
17
+ } = CIFailureParser;
18
+
19
+ export class NormalBuild extends Job {
20
+ constructor(cli, request, jobName, id) {
21
+ const path = `job/${jobName}/${id}/`;
22
+ const tree = BUILD_TREE;
23
+ super(cli, request, path, tree);
24
+
25
+ this.failures = [];
26
+ this.builtOn = undefined;
27
+ }
28
+
29
+ async getResults() {
30
+ const { cli, request } = this;
31
+
32
+ let data;
33
+ try {
34
+ data = await this.getAPIData();
35
+ } catch (err) {
36
+ this.failures = [
37
+ new NCUFailure({ url: this.apiUrl }, err.message)
38
+ ];
39
+ return this.failures;
40
+ }
41
+
42
+ const { result, runs, builtOn } = data;
43
+ this.builtOn = builtOn;
44
+
45
+ if (result !== statusType.FAILURE) {
46
+ this.failures = [];
47
+ return this.failures;
48
+ }
49
+
50
+ if (!runs) return [];
51
+
52
+ if (!runs.length) {
53
+ this.failures = [
54
+ new BuildFailure(
55
+ { url: this.jobUrl, builtOn }, 'Failed to trigger runs'
56
+ )
57
+ ];
58
+ return this.failures;
59
+ }
60
+
61
+ const failed = runs.filter(run => {
62
+ return run.result === statusType.FAILURE;
63
+ });
64
+
65
+ if (!failed.length) {
66
+ return this.parseConsoleText();
67
+ }
68
+
69
+ const tests = failed.map(({ url }) => new TestRun(cli, request, url));
70
+
71
+ // Skip runs that are not actually triggered by this job
72
+ await Promise.all(tests.map(run => run.getData()));
73
+ const causes = tests.map(run => run.cause);
74
+ const actualRuns = tests.filter((_, index) => {
75
+ const upstream = causes[index].upstreamBuild;
76
+ if (!upstream) {
77
+ return true;
78
+ } else {
79
+ return this.jobUrl.includes(upstream + '');
80
+ }
81
+ });
82
+
83
+ const failures = await Promise.all(
84
+ actualRuns.map(run => run.getResults())
85
+ );
86
+ this.failures = flatten(failures);
87
+ return this.failures;
88
+ }
89
+ }
@@ -0,0 +1,101 @@
1
+ import { PR_TREE } from '../jenkins_constants.js';
2
+ import CIFailureParser from '../ci_failure_parser.js';
3
+ import { TestBuild } from './test_build.js';
4
+ import { CommitBuild } from './commit_build.js';
5
+
6
+ const {
7
+ FAILURE_TYPES: {
8
+ BUILD_FAILURE,
9
+ NCU_FAILURE
10
+ },
11
+ FAILURE_CONSTRUCTORS: {
12
+ [BUILD_FAILURE]: BuildFailure,
13
+ [NCU_FAILURE]: NCUFailure
14
+ }
15
+ } = CIFailureParser;
16
+
17
+ export class PRBuild extends TestBuild {
18
+ constructor(cli, request, id) {
19
+ const path = `job/node-test-pull-request/${id}/`;
20
+ const tree = PR_TREE;
21
+ super(cli, request, path, tree);
22
+
23
+ this.commitBuild = null;
24
+ }
25
+
26
+ // Get the failures and their reasons of this build
27
+ async getResults() {
28
+ const { cli, request } = this;
29
+
30
+ let data;
31
+ try {
32
+ data = await this.getBuildData();
33
+ } catch (err) {
34
+ this.failures = [
35
+ new NCUFailure({ url: this.apiUrl }, err.message)
36
+ ];
37
+ return this.failures;
38
+ }
39
+ const {
40
+ result, subBuilds, changeSet, actions, timestamp
41
+ } = data;
42
+
43
+ // No builds found.
44
+ if (data.status === '404') {
45
+ const failure = new BuildFailure(this, 'No builds found for PR');
46
+ this.failures = [failure];
47
+ return {
48
+ result: data.result,
49
+ builds: { failed: [], aborted: [], pending: [], unstable: [] },
50
+ failures: this.failures
51
+ };
52
+ }
53
+
54
+ this.setBuildData(data);
55
+
56
+ // No sub build at all
57
+ const commitBuild = subBuilds[0];
58
+ if (!commitBuild) {
59
+ const failure = new BuildFailure(
60
+ this, 'Failed to trigger node-test-commit'
61
+ );
62
+ Object.assign(failure, {
63
+ source: this.sourceURL,
64
+ upstream: this.jobUrl,
65
+ builtOn: this.builtOn
66
+ });
67
+ this.failures = [failure];
68
+ return { result, builds: {}, failures: this.failures };
69
+ }
70
+
71
+ // Get result from the sub build
72
+ // assert.strictEqual(commitBuild.jobName, 'node-test-commit');
73
+ const allBuilds = commitBuild.build.subBuilds;
74
+ // TODO: fetch result, builtOn, timestamp in the commit build's own data
75
+ // ..or maybe they do not worth an additional API call?
76
+ // Note that we have to pass the actions down to detect resume builds.
77
+ const buildData = {
78
+ result, subBuilds: allBuilds, changeSet, actions, timestamp
79
+ };
80
+ const commitBuildId = commitBuild.buildNumber;
81
+ this.commitBuild = new CommitBuild(cli, request, commitBuildId);
82
+ const { builds, failures } = await this.commitBuild.getResults(buildData);
83
+
84
+ // Set up aliases for display
85
+ this.builds = builds;
86
+ this.failures = failures;
87
+ return { result, builds, failures };
88
+ }
89
+
90
+ formatAsMarkdown() {
91
+ if (!this.commitBuild) {
92
+ let result = 'Failed to trigger node-test-commit';
93
+ if (this.builtOn) {
94
+ result += ` on ${this.builtOn}`;
95
+ }
96
+ result += `\n\nURL: ${this.jobUrl}`;
97
+ return result;
98
+ }
99
+ return super.formatAsMarkdown();
100
+ }
101
+ }
@@ -0,0 +1,186 @@
1
+ import chalk from 'chalk';
2
+
3
+ import { shortSha } from '../../utils.js';
4
+ import {
5
+ fold,
6
+ getNodeName,
7
+ statusType
8
+ } from '../ci_utils.js';
9
+ import { CI_DOMAIN } from '../ci_type_parser.js';
10
+ import { Job } from './job.js';
11
+
12
+ const resultName = (result) => {
13
+ return result === null ? 'PENDING' : result.toUpperCase();
14
+ };
15
+
16
+ const getUrl = (path) => {
17
+ const urlPath = path.replace(`https://${CI_DOMAIN}/`, '').replace('api/json', '');
18
+ return `https://${CI_DOMAIN}/${urlPath}`;
19
+ };
20
+
21
+ export class TestBuild extends Job {
22
+ constructor(cli, request, path, tree) {
23
+ super(cli, request, path, tree);
24
+
25
+ // Should be assigned in getResults()
26
+ this.result = null;
27
+ this.params = {};
28
+ this.change = {};
29
+ this.date = undefined;
30
+ this.builds = {
31
+ failed: [], aborted: [], pending: [], unstable: []
32
+ };
33
+ this.failures = [];
34
+ this.builtOn = undefined;
35
+ }
36
+
37
+ setBuildData({ result, changeSet, actions, timestamp, builtOn }) {
38
+ const params = actions.find(item => typeof item.parameters === 'object');
39
+ params.parameters.forEach(pair => {
40
+ this.params[pair.name] = pair.value;
41
+ });
42
+
43
+ this.change = changeSet.items[0] || {};
44
+ this.date = new Date(timestamp);
45
+ this.result = result;
46
+ this.builtOn = builtOn;
47
+ }
48
+
49
+ setDailyBuildData({ result, changeSet, timestamp, builtOn }) {
50
+ this.change = changeSet.items[0] || {};
51
+ this.date = new Date(timestamp);
52
+ this.result = result;
53
+ this.builtOn = builtOn;
54
+ }
55
+
56
+ get sourceURL() {
57
+ const { params } = this;
58
+
59
+ if (params.PR_ID) { // from a node-test-pull-request build
60
+ const owner = params.TARGET_GITHUB_ORG;
61
+ const repo = params.TARGET_REPO_NAME;
62
+ const prid = params.PR_ID;
63
+ return `https://github.com/${owner}/${repo}/pull/${prid}/`;
64
+ }
65
+
66
+ if (params.GITHUB_ORG) { // from a node-test-commit build
67
+ const owner = params.GITHUB_ORG;
68
+ const repo = params.REPO_NAME;
69
+ const prm = params.GIT_REMOTE_REF.match(/refs\/pull\/(\d+)\/head/);
70
+ if (prm) {
71
+ return `https://github.com/${owner}/${repo}/pull/${prm[1]}/`;
72
+ } else {
73
+ const result =
74
+ `https://api.github.com/repos/${owner}/${repo}/git/` +
75
+ params.GIT_REMOTE_REF;
76
+ return result;
77
+ }
78
+ }
79
+ }
80
+
81
+ get commit() {
82
+ const { change } = this;
83
+ if (!change.commitId) {
84
+ return 'Unknown';
85
+ }
86
+ return `[${shortSha(change.commitId)}] ${change.msg}`;
87
+ }
88
+
89
+ get author() {
90
+ const { change } = this;
91
+ if (!change.author) {
92
+ return 'Unknown';
93
+ }
94
+ return `${change.author.fullName} <${change.authorEmail}>`;
95
+ }
96
+
97
+ displayHeader() {
98
+ const { cli, result, change } = this;
99
+ cli.separator('Summary');
100
+ cli.table('Result', resultName(result));
101
+ cli.table('URL', this.jobUrl);
102
+ cli.table('Source', this.sourceURL);
103
+ cli.table('Commit', this.commit);
104
+ cli.table('Date', change.date);
105
+ cli.table('Author', this.author);
106
+ }
107
+
108
+ displayFailure(failure) {
109
+ const { cli } = this;
110
+ const { url, reason } = failure;
111
+ cli.separator(getNodeName(url));
112
+ cli.table('URL', url);
113
+ if (failure.type) {
114
+ cli.table('Type', failure.type);
115
+ }
116
+ if (failure.builtOn) {
117
+ cli.table('Built On', failure.builtOn);
118
+ }
119
+ if (!reason.includes('\n') && reason.length < 40) {
120
+ cli.table('Reason', chalk.red(reason));
121
+ } else {
122
+ cli.table('Reason', '');
123
+ const lines = reason.split('\n');
124
+ cli.log(` ${chalk.red(lines[0])}`);
125
+ for (let i = 1; i < lines.length; ++i) {
126
+ cli.log(` ${lines[i]}`);
127
+ }
128
+ }
129
+ }
130
+
131
+ displayBuilds() {
132
+ const { cli, failures, builds } = this;
133
+ for (const failure of failures) {
134
+ if (failure !== undefined) {
135
+ this.displayFailure(failure);
136
+ }
137
+ }
138
+ cli.separator('Other builds');
139
+ for (const aborted of builds.aborted) {
140
+ cli.table('Aborted', getUrl(aborted.url));
141
+ }
142
+ for (const pending of builds.pending) {
143
+ cli.table('Pending', getUrl(pending.url));
144
+ }
145
+ for (const unstable of builds.unstable) {
146
+ cli.table('Unstable', getUrl(unstable.url));
147
+ }
148
+ }
149
+
150
+ display() {
151
+ this.displayHeader();
152
+ this.displayBuilds();
153
+ }
154
+
155
+ formatAsMarkdown() {
156
+ if (this.result === statusType.SUCCESS) {
157
+ return `Job ${this.jobUrl} is green.`;
158
+ }
159
+ const { failures } = this;
160
+ let output = `Failures in job ${this.jobUrl}\n\n`;
161
+ for (const failure of failures) {
162
+ if (failure === undefined) continue;
163
+ output += `#### [${getNodeName(failure.url)}](${failure.url})`;
164
+ if (!failure.reason.includes('\n') && failure.reason.length < 20) {
165
+ const builtOn = failure.builtOn ? `On ${failure.builtOn}: ` : '';
166
+ output += `\n\n${builtOn}${failure.reason}\n`;
167
+ } else {
168
+ output += '\n\n';
169
+ const builtOn = failure.builtOn ? ` on ${failure.builtOn}:` : '';
170
+ output += fold(`See failures${builtOn}`, failure.reason) + '\n\n';
171
+ }
172
+ }
173
+ return output;
174
+ }
175
+
176
+ formatAsJson() {
177
+ const { jobUrl, failures, sourceURL } = this;
178
+
179
+ const result = failures.map(item => Object.assign({
180
+ source: sourceURL,
181
+ upstream: jobUrl
182
+ }, item));
183
+
184
+ return JSON.parse(JSON.stringify(result));
185
+ }
186
+ }
@@ -0,0 +1,41 @@
1
+ import { RUN_TREE } from '../jenkins_constants.js';
2
+ import { getPath } from '../ci_utils.js';
3
+ import CIFailureParser from '../ci_failure_parser.js';
4
+ import { Job } from './job.js';
5
+
6
+ const {
7
+ FAILURE_TYPES: { NCU_FAILURE },
8
+ FAILURE_CONSTRUCTORS: {
9
+ [NCU_FAILURE]: NCUFailure
10
+ }
11
+ } = CIFailureParser;
12
+
13
+ export class TestRun extends Job {
14
+ constructor(cli, request, url) {
15
+ const path = getPath(url);
16
+ const tree = RUN_TREE;
17
+ super(cli, request, path, tree);
18
+
19
+ this.failures = [];
20
+ this.cause = {};
21
+ this.builtOn = undefined;
22
+ }
23
+
24
+ async getData() {
25
+ let data;
26
+ try {
27
+ data = await this.getAPIData();
28
+ } catch (err) {
29
+ this.failures = [
30
+ new NCUFailure({ url: this.apiUrl }, err.message)
31
+ ];
32
+ return this.failures;
33
+ }
34
+ this.causes = this.getCause(data.actions) || {};
35
+ this.builtOn = data.builtOn;
36
+ }
37
+
38
+ async getResults() {
39
+ return this.parseConsoleText();
40
+ }
41
+ }