From a838bc4ce5ace50000c56d4bf627cf3b63931d9f Mon Sep 17 00:00:00 2001 From: "Gavin Barron (from Dev Box)" Date: Fri, 9 Oct 2026 11:33:02 -0700 Subject: [PATCH 1/4] fix(hidi): automate independent v2 version PRs Use the existing pinned release-please engine with exact component path exclusions and an isolated, tag-free Hidi version PR lifecycle. Preserve OData releases, baseline versions, and protected publishing gates; verify real generated plans, repeated cycles, and measured runner coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dc4344a-fac5-4e6e-89f8-eb2c9467edd4 --- .github/release-please/package-lock.json | 1858 ++++++++++++++++++++++ .github/release-please/package.json | 15 + .github/release-please/run.cjs | 203 +++ .github/release-please/run.test.cjs | 499 ++++++ .github/workflows/release-please-gha.yml | 69 +- .github/workflows/sonarcloud.yml | 22 +- CONTRIBUTING.md | 60 +- README.md | 8 +- hidi-release-please-config.json | 19 +- release-please-config.json | 5 + src/Microsoft.OpenApi.Hidi/CHANGELOG.md | 3 +- src/Microsoft.OpenApi.Hidi/readme.md | 13 +- 12 files changed, 2747 insertions(+), 27 deletions(-) create mode 100644 .github/release-please/package-lock.json create mode 100644 .github/release-please/package.json create mode 100644 .github/release-please/run.cjs create mode 100644 .github/release-please/run.test.cjs diff --git a/.github/release-please/package-lock.json b/.github/release-please/package-lock.json new file mode 100644 index 00000000..96494217 --- /dev/null +++ b/.github/release-please/package-lock.json @@ -0,0 +1,1858 @@ +{ + "name": "openapi-odata-release-please", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openapi-odata-release-please", + "dependencies": { + "@actions/core": "1.11.1", + "release-please": "17.3.0" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/@actions/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", + "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", + "dependencies": { + "@actions/exec": "^1.1.1", + "@actions/http-client": "^2.0.1" + } + }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@conventional-commits/parser": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@conventional-commits/parser/-/parser-0.4.1.tgz", + "integrity": "sha512-H2ZmUVt6q+KBccXfMBhbBF14NlANeqHTXL4qCL6QGbMzrc4HDXyzWuxPxPNbz71f/5UkR5DrycP5VO9u7crahg==", + "dependencies": { + "unist-util-visit": "^2.0.3", + "unist-util-visit-parents": "^3.1.1" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@google-automations/git-file-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@google-automations/git-file-utils/-/git-file-utils-3.2.1.tgz", + "integrity": "sha512-LYOjAnGu/xtEkYYh6W3/1RmeK9HB/fV+xMe7nHc+WiDYrnxAJWBfcyUucoJtYS8XAhVUzNWrQvYDPRbxe67DNQ==", + "dependencies": { + "@octokit/rest": "^20.1.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": ">= 22" + } + }, + "node_modules/@iarna/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-td6ZUkz2oS3VeleBcN+m//Q6HlCFCPrnI0FZhrt/h4XqLEdOyYp2u21nd8MdsR+WJy5r9PTDaHTDDfhf4H4l6Q==" + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", + "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.4.1", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", + "dependencies": { + "@octokit/request": "^8.4.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.4.4-cjs.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.4-cjs.2.tgz", + "integrity": "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==", + "dependencies": { + "@octokit/types": "^13.7.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", + "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "13.3.2-cjs.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.2-cjs.1.tgz", + "integrity": "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==", + "dependencies": { + "@octokit/types": "^13.8.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^5" + } + }, + "node_modules/@octokit/request": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", + "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", + "dependencies": { + "@octokit/endpoint": "^9.0.6", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", + "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/rest": { + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.2.tgz", + "integrity": "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==", + "dependencies": { + "@octokit/core": "^5.0.2", + "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", + "@octokit/plugin-request-log": "^4.0.0", + "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==" + }, + "node_modules/@types/npm-package-arg": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/npm-package-arg/-/npm-package-arg-6.1.4.tgz", + "integrity": "sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q==" + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, + "node_modules/@types/yargs": { + "version": "16.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.11.tgz", + "integrity": "sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==" + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/code-suggester": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/code-suggester/-/code-suggester-5.0.1.tgz", + "integrity": "sha512-8qJiiSCfkbPNWvjEFzdG1UW3axL+Bs0ldV1/TdlBKmF9I/a/WooSQZQCi9M44HoXbVTQesn/IQr6+nIWNnVIWA==", + "dependencies": { + "@octokit/rest": "^20.1.2", + "@types/yargs": "^16.0.0", + "async-retry": "^1.3.1", + "diff": "^8.0.3", + "glob": "^7.1.6", + "parse-diff": "^0.11.0", + "yargs": "^16.0.0" + }, + "bin": { + "code-suggester": "build/src/bin/code-suggester.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/code-suggester/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/code-suggester/node_modules/yargs": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz", + "integrity": "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz", + "integrity": "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==", + "dependencies": { + "conventional-commits-filter": "^3.0.0", + "dateformat": "^3.0.3", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "meow": "^8.1.2", + "semver": "^7.0.0", + "split": "^1.0.1" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-commits-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", + "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", + "dependencies": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/handlebars": { + "version": "4.7.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.10.tgz", + "integrity": "sha512-P5VJMVM7qgBn6vjXMw8WG9uVI+ncf2pi72j4de4yz5ZULLj2RGqLYaKOYGsgyrViQ0tePOVlN1tDCCXXtFqXKg==", + "dependencies": { + "minimist": "^1.2.8", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-core-module": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.17.0.tgz", + "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==", + "dependencies": { + "hasown": "^2.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/node-html-parser": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-diff": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.11.1.tgz", + "integrity": "sha512-Oq4j8LAOPOcssanQkIjxosjATBIEJhCxMCxPhMu+Ci4wdNmAEdx0O+a7gzbR2PyKXgKPvRLIN5g224+dJAsKHA==" + }, + "node_modules/parse-github-repo-url": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", + "integrity": "sha512-bSWyzBKqcSL4RrncTpGsEKoJ7H8a4L3++ifTAbTFeMHyq2wRV+42DGmQcHIrJIvdcacjIOxEuKH/w4tthF17gg==" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dependencies": { + "@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": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/release-please": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/release-please/-/release-please-17.3.0.tgz", + "integrity": "sha512-dB7HsFUpAvU1Wj9RGCINUz8Zi2qQDZiGbDEEVnJ7baNfJmk5XdYhuUFL6RcuDGjReGhp1gzY8Tc2g7vHlM4zpg==", + "dependencies": { + "@conventional-commits/parser": "^0.4.1", + "@google-automations/git-file-utils": "^3.0.0", + "@iarna/toml": "^3.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/rest": "^20.1.1", + "@types/npm-package-arg": "^6.1.0", + "@xmldom/xmldom": "^0.8.4", + "chalk": "^4.0.0", + "code-suggester": "^5.0.0", + "conventional-changelog-conventionalcommits": "^6.0.0", + "conventional-changelog-writer": "^6.0.0", + "conventional-commits-filter": "^3.0.0", + "detect-indent": "^6.1.0", + "diff": "^8.0.3", + "figures": "^3.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "js-yaml": "^4.0.0", + "jsonpath-plus": "^10.0.0", + "node-html-parser": "^6.0.0", + "parse-github-repo-url": "^1.4.1", + "semver": "^7.5.3", + "type-fest": "^3.0.0", + "typescript": "^4.6.4", + "unist-util-visit": "^2.0.3", + "unist-util-visit-parents": "^3.1.1", + "xpath": "^0.0.34", + "yaml": "^2.2.2", + "yargs": "^17.0.0" + }, + "bin": { + "release-please": "build/src/bin/release-please.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.13", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.13.tgz", + "integrity": "sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.17.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.24", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.24.tgz", + "integrity": "sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ==" + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xpath": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.34.tgz", + "integrity": "sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==", + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/.github/release-please/package.json b/.github/release-please/package.json new file mode 100644 index 00000000..cc62d4b3 --- /dev/null +++ b/.github/release-please/package.json @@ -0,0 +1,15 @@ +{ + "name": "openapi-odata-release-please", + "private": true, + "engines": { + "node": ">=24" + }, + "scripts": { + "test": "node --test run.test.cjs", + "coverage": "node -e \"require('node:fs').mkdirSync('../../artifacts/release-please', {recursive: true})\" && cd ../.. && node --test --experimental-test-coverage --test-coverage-include=.github/release-please/run.cjs --test-coverage-lines=80 --test-coverage-functions=80 --test-reporter=spec --test-reporter=lcov --test-reporter-destination=stdout --test-reporter-destination=artifacts/release-please/lcov.info .github/release-please/run.test.cjs" + }, + "dependencies": { + "@actions/core": "1.11.1", + "release-please": "17.3.0" + } +} diff --git a/.github/release-please/run.cjs b/.github/release-please/run.cjs new file mode 100644 index 00000000..67a344ae --- /dev/null +++ b/.github/release-please/run.cjs @@ -0,0 +1,203 @@ +const {GitHub, Manifest, registerPlugin} = require('release-please'); +const {ManifestPlugin} = require('release-please/build/src/plugin'); +const {Version} = require('release-please/build/src/version'); +const {buildStrategy} = require('release-please/build/src/factory'); +const {FilePullRequestOverflowHandler} = require('release-please/build/src/util/pull-request-overflow-handler'); + +const HIDI_PENDING = 'autorelease: hidi-pending'; +const HIDI_VERSIONED = 'autorelease: hidi-versioned'; +const HIDI_FLOORS = {'main': '3.10.2', 'support/v2': '2.12.2'}; + +async function ensureHidiLabels(token, owner, repo, request = fetch) { + const api = (process.env.GITHUB_API_URL || 'https://api.github.com').replace(/\/$/, ''); + const url = `${api}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/labels`; + const headers = { + Authorization: `Bearer ${token}`, + Accept: 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28' + }; + for (const label of [ + {name: HIDI_PENDING, color: 'fbca04', description: 'Pending independent Hidi version pull request'}, + {name: HIDI_VERSIONED, color: '0e8a16', description: 'Merged Hidi version pull request; no production release'} + ]) { + const labelUrl = `${url}/${encodeURIComponent(label.name)}`; + let response = await request(labelUrl, {headers}); + let expectedStatus = 200; + if (response.status === 404) { + response = await request(url, { + method: 'POST', headers: {...headers, 'Content-Type': 'application/json'}, + body: JSON.stringify(label) + }); + if (response.status === 422) { + // Another branch job may have created the same label concurrently. + response = await request(labelUrl, {headers}); + } else if (response.status !== 201) { + throw new Error(`Cannot create Hidi lifecycle label '${label.name}': HTTP ${response.status}`); + } else { + expectedStatus = 201; + } + } + if (response.status !== expectedStatus || (await response.json()).name !== label.name) { + throw new Error(`Cannot verify Hidi lifecycle label '${label.name}': HTTP ${response.status}`); + } + } +} + +class ExactPathExclusions extends ManifestPlugin { + async preconfigure(strategies, commitsByPath) { + for (const [path, config] of Object.entries(this.repositoryConfig)) { + const excludes = config.excludePaths || []; + commitsByPath[path] = commitsByPath[path].filter(commit => { + if (!Array.isArray(commit.files)) { + throw new Error(`Missing changed files for commit ${commit.sha}`); + } + return commit.files.some(file => + (path === '.' || file.startsWith(`${path}/`)) && + !excludes.some(exclude => file === exclude || file.startsWith(`${exclude}/`)) + ); + }); + } + return strategies; + } + + async run(candidates) { + for (const candidate of candidates) { + if (candidate.config.component !== 'hidi') continue; + const floor = HIDI_FLOORS[this.targetBranch]; + const version = candidate.pullRequest.version; + if (!floor || !version || version.major !== Version.parse(floor).major || + version.preRelease || version.build || version.compare(Version.parse(floor)) <= 0) { + throw new Error('Generated Hidi version is outside the branch major or migration floor'); + } + } + return candidates; + } +} + +registerPlugin('exact-path-exclusions', options => + new ExactPathExclusions(options.github, options.targetBranch, options.repositoryConfig) +); + +async function prepareHidiVersionPrs(github, manifest, branch) { + const floor = HIDI_FLOORS[branch]; + const manifestConfig = await github.getFileJson('hidi-release-please-config.json', branch); + const config = manifest.repositoryConfig['.']; + const version = manifest.releasedVersions['.']; + if (!floor || Object.keys(manifest.repositoryConfig).length !== 1 || + Object.keys(manifest.releasedVersions).length !== 1 || + config?.component !== 'hidi' || config.releaseType !== 'simple' || + !config.includeComponentInTag || !config.includeVInTag || + (config.tagSeparator && config.tagSeparator !== '-') || + config.skipGithubRelease || + !config.separatePullRequests || + manifestConfig.label !== HIDI_PENDING || + !version || version.major !== Version.parse(floor).major || + version.preRelease || version.build || version.compare(Version.parse(floor)) < 0) { + throw new Error('Unsafe Hidi branch, manifest, component, labels or version configuration'); + } + const project = await github.getFileContentsOnBranch('src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj', branch); + const projectVersions = [...project.parsedContent.matchAll(/\s*([^<]+?)\s*<\/Version>/g)]; + if (projectVersions.length !== 1 || projectVersions[0][1] !== version.toString()) { + throw new Error('Hidi project version does not match its manifest'); + } + + const strategy = await buildStrategy({...config, github, path: '.', targetBranch: branch}); + const overflow = new FilePullRequestOverflowHandler(github); + const expectedBranch = `release-please--branches--${branch}--components--hidi`; + const pending = []; + let checkpoint; + for await (const pr of github.pullRequestIterator(branch, 'MERGED', 200, false)) { + if (!pr.labels.some(label => label === HIDI_PENDING || label === HIDI_VERSIONED)) continue; + if (pr.headBranchName !== expectedBranch || !pr.sha) { + throw new Error(`Unsafe Hidi version PR #${pr.number}: unexpected branch or missing merge SHA`); + } + const releases = await strategy.buildReleases(pr); + if (releases.length !== 1 || releases[0].tag.component !== 'hidi') { + throw new Error(`Cannot parse merged Hidi version PR #${pr.number}`); + } + const release = releases[0]; + const body = await overflow.parseOverflow(pr); + if (body?.releaseData.length !== 1 || + (body.releaseData[0].component && body.releaseData[0].component !== 'hidi') || + body.releaseData[0].version?.compare(release.tag.version) !== 0) { + throw new Error(`Hidi version PR #${pr.number} has inconsistent title and body versions`); + } + if (release.tag.version.compare(version) > 0 || + release.tag.version.compare(Version.parse(floor)) <= 0) { + throw new Error(`Merged Hidi PR #${pr.number} disagrees with the current manifest or migration floor`); + } + if (release.tag.version.compare(version) === 0) { + if (checkpoint && checkpoint.sha !== pr.sha) { + throw new Error(`Multiple merged Hidi PRs claim version ${version}`); + } + checkpoint = pr; + } + if (pr.labels.includes(HIDI_PENDING)) pending.push(pr); + } + if (!checkpoint && (version.toString() !== floor || pending.length)) { + throw new Error(`No merged Hidi version PR matches manifest version ${version}`); + } + if (checkpoint) { + // A version PR merge, not a production tag, is the boundary for the next cycle. + let reachable = false; + for await (const commit of github.mergeCommitIterator(branch, { + maxResults: manifest.commitSearchDepth, backfillFiles: false + })) { + if (commit.sha === checkpoint.sha) { + reachable = true; + break; + } + } + if (!reachable) throw new Error(`Hidi checkpoint ${checkpoint.sha} is outside the branch commit search`); + } + for (const pr of pending) { + // Adding first makes an interrupted label transition safe to retry. + await github.addIssueLabels([HIDI_VERSIONED], pr.number); + await github.removeIssueLabels([HIDI_PENDING], pr.number); + } + return checkpoint?.sha; +} + +async function runReleasePlease(github, branch, component) { + if (!['odata', 'hidi'].includes(component)) throw new Error(`Unknown component: ${component}`); + const configFile = component === 'hidi' ? 'hidi-release-please-config.json' : 'release-please-config.json'; + const manifestFile = component === 'hidi' ? '.hidi-release-please-manifest.json' : '.release-please-manifest.json'; + const load = (options = {}) => Manifest.fromManifest(github, branch, configFile, manifestFile, options); + const releases = component === 'odata' ? await (await load()).createReleases() : []; + let manifest = await load(); + if (component === 'hidi') { + const lastReleaseSha = await prepareHidiVersionPrs(github, manifest, branch); + if (lastReleaseSha) manifest = await load({lastReleaseSha}); + } + const prs = await manifest.createPullRequests(); + return {releases, prs}; +} + +async function main() { + const core = require('@actions/core'); + const token = process.env.RELEASE_PLEASE_TOKEN; + const branch = process.env.GITHUB_REF_NAME; + const [owner, repo] = (process.env.GITHUB_REPOSITORY || '').split('/'); + if (!token || !branch || !owner || !repo) throw new Error('Missing release automation environment'); + if (process.argv[2] === 'hidi') await ensureHidiLabels(token, owner, repo); + const github = await GitHub.create({owner, repo, token, defaultBranch: branch}); + const {releases, prs} = await runReleasePlease(github, branch, process.argv[2]); + core.setOutput('releases_created', releases.length > 0); + core.setOutput('prs_created', prs.length > 0); + core.setOutput('prs', JSON.stringify(prs)); + core.setOutput('paths_released', JSON.stringify(releases.map(release => release.path))); + if (prs.length) core.setOutput('pr', prs[0]); + for (const release of releases) { + const prefix = release.path === '.' ? '' : `${release.path}--`; + core.setOutput(`${prefix}release_created`, true); + for (const [name, value] of Object.entries(release)) { + const key = {tagName: 'tag_name', uploadUrl: 'upload_url', notes: 'body', url: 'html_url'}[name] || name; + core.setOutput(`${prefix}${key}`, value); + } + } +} + +module.exports = {ExactPathExclusions, prepareHidiVersionPrs, runReleasePlease, ensureHidiLabels, main}; +if (require.main === module) { + main().catch(error => require('@actions/core').setFailed(error.message)); +} diff --git a/.github/release-please/run.test.cjs b/.github/release-please/run.test.cjs new file mode 100644 index 00000000..9988dd64 --- /dev/null +++ b/.github/release-please/run.test.cjs @@ -0,0 +1,499 @@ +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const {test} = require('node:test'); +const {GitHub, Manifest, setLogger} = require('release-please'); +const {Version} = require('release-please/build/src/version'); +const {PullRequestBody} = require('release-please/build/src/util/pull-request-body'); +const {runReleasePlease, main, ExactPathExclusions, ensureHidiLabels} = require('./run.cjs'); + +setLogger({debug() {}, info() {}, warn() {}, error() {}}); +const root = path.resolve(__dirname, '..', '..'); +const branch = JSON.parse(fs.readFileSync(path.join(root, '.hidi-release-please-manifest.json')))['.'].startsWith('3.') ? 'main' : 'support/v2'; +const hidiProject = 'src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj'; +const hidiReadme = 'src/Microsoft.OpenApi.Hidi/readme.md'; +const hidiChangelog = 'src/Microsoft.OpenApi.Hidi/CHANGELOG.md'; +const hidiManifest = '.hidi-release-please-manifest.json'; +const odataManifest = '.release-please-manifest.json'; +const inputPaths = [ + 'release-please-config.json', 'hidi-release-please-config.json', + hidiManifest, odataManifest, hidiProject, hidiReadme, hidiChangelog, + 'Directory.Build.props', 'CHANGELOG.md' +]; + +class MemoryGitHub { + constructor(hidiVersion) { + this.repository = {owner: 'microsoft', repo: 'OpenAPI.NET.OData', defaultBranch: branch}; + this.files = Object.fromEntries(inputPaths.map(file => [file, fs.readFileSync(path.join(root, file), 'utf8')])); + this.commits = ['hidi-release-please-config.json', 'release-please-config.json'].map(file => ({ + sha: JSON.parse(this.files[file])['bootstrap-sha'], message: 'chore: baseline', files: [] + })); + this.prs = []; + this.releases = []; + this.tags = []; + this.labelWrites = []; + this.nextPr = 1; + if (hidiVersion) { + this.files[hidiManifest] = JSON.stringify({'.': hidiVersion}); + this.files[hidiProject] = this.files[hidiProject].replace(/.*?<\/Version>/, `${hidiVersion}`); + } + const current = JSON.parse(this.files[hidiManifest])['.']; + const floor = branch === 'main' ? '3.10.2' : '2.12.2'; + if (current !== floor) { + const checkpoint = { + number: 0, state: 'MERGED', sha: 'initial-hidi-checkpoint', + headBranchName: `release-please--branches--${branch}--components--hidi`, + baseBranchName: branch, + title: `chore(${branch}): release hidi ${current}`, + body: new PullRequestBody([{component: 'hidi', version: Version.parse(current), notes: 'Previously merged version'}], {useComponents: true}).toString(), + labels: ['autorelease: hidi-versioned'], files: [hidiManifest, hidiProject] + }; + this.prs.push(checkpoint); + this.commits.unshift({sha: checkpoint.sha, message: checkpoint.title, files: checkpoint.files, pullRequest: checkpoint}); + } + } + async getFileJson(file) { return JSON.parse(this.files[file]); } + async getFileContentsOnBranch(file) { + assert.ok(Object.hasOwn(this.files, file), `Unexpected read of ${file}`); + return {parsedContent: this.files[file], content: Buffer.from(this.files[file]).toString('base64'), sha: 'file-sha'}; + } + async *releaseIterator() { yield* this.releases; } + async *tagIterator() { yield* this.tags; } + async *mergeCommitIterator() { yield* this.commits; } + async *pullRequestIterator(target, state) { + assert.equal(target, branch); + yield* this.prs.filter(pr => pr.state === state); + } + change(files, message = 'fix: representative change') { + this.commits.unshift({sha: `change-${this.commits.length}`, message, files}); + } + materialize(updates) { + return Object.fromEntries(updates + .filter(update => update.createIfMissing || Object.hasOwn(this.files, update.path)) + .map(update => [update.path, update.updater.updateContent(this.files[update.path] || '')])); + } + async createPullRequest(pr, target, message, updates) { + assert.equal(target, branch); + const created = {...pr, number: this.nextPr++, state: 'OPEN', output: this.materialize(updates)}; + this.prs.unshift(created); + return created; + } + async updatePullRequest(number, plan) { + const pr = this.prs.find(item => item.number === number); + Object.assign(pr, {title: plan.title.toString(), body: plan.body.toString(), output: this.materialize(plan.updates)}); + return pr; + } + async addIssueLabels(labels, number) { + this.labelWrites.push(['add', number, labels]); + const pr = this.prs.find(item => item.number === number); + pr.labels = [...new Set([...pr.labels, ...labels])]; + } + async removeIssueLabels(labels, number) { + this.labelWrites.push(['remove', number, labels]); + const pr = this.prs.find(item => item.number === number); + pr.labels = pr.labels.filter(label => !labels.includes(label)); + } + async commentOnIssue() {} + async createRelease(release) { + const result = {tagName: release.tag.toString(), sha: release.sha, notes: release.notes, url: 'https://example.invalid/release'}; + this.releases.unshift(result); + this.tags.unshift({name: result.tagName, sha: result.sha}); + return result; + } + merge(pr) { + Object.assign(this.files, pr.output); + Object.assign(pr, {state: 'MERGED', sha: `merge-${pr.number}`}); + this.commits.unshift({sha: pr.sha, message: pr.title, files: Object.keys(pr.output), pullRequest: pr}); + } +} + +async function plans(github, component) { + return (await Manifest.fromManifest(github, branch, + component === 'hidi' ? 'hidi-release-please-config.json' : 'release-please-config.json', + component === 'hidi' ? hidiManifest : odataManifest)).buildPullRequests(); +} + +const routingCases = [ + ['src/Microsoft.OpenApi.Hidi/Program.cs', false, true], + ['src/Microsoft.OpenApi.Hidi/CsdlFilter.xslt', false, true], + [hidiProject, false, true], + [hidiReadme, false, true], + [hidiChangelog, false, true], + ['test/Microsoft.OpenApi.Hidi.Tests/StatsVisitorTests.cs', false, true], + ['test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/SampleOpenApi.yml', false, true], + ['test/Microsoft.OpenApi.Hidi.Tests/check-nuget-package-published.Tests.ps1', false, true], + ['scripts/check-nuget-package-published.ps1', false, true], + ['test/scripts/check-nuget-package-published.Tests.ps1', false, true], + ['Dockerfile', false, true], + ['.dockerignore', false, true], + ['install-tool.ps1', false, true], + ['tool/hidi-local-nuget.config', false, true], + ['tool/Microsoft.OpenApi.Hidi.public.snk', false, true], + ['hidi-release-please-config.json', false, true], + [hidiManifest, false, true], + ['.azure-pipelines/hidi-release.yml', false, true], + ['src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs', true, false], + ['test/Microsoft.OpenAPI.OData.Reader.Tests/OpenApiConvertSettingsTests.cs', true, false], + ['src/OoasGui/Program.cs', true, false], + ['src/OoasUtil/Program.cs', true, false], + ['docs/graphSecurityScheme/GraphSchemes.md', true, false], + ['Directory.Build.props', true, false], + ['redocly.yaml', true, false], + ['.redocly.lint-ignore.yaml', true, false], + ['src/AssemblyInfo/AssemblyInfoCommon.cs', true, false], + ['CHANGELOG.md', true, false], + ['release-please-config.json', true, false], + [odataManifest, true, false], + ['tool/Microsoft.OpenApi.OData.snk', true, false], + ['tool/35MSSharedLib1024.snk', true, false], + ['tool/Microsoft.OpenApi.OData.public.snk', false, true], + ['README.md', true, true], + ['CONTRIBUTING.md', true, true], + ['Build.props', true, true], + ['src/Build.props', true, true], + ['build.root', true, true], + ['build.ps1', true, false], + ['build.cmd', true, false], + ['global.json', true, true], + ['Microsoft.OpenApi.OData.sln', true, true], + ['.github/workflows/ci-cd.yml', false, false], + ['.github/release-please/run.cjs', false, false], + ['.azure-pipelines/ci-build.yml', false, false], + ['src/Microsoft.OpenApi.HidiSibling/Program.cs', true, true] +]; + +for (const [file, odata, hidi] of routingCases) { + test(`real engine routing: ${file}`, async () => { + const github = new MemoryGitHub(); + github.change([file]); + assert.equal((await plans(github, 'odata')).length, Number(odata)); + assert.equal((await plans(github, 'hidi')).length, Number(hidi)); + }); +} + +test('mixed changes affect both components; excluded-only and empty changes affect neither', async () => { + const github = new MemoryGitHub(); + github.change(['Dockerfile', 'src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs']); + assert.equal((await plans(github, 'odata')).length, 1); + assert.equal((await plans(github, 'hidi')).length, 1); + github.commits.shift(); + github.change(['Dockerfile', 'test/Microsoft.OpenApi.Hidi.Tests/StatsVisitorTests.cs']); + assert.equal((await plans(github, 'odata')).length, 0); + github.commits.shift(); + github.change([]); + assert.equal((await plans(github, 'odata')).length, 0); + assert.equal((await plans(github, 'hidi')).length, 0); +}); + +test('mixed unreleased history does not leak a Hidi feature into an OData patch', async () => { + const github = new MemoryGitHub(); + const odata = JSON.parse(github.files[odataManifest])['.']; + const hidi = JSON.parse(github.files[hidiManifest])['.']; + github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], 'feat(hidi): independent CLI capability'); + github.change(['src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs'], 'fix(odata): independent converter correction'); + const [rootPr] = await plans(github, 'odata'); + const [hidiPr] = await plans(github, 'hidi'); + assert.equal(rootPr.version.toString(), odata.replace(/\d+$/, patch => Number(patch) + 1)); + const [major, minor] = hidi.split('.').map(Number); + assert.equal(hidiPr.version.toString(), `${major}.${minor + 1}.0`); + assert.ok(rootPr.body.toString().includes('independent converter correction')); + assert.ok(!rootPr.body.toString().includes('independent CLI capability')); + assert.ok(hidiPr.body.toString().includes('independent CLI capability')); + assert.ok(!hidiPr.body.toString().includes('independent converter correction')); +}); + +test('actual Hidi patch output changes only its version, manifest, changelog and install examples', async () => { + const github = new MemoryGitHub(); + const baseline = github.files[hidiProject]; + const oldVersion = JSON.parse(github.files[hidiManifest])['.']; + const next = oldVersion.replace(/\d+$/, patch => Number(patch) + 1); + github.change(['Dockerfile'], 'fix(hidi): independent distribution fix'); + const [pr] = await plans(github, 'hidi'); + const output = github.materialize(pr.updates); + assert.deepEqual(Object.keys(output).sort(), [hidiChangelog, hidiProject, hidiReadme, hidiManifest].sort()); + assert.equal(pr.headRefName, `release-please--branches--${branch}--components--hidi`); + assert.equal(pr.version.toString(), next); + assert.ok(output[hidiProject].includes(`${next}`)); + const dependencies = text => [...text.matchAll(/ match.slice(1)); + assert.deepEqual(dependencies(output[hidiProject]), dependencies(baseline)); + assert.match(output[hidiChangelog], new RegExp(`hidi-v${oldVersion}\\.\\.\\.hidi-v${next}`)); + assert.equal(JSON.parse(output[hidiManifest])['.'], next); + assert.equal((output[hidiReadme].match(new RegExp(`--version ${next}`, 'g')) || []).length, 2); + assert.ok(output[hidiReadme].includes(`migration baseline ${branch === 'main' ? '3.10.2' : '2.12.2'} is already published`)); +}); + +test('actual OData output and componentless tags retain existing behavior', async () => { + const github = new MemoryGitHub(); + const oldVersion = JSON.parse(github.files[odataManifest])['.']; + const next = oldVersion.replace(/\d+$/, patch => Number(patch) + 1); + github.releases.push({tagName: `v${oldVersion}`, sha: github.commits.at(-1).sha, notes: ''}); + github.change(['Directory.Build.props'], 'fix(odata): independent library fix'); + const [pr] = await plans(github, 'odata'); + const output = github.materialize(pr.updates); + assert.deepEqual(Object.keys(output).sort(), ['CHANGELOG.md', 'Directory.Build.props', odataManifest].sort()); + assert.equal(pr.headRefName, `release-please--branches--${branch}--components--Microsoft.OpenApi.OData`); + assert.ok(output['Directory.Build.props'].includes(`${next}`)); + assert.match(output['CHANGELOG.md'], new RegExp(`v${oldVersion}\\.\\.\\.v${next}`)); + const created = await runReleasePlease(github, branch, 'odata'); + github.merge(created.prs[0]); + const released = await runReleasePlease(github, branch, 'odata'); + assert.equal(released.releases[0].tagName, `v${next}`); + assert.equal(released.prs.length, 0); +}); + +test('Hidi feature release increments minor; breaking changes fail before writing a PR or release', async () => { + const github = new MemoryGitHub(); + const [major, minor] = JSON.parse(github.files[hidiManifest])['.'].split('.').map(Number); + github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], 'feat(hidi): independent feature'); + assert.equal((await plans(github, 'hidi'))[0].version.toString(), `${major}.${minor + 1}.0`); + github.commits.shift(); + github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], 'feat(hidi)!: incompatible feature'); + await assert.rejects(runReleasePlease(github, branch, 'hidi'), /outside the branch major/); + assert.equal(github.prs.length, 0); + assert.equal(github.releases.length, 0); +}); + +test('generated Hidi fix and feature tags match the unchanged official pipeline guards without publishing', async () => { + const pipeline = fs.readFileSync(path.join(root, '.azure-pipelines', 'hidi-release.yml'), 'utf8'); + const floor = branch === 'main' ? '3.10.2' : '2.12.2'; + const current = JSON.parse(fs.readFileSync(path.join(root, hidiManifest), 'utf8'))['.']; + const [major, minor, patch] = current.split('.').map(Number); + assert.ok(pipeline.includes(`- hidi-v${major}.*`)); + assert.ok(pipeline.includes(`hidiPublishingEnabled: 'false'`)); + assert.ok(pipeline.includes(`[version]'${floor}'`)); + assert.ok(pipeline.includes('refs/tags/hidi-v$version')); + for (const [type, expected] of [ + ['fix', `${major}.${minor}.${patch + 1}`], + ['feat', `${major}.${minor + 1}.0`] + ]) { + const github = new MemoryGitHub(); + github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], `${type}(hidi): guarded version`); + const {prs} = await runReleasePlease(github, branch, 'hidi'); + github.merge(prs[0]); + const manifest = await Manifest.fromManifest(github, branch, 'hidi-release-please-config.json', hidiManifest); + const candidates = await manifest.buildReleases(); + assert.equal(candidates.length, 1); + assert.equal(candidates[0].tag.toString(), `hidi-v${expected}`); + assert.ok(Version.parse(expected).compare(Version.parse(floor)) > 0); + assert.ok(prs[0].output[hidiProject].includes(`${expected}`)); + assert.deepEqual(github.tags, []); + assert.deepEqual(github.releases, []); + } +}); + +test('two tag-free Hidi version cycles do not replay commits or block OData', async () => { + const github = new MemoryGitHub(); + const baseline = JSON.parse(github.files[hidiManifest])['.']; + github.change(['Dockerfile'], 'fix(hidi): first cycle'); + const first = await runReleasePlease(github, branch, 'hidi'); + assert.deepEqual(first.releases, []); + assert.deepEqual(first.prs[0].labels, ['autorelease: hidi-pending']); + assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); + github.merge(first.prs[0]); + assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); + assert.deepEqual(first.prs[0].labels, ['autorelease: hidi-versioned']); + assert.deepEqual(github.labelWrites.slice(0, 2).map(write => write[0]), ['add', 'remove']); + github.change(['scripts/check-nuget-package-published.ps1'], 'fix(hidi): second cycle'); + const second = await runReleasePlease(github, branch, 'hidi'); + const patch = Number(baseline.split('.')[2]); + assert.equal(JSON.parse(second.prs[0].output[hidiManifest])['.'], baseline.replace(/\d+$/, String(patch + 2))); + assert.ok(second.prs[0].body.includes('second cycle')); + assert.ok(!second.prs[0].body.includes('first cycle')); + github.merge(second.prs[0]); + assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); + github.change(['src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs'], 'fix(odata): after Hidi merges'); + assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); + assert.equal((await runReleasePlease(github, branch, 'odata')).prs.length, 1); + assert.deepEqual(github.tags, []); + assert.deepEqual(github.releases, []); +}); + +test('version automation and its fixtures keep working after the repository manifest advances', async () => { + const current = JSON.parse(fs.readFileSync(path.join(root, hidiManifest), 'utf8'))['.']; + const advanced = current.replace(/\d+$/, patch => Number(patch) + 1); + const next = current.replace(/\d+$/, patch => Number(patch) + 2); + const github = new MemoryGitHub(advanced); + github.change(['Dockerfile'], 'fix(hidi): after an existing version checkpoint'); + const {prs, releases} = await runReleasePlease(github, branch, 'hidi'); + assert.equal(JSON.parse(prs[0].output[hidiManifest])['.'], next); + assert.deepEqual(releases, []); + github.merge(prs[0]); + assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); + assert.deepEqual(github.tags, []); +}); + +test('open Hidi PR updates with additional commits instead of opening a duplicate', async () => { + const github = new MemoryGitHub(); + github.change(['Dockerfile'], 'fix(hidi): first fix'); + const first = await runReleasePlease(github, branch, 'hidi'); + github.change(['install-tool.ps1'], 'fix(hidi): additional fix'); + const updated = await runReleasePlease(github, branch, 'hidi'); + assert.equal(updated.prs[0].number, first.prs[0].number); + assert.equal(github.prs.length, 1); + assert.ok(updated.prs[0].body.includes('additional fix')); +}); + +test('unsafe manifest and merged PR state fail without label or release writes', async t => { + for (const kind of ['wrong-major', 'project-version-mismatch', 'missing-checkpoint', 'wrong-branch', 'bad-body', 'future-version', 'duplicate-checkpoint', 'unreachable-checkpoint', 'title-body-mismatch']) { + await t.test(kind, async () => { + const github = new MemoryGitHub(); + github.change(['Dockerfile'], 'fix(hidi): cycle'); + const {prs} = await runReleasePlease(github, branch, 'hidi'); + github.merge(prs[0]); + if (kind === 'wrong-major') github.files[hidiManifest] = '{".":"9.0.0"}'; + if (kind === 'project-version-mismatch') github.files[hidiProject] = github.files[hidiProject].replace(/.*?<\/Version>/, '9.0.0'); + if (kind === 'missing-checkpoint') github.prs = []; + if (kind === 'wrong-branch') prs[0].headBranchName = 'unrelated'; + if (kind === 'bad-body') prs[0].body = 'not a release PR'; + if (kind === 'future-version') github.files[hidiManifest] = fs.readFileSync(path.join(root, hidiManifest), 'utf8'); + if (kind === 'duplicate-checkpoint') github.prs.push({...prs[0], number: 99, sha: 'duplicate'}); + if (kind === 'unreachable-checkpoint') github.commits.shift(); + if (kind === 'title-body-mismatch') prs[0].title = 'chore(main): release hidi 9.0.0'; + await assert.rejects(runReleasePlease(github, branch, 'hidi')); + assert.deepEqual(github.labelWrites, []); + assert.deepEqual(github.releases, []); + }); + } +}); + +test('merged PR body version must agree with its title even when the title matches the manifest', async () => { + const github = new MemoryGitHub(); + github.change(['Dockerfile'], 'fix(hidi): cycle'); + const {prs} = await runReleasePlease(github, branch, 'hidi'); + github.merge(prs[0]); + const current = JSON.parse(github.files[hidiManifest])['.']; + prs[0].body = prs[0].body.replaceAll(current, current.replace(/\d+$/, patch => Number(patch) + 1)); + await assert.rejects(runReleasePlease(github, branch, 'hidi'), /inconsistent title and body/); + assert.deepEqual(github.labelWrites, []); +}); + +test('unknown component is an explicit failure', async () => { + await assert.rejects(runReleasePlease(new MemoryGitHub(), branch, 'unknown'), /Unknown component/); +}); + +test('missing commit files are an explicit plugin failure', async () => { + const plugin = new ExactPathExclusions(new MemoryGitHub(), branch, {'.': {excludePaths: []}}); + await assert.rejects(plugin.preconfigure({}, {'.': [{sha: 'bad'}]}), /Missing changed files/); +}); + +test('Hidi ignores pending OData PRs and interrupted label transitions are retryable', async () => { + const github = new MemoryGitHub(); + github.change(['Directory.Build.props'], 'fix(odata): root cycle'); + const rootPr = (await runReleasePlease(github, branch, 'odata')).prs[0]; + github.merge(rootPr); + github.change(['Dockerfile'], 'fix(hidi): independent cycle'); + const hidiPr = (await runReleasePlease(github, branch, 'hidi')).prs[0]; + assert.ok(hidiPr); + github.merge(hidiPr); + hidiPr.labels.push('autorelease: hidi-versioned'); + assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); + assert.deepEqual(hidiPr.labels, ['autorelease: hidi-versioned']); + assert.deepEqual(rootPr.labels, ['autorelease: pending']); +}); + +test('Hidi lifecycle labels are created using the authenticated GitHub REST API only when missing', async () => { + const calls = []; + const labels = new Set(); + const request = async (url, options) => { + assert.equal(options.headers.Authorization, 'Bearer offline-test-token'); + assert.equal(options.headers['X-GitHub-Api-Version'], '2022-11-28'); + calls.push([url, options.method || 'GET']); + if (options.method === 'POST') { + const label = JSON.parse(options.body); + assert.ok(['autorelease: hidi-pending', 'autorelease: hidi-versioned'].includes(label.name)); + labels.add(label.name); + return Response.json(label, {status: 201}); + } + const name = decodeURIComponent(url.split('/').at(-1)); + return labels.has(name) ? Response.json({name}) : Response.json({}, {status: 404}); + }; + await ensureHidiLabels('offline-test-token', 'microsoft', 'OpenAPI.NET.OData', request); + assert.deepEqual(calls.map(call => call[1]), ['GET', 'POST', 'GET', 'POST']); + assert.ok(calls[0][0].endsWith('/labels/autorelease%3A%20hidi-pending')); + calls.length = 0; + await ensureHidiLabels('offline-test-token', 'microsoft', 'OpenAPI.NET.OData', request); + assert.deepEqual(calls.map(call => call[1]), ['GET', 'GET']); +}); + +test('Hidi label bootstrap fails explicitly on permissions, network errors or invalid responses', async t => { + for (const status of [401, 403, 500]) { + await t.test(`read HTTP ${status}`, async () => { + await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', + async () => Response.json({}, {status})), new RegExp(`HTTP ${status}`)); + }); + } + await t.test('creation permissions', async () => { + await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', + async (url, options) => Response.json({}, {status: options.method === 'POST' ? 403 : 404})), + /Cannot create.*HTTP 403/); + }); + await t.test('network error', async () => { + await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', + async () => { throw new Error('offline connection failed'); }), /offline connection failed/); + }); + await t.test('unexpected label', async () => { + await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', + async () => Response.json({name: 'autorelease: pending'})), /Cannot verify/); + }); + await t.test('invalid JSON', async () => { + await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', + async () => new Response('invalid JSON')), SyntaxError); + }); +}); + +test('concurrent Hidi label creation is accepted only after verifying the exact existing label', async () => { + const existing = new Set(); + await ensureHidiLabels('token', 'owner', 'repo', async (url, options) => { + if (options.method === 'POST') { + existing.add(JSON.parse(options.body).name); + return Response.json({}, {status: 422}); + } + const name = decodeURIComponent(url.split('/').at(-1)); + return existing.has(name) ? Response.json({name}) : Response.json({}, {status: 404}); + }); + await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', + async (url, options) => Response.json({}, {status: options.method === 'POST' ? 422 : 404})), + /Cannot verify.*HTTP 404/); +}); + +test('CLI wiring emits real library PR/release outputs and uses the app token', async t => { + const github = new MemoryGitHub(); + const core = require('@actions/core'); + const saved = {...process.env}; + const argv = process.argv; + t.after(() => { process.env = saved; process.argv = argv; }); + Object.assign(process.env, {RELEASE_PLEASE_TOKEN: 'offline-test-token', GITHUB_REF_NAME: branch, GITHUB_REPOSITORY: 'microsoft/OpenAPI.NET.OData'}); + let labelReads = 0; + t.mock.method(globalThis, 'fetch', async (url, options) => { + labelReads++; + assert.equal(options.headers.Authorization, 'Bearer offline-test-token'); + assert.equal(options.method, undefined); + return Response.json({name: decodeURIComponent(url.split('/').at(-1))}); + }); + t.mock.method(GitHub, 'create', async options => { + assert.equal(options.token, 'offline-test-token'); + assert.equal(options.defaultBranch, branch); + return github; + }); + const outputs = {}; + t.mock.method(core, 'setOutput', (key, value) => { outputs[key] = value; }); + process.argv = ['node', 'run.cjs', 'hidi']; + github.change(['Dockerfile'], 'fix(hidi): CLI cycle'); + await main(); + assert.equal(outputs.prs_created, true); + assert.equal(outputs.releases_created, false); + assert.equal(JSON.parse(outputs.prs)[0].headBranchName, `release-please--branches--${branch}--components--hidi`); + assert.equal(outputs.paths_released, '[]'); + process.argv[2] = 'odata'; + github.change(['Directory.Build.props'], 'fix(odata): CLI cycle'); + await main(); + github.merge(github.prs.find(pr => pr.labels.includes('autorelease: pending'))); + await main(); + assert.equal(outputs.releases_created, true); + assert.equal(outputs.release_created, true); + assert.ok(outputs.tag_name.startsWith('v')); + assert.ok(outputs.html_url); + assert.equal(labelReads, 2); + delete process.env.RELEASE_PLEASE_TOKEN; + await assert.rejects(main(), /Missing release automation environment/); +}); diff --git a/.github/workflows/release-please-gha.yml b/.github/workflows/release-please-gha.yml index 5f46bf25..428e141a 100644 --- a/.github/workflows/release-please-gha.yml +++ b/.github/workflows/release-please-gha.yml @@ -5,8 +5,8 @@ # # Summary: # This GitHub Actions workflow automates the release process using Release Please. -# It triggers on pushes to the main branch, generates a GitHub App token using organization -# variables and secrets, and then runs the release-please-action to manage versioning and changelogs. +# It tests component routing and uses a GitHub App token to manage independent +# OData releases and tag-free Hidi version pull requests on their target branches. name: Release Please @@ -16,12 +16,40 @@ on: - main - support/v1 - support/v2 + pull_request: + branches: + - main + - support/v1 + - support/v2 + paths: + - '.github/release-please/**' + - '.github/workflows/release-please-gha.yml' + - '*release-please*.json' + - 'Directory.Build.props' + - 'src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj' + - 'src/Microsoft.OpenApi.Hidi/readme.md' permissions: contents: read jobs: + release-please-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 + with: + node-version: '24' + - name: Install pinned Release Please + working-directory: .github/release-please + run: npm ci --ignore-scripts + - name: Verify component routing and version-only lifecycle + working-directory: .github/release-please + run: npm test + release-please-master: + if: ${{ github.event_name == 'push' }} + needs: release-please-tests runs-on: ubuntu-latest steps: - name: Checkout repository @@ -34,17 +62,22 @@ jobs: app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }} private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }} - - name: Release Please - uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 with: - token: ${{ steps.app-token.outputs.token }} - config-file: release-please-config.json - manifest-file: .release-please-manifest.json - target-branch: ${{ github.ref_name }} + node-version: '24' + - name: Install pinned Release Please + working-directory: .github/release-please + run: npm ci --ignore-scripts + - name: Release Please (OData) + run: node .github/release-please/run.cjs odata + env: + RELEASE_PLEASE_TOKEN: ${{ steps.app-token.outputs.token }} + GITHUB_REF_NAME: ${{ github.ref_name }} release-please-hidi: - # Enable only after the destination PR lands and source publishing is cut over. - if: ${{ false }} + # Version PRs only; tags, releases and protected publishing remain disabled. + if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'support/v2') }} + needs: release-please-tests runs-on: ubuntu-latest permissions: contents: read @@ -56,10 +89,14 @@ jobs: with: app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }} private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }} - - name: Release Please (independent hidi version) - uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 with: - token: ${{ steps.app-token.outputs.token }} - config-file: hidi-release-please-config.json - manifest-file: .hidi-release-please-manifest.json - target-branch: ${{ github.ref_name }} + node-version: '24' + - name: Install pinned Release Please + working-directory: .github/release-please + run: npm ci --ignore-scripts + - name: Release Please (independent Hidi version PR) + run: node .github/release-please/run.cjs hidi + env: + RELEASE_PLEASE_TOKEN: ${{ steps.app-token.outputs.token }} + GITHUB_REF_NAME: ${{ github.ref_name }} diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index ca6bd5d3..9c86a252 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -49,6 +49,26 @@ jobs: - uses: actions/checkout@v6 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Set up Node.js for Release Please runner tests + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 + with: + node-version: '24' + - name: Test Release Please runner with measured JavaScript coverage + shell: pwsh + working-directory: .github/release-please + run: | + npm ci --ignore-scripts + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + npm run coverage + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $report = '..\..\artifacts\release-please\lcov.info' + if (-not (Test-Path $report)) { + throw 'Release Please runner LCOV report was not generated.' + } + $sources = @(Get-Content $report | Where-Object { $_ -like 'SF:*' }) + if ($sources.Count -ne 1 -or $sources[0] -notmatch '^SF:\.github[/\\]release-please[/\\]run\.cjs$') { + throw 'Expected measured JavaScript coverage of only the Release Please runner.' + } - name: Cache SonarCloud packages uses: actions/cache@v5 with: @@ -120,7 +140,7 @@ jobs: CoverletOutputFormat: 'opencover' # https://github.com/microsoft/vstest/issues/4014#issuecomment-1307913682 shell: pwsh run: | - dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="test/**/coverage.net8.0.opencover.xml,artifacts/hidi/coverage/*opencover*.xml" /d:sonar.coverageReportPaths="artifacts/hidi/powershell-coverage/sonar-coverage.xml" + dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="test/**/coverage.net8.0.opencover.xml,artifacts/hidi/coverage/*opencover*.xml" /d:sonar.coverageReportPaths="artifacts/hidi/powershell-coverage/sonar-coverage.xml" /d:sonar.javascript.lcov.reportPaths="artifacts/release-please/lcov.info" /d:sonar.test.inclusions="test/**,**/run.test.cjs" dotnet workload restore dotnet build dotnet test test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenAPI.OData.Reader.Tests.csproj --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d44c94f2..dacd3642 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,9 +28,63 @@ is handled only by the official Azure pipeline. Hidi's version is in its own project and `.hidi-release-please-manifest.json`. Its `hidi-v2.*` tags must not trigger OData publishing. Version 2.12.2 is the -already-published migration baseline, not a new release. Hidi release automation -and publishing remain disabled until source cutover. History-import migration -PRs must be merged with a merge commit, never squash or rebase. +already-published migration baseline, not a new release. Release Please now +opens independent version PRs on `support/v2`; Hidi tags, GitHub releases, and +production publishing remain disabled until source cutover. History-import +migration PRs must be merged with a merge commit, never squash or rebase. + +### Independent automated versions + +The Release Please workflow uses the pinned API runner in +`.github/release-please`. It registers `exact-path-exclusions` because the +upstream `exclude-paths` implementation matches directories, not individual +files. Keep the root OData config/manifest and the Hidi config/manifest separate; +the existing `simple` strategy updates `Directory.Build.props` for OData and +only the Hidi project's `` for Hidi. Hidi's changelog and annotated +installation examples are updated in the same version PR, without changing its +published OpenAPI dependencies. + +| Changed paths | Version track | +| --- | --- | +| Hidi CLI source, tests, and packaged readme | Hidi only | +| `Dockerfile`, `.dockerignore`, `install-tool.ps1`, Hidi public keys/local NuGet config | Hidi only | +| `.azure-pipelines/hidi-release.yml`, private-feed helper and its Pester tests, Hidi config/manifest | Hidi only | +| OData reader, GUI/utilities, OData tests/assembly metadata, `docs`, Redocly config, legacy `build.cmd`/`build.ps1`, OData config/manifest, `Directory.Build.props` | OData only | +| Root README/contributing docs, solution, SDK, `Build.props`, `src/Build.props`, `build.root` | Both, for releasable commits | +| `.github`, editor configuration directories, OData Azure CI pipeline | Neither | + +Routing is by changed paths, not commit scopes. Use `fix(hidi):` or +`feat(hidi):` for clarity, but a Hidi scope does not override file ownership. +A mixed change touching both components contributes to both tracks. An OData +version-only edit does not independently bump Hidi. + +Hidi version PRs use the `hidi` component and their own branch and lifecycle +labels (`autorelease: hidi-pending` and `autorelease: hidi-versioned`). After a +version PR merges, the runner uses that merge commit as the next version's +checkpoint and retires the pending label. This allows subsequent version PRs +without tags and does not block OData's normal release lifecycle. No Hidi +GitHub release or publishing job is invoked by this runner; production cutover +remains a separate protected operation. + +On its first Hidi run, the app token creates those two repository labels if +missing, using the GitHub labels API. Existing labels and OData's default labels +are not changed. API permission, network, or validation failures stop automation +explicitly; no publishing permissions or protected resources are granted. + +Run the offline routing and version-file tests with Node.js 24: + +```powershell +Push-Location .github\release-please +npm ci --ignore-scripts +npm test +npm run coverage +Pop-Location +``` + +The coverage command measures only the runner with Node's native coverage +instrumentation and writes `artifacts/release-please/lcov.info` relative to the +repository root. The existing SonarCloud workflow imports this report alongside +the unchanged C# and PowerShell coverage reports. OpenAPI.net.OData is open to contributions. There are a couple of different recommended paths to get contributions into the released version of this library. diff --git a/README.md b/README.md index a1e490db..509843fd 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,12 @@ tests requires the .NET 10 SDK. Existing OData tests still use .NET 8 and VSTest Hidi's filtered history was imported with a merge, not squashed. **Merge this migration PR using a merge commit, not squash or rebase**, so the canonical imported commits can also be retained by the later main-branch migration. -Destination hidi release and production publishing are disabled until source -cutover; OpenAPI.NET remains the publisher in the meantime. +Independent Hidi version PRs are automated by Release Please on `support/v2`; +its project, manifest, changelog, and installation examples advance separately +from OData. Hidi tags, GitHub releases, and production publishing remain disabled +until source cutover; OpenAPI.NET remains the publisher in the meantime. +See [independent automated versions](CONTRIBUTING.md#independent-automated-versions) +for changed-path ownership and the tag-free version PR lifecycle. The gated hidi NuGet release uses `EsrpRelease@14`, staging only the exact `Microsoft.OpenApi.Hidi` package and its `.snupkg` symbols from the Hidi build diff --git a/hidi-release-please-config.json b/hidi-release-please-config.json index 6e95505c..d93afadc 100644 --- a/hidi-release-please-config.json +++ b/hidi-release-please-config.json @@ -2,10 +2,16 @@ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", "bootstrap-sha": "8ebc6abbb1da683db4b5bc0928183dec947f2f02", "release-type": "simple", + "plugins": [ + "exact-path-exclusions" + ], + "separate-pull-requests": true, + "label": "autorelease: hidi-pending", + "release-label": "autorelease: hidi-versioned", "include-component-in-tag": true, "include-v-in-tag": true, "exclude-paths": [ - ".azure-pipelines", + ".azure-pipelines/ci-build.yml", ".github", ".idea", ".vs", @@ -13,10 +19,17 @@ "src/Microsoft.OpenApi.OData.Reader", "src/OoasGui", "src/OoasUtil", + "src/AssemblyInfo", "test/Microsoft.OpenAPI.OData.Reader.Tests", "docs", "CHANGELOG.md", "Directory.Build.props", + "build.cmd", + "build.ps1", + "redocly.yaml", + ".redocly.lint-ignore.yaml", + "tool/35MSSharedLib1024.snk", + "tool/Microsoft.OpenApi.OData.snk", "release-please-config.json", ".release-please-manifest.json" ], @@ -30,6 +43,10 @@ "type": "xml", "path": "src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj", "xpath": "//Project/PropertyGroup/Version" + }, + { + "type": "generic", + "path": "src/Microsoft.OpenApi.Hidi/readme.md" } ] } diff --git a/release-please-config.json b/release-please-config.json index 75e417d6..b7007cd1 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,5 +1,8 @@ { "bootstrap-sha": "4f9bad6ea7d25e8596c0ca214975e690d925e6e7", + "plugins": [ + "exact-path-exclusions" + ], "exclude-paths": [ ".azure-pipelines", ".github", @@ -12,6 +15,8 @@ "Microsoft.OpenApi.Hidi.Tests", "test/Microsoft.OpenApi.Hidi.Tests", "test/Microsoft.OpenApi.Tests", + "test/scripts", + "scripts/check-nuget-package-published.ps1", "tool/Microsoft.OpenApi.Hidi.public.snk", "tool/Microsoft.OpenApi.OData.public.snk", "tool/hidi-local-nuget.config", diff --git a/src/Microsoft.OpenApi.Hidi/CHANGELOG.md b/src/Microsoft.OpenApi.Hidi/CHANGELOG.md index 21c25cb3..0d8e2ea5 100644 --- a/src/Microsoft.OpenApi.Hidi/CHANGELOG.md +++ b/src/Microsoft.OpenApi.Hidi/CHANGELOG.md @@ -7,4 +7,5 @@ published and must not be republished from this repository. Earlier release notes remain in [OpenAPI.NET releases](https://github.com/microsoft/OpenAPI.NET/releases). Hidi has its own release manifest and `hidi-v2.*` tags, independent of OData. -Destination release automation is disabled until the source publishing cutover. +Independent version PRs are automated without tags or GitHub releases. +Destination publishing remains disabled until the source publishing cutover. diff --git a/src/Microsoft.OpenApi.Hidi/readme.md b/src/Microsoft.OpenApi.Hidi/readme.md index b8703368..cf37a95f 100644 --- a/src/Microsoft.OpenApi.Hidi/readme.md +++ b/src/Microsoft.OpenApi.Hidi/readme.md @@ -17,16 +17,20 @@ Install [Microsoft.OpenApi.Hidi](https://www.nuget.org/packages/Microsoft.OpenAp ### .NET CLI(Global) + ```bash dotnet tool install --global Microsoft.OpenApi.Hidi --version 2.12.2 ``` + ### .NET CLI(local) + ```bash dotnet new tool-manifest # if the repository does not have a tool manifest dotnet tool install --local Microsoft.OpenApi.Hidi --version 2.12.2 ``` + @@ -71,9 +75,12 @@ docker run --rm --mount "type=bind,source=$PWD\test\Microsoft.OpenApi.Hidi.Tests Local/CI builds use the public-only strong-name identity. Official release artifacts are signed in Azure Pipelines; private signing keys do not belong in this repository. The migration baseline 2.12.2 is already published. Destination -NuGet, GitHub release, and Docker publishing are disabled until source cutover, -and the first destination release must advance the hidi version. OData releases -use separate artifacts and tags. +NuGet, GitHub release, and Docker publishing are disabled until source cutover. +Release Please opens independent Hidi version PRs on `support/v2`, updating its +manifest, project version, changelog, and installation examples without creating +tags or GitHub releases. The first destination release must advance the Hidi +version beyond the baseline and use an exact `hidi-v2.` tag matching the +project. OData releases use separate artifacts and tags. Docker builds opt into `HidiPublicSignBuild=true` for the local OData project, using its own public-only key without changing normal OData signing behavior. From 0fd95224f0271342c6e1ead57d68dc98e745a5ea Mon Sep 17 00:00:00 2001 From: "Gavin Barron (from Dev Box)" Date: Fri, 9 Oct 2026 11:36:28 -0700 Subject: [PATCH 2/4] test(hidi): keep version fixtures stable after bumps Count open version PRs independently of seeded merged checkpoints so the full release-please suite continues to pass after the manifest advances. Verified all 80 cases against both the current and a generated future Hidi baseline. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dc4344a-fac5-4e6e-89f8-eb2c9467edd4 --- .github/release-please/run.test.cjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/release-please/run.test.cjs b/.github/release-please/run.test.cjs index 9988dd64..9056b6b4 100644 --- a/.github/release-please/run.test.cjs +++ b/.github/release-please/run.test.cjs @@ -249,7 +249,7 @@ test('Hidi feature release increments minor; breaking changes fail before writin github.commits.shift(); github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], 'feat(hidi)!: incompatible feature'); await assert.rejects(runReleasePlease(github, branch, 'hidi'), /outside the branch major/); - assert.equal(github.prs.length, 0); + assert.equal(github.prs.filter(pr => pr.state === 'OPEN').length, 0); assert.equal(github.releases.length, 0); }); @@ -329,7 +329,7 @@ test('open Hidi PR updates with additional commits instead of opening a duplicat github.change(['install-tool.ps1'], 'fix(hidi): additional fix'); const updated = await runReleasePlease(github, branch, 'hidi'); assert.equal(updated.prs[0].number, first.prs[0].number); - assert.equal(github.prs.length, 1); + assert.equal(github.prs.filter(pr => pr.state === 'OPEN').length, 1); assert.ok(updated.prs[0].body.includes('additional fix')); }); From 9b21c9a2af8acc612d8f98a9961d835a07932b59 Mon Sep 17 00:00:00 2001 From: "Gavin Barron (from Dev Box)" Date: Fri, 9 Oct 2026 11:57:42 -0700 Subject: [PATCH 3/4] fix(hidi): use standard multi-component release configuration Follow the user-provided release-please configuration pattern with one shared config and manifest, independent component versions, and the existing stock action. Remove custom runner, npm tooling, test/coverage machinery, labels and duplicate Hidi scaffolding. Use the supported separate-pull-requests option to preserve componentless OData releases; keep package baselines and protected production publishers unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dc4344a-fac5-4e6e-89f8-eb2c9467edd4 --- .github/release-please/package-lock.json | 1858 ---------------------- .github/release-please/package.json | 15 - .github/release-please/run.cjs | 203 --- .github/release-please/run.test.cjs | 499 ------ .github/workflows/release-please-gha.yml | 75 +- .github/workflows/sonarcloud.yml | 22 +- .hidi-release-please-manifest.json | 3 - .release-please-manifest.json | 3 +- CONTRIBUTING.md | 77 +- README.md | 10 +- hidi-release-please-config.json | 54 - release-please-config.json | 45 +- src/Microsoft.OpenApi.Hidi/CHANGELOG.md | 4 +- src/Microsoft.OpenApi.Hidi/readme.md | 16 +- 14 files changed, 71 insertions(+), 2813 deletions(-) delete mode 100644 .github/release-please/package-lock.json delete mode 100644 .github/release-please/package.json delete mode 100644 .github/release-please/run.cjs delete mode 100644 .github/release-please/run.test.cjs delete mode 100644 .hidi-release-please-manifest.json delete mode 100644 hidi-release-please-config.json diff --git a/.github/release-please/package-lock.json b/.github/release-please/package-lock.json deleted file mode 100644 index 96494217..00000000 --- a/.github/release-please/package-lock.json +++ /dev/null @@ -1,1858 +0,0 @@ -{ - "name": "openapi-odata-release-please", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "openapi-odata-release-please", - "dependencies": { - "@actions/core": "1.11.1", - "release-please": "17.3.0" - }, - "engines": { - "node": ">=24" - } - }, - "node_modules/@actions/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", - "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", - "dependencies": { - "@actions/exec": "^1.1.1", - "@actions/http-client": "^2.0.1" - } - }, - "node_modules/@actions/exec": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", - "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", - "dependencies": { - "@actions/io": "^1.0.1" - } - }, - "node_modules/@actions/http-client": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", - "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", - "dependencies": { - "tunnel": "^0.0.6", - "undici": "^5.25.4" - } - }, - "node_modules/@actions/io": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", - "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==" - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@conventional-commits/parser": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@conventional-commits/parser/-/parser-0.4.1.tgz", - "integrity": "sha512-H2ZmUVt6q+KBccXfMBhbBF14NlANeqHTXL4qCL6QGbMzrc4HDXyzWuxPxPNbz71f/5UkR5DrycP5VO9u7crahg==", - "dependencies": { - "unist-util-visit": "^2.0.3", - "unist-util-visit-parents": "^3.1.1" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "engines": { - "node": ">=14" - } - }, - "node_modules/@google-automations/git-file-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@google-automations/git-file-utils/-/git-file-utils-3.2.1.tgz", - "integrity": "sha512-LYOjAnGu/xtEkYYh6W3/1RmeK9HB/fV+xMe7nHc+WiDYrnxAJWBfcyUucoJtYS8XAhVUzNWrQvYDPRbxe67DNQ==", - "dependencies": { - "@octokit/rest": "^20.1.1", - "minimatch": "^10.2.4" - }, - "engines": { - "node": ">= 22" - } - }, - "node_modules/@iarna/toml": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-td6ZUkz2oS3VeleBcN+m//Q6HlCFCPrnI0FZhrt/h4XqLEdOyYp2u21nd8MdsR+WJy5r9PTDaHTDDfhf4H4l6Q==" - }, - "node_modules/@jsep-plugin/assignment": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", - "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, - "node_modules/@jsep-plugin/regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", - "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, - "node_modules/@octokit/auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", - "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", - "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", - "dependencies": { - "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.1.0", - "@octokit/request": "^8.4.1", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/endpoint": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", - "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", - "dependencies": { - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/graphql": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", - "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", - "dependencies": { - "@octokit/request": "^8.4.1", - "@octokit/types": "^13.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "11.4.4-cjs.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.4-cjs.2.tgz", - "integrity": "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==", - "dependencies": { - "@octokit/types": "^13.7.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-request-log": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", - "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "13.3.2-cjs.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.2-cjs.1.tgz", - "integrity": "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==", - "dependencies": { - "@octokit/types": "^13.8.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "^5" - } - }, - "node_modules/@octokit/request": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", - "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", - "dependencies": { - "@octokit/endpoint": "^9.0.6", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", - "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", - "dependencies": { - "@octokit/types": "^13.1.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/rest": { - "version": "20.1.2", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.2.tgz", - "integrity": "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==", - "dependencies": { - "@octokit/core": "^5.0.2", - "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", - "@octokit/plugin-request-log": "^4.0.0", - "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==" - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==" - }, - "node_modules/@types/npm-package-arg": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@types/npm-package-arg/-/npm-package-arg-6.1.4.tgz", - "integrity": "sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q==" - }, - "node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" - }, - "node_modules/@types/yargs": { - "version": "16.0.11", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.11.tgz", - "integrity": "sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", - "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==" - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dependencies": { - "retry": "0.13.1" - } - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/brace-expansion": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", - "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/code-suggester": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/code-suggester/-/code-suggester-5.0.1.tgz", - "integrity": "sha512-8qJiiSCfkbPNWvjEFzdG1UW3axL+Bs0ldV1/TdlBKmF9I/a/WooSQZQCi9M44HoXbVTQesn/IQr6+nIWNnVIWA==", - "dependencies": { - "@octokit/rest": "^20.1.2", - "@types/yargs": "^16.0.0", - "async-retry": "^1.3.1", - "diff": "^8.0.3", - "glob": "^7.1.6", - "parse-diff": "^0.11.0", - "yargs": "^16.0.0" - }, - "bin": { - "code-suggester": "build/src/bin/code-suggester.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/code-suggester/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/code-suggester/node_modules/yargs": { - "version": "16.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", - "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/conventional-changelog-conventionalcommits": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz", - "integrity": "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==", - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-changelog-writer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz", - "integrity": "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==", - "dependencies": { - "conventional-commits-filter": "^3.0.0", - "dateformat": "^3.0.3", - "handlebars": "^4.7.7", - "json-stringify-safe": "^5.0.1", - "meow": "^8.1.2", - "semver": "^7.0.0", - "split": "^1.0.1" - }, - "bin": { - "conventional-changelog-writer": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-commits-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", - "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", - "dependencies": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" - }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", - "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/handlebars": { - "version": "4.7.10", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.10.tgz", - "integrity": "sha512-P5VJMVM7qgBn6vjXMw8WG9uVI+ncf2pi72j4de4yz5ZULLj2RGqLYaKOYGsgyrViQ0tePOVlN1tDCCXXtFqXKg==", - "dependencies": { - "minimist": "^1.2.8", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-core-module": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.17.0.tgz", - "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==", - "dependencies": { - "hasown": "^2.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", - "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsep": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", - "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", - "engines": { - "node": ">= 10.16.0" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "node_modules/jsonpath-plus": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", - "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", - "dependencies": { - "@jsep-plugin/assignment": "^1.3.0", - "@jsep-plugin/regex": "^1.0.4", - "jsep": "^1.4.0" - }, - "bin": { - "jsonpath": "bin/jsonpath-cli.js", - "jsonpath-plus": "bin/jsonpath-cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node_modules/node-html-parser": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", - "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", - "dependencies": { - "css-select": "^5.1.0", - "he": "1.2.0" - } - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-diff": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.11.1.tgz", - "integrity": "sha512-Oq4j8LAOPOcssanQkIjxosjATBIEJhCxMCxPhMu+Ci4wdNmAEdx0O+a7gzbR2PyKXgKPvRLIN5g224+dJAsKHA==" - }, - "node_modules/parse-github-repo-url": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", - "integrity": "sha512-bSWyzBKqcSL4RrncTpGsEKoJ7H8a4L3++ifTAbTFeMHyq2wRV+42DGmQcHIrJIvdcacjIOxEuKH/w4tthF17gg==" - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dependencies": { - "@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": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/release-please": { - "version": "17.3.0", - "resolved": "https://registry.npmjs.org/release-please/-/release-please-17.3.0.tgz", - "integrity": "sha512-dB7HsFUpAvU1Wj9RGCINUz8Zi2qQDZiGbDEEVnJ7baNfJmk5XdYhuUFL6RcuDGjReGhp1gzY8Tc2g7vHlM4zpg==", - "dependencies": { - "@conventional-commits/parser": "^0.4.1", - "@google-automations/git-file-utils": "^3.0.0", - "@iarna/toml": "^3.0.0", - "@octokit/graphql": "^7.1.0", - "@octokit/request": "^8.3.1", - "@octokit/request-error": "^5.1.0", - "@octokit/rest": "^20.1.1", - "@types/npm-package-arg": "^6.1.0", - "@xmldom/xmldom": "^0.8.4", - "chalk": "^4.0.0", - "code-suggester": "^5.0.0", - "conventional-changelog-conventionalcommits": "^6.0.0", - "conventional-changelog-writer": "^6.0.0", - "conventional-commits-filter": "^3.0.0", - "detect-indent": "^6.1.0", - "diff": "^8.0.3", - "figures": "^3.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "js-yaml": "^4.0.0", - "jsonpath-plus": "^10.0.0", - "node-html-parser": "^6.0.0", - "parse-github-repo-url": "^1.4.1", - "semver": "^7.5.3", - "type-fest": "^3.0.0", - "typescript": "^4.6.4", - "unist-util-visit": "^2.0.3", - "unist-util-visit-parents": "^3.1.1", - "xpath": "^0.0.34", - "yaml": "^2.2.2", - "yargs": "^17.0.0" - }, - "bin": { - "release-please": "build/src/bin/release-please.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.13", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.13.tgz", - "integrity": "sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.17.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.24", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.24.tgz", - "integrity": "sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ==" - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/xpath": { - "version": "0.0.34", - "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.34.tgz", - "integrity": "sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==", - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yaml": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", - "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - } - } -} diff --git a/.github/release-please/package.json b/.github/release-please/package.json deleted file mode 100644 index cc62d4b3..00000000 --- a/.github/release-please/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "openapi-odata-release-please", - "private": true, - "engines": { - "node": ">=24" - }, - "scripts": { - "test": "node --test run.test.cjs", - "coverage": "node -e \"require('node:fs').mkdirSync('../../artifacts/release-please', {recursive: true})\" && cd ../.. && node --test --experimental-test-coverage --test-coverage-include=.github/release-please/run.cjs --test-coverage-lines=80 --test-coverage-functions=80 --test-reporter=spec --test-reporter=lcov --test-reporter-destination=stdout --test-reporter-destination=artifacts/release-please/lcov.info .github/release-please/run.test.cjs" - }, - "dependencies": { - "@actions/core": "1.11.1", - "release-please": "17.3.0" - } -} diff --git a/.github/release-please/run.cjs b/.github/release-please/run.cjs deleted file mode 100644 index 67a344ae..00000000 --- a/.github/release-please/run.cjs +++ /dev/null @@ -1,203 +0,0 @@ -const {GitHub, Manifest, registerPlugin} = require('release-please'); -const {ManifestPlugin} = require('release-please/build/src/plugin'); -const {Version} = require('release-please/build/src/version'); -const {buildStrategy} = require('release-please/build/src/factory'); -const {FilePullRequestOverflowHandler} = require('release-please/build/src/util/pull-request-overflow-handler'); - -const HIDI_PENDING = 'autorelease: hidi-pending'; -const HIDI_VERSIONED = 'autorelease: hidi-versioned'; -const HIDI_FLOORS = {'main': '3.10.2', 'support/v2': '2.12.2'}; - -async function ensureHidiLabels(token, owner, repo, request = fetch) { - const api = (process.env.GITHUB_API_URL || 'https://api.github.com').replace(/\/$/, ''); - const url = `${api}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/labels`; - const headers = { - Authorization: `Bearer ${token}`, - Accept: 'application/vnd.github+json', - 'X-GitHub-Api-Version': '2022-11-28' - }; - for (const label of [ - {name: HIDI_PENDING, color: 'fbca04', description: 'Pending independent Hidi version pull request'}, - {name: HIDI_VERSIONED, color: '0e8a16', description: 'Merged Hidi version pull request; no production release'} - ]) { - const labelUrl = `${url}/${encodeURIComponent(label.name)}`; - let response = await request(labelUrl, {headers}); - let expectedStatus = 200; - if (response.status === 404) { - response = await request(url, { - method: 'POST', headers: {...headers, 'Content-Type': 'application/json'}, - body: JSON.stringify(label) - }); - if (response.status === 422) { - // Another branch job may have created the same label concurrently. - response = await request(labelUrl, {headers}); - } else if (response.status !== 201) { - throw new Error(`Cannot create Hidi lifecycle label '${label.name}': HTTP ${response.status}`); - } else { - expectedStatus = 201; - } - } - if (response.status !== expectedStatus || (await response.json()).name !== label.name) { - throw new Error(`Cannot verify Hidi lifecycle label '${label.name}': HTTP ${response.status}`); - } - } -} - -class ExactPathExclusions extends ManifestPlugin { - async preconfigure(strategies, commitsByPath) { - for (const [path, config] of Object.entries(this.repositoryConfig)) { - const excludes = config.excludePaths || []; - commitsByPath[path] = commitsByPath[path].filter(commit => { - if (!Array.isArray(commit.files)) { - throw new Error(`Missing changed files for commit ${commit.sha}`); - } - return commit.files.some(file => - (path === '.' || file.startsWith(`${path}/`)) && - !excludes.some(exclude => file === exclude || file.startsWith(`${exclude}/`)) - ); - }); - } - return strategies; - } - - async run(candidates) { - for (const candidate of candidates) { - if (candidate.config.component !== 'hidi') continue; - const floor = HIDI_FLOORS[this.targetBranch]; - const version = candidate.pullRequest.version; - if (!floor || !version || version.major !== Version.parse(floor).major || - version.preRelease || version.build || version.compare(Version.parse(floor)) <= 0) { - throw new Error('Generated Hidi version is outside the branch major or migration floor'); - } - } - return candidates; - } -} - -registerPlugin('exact-path-exclusions', options => - new ExactPathExclusions(options.github, options.targetBranch, options.repositoryConfig) -); - -async function prepareHidiVersionPrs(github, manifest, branch) { - const floor = HIDI_FLOORS[branch]; - const manifestConfig = await github.getFileJson('hidi-release-please-config.json', branch); - const config = manifest.repositoryConfig['.']; - const version = manifest.releasedVersions['.']; - if (!floor || Object.keys(manifest.repositoryConfig).length !== 1 || - Object.keys(manifest.releasedVersions).length !== 1 || - config?.component !== 'hidi' || config.releaseType !== 'simple' || - !config.includeComponentInTag || !config.includeVInTag || - (config.tagSeparator && config.tagSeparator !== '-') || - config.skipGithubRelease || - !config.separatePullRequests || - manifestConfig.label !== HIDI_PENDING || - !version || version.major !== Version.parse(floor).major || - version.preRelease || version.build || version.compare(Version.parse(floor)) < 0) { - throw new Error('Unsafe Hidi branch, manifest, component, labels or version configuration'); - } - const project = await github.getFileContentsOnBranch('src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj', branch); - const projectVersions = [...project.parsedContent.matchAll(/\s*([^<]+?)\s*<\/Version>/g)]; - if (projectVersions.length !== 1 || projectVersions[0][1] !== version.toString()) { - throw new Error('Hidi project version does not match its manifest'); - } - - const strategy = await buildStrategy({...config, github, path: '.', targetBranch: branch}); - const overflow = new FilePullRequestOverflowHandler(github); - const expectedBranch = `release-please--branches--${branch}--components--hidi`; - const pending = []; - let checkpoint; - for await (const pr of github.pullRequestIterator(branch, 'MERGED', 200, false)) { - if (!pr.labels.some(label => label === HIDI_PENDING || label === HIDI_VERSIONED)) continue; - if (pr.headBranchName !== expectedBranch || !pr.sha) { - throw new Error(`Unsafe Hidi version PR #${pr.number}: unexpected branch or missing merge SHA`); - } - const releases = await strategy.buildReleases(pr); - if (releases.length !== 1 || releases[0].tag.component !== 'hidi') { - throw new Error(`Cannot parse merged Hidi version PR #${pr.number}`); - } - const release = releases[0]; - const body = await overflow.parseOverflow(pr); - if (body?.releaseData.length !== 1 || - (body.releaseData[0].component && body.releaseData[0].component !== 'hidi') || - body.releaseData[0].version?.compare(release.tag.version) !== 0) { - throw new Error(`Hidi version PR #${pr.number} has inconsistent title and body versions`); - } - if (release.tag.version.compare(version) > 0 || - release.tag.version.compare(Version.parse(floor)) <= 0) { - throw new Error(`Merged Hidi PR #${pr.number} disagrees with the current manifest or migration floor`); - } - if (release.tag.version.compare(version) === 0) { - if (checkpoint && checkpoint.sha !== pr.sha) { - throw new Error(`Multiple merged Hidi PRs claim version ${version}`); - } - checkpoint = pr; - } - if (pr.labels.includes(HIDI_PENDING)) pending.push(pr); - } - if (!checkpoint && (version.toString() !== floor || pending.length)) { - throw new Error(`No merged Hidi version PR matches manifest version ${version}`); - } - if (checkpoint) { - // A version PR merge, not a production tag, is the boundary for the next cycle. - let reachable = false; - for await (const commit of github.mergeCommitIterator(branch, { - maxResults: manifest.commitSearchDepth, backfillFiles: false - })) { - if (commit.sha === checkpoint.sha) { - reachable = true; - break; - } - } - if (!reachable) throw new Error(`Hidi checkpoint ${checkpoint.sha} is outside the branch commit search`); - } - for (const pr of pending) { - // Adding first makes an interrupted label transition safe to retry. - await github.addIssueLabels([HIDI_VERSIONED], pr.number); - await github.removeIssueLabels([HIDI_PENDING], pr.number); - } - return checkpoint?.sha; -} - -async function runReleasePlease(github, branch, component) { - if (!['odata', 'hidi'].includes(component)) throw new Error(`Unknown component: ${component}`); - const configFile = component === 'hidi' ? 'hidi-release-please-config.json' : 'release-please-config.json'; - const manifestFile = component === 'hidi' ? '.hidi-release-please-manifest.json' : '.release-please-manifest.json'; - const load = (options = {}) => Manifest.fromManifest(github, branch, configFile, manifestFile, options); - const releases = component === 'odata' ? await (await load()).createReleases() : []; - let manifest = await load(); - if (component === 'hidi') { - const lastReleaseSha = await prepareHidiVersionPrs(github, manifest, branch); - if (lastReleaseSha) manifest = await load({lastReleaseSha}); - } - const prs = await manifest.createPullRequests(); - return {releases, prs}; -} - -async function main() { - const core = require('@actions/core'); - const token = process.env.RELEASE_PLEASE_TOKEN; - const branch = process.env.GITHUB_REF_NAME; - const [owner, repo] = (process.env.GITHUB_REPOSITORY || '').split('/'); - if (!token || !branch || !owner || !repo) throw new Error('Missing release automation environment'); - if (process.argv[2] === 'hidi') await ensureHidiLabels(token, owner, repo); - const github = await GitHub.create({owner, repo, token, defaultBranch: branch}); - const {releases, prs} = await runReleasePlease(github, branch, process.argv[2]); - core.setOutput('releases_created', releases.length > 0); - core.setOutput('prs_created', prs.length > 0); - core.setOutput('prs', JSON.stringify(prs)); - core.setOutput('paths_released', JSON.stringify(releases.map(release => release.path))); - if (prs.length) core.setOutput('pr', prs[0]); - for (const release of releases) { - const prefix = release.path === '.' ? '' : `${release.path}--`; - core.setOutput(`${prefix}release_created`, true); - for (const [name, value] of Object.entries(release)) { - const key = {tagName: 'tag_name', uploadUrl: 'upload_url', notes: 'body', url: 'html_url'}[name] || name; - core.setOutput(`${prefix}${key}`, value); - } - } -} - -module.exports = {ExactPathExclusions, prepareHidiVersionPrs, runReleasePlease, ensureHidiLabels, main}; -if (require.main === module) { - main().catch(error => require('@actions/core').setFailed(error.message)); -} diff --git a/.github/release-please/run.test.cjs b/.github/release-please/run.test.cjs deleted file mode 100644 index 9056b6b4..00000000 --- a/.github/release-please/run.test.cjs +++ /dev/null @@ -1,499 +0,0 @@ -const assert = require('node:assert/strict'); -const fs = require('node:fs'); -const path = require('node:path'); -const {test} = require('node:test'); -const {GitHub, Manifest, setLogger} = require('release-please'); -const {Version} = require('release-please/build/src/version'); -const {PullRequestBody} = require('release-please/build/src/util/pull-request-body'); -const {runReleasePlease, main, ExactPathExclusions, ensureHidiLabels} = require('./run.cjs'); - -setLogger({debug() {}, info() {}, warn() {}, error() {}}); -const root = path.resolve(__dirname, '..', '..'); -const branch = JSON.parse(fs.readFileSync(path.join(root, '.hidi-release-please-manifest.json')))['.'].startsWith('3.') ? 'main' : 'support/v2'; -const hidiProject = 'src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj'; -const hidiReadme = 'src/Microsoft.OpenApi.Hidi/readme.md'; -const hidiChangelog = 'src/Microsoft.OpenApi.Hidi/CHANGELOG.md'; -const hidiManifest = '.hidi-release-please-manifest.json'; -const odataManifest = '.release-please-manifest.json'; -const inputPaths = [ - 'release-please-config.json', 'hidi-release-please-config.json', - hidiManifest, odataManifest, hidiProject, hidiReadme, hidiChangelog, - 'Directory.Build.props', 'CHANGELOG.md' -]; - -class MemoryGitHub { - constructor(hidiVersion) { - this.repository = {owner: 'microsoft', repo: 'OpenAPI.NET.OData', defaultBranch: branch}; - this.files = Object.fromEntries(inputPaths.map(file => [file, fs.readFileSync(path.join(root, file), 'utf8')])); - this.commits = ['hidi-release-please-config.json', 'release-please-config.json'].map(file => ({ - sha: JSON.parse(this.files[file])['bootstrap-sha'], message: 'chore: baseline', files: [] - })); - this.prs = []; - this.releases = []; - this.tags = []; - this.labelWrites = []; - this.nextPr = 1; - if (hidiVersion) { - this.files[hidiManifest] = JSON.stringify({'.': hidiVersion}); - this.files[hidiProject] = this.files[hidiProject].replace(/.*?<\/Version>/, `${hidiVersion}`); - } - const current = JSON.parse(this.files[hidiManifest])['.']; - const floor = branch === 'main' ? '3.10.2' : '2.12.2'; - if (current !== floor) { - const checkpoint = { - number: 0, state: 'MERGED', sha: 'initial-hidi-checkpoint', - headBranchName: `release-please--branches--${branch}--components--hidi`, - baseBranchName: branch, - title: `chore(${branch}): release hidi ${current}`, - body: new PullRequestBody([{component: 'hidi', version: Version.parse(current), notes: 'Previously merged version'}], {useComponents: true}).toString(), - labels: ['autorelease: hidi-versioned'], files: [hidiManifest, hidiProject] - }; - this.prs.push(checkpoint); - this.commits.unshift({sha: checkpoint.sha, message: checkpoint.title, files: checkpoint.files, pullRequest: checkpoint}); - } - } - async getFileJson(file) { return JSON.parse(this.files[file]); } - async getFileContentsOnBranch(file) { - assert.ok(Object.hasOwn(this.files, file), `Unexpected read of ${file}`); - return {parsedContent: this.files[file], content: Buffer.from(this.files[file]).toString('base64'), sha: 'file-sha'}; - } - async *releaseIterator() { yield* this.releases; } - async *tagIterator() { yield* this.tags; } - async *mergeCommitIterator() { yield* this.commits; } - async *pullRequestIterator(target, state) { - assert.equal(target, branch); - yield* this.prs.filter(pr => pr.state === state); - } - change(files, message = 'fix: representative change') { - this.commits.unshift({sha: `change-${this.commits.length}`, message, files}); - } - materialize(updates) { - return Object.fromEntries(updates - .filter(update => update.createIfMissing || Object.hasOwn(this.files, update.path)) - .map(update => [update.path, update.updater.updateContent(this.files[update.path] || '')])); - } - async createPullRequest(pr, target, message, updates) { - assert.equal(target, branch); - const created = {...pr, number: this.nextPr++, state: 'OPEN', output: this.materialize(updates)}; - this.prs.unshift(created); - return created; - } - async updatePullRequest(number, plan) { - const pr = this.prs.find(item => item.number === number); - Object.assign(pr, {title: plan.title.toString(), body: plan.body.toString(), output: this.materialize(plan.updates)}); - return pr; - } - async addIssueLabels(labels, number) { - this.labelWrites.push(['add', number, labels]); - const pr = this.prs.find(item => item.number === number); - pr.labels = [...new Set([...pr.labels, ...labels])]; - } - async removeIssueLabels(labels, number) { - this.labelWrites.push(['remove', number, labels]); - const pr = this.prs.find(item => item.number === number); - pr.labels = pr.labels.filter(label => !labels.includes(label)); - } - async commentOnIssue() {} - async createRelease(release) { - const result = {tagName: release.tag.toString(), sha: release.sha, notes: release.notes, url: 'https://example.invalid/release'}; - this.releases.unshift(result); - this.tags.unshift({name: result.tagName, sha: result.sha}); - return result; - } - merge(pr) { - Object.assign(this.files, pr.output); - Object.assign(pr, {state: 'MERGED', sha: `merge-${pr.number}`}); - this.commits.unshift({sha: pr.sha, message: pr.title, files: Object.keys(pr.output), pullRequest: pr}); - } -} - -async function plans(github, component) { - return (await Manifest.fromManifest(github, branch, - component === 'hidi' ? 'hidi-release-please-config.json' : 'release-please-config.json', - component === 'hidi' ? hidiManifest : odataManifest)).buildPullRequests(); -} - -const routingCases = [ - ['src/Microsoft.OpenApi.Hidi/Program.cs', false, true], - ['src/Microsoft.OpenApi.Hidi/CsdlFilter.xslt', false, true], - [hidiProject, false, true], - [hidiReadme, false, true], - [hidiChangelog, false, true], - ['test/Microsoft.OpenApi.Hidi.Tests/StatsVisitorTests.cs', false, true], - ['test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/SampleOpenApi.yml', false, true], - ['test/Microsoft.OpenApi.Hidi.Tests/check-nuget-package-published.Tests.ps1', false, true], - ['scripts/check-nuget-package-published.ps1', false, true], - ['test/scripts/check-nuget-package-published.Tests.ps1', false, true], - ['Dockerfile', false, true], - ['.dockerignore', false, true], - ['install-tool.ps1', false, true], - ['tool/hidi-local-nuget.config', false, true], - ['tool/Microsoft.OpenApi.Hidi.public.snk', false, true], - ['hidi-release-please-config.json', false, true], - [hidiManifest, false, true], - ['.azure-pipelines/hidi-release.yml', false, true], - ['src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs', true, false], - ['test/Microsoft.OpenAPI.OData.Reader.Tests/OpenApiConvertSettingsTests.cs', true, false], - ['src/OoasGui/Program.cs', true, false], - ['src/OoasUtil/Program.cs', true, false], - ['docs/graphSecurityScheme/GraphSchemes.md', true, false], - ['Directory.Build.props', true, false], - ['redocly.yaml', true, false], - ['.redocly.lint-ignore.yaml', true, false], - ['src/AssemblyInfo/AssemblyInfoCommon.cs', true, false], - ['CHANGELOG.md', true, false], - ['release-please-config.json', true, false], - [odataManifest, true, false], - ['tool/Microsoft.OpenApi.OData.snk', true, false], - ['tool/35MSSharedLib1024.snk', true, false], - ['tool/Microsoft.OpenApi.OData.public.snk', false, true], - ['README.md', true, true], - ['CONTRIBUTING.md', true, true], - ['Build.props', true, true], - ['src/Build.props', true, true], - ['build.root', true, true], - ['build.ps1', true, false], - ['build.cmd', true, false], - ['global.json', true, true], - ['Microsoft.OpenApi.OData.sln', true, true], - ['.github/workflows/ci-cd.yml', false, false], - ['.github/release-please/run.cjs', false, false], - ['.azure-pipelines/ci-build.yml', false, false], - ['src/Microsoft.OpenApi.HidiSibling/Program.cs', true, true] -]; - -for (const [file, odata, hidi] of routingCases) { - test(`real engine routing: ${file}`, async () => { - const github = new MemoryGitHub(); - github.change([file]); - assert.equal((await plans(github, 'odata')).length, Number(odata)); - assert.equal((await plans(github, 'hidi')).length, Number(hidi)); - }); -} - -test('mixed changes affect both components; excluded-only and empty changes affect neither', async () => { - const github = new MemoryGitHub(); - github.change(['Dockerfile', 'src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs']); - assert.equal((await plans(github, 'odata')).length, 1); - assert.equal((await plans(github, 'hidi')).length, 1); - github.commits.shift(); - github.change(['Dockerfile', 'test/Microsoft.OpenApi.Hidi.Tests/StatsVisitorTests.cs']); - assert.equal((await plans(github, 'odata')).length, 0); - github.commits.shift(); - github.change([]); - assert.equal((await plans(github, 'odata')).length, 0); - assert.equal((await plans(github, 'hidi')).length, 0); -}); - -test('mixed unreleased history does not leak a Hidi feature into an OData patch', async () => { - const github = new MemoryGitHub(); - const odata = JSON.parse(github.files[odataManifest])['.']; - const hidi = JSON.parse(github.files[hidiManifest])['.']; - github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], 'feat(hidi): independent CLI capability'); - github.change(['src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs'], 'fix(odata): independent converter correction'); - const [rootPr] = await plans(github, 'odata'); - const [hidiPr] = await plans(github, 'hidi'); - assert.equal(rootPr.version.toString(), odata.replace(/\d+$/, patch => Number(patch) + 1)); - const [major, minor] = hidi.split('.').map(Number); - assert.equal(hidiPr.version.toString(), `${major}.${minor + 1}.0`); - assert.ok(rootPr.body.toString().includes('independent converter correction')); - assert.ok(!rootPr.body.toString().includes('independent CLI capability')); - assert.ok(hidiPr.body.toString().includes('independent CLI capability')); - assert.ok(!hidiPr.body.toString().includes('independent converter correction')); -}); - -test('actual Hidi patch output changes only its version, manifest, changelog and install examples', async () => { - const github = new MemoryGitHub(); - const baseline = github.files[hidiProject]; - const oldVersion = JSON.parse(github.files[hidiManifest])['.']; - const next = oldVersion.replace(/\d+$/, patch => Number(patch) + 1); - github.change(['Dockerfile'], 'fix(hidi): independent distribution fix'); - const [pr] = await plans(github, 'hidi'); - const output = github.materialize(pr.updates); - assert.deepEqual(Object.keys(output).sort(), [hidiChangelog, hidiProject, hidiReadme, hidiManifest].sort()); - assert.equal(pr.headRefName, `release-please--branches--${branch}--components--hidi`); - assert.equal(pr.version.toString(), next); - assert.ok(output[hidiProject].includes(`${next}`)); - const dependencies = text => [...text.matchAll(/ match.slice(1)); - assert.deepEqual(dependencies(output[hidiProject]), dependencies(baseline)); - assert.match(output[hidiChangelog], new RegExp(`hidi-v${oldVersion}\\.\\.\\.hidi-v${next}`)); - assert.equal(JSON.parse(output[hidiManifest])['.'], next); - assert.equal((output[hidiReadme].match(new RegExp(`--version ${next}`, 'g')) || []).length, 2); - assert.ok(output[hidiReadme].includes(`migration baseline ${branch === 'main' ? '3.10.2' : '2.12.2'} is already published`)); -}); - -test('actual OData output and componentless tags retain existing behavior', async () => { - const github = new MemoryGitHub(); - const oldVersion = JSON.parse(github.files[odataManifest])['.']; - const next = oldVersion.replace(/\d+$/, patch => Number(patch) + 1); - github.releases.push({tagName: `v${oldVersion}`, sha: github.commits.at(-1).sha, notes: ''}); - github.change(['Directory.Build.props'], 'fix(odata): independent library fix'); - const [pr] = await plans(github, 'odata'); - const output = github.materialize(pr.updates); - assert.deepEqual(Object.keys(output).sort(), ['CHANGELOG.md', 'Directory.Build.props', odataManifest].sort()); - assert.equal(pr.headRefName, `release-please--branches--${branch}--components--Microsoft.OpenApi.OData`); - assert.ok(output['Directory.Build.props'].includes(`${next}`)); - assert.match(output['CHANGELOG.md'], new RegExp(`v${oldVersion}\\.\\.\\.v${next}`)); - const created = await runReleasePlease(github, branch, 'odata'); - github.merge(created.prs[0]); - const released = await runReleasePlease(github, branch, 'odata'); - assert.equal(released.releases[0].tagName, `v${next}`); - assert.equal(released.prs.length, 0); -}); - -test('Hidi feature release increments minor; breaking changes fail before writing a PR or release', async () => { - const github = new MemoryGitHub(); - const [major, minor] = JSON.parse(github.files[hidiManifest])['.'].split('.').map(Number); - github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], 'feat(hidi): independent feature'); - assert.equal((await plans(github, 'hidi'))[0].version.toString(), `${major}.${minor + 1}.0`); - github.commits.shift(); - github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], 'feat(hidi)!: incompatible feature'); - await assert.rejects(runReleasePlease(github, branch, 'hidi'), /outside the branch major/); - assert.equal(github.prs.filter(pr => pr.state === 'OPEN').length, 0); - assert.equal(github.releases.length, 0); -}); - -test('generated Hidi fix and feature tags match the unchanged official pipeline guards without publishing', async () => { - const pipeline = fs.readFileSync(path.join(root, '.azure-pipelines', 'hidi-release.yml'), 'utf8'); - const floor = branch === 'main' ? '3.10.2' : '2.12.2'; - const current = JSON.parse(fs.readFileSync(path.join(root, hidiManifest), 'utf8'))['.']; - const [major, minor, patch] = current.split('.').map(Number); - assert.ok(pipeline.includes(`- hidi-v${major}.*`)); - assert.ok(pipeline.includes(`hidiPublishingEnabled: 'false'`)); - assert.ok(pipeline.includes(`[version]'${floor}'`)); - assert.ok(pipeline.includes('refs/tags/hidi-v$version')); - for (const [type, expected] of [ - ['fix', `${major}.${minor}.${patch + 1}`], - ['feat', `${major}.${minor + 1}.0`] - ]) { - const github = new MemoryGitHub(); - github.change(['src/Microsoft.OpenApi.Hidi/Program.cs'], `${type}(hidi): guarded version`); - const {prs} = await runReleasePlease(github, branch, 'hidi'); - github.merge(prs[0]); - const manifest = await Manifest.fromManifest(github, branch, 'hidi-release-please-config.json', hidiManifest); - const candidates = await manifest.buildReleases(); - assert.equal(candidates.length, 1); - assert.equal(candidates[0].tag.toString(), `hidi-v${expected}`); - assert.ok(Version.parse(expected).compare(Version.parse(floor)) > 0); - assert.ok(prs[0].output[hidiProject].includes(`${expected}`)); - assert.deepEqual(github.tags, []); - assert.deepEqual(github.releases, []); - } -}); - -test('two tag-free Hidi version cycles do not replay commits or block OData', async () => { - const github = new MemoryGitHub(); - const baseline = JSON.parse(github.files[hidiManifest])['.']; - github.change(['Dockerfile'], 'fix(hidi): first cycle'); - const first = await runReleasePlease(github, branch, 'hidi'); - assert.deepEqual(first.releases, []); - assert.deepEqual(first.prs[0].labels, ['autorelease: hidi-pending']); - assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); - github.merge(first.prs[0]); - assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); - assert.deepEqual(first.prs[0].labels, ['autorelease: hidi-versioned']); - assert.deepEqual(github.labelWrites.slice(0, 2).map(write => write[0]), ['add', 'remove']); - github.change(['scripts/check-nuget-package-published.ps1'], 'fix(hidi): second cycle'); - const second = await runReleasePlease(github, branch, 'hidi'); - const patch = Number(baseline.split('.')[2]); - assert.equal(JSON.parse(second.prs[0].output[hidiManifest])['.'], baseline.replace(/\d+$/, String(patch + 2))); - assert.ok(second.prs[0].body.includes('second cycle')); - assert.ok(!second.prs[0].body.includes('first cycle')); - github.merge(second.prs[0]); - assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); - github.change(['src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs'], 'fix(odata): after Hidi merges'); - assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); - assert.equal((await runReleasePlease(github, branch, 'odata')).prs.length, 1); - assert.deepEqual(github.tags, []); - assert.deepEqual(github.releases, []); -}); - -test('version automation and its fixtures keep working after the repository manifest advances', async () => { - const current = JSON.parse(fs.readFileSync(path.join(root, hidiManifest), 'utf8'))['.']; - const advanced = current.replace(/\d+$/, patch => Number(patch) + 1); - const next = current.replace(/\d+$/, patch => Number(patch) + 2); - const github = new MemoryGitHub(advanced); - github.change(['Dockerfile'], 'fix(hidi): after an existing version checkpoint'); - const {prs, releases} = await runReleasePlease(github, branch, 'hidi'); - assert.equal(JSON.parse(prs[0].output[hidiManifest])['.'], next); - assert.deepEqual(releases, []); - github.merge(prs[0]); - assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); - assert.deepEqual(github.tags, []); -}); - -test('open Hidi PR updates with additional commits instead of opening a duplicate', async () => { - const github = new MemoryGitHub(); - github.change(['Dockerfile'], 'fix(hidi): first fix'); - const first = await runReleasePlease(github, branch, 'hidi'); - github.change(['install-tool.ps1'], 'fix(hidi): additional fix'); - const updated = await runReleasePlease(github, branch, 'hidi'); - assert.equal(updated.prs[0].number, first.prs[0].number); - assert.equal(github.prs.filter(pr => pr.state === 'OPEN').length, 1); - assert.ok(updated.prs[0].body.includes('additional fix')); -}); - -test('unsafe manifest and merged PR state fail without label or release writes', async t => { - for (const kind of ['wrong-major', 'project-version-mismatch', 'missing-checkpoint', 'wrong-branch', 'bad-body', 'future-version', 'duplicate-checkpoint', 'unreachable-checkpoint', 'title-body-mismatch']) { - await t.test(kind, async () => { - const github = new MemoryGitHub(); - github.change(['Dockerfile'], 'fix(hidi): cycle'); - const {prs} = await runReleasePlease(github, branch, 'hidi'); - github.merge(prs[0]); - if (kind === 'wrong-major') github.files[hidiManifest] = '{".":"9.0.0"}'; - if (kind === 'project-version-mismatch') github.files[hidiProject] = github.files[hidiProject].replace(/.*?<\/Version>/, '9.0.0'); - if (kind === 'missing-checkpoint') github.prs = []; - if (kind === 'wrong-branch') prs[0].headBranchName = 'unrelated'; - if (kind === 'bad-body') prs[0].body = 'not a release PR'; - if (kind === 'future-version') github.files[hidiManifest] = fs.readFileSync(path.join(root, hidiManifest), 'utf8'); - if (kind === 'duplicate-checkpoint') github.prs.push({...prs[0], number: 99, sha: 'duplicate'}); - if (kind === 'unreachable-checkpoint') github.commits.shift(); - if (kind === 'title-body-mismatch') prs[0].title = 'chore(main): release hidi 9.0.0'; - await assert.rejects(runReleasePlease(github, branch, 'hidi')); - assert.deepEqual(github.labelWrites, []); - assert.deepEqual(github.releases, []); - }); - } -}); - -test('merged PR body version must agree with its title even when the title matches the manifest', async () => { - const github = new MemoryGitHub(); - github.change(['Dockerfile'], 'fix(hidi): cycle'); - const {prs} = await runReleasePlease(github, branch, 'hidi'); - github.merge(prs[0]); - const current = JSON.parse(github.files[hidiManifest])['.']; - prs[0].body = prs[0].body.replaceAll(current, current.replace(/\d+$/, patch => Number(patch) + 1)); - await assert.rejects(runReleasePlease(github, branch, 'hidi'), /inconsistent title and body/); - assert.deepEqual(github.labelWrites, []); -}); - -test('unknown component is an explicit failure', async () => { - await assert.rejects(runReleasePlease(new MemoryGitHub(), branch, 'unknown'), /Unknown component/); -}); - -test('missing commit files are an explicit plugin failure', async () => { - const plugin = new ExactPathExclusions(new MemoryGitHub(), branch, {'.': {excludePaths: []}}); - await assert.rejects(plugin.preconfigure({}, {'.': [{sha: 'bad'}]}), /Missing changed files/); -}); - -test('Hidi ignores pending OData PRs and interrupted label transitions are retryable', async () => { - const github = new MemoryGitHub(); - github.change(['Directory.Build.props'], 'fix(odata): root cycle'); - const rootPr = (await runReleasePlease(github, branch, 'odata')).prs[0]; - github.merge(rootPr); - github.change(['Dockerfile'], 'fix(hidi): independent cycle'); - const hidiPr = (await runReleasePlease(github, branch, 'hidi')).prs[0]; - assert.ok(hidiPr); - github.merge(hidiPr); - hidiPr.labels.push('autorelease: hidi-versioned'); - assert.equal((await runReleasePlease(github, branch, 'hidi')).prs.length, 0); - assert.deepEqual(hidiPr.labels, ['autorelease: hidi-versioned']); - assert.deepEqual(rootPr.labels, ['autorelease: pending']); -}); - -test('Hidi lifecycle labels are created using the authenticated GitHub REST API only when missing', async () => { - const calls = []; - const labels = new Set(); - const request = async (url, options) => { - assert.equal(options.headers.Authorization, 'Bearer offline-test-token'); - assert.equal(options.headers['X-GitHub-Api-Version'], '2022-11-28'); - calls.push([url, options.method || 'GET']); - if (options.method === 'POST') { - const label = JSON.parse(options.body); - assert.ok(['autorelease: hidi-pending', 'autorelease: hidi-versioned'].includes(label.name)); - labels.add(label.name); - return Response.json(label, {status: 201}); - } - const name = decodeURIComponent(url.split('/').at(-1)); - return labels.has(name) ? Response.json({name}) : Response.json({}, {status: 404}); - }; - await ensureHidiLabels('offline-test-token', 'microsoft', 'OpenAPI.NET.OData', request); - assert.deepEqual(calls.map(call => call[1]), ['GET', 'POST', 'GET', 'POST']); - assert.ok(calls[0][0].endsWith('/labels/autorelease%3A%20hidi-pending')); - calls.length = 0; - await ensureHidiLabels('offline-test-token', 'microsoft', 'OpenAPI.NET.OData', request); - assert.deepEqual(calls.map(call => call[1]), ['GET', 'GET']); -}); - -test('Hidi label bootstrap fails explicitly on permissions, network errors or invalid responses', async t => { - for (const status of [401, 403, 500]) { - await t.test(`read HTTP ${status}`, async () => { - await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', - async () => Response.json({}, {status})), new RegExp(`HTTP ${status}`)); - }); - } - await t.test('creation permissions', async () => { - await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', - async (url, options) => Response.json({}, {status: options.method === 'POST' ? 403 : 404})), - /Cannot create.*HTTP 403/); - }); - await t.test('network error', async () => { - await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', - async () => { throw new Error('offline connection failed'); }), /offline connection failed/); - }); - await t.test('unexpected label', async () => { - await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', - async () => Response.json({name: 'autorelease: pending'})), /Cannot verify/); - }); - await t.test('invalid JSON', async () => { - await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', - async () => new Response('invalid JSON')), SyntaxError); - }); -}); - -test('concurrent Hidi label creation is accepted only after verifying the exact existing label', async () => { - const existing = new Set(); - await ensureHidiLabels('token', 'owner', 'repo', async (url, options) => { - if (options.method === 'POST') { - existing.add(JSON.parse(options.body).name); - return Response.json({}, {status: 422}); - } - const name = decodeURIComponent(url.split('/').at(-1)); - return existing.has(name) ? Response.json({name}) : Response.json({}, {status: 404}); - }); - await assert.rejects(ensureHidiLabels('token', 'owner', 'repo', - async (url, options) => Response.json({}, {status: options.method === 'POST' ? 422 : 404})), - /Cannot verify.*HTTP 404/); -}); - -test('CLI wiring emits real library PR/release outputs and uses the app token', async t => { - const github = new MemoryGitHub(); - const core = require('@actions/core'); - const saved = {...process.env}; - const argv = process.argv; - t.after(() => { process.env = saved; process.argv = argv; }); - Object.assign(process.env, {RELEASE_PLEASE_TOKEN: 'offline-test-token', GITHUB_REF_NAME: branch, GITHUB_REPOSITORY: 'microsoft/OpenAPI.NET.OData'}); - let labelReads = 0; - t.mock.method(globalThis, 'fetch', async (url, options) => { - labelReads++; - assert.equal(options.headers.Authorization, 'Bearer offline-test-token'); - assert.equal(options.method, undefined); - return Response.json({name: decodeURIComponent(url.split('/').at(-1))}); - }); - t.mock.method(GitHub, 'create', async options => { - assert.equal(options.token, 'offline-test-token'); - assert.equal(options.defaultBranch, branch); - return github; - }); - const outputs = {}; - t.mock.method(core, 'setOutput', (key, value) => { outputs[key] = value; }); - process.argv = ['node', 'run.cjs', 'hidi']; - github.change(['Dockerfile'], 'fix(hidi): CLI cycle'); - await main(); - assert.equal(outputs.prs_created, true); - assert.equal(outputs.releases_created, false); - assert.equal(JSON.parse(outputs.prs)[0].headBranchName, `release-please--branches--${branch}--components--hidi`); - assert.equal(outputs.paths_released, '[]'); - process.argv[2] = 'odata'; - github.change(['Directory.Build.props'], 'fix(odata): CLI cycle'); - await main(); - github.merge(github.prs.find(pr => pr.labels.includes('autorelease: pending'))); - await main(); - assert.equal(outputs.releases_created, true); - assert.equal(outputs.release_created, true); - assert.ok(outputs.tag_name.startsWith('v')); - assert.ok(outputs.html_url); - assert.equal(labelReads, 2); - delete process.env.RELEASE_PLEASE_TOKEN; - await assert.rejects(main(), /Missing release automation environment/); -}); diff --git a/.github/workflows/release-please-gha.yml b/.github/workflows/release-please-gha.yml index 428e141a..87d433db 100644 --- a/.github/workflows/release-please-gha.yml +++ b/.github/workflows/release-please-gha.yml @@ -5,8 +5,8 @@ # # Summary: # This GitHub Actions workflow automates the release process using Release Please. -# It tests component routing and uses a GitHub App token to manage independent -# OData releases and tag-free Hidi version pull requests on their target branches. +# It triggers on pushes to the main branch, generates a GitHub App token using organization +# variables and secrets, and then runs the release-please-action to manage versioning and changelogs. name: Release Please @@ -16,40 +16,12 @@ on: - main - support/v1 - support/v2 - pull_request: - branches: - - main - - support/v1 - - support/v2 - paths: - - '.github/release-please/**' - - '.github/workflows/release-please-gha.yml' - - '*release-please*.json' - - 'Directory.Build.props' - - 'src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj' - - 'src/Microsoft.OpenApi.Hidi/readme.md' permissions: contents: read jobs: - release-please-tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 - with: - node-version: '24' - - name: Install pinned Release Please - working-directory: .github/release-please - run: npm ci --ignore-scripts - - name: Verify component routing and version-only lifecycle - working-directory: .github/release-please - run: npm test - release-please-master: - if: ${{ github.event_name == 'push' }} - needs: release-please-tests runs-on: ubuntu-latest steps: - name: Checkout repository @@ -62,41 +34,10 @@ jobs: app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }} private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }} - - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 - with: - node-version: '24' - - name: Install pinned Release Please - working-directory: .github/release-please - run: npm ci --ignore-scripts - - name: Release Please (OData) - run: node .github/release-please/run.cjs odata - env: - RELEASE_PLEASE_TOKEN: ${{ steps.app-token.outputs.token }} - GITHUB_REF_NAME: ${{ github.ref_name }} - - release-please-hidi: - # Version PRs only; tags, releases and protected publishing remain disabled. - if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'support/v2') }} - needs: release-please-tests - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }} - private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }} - - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 + - name: Release Please + uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4 with: - node-version: '24' - - name: Install pinned Release Please - working-directory: .github/release-please - run: npm ci --ignore-scripts - - name: Release Please (independent Hidi version PR) - run: node .github/release-please/run.cjs hidi - env: - RELEASE_PLEASE_TOKEN: ${{ steps.app-token.outputs.token }} - GITHUB_REF_NAME: ${{ github.ref_name }} + token: ${{ steps.app-token.outputs.token }} + config-file: release-please-config.json + manifest-file: .release-please-manifest.json + target-branch: ${{ github.ref_name }} diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 9c86a252..ca6bd5d3 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -49,26 +49,6 @@ jobs: - uses: actions/checkout@v6 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Set up Node.js for Release Please runner tests - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 - with: - node-version: '24' - - name: Test Release Please runner with measured JavaScript coverage - shell: pwsh - working-directory: .github/release-please - run: | - npm ci --ignore-scripts - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - npm run coverage - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - $report = '..\..\artifacts\release-please\lcov.info' - if (-not (Test-Path $report)) { - throw 'Release Please runner LCOV report was not generated.' - } - $sources = @(Get-Content $report | Where-Object { $_ -like 'SF:*' }) - if ($sources.Count -ne 1 -or $sources[0] -notmatch '^SF:\.github[/\\]release-please[/\\]run\.cjs$') { - throw 'Expected measured JavaScript coverage of only the Release Please runner.' - } - name: Cache SonarCloud packages uses: actions/cache@v5 with: @@ -140,7 +120,7 @@ jobs: CoverletOutputFormat: 'opencover' # https://github.com/microsoft/vstest/issues/4014#issuecomment-1307913682 shell: pwsh run: | - dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="test/**/coverage.net8.0.opencover.xml,artifacts/hidi/coverage/*opencover*.xml" /d:sonar.coverageReportPaths="artifacts/hidi/powershell-coverage/sonar-coverage.xml" /d:sonar.javascript.lcov.reportPaths="artifacts/release-please/lcov.info" /d:sonar.test.inclusions="test/**,**/run.test.cjs" + dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="test/**/coverage.net8.0.opencover.xml,artifacts/hidi/coverage/*opencover*.xml" /d:sonar.coverageReportPaths="artifacts/hidi/powershell-coverage/sonar-coverage.xml" dotnet workload restore dotnet build dotnet test test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenAPI.OData.Reader.Tests.csproj --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover diff --git a/.hidi-release-please-manifest.json b/.hidi-release-please-manifest.json deleted file mode 100644 index ddfb5d57..00000000 --- a/.hidi-release-please-manifest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - ".": "2.12.2" -} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 89d8ff81..d12ffb60 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,4 @@ { - ".": "2.2.1" + ".": "2.2.1", + "src/Microsoft.OpenApi.Hidi": "2.12.2" } \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dacd3642..99fe3377 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,65 +26,32 @@ public-only signing key preserves assembly identity and friend-assembly access; never add the source repository's private strong-name key. Production signing is handled only by the official Azure pipeline. -Hidi's version is in its own project and `.hidi-release-please-manifest.json`. +Hidi's version is in its own project and the +`src/Microsoft.OpenApi.Hidi` entry in `.release-please-manifest.json`. Its `hidi-v2.*` tags must not trigger OData publishing. Version 2.12.2 is the -already-published migration baseline, not a new release. Release Please now -opens independent version PRs on `support/v2`; Hidi tags, GitHub releases, and -production publishing remain disabled until source cutover. History-import -migration PRs must be merged with a merge commit, never squash or rebase. +already-published migration baseline, not a new release. Production publishing +remains disabled until source cutover. History-import migration PRs must be +merged with a merge commit, never squash or rebase. ### Independent automated versions -The Release Please workflow uses the pinned API runner in -`.github/release-please`. It registers `exact-path-exclusions` because the -upstream `exclude-paths` implementation matches directories, not individual -files. Keep the root OData config/manifest and the Hidi config/manifest separate; -the existing `simple` strategy updates `Directory.Build.props` for OData and -only the Hidi project's `` for Hidi. Hidi's changelog and annotated -installation examples are updated in the same version PR, without changing its -published OpenAPI dependencies. - -| Changed paths | Version track | -| --- | --- | -| Hidi CLI source, tests, and packaged readme | Hidi only | -| `Dockerfile`, `.dockerignore`, `install-tool.ps1`, Hidi public keys/local NuGet config | Hidi only | -| `.azure-pipelines/hidi-release.yml`, private-feed helper and its Pester tests, Hidi config/manifest | Hidi only | -| OData reader, GUI/utilities, OData tests/assembly metadata, `docs`, Redocly config, legacy `build.cmd`/`build.ps1`, OData config/manifest, `Directory.Build.props` | OData only | -| Root README/contributing docs, solution, SDK, `Build.props`, `src/Build.props`, `build.root` | Both, for releasable commits | -| `.github`, editor configuration directories, OData Azure CI pipeline | Neither | - -Routing is by changed paths, not commit scopes. Use `fix(hidi):` or -`feat(hidi):` for clarity, but a Hidi scope does not override file ownership. -A mixed change touching both components contributes to both tracks. An OData -version-only edit does not independently bump Hidi. - -Hidi version PRs use the `hidi` component and their own branch and lifecycle -labels (`autorelease: hidi-pending` and `autorelease: hidi-versioned`). After a -version PR merges, the runner uses that merge commit as the next version's -checkpoint and retires the pending label. This allows subsequent version PRs -without tags and does not block OData's normal release lifecycle. No Hidi -GitHub release or publishing job is invoked by this runner; production cutover -remains a separate protected operation. - -On its first Hidi run, the app token creates those two repository labels if -missing, using the GitHub labels API. Existing labels and OData's default labels -are not changed. API permission, network, or validation failures stop automation -explicitly; no publishing permissions or protected resources are granted. - -Run the offline routing and version-file tests with Node.js 24: - -```powershell -Push-Location .github\release-please -npm ci --ignore-scripts -npm test -npm run coverage -Pop-Location -``` - -The coverage command measures only the runner with Node's native coverage -instrumentation and writes `artifacts/release-please/lcov.info` relative to the -repository root. The existing SonarCloud workflow imports this report alongside -the unchanged C# and PowerShell coverage reports. +The standard Release Please action uses one `release-please-config.json` and +one `.release-please-manifest.json` with two components: root OData (`.`) and +Hidi (`src/Microsoft.OpenApi.Hidi`). Their versions advance independently in +the generated release PRs. The stock `separate-pull-requests` option preserves +OData's existing release branch and avoids the stock engine's componentless-root +parsing issue with combined release PRs. + +Hidi source changes update its project `` and local `CHANGELOG.md`; +the root component excludes Hidi source and tests. OData changes update +`Directory.Build.props` and the root `CHANGELOG.md`, without changing Hidi. +Hidi keeps `hidi-v2.*` tags; OData keeps componentless `v2.*` tags. Hidi's +published OpenAPI dependency versions are not changed by its version updater. + +Routing follows component paths, not commit scopes. Hidi-only tests do not +create a release by themselves, and root-level distribution/helper files remain +root-owned under this standard configuration. Production package, executable, +and container publishing remains gated in the official Azure pipeline. OpenAPI.net.OData is open to contributions. There are a couple of different recommended paths to get contributions into the released version of this library. diff --git a/README.md b/README.md index 509843fd..0253c820 100644 --- a/README.md +++ b/README.md @@ -100,12 +100,12 @@ tests requires the .NET 10 SDK. Existing OData tests still use .NET 8 and VSTest Hidi's filtered history was imported with a merge, not squashed. **Merge this migration PR using a merge commit, not squash or rebase**, so the canonical imported commits can also be retained by the later main-branch migration. -Independent Hidi version PRs are automated by Release Please on `support/v2`; -its project, manifest, changelog, and installation examples advance separately -from OData. Hidi tags, GitHub releases, and production publishing remain disabled -until source cutover; OpenAPI.NET remains the publisher in the meantime. +The standard Release Please config and manifest track Hidi and OData as separate +components on `support/v2`, updating their project versions and changelogs +independently. Production publishing remains disabled until source cutover; +OpenAPI.NET remains the package publisher in the meantime. See [independent automated versions](CONTRIBUTING.md#independent-automated-versions) -for changed-path ownership and the tag-free version PR lifecycle. +for component paths and version-file ownership. The gated hidi NuGet release uses `EsrpRelease@14`, staging only the exact `Microsoft.OpenApi.Hidi` package and its `.snupkg` symbols from the Hidi build diff --git a/hidi-release-please-config.json b/hidi-release-please-config.json deleted file mode 100644 index d93afadc..00000000 --- a/hidi-release-please-config.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", - "bootstrap-sha": "8ebc6abbb1da683db4b5bc0928183dec947f2f02", - "release-type": "simple", - "plugins": [ - "exact-path-exclusions" - ], - "separate-pull-requests": true, - "label": "autorelease: hidi-pending", - "release-label": "autorelease: hidi-versioned", - "include-component-in-tag": true, - "include-v-in-tag": true, - "exclude-paths": [ - ".azure-pipelines/ci-build.yml", - ".github", - ".idea", - ".vs", - ".vscode", - "src/Microsoft.OpenApi.OData.Reader", - "src/OoasGui", - "src/OoasUtil", - "src/AssemblyInfo", - "test/Microsoft.OpenAPI.OData.Reader.Tests", - "docs", - "CHANGELOG.md", - "Directory.Build.props", - "build.cmd", - "build.ps1", - "redocly.yaml", - ".redocly.lint-ignore.yaml", - "tool/35MSSharedLib1024.snk", - "tool/Microsoft.OpenApi.OData.snk", - "release-please-config.json", - ".release-please-manifest.json" - ], - "packages": { - ".": { - "package-name": "Microsoft.OpenApi.Hidi", - "component": "hidi", - "changelog-path": "src/Microsoft.OpenApi.Hidi/CHANGELOG.md", - "extra-files": [ - { - "type": "xml", - "path": "src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj", - "xpath": "//Project/PropertyGroup/Version" - }, - { - "type": "generic", - "path": "src/Microsoft.OpenApi.Hidi/readme.md" - } - ] - } - } -} diff --git a/release-please-config.json b/release-please-config.json index b7007cd1..1b2a820b 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,32 +1,14 @@ { "bootstrap-sha": "4f9bad6ea7d25e8596c0ca214975e690d925e6e7", - "plugins": [ - "exact-path-exclusions" - ], "exclude-paths": [ ".azure-pipelines", ".github", ".idea", ".vs", - ".vscode", - "src/Microsoft.OpenApi.Hidi", - "src/Microsoft.OpenApi.Tool", - "src/Microsoft.Hidi", - "Microsoft.OpenApi.Hidi.Tests", - "test/Microsoft.OpenApi.Hidi.Tests", - "test/Microsoft.OpenApi.Tests", - "test/scripts", - "scripts/check-nuget-package-published.ps1", - "tool/Microsoft.OpenApi.Hidi.public.snk", - "tool/Microsoft.OpenApi.OData.public.snk", - "tool/hidi-local-nuget.config", - "Dockerfile", - ".dockerignore", - "install-tool.ps1", - "hidi-release-please-config.json", - ".hidi-release-please-manifest.json" + ".vscode" ], "release-type": "simple", + "separate-pull-requests": true, "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "include-component-in-tag": false, @@ -36,6 +18,15 @@ ".": { "package-name": "Microsoft.OpenApi.OData", "changelog-path": "CHANGELOG.md", + "exclude-paths": [ + ".azure-pipelines", + ".github", + ".idea", + ".vs", + ".vscode", + "src/Microsoft.OpenApi.Hidi", + "test/Microsoft.OpenApi.Hidi.Tests" + ], "extra-files": [ { "type": "xml", @@ -43,6 +34,20 @@ "xpath": "//Project/PropertyGroup/Version" } ] + }, + "src/Microsoft.OpenApi.Hidi": { + "package-name": "Microsoft.OpenApi.Hidi", + "component": "hidi", + "changelog-path": "CHANGELOG.md", + "include-component-in-tag": true, + "include-v-in-tag": true, + "extra-files": [ + { + "type": "xml", + "path": "Microsoft.OpenApi.Hidi.csproj", + "xpath": "//Project/PropertyGroup/Version" + } + ] } }, "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" diff --git a/src/Microsoft.OpenApi.Hidi/CHANGELOG.md b/src/Microsoft.OpenApi.Hidi/CHANGELOG.md index 0d8e2ea5..7dede925 100644 --- a/src/Microsoft.OpenApi.Hidi/CHANGELOG.md +++ b/src/Microsoft.OpenApi.Hidi/CHANGELOG.md @@ -6,6 +6,6 @@ Migration baseline from OpenAPI.NET `support/v2`. This version is already published and must not be republished from this repository. Earlier release notes remain in [OpenAPI.NET releases](https://github.com/microsoft/OpenAPI.NET/releases). -Hidi has its own release manifest and `hidi-v2.*` tags, independent of OData. -Independent version PRs are automated without tags or GitHub releases. +Hidi has its own component entry in `.release-please-manifest.json` and +`hidi-v2.*` tags, independent of OData. Destination publishing remains disabled until the source publishing cutover. diff --git a/src/Microsoft.OpenApi.Hidi/readme.md b/src/Microsoft.OpenApi.Hidi/readme.md index cf37a95f..a922a5ee 100644 --- a/src/Microsoft.OpenApi.Hidi/readme.md +++ b/src/Microsoft.OpenApi.Hidi/readme.md @@ -17,20 +17,16 @@ Install [Microsoft.OpenApi.Hidi](https://www.nuget.org/packages/Microsoft.OpenAp ### .NET CLI(Global) - ```bash dotnet tool install --global Microsoft.OpenApi.Hidi --version 2.12.2 ``` - ### .NET CLI(local) - ```bash dotnet new tool-manifest # if the repository does not have a tool manifest dotnet tool install --local Microsoft.OpenApi.Hidi --version 2.12.2 ``` - @@ -75,12 +71,12 @@ docker run --rm --mount "type=bind,source=$PWD\test\Microsoft.OpenApi.Hidi.Tests Local/CI builds use the public-only strong-name identity. Official release artifacts are signed in Azure Pipelines; private signing keys do not belong in this repository. The migration baseline 2.12.2 is already published. Destination -NuGet, GitHub release, and Docker publishing are disabled until source cutover. -Release Please opens independent Hidi version PRs on `support/v2`, updating its -manifest, project version, changelog, and installation examples without creating -tags or GitHub releases. The first destination release must advance the Hidi -version beyond the baseline and use an exact `hidi-v2.` tag matching the -project. OData releases use separate artifacts and tags. +NuGet, executable, and Docker publishing are disabled until source cutover. +The standard Release Please config tracks Hidi as its own component, with a +separate manifest version, project version, changelog, and `hidi-v2.*` tags. +The first destination package release must advance beyond the baseline and use +an exact `hidi-v2.` tag matching the project. OData releases use separate +artifacts and tags. Docker builds opt into `HidiPublicSignBuild=true` for the local OData project, using its own public-only key without changing normal OData signing behavior. From f9ac07c8133a7f23f030f9d643eb53c7d09f2414 Mon Sep 17 00:00:00 2001 From: "Gavin Barron (from Dev Box)" Date: Fri, 9 Oct 2026 12:17:42 -0700 Subject: [PATCH 4/4] fix(release): route v2 publishing by component tag Release only OData for v2 tags and Hidi for hidi-v2 tags. Validate exact project/tag versions before artifact staging, select exact component packages and GitHub assets, and stop publishing after guard failures. Use supported DotNetCoreCLI pack inputs so the OData job does not default to packing Hidi and GUI projects or rebuilding signed binaries. Preserve existing protected environments, signing connections, Hidi publishing-off flag, private-feed behavior and migration floors. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dc4344a-fac5-4e6e-89f8-eb2c9467edd4 --- .azure-pipelines/ci-build.yml | 78 ++++++++++++++++++++++++------- .azure-pipelines/hidi-release.yml | 38 ++++++++++----- CONTRIBUTING.md | 15 ++++++ 3 files changed, 102 insertions(+), 29 deletions(-) diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index 724b3dea..f7e4e884 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -11,7 +11,7 @@ trigger: - support/v2 tags: include: - - 'v*' + - 'v2.*' pr: branches: include: @@ -56,6 +56,20 @@ extends: targetPath: '$(Build.ArtifactStagingDirectory)' steps: + - pwsh: | + $ErrorActionPreference = 'Stop' + $version = ([xml](Get-Content -LiteralPath Directory.Build.props)).SelectSingleNode('/Project/PropertyGroup/Version').InnerText + if ($version -cnotmatch '^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Invalid OData project version: $version." } + $sourceBranch = $env:BUILD_SOURCEBRANCH + if ($sourceBranch.StartsWith('refs/tags/')) { + if ($sourceBranch -cnotmatch '^refs/tags/v2\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { + throw "This pipeline only releases OData v2.* tags." + } + if ($sourceBranch -cne "refs/tags/v$version") { throw "OData tag must exactly match Directory.Build.props version." } + } + Write-Host "##vso[task.setvariable variable=ODataVersion]$version" + displayName: 'Verify OData component tag and project version' + - task: UseDotNet@2 displayName: 'Use .NET 6' # needed for ESRP signing inputs: @@ -174,8 +188,13 @@ extends: displayName: 'pack' inputs: command: pack - projects: src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj - arguments: '-o $(Build.ArtifactStagingDirectory) --configuration $(BuildConfiguration) --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg' + packagesToPack: src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj + configuration: '$(BuildConfiguration)' + packDirectory: '$(Build.ArtifactStagingDirectory)' + nobuild: true + includesymbols: true + includesource: true + buildProperties: 'SymbolPackageFormat=snupkg' - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'ESRP CodeSigning Nuget Packages' @@ -187,7 +206,7 @@ extends: AuthAKVName: 'akv-prod-eastus' AuthCertName: 'ReferenceLibraryPrivateCert' AuthSignCertName: 'ReferencePackagePublisherCertificate' - Pattern: '*.nupkg' + Pattern: 'Microsoft.OpenApi.OData.$(ODataVersion).nupkg' signConfigType: inlineSignParams inlineOperation: | [ @@ -212,7 +231,7 @@ extends: PendingAnalysisWaitTimeoutMinutes: '5' - stage: deploy - condition: and(contains(variables['build.sourceBranch'], 'refs/tags/v'), succeeded()) + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v2.')) dependsOn: build jobs: - deployment: deploy @@ -230,10 +249,26 @@ extends: pool: vmImage: ubuntu-latest steps: + - pwsh: | + $ErrorActionPreference = 'Stop' + $sourceBranch = $env:BUILD_SOURCEBRANCH + if ($sourceBranch -cnotmatch '^refs/tags/v2\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Expected an OData v2.* release tag." } + $version = $sourceBranch.Substring('refs/tags/v'.Length) + $packages = @(Get-ChildItem -LiteralPath '$(Pipeline.Workspace)' -Filter '*.nupkg' -File -Recurse) + if ($packages.Count -ne 1 -or $packages[0].Name -cne "Microsoft.OpenApi.OData.$version.nupkg") { + throw "Expected only the exact OData package matching the triggering tag." + } + $symbols = Join-Path $packages[0].DirectoryName "Microsoft.OpenApi.OData.$version.snupkg" + if (-not (Test-Path -LiteralPath $symbols -PathType Leaf)) { + throw "Missing exact OData symbols package for $version." + } + Write-Host "##vso[task.setvariable variable=ODataReleaseVersion]$version" + Write-Host "##vso[task.setvariable variable=ODataPackagePath]$($packages[0].FullName)" + displayName: 'Verify tagged OData package and symbols' - task: 1ES.PublishNuget@1 displayName: 'NuGet push' inputs: - packagesToPush: '$(Pipeline.Workspace)/Microsoft.OpenApi.OData.*.nupkg' + packagesToPush: '$(ODataPackagePath)' nuGetFeedType: external publishFeedCredentials: 'OpenAPI Nuget Connection' packageParentPath: '$(Pipeline.Workspace)' @@ -255,23 +290,30 @@ extends: vmImage: ubuntu-latest steps: - pwsh: | - $artifacts = @(Get-ChildItem -Path $(Pipeline.Workspace) -Filter Microsoft.OpenApi.OData.*.nupkg -Recurse) - if ($artifacts.Count -ne 1) { throw "Expected exactly one OData package; found $($artifacts.Count)." } - $artifactName = $artifacts[0] - $artifactVersion= $artifactName.Name -replace "Microsoft.OpenApi.OData.", "" -replace ".nupkg", "" - #Set Variable $artifactName and $artifactVersion - Write-Host "##vso[task.setvariable variable=artifactVersion; isSecret=false;]$artifactVersion" - echo "$artifactVersion" - displayName: 'Fetch Artifact Name' + $ErrorActionPreference = 'Stop' + $sourceBranch = $env:BUILD_SOURCEBRANCH + if ($sourceBranch -cnotmatch '^refs/tags/v2\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Expected an OData v2.* release tag." } + $version = $sourceBranch.Substring('refs/tags/v'.Length) + $packages = @(Get-ChildItem -LiteralPath '$(Pipeline.Workspace)' -Filter '*.nupkg' -File -Recurse) + if ($packages.Count -ne 1 -or $packages[0].Name -cne "Microsoft.OpenApi.OData.$version.nupkg") { + throw "Expected only the exact OData package matching the triggering tag." + } + $symbols = Join-Path $packages[0].DirectoryName "Microsoft.OpenApi.OData.$version.snupkg" + if (-not (Test-Path -LiteralPath $symbols -PathType Leaf)) { + throw "Missing exact OData symbols package for $version." + } + Write-Host "##vso[task.setvariable variable=ODataReleaseVersion]$version" + Write-Host "##vso[task.setvariable variable=ODataPackagePath]$($packages[0].FullName)" + displayName: 'Verify tagged OData release artifact' - task: GitHubRelease@1 displayName: 'GitHub release' - condition: succeededOrFailed() + condition: succeeded() inputs: gitHubConnection: 'Github-MaggieKimani1' action: edit tagSource: userSpecifiedTag - tag: 'v$(artifactVersion)' - title: 'v$(artifactVersion)' + tag: 'v$(ODataReleaseVersion)' + title: 'v$(ODataReleaseVersion)' releaseNotesSource: inline - assets: '$(Pipeline.Workspace)\Microsoft.OpenApi.OData.*.nupkg' + assets: '$(ODataPackagePath)' addChangeLog: false diff --git a/.azure-pipelines/hidi-release.yml b/.azure-pipelines/hidi-release.yml index 6bd8d486..0087ca80 100644 --- a/.azure-pipelines/hidi-release.yml +++ b/.azure-pipelines/hidi-release.yml @@ -49,6 +49,16 @@ extends: artifactName: HidiDockerContext targetPath: '$(Build.ArtifactStagingDirectory)\HidiDockerContext' steps: + - pwsh: | + $ErrorActionPreference = 'Stop' + $version = ([xml](Get-Content -LiteralPath src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj)).SelectSingleNode('/Project/PropertyGroup/Version').InnerText + if ($version -cnotmatch '^2\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Expected a hidi 2.x version, got $version." } + $sourceBranch = $env:BUILD_SOURCEBRANCH + if ($sourceBranch.StartsWith('refs/tags/') -and $sourceBranch -cne "refs/tags/hidi-v$version") { + throw "This pipeline only releases hidi-v2.* tags exactly matching the hidi project version." + } + Write-Host "##vso[task.setvariable variable=HidiVersion]$version" + displayName: Verify Hidi component tag and project version - task: CopyFiles@2 displayName: Stage public-only hidi Docker context inputs: @@ -103,12 +113,6 @@ extends: '@ | Set-Content -Path '$(Build.SourcesDirectory)\nuget.config' displayName: Configure approved NuGet feed - pwsh: | - $version = ([xml](Get-Content src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj)).Project.PropertyGroup.Version - if ($version -notmatch '^2\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Expected a hidi 2.x version, got $version." } - if ('$(Build.SourceBranch)' -like 'refs/tags/*' -and '$(Build.SourceBranch)' -ne "refs/tags/hidi-v$version") { - throw "Hidi tag must exactly match the hidi project version." - } - Write-Host "##vso[task.setvariable variable=HidiVersion]$version" dotnet build src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) -p:GeneratePackageOnBuild=false if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet run --project test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj -c $(buildConfiguration) -- --minimum-expected-tests 1 @@ -226,12 +230,22 @@ extends: deploy: steps: - pwsh: | - $tag = '$(Build.SourceBranch)' -replace '^refs/tags/hidi-v', '' + $ErrorActionPreference = 'Stop' + $sourceBranch = $env:BUILD_SOURCEBRANCH + if ($sourceBranch -cnotmatch '^refs/tags/hidi-v2\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Expected a Hidi hidi-v2.* release tag." } + $tag = $sourceBranch.Substring('refs/tags/hidi-v'.Length) if ([version]($tag -split '-')[0] -le [version]'2.12.2') { throw "Never republish the source migration baseline or an older hidi version." } $package = "$(Pipeline.Workspace)\hidi\Microsoft.OpenApi.Hidi.$tag.nupkg" - if (-not (Test-Path $package)) { throw "Missing exact hidi package: $package" } + if (-not (Test-Path -LiteralPath $package -PathType Leaf)) { throw "Missing exact hidi package: $package" } $symbols = "$(Pipeline.Workspace)\hidi\Microsoft.OpenApi.Hidi.$tag.snupkg" - if (-not (Test-Path $symbols)) { throw "Missing exact hidi symbols: $symbols" } + if (-not (Test-Path -LiteralPath $symbols -PathType Leaf)) { throw "Missing exact hidi symbols: $symbols" } + $packages = @(Get-ChildItem -LiteralPath '$(Pipeline.Workspace)\hidi' -Filter '*.nupkg' -File) + if ($packages.Count -ne 1 -or $packages[0].Name -cne "Microsoft.OpenApi.Hidi.$tag.nupkg") { + throw "Expected only the exact Hidi package matching the triggering tag." + } + foreach ($artifact in @("$(Pipeline.Workspace)\hidi\Microsoft.OpenApi.Hidi.exe", "$(Pipeline.Workspace)\hidi\hidi-win-x64-$tag.zip")) { + if (-not (Test-Path -LiteralPath $artifact -PathType Leaf)) { throw "Missing exact Hidi executable artifact: $artifact" } + } Write-Host "##vso[task.setvariable variable=HidiReleaseVersion]$tag" displayName: Verify new hidi release version and exact package - task: PowerShell@2 @@ -303,8 +317,10 @@ extends: vmImage: ubuntu-latest steps: - pwsh: | - $version = ([xml](Get-Content -LiteralPath '$(Pipeline.Workspace)/HidiDockerContext/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj')).Project.PropertyGroup.Version - if ('$(Build.SourceBranch)' -ne "refs/tags/hidi-v$version") { throw "Hidi tag does not match project version." } + $ErrorActionPreference = 'Stop' + $version = ([xml](Get-Content -LiteralPath '$(Pipeline.Workspace)/HidiDockerContext/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj')).SelectSingleNode('/Project/PropertyGroup/Version').InnerText + if ($version -cnotmatch '^2\.\d+\.\d+(-[0-9A-Za-z.-]+)?$') { throw "Expected a hidi 2.x container version, got $version." } + if ($env:BUILD_SOURCEBRANCH -cne "refs/tags/hidi-v$version") { throw "Hidi tag does not match project version." } if ([version]($version -split '-')[0] -le [version]'2.12.2') { throw "Do not republish the migration baseline or an older hidi version." } Write-Host "##vso[task.setvariable variable=HidiReleaseVersion]$version" displayName: Read independent hidi version diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 99fe3377..9a777e70 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,21 @@ create a release by themselves, and root-level distribution/helper files remain root-owned under this standard configuration. Production package, executable, and container publishing remains gated in the official Azure pipeline. +### Component-tagged Azure releases + +On `support/v2`, `.azure-pipelines/ci-build.yml` releases only the OData package +and attaches only its artifact for `v2.*` tags. +`.azure-pipelines/hidi-release.yml` handles only `hidi-v2.*` tags for Hidi's +NuGet package, Windows executable/ZIP, and container. Hidi publishing stays +disabled until the protected cutover; this routing does not enable it. + +Tag runs must exactly match the component's project version before staging +artifacts. Release jobs require the exact tag-derived package and symbols; +Hidi also requires its executable/ZIP or matching Docker-context version. +Wrong-component, malformed, other-major, or version-mismatched manually selected +tags fail validation instead of publishing. Ordinary branch/PR builds still +validate both projects as before, without running tag-only release stages. + OpenAPI.net.OData is open to contributions. There are a couple of different recommended paths to get contributions into the released version of this library. __NOTE__ A signed a contribution license agreement is required for all contributions, and is checked automatically on new pull requests. Please read and sign [the agreement](https://cla.microsoft.com/) before starting any work for this repository.