diff --git a/index.js b/index.js index 8b1305eb..d4c58842 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,14 @@ const NopCommand = require('./lib/nopcommand') const SettingsGenerator = require('./lib/settingsGenerator') const AppOctokitClient = require('./lib/appOctokitClient') const env = require('./lib/env') +const { getProxyForUrl } = require('proxy-from-env') +const { setGlobalDispatcher, ProxyAgent } = require('undici') + +const baseUrl = env.GHE_HOST ? `${env.GHE_PROTOCOL || 'https'}://${env.GHE_HOST}` : 'https://api.github.com' +const proxyAddress = getProxyForUrl(baseUrl) +if (proxyAddress) { + setGlobalDispatcher(new ProxyAgent(proxyAddress)) +} let deploymentConfig @@ -589,7 +597,7 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => repo: env.ADMIN_REPO, path: oldPath, headers: { - 'X-GitHub-Api-Version': '2022-11-28' + 'X-GitHub-Api-Version': '2026-03-10' } }) let content = Buffer.from(repofile.data.content, 'base64').toString() @@ -603,7 +611,7 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => repo: env.ADMIN_REPO, path: newPath, headers: { - 'X-GitHub-Api-Version': '2022-11-28' + 'X-GitHub-Api-Version': '2026-03-10' } }) } catch (error) { @@ -618,7 +626,7 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => message: `Repo Renamed and safe-settings renamed the file from ${payload.changes.repository.name.from} to ${payload.repository.name}`, sha: repofile.data.sha, headers: { - 'X-GitHub-Api-Version': '2022-11-28' + 'X-GitHub-Api-Version': '2026-03-10' } }) robot.log.debug(`Created a new setting file ${newPath}`) diff --git a/lib/plugins/variables.js b/lib/plugins/variables.js index 292c9b1b..470a3471 100644 --- a/lib/plugins/variables.js +++ b/lib/plugins/variables.js @@ -6,7 +6,6 @@ module.exports = class Variables extends Diffable { super(...args) if (this.entries) { - // Force all names to uppercase to avoid comparison issues. this.entries.forEach((variable) => { variable.name = variable.name.toUpperCase() }) diff --git a/lib/settings.js b/lib/settings.js index e36ee07c..84325ca6 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -2025,7 +2025,7 @@ class Settings { // Copilot code review would recoommend using object assign but that would cause the error let repoConfig = this.config.repository if (repoConfig) { - repoConfig = Object.assign(repoConfig, { name: repo.repo, org: repo.owner }) + repoConfig = Object.assign({}, repoConfig, { name: repo.repo, org: repo.owner }) } const subOrgConfig = this.getSubOrgConfig(repo.repo) @@ -2041,7 +2041,8 @@ class Settings { if (subOrgConfig) { let suborgRepoConfig = subOrgConfig.repository if (suborgRepoConfig) { - suborgRepoConfig = Object.assign(suborgRepoConfig, { name: repo.repo, org: repo.owner }) + // Create a new object to avoid mutating the shared subOrgConfig.repository + suborgRepoConfig = Object.assign({}, suborgRepoConfig, { name: repo.repo, org: repo.owner }) repoConfig = this.mergeDeep.mergeDeep({}, repoConfig, suborgRepoConfig) } } @@ -2556,7 +2557,7 @@ class Settings { this.log.debug(` In getRepoConfigMap ${JSON.stringify(this.repo)}`) // GitHub getContent api has a hard limit of returning 1000 entries without // any pagination. They suggest to use Tree api. - // https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-repository-content + // https://docs.github.com/en/rest/repos/contents?apiVersion=2026-03-10#get-repository-content // get /repos directory sha to use in the getTree api const repo = { owner: this.repo.owner, repo: env.ADMIN_REPO } diff --git a/package-lock.json b/package-lock.json index 03059ad9..91876708 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,10 +32,10 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.6.0", "http-status-codes": "^2.2.0", - "jest": "^29.5.0", - "jest-junit": "^16.0.0", + "jest": "^29.7.0", + "jest-junit": "^17.0.0", "jest-when": "^3.5.2", - "lockfile-lint": "^4.14.0", + "lockfile-lint": "^4.14.1", "nock": "^14.0.1", "nodemon": "^3.1.9", "npm-run-all": "^4.1.5", @@ -771,7 +771,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -3887,7 +3886,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -4494,21 +4492,34 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^1.0.5", + "content-type": "^2.0.0", "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", "engines": { "node": ">=18" }, @@ -6556,7 +6567,6 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -6939,9 +6949,9 @@ } }, "node_modules/flatted": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", - "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true, "license": "ISC" }, @@ -8872,19 +8882,19 @@ } }, "node_modules/jest-junit": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", - "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-17.0.0.tgz", + "integrity": "sha512-RYWCkq4j59gUXj5DsgbIE7xFBZzu1gtibPhyjSjMmGaOTLnqlXhg7x9zuGCwgbCuMAyoyvk0Mi8wSrRR5uOeLA==", "dev": true, "license": "Apache-2.0", "dependencies": { "mkdirp": "^1.0.4", "strip-ansi": "^6.0.1", - "uuid": "^8.3.2", + "uuid": "^14.0.0", "xml": "^1.0.1" }, "engines": { - "node": ">=10.12.0" + "node": ">=20.0.0" } }, "node_modules/jest-leak-detector": { @@ -9950,6 +9960,7 @@ "url": "https://github.com/sponsors/nodeca" } ], + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -11698,7 +11709,6 @@ "version": "14.3.2", "resolved": "https://registry.npmjs.org/probot/-/probot-14.3.2.tgz", "integrity": "sha512-Bprr2KwlVF4Jpb6bnIcfadA4Dtns8nDJxSEEPNy3FhRrtHUYxZGiczReG5Vo6M7t4iS8Kcvek7CDUTTXgkaSBw==", - "license": "ISC", "dependencies": { "@octokit/core": "^7.0.3", "@octokit/plugin-enterprise-compatibility": "^6.0.1", @@ -11856,12 +11866,12 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -12526,6 +12536,7 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -12540,13 +12551,14 @@ "license": "BSD-2-Clause" }, "node_modules/side-channel": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", - "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.4", - "side-channel-list": "^1.0.1", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -12558,12 +12570,13 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" + "object-inspect": "^1.13.3" }, "engines": { "node": ">= 0.4" @@ -12742,8 +12755,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/stack-utils": { "version": "2.0.6", @@ -13430,17 +13442,34 @@ } }, "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", "dependencies": { - "content-type": "^1.0.5", + "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typed-array-buffer": { @@ -13558,9 +13587,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.5.tgz", - "integrity": "sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", "license": "MIT", "engines": { "node": ">=20.18.1" @@ -13654,13 +13683,17 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/v8-to-istanbul": { diff --git a/package.json b/package.json index db6bed66..be427e6e 100644 --- a/package.json +++ b/package.json @@ -51,10 +51,10 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.6.0", "http-status-codes": "^2.2.0", - "jest": "^29.5.0", - "jest-junit": "^16.0.0", + "jest": "^29.7.0", + "jest-junit": "^17.0.0", "jest-when": "^3.5.2", - "lockfile-lint": "^4.14.0", + "lockfile-lint": "^4.14.1", "nock": "^14.0.1", "nodemon": "^3.1.9", "npm-run-all": "^4.1.5", diff --git a/test/unit/lib/plugins/archive.test.js b/test/unit/lib/plugins/archive.test.js index 0ed0f38d..a60eafac 100644 --- a/test/unit/lib/plugins/archive.test.js +++ b/test/unit/lib/plugins/archive.test.js @@ -93,6 +93,56 @@ describe('Archive Plugin', () => { }) }) + describe('getState', () => { + it('getState when repo is already archived and desired state is not set returns isArchived true shouldArchive false shouldUnarchive false', async () => { + // Arrange + github.rest.repos.get.mockResolvedValue({ data: { archived: true } }) + archive = new Archive(false, github, repo, {}, log) + + // Act + const result = await archive.getState() + + // Assert + expect(result).toEqual({ + isArchived: true, + shouldArchive: false, + shouldUnarchive: false + }) + }) + + it('getState when repo is not archived and desired state is not set returns isArchived false shouldArchive false shouldUnarchive false', async () => { + // Arrange + github.rest.repos.get.mockResolvedValue({ data: { archived: false } }) + archive = new Archive(false, github, repo, {}, log) + + // Act + const result = await archive.getState() + + // Assert + expect(result).toEqual({ + isArchived: false, + shouldArchive: false, + shouldUnarchive: false + }) + }) + + it('getState when repo is archived and desired state is false returns isArchived true shouldArchive false shouldUnarchive true', async () => { + // Arrange + github.rest.repos.get.mockResolvedValue({ data: { archived: true } }) + archive = new Archive(false, github, repo, { archived: false }, log) + + // Act + const result = await archive.getState() + + // Assert + expect(result).toEqual({ + isArchived: true, + shouldArchive: false, + shouldUnarchive: true + }) + }) + }) + describe('sync', () => { beforeEach(() => { archive = new Archive(false, github, repo, settings, log)