From f73024038bb7352e1ddb950661089cc18edc791f Mon Sep 17 00:00:00 2001 From: Jonathan Morley Date: Thu, 27 Feb 2025 17:58:24 -0500 Subject: [PATCH 1/3] feat: separate runtime and deployment configs --- index.js | 33 +++----- lib/deploymentConfig.js | 53 +++++------- lib/mergeDeep.js | 8 +- lib/settings.js | 41 +++------ test/unit/lib/deploymentConfig.test.js | 62 ++++++++++++++ test/unit/lib/settings.test.js | 112 +++++++++++++++++-------- test/unit/lib/validator.test.js | 20 +++-- 7 files changed, 205 insertions(+), 124 deletions(-) create mode 100644 test/unit/lib/deploymentConfig.test.js diff --git a/index.js b/index.js index 40e057391..f9c9538cc 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ const fs = require('fs') const cron = require('node-cron') const Glob = require('./lib/glob') const ConfigManager = require('./lib/configManager') +const DeploymentConfig = require('./lib/deploymentConfig') const NopCommand = require('./lib/nopcommand') const env = require('./lib/env') @@ -13,11 +14,11 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => let appSlug = 'safe-settings' async function syncAllSettings (nop, context, repo = context.repo(), ref) { try { - deploymentConfig = await loadYamlFileSystem() + deploymentConfig = await loadYamlFileSystem(context) robot.log.debug(`deploymentConfig is ${JSON.stringify(deploymentConfig)}`) const configManager = new ConfigManager(context, ref) const runtimeConfig = await configManager.loadGlobalSettingsYaml() - const config = Object.assign({}, deploymentConfig, runtimeConfig) + const config = { deploymentConfig, runtimeConfig } robot.log.debug(`config for ref ${ref} is ${JSON.stringify(config)}`) if (ref) { return Settings.syncAll(nop, context, repo, config, ref) @@ -42,11 +43,11 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => async function syncSubOrgSettings (nop, context, suborg, repo = context.repo(), ref) { try { - deploymentConfig = await loadYamlFileSystem() + deploymentConfig = await loadYamlFileSystem(context) robot.log.debug(`deploymentConfig is ${JSON.stringify(deploymentConfig)}`) const configManager = new ConfigManager(context, ref) const runtimeConfig = await configManager.loadGlobalSettingsYaml() - const config = Object.assign({}, deploymentConfig, runtimeConfig) + const config = { deploymentConfig, runtimeConfig } robot.log.debug(`config for ref ${ref} is ${JSON.stringify(config)}`) return Settings.syncSubOrgs(nop, context, suborg, repo, config, ref) } catch (e) { @@ -67,11 +68,11 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => async function syncSettings (nop, context, repo = context.repo(), ref) { try { - deploymentConfig = await loadYamlFileSystem() + deploymentConfig = await loadYamlFileSystem(context) robot.log.debug(`deploymentConfig is ${JSON.stringify(deploymentConfig)}`) const configManager = new ConfigManager(context, ref) const runtimeConfig = await configManager.loadGlobalSettingsYaml() - const config = Object.assign({}, deploymentConfig, runtimeConfig) + const config = { deploymentConfig, runtimeConfig } robot.log.debug(`config for ref ${ref} is ${JSON.stringify(config)}`) return Settings.sync(nop, context, repo, config, ref) } catch (e) { @@ -92,14 +93,14 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => async function renameSync (nop, context, repo = context.repo(), rename, ref) { try { - deploymentConfig = await loadYamlFileSystem() + deploymentConfig = await loadYamlFileSystem(context) robot.log.debug(`deploymentConfig is ${JSON.stringify(deploymentConfig)}`) const configManager = new ConfigManager(context, ref) const runtimeConfig = await configManager.loadGlobalSettingsYaml() - const config = Object.assign({}, deploymentConfig, runtimeConfig) - const renameConfig = Object.assign({}, config, rename) + const renameConfig = Object.assign({}, runtimeConfig, rename) + const config = { deploymentConfig, runtimeConfig: renameConfig } robot.log.debug(`config for ref ${ref} is ${JSON.stringify(config)}`) - return Settings.sync(nop, context, repo, renameConfig, ref) + return Settings.sync(nop, context, repo, config, ref) } catch (e) { if (nop) { let filename = env.SETTINGS_FILE_PATH @@ -121,16 +122,8 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => * * @return The parsed YAML file */ - async function loadYamlFileSystem () { - if (deploymentConfig === undefined) { - const deploymentConfigPath = env.DEPLOYMENT_CONFIG_FILE - if (fs.existsSync(deploymentConfigPath)) { - deploymentConfig = yaml.load(fs.readFileSync(deploymentConfigPath)) - } else { - deploymentConfig = { restrictedRepos: ['admin', '.github', 'safe-settings'] } - } - } - return deploymentConfig + async function loadYamlFileSystem (context) { + return new DeploymentConfig(context) } function getAllChangedSubOrgConfigs (payload) { diff --git a/lib/deploymentConfig.js b/lib/deploymentConfig.js index 7dd8b932f..a639de824 100644 --- a/lib/deploymentConfig.js +++ b/lib/deploymentConfig.js @@ -2,54 +2,47 @@ const yaml = require('js-yaml') const fs = require('fs') const env = require('./env') +function isIterable (obj) { + // checks for null and undefined + if (obj == null) { + return false + } + return typeof obj[Symbol.iterator] === 'function' +} + /** * Class representing a deployment config. - * It is a singleton (class object) for the deployment settings. - * The settings are loaded from the deployment-settings.yml file during initialization and stored as static properties. + * The settings are loaded from the deployment-settings.yml file. */ -class DeploymentConfig { - // static config - static configvalidators = {} - static overridevalidators = {} +module.exports = class DeploymentConfig { + constructor (context, configPath) { + const deploymentConfigPath = configPath ?? env.DEPLOYMENT_CONFIG_FILE - static { - const deploymentConfigPath = process.env.DEPLOYMENT_CONFIG_FILE ? process.env.DEPLOYMENT_CONFIG_FILE : 'deployment-settings.yml' + let deploymentConfig = {} if (fs.existsSync(deploymentConfigPath)) { - this.config = yaml.load(fs.readFileSync(deploymentConfigPath)) + deploymentConfig = yaml.load(fs.readFileSync(deploymentConfigPath)) } else { - this.config = { restrictedRepos: ['admin', '.github', 'safe-settings'] } + context.log.info(`No deployment settings found at ${deploymentConfigPath}`) } - const overridevalidators = this.config.overridevalidators - if (this.isIterable(overridevalidators)) { - for (const validator of overridevalidators) { + this.overridevalidators = {} + if (isIterable(deploymentConfig.overridevalidators)) { + for (const validator of deploymentConfig.overridevalidators) { // eslint-disable-next-line no-new-func const f = new Function('baseconfig', 'overrideconfig', 'githubContext', validator.script) this.overridevalidators[validator.plugin] = { canOverride: f, error: validator.error } } } - const configvalidators = this.config.configvalidators - if (this.isIterable(configvalidators)) { - for (const validator of configvalidators) { + + this.configvalidators = {} + if (isIterable(deploymentConfig.configvalidators)) { + for (const validator of deploymentConfig.configvalidators) { // eslint-disable-next-line no-new-func const f = new Function('baseconfig', 'githubContext', validator.script) this.configvalidators[validator.plugin] = { isValid: f, error: validator.error } } } - } - static isIterable (obj) { - // checks for null and undefined - if (obj == null) { - return false - } - return typeof obj[Symbol.iterator] === 'function' - } - - // eslint-disable-next-line no-useless-constructor - constructor (nop, context, repo, config, ref, suborg) { + this.restrictedRepos = deploymentConfig.restrictedRepos ?? ['admin', '.github', 'safe-settings'] } } -DeploymentConfig.FILE_NAME = `${env.CONFIG_PATH}/settings.yml` - -module.exports = DeploymentConfig diff --git a/lib/mergeDeep.js b/lib/mergeDeep.js index ab278e5c2..2747b79a1 100644 --- a/lib/mergeDeep.js +++ b/lib/mergeDeep.js @@ -6,12 +6,14 @@ const NAME_USERNAME_PROPERTY = item => NAME_FIELDS.find(prop => Object.prototype const GET_NAME_USERNAME_PROPERTY = item => { if (NAME_USERNAME_PROPERTY(item)) return item[NAME_USERNAME_PROPERTY(item)] } class MergeDeep { - constructor (log, github, ignorableFields = [], configvalidators = {}, overridevalidators = {}) { + constructor (log, github, ignorableFields = []) { this.log = log this.github = github this.ignorableFields = ignorableFields - this.configvalidators = DeploymentConfig.configvalidators - this.overridevalidators = DeploymentConfig.overridevalidators + + const deploymentConfig = new DeploymentConfig({ log }) + this.configvalidators = deploymentConfig.configvalidators + this.overridevalidators = deploymentConfig.overridevalidators } isObjectNotArray (item) { diff --git a/lib/settings.js b/lib/settings.js index 9e00c1400..9c07f55b3 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -10,6 +10,7 @@ const env = require('./env') const CONFIG_PATH = env.CONFIG_PATH const eta = new Eta({ views: path.join(__dirname) }) const SCOPE = { ORG: 'org', REPO: 'repo' } // Determine if the setting is a org setting or repo setting + class Settings { static async syncAll (nop, context, repo, config, ref) { const settings = new Settings(nop, context, repo, config, ref) @@ -65,7 +66,6 @@ class Settings { this.installation_id = context.payload.installation.id this.github = context.octokit this.repo = repo - this.config = config this.nop = nop this.suborgChange = !!suborg // If suborg config has been updated, do not load the entire suborg config, and only process repos restricted to it. @@ -75,26 +75,15 @@ class Settings { this.log = context.log this.results = [] this.errors = [] - this.configvalidators = {} - this.overridevalidators = {} - const overridevalidators = config.overridevalidators - if (this.isIterable(overridevalidators)) { - for (const validator of overridevalidators) { - // eslint-disable-next-line no-new-func - const f = new Function('baseconfig', 'overrideconfig', 'githubContext', validator.script) - this.overridevalidators[validator.plugin] = { canOverride: f, error: validator.error } - } - } - const configvalidators = config.configvalidators - if (this.isIterable(configvalidators)) { - for (const validator of configvalidators) { - this.log.debug(`Logging each script: ${typeof validator.script}`) - // eslint-disable-next-line no-new-func - const f = new Function('baseconfig', 'githubContext', validator.script) - this.configvalidators[validator.plugin] = { isValid: f, error: validator.error } - } - } - this.mergeDeep = new MergeDeep(this.log, this.github, [], this.configvalidators, this.overridevalidators) + + this.mergeDeep = new MergeDeep(this.log, this.github, []) + + this.config = config.runtimeConfig + + // these can only be defined in the deployment config + this.overridevalidators = config.deploymentConfig.overridevalidators + this.configvalidators = config.deploymentConfig.configvalidators + this.restrictedRepos = config.deploymentConfig.restrictedRepos } // Create a check in the Admin repo for safe-settings. @@ -445,7 +434,7 @@ ${this.results.reduce((x, y) => { } isRestricted(repoName) { - const restrictedRepos = this.config.restrictedRepos + const restrictedRepos = this.restrictedRepos // Skip configuring any restricted repos if (Array.isArray(restrictedRepos)) { // For backward compatibility support the old format @@ -887,14 +876,6 @@ ${this.results.reduce((x, y) => { isObject (item) { return (item && typeof item === 'object' && !Array.isArray(item)) } - - isIterable(obj) { - // checks for null and undefined - if (obj == null) { - return false - } - return typeof obj[Symbol.iterator] === 'function' - } } function prettify (obj) { diff --git a/test/unit/lib/deploymentConfig.test.js b/test/unit/lib/deploymentConfig.test.js new file mode 100644 index 000000000..4da92e825 --- /dev/null +++ b/test/unit/lib/deploymentConfig.test.js @@ -0,0 +1,62 @@ +const DeploymentConfig = require('../../../lib/deploymentConfig') + +const defaultConfig = { + configvalidators: {}, + overridevalidators: {}, + restrictedRepos: ['admin', '.github', 'safe-settings'] +} + +const context = { log: { info: jest.fn() } } + +describe('no deploymentConfig', () => { + const deploymentConfig = new DeploymentConfig(context, 'nonexistent.yml') + + test('matches default config', () => { + expect(deploymentConfig).toMatchObject(defaultConfig) + }) + + test('outputs info message', () => { + expect(context.log.info).toHaveBeenCalledWith('No deployment settings found at nonexistent.yml') + }) +}) + +describe('sample deploymentConfig', () => { + const deploymentConfig = new DeploymentConfig(context, './docs/sample-settings/sample-deployment-settings.yml') + + test('matches snapshot', () => { + expect(deploymentConfig).toMatchInlineSnapshot(` +DeploymentConfig { + "configvalidators": { + "collaborators": { + "error": "\`Admin cannot be assigned to collaborators\` +", + "isValid": [Function], + }, + }, + "overridevalidators": { + "branches": { + "canOverride": [Function], + "error": "\`Branch protection required_approving_review_count cannot be overidden to a lower value\` +", + }, + "labels": { + "canOverride": [Function], + "error": "Some error +", + }, + }, + "restrictedRepos": { + "exclude": [ + "^admin$", + "^\\.github$", + "^safe-settings$", + ".*-test", + ], + "include": [ + "^test$", + ], + }, +} +`) + }) +}) diff --git a/test/unit/lib/settings.test.js b/test/unit/lib/settings.test.js index c91583d36..5a7b424fd 100644 --- a/test/unit/lib/settings.test.js +++ b/test/unit/lib/settings.test.js @@ -8,6 +8,7 @@ const yaml = require('js-yaml') // return OriginalSettings // }) +let settings describe('Settings Tests', () => { let stubContext @@ -19,7 +20,7 @@ describe('Settings Tests', () => { function createSettings(config) { const settings = new Settings(false, stubContext, mockRepo, config, mockRef, mockSubOrg) - return settings; + return settings } beforeEach(() => { @@ -52,7 +53,7 @@ repository: # A comma-separated list of topics to set on the repository topics: - frontend - `).toString('base64'); + `).toString('base64') mockOctokit.repos = { getContent: jest.fn().mockResolvedValue({ data: { content } }) } @@ -83,18 +84,17 @@ repository: } } - - mockRepo = { owner: 'test', repo: 'test-repo' } mockRef = 'main' mockSubOrg = 'frontend' }) describe('restrictedRepos', () => { - describe('restrictedRepos not defined', () => { + describe('restrictedRepos is empty object', () => { beforeEach(() => { stubConfig = { - restrictedRepos: { + deploymentConfig: { + restrictedRepos: {} } } }) @@ -113,11 +113,74 @@ repository: }) }) + describe('restrictedRepos is not present', () => { + beforeEach(() => { + stubConfig = { + deploymentConfig: {} + } + }) + + it('throws TypeError', () => { + settings = createSettings(stubConfig) + expect(() => settings.isRestricted('my-repo')).toThrow('Cannot read properties of undefined (reading \'include\')') + }) + }) + + describe('restrictedRepos is null', () => { + beforeEach(() => { + stubConfig = { + deploymentConfig: { + restrictedRepos: null + } + } + }) + + it('throws TypeError', () => { + settings = createSettings(stubConfig) + expect(() => settings.isRestricted('my-repo')).toThrow('Cannot read properties of null (reading \'include\')') + }) + }) + + describe('restrictedRepos is empty array', () => { + beforeEach(() => { + stubConfig = { + deploymentConfig: { + restrictedRepos: [] + } + } + }) + + it('allows all repositories', () => { + settings = createSettings(stubConfig) + expect(settings.isRestricted('my-repo')).toEqual(false) + }) + }) + + describe('restrictedRepos also defined in runtimeConfig', () => { + beforeEach(() => { + stubConfig = { + deploymentConfig: { + restrictedRepos: ['admin', '.github', 'safe-settings'] + }, + runtimeConfig: { + restrictedRepos: ['foo', 'bar'] + } + } + }) + + it('ignores restrictedRepos from runtimeConfig', () => { + settings = createSettings(stubConfig) + expect(settings.restrictedRepos).toMatchObject(['admin', '.github', 'safe-settings']) + }) + }) + describe('restrictedRepos.exclude defined', () => { beforeEach(() => { stubConfig = { - restrictedRepos: { - exclude: ['foo', '.*-test$', '^personal-.*$'] + deploymentConfig: { + restrictedRepos: { + exclude: ['foo', '.*-test$', '^personal-.*$'] + } } } }) @@ -143,8 +206,10 @@ repository: describe('restrictedRepos.include defined', () => { beforeEach(() => { stubConfig = { - restrictedRepos: { - include: ['foo', '.*-test$', '^personal-.*$'] + deploymentConfig: { + restrictedRepos: { + include: ['foo', '.*-test$', '^personal-.*$'] + } } } }) @@ -166,37 +231,14 @@ repository: expect(settings.isRestricted('personalization-repo')).toEqual(true) }) }) - - describe('restrictedRepos not defined', () => { - it('Throws TypeError if restrictedRepos not defined', () => { - stubConfig = {} - settings = createSettings(stubConfig) - expect(() => settings.isRestricted('my-repo')).toThrow('Cannot read properties of undefined (reading \'include\')') - }) - - it('Throws TypeError if restrictedRepos is null', () => { - stubConfig = { - restrictedRepos: null - } - settings = createSettings(stubConfig) - expect(() => settings.isRestricted('my-repo')).toThrow('Cannot read properties of null (reading \'include\')') - }) - - it('Allowing all repositories if restrictedRepos is empty', () => { - stubConfig = { - restrictedRepos: [] - } - settings = createSettings(stubConfig) - expect(settings.isRestricted('my-repo')).toEqual(false) - }) - }) }) // restrictedRepos describe('loadConfigs', () => { describe('load suborg configs', () => { beforeEach(() => { stubConfig = { - restrictedRepos: { + deploymentConfig: { + restrictedRepos: {} } } subOrgConfig = yaml.load(` diff --git a/test/unit/lib/validator.test.js b/test/unit/lib/validator.test.js index 56a1b87a0..abcd699cc 100644 --- a/test/unit/lib/validator.test.js +++ b/test/unit/lib/validator.test.js @@ -4,6 +4,8 @@ const MergeDeep = require('../../../lib/mergeDeep') const YAML = require('js-yaml') const log = require('pino')('test.log') +jest.mock('../../../lib/deploymentConfig') + describe('Validator Tests', () => { it('Branch override validator test', () => { const overrideMock = jest.fn((baseconfig, overrideconfig) => { @@ -20,8 +22,10 @@ describe('Validator Tests', () => { console.log(`Branch config validator, baseconfig ${baseconfig}`) return false }) - DeploymentConfig.overridevalidators = { branches: { canOverride: overrideMock, error: 'Branch overrideValidators.error' } } - DeploymentConfig.configvalidators = { branches: { isValid: configMock, error: 'Branch configValidators.error' } } + DeploymentConfig.mockImplementation(() => ({ + overridevalidators: { branches: { canOverride: overrideMock, error: 'Branch overrideValidators.error' } }, + configvalidators: { branches: { isValid: configMock, error: 'Branch configValidators.error' } } + })) const overrideconfig = YAML.load(` branches: @@ -77,8 +81,10 @@ describe('Validator Tests', () => { console.log(`Repo config validator, baseconfig ${baseconfig}`) return false }) - DeploymentConfig.overridevalidators = { repository: { canOverride: overrideMock, error: 'Repo overrideValidators.error' } } - DeploymentConfig.configvalidators = { repository: { isValid: configMock, error: 'Repo configValidators.error' } } + DeploymentConfig.mockImplementation(() => ({ + overridevalidators: { repository: { canOverride: overrideMock, error: 'Repo overrideValidators.error' } }, + configvalidators: { branches: { isValid: configMock, error: 'Branch configValidators.error' } } + })) const overrideconfig = YAML.load(` repository: @@ -132,8 +138,10 @@ describe('Validator Tests', () => { console.log(`Repo config validator, baseconfig ${baseconfig}`) return false }) - DeploymentConfig.overridevalidators = { repository: { canOverride: overrideMock, error: 'Repo overrideValidators.error' } } - DeploymentConfig.configvalidators = { repository: { isValid: configMock, error: 'Repo configValidators.error' } } + DeploymentConfig.mockImplementation(() => ({ + overridevalidators: { repository: { canOverride: overrideMock, error: 'Repo overrideValidators.error' } }, + configvalidators: { repository: { isValid: configMock, error: 'Repo configValidators.error' } } + })) const overrideconfig = YAML.load(` repository: From d837f579b8b5c35a76dfcd9bad54c8d6c0f3e46a Mon Sep 17 00:00:00 2001 From: Jonathan Morley Date: Wed, 5 Mar 2025 12:05:09 -0500 Subject: [PATCH 2/3] test: add log.info to tests --- test/unit/lib/plugins/autolinks.test.js | 2 +- test/unit/lib/plugins/branches.test.js | 1 + test/unit/lib/plugins/collaborators.test.js | 2 +- test/unit/lib/plugins/custom_properties.test.js | 2 +- test/unit/lib/plugins/labels.test.js | 2 +- test/unit/lib/plugins/repository.test.js | 1 + test/unit/lib/plugins/rulesets.test.js | 1 + test/unit/lib/plugins/teams.test.js | 2 +- 8 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/unit/lib/plugins/autolinks.test.js b/test/unit/lib/plugins/autolinks.test.js index 10413cc1a..721a29857 100644 --- a/test/unit/lib/plugins/autolinks.test.js +++ b/test/unit/lib/plugins/autolinks.test.js @@ -5,7 +5,7 @@ describe('Autolinks', () => { let github function configure (config) { - const log = { debug: jest.fn(), error: console.error } + const log = { ...console, debug: jest.fn() } const nop = false const errors = [] return new Autolinks(nop, github, repo, config, log, errors) diff --git a/test/unit/lib/plugins/branches.test.js b/test/unit/lib/plugins/branches.test.js index 62b50cb1f..2800daad3 100644 --- a/test/unit/lib/plugins/branches.test.js +++ b/test/unit/lib/plugins/branches.test.js @@ -6,6 +6,7 @@ const Branches = require('../../../../lib/plugins/branches') describe('Branches', () => { let github const log = jest.fn() + log.info = jest.fn() log.debug = jest.fn() log.error = jest.fn() diff --git a/test/unit/lib/plugins/collaborators.test.js b/test/unit/lib/plugins/collaborators.test.js index 359dd4614..00584cbae 100644 --- a/test/unit/lib/plugins/collaborators.test.js +++ b/test/unit/lib/plugins/collaborators.test.js @@ -4,7 +4,7 @@ describe('Collaborators', () => { let github function configure (config) { - const log = { debug: jest.fn(), error: console.error } + const log = { ...console, debug: jest.fn() } return new Collaborators(undefined, github, { owner: 'bkeepers', repo: 'test' }, config, log) } diff --git a/test/unit/lib/plugins/custom_properties.test.js b/test/unit/lib/plugins/custom_properties.test.js index f11488376..e3461bec5 100644 --- a/test/unit/lib/plugins/custom_properties.test.js +++ b/test/unit/lib/plugins/custom_properties.test.js @@ -19,7 +19,7 @@ describe('CustomProperties', () => { // ] // }) } - log = { debug: jest.fn(), error: console.error } + log = { ...console, debug: jest.fn() } }) describe('sync', () => { diff --git a/test/unit/lib/plugins/labels.test.js b/test/unit/lib/plugins/labels.test.js index 71eaf2c8b..79b50c25a 100644 --- a/test/unit/lib/plugins/labels.test.js +++ b/test/unit/lib/plugins/labels.test.js @@ -26,7 +26,7 @@ describe('Labels', () => { updateLabel: jest.fn().mockImplementation(() => Promise.resolve()) } } - log = { debug: jest.fn(), error: console.error } + log = { ...console, debug: jest.fn() } }) describe('sync', () => { diff --git a/test/unit/lib/plugins/repository.test.js b/test/unit/lib/plugins/repository.test.js index b7af39128..aa8d56ac1 100644 --- a/test/unit/lib/plugins/repository.test.js +++ b/test/unit/lib/plugins/repository.test.js @@ -13,6 +13,7 @@ describe('Repository', () => { } } const log = jest.fn() + log.info = jest.fn() log.debug = jest.fn() log.error = jest.fn() diff --git a/test/unit/lib/plugins/rulesets.test.js b/test/unit/lib/plugins/rulesets.test.js index f15abd63f..c36705566 100644 --- a/test/unit/lib/plugins/rulesets.test.js +++ b/test/unit/lib/plugins/rulesets.test.js @@ -85,6 +85,7 @@ function generateResponseRuleset(id, name, conditions, checks, org=false) { describe('Rulesets', () => { let github const log = jest.fn() + log.info = jest.fn() log.debug = jest.fn() log.error = jest.fn() diff --git a/test/unit/lib/plugins/teams.test.js b/test/unit/lib/plugins/teams.test.js index 60ef23dbc..108aa28e9 100644 --- a/test/unit/lib/plugins/teams.test.js +++ b/test/unit/lib/plugins/teams.test.js @@ -15,7 +15,7 @@ describe('Teams', () => { const org = 'bkeepers' function configure (config) { - const log = { debug: jest.fn(), error: console.error } + const log = { ...console, debug: jest.fn() } const errors = [] return new Teams(undefined, github, { owner: 'bkeepers', repo: 'test' }, config, log, errors) } From 464ae61b74df844fdd9c0cbf2d84f4f60a5d248f Mon Sep 17 00:00:00 2001 From: "mend-5034428[bot]" Date: Thu, 6 Mar 2025 14:47:14 +0000 Subject: [PATCH 3/3] chore(deps): replace dependency npm-run-all with npm-run-all2 ^5.0.0 --- package-lock.json | 208 ++++++++++------------------------------------ package.json | 2 +- 2 files changed, 46 insertions(+), 164 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8823564d6..611675893 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "lockfile-lint": "^4.14.0", "nock": "^14.0.1", "nodemon": "^3.1.9", - "npm-run-all": "^4.1.5", + "npm-run-all2": "^5.0.0", "smee-client": "^3.1.1", "standard": "^17.1.2" }, @@ -3539,6 +3539,13 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://nexus.core.cvent.org/nexus/repository/npm-public/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/pg": { "version": "8.6.1", "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", @@ -9644,12 +9651,6 @@ "node": ">= 0.6" } }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node_modules/nock": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.1.tgz", @@ -9760,21 +9761,20 @@ "node": ">=0.10.0" } }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "node_modules/npm-run-all2": { + "version": "5.0.2", + "resolved": "https://nexus.core.cvent.org/nexus/repository/npm-public/npm-run-all2/-/npm-run-all2-5.0.2.tgz", + "integrity": "sha512-S2G6FWZ3pNWAAKm2PFSOtEAG/N+XO/kz3+9l6V91IY+Y3XFSt7Lp7DV92KCgEboEW0hRTu0vFaMe4zXDZYaOyA==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", + "ansi-styles": "^5.0.0", + "cross-spawn": "^7.0.3", "memorystream": "^0.3.1", "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" + "pidtree": "^0.5.0", + "read-pkg": "^5.2.0", + "shell-quote": "^1.6.1" }, "bin": { "npm-run-all": "bin/npm-run-all/index.js", @@ -9782,75 +9782,20 @@ "run-s": "bin/run-s/index.js" }, "engines": { - "node": ">= 4" + "node": ">= 10" } }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://nexus.core.cvent.org/nexus/repository/npm-public/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, "engines": { - "node": ">=4.8" - } - }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" + "node": ">=10" }, - "bin": { - "which": "bin/which" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/npm-run-path": { @@ -10445,10 +10390,11 @@ } }, "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "version": "0.5.0", + "resolved": "https://nexus.core.cvent.org/nexus/repository/npm-public/pidtree/-/pidtree-0.5.0.tgz", + "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", "dev": true, + "license": "MIT", "bin": { "pidtree": "bin/pidtree.js" }, @@ -10980,75 +10926,29 @@ "dev": true }, "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "version": "5.2.0", + "resolved": "https://nexus.core.cvent.org/nexus/repository/npm-public/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, + "license": "MIT", "dependencies": { - "pify": "^3.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/read-pkg/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://nexus.core.cvent.org/nexus/repository/npm-public/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/readdirp": { @@ -12039,24 +11939,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.padend": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", - "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/string.prototype.repeat": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", diff --git a/package.json b/package.json index c1f2f5c50..451a2b0d1 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "lockfile-lint": "^4.14.0", "nock": "^14.0.1", "nodemon": "^3.1.9", - "npm-run-all": "^4.1.5", + "npm-run-all2": "^5.0.0", "smee-client": "^3.1.1", "standard": "^17.1.2" },