Skip to content

Commit 7f464f4

Browse files
feat: add --ecosystems flag to apply and rollback commands (#29)
Adds ecosystem filtering to restrict patching/rollback to specific ecosystems (npm, pypi). Also updates the default npm postinstall command to include --ecosystems npm for scoped patching. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7b8f849 commit 7f464f4

4 files changed

Lines changed: 42 additions & 14 deletions

File tree

src/commands/apply.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ interface ApplyArgs {
3636
offline: boolean
3737
global: boolean
3838
'global-prefix'?: string
39+
ecosystems?: string[]
3940
}
4041

4142
async function applyPatches(
@@ -46,6 +47,7 @@ async function applyPatches(
4647
offline: boolean,
4748
useGlobal: boolean,
4849
globalPrefix?: string,
50+
ecosystems?: string[],
4951
): Promise<{ success: boolean; results: ApplyResult[] }> {
5052
// Read and parse manifest
5153
const manifestContent = await fs.readFile(manifestPath, 'utf-8')
@@ -102,8 +104,14 @@ async function applyPatches(
102104

103105
// Partition manifest PURLs by ecosystem
104106
const manifestPurls = Object.keys(manifest.patches)
105-
const npmPurls = manifestPurls.filter(p => isNpmPurl(p))
106-
const pypiPurls = manifestPurls.filter(p => isPyPIPurl(p))
107+
let npmPurls = manifestPurls.filter(p => isNpmPurl(p))
108+
let pypiPurls = manifestPurls.filter(p => isPyPIPurl(p))
109+
110+
// Filter by ecosystem if specified
111+
if (ecosystems && ecosystems.length > 0) {
112+
if (!ecosystems.includes('npm')) npmPurls = []
113+
if (!ecosystems.includes('pypi')) pypiPurls = []
114+
}
107115

108116
const crawlerOptions = {
109117
cwd,
@@ -316,6 +324,11 @@ export const applyCommand: CommandModule<{}, ApplyArgs> = {
316324
describe: 'Custom path to global node_modules (overrides auto-detection, useful for yarn/pnpm)',
317325
type: 'string',
318326
})
327+
.option('ecosystems', {
328+
describe: 'Restrict patching to specific ecosystems (comma-separated)',
329+
type: 'array',
330+
choices: ['npm', 'pypi'],
331+
})
319332
.example('$0 apply', 'Apply all patches to local packages')
320333
.example('$0 apply --global', 'Apply patches to global npm packages')
321334
.example('$0 apply --global-prefix /custom/path', 'Apply patches to custom global location')
@@ -350,6 +363,7 @@ export const applyCommand: CommandModule<{}, ApplyArgs> = {
350363
argv.offline,
351364
argv.global,
352365
argv['global-prefix'],
366+
argv.ecosystems,
353367
)
354368

355369
// Print results if not silent

src/commands/rollback.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ interface RollbackArgs {
4343
org?: string
4444
'api-url'?: string
4545
'api-token'?: string
46+
ecosystems?: string[]
4647
}
4748

4849
interface PatchToRollback {
@@ -134,6 +135,7 @@ async function rollbackPatches(
134135
offline: boolean,
135136
useGlobal: boolean,
136137
globalPrefix?: string,
138+
ecosystems?: string[],
137139
): Promise<{ success: boolean; results: RollbackResult[] }> {
138140
// Read and parse manifest
139141
const manifestContent = await fs.readFile(manifestPath, 'utf-8')
@@ -214,8 +216,14 @@ async function rollbackPatches(
214216

215217
// Partition PURLs by ecosystem
216218
const rollbackPurls = patchesToRollback.map(p => p.purl)
217-
const npmPurls = rollbackPurls.filter(p => !isPyPIPurl(p))
218-
const pypiPurls = rollbackPurls.filter(p => isPyPIPurl(p))
219+
let npmPurls = rollbackPurls.filter(p => !isPyPIPurl(p))
220+
let pypiPurls = rollbackPurls.filter(p => isPyPIPurl(p))
221+
222+
// Filter by ecosystem if specified
223+
if (ecosystems && ecosystems.length > 0) {
224+
if (!ecosystems.includes('npm')) npmPurls = []
225+
if (!ecosystems.includes('pypi')) pypiPurls = []
226+
}
219227

220228
const crawlerOptions = { cwd, global: useGlobal, globalPrefix }
221229
const allPackages = new Map<string, string>()
@@ -374,6 +382,11 @@ export const rollbackCommand: CommandModule<{}, RollbackArgs> = {
374382
describe: 'Socket API token (overrides SOCKET_API_TOKEN env var)',
375383
type: 'string',
376384
})
385+
.option('ecosystems', {
386+
describe: 'Restrict rollback to specific ecosystems (comma-separated)',
387+
type: 'array',
388+
choices: ['npm', 'pypi'],
389+
})
377390
.example('$0 rollback', 'Rollback all patches')
378391
.example(
379392
'$0 rollback pkg:npm/lodash@4.17.21',
@@ -453,6 +466,7 @@ export const rollbackCommand: CommandModule<{}, RollbackArgs> = {
453466
argv.offline,
454467
argv.global,
455468
argv['global-prefix'],
469+
argv.ecosystems,
456470
)
457471

458472
// Print results if not silent

src/package-json/detect.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -411,19 +411,19 @@ describe('isPostinstallConfigured', () => {
411411
describe('generateUpdatedPostinstall', () => {
412412
it('should create command for empty string', () => {
413413
const result = generateUpdatedPostinstall('')
414-
assert.equal(result, 'socket patch apply --silent')
414+
assert.equal(result, 'socket patch apply --silent --ecosystems npm')
415415
})
416416

417417
it('should create command for whitespace-only string', () => {
418418
const result = generateUpdatedPostinstall(' \n\t ')
419-
assert.equal(result, 'socket patch apply --silent')
419+
assert.equal(result, 'socket patch apply --silent --ecosystems npm')
420420
})
421421

422422
it('should prepend to existing script', () => {
423423
const result = generateUpdatedPostinstall('echo "Hello"')
424424
assert.equal(
425425
result,
426-
'socket patch apply --silent && echo "Hello"',
426+
'socket patch apply --silent --ecosystems npm && echo "Hello"',
427427
)
428428
})
429429

@@ -456,7 +456,7 @@ describe('generateUpdatedPostinstall', () => {
456456
const result = generateUpdatedPostinstall(existing)
457457
assert.equal(
458458
result,
459-
'socket patch apply --silent && socket apply',
459+
'socket patch apply --silent --ecosystems npm && socket apply',
460460
'Should add socket patch apply even if socket apply is present',
461461
)
462462
})
@@ -476,7 +476,7 @@ describe('updatePackageJsonContent', () => {
476476
assert.ok(updated.scripts)
477477
assert.equal(
478478
updated.scripts.postinstall,
479-
'socket patch apply --silent',
479+
'socket patch apply --silent --ecosystems npm',
480480
)
481481
})
482482

@@ -496,7 +496,7 @@ describe('updatePackageJsonContent', () => {
496496
const updated = JSON.parse(result.content)
497497
assert.equal(
498498
updated.scripts.postinstall,
499-
'socket patch apply --silent',
499+
'socket patch apply --silent --ecosystems npm',
500500
)
501501
assert.equal(updated.scripts.test, 'jest', 'Should preserve other scripts')
502502
assert.equal(updated.scripts.build, 'tsc', 'Should preserve other scripts')
@@ -517,7 +517,7 @@ describe('updatePackageJsonContent', () => {
517517
assert.equal(result.oldScript, 'echo "Setup complete"')
518518
assert.equal(
519519
result.newScript,
520-
'socket patch apply --silent && echo "Setup complete"',
520+
'socket patch apply --silent --ecosystems npm && echo "Setup complete"',
521521
)
522522
})
523523

@@ -575,7 +575,7 @@ describe('updatePackageJsonContent', () => {
575575
const updated = JSON.parse(result.content)
576576
assert.equal(
577577
updated.scripts.postinstall,
578-
'socket patch apply --silent',
578+
'socket patch apply --silent --ecosystems npm',
579579
)
580580
})
581581

@@ -594,7 +594,7 @@ describe('updatePackageJsonContent', () => {
594594
const updated = JSON.parse(result.content)
595595
assert.equal(
596596
updated.scripts.postinstall,
597-
'socket patch apply --silent',
597+
'socket patch apply --silent --ecosystems npm',
598598
)
599599
})
600600

src/package-json/detect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
// The command to run for applying patches via socket CLI.
7-
const SOCKET_PATCH_COMMAND = 'socket patch apply --silent'
7+
const SOCKET_PATCH_COMMAND = 'socket patch apply --silent --ecosystems npm'
88

99
// Legacy command patterns to detect existing configurations.
1010
const LEGACY_PATCH_PATTERNS = [

0 commit comments

Comments
 (0)