Skip to content

Commit 6bc355a

Browse files
authored
fix: set package.json version from release please (#192)
1 parent c0f6c06 commit 6bc355a

File tree

5 files changed

+221
-25
lines changed

5 files changed

+221
-25
lines changed

bin/release-please.js

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ const setOutput = (key, val) => {
2020
console.log(update.updater.changelogEntry)
2121
console.log('-'.repeat(40))
2222
}
23+
for (const update of val.updates.filter(u => u.updater.rawContent)) {
24+
console.log('package:', update.path)
25+
console.log('-'.repeat(40))
26+
console.log(JSON.parse(update.updater.rawContent).name)
27+
console.log(JSON.parse(update.updater.rawContent).version)
28+
console.log('-'.repeat(40))
29+
}
2330
}
2431
} else {
2532
core.setOutput(key, JSON.stringify(val))

lib/release-please/github.js

+27-23
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,39 @@ module.exports = (gh) => {
1010
return response
1111
}
1212

13-
const { repository } = await gh.graphql(
14-
`fragment CommitAuthors on GitObject {
15-
... on Commit {
16-
authors (first:10) {
17-
nodes {
18-
user { login }
19-
name
13+
try {
14+
const { repository } = await gh.graphql(
15+
`fragment CommitAuthors on GitObject {
16+
... on Commit {
17+
authors (first:10) {
18+
nodes {
19+
user { login }
20+
name
21+
}
2022
}
2123
}
2224
}
23-
}
24-
query {
25-
repository (owner:"${owner}", name:"${repo}") {
26-
${shas.map((s) => {
27-
return `_${s}: object (expression: "${s}") { ...CommitAuthors }`
28-
})}
25+
query {
26+
repository (owner:"${owner}", name:"${repo}") {
27+
${shas.map((s) => {
28+
return `_${s}: object (expression: "${s}") { ...CommitAuthors }`
29+
})}
30+
}
31+
}`
32+
)
33+
34+
for (const [key, commit] of Object.entries(repository)) {
35+
if (commit) {
36+
response[key.slice(1)] = commit.authors.nodes
37+
.map((a) => a.user && a.user.login ? `@${a.user.login}` : a.name)
38+
.filter(Boolean)
2939
}
30-
}`
31-
)
32-
33-
for (const [key, commit] of Object.entries(repository)) {
34-
if (commit) {
35-
response[key.slice(1)] = commit.authors.nodes
36-
.map((a) => a.user && a.user.login ? `@${a.user.login}` : a.name)
37-
.filter(Boolean)
3840
}
39-
}
4041

41-
return response
42+
return response
43+
} catch {
44+
return response
45+
}
4246
}
4347

4448
const url = (...p) => `https://github.com/${owner}/${repo}/${p.join('/')}`

