diff --git a/lib/manager/poetry/extract.ts b/lib/manager/poetry/extract.ts index 6461754b6fc245..8bb1abed9efebd 100644 --- a/lib/manager/poetry/extract.ts +++ b/lib/manager/poetry/extract.ts @@ -28,7 +28,8 @@ export function extractPackageFile( if (!deps.length) { return null; } - return { deps }; + + return { deps, registryUrls: extractRegistries(pyprojectfile) }; } function extractFromSection( @@ -84,3 +85,24 @@ function extractFromSection( }); return deps; } + +function extractRegistries(pyprojectfile: PoetryFile): string[] { + const sources = + pyprojectfile.tool && + pyprojectfile.tool.poetry && + pyprojectfile.tool.poetry.source; + + if (!Array.isArray(sources) || sources.length === 0) { + return null; + } + + const registryUrls = new Set(); + for (const source of sources) { + if (source.url) { + registryUrls.add(source.url); + } + } + registryUrls.add('https://pypi.org/pypi/'); + + return Array.from(registryUrls); +} diff --git a/lib/manager/poetry/types.ts b/lib/manager/poetry/types.ts index e409718d83cdfe..1e8189433ab510 100644 --- a/lib/manager/poetry/types.ts +++ b/lib/manager/poetry/types.ts @@ -2,6 +2,7 @@ export interface PoetrySection { dependencies: Record; 'dev-dependencies': Record; extras: Record; + source?: PoetrySource[]; } export interface PoetryFile { @@ -15,3 +16,8 @@ export interface PoetryDependency { git?: string; version?: string; } + +export interface PoetrySource { + name?: string; + url?: string; +} diff --git a/test/manager/poetry/__snapshots__/extract.spec.ts.snap b/test/manager/poetry/__snapshots__/extract.spec.ts.snap index dae3171c559d1a..5ab6e2c8aabab2 100644 --- a/test/manager/poetry/__snapshots__/extract.spec.ts.snap +++ b/test/manager/poetry/__snapshots__/extract.spec.ts.snap @@ -1,5 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`lib/manager/poetry/extract extractPackageFile() dedupes registries 1`] = ` +Array [ + "https://pypi.org/pypi/", + "https://bar.baz/+simple/", +] +`; + exports[`lib/manager/poetry/extract extractPackageFile() extracts multiple dependencies (with dep = {version = "1.2.3"} case) 1`] = ` Array [ Object { @@ -157,6 +164,14 @@ Array [ ] `; +exports[`lib/manager/poetry/extract extractPackageFile() extracts registries 1`] = ` +Array [ + "https://foo.bar/simple/", + "https://bar.baz/+simple/", + "https://pypi.org/pypi/", +] +`; + exports[`lib/manager/poetry/extract extractPackageFile() handles multiple constraint dependencies 1`] = ` Array [ Object { diff --git a/test/manager/poetry/_fixtures/pyproject.6.toml b/test/manager/poetry/_fixtures/pyproject.6.toml new file mode 100644 index 00000000000000..40d18d467eac47 --- /dev/null +++ b/test/manager/poetry/_fixtures/pyproject.6.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "example 6" +version = "0.1.0" +description = "" +authors = ["John Doe "] + +[tool.poetry.dependencies] +dep0 = "0.0.0" + +[[tool.poetry.source]] +name = "foo" +url = "https://foo.bar/simple/" + +[[tool.poetry.source]] +name = "bar" +url = "https://bar.baz/+simple/" \ No newline at end of file diff --git a/test/manager/poetry/_fixtures/pyproject.7.toml b/test/manager/poetry/_fixtures/pyproject.7.toml new file mode 100644 index 00000000000000..398e371b584a37 --- /dev/null +++ b/test/manager/poetry/_fixtures/pyproject.7.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "example 7" +version = "0.1.0" +description = "" +authors = ["John Doe "] +source = [] + +[tool.poetry.dependencies] +dep0 = "0.0.0" \ No newline at end of file diff --git a/test/manager/poetry/_fixtures/pyproject.8.toml b/test/manager/poetry/_fixtures/pyproject.8.toml new file mode 100644 index 00000000000000..f15169159e03b0 --- /dev/null +++ b/test/manager/poetry/_fixtures/pyproject.8.toml @@ -0,0 +1,20 @@ +[tool.poetry] +name = "example 8" +version = "0.1.0" +description = "" +authors = ["John Doe "] + +[tool.poetry.dependencies] +dep0 = "0.0.0" + +[[tool.poetry.source]] +name = "foo" +url = "https://pypi.org/pypi/" + +[[tool.poetry.source]] +name = "bar" +url = "https://bar.baz/+simple/" + +[[tool.poetry.source]] +name = "baz" +url = "https://bar.baz/+simple/" diff --git a/test/manager/poetry/extract.spec.ts b/test/manager/poetry/extract.spec.ts index 17b792c08edff6..3a35eed7fc201c 100644 --- a/test/manager/poetry/extract.spec.ts +++ b/test/manager/poetry/extract.spec.ts @@ -26,41 +26,73 @@ const pyproject5toml = readFileSync( 'utf8' ); +const pyproject6toml = readFileSync( + 'test/manager/poetry/_fixtures/pyproject.6.toml', + 'utf8' +); + +const pyproject7toml = readFileSync( + 'test/manager/poetry/_fixtures/pyproject.7.toml', + 'utf8' +); + +const pyproject8toml = readFileSync( + 'test/manager/poetry/_fixtures/pyproject.8.toml', + 'utf8' +); + describe('lib/manager/poetry/extract', () => { describe('extractPackageFile()', () => { - let config; + let filename: string; beforeEach(() => { - config = {}; + filename = ''; }); it('returns null for empty', () => { - expect(extractPackageFile('nothing here', config)).toBeNull(); + expect(extractPackageFile('nothing here', filename)).toBeNull(); }); it('returns null for parsed file without poetry section', () => { - expect(extractPackageFile(pyproject5toml, config)).toBeNull(); + expect(extractPackageFile(pyproject5toml, filename)).toBeNull(); }); it('extracts multiple dependencies', () => { - const res = extractPackageFile(pyproject1toml, config); + const res = extractPackageFile(pyproject1toml, filename); expect(res.deps).toMatchSnapshot(); expect(res.deps).toHaveLength(9); }); it('extracts multiple dependencies (with dep = {version = "1.2.3"} case)', () => { - const res = extractPackageFile(pyproject2toml, config); + const res = extractPackageFile(pyproject2toml, filename); expect(res.deps).toMatchSnapshot(); expect(res.deps).toHaveLength(7); }); it('handles case with no dependencies', () => { - const res = extractPackageFile(pyproject3toml, config); + const res = extractPackageFile(pyproject3toml, filename); expect(res).toBeNull(); }); it('handles multiple constraint dependencies', () => { - const res = extractPackageFile(pyproject4toml, config); + const res = extractPackageFile(pyproject4toml, filename); expect(res.deps).toMatchSnapshot(); expect(res.deps).toHaveLength(1); }); + it('extracts registries', () => { + const res = extractPackageFile(pyproject6toml, filename); + expect(res.registryUrls).toMatchSnapshot(); + expect(res.registryUrls).toHaveLength(3); + }); + it('can parse empty registries', () => { + const res = extractPackageFile(pyproject7toml, filename); + expect(res.registryUrls).toBeNull(); + }); + it('can parse missing registries', () => { + const res = extractPackageFile(pyproject1toml, filename); + expect(res.registryUrls).toBeNull(); + }); + it('dedupes registries', () => { + const res = extractPackageFile(pyproject8toml, filename); + expect(res.registryUrls).toMatchSnapshot(); + }); it('skips git dependencies', () => { const content = '[tool.poetry.dependencies]\r\nflask = {git = "https://github.com/pallets/flask.git"}\r\nwerkzeug = ">=0.14"'; - const res = extractPackageFile(content, config).deps; + const res = extractPackageFile(content, filename).deps; expect(res[0].depName).toBe('flask'); expect(res[0].currentValue).toBe(''); expect(res[0].skipReason).toBe('git-dependency'); @@ -69,7 +101,7 @@ describe('lib/manager/poetry/extract', () => { it('skips git dependencies', () => { const content = '[tool.poetry.dependencies]\r\nflask = {git = "https://github.com/pallets/flask.git", version="1.2.3"}\r\nwerkzeug = ">=0.14"'; - const res = extractPackageFile(content, config).deps; + const res = extractPackageFile(content, filename).deps; expect(res[0].depName).toBe('flask'); expect(res[0].currentValue).toBe('1.2.3'); expect(res[0].skipReason).toBe('git-dependency'); @@ -78,7 +110,7 @@ describe('lib/manager/poetry/extract', () => { it('skips path dependencies', () => { const content = '[tool.poetry.dependencies]\r\nflask = {path = "/some/path/"}\r\nwerkzeug = ">=0.14"'; - const res = extractPackageFile(content, config).deps; + const res = extractPackageFile(content, filename).deps; expect(res[0].depName).toBe('flask'); expect(res[0].currentValue).toBe(''); expect(res[0].skipReason).toBe('path-dependency'); @@ -87,7 +119,7 @@ describe('lib/manager/poetry/extract', () => { it('skips path dependencies', () => { const content = '[tool.poetry.dependencies]\r\nflask = {path = "/some/path/", version = "1.2.3"}\r\nwerkzeug = ">=0.14"'; - const res = extractPackageFile(content, config).deps; + const res = extractPackageFile(content, filename).deps; expect(res[0].depName).toBe('flask'); expect(res[0].currentValue).toBe('1.2.3'); expect(res[0].skipReason).toBe('path-dependency');