From 3505508c9c03599eb64cbd9792018a18de4db42d Mon Sep 17 00:00:00 2001 From: Bob van de Vijver <bobvandevijver@users.noreply.github.com> Date: Mon, 23 Aug 2021 20:13:30 +0200 Subject: [PATCH] feat: Add fully configurable composer ignore platform requirement configuration (#11138) Co-authored-by: Michael Kriese <michael.kriese@visualon.de> --- docs/usage/configuration-options.md | 15 +++++++++++ docs/usage/self-hosted-configuration.md | 4 --- lib/config/migration.spec.ts | 27 +++++++++++++++++++ lib/config/migration.ts | 6 +++++ lib/config/options/index.ts | 8 +++--- .../__snapshots__/artifacts.spec.ts.snap | 24 +++++++++++++++++ lib/manager/composer/artifacts.spec.ts | 26 ++++++++++++++++-- lib/manager/composer/artifacts.ts | 8 +++++- lib/manager/types.ts | 2 +- 9 files changed, 108 insertions(+), 12 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 4b5cc2992b..c021f85fca 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -357,6 +357,21 @@ Usually left empty except for internal use (multiple base branches, and vulnerab This is used to alter `commitMessage` and `prTitle` without needing to copy/paste the whole string. The "topic" is usually refers to the dependency being updated, e.g. `"dependency react"`. +## composerIgnorePlatformReqs + +By default, Renovate will run Composer with `--ignore-platform-reqs` as the PHP platform used by Renovate most probably won't match with the required PHP environment of your project as configured in your `composer.json` file. +However, this also means that all platform constraints (including PHP version) will be ignored by default, which can result in updated dependencies that are not compatible with your platform. + +To solve this, you should configure explicit ignored platform requirements (for example `ext-zip`) by setting them separately in this array. +Each item will be added to the Composer command with `--ignore-platform-req`, resulting in it being ignored during its invocation. +The used PHP version will be guessed automatically from your `composer.json` definition, so `php` should not be added as explicit dependency. + +If an empty array is configured, Renovate uses its default behaviour. + +Set to `null` (not recommended) to fully omit `--ignore-platform-reqs/--ignore-platform-req` during Composer invocation. +This requires the Renovate image to be fully compatible with your Composer platform requirements in order for the Composer invocation to succeed, otherwise Renovate will fail to create the updated lock file. +The Composer output should inform you about the reasons the update failed. + ## configWarningReuseIssue Renovate's default behavior is to reuse/reopen a single Config Warning issue in each repository so as to keep the "noise" down. diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index f48cbf777c..5da83d57cb 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -126,10 +126,6 @@ e.g. } ``` -## composerIgnorePlatformReqs - -Set to `false` to prevent usage of `--ignore-platform-reqs` in the Composer package manager.s - ## customEnvVariables This configuration will be applied after all other environment variables so that it can be used to override defaults. diff --git a/lib/config/migration.spec.ts b/lib/config/migration.spec.ts index 08bb570a50..1fec9128db 100644 --- a/lib/config/migration.spec.ts +++ b/lib/config/migration.spec.ts @@ -722,6 +722,33 @@ describe('config/migration', () => { expect(isMigrated).toBe(true); expect(migratedConfig).toEqual({ extends: ['local>org/renovate-config'] }); }); + + it('it migrates composerIgnorePlatformReqs values', () => { + let config: TestRenovateConfig; + let res: MigratedConfig; + + config = { + composerIgnorePlatformReqs: true, + } as never; + res = configMigration.migrateConfig(config); + expect(res.isMigrated).toBe(true); + expect(res.migratedConfig.composerIgnorePlatformReqs).toStrictEqual([]); + + config = { + composerIgnorePlatformReqs: false, + } as never; + res = configMigration.migrateConfig(config); + expect(res.isMigrated).toBe(true); + expect(res.migratedConfig.composerIgnorePlatformReqs).toBeNull(); + + config = { + composerIgnorePlatformReqs: [], + } as never; + res = configMigration.migrateConfig(config); + expect(res.isMigrated).toBe(false); + expect(res.migratedConfig.composerIgnorePlatformReqs).toStrictEqual([]); + }); + it('it migrates gradle-lite', () => { const config: RenovateConfig = { gradle: { diff --git a/lib/config/migration.ts b/lib/config/migration.ts index d336a965b9..ef305caef7 100644 --- a/lib/config/migration.ts +++ b/lib/config/migration.ts @@ -518,6 +518,12 @@ export function migrateConfig( } } else if (key === 'binarySource' && val === 'auto') { migratedConfig.binarySource = 'global'; + } else if (key === 'composerIgnorePlatformReqs') { + if (val === true) { + migratedConfig.composerIgnorePlatformReqs = []; + } else if (val === false) { + migratedConfig.composerIgnorePlatformReqs = null; + } } const migratedTemplates = { fromVersion: 'currentVersion', diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index b796b0990d..1bacce70bf 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -298,10 +298,10 @@ const options: RenovateOptions[] = [ { name: 'composerIgnorePlatformReqs', description: - 'Enable / disable use of --ignore-platform-reqs in the Composer package manager.', - type: 'boolean', - default: true, - globalOnly: true, + 'Configure use of `--ignore-platform-reqs`/`--ignore-platform-req` for the Composer package manager.', + type: 'array', + subType: 'string', + default: [], }, // Log options { diff --git a/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap b/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap index f814fe495b..c9f2c54c08 100644 --- a/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap +++ b/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap @@ -1,5 +1,29 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`manager/composer/artifacts adds all ignorePlatformReq items 1`] = ` +Array [ + Object { + "cmd": "composer update --with-dependencies --ignore-platform-req ext-posix --ignore-platform-req ext-sodium --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "LANG": "en_US.UTF-8", + "LC_ALL": "en_US", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + "maxBuffer": 10485760, + "timeout": 900000, + }, + }, +] +`; + exports[`manager/composer/artifacts catches errors 1`] = ` Array [ Object { diff --git a/lib/manager/composer/artifacts.spec.ts b/lib/manager/composer/artifacts.spec.ts index c382cc80c0..c8d8f13b76 100644 --- a/lib/manager/composer/artifacts.spec.ts +++ b/lib/manager/composer/artifacts.spec.ts @@ -24,7 +24,7 @@ jest.mock('../../util/git'); const datasource = mocked(_datasource); const config: UpdateArtifactsConfig = { - composerIgnorePlatformReqs: true, + composerIgnorePlatformReqs: [], ignoreScripts: false, }; @@ -337,7 +337,29 @@ describe('manager/composer/artifacts', () => { newPackageFileContent: '{}', config: { ...config, - composerIgnorePlatformReqs: false, + composerIgnorePlatformReqs: null, + }, + }) + ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); + }); + + it('adds all ignorePlatformReq items', async () => { + fs.readLocalFile.mockResolvedValueOnce('{}'); + const execSnapshots = mockExecAll(exec); + fs.readLocalFile.mockResolvedValueOnce('{ }'); + git.getRepoStatus.mockResolvedValue({ + ...repoStatus, + modified: ['composer.lock'], + }); + expect( + await composer.updateArtifacts({ + packageFileName: 'composer.json', + updatedDeps: [], + newPackageFileContent: '{}', + config: { + ...config, + composerIgnorePlatformReqs: ['ext-posix', 'ext-sodium'], }, }) ).not.toBeNull(); diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts index eb307b1a4e..17320ab165 100644 --- a/lib/manager/composer/artifacts.ts +++ b/lib/manager/composer/artifacts.ts @@ -134,7 +134,13 @@ export async function updateArtifacts({ ).trim() + ' --with-dependencies'; } if (config.composerIgnorePlatformReqs) { - args += ' --ignore-platform-reqs'; + if (config.composerIgnorePlatformReqs.length === 0) { + args += ' --ignore-platform-reqs'; + } else { + config.composerIgnorePlatformReqs.forEach((req) => { + args += ' --ignore-platform-req ' + quote(req); + }); + } } args += ' --no-ansi --no-interaction'; if (!getGlobalConfig().allowScripts || config.ignoreScripts) { diff --git a/lib/manager/types.ts b/lib/manager/types.ts index 000c830f0d..ef1ba6b9a7 100644 --- a/lib/manager/types.ts +++ b/lib/manager/types.ts @@ -41,7 +41,7 @@ export interface CustomExtractConfig extends ExtractConfig { export interface UpdateArtifactsConfig extends ManagerConfig { isLockFileMaintenance?: boolean; constraints?: Record<string, string>; - composerIgnorePlatformReqs?: boolean; + composerIgnorePlatformReqs?: string[]; currentValue?: string; postUpdateOptions?: string[]; ignoreScripts?: boolean; -- GitLab