diff --git a/lib/modules/manager/gomod/extract.spec.ts b/lib/modules/manager/gomod/extract.spec.ts index 0ca53a8a7304b87a1cbd3167e59679cce087a025..49f87ee7b68a7bf05c0dcb25016ae739d999ad7a 100644 --- a/lib/modules/manager/gomod/extract.spec.ts +++ b/lib/modules/manager/gomod/extract.spec.ts @@ -40,5 +40,78 @@ describe('modules/manager/gomod/extract', () => { expect(res).toHaveLength(58); expect(res?.filter((e) => e.skipReason)).toHaveLength(0); }); + + it('extracts replace directives from multi-line and single line', () => { + const goMod = ` +module github.com/renovate-tests/gomod +go 1.18 +replace golang.org/x/foo => github.com/pravesht/gocql v0.0.0 +replace ( + k8s.io/client-go => k8s.io/client-go v0.21.9 + ) +replace ( + k8s.io/cloud-provider => k8s.io/cloud-provider v0.17.3 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.17.3 // indirect + k8s.io/code-generator => k8s.io/code-generator v0.17.3 +)`; + const res = extractPackageFile(goMod); + expect(res).toEqual({ + constraints: { + go: '^1.18', + }, + deps: [ + { + managerData: { + lineNumber: 2, + }, + depName: 'go', + depType: 'golang', + currentValue: '1.18', + datasource: 'golang-version', + versioning: 'npm', + rangeStrategy: 'replace', + }, + { + managerData: { + lineNumber: 3, + }, + depName: 'github.com/pravesht/gocql', + depType: 'replace', + currentValue: 'v0.0.0', + datasource: 'go', + }, + { + managerData: { + lineNumber: 5, + multiLine: true, + }, + depName: 'k8s.io/client-go', + depType: 'replace', + currentValue: 'v0.21.9', + datasource: 'go', + }, + { + managerData: { + lineNumber: 8, + multiLine: true, + }, + depName: 'k8s.io/cloud-provider', + depType: 'replace', + currentValue: 'v0.17.3', + datasource: 'go', + }, + { + managerData: { + lineNumber: 10, + multiLine: true, + }, + depName: 'k8s.io/code-generator', + depType: 'replace', + currentValue: 'v0.17.3', + datasource: 'go', + }, + ], + }); + }); }); }); diff --git a/lib/modules/manager/gomod/extract.ts b/lib/modules/manager/gomod/extract.ts index 61d30af520d20bd07900be1deae75219836a9026..5bfe991295199c50598088a2fb06a75e82adb667 100644 --- a/lib/modules/manager/gomod/extract.ts +++ b/lib/modules/manager/gomod/extract.ts @@ -88,6 +88,17 @@ export function extractPackageFile(content: string): PackageFile | null { ); lineNumber = reachedLine; deps.push(...detectedDeps); + } else if (line.trim() === 'replace (') { + logger.trace(`Matched multi-line replace on line ${lineNumber}`); + const matcher = regEx(/^\s+[^\s]+[\s]+[=][>]\s+([^\s]+)\s+([^\s]+)/); + const { reachedLine, detectedDeps } = parseMultiLine( + lineNumber, + lines, + matcher, + 'replace' + ); + lineNumber = reachedLine; + deps.push(...detectedDeps); } } } catch (err) /* istanbul ignore next */ { diff --git a/lib/modules/manager/gomod/update.spec.ts b/lib/modules/manager/gomod/update.spec.ts index 6b80f5893d13a31f93b6a35d78499b7922acfc02..0f1fb82db767909d950f47eb792de19c2a7bce07 100644 --- a/lib/modules/manager/gomod/update.spec.ts +++ b/lib/modules/manager/gomod/update.spec.ts @@ -318,6 +318,26 @@ describe('modules/manager/gomod/update', () => { expect(res).toContain('github.com/caarlos0/env/v6 v6.1.0'); }); + it('handles multiline replace update', () => { + const fileContent = ` + go 1.18 + replace ( + k8s.io/client-go => k8s.io/client-go v0.21.9 + )`; + const upgrade = { + depName: 'k8s.io/client-go', + managerData: { lineNumber: 3, multiLine: true }, + newValue: 'v2.2.2', + depType: 'replace', + currentValue: 'v0.21.9', + newMajor: 2, + updateType: 'major' as UpdateType, + }; + const res = updateDependency({ fileContent, upgrade }); + expect(res).not.toEqual(fileContent); + expect(res).toContain('k8s.io/client-go/v2 => k8s.io/client-go v2.2.2'); + }); + it('should return null for replacement', () => { const res = updateDependency({ fileContent: '', diff --git a/lib/modules/manager/gomod/update.ts b/lib/modules/manager/gomod/update.ts index f6abe980c6d12afc232d71c94fc1cc50eeb4f1b2..de7f06b346ffdce6f5f05201604d4e16e6aa650d 100644 --- a/lib/modules/manager/gomod/update.ts +++ b/lib/modules/manager/gomod/update.ts @@ -46,9 +46,15 @@ export function updateDependency({ updateLineExp = regEx(/(?<depPart>go)(?<divider>\s+)[^\s]+/); } if (depType === 'replace') { - updateLineExp = regEx( - /^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/ - ); + if (upgrade.managerData.multiLine) { + updateLineExp = regEx( + /^(?<depPart>\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/ + ); + } else { + updateLineExp = regEx( + /^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/ + ); + } } else if (depType === 'require') { if (upgrade.managerData.multiLine) { updateLineExp = regEx(/^(?<depPart>\s+[^\s]+)(?<divider>\s+)[^\s]+/);