lib/release-please/node-workspace.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const localeCompare = require('@isaacs/string-locale-compare')('en')
12
const { NodeWorkspace } = require('release-please/build/src/plugins/node-workspace.js')
23
const { RawContent } = require('release-please/build/src/updaters/raw-content.js')
34
const { jsonStringify } = require('release-please/build/src/util/json-stringify.js')
@@ -105,9 +106,11 @@ module.exports = class extends NodeWorkspace {
105106
// except it only updates the package.json instead of appending
106107
// anything to changelogs since we've already done that in preconfigure.
107108
updateCandidate (candidate, pkg, updatedVersions) {
109+
const newVersion = updatedVersions.get(pkg.name)
108110
const graphPackage = this.packageGraph.get(pkg.name)
109-
const updatedPackage = pkg.clone()
110111

112+
const updatedPackage = pkg.clone()
113+
updatedPackage.version = newVersion.toString()
111114
for (const [depName, resolved] of graphPackage.localDependencies) {
112115
const depVersion = updatedVersions.get(depName)
113116
if (depVersion && resolved.type !== 'directory') {
@@ -160,10 +163,13 @@ module.exports = class extends NodeWorkspace {
160163
if (aPath === ROOT_PROJECT_PATH) {
161164
return -1
162165
}
166+
// release please pre sorts based on graph order so
167+
// this is never called in normal circumstances
168+
/* istanbul ignore next */
163169
if (bPath === ROOT_PROJECT_PATH) {
164170
return 1
165171
}
166-
return 0
172+
return localeCompare(aPath, bPath)
167173
})
168174
}
169175

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@actions/core": "^1.9.1",
3333
"@commitlint/cli": "^17.1.1",
3434
"@commitlint/config-conventional": "^17.1.0",
35+
"@isaacs/string-locale-compare": "^1.1.0",
3536
"@npmcli/fs": "^2.0.1",
3637
"@npmcli/git": "^3.0.0",
3738
"@npmcli/map-workspaces": "^2.0.2",

test/release-please/node-workspace.js

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
const t = require('tap')
2+
const { setLogger } = require('release-please') // this avoids a release-please cycle when testing
3+
const { Node } = require('release-please/build/src/strategies/node')
4+
const { Version } = require('release-please/build/src/version')
5+
const { TagName } = require('release-please/build/src/util/tag-name')
6+
const NodeWorkspace = require('../../lib/release-please/node-workspace')
7+
const Changelog = require('../../lib/release-please/changelog')
8+
9+
setLogger({ error () {}, warn () {}, info () {}, debug () {}, trace () {} })
10+
11+
const mockNodeWorkspace = async (workspaceNames = ['a']) => {
12+
const names = { '.': 'npm' }
13+
const versions = { '.': new Version(1, 1, 1) }
14+
15+
for (const ws of workspaceNames) {
16+
names[`workspaces/${ws}`] = `@npmcli/${ws}`
17+
versions[`workspaces/${ws}`] = new Version(2, 2, 2)
18+
}
19+
20+
const paths = Object.keys(names)
21+
22+
const github = {
23+
repository: { owner: 'npm', repo: 'cli' },
24+
getFileContentsOnBranch: (file) => {
25+
const path = file.replace(/\/?package.json$/, '') || '.'
26+
const dependencies = path === '.' ? paths.filter(p => p !== '.').reduce((acc, ws) => {
27+
acc[names[ws]] = `^${versions[ws]}`
28+
return acc
29+
}, {}) : {}
30+
return {
31+
parsedContent: JSON.stringify({
32+
name: names[path],
33+
version: versions[path].toString(),
34+
dependencies,
35+
}),
36+
}
37+
},
38+
}
39+
40+
const workspaces = (fn) => paths.reduce((acc, p) => {
41+
acc[p] = fn(p)
42+
return acc
43+
}, {})
44+
45+
return {
46+
workspaces,
47+
github,
48+
versions,
49+
paths,
50+
plugin: new NodeWorkspace(github, 'latest', workspaces(() => ({ releaseType: 'node' }))),
51+
}
52+
}
53+
54+
const mockPullRequests = async (workspace, updates = workspace.paths) => {
55+
const { workspaces, plugin, github, versions } = workspace
56+
57+
const strategiesByPath = workspaces((path) => new Node({
58+
github,
59+
path,
60+
changelogSections: [
61+
{ type: 'deps', section: 'Dependencies' },
62+
{ type: 'fix', section: 'Fixes' },
63+
],
64+
changelogNotes: new Changelog({ github }),
65+
}))
66+
67+
const commitsByPath = workspaces((path) => updates.includes(path) ? [{
68+
sha: '123',
69+
message: 'fix: stuff',
70+
files: ['package.json'],
71+
}] : [])
72+
73+
const releaseByPath = workspaces((p) => ({
74+
sha: '',
75+
notes: '',
76+
tag: new TagName(versions[p], '', '-', true),
77+
}))
78+
79+
await plugin.preconfigure(strategiesByPath, commitsByPath, releaseByPath)
80+
81+
const candidatePullRequests = []
82+
for (const [path, strategy] of Object.entries(strategiesByPath)) {
83+
const pullRequest = await strategy.buildReleasePullRequest(
84+
commitsByPath[path],
85+
releaseByPath[path]
86+
)
87+
if (pullRequest?.version) {
88+
candidatePullRequests.push({
89+
path,
90+
pullRequest,
91+
config: {
92+
releaseType: 'node',
93+
},
94+
})
95+
}
96+
}
97+
98+
const result = await plugin.run(candidatePullRequests)
99+
return result[0].pullRequest
100+
}
101+
102+
t.test('root and ws fixes', async t => {
103+
const workspace = await mockNodeWorkspace()
104+
const pullRequest = await mockPullRequests(workspace)
105+
const pkgs = pullRequest.updates
106+
.filter(u => u.updater.rawContent)
107+
.map(u => JSON.parse(u.updater.rawContent))
108+
109+
t.strictSame(pkgs, [
110+
{
111+
name: '@npmcli/a',
112+
version: '2.2.3',
113+
dependencies: {},
114+
},
115+
{
116+
name: 'npm',
117+
version: '1.1.2',
118+
dependencies: { '@npmcli/a': '^2.2.3' },
119+
},
120+
])
121+
})
122+
123+
t.test('root only', async t => {
124+
const workspace = await mockNodeWorkspace()
125+
const pullRequest = await mockPullRequests(workspace, ['.'])
126+
const pkgs = pullRequest.updates
127+
.filter(u => u.updater.rawContent)
128+
.map(u => JSON.parse(u.updater.rawContent))
129+
130+
t.strictSame(pkgs, [
131+
{
132+
name: 'npm',
133+
version: '1.1.2',
134+
dependencies: { '@npmcli/a': '^2.2.2' },
135+
},
136+
])
137+
})
138+
139+
t.test('ws only', async t => {
140+
const workspace = await mockNodeWorkspace()
141+
const pullRequest = await mockPullRequests(workspace, ['workspaces/a'])
142+
const pkgs = pullRequest.updates
143+
.filter(u => u.updater.rawContent)
144+
.map(u => JSON.parse(u.updater.rawContent))
145+
146+
t.strictSame(pkgs, [
147+
{
148+
name: '@npmcli/a',
149+
version: '2.2.3',
150+
dependencies: {},
151+
},
152+
{
153+
name: 'npm',
154+
version: '1.1.2',
155+
dependencies: { '@npmcli/a': '^2.2.3' },
156+
},
157+
])
158+
})
159+
160+
t.test('orders root to top', async t => {
161+
const ws1 = await mockNodeWorkspace(['a', 'b', 'c', 'd', 'e', 'f'])
162+
const [rootWs1] = ws1.paths.splice(0, 1)
163+
ws1.paths.push(rootWs1)
164+
const pr1 = await mockPullRequests(ws1)
165+
t.equal(pr1.body.releaseData[0].component, 'npm')
166+
167+
const ws2 = await mockNodeWorkspace(['a', '123', 'bb', 'bbb', 'bbbe', 'aaaa'])
168+
const [rootWs2] = ws2.paths.splice(0, 1)
169+
ws2.paths.splice(4, 0, rootWs2)
170+
const pr2 = await mockPullRequests(ws2)
171+
t.equal(pr2.body.releaseData[0].component, 'npm')
172+
})
173+
174+
t.test('stubbed errors', async t => {
175+
const { plugin } = await mockNodeWorkspace()
176+
t.throws(() => plugin.newCandidate())
177+
t.throws(() => plugin.bumpVersion())
178+
})

0 commit comments

Comments
 (0)