diff --git a/lib/manager/pip_requirements/extract.js b/lib/manager/pip_requirements/extract.js index cd3e7a336739c75987ea103741424dc9f71f62f4..5288056399632be04a51ca5139b33c77ebd0a2ba 100644 --- a/lib/manager/pip_requirements/extract.js +++ b/lib/manager/pip_requirements/extract.js @@ -27,14 +27,28 @@ function extractDependencies(content) { const regex = new RegExp(`^(${packagePattern})(${specifierPattern})$`, 'g'); const deps = content .split('\n') - .map((line, lineNumber) => { + .map((rawline, lineNumber) => { + let dep = {}; + const [line, comment] = rawline.split('#').map(part => part.trim()); + if (comment && comment.match(/^(renovate|pyup):/)) { + const command = comment + .split('#')[0] + .split(':')[1] + .trim(); + if (command === 'ignore') { + dep.skipReason = 'ignored'; + } else { + logger.info('Unknown pip_requirements command: ' + command); + } + } regex.lastIndex = 0; const matches = regex.exec(line); if (!matches) { return null; } const [, depName, currentValue] = matches; - const dep = { + dep = { + ...dep, depName, currentValue, lineNumber, diff --git a/lib/manager/pip_requirements/update.js b/lib/manager/pip_requirements/update.js index 99360c10029f14421d825c6a85ff5bc5b775fa85..8d8140ead19e491c020fd360d63a29c4e4c1c4a2 100644 --- a/lib/manager/pip_requirements/update.js +++ b/lib/manager/pip_requirements/update.js @@ -6,7 +6,12 @@ function updateDependency(fileContent, upgrade) { try { logger.debug(`pip_requirements.updateDependency(): ${upgrade.newValue}`); const lines = fileContent.split('\n'); - lines[upgrade.lineNumber] = `${upgrade.depName}${upgrade.newValue}`; + const oldValue = lines[upgrade.lineNumber]; + const newValue = oldValue.replace( + /^.+?(\s.*)?$/, + `${upgrade.depName}${upgrade.newValue}$1` + ); + lines[upgrade.lineNumber] = newValue; return lines.join('\n'); } catch (err) { logger.info({ err }, 'Error setting new package version'); diff --git a/test/_fixtures/pip_requirements/requirements3.txt b/test/_fixtures/pip_requirements/requirements3.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae45a3a3564fc5454d41f7cf73327073b96b9a55 --- /dev/null +++ b/test/_fixtures/pip_requirements/requirements3.txt @@ -0,0 +1,5 @@ +Django==1 # renovate +distribute==0.6.27 # renovate: ignore +dj-database-url==0.2 # pyup: nothing +psycopg2==2.4.5 # renovate: +wsgiref==0.1.2 # something else diff --git a/test/manager/pip_requirements/__snapshots__/extract.spec.js.snap b/test/manager/pip_requirements/__snapshots__/extract.spec.js.snap index c366526d88cc18be53f125f25ec8c2d5f6b39006..f352abc926e4bcffa82dead4ac98d5c622185b8d 100644 --- a/test/manager/pip_requirements/__snapshots__/extract.spec.js.snap +++ b/test/manager/pip_requirements/__snapshots__/extract.spec.js.snap @@ -74,3 +74,44 @@ Array [ }, ] `; + +exports[`lib/manager/pip_requirements/extract extractDependencies() handles comments and commands 1`] = ` +Array [ + Object { + "currentValue": "==1", + "depName": "Django", + "lineNumber": 0, + "purl": "pkg:pypi/Django", + "versionScheme": "pep440", + }, + Object { + "currentValue": "==0.6.27", + "depName": "distribute", + "lineNumber": 1, + "purl": "pkg:pypi/distribute", + "skipReason": "ignored", + "versionScheme": "pep440", + }, + Object { + "currentValue": "==0.2", + "depName": "dj-database-url", + "lineNumber": 2, + "purl": "pkg:pypi/dj-database-url", + "versionScheme": "pep440", + }, + Object { + "currentValue": "==2.4.5", + "depName": "psycopg2", + "lineNumber": 3, + "purl": "pkg:pypi/psycopg2", + "versionScheme": "pep440", + }, + Object { + "currentValue": "==0.1.2", + "depName": "wsgiref", + "lineNumber": 4, + "purl": "pkg:pypi/wsgiref", + "versionScheme": "pep440", + }, +] +`; diff --git a/test/manager/pip_requirements/__snapshots__/update.spec.js.snap b/test/manager/pip_requirements/__snapshots__/update.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..381e373e605654807124f022f88e7fe454e4ae53 --- /dev/null +++ b/test/manager/pip_requirements/__snapshots__/update.spec.js.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`manager/pip_requirements/update updateDependency replaces existing value 1`] = ` +"--index-url http://example.com/private-pypi/ +# simple comment +url==1.0.1 +some-other-package==1.0.0 +not_semver==1.9 + +" +`; + +exports[`manager/pip_requirements/update updateDependency replaces existing value with comment 1`] = ` +"Django==1 # renovate +distribute==0.6.27 # renovate: ignore +dj-database-url==0.2 # pyup: nothing +psycopg2==2.4.6 # renovate: +wsgiref==0.1.2 # something else +" +`; diff --git a/test/manager/pip_requirements/extract.spec.js b/test/manager/pip_requirements/extract.spec.js index 1f4a4b83848a2923ca3e6e8138d8e34175c4a87d..9904e56da42773c291e62011e2b22aca2c8101ac 100644 --- a/test/manager/pip_requirements/extract.spec.js +++ b/test/manager/pip_requirements/extract.spec.js @@ -11,6 +11,10 @@ const requirements2 = fs.readFileSync( 'test/_fixtures/pip_requirements/requirements2.txt', 'utf8' ); +const requirements3 = fs.readFileSync( + 'test/_fixtures/pip_requirements/requirements3.txt', + 'utf8' +); describe('lib/manager/pip_requirements/extract', () => { describe('extractDependencies()', () => { @@ -31,5 +35,10 @@ describe('lib/manager/pip_requirements/extract', () => { expect(res).toMatchSnapshot(); expect(res).toHaveLength(5); }); + it('handles comments and commands', () => { + const res = extractDependencies(requirements3, config).deps; + expect(res).toMatchSnapshot(); + expect(res).toHaveLength(5); + }); }); }); diff --git a/test/manager/pip_requirements/update.spec.js b/test/manager/pip_requirements/update.spec.js index 086dd07b1a87086a2a36eb4477dd41eac176f113..3caa64fb2f1b32b8663089792f96a3d5c9de7453 100644 --- a/test/manager/pip_requirements/update.spec.js +++ b/test/manager/pip_requirements/update.spec.js @@ -8,15 +8,21 @@ const requirements = fs.readFileSync( 'utf8' ); +const requirements3 = fs.readFileSync( + 'test/_fixtures/pip_requirements/requirements3.txt', + 'utf8' +); + describe('manager/pip_requirements/update', () => { describe('updateDependency', () => { it('replaces existing value', () => { const upgrade = { depName: 'url', lineNumber: 2, - newValue: '1.0.1', + newValue: '==1.0.1', }; const res = updateDependency(requirements, upgrade); + expect(res).toMatchSnapshot(); expect(res).not.toEqual(requirements); expect(res.includes(upgrade.newValue)).toBe(true); }); @@ -24,5 +30,16 @@ describe('manager/pip_requirements/update', () => { const res = updateDependency(null, null); expect(res).toBe(null); }); + it('replaces existing value with comment', () => { + const upgrade = { + depName: 'psycopg2', + lineNumber: 3, + newValue: '==2.4.6', + }; + const res = updateDependency(requirements3, upgrade); + expect(res).toMatchSnapshot(); + expect(res).not.toEqual(requirements3); + expect(res.includes(upgrade.newValue)).toBe(true); + }); }); });