Skip to content

Commit

Permalink
Merge pull request #999 from ckeditor/ci/3761-stale-bot
Browse files Browse the repository at this point in the history
Internal (stale-bot): Converted the package to ESM.
  • Loading branch information
pomek authored Sep 9, 2024
2 parents d755828 + 85bdfd7 commit 3dc5e19
Show file tree
Hide file tree
Showing 28 changed files with 1,019 additions and 1,130 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module.exports = {
{
files: [
// TODO: add packages as they are migrated to ESM.
'./packages/ckeditor5-dev-stale-bot/**/*',
'./packages/ckeditor5-dev-ci/**/*'
],
rules: {
Expand Down
20 changes: 9 additions & 11 deletions packages/ckeditor5-dev-stale-bot/bin/stale-bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const fs = require( 'fs-extra' );
const chalk = require( 'chalk' );
const createSpinner = require( './utils/createspinner' );
const parseArguments = require( './utils/parsearguments' );
const validateConfig = require( './utils/validateconfig' );
const parseConfig = require( './utils/parseconfig' );
const GitHubRepository = require( '../lib/githubrepository' );
import fs from 'fs-extra';
import chalk from 'chalk';
import createSpinner from './utils/createspinner.js';
import parseArguments from './utils/parsearguments.js';
import validateConfig from './utils/validateconfig.js';
import parseConfig from './utils/parseconfig.js';
import GitHubRepository from '../lib/githubrepository.js';

main().catch( error => {
console.error( '\n🔥 Unable to process stale issues and pull requests.\n', error );
Expand All @@ -34,7 +32,7 @@ async function main() {
throw new Error( 'Missing or invalid CLI argument: --config-path' );
}

const config = require( configPath );
const config = await import( configPath );

validateConfig( config );

Expand Down Expand Up @@ -286,7 +284,7 @@ function printStatus( dryRun, searchResult, options ) {
/**
* Prints in the console issues and pull requests from a single section.
*
* @param {String} statusMessage Seaction header.
* @param {String} statusMessage Section header.
* @param {Array.<IssueOrPullRequestResult>} entries Found issues and pull requests.
*/
function printStatusSection( statusMessage, entries ) {
Expand Down
10 changes: 4 additions & 6 deletions packages/ckeditor5-dev-stale-bot/bin/utils/createspinner.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const ora = require( 'ora' );
const chalk = require( 'chalk' );
import ora from 'ora';
import chalk from 'chalk';

/**
* Creates the spinner instance with methods to update spinner text.
*
* @returns {Spinner}
*/
module.exports = function createSpinner() {
export default function createSpinner() {
const instance = ora();

const printStatus = text => {
Expand All @@ -40,7 +38,7 @@ module.exports = function createSpinner() {
printStatus,
onProgress
};
};
}

/**
* @typedef {Object} Spinner
Expand Down
10 changes: 4 additions & 6 deletions packages/ckeditor5-dev-stale-bot/bin/utils/parsearguments.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const minimist = require( 'minimist' );
const upath = require( 'upath' );
import minimist from 'minimist';
import upath from 'upath';

/**
* Parses CLI arguments.
Expand All @@ -16,7 +14,7 @@ const upath = require( 'upath' );
* @returns {Boolean} result.dryRun
* @returns {String} result.configPath
*/
module.exports = function parseArguments( args ) {
export default function parseArguments( args ) {
const config = {
boolean: [
'dry-run'
Expand All @@ -38,4 +36,4 @@ module.exports = function parseArguments( args ) {
dryRun: options[ 'dry-run' ],
configPath: upath.join( process.cwd(), options[ 'config-path' ] )
};
};
}
8 changes: 3 additions & 5 deletions packages/ckeditor5-dev-stale-bot/bin/utils/parseconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const { subDays, formatISO } = require( 'date-fns' );
import { subDays, formatISO } from 'date-fns';

/**
* Converts configuration options into format required by the GitHubRepository.
Expand All @@ -14,7 +12,7 @@ const { subDays, formatISO } = require( 'date-fns' );
* @param {Config} config Configuration options.
* @returns {Options}
*/
module.exports = function parseConfig( viewerLogin, config ) {
export default function parseConfig( viewerLogin, config ) {
const {
REPOSITORY_SLUG,
STALE_LABELS,
Expand Down Expand Up @@ -63,7 +61,7 @@ module.exports = function parseConfig( viewerLogin, config ) {
[ ...IGNORED_ACTIVITY_LOGINS, viewerLogin ] :
IGNORED_ACTIVITY_LOGINS
};
};
}

/**
* @typedef {Object} Config
Expand Down
6 changes: 2 additions & 4 deletions packages/ckeditor5-dev-stale-bot/bin/utils/validateconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const requiredFields = [
'GITHUB_TOKEN',
'REPOSITORY_SLUG',
Expand All @@ -23,13 +21,13 @@ const requiredFields = [
* @param {Config} config Configuration options.
* @returns {void}
*/
module.exports = function validateConfig( config ) {
export default function validateConfig( config ) {
const missingFields = requiredFields.filter( fieldName => !config[ fieldName ] );

if ( !missingFields.length ) {
return;
}

throw new Error( `Missing configuration options: ${ missingFields.join( ', ' ) }.` );
};
}

79 changes: 40 additions & 39 deletions packages/ckeditor5-dev-stale-bot/lib/githubrepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,32 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const upath = require( 'upath' );
const fs = require( 'fs-extra' );
const { GraphQLClient } = require( 'graphql-request' );
const { logger } = require( '@ckeditor/ckeditor5-dev-utils' );
const {
import upath from 'upath';
import fs from 'fs-extra';
import { GraphQLClient } from 'graphql-request';
import { logger } from '@ckeditor/ckeditor5-dev-utils';
import {
addSeconds,
fromUnixTime,
formatDistanceToNow,
differenceInSeconds
} = require( 'date-fns' );
const prepareSearchQuery = require( './utils/preparesearchquery' );
const isIssueOrPullRequestToStale = require( './utils/isissueorpullrequesttostale' );
const isIssueOrPullRequestToUnstale = require( './utils/isissueorpullrequesttounstale' );
const isIssueOrPullRequestToClose = require( './utils/isissueorpullrequesttoclose' );
const isPendingIssueToStale = require( './utils/ispendingissuetostale' );
const isPendingIssueToUnlabel = require( './utils/ispendingissuetounlabel' );
} from 'date-fns';
import prepareSearchQuery from './utils/preparesearchquery.js';
import isIssueOrPullRequestToStale from './utils/isissueorpullrequesttostale.js';
import isIssueOrPullRequestToUnstale from './utils/isissueorpullrequesttounstale.js';
import isIssueOrPullRequestToClose from './utils/isissueorpullrequesttoclose.js';
import isPendingIssueToStale from './utils/ispendingissuetostale.js';
import isPendingIssueToUnlabel from './utils/ispendingissuetounlabel.js';

const GRAPHQL_PATH = upath.join( __dirname, 'graphql' );

const queries = {
getViewerLogin: readGraphQL( 'getviewerlogin' ),
searchIssuesOrPullRequests: readGraphQL( 'searchissuesorpullrequests' ),
searchPendingIssues: readGraphQL( 'searchpendingissues' ),
getIssueOrPullRequestTimelineItems: readGraphQL( 'getissueorpullrequesttimelineitems' ),
addComment: readGraphQL( 'addcomment' ),
getLabels: readGraphQL( 'getlabels' ),
addLabels: readGraphQL( 'addlabels' ),
removeLabels: readGraphQL( 'removelabels' ),
closeIssue: readGraphQL( 'closeissue' ),
closePullRequest: readGraphQL( 'closepullrequest' )
};

/**
* A GitHub client containing methods used to interact with GitHub using its GraphQL API.
*
* All methods handles paginated data and it supports a case when a request has exceeded the GitHub API rate limit.
* In such a case, the request waits until the limit is reset and it is automatically sent again.
*/
module.exports = class GitHubRepository {
export default class GitHubRepository {
constructor( authToken ) {
/**
* @private
Expand All @@ -63,6 +48,22 @@ module.exports = class GitHubRepository {
* @property {Logger}
*/
this.logger = logger();

/**
* @private
*/
this.queries = {
getViewerLogin: readGraphQL( 'getviewerlogin' ),
searchIssuesOrPullRequests: readGraphQL( 'searchissuesorpullrequests' ),
searchPendingIssues: readGraphQL( 'searchpendingissues' ),
getIssueOrPullRequestTimelineItems: readGraphQL( 'getissueorpullrequesttimelineitems' ),
addComment: readGraphQL( 'addcomment' ),
getLabels: readGraphQL( 'getlabels' ),
addLabels: readGraphQL( 'addlabels' ),
removeLabels: readGraphQL( 'removelabels' ),
closeIssue: readGraphQL( 'closeissue' ),
closePullRequest: readGraphQL( 'closepullrequest' )
};
}

/**
Expand All @@ -71,7 +72,7 @@ module.exports = class GitHubRepository {
* @returns {Promise.<String>}
*/
async getViewerLogin() {
return this.sendRequest( await queries.getViewerLogin )
return this.sendRequest( await this.queries.getViewerLogin )
.then( data => data.viewer.login )
.catch( error => {
this.logger.error( 'Unexpected error when executing "#getViewerLogin()".', error );
Expand Down Expand Up @@ -105,7 +106,7 @@ module.exports = class GitHubRepository {
cursor: pageInfo.cursor || null
};

return this.sendRequest( await queries.searchIssuesOrPullRequests, variables )
return this.sendRequest( await this.queries.searchIssuesOrPullRequests, variables )
.then( async data => {
const issuesOrPullRequests = await this.parseIssuesOrPullRequests( data.search );

Expand Down Expand Up @@ -151,7 +152,7 @@ module.exports = class GitHubRepository {
cursor: pageInfo.cursor || null
};

return this.sendRequest( await queries.searchIssuesOrPullRequests, variables )
return this.sendRequest( await this.queries.searchIssuesOrPullRequests, variables )
.then( async data => {
const issuesOrPullRequests = await this.parseIssuesOrPullRequests( data.search );

Expand Down Expand Up @@ -217,7 +218,7 @@ module.exports = class GitHubRepository {
cursor: pageInfo.cursor || null
};

return this.sendRequest( await queries.searchPendingIssues, variables )
return this.sendRequest( await this.queries.searchPendingIssues, variables )
.then( async data => {
const pendingIssues = this.parsePendingIssues( data.search );

Expand Down Expand Up @@ -263,7 +264,7 @@ module.exports = class GitHubRepository {
cursor: pageInfo.cursor || null
};

return this.sendRequest( await queries.getIssueOrPullRequestTimelineItems, variables )
return this.sendRequest( await this.queries.getIssueOrPullRequestTimelineItems, variables )
.then( async data => {
pageInfo = data.node.timelineItems.pageInfo;

Expand Down Expand Up @@ -295,7 +296,7 @@ module.exports = class GitHubRepository {
comment
};

return this.sendRequest( await queries.addComment, variables )
return this.sendRequest( await this.queries.addComment, variables )
.catch( error => {
this.logger.error( 'Unexpected error when executing "#addComment()".', error );

Expand All @@ -322,7 +323,7 @@ module.exports = class GitHubRepository {
labelNames: labelNames.join( ' ' )
};

return this.sendRequest( await queries.getLabels, variables )
return this.sendRequest( await this.queries.getLabels, variables )
.then( data => {
return data.repository.labels.nodes
// Additional filtering is needed, because GitHub endpoint may return many more results than match the query.
Expand All @@ -349,7 +350,7 @@ module.exports = class GitHubRepository {
labelIds
};

return this.sendRequest( await queries.addLabels, variables )
return this.sendRequest( await this.queries.addLabels, variables )
.catch( error => {
this.logger.error( 'Unexpected error when executing "#addLabels()".', error );

Expand All @@ -370,7 +371,7 @@ module.exports = class GitHubRepository {
labelIds
};

return this.sendRequest( await queries.removeLabels, variables )
return this.sendRequest( await this.queries.removeLabels, variables )
.catch( error => {
this.logger.error( 'Unexpected error when executing "#removeLabels()".', error );

Expand All @@ -390,7 +391,7 @@ module.exports = class GitHubRepository {
nodeId
};

const query = type === 'Issue' ? await queries.closeIssue : await queries.closePullRequest;
const query = type === 'Issue' ? await this.queries.closeIssue : await this.queries.closePullRequest;

return this.sendRequest( query, variables )
.catch( error => {
Expand Down Expand Up @@ -556,7 +557,7 @@ module.exports = class GitHubRepository {
return Promise.reject( error );
} );
}
};
}

/**
* Reads the GraphQL query from filesystem.
Expand Down
8 changes: 3 additions & 5 deletions packages/ckeditor5-dev-stale-bot/lib/utils/findstaledate.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const { isAfter, parseISO } = require( 'date-fns' );
import { isAfter, parseISO } from 'date-fns';

/**
* Finds the most recent event date of the stale label assignment to issue or pull request.
Expand All @@ -14,7 +12,7 @@ const { isAfter, parseISO } = require( 'date-fns' );
* @param {Options} options Configuration options.
* @returns {String}
*/
module.exports = function findStaleDate( issueOrPullRequest, options ) {
export default function findStaleDate( issueOrPullRequest, options ) {
const { staleLabels } = options;

return issueOrPullRequest.timelineItems
Expand All @@ -27,4 +25,4 @@ module.exports = function findStaleDate( issueOrPullRequest, options ) {
} )
.find( entry => staleLabels.includes( entry.label ) )
.eventDate;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
* For licensing, see LICENSE.md.
*/

'use strict';

const { isAfter, parseISO } = require( 'date-fns' );
import { isAfter, parseISO } from 'date-fns';

/**
* Verifies dates from an issue or pull request to check if some of them occurred after the provided moment, meaning that the issue or pull
Expand All @@ -25,7 +23,7 @@ const { isAfter, parseISO } = require( 'date-fns' );
* @param {Options} options Configuration options.
* @returns {Boolean}
*/
module.exports = function isIssueOrPullRequestActive( issueOrPullRequest, staleDate, options ) {
export default function isIssueOrPullRequestActive( issueOrPullRequest, staleDate, options ) {
const { ignoredActivityLogins, ignoredActivityLabels } = options;

const dates = [
Expand Down Expand Up @@ -53,4 +51,4 @@ module.exports = function isIssueOrPullRequestActive( issueOrPullRequest, staleD
return dates
.filter( Boolean )
.some( date => isAfter( parseISO( date ), parseISO( staleDate ) ) );
};
}
Loading

0 comments on commit 3dc5e19

Please sign in to comment.