Skip to content

Commit 00bebd4

Browse files
authored
fix!: revert to semantic-release-monorepo (#1536)
`@anolilab/multi-semantic-release` does not cause semantic release to check the commits of each package before working out if anything has changed so creates unecessary comments on long-closed github issues. `semantic-release-monorepo` did not do this and has been updated to be ESM-compatible recently so switch back to that. BREAKING CHANGE: if using `aegir release` in the scripts of a monorepo package, config must be updated: 1. Change `"release": "aegir release"` in the monorepo root to `"release": "aegir run release"` 2. Add `"release": "aegir release"` to each monorepo package 3. Add semantic release config to each monorepo package
1 parent a020beb commit 00bebd4

7 files changed

+187
-148
lines changed

.aegir.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default {
1717
'playwright-test',
1818
'react-native-test-runner',
1919
'semantic-release',
20-
'@anolilab/multi-semantic-release',
20+
'semantic-release-monorepo',
2121
'source-map-support',
2222
'typedoc-plugin-mdn-links',
2323
'typedoc-plugin-missing-exports',

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@
222222
"release": "node src/index.js release --no-bundle"
223223
},
224224
"dependencies": {
225-
"@anolilab/multi-semantic-release": "^1.0.3",
226225
"@electron/get": "^3.0.0",
227226
"@polka/send-type": "^0.5.2",
228227
"@semantic-release/changelog": "^6.0.1",
@@ -263,6 +262,7 @@
263262
"eslint-plugin-promise": "^6.1.1",
264263
"execa": "^8.0.1",
265264
"extract-zip": "^2.0.1",
265+
"fast-glob": "^3.3.2",
266266
"fs-extra": "^11.1.0",
267267
"gh-pages": "^6.0.0",
268268
"globby": "^14.0.0",
@@ -283,7 +283,6 @@
283283
"micromark-extension-gfm-strikethrough": "^2.0.0",
284284
"micromark-extension-gfm-table": "^2.0.0",
285285
"micromark-extension-gfm-task-list-item": "^2.0.1",
286-
"fast-glob": "^3.3.2",
287286
"mocha": "^10.0.0",
288287
"npm-package-json-lint": "^7.0.0",
289288
"nyc": "^15.1.0",
@@ -300,6 +299,7 @@
300299
"read-pkg-up": "^11.0.0",
301300
"rimraf": "^5.0.0",
302301
"semantic-release": "^23.0.0",
302+
"semantic-release-monorepo": "^8.0.2",
303303
"semver": "^7.3.8",
304304
"source-map-support": "^0.5.20",
305305
"strip-bom": "^5.0.0",

src/align-versions.js

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/* eslint-disable no-console */
2+
3+
import path from 'path'
4+
import { execa } from 'execa'
5+
import fs from 'fs-extra'
6+
import Listr from 'listr'
7+
import { calculateSiblingVersion } from './check-project/utils.js'
8+
import { isMonorepoRoot, getSubprojectDirectories, pkg } from './utils.js'
9+
10+
/**
11+
* @typedef {import("./types.js").GlobalOptions} GlobalOptions
12+
* @typedef {import("./types.js").ReleaseOptions} ReleaseOptions
13+
* @typedef {import("listr").ListrTaskWrapper} Task
14+
*/
15+
16+
const tasks = new Listr([
17+
{
18+
title: 'align sibling dependency versions',
19+
enabled: () => isMonorepoRoot(),
20+
/**
21+
* @param {GlobalOptions & ReleaseOptions} ctx
22+
*/
23+
task: async (ctx) => {
24+
const rootDir = process.cwd()
25+
const workspaces = pkg.workspaces
26+
27+
if (!workspaces || !Array.isArray(workspaces)) {
28+
throw new Error('No monorepo workspaces found')
29+
}
30+
31+
const {
32+
siblingVersions,
33+
packageDirs
34+
} = await calculateSiblingVersions(rootDir, workspaces)
35+
36+
// check these dependency types for monorepo siblings
37+
const dependencyTypes = [
38+
'dependencies',
39+
'devDependencies',
40+
'peerDependencies',
41+
'optionalDependencies'
42+
]
43+
44+
// align the versions of siblings in each package
45+
for (const packageDir of packageDirs) {
46+
const manifestPath = path.join(packageDir, 'package.json')
47+
const manifest = fs.readJSONSync(path.join(packageDir, 'package.json'))
48+
49+
for (const type of dependencyTypes) {
50+
for (const [dep, version] of Object.entries(siblingVersions)) {
51+
if (manifest[type] != null && manifest[type][dep] != null && manifest[type][dep] !== version) {
52+
console.info('Update', type, dep, manifest[type][dep], '->', version) // eslint-disable-line no-console
53+
manifest[type][dep] = version
54+
}
55+
}
56+
}
57+
58+
fs.writeJSONSync(manifestPath, manifest, {
59+
spaces: 2
60+
})
61+
}
62+
63+
// all done, commit changes and push to remote
64+
const status = await execa('git', ['status', '--porcelain'], {
65+
cwd: rootDir
66+
})
67+
68+
if (status.stdout === '') {
69+
// no changes, nothing to do
70+
return
71+
}
72+
73+
if (!process.env.CI) {
74+
console.info('CI env var is not set, not pushing to git') // eslint-disable-line no-console
75+
return
76+
}
77+
78+
// When running on CI, set the commits author and commiter info and prevent the `git` CLI to prompt for username/password.
79+
// Borrowed from `semantic-release`
80+
process.env.GIT_AUTHOR_NAME = ctx.siblingDepUpdateName
81+
process.env.GIT_AUTHOR_EMAIL = ctx.siblingDepUpdateEmail
82+
process.env.GIT_COMMITTER_NAME = ctx.siblingDepUpdateName
83+
process.env.GIT_COMMITTER_EMAIL = ctx.siblingDepUpdateEmail
84+
process.env.GIT_ASKPASS = 'echo'
85+
process.env.GIT_TERMINAL_PROMPT = '0'
86+
87+
console.info(`Commit with message "${ctx.siblingDepUpdateMessage}"`) // eslint-disable-line no-console
88+
89+
await execa('git', ['add', '-A'], {
90+
cwd: rootDir
91+
})
92+
await execa('git', ['commit', '-m', ctx.siblingDepUpdateMessage], {
93+
cwd: rootDir
94+
})
95+
console.info('Push to remote') // eslint-disable-line no-console
96+
await execa('git', ['push'], {
97+
cwd: rootDir
98+
})
99+
}
100+
}
101+
], { renderer: 'verbose' })
102+
103+
/**
104+
* @param {string} rootDir
105+
* @param {string[]} workspaces
106+
*/
107+
async function calculateSiblingVersions (rootDir, workspaces) {
108+
const packageDirs = []
109+
110+
/** @type {Record<string, string>} */
111+
const siblingVersions = {}
112+
113+
for (const subProjectDir of await getSubprojectDirectories(rootDir, workspaces)) {
114+
const pkg = JSON.parse(fs.readFileSync(path.join(subProjectDir, 'package.json'), {
115+
encoding: 'utf-8'
116+
}))
117+
118+
siblingVersions[pkg.name] = calculateSiblingVersion(pkg.version)
119+
packageDirs.push(subProjectDir)
120+
}
121+
122+
return {
123+
packageDirs,
124+
siblingVersions
125+
}
126+
}
127+
128+
export default tasks

src/cmds/align-versions.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import alignVersions from '../align-versions.js'
2+
import { loadUserConfig } from '../config/user.js'
3+
4+
/**
5+
* @typedef {import("yargs").Argv} Argv
6+
* @typedef {import("yargs").Arguments} Arguments
7+
* @typedef {import("yargs").CommandModule} CommandModule
8+
*/
9+
10+
/** @type {CommandModule} */
11+
export default {
12+
command: 'align-versions',
13+
describe: 'Align monorepo sibling dependency versions',
14+
/**
15+
* @param {Argv} yargs
16+
*/
17+
builder: async (yargs) => {
18+
const userConfig = await loadUserConfig()
19+
20+
return yargs
21+
.options({
22+
siblingDepUpdateMessage: {
23+
alias: 'm',
24+
type: 'string',
25+
describe: 'The commit message to use when updating sibling dependencies',
26+
default: userConfig.release.siblingDepUpdateMessage
27+
},
28+
siblingDepUpdateName: {
29+
type: 'string',
30+
describe: 'The user name to use when updating sibling dependencies',
31+
default: userConfig.release.siblingDepUpdateName
32+
},
33+
siblingDepUpdateEmail: {
34+
type: 'string',
35+
describe: 'The email to use when updating sibling dependencies',
36+
default: userConfig.release.siblingDepUpdateEmail
37+
}
38+
})
39+
},
40+
/**
41+
* @param {any} argv
42+
*/
43+
async handler (argv) {
44+
await alignVersions.run(argv)
45+
}
46+
}

src/cmds/release.js

+1-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { loadUserConfig } from '../config/user.js'
21
import releaseCmd from '../release.js'
32

43
/**
@@ -19,28 +18,9 @@ export default {
1918
* @param {Argv} yargs
2019
*/
2120
builder: async (yargs) => {
22-
const userConfig = await loadUserConfig()
23-
2421
return yargs
2522
.epilog(EPILOG)
26-
.options({
27-
siblingDepUpdateMessage: {
28-
alias: 'm',
29-
type: 'string',
30-
describe: 'The commit message to use when updating sibling dependencies',
31-
default: userConfig.release.siblingDepUpdateMessage
32-
},
33-
siblingDepUpdateName: {
34-
type: 'string',
35-
describe: 'The user name to use when updating sibling dependencies',
36-
default: userConfig.release.siblingDepUpdateName
37-
},
38-
siblingDepUpdateEmail: {
39-
type: 'string',
40-
describe: 'The email to use when updating sibling dependencies',
41-
default: userConfig.release.siblingDepUpdateEmail
42-
}
43-
})
23+
.options({})
4424
},
4525
/**
4626
* @param {any} argv

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import { readPackageUpSync } from 'read-pkg-up'
55
import yargs from 'yargs'
66
import { hideBin } from 'yargs/helpers'
7+
import alignVersionsCmd from './cmds/align-versions.js'
78
import buildCmd from './cmds/build.js'
89
import checkProjectCmd from './cmds/check-project.js'
910
import checkCmd from './cmds/check.js'
@@ -92,6 +93,7 @@ async function main () {
9293
res.command(testCmd)
9394
res.command(execCmd)
9495
res.command(runCmd)
96+
res.command(alignVersionsCmd)
9597

9698
try {
9799
await res.parse()

0 commit comments

Comments
 (0)