From 91812d025da748722777156da936d07e205cf0d9 Mon Sep 17 00:00:00 2001 From: Jorge Silva <jorgesilva.me@gmail.com> Date: Tue, 18 Apr 2023 05:55:28 +0100 Subject: [PATCH] feat(manager/gomod): add `goGetDirs` option (#20156) Co-authored-by: Rhys Arkins <rhys@arkins.net> Co-authored-by: Michael Kriese <michael.kriese@visualon.de> Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com> --- docs/usage/configuration-options.md | 11 ++ docs/usage/golang.md | 2 +- lib/config/options/index.ts | 8 ++ lib/modules/manager/gomod/artifacts.spec.ts | 110 +++++++++++++++++++- lib/modules/manager/gomod/artifacts.ts | 22 +++- lib/modules/manager/types.ts | 1 + 6 files changed, 151 insertions(+), 3 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 775d6aad22..690946388f 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -1040,6 +1040,17 @@ Under the hood, it creates a MR-level approval rule where `approvals_required` i This option works only when `automerge=true`, `automergeType=pr` or `automergeType=branch`, and `platformAutomerge=true`. Also, approval rules overriding should not be [prevented in GitLab settings](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/settings.html#prevent-editing-approval-rules-in-merge-requests). +## goGetDirs + +By default, Renovate will run `go get -d -t ./...` to update the `go.sum`. +If you need to modify this path, for example in order to ignore directories, you can override the default `./...` value using this option: + +```json +{ + "goGetDirs": ["./some-project/", "./tools/..."] +} +``` + ## golang Configuration added here applies for all Go-related updates. diff --git a/docs/usage/golang.md b/docs/usage/golang.md index 705e294f20..fd560949a9 100644 --- a/docs/usage/golang.md +++ b/docs/usage/golang.md @@ -13,7 +13,7 @@ Renovate supports upgrading dependencies in `go.mod` files and their accompanyin 1. Renovate extracts existing dependencies from `require` statements 1. Renovate resolves the dependency's source repository and checks for SemVer tags if found. Otherwise commits and `v0.0.0-....` syntax will be used 1. If Renovate finds an update, Renovate will update `go.mod` to the new value -1. Renovate runs `go get` to update the `go.sum` files +1. Renovate runs `go get` to update the `go.sum` files (you can configure which directory are included using the `goGetDirs` option) 1. If the user has enabled the option `gomodUpdateImportPaths` in the [`postUpdateOptions`](https://docs.renovatebot.com/configuration-options/#postupdateoptions) array, then Renovate uses [mod](https://github.com/marwan-at-work/mod) to update import paths on major updates, which can update any Go source file 1. If the user has any of the available `gomodTidy` options (e.g. `gomodTidy1.17`) in the [`postUpdateOptions`](https://docs.renovatebot.com/configuration-options/#postupdateoptions), then Renovate runs `go mod tidy` with the respective options (multiple options are allowed). 1. `go mod vendor` is run if vendored modules are detected diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 4702833112..ae357e8d09 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -366,6 +366,14 @@ const options: RenovateOptions[] = [ subType: 'string', default: [], }, + { + name: 'goGetDirs', + description: 'Directory pattern to run `go get` on', + type: 'array', + subType: 'string', + default: ['./...'], + supportedManagers: ['gomod'], + }, // Log options { name: 'logFile', diff --git a/lib/modules/manager/gomod/artifacts.spec.ts b/lib/modules/manager/gomod/artifacts.spec.ts index 667eee6bdd..22cfc117b7 100644 --- a/lib/modules/manager/gomod/artifacts.spec.ts +++ b/lib/modules/manager/gomod/artifacts.spec.ts @@ -15,7 +15,17 @@ jest.mock('../../../util/exec/env'); jest.mock('../../../util/git'); jest.mock('../../../util/host-rules'); jest.mock('../../../util/http'); -jest.mock('../../../util/fs'); +jest.mock('../../../util/fs', () => { + // restore + return { + __esModules: true, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + ...(jest.createMockFromModule('../../../util/fs') as any), + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + isValidLocalPath: (jest.requireActual('../../../util/fs') as any) + .isValidLocalPath, + }; +}); jest.mock('../../datasource'); process.env.BUILDPACK = 'true'; @@ -1939,4 +1949,102 @@ describe('modules/manager/gomod/artifacts', () => { ]; expect(execSnapshots).toMatchObject(expectedResult); }); + + it('handles goGetDirs configuration correctly', async () => { + fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); + fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename + const execSnapshots = mockExecAll(); + git.getRepoStatus.mockResolvedValueOnce( + partial<StatusResult>({ + modified: [], + }) + ); + + expect( + await gomod.updateArtifacts({ + packageFileName: 'go.mod', + updatedDeps: [], + newPackageFileContent: gomod1, + config: { + ...config, + goGetDirs: ['.', 'foo', '.bar/...', '&&', 'cat', '/etc/passwd'], + }, + }) + ).toBeNull(); + expect(execSnapshots).toMatchObject([ + { + cmd: 'go get -d -t . foo .bar/... cat', + options: { + cwd: '/tmp/github/some/repo', + }, + }, + ]); + }); + + it('returns updated go.sum when goGetDirs is specified', async () => { + fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); + fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename + const execSnapshots = mockExecAll(); + git.getRepoStatus.mockResolvedValueOnce( + partial<StatusResult>({ + modified: ['go.sum'], + }) + ); + fs.readLocalFile.mockResolvedValueOnce('New go.sum'); + fs.readLocalFile.mockResolvedValueOnce(gomod1); + expect( + await gomod.updateArtifacts({ + packageFileName: 'go.mod', + updatedDeps: [], + newPackageFileContent: gomod1, + config: { + ...config, + goGetDirs: ['.'], + }, + }) + ).toEqual([ + { + file: { + contents: 'New go.sum', + path: 'go.sum', + type: 'addition', + }, + }, + ]); + expect(execSnapshots).toMatchObject([ + { + cmd: 'go get -d -t .', + options: { + cwd: '/tmp/github/some/repo', + }, + }, + ]); + }); + + it('errors when goGetDirs is specified with all invalid paths', async () => { + fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); + fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename + const execSnapshots = mockExecAll(); + git.getRepoStatus.mockResolvedValueOnce( + partial<StatusResult>({ + modified: ['go.sum'], + }) + ); + fs.readLocalFile.mockResolvedValueOnce('New go.sum'); + fs.readLocalFile.mockResolvedValueOnce(gomod1); + expect( + await gomod.updateArtifacts({ + packageFileName: 'go.mod', + updatedDeps: [], + newPackageFileContent: gomod1, + config: { + ...config, + goGetDirs: ['&&', '||'], + }, + }) + ).toEqual([ + { artifactError: { lockFile: 'go.sum', stderr: 'Invalid goGetDirs' } }, + ]); + expect(execSnapshots).toMatchObject([]); + }); }); diff --git a/lib/modules/manager/gomod/artifacts.ts b/lib/modules/manager/gomod/artifacts.ts index 6ef9025014..0b6de5e39d 100644 --- a/lib/modules/manager/gomod/artifacts.ts +++ b/lib/modules/manager/gomod/artifacts.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import semver from 'semver'; +import { quote } from 'shlex'; import upath from 'upath'; import { GlobalConfig } from '../../../config/global'; import type { PlatformId } from '../../../constants'; @@ -10,6 +11,7 @@ import { exec } from '../../../util/exec'; import type { ExecOptions } from '../../../util/exec/types'; import { ensureCacheDir, + isValidLocalPath, readLocalFile, writeLocalFile, } from '../../../util/fs'; @@ -296,7 +298,25 @@ export async function updateArtifacts({ const execCommands: string[] = []; - let args = 'get -d -t ./...'; + let goGetDirs: string | undefined; + if (config.goGetDirs) { + goGetDirs = config.goGetDirs + .filter((dir) => { + const isValid = isValidLocalPath(dir); + if (!isValid) { + logger.warn({ dir }, 'Invalid path in goGetDirs'); + } + return isValid; + }) + .map(quote) + .join(' '); + + if (goGetDirs === '') { + throw new Error('Invalid goGetDirs'); + } + } + + let args = `get -d -t ${goGetDirs ?? './...'}`; logger.trace({ cmd, args }, 'go get command included'); execCommands.push(`${cmd} ${args}`); diff --git a/lib/modules/manager/types.ts b/lib/modules/manager/types.ts index abd361b4b1..c81b729d1c 100644 --- a/lib/modules/manager/types.ts +++ b/lib/modules/manager/types.ts @@ -33,6 +33,7 @@ export interface UpdateArtifactsConfig { isLockFileMaintenance?: boolean; constraints?: Record<string, string>; composerIgnorePlatformReqs?: string[]; + goGetDirs?: string[]; currentValue?: string; postUpdateOptions?: string[]; ignorePlugins?: boolean; -- GitLab