@@ -157,31 +157,47 @@ export async function pnpmFix(
157157 continue
158158 }
159159
160- const failedSpecs = new Set < string > ( )
161160 const fixedSpecs = new Set < string > ( )
162- const installedSpecs = new Set < string > ( )
163- const testedSpecs = new Set < string > ( )
164- const unavailableSpecs = new Set < string > ( )
165- const revertedSpecs = new Set < string > ( )
166161
167162 for ( const pkgJsonPath of pkgJsonPaths ) {
163+ // Re-read actualTree to avoid lockfile state issues
164+ // eslint-disable-next-line no-await-in-loop
165+ actualTree = await getActualTree ( cwd )
166+
167+ const pkgPath = path . dirname ( pkgJsonPath )
168+ const isWorkspaceRoot =
169+ pkgJsonPath === pkgEnvDetails . editablePkgJson . filename
170+ const workspaceName = isWorkspaceRoot
171+ ? 'root'
172+ : path . relative ( rootPath , pkgPath )
173+
174+ const editablePkgJson = isWorkspaceRoot
175+ ? pkgEnvDetails . editablePkgJson
176+ : // eslint-disable-next-line no-await-in-loop
177+ await readPackageJson ( pkgJsonPath , { editable : true } )
178+
179+ // Get current overrides for revert logic
180+ const oldPnpmSection = editablePkgJson . content [ PNPM ] as
181+ | StringKeyValueObject
182+ | undefined
183+ const oldOverrides = oldPnpmSection ?. [ OVERRIDES ] as
184+ | Record < string , string >
185+ | undefined
186+
168187 for ( const oldVersion of oldVersions ) {
169188 const oldSpec = `${ name } @${ oldVersion } `
170189 const oldPurl = `pkg:npm/${ oldSpec } `
171190
191+ const node = findPackageNode ( actualTree , name , oldVersion )
192+ if ( ! node ) {
193+ debugLog ( `Skipping ${ oldSpec } , no node found in ${ pkgJsonPath } ` )
194+ continue
195+ }
196+
172197 for ( const {
173198 firstPatchedVersionIdentifier,
174199 vulnerableVersionRange
175200 } of infos ) {
176- const node = findPackageNode ( actualTree , name , oldVersion )
177- if ( ! node ) {
178- debugLog (
179- `Skipping ${ oldSpec } , no node found in arborist.actualTree` ,
180- pkgJsonPath
181- )
182- continue
183- }
184-
185201 const availableVersions = Object . keys ( packument . versions )
186202 const newVersion = findBestPatchVersion (
187203 node ,
@@ -194,99 +210,65 @@ export async function pnpmFix(
194210 : undefined
195211
196212 if ( ! ( newVersion && newVersionPackument ) ) {
197- if ( ! unavailableSpecs . has ( oldSpec ) ) {
198- unavailableSpecs . add ( oldSpec )
199- spinner ?. fail ( `No update available for ${ oldSpec } ` )
200- }
213+ spinner ?. fail ( `No update available for ${ oldSpec } ` )
201214 continue
202215 }
203216
204- const isWorkspaceRoot =
205- pkgJsonPath === pkgEnvDetails . editablePkgJson . filename
206- const workspaceName = isWorkspaceRoot
207- ? ''
208- : path . relative ( rootPath , path . dirname ( pkgJsonPath ) )
209- const workspaceDetails = workspaceName ? ` in ${ workspaceName } ` : ''
210- const editablePkgJson = isWorkspaceRoot
211- ? pkgEnvDetails . editablePkgJson
212- : // eslint-disable-next-line no-await-in-loop
213- await readPackageJson ( pkgJsonPath , { editable : true } )
214-
215- const oldPnpm = editablePkgJson . content [ PNPM ] as
216- | StringKeyValueObject
217- | undefined
218- const oldPnpmKeyCount = oldPnpm ? Object . keys ( oldPnpm ) . length : 0
219- const oldOverrides = ( oldPnpm as StringKeyValueObject ) ?. [ OVERRIDES ] as
220- | Record < string , string >
221- | undefined
222- const oldOverridesCount = oldOverrides
223- ? Object . keys ( oldOverrides ) . length
224- : 0
225-
226217 const overrideKey = `${ name } @${ vulnerableVersionRange } `
227218 const newVersionRange = applyRange (
228219 oldOverrides ?. [ overrideKey ] ?? oldVersion ,
229220 newVersion ,
230221 rangeStyle
231222 )
232223 const newSpec = `${ name } @${ newVersionRange } `
233- const newSpecKey = `${ workspaceName ? `${ workspaceName } >` : '' } ${ newSpec } `
224+ const newSpecKey = `${ workspaceName } :${ newSpec } `
225+
226+ if ( fixedSpecs . has ( newSpecKey ) ) {
227+ debugLog ( `Already fixed ${ newSpec } in ${ workspaceName } , skipping` )
228+ continue
229+ }
234230
235231 const updateData = isWorkspaceRoot
236- ? {
232+ ? ( {
237233 [ PNPM ] : {
238- ...oldPnpm ,
234+ ...oldPnpmSection ,
239235 [ OVERRIDES ] : {
240- [ overrideKey ] : newVersionRange ,
241- ... oldOverrides
236+ ... oldOverrides ,
237+ [ overrideKey ] : newVersionRange
242238 }
243239 }
244- }
240+ } as PackageJson )
245241 : undefined
246242
247243 const revertData = {
248244 ...( isWorkspaceRoot
249245 ? {
250- [ PNPM ] : oldPnpmKeyCount
251- ? {
252- ...oldPnpm ,
253- [ OVERRIDES ] :
254- oldOverridesCount === 1
255- ? undefined
256- : {
257- [ overrideKey ] : undefined ,
258- ...oldOverrides
259- }
260- }
261- : undefined
246+ [ PNPM ] : {
247+ ...oldPnpmSection ,
248+ [ OVERRIDES ] :
249+ oldOverrides && Object . keys ( oldOverrides ) . length > 1
250+ ? {
251+ ...oldOverrides ,
252+ [ overrideKey ] : undefined
253+ }
254+ : undefined
255+ }
262256 }
263257 : { } ) ,
264- ...( editablePkgJson . content . dependencies
265- ? { dependencies : editablePkgJson . content . dependencies }
266- : undefined ) ,
267- ...( editablePkgJson . content . optionalDependencies
268- ? {
269- optionalDependencies :
270- editablePkgJson . content . optionalDependencies
271- }
272- : undefined ) ,
273- ...( editablePkgJson . content . peerDependencies
274- ? { peerDependencies : editablePkgJson . content . peerDependencies }
275- : undefined )
258+ ...( editablePkgJson . content . dependencies && {
259+ dependencies : editablePkgJson . content . dependencies
260+ } ) ,
261+ ...( editablePkgJson . content . optionalDependencies && {
262+ optionalDependencies : editablePkgJson . content . optionalDependencies
263+ } ) ,
264+ ...( editablePkgJson . content . peerDependencies && {
265+ peerDependencies : editablePkgJson . content . peerDependencies
266+ } )
276267 } as PackageJson
277268
278- const branch = isCi
279- ? getSocketBranchName ( oldPurl , newVersion , workspaceName )
280- : ''
281- const shouldOpenPr = isCi
282- ? // eslint-disable-next-line no-await-in-loop
283- ! ( await doesPullRequestExistForBranch ( owner , repo , branch ) )
284- : false
285-
286269 if ( updateData ) {
287270 editablePkgJson . update ( updateData )
288271 }
289-
290272 const modded = updatePackageJsonFromNode (
291273 editablePkgJson ,
292274 actualTree ,
@@ -296,104 +278,98 @@ export async function pnpmFix(
296278 )
297279 debugLog ( `Updated package.json from node: ${ modded } ` )
298280
299- let error : unknown
300- let errored = false
301- let installed = false
302-
303281 // eslint-disable-next-line no-await-in-loop
304282 if ( ! ( await editablePkgJson . save ( ) ) ) {
305- debugLog ( `Skipping nothing changed in ${ editablePkgJson . filename } ` )
283+ debugLog ( `No changes saved for ${ pkgJsonPath } , skipping install ` )
306284 continue
307285 }
308286
309- if ( ! installedSpecs . has ( newSpecKey ) ) {
310- installedSpecs . add ( newSpecKey )
311- spinner ?. info ( `Installing ${ newSpec } ${ workspaceDetails } ` )
312- }
287+ spinner ?. info ( `Installing ${ newSpec } in ${ workspaceName } ` )
288+
289+ let errored = false
290+ let error : unknown
313291
314292 try {
315293 // eslint-disable-next-line no-await-in-loop
316294 actualTree = await install ( pkgEnvDetails , { spinner } )
317- installed = true
318295
319296 if ( test ) {
320- if ( ! testedSpecs . has ( newSpecKey ) ) {
321- testedSpecs . add ( newSpecKey )
322- spinner ?. info ( `Testing ${ newSpec } ${ workspaceDetails } ` )
323- }
297+ spinner ?. info ( `Testing ${ newSpec } in ${ workspaceName } ` )
324298 // eslint-disable-next-line no-await-in-loop
325299 await runScript ( testScript , [ ] , { spinner, stdio : 'ignore' } )
326300 }
327- if ( ! fixedSpecs . has ( newSpecKey ) ) {
328- fixedSpecs . add ( newSpecKey )
329- spinner ?. successAndStop ( `Fixed ${ name } ${ workspaceDetails } ` )
330- spinner ?. start ( )
331- }
332- } catch ( e ) {
333- error = e
334- errored = true
335- }
336301
337- if (
338- ! errored &&
339- shouldOpenPr &&
340- // eslint-disable-next-line no-await-in-loop
341- ( await gitCreateAndPushBranchIfNeeded (
342- branch ,
343- getSocketCommitMessage ( oldPurl , newVersion , workspaceName ) ,
344- cwd
345- ) )
346- ) {
347- // eslint-disable-next-line no-await-in-loop
348- const prResponse = await openGitHubPullRequest (
349- owner ,
350- repo ,
351- baseBranch ,
352- branch ,
302+ fixedSpecs . add ( newSpecKey )
303+ spinner ?. successAndStop ( `Fixed ${ name } in ${ workspaceName } ` )
304+ spinner ?. start ( )
305+
306+ const branch = getSocketBranchName (
353307 oldPurl ,
354308 newVersion ,
355- {
356- cwd,
357- workspaceName
358- }
309+ workspaceName
359310 )
360- if ( prResponse ) {
361- const { data } = prResponse
362- spinner ?. info ( `PR #${ data . number } opened.` )
363- if ( autoMerge ) {
364- // eslint-disable-next-line no-await-in-loop
365- await enableAutoMerge ( data )
311+ const shouldOpenPr = isCi
312+ ? // eslint-disable-next-line no-await-in-loop
313+ ! ( await doesPullRequestExistForBranch ( owner , repo , branch ) )
314+ : false
315+
316+ if (
317+ isCi &&
318+ shouldOpenPr &&
319+ // eslint-disable-next-line no-await-in-loop
320+ ( await gitCreateAndPushBranchIfNeeded (
321+ branch ,
322+ getSocketCommitMessage ( oldPurl , newVersion , workspaceName ) ,
323+ cwd
324+ ) )
325+ ) {
326+ // eslint-disable-next-line no-await-in-loop
327+ const prResponse = await openGitHubPullRequest (
328+ owner ,
329+ repo ,
330+ baseBranch ,
331+ branch ,
332+ oldPurl ,
333+ newVersion ,
334+ {
335+ cwd,
336+ workspaceName
337+ }
338+ )
339+ if ( prResponse ) {
340+ const { data } = prResponse
341+ spinner ?. info ( `PR #${ data . number } opened.` )
342+ if ( autoMerge ) {
343+ // eslint-disable-next-line no-await-in-loop
344+ await enableAutoMerge ( data )
345+ }
366346 }
367347 }
348+ } catch ( e ) {
349+ error = e
350+ errored = true
368351 }
369352
370353 if ( errored || isCi ) {
371- if ( errored ) {
372- if ( ! revertedSpecs . has ( newSpecKey ) ) {
373- revertedSpecs . add ( newSpecKey )
374- spinner ?. error ( `Reverting ${ newSpec } ${ workspaceDetails } ` , error )
375- }
376- }
377-
378354 editablePkgJson . update ( revertData )
355+
379356 // eslint-disable-next-line no-await-in-loop
380357 await Promise . all ( [
381358 removeNodeModules ( cwd ) ,
382359 ...( isCi
383360 ? [ gitCheckoutBaseBranchIfAvailable ( baseBranch , cwd ) ]
384361 : [ ] ) ,
385- ...( installed && ! isCi ? [ editablePkgJson . save ( ) ] : [ ] )
362+ ...( isCi ? [ ] : [ editablePkgJson . save ( ) ] )
386363 ] )
364+
387365 // eslint-disable-next-line no-await-in-loop
388366 actualTree = await install ( pkgEnvDetails , { spinner } )
389367
390368 if ( errored ) {
391- if ( ! failedSpecs . has ( newSpecKey ) ) {
392- failedSpecs . add ( newSpecKey )
393- spinner ?. failAndStop (
394- `Update failed for ${ oldSpec } ${ workspaceDetails } `
395- )
396- }
369+ spinner ?. failAndStop (
370+ `Update failed for ${ oldSpec } in ${ workspaceName } ` ,
371+ error
372+ )
397373 }
398374 }
399375 }
0 commit comments