From d1f3d22adc691b7ba185f43f2014da7cec240a2f Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Fri, 27 Feb 2026 16:55:37 +0000 Subject: [PATCH 01/10] AEA-5986 Add pypi plugin to semantic release. --- .github/workflows/tag-release.yml | 15 ++++++++++++++- release.config.cjs | 11 +++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 86770c2..bba9616 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -46,6 +46,16 @@ on: description: "An repository for the extra artifact" required: false type: string + pypi_publish: + description: "Whether to publish to PyPI" + required: false + type: boolean + default: false + pypi_test_publish: + description: "Whether to publish to Test PyPI" + required: false + type: boolean + default: false outputs: version_tag: value: ${{ jobs.tag_release.outputs.version_tag }} @@ -71,6 +81,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: repository: NHSDigital/eps-common-workflows + ref: aea-5986-publish-fame-library sparse-checkout-cone-mode: false sparse-checkout: | package.json @@ -249,7 +260,7 @@ jobs: PYTHON_CONFIGURE_OPTS: --enable-shared - name: Install Dependencies and Build Package - if: inputs.publish_packages != '' + if: inputs.publish_packages != '' || inputs.pypi_publish != '' run: | make install make build @@ -320,6 +331,8 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} MAIN_BRANCH: ${{ inputs.main_branch }} EXTRA_ASSET: ${{ inputs.extra_artifact_name }} + PYPI_PUBLISH: ${{ inputs.pypi_publish }} + PYPI_TEST_PUBLISH: ${{ inputs.pypi_test_publish }} - name: Create semantic release tag if: ${{ !inputs.dry_run }} diff --git a/release.config.cjs b/release.config.cjs index 9c6c739..7f44dbf 100644 --- a/release.config.cjs +++ b/release.config.cjs @@ -5,6 +5,10 @@ const commitTemplate = readFileSync("./releaseNotesTemplates/commit.hbs").toStri const publish_packages = process.env.PUBLISH_PACKAGES?.split(",").map(s => s.trim()).filter(s => s.length > 0) || [] const mainBranch = process.env.MAIN_BRANCH || "main" +const pypiPublish = process.env.PYPI_PUBLISH || false +const pypiTestPublish = process.env.PYPI_TEST_PUBLISH || false +const pypiRepoUrl = pypiTestPublish ? "https://test.pypi.org/legacy/" : "https://upload.pypi.org/legacy/" + module.exports = { branches: [ { @@ -73,6 +77,13 @@ module.exports = { pkgRoot: subpackage } ]), + [ + "semantic-release-pypi", + { + pypiPublish, pypiPublish, + repoUrl: pypiRepoUrl + } + ], [ "@semantic-release/github", { From fa5243b46244df8cc1e2f766258ae8c5c23ec1cc Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Mon, 2 Mar 2026 11:59:06 +0000 Subject: [PATCH 02/10] AEA-5986 Add pypi plugin for semantic release. --- package-lock.json | 565 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 +- 2 files changed, 566 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e2f6b80..3736a17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "@semantic-release/github": "^12.0.6", "@semantic-release/release-notes-generator": "^14.1.0", "conventional-changelog-eslint": "^6.0.0", - "semantic-release": "^25.0.3" + "semantic-release": "^25.0.3", + "semantic-release-pypi": "^5.1.3" } }, "node_modules/@actions/core": { @@ -627,6 +628,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, "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", @@ -728,6 +749,13 @@ "dev": true, "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", @@ -755,6 +783,62 @@ "node": ">=8" } }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1059,6 +1143,19 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", @@ -1277,6 +1374,35 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -1287,6 +1413,26 @@ "node": ">=4.0.0" } }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1313,6 +1459,21 @@ "node": ">=8" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -1486,6 +1647,55 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1639,6 +1849,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/form-data": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -1665,6 +1902,16 @@ "node": ">=14.14" } }, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/function-timeout": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz", @@ -1701,6 +1948,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", @@ -1729,6 +2015,71 @@ "traverse": "0.6.8" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/got/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1768,6 +2119,48 @@ "node": ">=4" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -1791,6 +2184,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -1805,6 +2205,20 @@ "node": ">= 14" } }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -2072,6 +2486,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -2099,6 +2520,16 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -2199,6 +2630,19 @@ "dev": true, "license": "MIT" }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -2273,6 +2717,16 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/meow": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", @@ -2323,6 +2777,29 @@ "node": ">=16" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -2336,6 +2813,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -4453,6 +4943,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, "node_modules/p-each-series": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", @@ -4755,6 +5255,19 @@ "dev": true, "license": "ISC" }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -4876,6 +5389,13 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -4886,6 +5406,22 @@ "node": ">=8" } }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4937,6 +5473,20 @@ "node": "^22.14.0 || >= 24.10.0" } }, + "node_modules/semantic-release-pypi": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/semantic-release-pypi/-/semantic-release-pypi-5.1.3.tgz", + "integrity": "sha512-VGkW+PZ8eXu0gBRwhlxfgMozp8od7YLhQgVTdgDU1pFX94GrKQ2GKvLtVuchbPqDJ+HW+eMF3j4qwejVCt/QDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^9.4.1", + "form-data": "^3.0.0", + "got": "^12.6.1", + "lodash": "^4.17.21", + "smol-toml": "^1.3.1" + } + }, "node_modules/semantic-release/node_modules/@semantic-release/error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", @@ -5227,6 +5777,19 @@ "node": ">=8" } }, + "node_modules/smol-toml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz", + "integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 1f6ac68..d97d37e 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@semantic-release/github": "^12.0.6", "@semantic-release/release-notes-generator": "^14.1.0", "conventional-changelog-eslint": "^6.0.0", - "semantic-release": "^25.0.3" + "semantic-release": "^25.0.3", + "semantic-release-pypi": "^5.1.3" } } From a8fc17344afaa6ed1141936f4a5c77f81b62b7ee Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Mon, 2 Mar 2026 17:12:34 +0000 Subject: [PATCH 03/10] AEA-5986 Install asdf dependencies when pypi_publish. --- .github/workflows/tag-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index bba9616..ba412b5 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -242,7 +242,7 @@ jobs: name: config_artifact - name: Cache asdf - if: inputs.publish_packages != '' + if: inputs.publish_packages != '' || inputs.pypi_publish != '' uses: actions/cache@v5 with: path: | @@ -252,7 +252,7 @@ jobs: ${{ runner.os }}-asdf- - name: Install asdf dependencies in .tool-versions - if: inputs.publish_packages != '' + if: inputs.publish_packages != '' || inputs.pypi_publish != '' uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 with: asdf_version: ${{ inputs.asdfVersion }} From 81fd8de5722e7022d8a609edc4f174cfbd8a4bd4 Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Tue, 3 Mar 2026 16:38:53 +0000 Subject: [PATCH 04/10] AEA-5986 Accept pypi token secrets. --- .github/workflows/tag-release.yml | 6 ++++++ release.config.cjs | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index ba412b5..75b24ff 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -69,6 +69,12 @@ on: NPM_TOKEN: required: false description: "NPM token to publish packages" + PYPI_TOKEN: + required: false + description: "PyPI token to publish packages" + PYPI_TEST_TOKEN: + required: false + description: "Test PyPI token to publish packages to test index" jobs: install_semantic_release: # Install asdf diff --git a/release.config.cjs b/release.config.cjs index 7f44dbf..b6e921b 100644 --- a/release.config.cjs +++ b/release.config.cjs @@ -8,6 +8,7 @@ const mainBranch = process.env.MAIN_BRANCH || "main" const pypiPublish = process.env.PYPI_PUBLISH || false const pypiTestPublish = process.env.PYPI_TEST_PUBLISH || false const pypiRepoUrl = pypiTestPublish ? "https://test.pypi.org/legacy/" : "https://upload.pypi.org/legacy/" +const pypiToken = pypiTestPublish ? process.env.PYPI_TEST_TOKEN : process.env.PYPI_TOKEN module.exports = { branches: [ @@ -81,7 +82,8 @@ module.exports = { "semantic-release-pypi", { pypiPublish, pypiPublish, - repoUrl: pypiRepoUrl + repoUrl: pypiRepoUrl, + repoToken: pypiToken } ], [ From 6678e2d133256b95b1a7dceb403b0a56a348285e Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Tue, 3 Mar 2026 16:59:11 +0000 Subject: [PATCH 05/10] AEA-5986 Handle bools as strings. --- .github/workflows/tag-release.yml | 2 ++ release.config.cjs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 75b24ff..bc8d69c 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -339,6 +339,8 @@ jobs: EXTRA_ASSET: ${{ inputs.extra_artifact_name }} PYPI_PUBLISH: ${{ inputs.pypi_publish }} PYPI_TEST_PUBLISH: ${{ inputs.pypi_test_publish }} + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + PYPI_TEST_TOKEN: ${{ secrets.PYPI_TEST_TOKEN }} - name: Create semantic release tag if: ${{ !inputs.dry_run }} diff --git a/release.config.cjs b/release.config.cjs index b6e921b..7c621eb 100644 --- a/release.config.cjs +++ b/release.config.cjs @@ -5,8 +5,8 @@ const commitTemplate = readFileSync("./releaseNotesTemplates/commit.hbs").toStri const publish_packages = process.env.PUBLISH_PACKAGES?.split(",").map(s => s.trim()).filter(s => s.length > 0) || [] const mainBranch = process.env.MAIN_BRANCH || "main" -const pypiPublish = process.env.PYPI_PUBLISH || false -const pypiTestPublish = process.env.PYPI_TEST_PUBLISH || false +const pypiPublish = process.env.PYPI_PUBLISH?.toLowerCase() === 'true' || false +const pypiTestPublish = process.env.PYPI_TEST_PUBLISH?.toLowerCase() === 'true' || false const pypiRepoUrl = pypiTestPublish ? "https://test.pypi.org/legacy/" : "https://upload.pypi.org/legacy/" const pypiToken = pypiTestPublish ? process.env.PYPI_TEST_TOKEN : process.env.PYPI_TOKEN From 39c46dfce557ea3da2df12f0d5366075ac463b35 Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Wed, 4 Mar 2026 12:08:28 +0000 Subject: [PATCH 06/10] AEA-5986 Rely on dry-run rather than publish to test index. --- .github/workflows/tag-release.yml | 10 ---------- release.config.cjs | 7 ++----- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index bc8d69c..da63818 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -51,11 +51,6 @@ on: required: false type: boolean default: false - pypi_test_publish: - description: "Whether to publish to Test PyPI" - required: false - type: boolean - default: false outputs: version_tag: value: ${{ jobs.tag_release.outputs.version_tag }} @@ -72,9 +67,6 @@ on: PYPI_TOKEN: required: false description: "PyPI token to publish packages" - PYPI_TEST_TOKEN: - required: false - description: "Test PyPI token to publish packages to test index" jobs: install_semantic_release: # Install asdf @@ -338,9 +330,7 @@ jobs: MAIN_BRANCH: ${{ inputs.main_branch }} EXTRA_ASSET: ${{ inputs.extra_artifact_name }} PYPI_PUBLISH: ${{ inputs.pypi_publish }} - PYPI_TEST_PUBLISH: ${{ inputs.pypi_test_publish }} PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - PYPI_TEST_TOKEN: ${{ secrets.PYPI_TEST_TOKEN }} - name: Create semantic release tag if: ${{ !inputs.dry_run }} diff --git a/release.config.cjs b/release.config.cjs index 7c621eb..8a64634 100644 --- a/release.config.cjs +++ b/release.config.cjs @@ -6,9 +6,7 @@ const publish_packages = process.env.PUBLISH_PACKAGES?.split(",").map(s => s.tri const mainBranch = process.env.MAIN_BRANCH || "main" const pypiPublish = process.env.PYPI_PUBLISH?.toLowerCase() === 'true' || false -const pypiTestPublish = process.env.PYPI_TEST_PUBLISH?.toLowerCase() === 'true' || false -const pypiRepoUrl = pypiTestPublish ? "https://test.pypi.org/legacy/" : "https://upload.pypi.org/legacy/" -const pypiToken = pypiTestPublish ? process.env.PYPI_TEST_TOKEN : process.env.PYPI_TOKEN +const pypiToken = process.env.PYPI_TOKEN module.exports = { branches: [ @@ -81,8 +79,7 @@ module.exports = { [ "semantic-release-pypi", { - pypiPublish, pypiPublish, - repoUrl: pypiRepoUrl, + pypiPublish: pypiPublish, repoToken: pypiToken } ], From 5d1c232dca2d144d5e61841e0ed513c465ad5ebc Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Wed, 4 Mar 2026 14:00:48 +0000 Subject: [PATCH 07/10] AEA-5986 Handle bool correctly in if condition. --- .github/workflows/tag-release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index da63818..2616233 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -240,7 +240,7 @@ jobs: name: config_artifact - name: Cache asdf - if: inputs.publish_packages != '' || inputs.pypi_publish != '' + if: ${{ inputs.publish_packages != '' || inputs.pypi_publish }} uses: actions/cache@v5 with: path: | @@ -250,7 +250,7 @@ jobs: ${{ runner.os }}-asdf- - name: Install asdf dependencies in .tool-versions - if: inputs.publish_packages != '' || inputs.pypi_publish != '' + if: ${{ inputs.publish_packages != '' || inputs.pypi_publish }} uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 with: asdf_version: ${{ inputs.asdfVersion }} @@ -258,7 +258,7 @@ jobs: PYTHON_CONFIGURE_OPTS: --enable-shared - name: Install Dependencies and Build Package - if: inputs.publish_packages != '' || inputs.pypi_publish != '' + if: ${{ inputs.publish_packages != '' || inputs.pypi_publish }} run: | make install make build From f2bdb2060708a1b97568570b4833a8d2dcab2ff1 Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Wed, 4 Mar 2026 14:12:35 +0000 Subject: [PATCH 08/10] AEA-5986 Add PyPI values to env to create semantic release tag step. --- .github/workflows/tag-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 2616233..b46d524 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -341,6 +341,8 @@ jobs: TAG_FORMAT: ${{ inputs.tag_format }} MAIN_BRANCH: ${{ inputs.main_branch }} EXTRA_ASSET: ${{ inputs.extra_artifact_name }} + PYPI_PUBLISH: ${{ inputs.pypi_publish }} + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} run: | npx semantic-release --tag-format "${TAG_FORMAT}" From fe9c4b7eeb5f99a465a978cd73fc86c362de2ea3 Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Wed, 4 Mar 2026 14:24:15 +0000 Subject: [PATCH 09/10] AEA-5986 Add minimatch vulnerability to trivy ignore. --- .trivyignore.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.trivyignore.yaml b/.trivyignore.yaml index 6fa84a3..e51078a 100644 --- a/.trivyignore.yaml +++ b/.trivyignore.yaml @@ -16,6 +16,12 @@ vulnerabilities: - id: CVE-2026-26996 statement: minimatch vulnerability accepted as risk expired_at: 2026-06-01 + - id: CVE-2026-27903 + statement: minimatch vulnerability accepted as risk - dependency of npm (multiple) + expired_at: 2026-06-01 + - id: CVE-2026-27904 + statement: minimatch vulnerability accepted as risk - dependency of npm (multiple) + expired_at: 2026-06-01 - id: CVE-2026-26960 statement: tar vulnerability accepted as risk expired_at: 2026-06-01 From 909fc185b2baf815b0032264600772d3468ae322 Mon Sep 17 00:00:00 2001 From: Phil Gee Date: Wed, 4 Mar 2026 14:42:27 +0000 Subject: [PATCH 10/10] AEA-5986 Remove branch-specific checkout. --- .github/workflows/tag-release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index b46d524..1b3e7cd 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -79,7 +79,6 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: repository: NHSDigital/eps-common-workflows - ref: aea-5986-publish-fame-library sparse-checkout-cone-mode: false sparse-checkout: | package.json