From 6bc355a2b313bdde0fd6fe7cdf0c290ebf747af9 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 14 Sep 2022 13:10:50 -0700 Subject: [PATCH] fix: set package.json version from release please (#192) --- bin/release-please.js | 7 + lib/release-please/github.js | 50 ++++---- lib/release-please/node-workspace.js | 10 +- package.json | 1 + test/release-please/node-workspace.js | 178 ++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 25 deletions(-) create mode 100644 test/release-please/node-workspace.js diff --git a/bin/release-please.js b/bin/release-please.js index 3ee33f75..23e4e5f5 100755 --- a/bin/release-please.js +++ b/bin/release-please.js @@ -20,6 +20,13 @@ const setOutput = (key, val) => { console.log(update.updater.changelogEntry) console.log('-'.repeat(40)) } + for (const update of val.updates.filter(u => u.updater.rawContent)) { + console.log('package:', update.path) + console.log('-'.repeat(40)) + console.log(JSON.parse(update.updater.rawContent).name) + console.log(JSON.parse(update.updater.rawContent).version) + console.log('-'.repeat(40)) + } } } else { core.setOutput(key, JSON.stringify(val)) diff --git a/lib/release-please/github.js b/lib/release-please/github.js index 18c033fa..d1df4224 100644 --- a/lib/release-please/github.js +++ b/lib/release-please/github.js @@ -10,35 +10,39 @@ module.exports = (gh) => { return response } - const { repository } = await gh.graphql( - `fragment CommitAuthors on GitObject { - ... on Commit { - authors (first:10) { - nodes { - user { login } - name + try { + const { repository } = await gh.graphql( + `fragment CommitAuthors on GitObject { + ... on Commit { + authors (first:10) { + nodes { + user { login } + name + } } } } - } - query { - repository (owner:"${owner}", name:"${repo}") { - ${shas.map((s) => { - return `_${s}: object (expression: "${s}") { ...CommitAuthors }` - })} + query { + repository (owner:"${owner}", name:"${repo}") { + ${shas.map((s) => { + return `_${s}: object (expression: "${s}") { ...CommitAuthors }` + })} + } + }` + ) + + for (const [key, commit] of Object.entries(repository)) { + if (commit) { + response[key.slice(1)] = commit.authors.nodes + .map((a) => a.user && a.user.login ? `@${a.user.login}` : a.name) + .filter(Boolean) } - }` - ) - - for (const [key, commit] of Object.entries(repository)) { - if (commit) { - response[key.slice(1)] = commit.authors.nodes - .map((a) => a.user && a.user.login ? `@${a.user.login}` : a.name) - .filter(Boolean) } - } - return response + return response + } catch { + return response + } } const url = (...p) => `https://github.com/${owner}/${repo}/${p.join('/')}` diff --git a/lib/release-please/node-workspace.js b/lib/release-please/node-workspace.js index a43b0345..fb4f9503 100644 --- a/lib/release-please/node-workspace.js +++ b/lib/release-please/node-workspace.js @@ -1,3 +1,4 @@ +const localeCompare = require('@isaacs/string-locale-compare')('en') const { NodeWorkspace } = require('release-please/build/src/plugins/node-workspace.js') const { RawContent } = require('release-please/build/src/updaters/raw-content.js') const { jsonStringify } = require('release-please/build/src/util/json-stringify.js') @@ -105,9 +106,11 @@ module.exports = class extends NodeWorkspace { // except it only updates the package.json instead of appending // anything to changelogs since we've already done that in preconfigure. updateCandidate (candidate, pkg, updatedVersions) { + const newVersion = updatedVersions.get(pkg.name) const graphPackage = this.packageGraph.get(pkg.name) - const updatedPackage = pkg.clone() + const updatedPackage = pkg.clone() + updatedPackage.version = newVersion.toString() for (const [depName, resolved] of graphPackage.localDependencies) { const depVersion = updatedVersions.get(depName) if (depVersion && resolved.type !== 'directory') { @@ -160,10 +163,13 @@ module.exports = class extends NodeWorkspace { if (aPath === ROOT_PROJECT_PATH) { return -1 } + // release please pre sorts based on graph order so + // this is never called in normal circumstances + /* istanbul ignore next */ if (bPath === ROOT_PROJECT_PATH) { return 1 } - return 0 + return localeCompare(aPath, bPath) }) } diff --git a/package.json b/package.json index 108c715e..f7ff4995 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@actions/core": "^1.9.1", "@commitlint/cli": "^17.1.1", "@commitlint/config-conventional": "^17.1.0", + "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^2.0.1", "@npmcli/git": "^3.0.0", "@npmcli/map-workspaces": "^2.0.2", diff --git a/test/release-please/node-workspace.js b/test/release-please/node-workspace.js new file mode 100644 index 00000000..564e9fb0 --- /dev/null +++ b/test/release-please/node-workspace.js @@ -0,0 +1,178 @@ +const t = require('tap') +const { setLogger } = require('release-please') // this avoids a release-please cycle when testing +const { Node } = require('release-please/build/src/strategies/node') +const { Version } = require('release-please/build/src/version') +const { TagName } = require('release-please/build/src/util/tag-name') +const NodeWorkspace = require('../../lib/release-please/node-workspace') +const Changelog = require('../../lib/release-please/changelog') + +setLogger({ error () {}, warn () {}, info () {}, debug () {}, trace () {} }) + +const mockNodeWorkspace = async (workspaceNames = ['a']) => { + const names = { '.': 'npm' } + const versions = { '.': new Version(1, 1, 1) } + + for (const ws of workspaceNames) { + names[`workspaces/${ws}`] = `@npmcli/${ws}` + versions[`workspaces/${ws}`] = new Version(2, 2, 2) + } + + const paths = Object.keys(names) + + const github = { + repository: { owner: 'npm', repo: 'cli' }, + getFileContentsOnBranch: (file) => { + const path = file.replace(/\/?package.json$/, '') || '.' + const dependencies = path === '.' ? paths.filter(p => p !== '.').reduce((acc, ws) => { + acc[names[ws]] = `^${versions[ws]}` + return acc + }, {}) : {} + return { + parsedContent: JSON.stringify({ + name: names[path], + version: versions[path].toString(), + dependencies, + }), + } + }, + } + + const workspaces = (fn) => paths.reduce((acc, p) => { + acc[p] = fn(p) + return acc + }, {}) + + return { + workspaces, + github, + versions, + paths, + plugin: new NodeWorkspace(github, 'latest', workspaces(() => ({ releaseType: 'node' }))), + } +} + +const mockPullRequests = async (workspace, updates = workspace.paths) => { + const { workspaces, plugin, github, versions } = workspace + + const strategiesByPath = workspaces((path) => new Node({ + github, + path, + changelogSections: [ + { type: 'deps', section: 'Dependencies' }, + { type: 'fix', section: 'Fixes' }, + ], + changelogNotes: new Changelog({ github }), + })) + + const commitsByPath = workspaces((path) => updates.includes(path) ? [{ + sha: '123', + message: 'fix: stuff', + files: ['package.json'], + }] : []) + + const releaseByPath = workspaces((p) => ({ + sha: '', + notes: '', + tag: new TagName(versions[p], '', '-', true), + })) + + await plugin.preconfigure(strategiesByPath, commitsByPath, releaseByPath) + + const candidatePullRequests = [] + for (const [path, strategy] of Object.entries(strategiesByPath)) { + const pullRequest = await strategy.buildReleasePullRequest( + commitsByPath[path], + releaseByPath[path] + ) + if (pullRequest?.version) { + candidatePullRequests.push({ + path, + pullRequest, + config: { + releaseType: 'node', + }, + }) + } + } + + const result = await plugin.run(candidatePullRequests) + return result[0].pullRequest +} + +t.test('root and ws fixes', async t => { + const workspace = await mockNodeWorkspace() + const pullRequest = await mockPullRequests(workspace) + const pkgs = pullRequest.updates + .filter(u => u.updater.rawContent) + .map(u => JSON.parse(u.updater.rawContent)) + + t.strictSame(pkgs, [ + { + name: '@npmcli/a', + version: '2.2.3', + dependencies: {}, + }, + { + name: 'npm', + version: '1.1.2', + dependencies: { '@npmcli/a': '^2.2.3' }, + }, + ]) +}) + +t.test('root only', async t => { + const workspace = await mockNodeWorkspace() + const pullRequest = await mockPullRequests(workspace, ['.']) + const pkgs = pullRequest.updates + .filter(u => u.updater.rawContent) + .map(u => JSON.parse(u.updater.rawContent)) + + t.strictSame(pkgs, [ + { + name: 'npm', + version: '1.1.2', + dependencies: { '@npmcli/a': '^2.2.2' }, + }, + ]) +}) + +t.test('ws only', async t => { + const workspace = await mockNodeWorkspace() + const pullRequest = await mockPullRequests(workspace, ['workspaces/a']) + const pkgs = pullRequest.updates + .filter(u => u.updater.rawContent) + .map(u => JSON.parse(u.updater.rawContent)) + + t.strictSame(pkgs, [ + { + name: '@npmcli/a', + version: '2.2.3', + dependencies: {}, + }, + { + name: 'npm', + version: '1.1.2', + dependencies: { '@npmcli/a': '^2.2.3' }, + }, + ]) +}) + +t.test('orders root to top', async t => { + const ws1 = await mockNodeWorkspace(['a', 'b', 'c', 'd', 'e', 'f']) + const [rootWs1] = ws1.paths.splice(0, 1) + ws1.paths.push(rootWs1) + const pr1 = await mockPullRequests(ws1) + t.equal(pr1.body.releaseData[0].component, 'npm') + + const ws2 = await mockNodeWorkspace(['a', '123', 'bb', 'bbb', 'bbbe', 'aaaa']) + const [rootWs2] = ws2.paths.splice(0, 1) + ws2.paths.splice(4, 0, rootWs2) + const pr2 = await mockPullRequests(ws2) + t.equal(pr2.body.releaseData[0].component, 'npm') +}) + +t.test('stubbed errors', async t => { + const { plugin } = await mockNodeWorkspace() + t.throws(() => plugin.newCandidate()) + t.throws(() => plugin.bumpVersion()) +})