Skip to content

Commit 505ada6

Browse files
authoredFeb 6, 2024
fix: update patch deps during check-project (#1460)
To ensure people with lockfiles get the latest version of deps, update patch versions during `check-project`.
1 parent 72d2fcd commit 505ada6

File tree

2 files changed

+40
-30
lines changed

2 files changed

+40
-30
lines changed
 

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@
268268
"globby": "^14.0.0",
269269
"is-plain-obj": "^4.1.0",
270270
"kleur": "^4.1.4",
271+
"latest-version": "^8.0.0",
271272
"lilconfig": "^3.0.0",
272273
"listr": "~0.14.2",
273274
"mdast-util-from-markdown": "^2.0.0",

‎src/check-project/index.js

+39-30
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from 'path'
44
import { fileURLToPath } from 'url'
55
import { execa } from 'execa'
66
import fs from 'fs-extra'
7+
import latestVersion from 'latest-version'
78
import Listr from 'listr'
89
import prompt from 'prompt'
910
import semver from 'semver'
@@ -161,38 +162,33 @@ async function processMonorepo (projectDir, manifest, branchName, repoUrl, ciFil
161162
* @param {string[]} projectDirs
162163
*/
163164
async function alignMonorepoProjectDependencies (projectDirs) {
164-
console.info('Align monorepo project dependencies')
165-
166165
/** @type {Record<string, string>} */
167166
const siblingVersions = {}
168167
/** @type {Record<string, string>} */
169168
const deps = {}
170-
/** @type {Record<string, string>} */
171-
const devDeps = {}
172-
/** @type {Record<string, string>} */
173-
const optionalDeps = {}
174-
/** @type {Record<string, string>} */
175-
const peerDeps = {}
176169

177170
// first loop over every project and choose the most recent version of a given dep
178171
for (const projectDir of projectDirs) {
179172
const pkg = fs.readJSONSync(path.join(projectDir, 'package.json'))
180173
siblingVersions[pkg.name] = calculateSiblingVersion(pkg.version)
181174

182-
chooseVersions(pkg.dependencies || {}, deps)
183-
chooseVersions(pkg.devDependencies || {}, devDeps)
184-
chooseVersions(pkg.optionalDependencies || {}, optionalDeps)
185-
chooseVersions(pkg.peerDependencies || {}, peerDeps)
175+
chooseVersions(pkg.dependencies ?? {}, deps)
176+
chooseVersions(pkg.devDependencies ?? {}, deps)
177+
chooseVersions(pkg.optionalDependencies ?? {}, deps)
178+
chooseVersions(pkg.peerDependencies ?? {}, deps)
186179
}
187180

181+
// get the latest patch release of every dep from npm
182+
await findLatestVersions(deps)
183+
188184
// now propose the most recent version of a dep for all projects
189185
for (const projectDir of projectDirs) {
190186
const pkg = fs.readJSONSync(path.join(projectDir, 'package.json'))
191187

192-
selectVersions(pkg.dependencies || {}, deps, siblingVersions)
193-
selectVersions(pkg.devDependencies || {}, devDeps, siblingVersions)
194-
selectVersions(pkg.optionalDependencies || {}, optionalDeps, siblingVersions)
195-
selectVersions(pkg.peerDependencies || {}, peerDeps, siblingVersions)
188+
selectVersions(pkg.dependencies ?? {}, deps, siblingVersions)
189+
selectVersions(pkg.devDependencies ?? {}, deps, siblingVersions)
190+
selectVersions(pkg.optionalDependencies ?? {}, deps, siblingVersions)
191+
selectVersions(pkg.peerDependencies ?? {}, deps, siblingVersions)
196192

197193
await ensureFileHasContents(projectDir, 'package.json', JSON.stringify(pkg, null, 2))
198194
}
@@ -203,37 +199,50 @@ async function alignMonorepoProjectDependencies (projectDirs) {
203199
* @param {Record<string, string>} list
204200
*/
205201
function chooseVersions (deps, list) {
206-
Object.entries(deps).forEach(([key, value]) => {
202+
for (const [dep, version] of Object.entries(deps)) {
207203
// not seen this dep before
208-
if (!list[key]) {
209-
list[key] = value
210-
return
204+
if (list[dep] == null) {
205+
list[dep] = version
206+
continue
207+
}
208+
209+
// test for later version
210+
if (semver.gt(version.replace(/\^|~/, ''), list[dep].replace(/\^|~/, ''))) {
211+
list[dep] = version
211212
}
213+
}
214+
}
212215

213-
const existingVersion = semver.minVersion(list[key])
214-
const moduleVersion = semver.minVersion(value)
216+
/**
217+
* @param {Record<string, string>} deps
218+
*/
219+
async function findLatestVersions (deps) {
220+
// find the latest semver-compatible release from npm
221+
for (const [key, value] of Object.entries(deps)) {
222+
try {
223+
const npmVersion = `^${await latestVersion(key, { version: value })}`
215224

216-
// take the most recent range or version
217-
const res = semver.compare(existingVersion ?? '0.0.0', moduleVersion ?? '0.0.0')
225+
console.info(key, 'local version:', value, 'npm version:', npmVersion)
218226

219-
if (res === -1) {
220-
list[key] = value
227+
deps[key] = npmVersion
228+
} catch (err) {
229+
console.error(`Could not load latest npm version of "${key}"`, err)
221230
}
222-
})
231+
}
223232
}
224233

225234
/**
226235
* @param {Record<string, string>} deps
227236
* @param {Record<string, string>} list
228237
* @param {Record<string, string>} siblingVersions
229238
*/
230-
function selectVersions (deps, list, siblingVersions) {
239+
async function selectVersions (deps, list, siblingVersions) {
231240
// release-please updates sibling versions to the latest patch releases but
232241
// we try to update to the latest minor so skip that if release please is
233242
// in use
234243
const ignoreSiblingDeps = usesReleasePlease()
235244

236-
Object.entries(list).forEach(([key, value]) => {
245+
for (const [key, value] of Object.entries(list)) {
237246
if (deps[key] != null) {
238247
if (siblingVersions[key] != null && !ignoreSiblingDeps) {
239248
// take sibling version if available
@@ -243,7 +252,7 @@ function selectVersions (deps, list, siblingVersions) {
243252
deps[key] = value
244253
}
245254
}
246-
})
255+
}
247256
}
248257

249258
/**

0 commit comments

Comments
 (0)