Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions lib/release/release-manager.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
const { Octokit } = require('@octokit/rest')
const core = require('@actions/core')
const { join } = require('path')
const semver = require('semver')
const assert = require('assert')
const dedent = require('dedent')
const mapWorkspaces = require('@npmcli/map-workspaces')
const { request: fetch } = require('undici')
const { getPublishTag, block, noop } = require('./util')

class ReleaseManager {
#octokit
#token
#owner
#repo
#cwd
Expand All @@ -28,7 +27,7 @@ class ReleaseManager {
assert(pr, 'pr is required')
assert(defaultTag, 'defaultTag is required')

this.#octokit = new Octokit({ auth: token })
this.#token = token
this.#owner = repo.split('/')[0]
this.#repo = repo.split('/')[1]
this.#cwd = cwd
Expand All @@ -43,9 +42,15 @@ class ReleaseManager {

static async run(options) {
const manager = new ReleaseManager(options)
await manager.#init()
return manager.run()
}

async #init() {
const { Octokit } = await import('@octokit/rest')
this.#octokit = new Octokit({ auth: this.#token })
}

async run() {
const { data: pullRequest } = await this.#octokit.rest.pulls.get({
owner: this.#owner,
Expand Down Expand Up @@ -168,15 +173,15 @@ class ReleaseManager {
// up because that means something is very wrong. This is a rare edge
// case that isn't worth testing.

if (r.statusCode === 200) {
if (r.status === 200) {
this.#info('Found release process from wiki')
return r.body.text()
} else if (r.statusCode === 404) {
return r.text()
} else if (r.status === 404) {
this.#info('No release process found in wiki, falling back to default process')
return this.#getReleaseSteps()
/* c8 ignore next 3 */
} else {
throw new Error(`Release process fetch failed with status: ${r.statusCode}`)
throw new Error(`Release process fetch failed with status: ${r.status}`)
}
})

Expand Down
8 changes: 2 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@npmcli/git": "^6.0.0",
"@npmcli/map-workspaces": "^4.0.0",
"@npmcli/package-json": "^6.0.0",
"@octokit/rest": "^19.0.4",
"@octokit/rest": "^22.0.0",
"dedent": "^1.5.1",
"diff": "^7.0.0",
"glob": "^10.1.0",
Expand All @@ -59,7 +59,6 @@
"proc-log": "^5.0.0",
"release-please": "16.15.0",
"semver": "^7.3.5",
"undici": "^6.7.0",
"yaml": "^2.1.1"
},
"files": [
Expand All @@ -71,15 +70,12 @@
"@npmcli/eslint-config": "^5.0.0",
"@npmcli/template-oss": "file:./",
"eslint-config-prettier": "^9.1.0",
"nock": "^13.3.8",
"nock": "^14.0.6",
"prettier": "^3.2.5",
"tap": "^21.0.1"
},
"tap": {
"timeout": 600,
"node-arg": [
"--no-experimental-fetch"
],
"exclude": [
"workspace/test-workspace/**"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
'use strict'
exports[`test/release/release-manager.js > TAP > mock release manager > must match snapshot 1`] = `
### Release Checklist for v4.0.5
### Release Checklist for v4.1.0

- [ ] 1. Checkout the release branch and test

Expand All @@ -23,6 +23,9 @@ exports[`test/release/release-manager.js > TAP > mock release manager > must mat
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
\`\`\`

- [ ] 3. Publish
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* IMPORTANT
* This snapshot file is auto-generated, but designed for humans.
* It should be checked into source control and tracked carefully.
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
* Make sure to inspect the output below. Do not ignore changes!
*/
'use strict'
exports[`test/release/release-manager.js > TAP > prerelease filtering > must match snapshot 1`] = `
### Release Checklist for v4.1.0

- [ ] 1. Checkout the release branch and test

\`\`\`sh
gh pr checkout 207 --force
npm update
npm test
gh pr checks 207 -R npm/npm-cli-release-please --watch
\`\`\`

- [ ] 2. Publish workspaces

\`\`\`sh
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
\`\`\`

- [ ] 3. Publish

\`\`\`sh
npm publish --tag=latest
\`\`\`

- [ ] 4. Merge release PR

\`\`\`sh
gh pr merge 207 -R npm/npm-cli-release-please --squash
git checkout main
git fetch
git reset --hard origin/main
\`\`\`

- [ ] 5. Check For Release Tags

Release Please will run on the just pushed release commit and create GitHub releases and tags for each package.

\`\`\`sh
gh run watch -R npm/npm-cli-release-please $(gh run list -R npm/npm-cli-release-please --workspace release -b main -L 1 --json databaseId -q ".[0].databaseId")
\`\`\`
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* IMPORTANT
* This snapshot file is auto-generated, but designed for humans.
* It should be checked into source control and tracked carefully.
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
* Make sure to inspect the output below. Do not ignore changes!
*/
'use strict'
exports[`test/release/release-manager.js > TAP > wiki with headers > must match snapshot 1`] = `
### Release Checklist for v4.1.0

- [ ] 1. Checkout the release branch and test

\`\`\`sh
gh pr checkout 207 --force
npm update
npm test
gh pr checks 207 -R npm/npm-cli-release-please --watch
\`\`\`

- [ ] 2. Publish workspaces

\`\`\`sh
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
npm publish --tag=latest
\`\`\`

- [ ] 3. Publish

\`\`\`sh
npm publish --tag=latest
\`\`\`

- [ ] 4. Merge release PR

\`\`\`sh
gh pr merge 207 -R npm/npm-cli-release-please --squash
git checkout main
git fetch
git reset --hard origin/main
\`\`\`

- [ ] 5. Check For Release Tags

Release Please will run on the just pushed release commit and create GitHub releases and tags for each package.

\`\`\`sh
gh run watch -R npm/npm-cli-release-please $(gh run list -R npm/npm-cli-release-please --workspace release -b main -L 1 --json databaseId -q ".[0].databaseId")
\`\`\`
`
1 change: 1 addition & 0 deletions test/fixtures/mock-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const setup = t => {
nock.recorder.clear()
nock.restore()
} else {
nock.cleanAll()
nock.enableNetConnect()
}
})
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion test/fixtures/nocks/release-manager-npm-cli.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"scope":"https://api.github.com:443","method":"GET","path":"/repos/npm/npm-cli-release-please/pulls/207","body":"","status":200,"response":["1f8b0800000000000013ed5c8d939b3616ff5718653ad3cdd9e61b0393b6d934fdbab964db747bd3669b2102045616238a847d8e67fff71b0981b1e364d70bb9a63d269338c8d2efe9e3e9bda7f713de82aacc800f168c15d4575558e0598ad9a20a671159aa252a0855f362c9ff4ea30c4f4b942148d1b4101f6a516519550d6d0e2600c7c0d71dcd358cb9ad791390931805bc10fcf822b85e3fbdf8de5effb674edc4b0ffd0c1042cd8320bf6c57744df2254ca8c7192f4c298710430010564d1a21f9280e0f3406985827ef32a309a89cdab65884ae01bda7c0228830c011f4419a12806139091e81ac5c06765852680619689af17a444be2261156ba6cf34300115e5405b909114e7c007759fa6306298e4f42a24ec955c494b773dd7708dee3a3e7bfaccf969e969cf9f7e635d5ca69b8ba73f7c012600ae2083e5e188452195a3e67223923394333101385775db74dcaf565f586002d252620831bc9f1f9a3d0e46d5fdae7f663f0909fbcc7e7aab62c1a2386c0c2620215946d6a8a41f5eb80f8a565b901610e7697f409ca75b95b0052a035efd864f18a6ac575705c0567c0438e69094c1b244711f5009b155c93a47e5cd56e8b9c0ae421a95b810f57b49e802810920650a73fc16f6062665caf1c4c6ec832300c004a015cafbad508db0558b12af60b4b911bd8b105ea138e88f7e000526806d0a6e389e1026ed44b0c2681dc8e2a20a331cf1a5c40c05305e72f391c08ca29b090849bc013ef04b1212e62b3f280bb8424a5422c850acc0d60a3d0c112a1e2a0f43428a87bfe7d3e9f4f79cff791423067146bf7c44abe512969b2f85bd7aa4368fbcd28307ca95287ef5f969063a22cb0296485d59336d66cd66b3958039533e3734c39ceafad4b0cf6a090f946f11645589287f7ea85cbd4e3c2bf1e6eeeb7b085d62a6cae666681a6618c7ba97b8480be746928410cd63d3409a13d99676a65c3d302cfb5429b5efb1ec3385912a5a2825214cf9fc71565da36b58961bda8eeb292a501ea33cc2edd8d6a4bca6058cd0a952e52355194cd5e23a75a62b934fed99afbc7e9c17cb28c3a2f8b1287d3dac307dba72c4f2f9ca6bfef8583c0d2cc498aeec9936b3a510e3b1781a5888d59936fef851a6cbde1762b742c6ed346ea7713b0db69d6ab5f89a47ddadb26b7a04e773745f6597cda165231dea733b765d0f86a166cdc3c88b9c589f3b9ae318de9952153164486168596490a129a1f4b8da7ebafd7ba43631c0f18080eba6af38c7c302a78f1d6b36416dccba5be2ffcaa23da952e55bfc9fddc0e6a1ae43cdbbefc064f3b9a57ba66969aeae858993200435145bb11b6a8e8674cd9b0f3430be6eff7b53fd5ec3366ae5a8959f9e567eea4ee053efdf1d9c94e12b62b6df7552a2b8873990ab2acd41bbc647cdc1c7d42e735a47fe07e1a9f9d8ea9c2cfe6f06fba9abeca7debf3b6c29d357c46c1f4b076933ab8796c9d5356b2d6bd7faa896bde38960e244ae796f4f249b87d07023c743b6e39aeedcd093d08b901dcd7557b7a06eb8ce197722a652b7fa1baeaeed2be6f1d5357baeae3cabc9d56d4f6e4757f72f3d85d6479b426b6f0aadbfef143a1f6d0a9dbd2974fe16532812f7970b4c951f5f286b489514e5a814c9fe35660be5ea854cf8ff283e8e0e202524cd102c3055f7fb7f36537e4648b98a49542d51ce04b7731ac48343443001928d0820033e68e75ebbd474dfb27c73fe92b31e62220eeb38979ae66bae6fbbbc4ecdbb7eb0ca1295a9ac925759260b827a5d02ba80c007a11179b1a9b96e3cd73d1db9da5c4b60147ba66b23d37223184791ad3906a75729c5698e5083d63c53e05fbde2a4d01f15a2bcdb25e28c0da71ffdab1dc5bb5b47c9ecda96a16bee3eaffb93f3ef5f9f67d19b5fb4676fbe595f9c7f714f5eb7526bf41ebcee5e7f3f4ce5ee553d89c1ddb5bc3f69fb0e461f9eb603d68b9aede00cc7c67641fb12b01dac5339d74ed3d369d64ee36198d5bddebc874cfd855fb7388d4ddddbd10cc1a5dce6190c5156ef6c713dc39a3b8eab69debcbb91ff75deb968e39e9f9f9f3ff99afd6c929f6edb7ab75e48a9c5abb062447ee37f6668fce085f394df51814b3eb0eef7caeedb8864a4043e4031ffc3efeda00456199383e6cfad56d5668ecfc31267883292b7962f2e61b26b53dbd35bd6eaee3798a4dfac35522c162fb85d1b4e942015645fc420121af4ad5a5f18ba01f51c0d3084dd75a4ee18f855a48aa2bee00d8cea1aa1673b46e4b928b46cddb22ccff4e2c8d32ddd4089ee5908e9ba11f22b510b0463718f89ab25f0415e2cfd7dd8e9342c611e2d109d4e9710e762ce13e0835babd50efa84ce1c5eaaca8ba574b58e3677e786b6ef6bbfd95c5c7b9b97c6b715fcb558c4df65abf0cd6febe76f53f3d99bf37bfb5d29aa87e3adbb7debadbc535d2d5ff97bfbd85de33ece95a3f4f2aa1c6038772ad0fafa510e72aa03e56d4ef79cbcd5302eb396ff1e5f79d19981936f20f151f12d28e25b53330dd3d1f5eeb67b115ca7d231ae77eeeab845e24a5a6559b0abf41ed3c5ef8df209e11732a55312ca311a83d1188cc6e04f3306f7bd580e0ee25070aef0095212522a0c5186f3b4bdca58b7502862bc982a2457a092e11552bec3ecfb2a142d678a489260aae48429306215ccb28d223a4f17fc6a64be592f508966622b94d7ad19e9155149b0be7199c00013708d367da138c496ff2b775b44b20c86a4848cdc66376ec5dec3daee3d7251e208d553447d0c9b800521bd675560b46f09dc65bbdc353a6fb6e52efa1f04bddd9a6ddea927608bb3551be3ddc4e03d911b98adfc9f587f98f65e7e282c6b9891b02f548a992a70b62a5dc0da6fb160803e72600eb3875ba264085c0ed3e2b2b2bf0688ce96420324ead047c9adc4cd609e5630ed0ddce2c85021856f6f8d78eed25b09244c62ce4a1c568358c41dd42e240907e8f00ee920d41906b890ee7e98cc8e44d9db11c32073fd3d441f28d3722c8953bb8a615245d2571ccf158923c410dac761d4ed3f0ac816726e381dd67f6a04a9b60d214537b3d96ccbb340370de1d2b7df3508f77365b4c0abbebddd363009299790892342c23b1b93759e1118f7ed6f8bd368c83061445723445e7188dc6417b4cdeaf65eb016a80b9f1386131cdde5ec74ab843daced5714e7119ac02c9b14b06438c205e4c17fed67787abcb793e1205b95e71dea43557d19a9276c03b355ebe03b464546364318ab0ed21186d5986aeed4f02ef5b96f6abe719461b5a79a35d5ac4bcdf20dd7379d9742ebf8d9a85bc5981af34bddf535dbd7cc97d294d75d4f31bbebf18e0f8dbb2dbad8b57dbc6be9dfda32ca487e68164e92bc3af493773d962ec81215304575fa86e2b708f8aee5d9da5e3412912a67c0772760cd5f45de2f6a2218e0837fc215fc59b85b0e0d6950effce615625e5294e40d8ad85ed9cee0740ad7f81aef35144152738c15cd308d2a4a456aa329af8fa7b2733ab709654964924b92dcb5f56cdf6b8e318561c69f9b445b8172d9f106489b800c4728a73baa9c278bb805bee63c9484c23468ae3ab4686b14b6fc3c4e7392240167e170d991c8488123cec0356943f06a025698e21067986dba5989fae8cc47d6e9a6e860b332624d240b16d4a715e003c140dcf0372af9ba1ff01b7b2cc61e5771d7ebda235731a627c7f4e49f9d9e1cb98ad1188cc6603406235731721523573172152357317215235731721523573172152357317215235731721523573172157f15ae22c870ce11b680a22ce19f8b9aa3e86586c56fdfca04c911cc3b69e3ee97826fa4df19a0779d9fe6bdd985528302ef5eb2b979e765a421e7f703720613f36ef476d306cd838f05d743698e5603e09ffe7212df12b0620b5206905212612833745f5f3cbf7cf1c3935f2e2f5e00518504228e6b0d40c4780cc67fcf392811a4cdab70cd0bc5ede6168fdcc234df97888799dd92b64ad0fc5e74955fe7649def5e4f0e374de59d6ae947d44d9b88adce20ce511944300f9624c6c9e6f03d3cd11ac631ae33c3be6e69dc6a64483e1be604440b9873d9090f87f8af85dffc17e32d7613815c0000"],"rawHeaders":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","cache-control":"private, max-age=60, s-maxage=60","content-encoding":"gzip","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Tue, 22 Jul 2025 21:22:55 GMT","etag":"W/\"26420892d5243dd7239746568a6d115d69f584cc33dbf79cf7d67b967a94c763\"","github-authentication-token-expiration":"2025-08-21 21:15:02 UTC","last-modified":"Sun, 26 Nov 2023 00:08:58 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","transfer-encoding":"chunked","vary":"Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With","x-accepted-oauth-scopes":"","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"FC58:28958:7361E4:78ABC2:6880012E","x-oauth-scopes":"admin:gpg_key, admin:ssh_signing_key, audit_log, codespace, copilot, delete:packages, gist, notifications, project, repo, user, workflow, write:discussion, write:network_configurations, write:packages","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4886","x-ratelimit-reset":"1753220116","x-ratelimit-resource":"core","x-ratelimit-used":"114","x-xss-protection":"0"},"responseIsBinary":false},{"scope":"https://raw.githubusercontent.com:443","method":"GET","path":"/wiki/npm/npm-cli-release-please/Release-Process.md","body":"","status":404,"response":"404: Not Found","rawHeaders":{"accept-ranges":"bytes","access-control-allow-origin":"*","connection":"keep-alive","content-length":"14","content-security-policy":"default-src 'none'; style-src 'unsafe-inline'; sandbox","content-type":"text/plain; charset=utf-8","cross-origin-resource-policy":"cross-origin","date":"Tue, 22 Jul 2025 21:22:55 GMT","expires":"Tue, 22 Jul 2025 21:27:55 GMT","source-age":"39","strict-transport-security":"max-age=31536000","vary":"Authorization,Accept-Encoding","via":"1.1 varnish","x-cache":"HIT","x-cache-hits":"2","x-content-type-options":"nosniff","x-fastly-request-id":"e9936a38cdd400d88e2e519fb2d58f71fa9cf278","x-frame-options":"deny","x-github-request-id":"B7B7:EFF99:1264B9:1760DC:68800106","x-served-by":"cache-bfi-krnt7300104-BFI","x-timer":"S1753219375.393753,VS0,VE0","x-xss-protection":"1; mode=block"},"responseIsBinary":false}]
Loading
Loading