@ckeditor/ckeditor5-dev-ci 38.2.1 → 38.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
5
|
+
* For licensing, see LICENSE.md.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* eslint-env node */
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const { execSync } = require( 'child_process' );
|
|
13
|
+
const fetch = require( 'node-fetch' );
|
|
14
|
+
const minimist = require( 'minimist' );
|
|
15
|
+
const processJobStatuses = require( '../lib/process-job-statuses' );
|
|
16
|
+
|
|
17
|
+
// This script allows the creation of a new job within a workflow that will be executed
|
|
18
|
+
// in the end, when all other jobs will be finished or errored.
|
|
19
|
+
//
|
|
20
|
+
// Below, you can find an example workflow.
|
|
21
|
+
//
|
|
22
|
+
// ┌─────┐ ┌─────┐
|
|
23
|
+
// │Job A├────►│Job B├──────────┐
|
|
24
|
+
// └─────┘ └─────┘ ▼
|
|
25
|
+
// ┌────────┐
|
|
26
|
+
// │Notifier│
|
|
27
|
+
// └────────┘
|
|
28
|
+
// ┌─────┐ ▲
|
|
29
|
+
// │Job C├──────────────────────┘
|
|
30
|
+
// └─────┘
|
|
31
|
+
//
|
|
32
|
+
// Job A triggers Job B, and Job C has no dependencies. When all jobs are done, we would like to execute Notifier.
|
|
33
|
+
//
|
|
34
|
+
// The Notifier job should also be executed when Job A ends with an error. In such a case, Job B is still blocked.
|
|
35
|
+
// Hence, we need to iterate over all jobs and verify if their dependencies ended with an error to unlock
|
|
36
|
+
// executing the final part of the workflow.
|
|
37
|
+
|
|
38
|
+
const {
|
|
39
|
+
/**
|
|
40
|
+
* Required. CircleCI API token used for obtaining data about the build from API.
|
|
41
|
+
*/
|
|
42
|
+
CKE5_CIRCLE_TOKEN,
|
|
43
|
+
|
|
44
|
+
// Variables that are available by default in Circle environment.
|
|
45
|
+
CIRCLE_WORKFLOW_ID,
|
|
46
|
+
CIRCLE_JOB
|
|
47
|
+
} = process.env;
|
|
48
|
+
|
|
49
|
+
const { task } = parseArguments( process.argv.slice( 2 ) );
|
|
50
|
+
|
|
51
|
+
waitForOtherJobsAndSendNotification()
|
|
52
|
+
.catch( err => {
|
|
53
|
+
console.error( err );
|
|
54
|
+
|
|
55
|
+
process.exit( 1 );
|
|
56
|
+
} );
|
|
57
|
+
|
|
58
|
+
async function waitForOtherJobsAndSendNotification() {
|
|
59
|
+
const jobs = processJobStatuses(
|
|
60
|
+
await getOtherJobsData()
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const workflowFinished = jobs.every( job => [ 'success', 'failed', 'failed_parent' ].includes( job.status ) );
|
|
64
|
+
const anyJobsFailed = jobs.some( job => job.status === 'failed' );
|
|
65
|
+
|
|
66
|
+
if ( !workflowFinished ) {
|
|
67
|
+
await new Promise( r => setTimeout( r, 30 * 1000 ) );
|
|
68
|
+
|
|
69
|
+
return waitForOtherJobsAndSendNotification();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if ( anyJobsFailed ) {
|
|
73
|
+
return execSync( task, { stdio: 'inherit' } );
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log( 'All jobs were successful.' );
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Fetches and returns data of all jobs except the one where this script runs.
|
|
81
|
+
*/
|
|
82
|
+
async function getOtherJobsData() {
|
|
83
|
+
const url = `https://circleci.com/api/v2/workflow/${ CIRCLE_WORKFLOW_ID }/job`;
|
|
84
|
+
const options = { headers: { 'Circle-Token': CKE5_CIRCLE_TOKEN } };
|
|
85
|
+
|
|
86
|
+
const response = await fetch( url, options );
|
|
87
|
+
const data = await response.json();
|
|
88
|
+
|
|
89
|
+
return data.items.filter( job => job.name !== CIRCLE_JOB );
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {Array.<String>} args
|
|
94
|
+
* @returns {Object} result
|
|
95
|
+
* @returns {String} result.task
|
|
96
|
+
*/
|
|
97
|
+
function parseArguments( args ) {
|
|
98
|
+
const config = {
|
|
99
|
+
string: [
|
|
100
|
+
'task'
|
|
101
|
+
],
|
|
102
|
+
|
|
103
|
+
default: {
|
|
104
|
+
task: 'yarn ckeditor5-dev-ci-notify-circle-status'
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return minimist( args, config );
|
|
109
|
+
}
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
/* eslint-env node */
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const fetch = require( 'node-fetch' );
|
|
11
11
|
const slackNotify = require( 'slack-notify' );
|
|
12
|
+
const formatMessage = require( '../lib/format-message' );
|
|
12
13
|
|
|
13
14
|
// This script assumes that is being executed on Circle CI.
|
|
14
15
|
// Step it is used on should have set value: `when: on_fail`, since it does not
|
|
File without changes
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The function aims to determine a proper build status for children's jobs based on their parent's statuses.
|
|
10
|
+
*
|
|
11
|
+
* For example, in the following workflow:
|
|
12
|
+
*
|
|
13
|
+
* ┌────┐ ┌────┐
|
|
14
|
+
* │Id 1├────►│Id 2│
|
|
15
|
+
* └────┘ └────┘
|
|
16
|
+
*
|
|
17
|
+
* If the "Id 1" job is marked as failed, the "Id 2" job should be kept, too (it will never start due to an error in the parent task).
|
|
18
|
+
*
|
|
19
|
+
* @param {Array.<WorkflowJob>} jobs
|
|
20
|
+
* @returns {Array.<WorkflowJob>}
|
|
21
|
+
*/
|
|
22
|
+
module.exports = function processJobStatuses( jobs ) {
|
|
23
|
+
// To avoid modifying the original object, let's clone.
|
|
24
|
+
const jobsClone = clone( jobs );
|
|
25
|
+
|
|
26
|
+
// Find jobs to mark as "failed" based on their relationship.
|
|
27
|
+
const jobsToProcess = jobsClone
|
|
28
|
+
.filter( job => {
|
|
29
|
+
// Ignore job with no dependencies.
|
|
30
|
+
if ( !job.dependencies.length ) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// If the job is already marked as failed, ignore it, too.
|
|
35
|
+
if ( isJobFailed( job ) ) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Verify if the job is a descant child of any failed job.
|
|
40
|
+
const dependencies = job.dependencies
|
|
41
|
+
.map( parentJobId => jobsClone.find( job => job.id === parentJobId ) )
|
|
42
|
+
.filter( parentJob => isJobFailed( parentJob ) );
|
|
43
|
+
|
|
44
|
+
// If so, save the job to process.
|
|
45
|
+
return dependencies.length;
|
|
46
|
+
} );
|
|
47
|
+
|
|
48
|
+
for ( const job of jobsToProcess ) {
|
|
49
|
+
job.status = 'failed_parent';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Whenever a job has been changed, we need to iterate over all jobs again to verify the remaining jobs.
|
|
53
|
+
if ( jobsToProcess.length ) {
|
|
54
|
+
return processJobStatuses( jobsClone );
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return jobsClone;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {WorkflowJob} job
|
|
62
|
+
* @returns {Boolean}
|
|
63
|
+
*/
|
|
64
|
+
function isJobFailed( job ) {
|
|
65
|
+
if ( job.status === 'failed' ) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if ( job.status === 'failed_parent' ) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @template T
|
|
78
|
+
* @param {T} obj
|
|
79
|
+
* @returns {T}
|
|
80
|
+
*/
|
|
81
|
+
function clone( obj ) {
|
|
82
|
+
return JSON.parse( JSON.stringify( obj ) );
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @typedef {Object} WorkflowJob
|
|
87
|
+
*
|
|
88
|
+
* @property {String} id
|
|
89
|
+
*
|
|
90
|
+
* @property {'blocked'|'running'|'failed'|'failed_parent'|'success'} status
|
|
91
|
+
*
|
|
92
|
+
* @property {Array.<String>} dependencies
|
|
93
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-dev-ci",
|
|
3
|
-
"version": "38.
|
|
4
|
-
"description": "Utils
|
|
3
|
+
"version": "38.3.0",
|
|
4
|
+
"description": "Utils used on various Continuous Integration services.",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"dependencies": {
|
|
7
|
+
"minimist": "^1.2.5",
|
|
7
8
|
"node-fetch": "^2.6.7",
|
|
8
9
|
"slack-notify": "^2.0.6"
|
|
9
10
|
},
|
|
@@ -17,7 +18,8 @@
|
|
|
17
18
|
],
|
|
18
19
|
"bin": {
|
|
19
20
|
"ckeditor5-dev-ci-notify-travis-status": "bin/notify-travis-status.js",
|
|
20
|
-
"ckeditor5-dev-ci-notify-circle-status": "bin/notify-circle-status.js"
|
|
21
|
+
"ckeditor5-dev-ci-notify-circle-status": "bin/notify-circle-status.js",
|
|
22
|
+
"ckeditor5-dev-ci-circle-workflow-notifier": "bin/circle-workflow-notifier.js"
|
|
21
23
|
},
|
|
22
24
|
"author": "CKSource (http://cksource.com/)",
|
|
23
25
|
"license": "GPL-2.0-or-later",
|