diff --git a/packages/ckeditor5-dev-ci/bin/notify-circle-status.js b/packages/ckeditor5-dev-ci/bin/notify-circle-status.js new file mode 100644 index 000000000..51a2458fd --- /dev/null +++ b/packages/ckeditor5-dev-ci/bin/notify-circle-status.js @@ -0,0 +1,120 @@ +#!/usr/bin/env node + +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/* eslint-env node */ + +const formatMessage = require( '../lib/format-message' ); +const slackNotify = require( 'slack-notify' ); + +// This script assumes that is being executed on Circle CI. +// Step it is used on should have set value: `when: on_fail`, since it does not +// check whether the build failed when determining whether the notification should be sent. +// Described environment variables starting with "CKE5" should be added by the integrator. + +const { + /** + * Required. Token to a Github account with the scope: "repos". It is required for obtaining an author of + * the commit if the build failed. The repository can be private and we can't use the public API. + */ + CKE5_GITHUB_TOKEN, + + /** + * Required. CircleCI API token used for obtaining data about the build from API. + */ + CKE5_CIRCLE_TOKEN, + + /** + * Required. Webhook URL of the Slack channel where the notification should be sent. + */ + CKE5_SLACK_WEBHOOK_URL, + + /** + * Optional. If both are defined, the script will use the URL as the commit URL. + * Otherwise, URL will be constructed using current repository data. + */ + CKE5_TRIGGER_REPOSITORY_SLUG, + CKE5_TRIGGER_COMMIT_HASH, + + /** + * Optional. If set to "true", commit author will be hidden. + * See: https://github.com/ckeditor/ckeditor5/issues/9252. + */ + CKE5_SLACK_NOTIFY_HIDE_AUTHOR, + + // Variables that are available by default in Circle environment. + CIRCLE_BRANCH, + CIRCLE_BUILD_NUM, + CIRCLE_BUILD_URL, + CIRCLE_PROJECT_REPONAME, + CIRCLE_PROJECT_USERNAME, + CIRCLE_SHA1 +} = process.env; + +notifyCircleStatus(); + +async function notifyCircleStatus() { + if ( !CKE5_GITHUB_TOKEN ) { + throw new Error( 'Missing environment variable: CKE5_GITHUB_TOKEN' ); + } + + if ( !CKE5_SLACK_WEBHOOK_URL ) { + throw new Error( 'Missing environment variable: CKE5_SLACK_WEBHOOK_URL' ); + } + + const jobData = await getJobData(); + + const message = await formatMessage( { + slackMessageUsername: 'Circle CI', + iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Circleci-icon-logo.svg/475px-Circleci-icon-logo.svg.png', + repositoryOwner: CIRCLE_PROJECT_USERNAME, + repositoryName: CIRCLE_PROJECT_REPONAME, + branch: CIRCLE_BRANCH, + jobUrl: CIRCLE_BUILD_URL, + jobId: CIRCLE_BUILD_NUM, + githubToken: CKE5_GITHUB_TOKEN, + triggeringCommitUrl: getTriggeringCommitUrl(), + startTime: Math.ceil( ( new Date( jobData.started_at ) ).getTime() / 1000 ), + endTime: Math.ceil( ( new Date() ) / 1000 ), + shouldHideAuthor: CKE5_SLACK_NOTIFY_HIDE_AUTHOR === 'true' + } ); + + return slackNotify( CKE5_SLACK_WEBHOOK_URL ) + .send( message ) + .catch( err => console.log( 'API error occurred:', err ) ); +} + +async function getJobData() { + const fetchUrl = [ + 'https://circleci.com/api/v2/project/gh', + CIRCLE_PROJECT_USERNAME, + CIRCLE_PROJECT_REPONAME, + 'job', + CIRCLE_BUILD_NUM + ].join( '/' ); + + const fetchOptions = { + method: 'GET', + headers: { 'Circle-Token': CKE5_CIRCLE_TOKEN } + }; + + const rawResponse = await fetch( fetchUrl, fetchOptions ); + return rawResponse.json(); +} + +function getTriggeringCommitUrl() { + let repoSlug, hash; + + if ( CKE5_TRIGGER_REPOSITORY_SLUG && CKE5_TRIGGER_COMMIT_HASH ) { + repoSlug = CKE5_TRIGGER_REPOSITORY_SLUG; + hash = CKE5_TRIGGER_COMMIT_HASH; + } else { + repoSlug = [ CIRCLE_PROJECT_USERNAME, CIRCLE_PROJECT_REPONAME ].join( '/' ); + hash = CIRCLE_SHA1; + } + + return [ 'https://github.com', repoSlug, 'commit', hash ].join( '/' ); +} diff --git a/packages/ckeditor5-dev-ci/bin/notify-travis-status.js b/packages/ckeditor5-dev-ci/bin/notify-travis-status.js new file mode 100644 index 000000000..c10921daa --- /dev/null +++ b/packages/ckeditor5-dev-ci/bin/notify-travis-status.js @@ -0,0 +1,112 @@ +#!/usr/bin/env node + +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/* eslint-env node */ + +const formatMessage = require( '../lib/format-message' ); +const slackNotify = require( 'slack-notify' ); + +const ALLOWED_BRANCHES = [ + 'stable', + 'master' +]; + +const ALLOWED_EVENTS = [ + 'push', + 'cron', + 'api' +]; + +// This script assumes that is being executed on Travis CI. +// Described environment variables should be added by the integrator. + +const { + /** + * POSIX timestamps created when the script has begun and ended the job. + * Timestamps should be in seconds instead of milliseconds. + */ + START_TIME, + END_TIME, + + /** + * Token to a Github account with the scope: "repos". It is required for obtaining an author of + * the commit if the build failed. The repository can be private and we can't use the public API. + */ + GITHUB_TOKEN, + + /** + * Required. Webhook URL of the Slack channel where the notification should be sent. + */ + SLACK_WEBHOOK_URL, + + /** + * Optional. If defined, the script will use the URL as the commit URL. + * Otherwise, URL will be constructed using current repository data. + */ + SLACK_NOTIFY_COMMIT_URL, + + /** + * Optional. If set to "true", commit author will be hidden. + * See: https://github.com/ckeditor/ckeditor5/issues/9252. + */ + SLACK_NOTIFY_HIDE_AUTHOR, + + // Variables that are available by default in Travis environment. + TRAVIS_BRANCH, + TRAVIS_COMMIT, + TRAVIS_EVENT_TYPE, + TRAVIS_JOB_NUMBER, + TRAVIS_JOB_WEB_URL, + TRAVIS_REPO_SLUG, + TRAVIS_TEST_RESULT +} = process.env; + +notifyTravisStatus(); + +async function notifyTravisStatus() { + // Send a notification only for main branches... + if ( !ALLOWED_BRANCHES.includes( TRAVIS_BRANCH ) ) { + console.log( `Aborting slack notification due to an invalid branch (${ TRAVIS_BRANCH }).` ); + + process.exit(); + } + + // ...and an event that triggered the build is correct... + if ( !ALLOWED_EVENTS.includes( TRAVIS_EVENT_TYPE ) ) { + console.log( `Aborting slack notification due to an invalid event type (${ TRAVIS_EVENT_TYPE }).` ); + + process.exit(); + } + + // ...and for builds that failed. + if ( TRAVIS_TEST_RESULT == 0 ) { + console.log( 'The build did not fail. The notification will not be sent.' ); + + process.exit(); + } + + const [ repositoryOwner, repositoryName ] = TRAVIS_REPO_SLUG.split( '/' ); + + const message = await formatMessage( { + slackMessageUsername: 'Travis CI', + iconUrl: 'https://a.slack-edge.com/66f9/img/services/travis_36.png', + repositoryOwner, + repositoryName, + branch: TRAVIS_BRANCH, + jobUrl: TRAVIS_JOB_WEB_URL, + jobId: TRAVIS_JOB_NUMBER, + githubToken: GITHUB_TOKEN, + triggeringCommitUrl: SLACK_NOTIFY_COMMIT_URL || `https://github.com/${ TRAVIS_REPO_SLUG }/commit/${ TRAVIS_COMMIT }`, + startTime: Number( START_TIME ), + endTime: Number( END_TIME ), + shouldHideAuthor: SLACK_NOTIFY_HIDE_AUTHOR === 'true' + } ); + + return slackNotify( SLACK_WEBHOOK_URL ) + .send( message ) + .catch( err => console.log( 'API error occurred:', err ) ); +} diff --git a/packages/ckeditor5-dev-ci/bin/notifytravisstatus.js b/packages/ckeditor5-dev-ci/bin/notifytravisstatus.js deleted file mode 100755 index 83d9493de..000000000 --- a/packages/ckeditor5-dev-ci/bin/notifytravisstatus.js +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env node - -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -/* eslint-env node */ - -// This script assumes that is being executed on Travis CI. It requires following environment variables: -// -// - SLACK_WEBHOOK_URL - a URL where the notification should be sent -// - START_TIME - POSIX time (when the script has begun the job) -// - END_TIME - POSIX time (when the script has finished the job) -// - GITHUB_TOKEN - token to a Github account with the scope: "repos". It is requires for obtaining an author of -// the commit if the build failed. The repository can be private and we can't use the public API. -// -// If the `SLACK_NOTIFY_COMMIT_URL` environment variable is defined, the script use the URL as the commit URL. -// Otherwise, a marge of variables `TRAVIS_REPO_SLUG` and `TRAVIS_COMMIT` will be used. -// -// Pinging an author of the commit can be disabled by defining the `SLACK_NOTIFY_HIDE_AUTHOR` environment variable -// to `"true"` (`SLACK_NOTIFY_HIDE_AUTHOR="true"`). See: https://github.com/ckeditor/ckeditor5/issues/9252. -// -// In order to enable the debug mode, set the `DEBUG=true` as the environment variable. - -const buildBranch = process.env.TRAVIS_BRANCH; - -const ALLOWED_BRANCHES = [ - 'stable', - 'master' -]; - -const ALLOWED_EVENTS = [ - 'push', - 'cron', - 'api' -]; - -// Send a notification only for main branches... -if ( !ALLOWED_BRANCHES.includes( buildBranch ) ) { - printLog( `Aborting due to an invalid branch (${ buildBranch }).` ); - - process.exit(); -} - -// ...and an event that triggered the build is correct... -if ( !ALLOWED_EVENTS.includes( process.env.TRAVIS_EVENT_TYPE ) ) { - printLog( `Aborting due to an invalid event type (${ process.env.TRAVIS_EVENT_TYPE }).` ); - - process.exit(); -} - -// ...and for builds that failed. -if ( process.env.TRAVIS_TEST_RESULT == 0 ) { - printLog( 'The build did not fail. The notification will not be sent.' ); - - process.exit(); -} - -const notifyTravisStatus = require( '../lib/notifytravisstatus' ); - -const options = { - repositorySlug: process.env.TRAVIS_REPO_SLUG, - startTime: parseInt( process.env.START_TIME ), - endTime: parseInt( process.env.END_TIME ), - githubToken: process.env.GITHUB_TOKEN, - slackWebhookUrl: process.env.SLACK_WEBHOOK_URL, - branch: buildBranch, - commit: process.env.TRAVIS_COMMIT, - notifyCommitUrl: process.env.SLACK_NOTIFY_COMMIT_URL, - shouldHideAuthor: process.env.SLACK_NOTIFY_HIDE_AUTHOR === 'true', - jobUrl: process.env.TRAVIS_JOB_WEB_URL, - jobId: process.env.TRAVIS_JOB_NUMBER -}; - -notifyTravisStatus( options ) - .catch( error => { - console.error( error ); - - throw error; - } ); - -/** - * @param {String} message - */ -function printLog( message ) { - console.log( '[Slack Notification]', message ); -} diff --git a/packages/ckeditor5-dev-ci/lib/data/bots.json b/packages/ckeditor5-dev-ci/lib/data/bots.json new file mode 100644 index 000000000..16fb9505b --- /dev/null +++ b/packages/ckeditor5-dev-ci/lib/data/bots.json @@ -0,0 +1,3 @@ +[ + "CKTravisBot" +] diff --git a/packages/ckeditor5-dev-ci/lib/members.json b/packages/ckeditor5-dev-ci/lib/data/members.json similarity index 91% rename from packages/ckeditor5-dev-ci/lib/members.json rename to packages/ckeditor5-dev-ci/lib/data/members.json index c165bea1c..d9ab19f1f 100644 --- a/packages/ckeditor5-dev-ci/lib/members.json +++ b/packages/ckeditor5-dev-ci/lib/data/members.json @@ -17,9 +17,8 @@ "ldrobnik": "U04DJ7B7ZCJ", "LukaszGudel": "U01FRHAT8T1", "mabryl": "U045033D401", - "Mgsy": "U5A38S2PN", "martnpaneq": "U045B560E00", - "mabryl": "U045033D401", + "Mgsy": "U5A38S2PN", "mlewand": "U03UQQ1N3", "mmotyczynska": "U02NSTQCTB8", "mremiszewski": "U04ACUBMDGT", @@ -31,6 +30,5 @@ "pszczesniak": "U04167FKV88", "Reinmar": "U03UQRP0C", "scofalik": "U05611ZMM", - "wwalc": "U03UQQ8PY", - "CKTravisBot": "CKTravisBot" + "wwalc": "U03UQQ8PY" } diff --git a/packages/ckeditor5-dev-ci/lib/format-message.js b/packages/ckeditor5-dev-ci/lib/format-message.js new file mode 100644 index 000000000..b88739c93 --- /dev/null +++ b/packages/ckeditor5-dev-ci/lib/format-message.js @@ -0,0 +1,193 @@ +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/* eslint-env node */ + +'use strict'; + +const fetch = require( 'node-fetch' ); + +const bots = require( './data/bots.json' ); +const members = require( './data/members.json' ); + +const REPOSITORY_REGEXP = /github\.com\/([^/]+)\/([^/]+)/; + +/** + * @param {String} slackMessageUsername + * @param {String} iconUrl + * @param {String} repositoryOwner + * @param {String} repositoryName + * @param {String} branch + * @param {String} jobUrl + * @param {String} jobId + * @param {String} githubToken + * @param {String} triggeringCommitUrl + * @param {Number} startTime + * @param {Number} endTime + * @param {Boolean} shouldHideAuthor + */ +module.exports = async function formatMessage( options ) { + const commitDetails = await getCommitDetails( options.triggeringCommitUrl, options.githubToken ); + const repoUrl = `https://github.com/${ options.repositoryOwner }/${ options.repositoryName }`; + + return { + username: options.slackMessageUsername, + icon_url: options.iconUrl, + unfurl_links: 1, + text: getNotifierMessage( { ...options, ...commitDetails } ), + attachments: [ { + color: 'danger', + fields: [ { + title: 'Repository (branch)', + value: `<${ repoUrl }|${ options.repositoryName }> (<${ repoUrl }/tree/${ options.branch }|${ options.branch }>)`, + short: true + }, { + title: 'Build number', + value: `<${ options.jobUrl }|#${ options.jobId }>`, + short: true + }, { + title: 'Commit', + value: `<${ options.triggeringCommitUrl }|${ commitDetails.hash.substring( 0, 7 ) }>`, + short: true + }, { + title: 'Build time', + value: getExecutionTime( options.startTime, options.endTime ), + short: true + }, { + title: 'Commit message', + value: getFormattedMessage( commitDetails.commitMessage, options.triggeringCommitUrl ), + short: false + } ] + } ] + }; +}; + +/** + * Returns the additional message that will be added to the notifier post. + * + * @param {Object} options + * @param {Boolean} options.shouldHideAuthor + * @param {String|null} options.githubAccount + * @param {String} options.commitAuthor + * @returns {String} + */ +function getNotifierMessage( options ) { + const slackAccount = members[ options.githubAccount ] || null; + + if ( options.shouldHideAuthor ) { + return '_The author of the commit was hidden. _'; + } + + // If the author of the commit could not be obtained, let's ping the entire team. + if ( !slackAccount ) { + return `@channel (${ options.commitAuthor }), could you take a look?`; + } + + if ( bots.includes( options.githubAccount ) ) { + return '_This commit is a result of merging a branch into another branch._'; + } + + return `<@${ slackAccount }>, could you take a look?`; +} + +/** + * Returns string representing amount of time passed between two timestamps. + * Timestamps should be in seconds instead of milliseconds. + * + * @param {Number} startTime + * @param {Number} endTime + * @returns {String} + */ +function getExecutionTime( startTime, endTime ) { + if ( !startTime || !endTime ) { + return 'Unavailable.'; + } + + const totalMs = ( endTime - startTime ) * 1000; + const date = new Date( totalMs ); + const hours = date.getUTCHours(); + const minutes = date.getUTCMinutes(); + const seconds = date.getUTCSeconds(); + + const stringParts = []; + + if ( hours ) { + stringParts.push( `${ hours } hr.` ); + } + + if ( minutes ) { + stringParts.push( `${ minutes } min.` ); + } + + if ( seconds ) { + stringParts.push( `${ seconds } sec.` ); + } + + if ( !stringParts.length ) { + return '0 sec.'; + } + + return stringParts.join( ' ' ); +} + +/** + * Replaces `#Id` and `Repo/Owner#Id` with URls to Github Issues. + * + * @param {String} commitMessage + * @param {String} triggeringCommitUrl + * @returns {string} + */ +function getFormattedMessage( commitMessage, triggeringCommitUrl ) { + if ( !commitMessage ) { + return 'Unavailable'; + } + + const [ , repoOwner, repoName ] = triggeringCommitUrl.match( REPOSITORY_REGEXP ); + + return commitMessage + .replace( / #(\d+)/g, ( _, issueId ) => { + return ` `; + } ) + .replace( /([\w-]+\/[\w-]+)#(\d+)/g, ( _, repoSlug, issueId ) => { + return ``; + } ); +} + +/** + * Returns a promise that resolves the commit details (author and message) based on the specified GitHub URL. + * + * @param {String} triggeringCommitUrl The URL to the commit on GitHub. + * @param {String} githubToken Github token used for authorization a request, + * @returns {Promise.} + */ +function getCommitDetails( triggeringCommitUrl, githubToken ) { + const apiGithubUrlCommit = getGithubApiUrl( triggeringCommitUrl ); + const options = { + method: 'GET', + credentials: 'include', + headers: { + authorization: `token ${ githubToken }` + } + }; + + return fetch( apiGithubUrlCommit, options ) + .then( response => response.json() ) + .then( json => ( { + githubAccount: json.author ? json.author.login : null, + commitAuthor: json.commit.author.name, + commitMessage: json.commit.message, + hash: json.sha + } ) ); +} + +/** + * Returns a URL to GitHub API which returns details of the commit that caused the CI to fail its job. + * + * @param {String} triggeringCommitUrl The URL to the commit on GitHub. + * @returns {String} + */ +function getGithubApiUrl( triggeringCommitUrl ) { + return triggeringCommitUrl.replace( 'github.com/', 'api.github.com/repos/' ).replace( '/commit/', '/commits/' ); +} diff --git a/packages/ckeditor5-dev-ci/lib/index.js b/packages/ckeditor5-dev-ci/lib/index.js deleted file mode 100644 index 8ab5f6f8a..000000000 --- a/packages/ckeditor5-dev-ci/lib/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const notifyTravisStatus = require( './notifytravisstatus' ); - -module.exports = { - notifyTravisStatus -}; diff --git a/packages/ckeditor5-dev-ci/lib/notifytravisstatus.js b/packages/ckeditor5-dev-ci/lib/notifytravisstatus.js deleted file mode 100644 index d0bb7f147..000000000 --- a/packages/ckeditor5-dev-ci/lib/notifytravisstatus.js +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -// A map that translates GitHub accounts to Slack ids. -const members = require( './members.json' ); - -const REPOSITORY_REGEXP = /github\.com\/([^/]+)\/([^/]+)/; - -const fetch = require( 'node-fetch' ); -const slackNotify = require( 'slack-notify' ); - -/** - * @param {Object} options - * @param {String} options.repositorySlug - * @param {Number} options.startTime - * @param {Number} options.endTime - * @param {String} options.githubToken - * @param {String} options.slackWebhookUrl - * @param {String} options.branch - * @param {String} options.commit - * @param {String} options.notifyCommitUrl - * @param {Boolean} options.shouldHideAuthor - * @param {String} options.jobUrl - * @param {String} options.jobId - * @returns {Promise} - */ -module.exports = async function notifyTravisStatus( options ) { - const commitUrl = getCommitUrl( { - commit: options.commit, - notifyCommitUrl: options.notifyCommitUrl, - repositorySlug: options.repositorySlug - } ); - const { githubAccount, commitAuthor, commitMessage } = await getCommitDetails( commitUrl, options.githubToken ); - - const [ buildRepoOwner, buildRepoName ] = options.repositorySlug.split( '/' ); - const slackAccount = members[ githubAccount ] || null; - const shortCommit = commitUrl.split( '/' ).pop().substring( 0, 7 ); - const repoMatch = commitUrl.match( REPOSITORY_REGEXP ); - - const messageData = { - username: 'Travis CI', - text: getNotifierMessage( { - slackAccount, - githubAccount, - commitAuthor, - shouldHideAuthor: options.shouldHideAuthor - } ), - icon_url: 'https://a.slack-edge.com/66f9/img/services/travis_36.png', - unfurl_links: 1, - attachments: [ - { - color: 'danger', - fields: [ - { - title: 'Repository (branch)', - value: [ - ``, - `()` - ].join( ' ' ), - short: true - }, - { - title: 'Commit', - value: `<${ commitUrl }|${ shortCommit }>`, - short: true - }, - { - title: 'Build number', - value: `<${ options.jobUrl }|#${ options.jobId }>`, - short: true - }, - { - title: 'Build time', - value: getExecutionTime( options.endTime, options.startTime ), - short: true - }, - { - title: 'Commit message', - value: getFormattedMessage( commitMessage, repoMatch[ 1 ], repoMatch[ 2 ] ), - short: false - } - ] - } - ] - }; - - return slackNotify( options.slackWebhookUrl ) - .send( messageData ) - .catch( err => console.log( 'API error occurred:', err ) ); -}; - -/** - * Returns string representing amount of time passed between two timestamps. - * - * @param {Number} endTime - * @param {Number} startTime - * @returns {String} - */ -function getExecutionTime( endTime, startTime ) { - const totalMs = ( endTime - startTime ) * 1000; - const date = new Date( totalMs ); - const hours = date.getUTCHours(); - const minutes = date.getUTCMinutes(); - const seconds = date.getUTCSeconds(); - - const stringParts = []; - - if ( hours ) { - stringParts.push( `${ hours } hr.` ); - } - - if ( minutes ) { - stringParts.push( `${ minutes } min.` ); - } - - if ( seconds ) { - stringParts.push( `${ seconds } sec.` ); - } - - return stringParts.join( ' ' ); -} - -/** - * Replaces `#Id` and `Repo/Owner#Id` with URls to Github Issues. - * - * @param {String} message - * @param {String} repoOwner - * @param {String} repoName - * @returns {string} - */ -function getFormattedMessage( message, repoOwner, repoName ) { - return message - .replace( / #(\d+)/g, ( _, issueId ) => { - return ` `; - } ) - .replace( /([\w-]+\/[\w-]+)#(\d+)/g, ( _, repoSlug, issueId ) => { - return ``; - } ); -} - -/** - * Returns a URL to the commit details on GitHub. - * - * @param {Object} options - * @param {String} options.notifyCommitUrl - * @param {String} options.repositorySlug - * @param {String} options.commit - * @returns {String} - */ -function getCommitUrl( options ) { - if ( options.notifyCommitUrl ) { - return options.notifyCommitUrl; - } - - return `https://github.com/${ options.repositorySlug }/commit/${ options.commit }`; -} - -/** - * Returns a URL to GitHub API which returns details of the commit that caused the CI to fail its job. - * - * @param {String} commitUrl The URL to the commit on GitHub. - * @returns {String} - */ -function getGithubApiUrl( commitUrl ) { - return commitUrl.replace( 'github.com/', 'api.github.com/repos/' ).replace( '/commit/', '/commits/' ); -} - -/** - * Returns a promise that resolves the commit details (author and message) based on the specified GitHub URL. - * - * @param {String} commitUrl The URL to the commit on GitHub. - * @param {String} githubToken Github token used for authorization a request, - * @returns {Promise.} - */ -function getCommitDetails( commitUrl, githubToken ) { - const apiGithubUrlCommit = getGithubApiUrl( commitUrl ); - const options = { - method: 'GET', - credentials: 'include', - headers: { - authorization: `token ${ githubToken }` - } - }; - - return fetch( apiGithubUrlCommit, options ) - .then( response => response.json() ) - .then( json => ( { - githubAccount: json.author ? json.author.login : null, - commitAuthor: json.commit.author.name, - commitMessage: json.commit.message - } ) ); -} - -/** - * Returns the additional message that will be added to the notifier post. - * - * @param {Object} options - * @param {Boolean} options.shouldHideAuthor - * @param {String|null} options.slackAccount - * @param {String|null} options.githubAccount - * @param {String} options.commitAuthor - * @returns {String} - */ -function getNotifierMessage( options ) { - if ( options.shouldHideAuthor ) { - return '_The author of the commit was hidden. _'; - } - - // If the author of the commit could not be obtained, let's ping the entire team. - if ( !options.slackAccount ) { - return `@channel (${ options.commitAuthor }), could you take a look?`; - } - - // Slack and GitHub names for bots are equal. - if ( options.slackAccount === options.githubAccount ) { - return '_This commit is a result of merging a branch into another branch._'; - } - - return `<@${ options.slackAccount }>, could you take a look?`; -} diff --git a/packages/ckeditor5-dev-ci/package.json b/packages/ckeditor5-dev-ci/package.json index 731f96546..8b391514a 100644 --- a/packages/ckeditor5-dev-ci/package.json +++ b/packages/ckeditor5-dev-ci/package.json @@ -16,7 +16,8 @@ "lib" ], "bin": { - "ckeditor5-dev-ci-notify-travis-status": "bin/notifytravisstatus.js" + "ckeditor5-dev-ci-notify-travis-status": "bin/notify-travis-status.js", + "ckeditor5-dev-ci-notify-circle-status": "bin/notify-circle-status.js" }, "author": "CKSource (http://cksource.com/)", "license": "GPL-2.0-or-later",