diff --git a/lib/config/definitions.js b/lib/config/definitions.js index ee5b0e4924e36a97b0d65a9cf797562b59abeaac..8855775f9d5ed11c707530dd3f62f8eebad970b2 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -999,6 +999,27 @@ const options = [ }, mergeable: true, }, + { + name: 'ruby', + releaseStatus: 'unpublished', + description: 'Configuration object for ruby language', + stage: 'package', + type: 'json', + default: {}, + mergeable: true, + cli: false, + }, + { + name: 'bundler', + releaseStatus: 'unpublished', + description: 'Configuration object for bundler Gemfiles', + stage: 'package', + type: 'json', + default: { + fileMatch: [], + }, + mergeable: true, + }, { name: 'terraform', description: 'Configuration object for Terraform module renovation', diff --git a/lib/manager/bundler/artifacts.js b/lib/manager/bundler/artifacts.js new file mode 100644 index 0000000000000000000000000000000000000000..5582aee4e836cbb6dfa82adbc4034f9efbc94b76 --- /dev/null +++ b/lib/manager/bundler/artifacts.js @@ -0,0 +1,19 @@ +module.exports = { + getArtifacts, +}; + +/* + * The getArtifacts() function is optional and necessary only if it is necessary to update "artifacts" + * after updating package files. Artifacts are files such as lock files or checksum files. + * Usually this will require running a child process command to produce an update. + */ + +async function getArtifacts( + packageFileName, + updatedDeps, + newPackageFileContent, + config +) { + await logger.debug({ config }, `composer.getArtifacts(${packageFileName})`); + return null; +} diff --git a/lib/manager/bundler/extract.js b/lib/manager/bundler/extract.js new file mode 100644 index 0000000000000000000000000000000000000000..7959622696e95948187a220704bae981e30d80bb --- /dev/null +++ b/lib/manager/bundler/extract.js @@ -0,0 +1,18 @@ +module.exports = { + extractPackageFile, +}; + +/* + * The extractPackageFile() function is mandatory unless extractAllPackageFiles() is used instead. + * + * Use extractPackageFile() if it is OK for Renovate to parse/extract package files in parallel independently. + * + * Here are examples of when extractAllPackageFiles has been necessary to be used instead: + * - for npm/yarn/lerna, "monorepos" can have links between package files and logic requiring us to selectively ignore "internal" dependencies within the same repository + * - for gradle, we use a third party CLI tool to extract all dependencies at once and so it should not be called independently on each package file separately + */ + +function extractPackageFile(content, fileName) { + logger.trace(`bundler.extractPackageFile(${fileName})`); + return null; +} diff --git a/lib/manager/bundler/index.js b/lib/manager/bundler/index.js new file mode 100644 index 0000000000000000000000000000000000000000..5d5954b56115c326f2601574f22f0b1fe643a0af --- /dev/null +++ b/lib/manager/bundler/index.js @@ -0,0 +1,19 @@ +const { extractPackageFile } = require('./extract'); +const { updateDependency } = require('./update'); +const { getArtifacts } = require('./artifacts'); +const { getRangeStrategy } = require('./range'); + +const language = 'ruby'; + +/* + * Each of the below functions contain some explanations within their own files. + * The best way to understand them in more detail is to look at the existing managers and find one that matches most closely what you need to do. + */ + +module.exports = { + extractPackageFile, // Mandatory unless extractAllPackageFiles is used instead + getArtifacts, // Optional + getRangeStrategy, // Optional + language, // Optional + updateDependency, // Mandatory +}; diff --git a/lib/manager/bundler/range.js b/lib/manager/bundler/range.js new file mode 100644 index 0000000000000000000000000000000000000000..382f15b7fafa7f5487ea2670f43428a3b7a7244c --- /dev/null +++ b/lib/manager/bundler/range.js @@ -0,0 +1,21 @@ +module.exports = { + getRangeStrategy, +}; + +/* + * The getRangeStrategy() function is optional and can be removed if not applicable. + * It is used when the user configures rangeStrategy=auto. + * + * For example in npm, when rangeStrategy is auto we: + * - Always pin "devDependencies" + * - Pin "dependencies" only if we detect that it's probably an app not a library + * - Always widen "peerDependencies" + * + * If this function is not present then the default 'replace' value will be used. + * + */ + +function getRangeStrategy(config) { + logger.debug({ config }); + return 'replace'; +} diff --git a/lib/manager/bundler/readme.md b/lib/manager/bundler/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..9727941975c5edabe9f15486e163db6c1be68d28 --- /dev/null +++ b/lib/manager/bundler/readme.md @@ -0,0 +1,107 @@ +## Overview + +#### Name of package manager + +--- + +#### What language does this support? + +--- + +#### Does that language have other (competing?) package managers? + +## Package File Detection + +#### What type of package files and names does it use? + +--- + +#### What [fileMatch](https://renovatebot.com/docs/configuration-options/#filematch) pattern(s) should be used? + +--- + +#### Is it likely that many users would need to extend this pattern for custom file names? + +--- + +#### Is the fileMatch pattern likely to get many "false hits" for files that have nothing to do with package management? + +## Parsing and Extraction + +#### Can package files have "local" links to each other that need to be resolved? + +#### Is there reason why package files need to be parsed together (in serial) instead of independently? + +--- + +#### What format/syntax is the package file in? e.g. JSON, TOML, custom? + +--- + +#### How do you suggest parsing the file? Using an off-the-shelf parser, using regex, or can it be custom-parsed line by line? + +--- + +#### Does the package file structure distinguish between different "types" of dependencies? e.g. production dependencies, dev dependencies, etc? + +No + +--- + +#### List all the sources/syntaxes of dependencies that can be extracted: + +--- + +#### Describe which types of dependencies above are supported and which will be implemented in future: + +## Versioning + +#### What versioning scheme do the package files use? + +--- + +#### Does this versioning scheme support range constraints, e.g. `^1.0.0` or `1.x`? + +--- + +#### Is this package manager used for applications, libraries, or both? If both, is there a way to tell which is which? + +--- + +#### If ranges are supported, are there any cases when Renovate should pin ranges to exact versions if rangeStrategy=auto? + +## Lookup + +#### Is a new datasource required? Provide details + +--- + +#### Will users need the capability to specify a custom host/registry to look up? Can it be found within the package files, or within other files inside the repository, or would it require Renovate configuration? + +--- + +#### Do the package files contain any "constraints" on the parent language (e.g. supports only v3.x of Python) or platform (Linux, Windows, etc) that should be used in the lookup procedure? + +--- + +#### Will users need the ability to configure language or other constraints using Renovate config? + +## Artifacts + +#### Are lock files or checksum files used? Mandatory? + +--- + +#### If so, what tool and exact commands should be used if updating 1 or more package versions in a dependency file? + +--- + +#### If applicable, describe how the tool maintains a cache and if it can be controlled via CLI or env? Do you recommend the cache be kept or disabled/ignored? + +--- + +#### If applicable, what command should be used to generate a lock file from scratch if you already have a package file? This will be used for "lock file maintenance". + +## Other + +#### Is there anything else to know about this package manager? diff --git a/lib/manager/bundler/update.js b/lib/manager/bundler/update.js new file mode 100644 index 0000000000000000000000000000000000000000..89178929fbfd99323baa0b25c0d4d0d1b9c7902f --- /dev/null +++ b/lib/manager/bundler/update.js @@ -0,0 +1,15 @@ +module.exports = { + updateDependency, +}; + +/* + * The updateDependency() function is mandatory, and is used for updating one dependency at a time. + * It returns the currentFileContent if no changes are necessary (e.g. because the existing branch/PR is up to date), + * or with new content if changes are necessary. + */ + +function updateDependency(currentFileContent, upgrade) { + logger.debug({ config: upgrade }, 'bundler.updateDependency()'); + // TODO + return currentFileContent; +} diff --git a/lib/manager/index.js b/lib/manager/index.js index cebad074bec84b1286b4d98cf88e33a0f53215b4..dd630c15fa9f35b487d9936018e485d380175607 100644 --- a/lib/manager/index.js +++ b/lib/manager/index.js @@ -10,6 +10,7 @@ const managerList = [ 'gomod', 'kubernetes', 'meteor', + 'bundler', 'npm', 'nvm', 'pip_requirements', @@ -29,6 +30,7 @@ const languageList = [ 'docker', 'golang', 'js', + 'ruby', 'node', 'php', 'python', diff --git a/test/manager/__snapshots__/manager-docs.spec.js.snap b/test/manager/__snapshots__/manager-docs.spec.js.snap index 1fb82070ede431673f625d9a590aad15323de4fc..837f06458ff1e26faa9b73b0d46bb464d9901e56 100644 --- a/test/manager/__snapshots__/manager-docs.spec.js.snap +++ b/test/manager/__snapshots__/manager-docs.spec.js.snap @@ -4,6 +4,7 @@ exports[`manager readmes has same questions for all managers 1`] = ` Array [ "bazel", "buildkite", + "bundler", "cargo", "circleci", "composer", @@ -87,3 +88,35 @@ Array [ "Is there anything else to know about this package manager?", ] `; + +exports[`manager readmes has same questions for all managers 4`] = ` +Array [ + "Name of package manager", + "What language does this support?", + "Does that language have other (competing?) package managers?", + "What type of package files and names does it use?", + "What [fileMatch](https://renovatebot.com/docs/configuration-options/#filematch) pattern(s) should be used?", + "Is it likely that many users would need to extend this pattern for custom file names?", + "Is the fileMatch pattern likely to get many \\"false hits\\" for files that have nothing to do with package management?", + "Can package files have \\"local\\" links to each other that need to be resolved?", + "Is there reason why package files need to be parsed together (in serial) instead of independently?", + "What format/syntax is the package file in? e.g. JSON, TOML, custom?", + "How do you suggest parsing the file? Using an off-the-shelf parser, using regex, or can it be custom-parsed line by line?", + "Does the package file structure distinguish between different \\"types\\" of dependencies? e.g. production dependencies, dev dependencies, etc?", + "List all the sources/syntaxes of dependencies that can be extracted:", + "Describe which types of dependencies above are supported and which will be implemented in future:", + "What versioning scheme do the package files use?", + "Does this versioning scheme support range constraints, e.g. \`^1.0.0\` or \`1.x\`?", + "Is this package manager used for applications, libraries, or both? If both, is there a way to tell which is which?", + "If ranges are supported, are there any cases when Renovate should pin ranges to exact versions if rangeStrategy=auto?", + "Is a new datasource required? Provide details", + "Will users need the capability to specify a custom host/registry to look up? Can it be found within the package files, or within other files inside the repository, or would it require Renovate configuration?", + "Do the package files contain any \\"constraints\\" on the parent language (e.g. supports only v3.x of Python) or platform (Linux, Windows, etc) that should be used in the lookup procedure?", + "Will users need the ability to configure language or other constraints using Renovate config?", + "Are lock files or checksum files used? Mandatory?", + "If so, what tool and exact commands should be used if updating 1 or more package versions in a dependency file?", + "If applicable, describe how the tool maintains a cache and if it can be controlled via CLI or env? Do you recommend the cache be kept or disabled/ignored?", + "If applicable, what command should be used to generate a lock file from scratch if you already have a package file? This will be used for \\"lock file maintenance\\".", + "Is there anything else to know about this package manager?", +] +`; diff --git a/test/manager/newmanager/artifacts.spec.js b/test/manager/newmanager/artifacts.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..fe2918907f83c7db42dd15c571e875a6445929f0 --- /dev/null +++ b/test/manager/newmanager/artifacts.spec.js @@ -0,0 +1,13 @@ +const cargo = require('../../../lib/manager/bundler/artifacts'); + +let config; + +describe('bundler.getArtifacts()', () => { + beforeEach(() => { + jest.resetAllMocks(); + config = {}; + }); + it('returns null by default', async () => { + expect(await cargo.getArtifacts('', [], '', config)).toBeNull(); + }); +}); diff --git a/test/manager/newmanager/extract.spec.js b/test/manager/newmanager/extract.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..d987c82c38a2540fd4637a117986d21845093ba9 --- /dev/null +++ b/test/manager/newmanager/extract.spec.js @@ -0,0 +1,13 @@ +const { extractPackageFile } = require('../../../lib/manager/bundler/extract'); + +describe('lib/manager/bundler/extract', () => { + describe('extractPackageFile()', () => { + let config; + beforeEach(() => { + config = {}; + }); + it('returns null for empty', () => { + expect(extractPackageFile('nothing here', config)).toBeNull(); + }); + }); +}); diff --git a/test/manager/newmanager/range.spec.js b/test/manager/newmanager/range.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..9885a7d23f6d497bccf36c61ab6eddb0c8c91bdb --- /dev/null +++ b/test/manager/newmanager/range.spec.js @@ -0,0 +1,13 @@ +const { getRangeStrategy } = require('../../../lib/manager/bundler'); + +describe('lib/manager/bundler/range', () => { + describe('getRangeStrategy()', () => { + let config; + beforeEach(() => { + config = {}; + }); + it('always returns replace', () => { + expect(getRangeStrategy(config)).toEqual('replace'); + }); + }); +}); diff --git a/test/manager/newmanager/update.spec.js b/test/manager/newmanager/update.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..9ab00c8d7b2c5f3da1f89fe367aa8f9ce19187b2 --- /dev/null +++ b/test/manager/newmanager/update.spec.js @@ -0,0 +1,13 @@ +const { updateDependency } = require('../../../lib/manager/bundler/update'); + +describe('lib/manager/bundler/update', () => { + describe('updateDependency()', () => { + let config; + beforeEach(() => { + config = {}; + }); + it('returns same', () => { + expect(updateDependency('abc', config)).toEqual('abc'); + }); + }); +}); diff --git a/test/workers/repository/extract/__snapshots__/index.spec.js.snap b/test/workers/repository/extract/__snapshots__/index.spec.js.snap index f958872656688a92e03d4e3da827cd3408b72eb4..b45f5f37dbb0ecc88708ab7b8b9e51228b9f3f23 100644 --- a/test/workers/repository/extract/__snapshots__/index.spec.js.snap +++ b/test/workers/repository/extract/__snapshots__/index.spec.js.snap @@ -8,6 +8,9 @@ Object { "buildkite": Array [ Object {}, ], + "bundler": Array [ + Object {}, + ], "cargo": Array [ Object {}, ],