-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat(npm): support yarn catalogs via yarn-plugin-catalogs #37293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 52 commits
67da7b0
ab690ff
fcc0159
d436370
8ca30d5
7a53772
d1874cd
350379e
fd9bc29
4cadc5c
04cb16b
3e254ee
6cc85df
5ab19aa
72b6c13
0c261e7
8622e23
c654c2f
90437ee
bfc0732
6c77671
72849f0
3ac804d
a918957
414f8c3
7f20994
7e38f93
39dea8d
4211ea6
043fd00
9a75e30
1e69a45
adca60c
8ac44af
0046429
eb70ee3
02ca083
ff63e13
90ccad6
693b441
5f1425f
b95c58f
216b519
91c287d
3f1aadd
0bfbc90
9ee3c7b
3619d5e
bd8a66b
2a61349
91bcff6
6c50ae5
e66caec
8aef009
c681481
7adbb9f
d73cf56
bf37bad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
vi.mock('fs-extra', async () => | ||
( | ||
await vi.importActual<typeof import('~test/fixtures')>('~test/fixtures') | ||
).fsExtra(), | ||
); | ||
|
||
import { GlobalConfig } from '../../../../../config/global'; | ||
import { logger } from '../../../../../logger'; | ||
import { hasPackageManager } from './package-file'; | ||
import { Fixtures } from '~test/fixtures'; | ||
|
||
describe('modules/manager/npm/extract/common/package-file', () => { | ||
beforeEach(() => { | ||
Fixtures.reset(); | ||
GlobalConfig.set({ localDir: '/', cacheDir: '/tmp/cache' }); | ||
vitest.clearAllMocks(); | ||
MKruschke marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
}); | ||
|
||
it('returns true for a valid packageManager with name@range (e.g. [email protected])', async () => { | ||
MKruschke marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Fixtures.mock({ | ||
'/repo/package.json': JSON.stringify({ packageManager: '[email protected]' }), | ||
}); | ||
await expect(hasPackageManager('/repo')).resolves.toBe(true); | ||
|
||
expect(logger.trace).toHaveBeenCalledWith( | ||
'npm.hasPackageManager from package.json', | ||
); | ||
}); | ||
|
||
it('returns true for a valid range like npm@^9', async () => { | ||
Fixtures.mock({ | ||
'/repo/package.json': JSON.stringify({ packageManager: 'npm@^9' }), | ||
}); | ||
await expect(hasPackageManager('/repo')).resolves.toBe(true); | ||
}); | ||
|
||
it('returns true for yarn classic pin [email protected]', async () => { | ||
Fixtures.mock({ | ||
'/repo/package.json': JSON.stringify({ packageManager: '[email protected]' }), | ||
}); | ||
await expect(hasPackageManager('/repo')).resolves.toBe(true); | ||
}); | ||
|
||
it("returns false when packageManager does not contain '@' (e.g. 'npm')", async () => { | ||
Fixtures.mock({ | ||
'/repo/package.json': JSON.stringify({ packageManager: 'npm' }), | ||
}); | ||
await expect(hasPackageManager('/repo')).resolves.toBe(false); | ||
}); | ||
|
||
it('returns false when packageManager is missing', async () => { | ||
Fixtures.mock({ '/repo/package.json': JSON.stringify({ name: 'demo' }) }); | ||
await expect(hasPackageManager('/repo')).resolves.toBe(false); | ||
}); | ||
|
||
it('returns false when package.json is invalid', async () => { | ||
Fixtures.mock({ '/repo/package.json': '{ not: valid json' }); | ||
await expect(hasPackageManager('/repo')).resolves.toBe(false); | ||
}); | ||
|
||
it('returns false if packageManager is an empty string', async () => { | ||
Fixtures.mock({ | ||
'/repo/package.json': JSON.stringify({ packageManager: '' }), | ||
}); | ||
await expect(hasPackageManager('/repo')).resolves.toBe(false); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import { codeBlock } from 'common-tags'; | ||
import { extractAllPackageFiles } from '..'; | ||
import { logger } from '../../../../logger'; | ||
import * as fsUtil from '../../../../util/fs/util'; | ||
import type { ExtractConfig } from '../../types'; | ||
import { postExtract } from './post'; | ||
import * as npmExtract from '.'; | ||
|
@@ -15,6 +16,10 @@ const defaultExtractConfig = { | |
|
||
const input01Content = Fixtures.get('inputs/01.json', '..'); | ||
const input02Content = Fixtures.get('inputs/02.json', '..'); | ||
const input01PackageManager = Fixtures.get( | ||
'inputs/01-package-manager.json', | ||
'..', | ||
); | ||
const input01GlobContent = Fixtures.get('inputs/01-glob.json', '..'); | ||
const workspacesContent = Fixtures.get('inputs/workspaces.json', '..'); | ||
const vendorisedContent = Fixtures.get('is-object.json', '..'); | ||
|
@@ -927,7 +932,7 @@ describe('modules/manager/npm/extract/index', () => { | |
const pJsonStr = JSON.stringify(pJson); | ||
const res = await npmExtract.extractPackageFile( | ||
pJsonStr, | ||
'package.json', | ||
'.yarnrc.yml', | ||
|
||
defaultExtractConfig, | ||
); | ||
expect(res).toMatchObject({ | ||
|
@@ -1268,6 +1273,142 @@ describe('modules/manager/npm/extract/index', () => { | |
}, | ||
]); | ||
}); | ||
|
||
it('extracts yarnrc.yml and adds it as packageFile', async () => { | ||
const yarnrc = codeBlock` | ||
nodeLinker: node-modules | ||
|
||
plugins: | ||
- checksum: 4cb9601cfc0c71e5b0ffd0a85b78e37430b62257040714c2558298ce1fc058f4e918903f0d1747a4fef3f58e15722c35bd76d27492d9d08aa5b04e235bf43b22 | ||
path: .yarn/plugins/@yarnpkg/plugin-catalogs.cjs | ||
spec: 'https://raw.githubusercontent.com/toss/yarn-plugin-catalogs/main/bundles/%40yarnpkg/plugin-catalogs.js' | ||
|
||
catalogs: | ||
list: | ||
is-positive: 1.0.0 | ||
`; | ||
fs.readLocalFile.mockResolvedValueOnce(yarnrc); | ||
|
||
fs.getParentDir.mockReturnValue('./'); | ||
|
||
vi.spyOn(fsUtil, 'ensureLocalPath').mockImplementation( | ||
(p) => './.yarnrc.yml', | ||
); | ||
|
||
fs.readLocalFile.mockResolvedValueOnce(input02Content); | ||
|
||
const res = await extractAllPackageFiles(defaultExtractConfig, [ | ||
'.yarnrc.yml', | ||
]); | ||
|
||
expect(res).toEqual([ | ||
{ | ||
deps: [ | ||
{ | ||
currentValue: '1.0.0', | ||
datasource: 'npm', | ||
depName: 'is-positive', | ||
depType: 'yarn.catalog.default', | ||
prettyDepType: 'yarn.catalog.default', | ||
}, | ||
], | ||
managerData: { | ||
hasPackageManager: false, | ||
}, | ||
packageFile: '.yarnrc.yml', | ||
}, | ||
]); | ||
}); | ||
|
||
it('extracts yarnrc.yml and adds it as packageFile and packageManager to true', async () => { | ||
const yarnrc = codeBlock` | ||
nodeLinker: node-modules | ||
|
||
plugins: | ||
- checksum: 4cb9601cfc0c71e5b0ffd0a85b78e37430b62257040714c2558298ce1fc058f4e918903f0d1747a4fef3f58e15722c35bd76d27492d9d08aa5b04e235bf43b22 | ||
path: .yarn/plugins/@yarnpkg/plugin-catalogs.cjs | ||
spec: 'https://raw.githubusercontent.com/toss/yarn-plugin-catalogs/main/bundles/%40yarnpkg/plugin-catalogs.js' | ||
|
||
catalogs: | ||
list: | ||
is-positive: 1.0.0 | ||
`; | ||
fs.getParentDir.mockReturnValue('./'); | ||
|
||
vi.spyOn(fsUtil, 'ensureLocalPath').mockImplementation( | ||
(p) => './.yarnrc.yml', | ||
); | ||
|
||
fs.readLocalFile.mockResolvedValueOnce(yarnrc); | ||
fs.readLocalFile.mockResolvedValueOnce(input01PackageManager); | ||
|
||
const res = await extractAllPackageFiles(defaultExtractConfig, [ | ||
'.yarnrc.yml', | ||
]); | ||
|
||
expect(res[0]).toEqual({ | ||
deps: [ | ||
{ | ||
currentValue: '1.0.0', | ||
datasource: 'npm', | ||
depName: 'is-positive', | ||
depType: 'yarn.catalog.default', | ||
prettyDepType: 'yarn.catalog.default', | ||
}, | ||
], | ||
managerData: { | ||
hasPackageManager: true, | ||
}, | ||
packageFile: '.yarnrc.yml', | ||
}); | ||
}); | ||
|
||
it('extracts yarnrc.yml and adds it as packageFile and packageManager to false if no deps', async () => { | ||
const yarnrc = codeBlock` | ||
nodeLinker: node-modules | ||
|
||
plugins: | ||
- checksum: 4cb9601cfc0c71e5b0ffd0a85b78e37430b62257040714c2558298ce1fc058f4e918903f0d1747a4fef3f58e15722c35bd76d27492d9d08aa5b04e235bf43b22 | ||
path: .yarn/plugins/@yarnpkg/plugin-catalogs.cjs | ||
spec: 'https://raw.githubusercontent.com/toss/yarn-plugin-catalogs/main/bundles/%40yarnpkg/plugin-catalogs.js' | ||
|
||
catalogs: | ||
list: | ||
is-positive: 1.0.0 | ||
`; | ||
|
||
fs.getParentDir.mockReturnValue('./'); | ||
|
||
vi.spyOn(fsUtil, 'ensureLocalPath').mockImplementation( | ||
(p) => './.yarnrc.yml', | ||
); | ||
|
||
fs.readLocalFile.mockResolvedValueOnce(yarnrc); | ||
|
||
fs.readLocalFile.mockResolvedValueOnce( | ||
'{"name": "simulate deps to be null", brokenJsonHere: }', | ||
); | ||
|
||
const res = await extractAllPackageFiles(defaultExtractConfig, [ | ||
'.yarnrc.yml', | ||
]); | ||
|
||
expect(res[0]).toEqual({ | ||
deps: [ | ||
{ | ||
currentValue: '1.0.0', | ||
datasource: 'npm', | ||
depName: 'is-positive', | ||
depType: 'yarn.catalog.default', | ||
prettyDepType: 'yarn.catalog.default', | ||
}, | ||
], | ||
managerData: { | ||
hasPackageManager: false, | ||
}, | ||
packageFile: '.yarnrc.yml', | ||
}); | ||
}); | ||
}); | ||
|
||
describe('.postExtract()', () => { | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -3,9 +3,11 @@ import { GlobalConfig } from '../../../../config/global'; | |||
import { logger } from '../../../../logger'; | ||||
import { | ||||
findLocalSiblingOrParent, | ||||
getParentDir, | ||||
getSiblingFileName, | ||||
readLocalFile, | ||||
} from '../../../../util/fs'; | ||||
import { ensureLocalPath } from '../../../../util/fs/util'; | ||||
|
import { ensureLocalPath } from '../../../../util/fs/util'; |
wrong import path anyways
Uh oh!
There was an error while loading. Please reload this page.