Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gomod): add support for package replacements #29575

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

jamietanna
Copy link
Contributor

@jamietanna jamietanna commented Jun 10, 2024

Changes

Modifies the gomod manager to add support for managing package replacements, if present.

Context

As part of #24883, towards being able to solve #29567, we want to add support for managing package replacement with Renovate.

To make it possible for folks using Go modules to be able to take
advantage of Renovate's package replacements, we should add support to
the gomod manager.

This adds support for managing the following updateTypes:

  • minor/patch
  • major
  • digest

For major and digest updates, we need to support the case that we're
performing a replacement, so add an additional check for the
updateType=replacement and whether there's a newMajor or
newDigest.

Additionally, as we're replacing the dependency's name, we want to have
a separate regex capture group for depName, which we can also use for
determining whether there are quotes around the dependency.

As part of #24883.

Documentation (please check one with an [x])

  • I have updated the documentation, or
  • No documentation update is required

How I've tested my work (please select one)

I have verified these changes via:

  • Code inspection only, or
  • Newly added/modified unit tests, or
  • No unit tests but ran on a real repository, or
  • Both unit tests + ran on a real repository

Example PR: jamietanna/renovate-iss-oapi#2

Note: should the Package column be updated in the PR description to be the new package?

@@ -36,11 +35,14 @@ export function updateDependency({
const lineToChange = lines[upgrade.managerData.lineNumber];
logger.trace({ upgrade, lineToChange }, 'go.mod current line');
if (
!lineToChange.includes(depNameNoVersion) &&
!lineToChange.includes(fromPackageNameNoVersion) &&
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also check toPackageNameNoVersion here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends if this code gets executed the "second" time (next run) after a replacement. If so it looks like you need to check both

To make it possible for folks using Go modules to be able to take
advantage of Renovate's package replacements, we should add support to
the `gomod` manager.

This adds support for managing the following `updateType`s:

- minor/patch
- major
- digest

For `major` and `digest` updates, we need to support the case that we're
performing a replacement, so add an additional check for the
`updateType=replacement` and whether there's a `newMajor` or
`newDigest`.

Because we're now managing multiple `depName`s, we should rename this to
`fromPackageName` and `toPackageName`, following how we've done this
with the `hermit` manager.

Additionally, as we're replacing the dependency's name, we want to have
a separate regex capture group for `depName`, which we can also use for
determining whether there are quotes around the dependency.

As part of renovatebot#24883.
@jamietanna jamietanna marked this pull request as ready for review June 10, 2024 16:55
Copy link
Collaborator

@rarkins rarkins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't reviewed the second half yet

lib/modules/manager/gomod/update.ts Outdated Show resolved Hide resolved
@@ -36,11 +35,14 @@ export function updateDependency({
const lineToChange = lines[upgrade.managerData.lineNumber];
logger.trace({ upgrade, lineToChange }, 'go.mod current line');
if (
!lineToChange.includes(depNameNoVersion) &&
!lineToChange.includes(fromPackageNameNoVersion) &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends if this code gets executed the "second" time (next run) after a replacement. If so it looks like you need to check both

lib/modules/manager/gomod/update.ts Outdated Show resolved Hide resolved
Comment on lines -58 to +71
/^(?<depPart>\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/,
/^(?<depPart>\s+[^\s]+[\s]+[=][>]+\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
);
} else {
updateLineExp = regEx(
/^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/,
/^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
);
}
} else if (depType === 'require' || depType === 'indirect') {
if (upgrade.managerData.multiLine) {
updateLineExp = regEx(/^(?<depPart>\s+[^\s]+)(?<divider>\s+)[^\s]+/);
updateLineExp = regEx(
/^(?<depPart>\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
);
} else {
updateLineExp = regEx(
/^(?<depPart>require\s+[^\s]+)(?<divider>\s+)[^\s]+/,
/^(?<depPart>require\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have concerns about these regex changes breaking something. Unfortunately the existing regex isn't documented

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex isn't user-facing is it? I believe it's only used in this file, so - from what I can tell - the usages in this file it seems to be OK, any thoughts on how we can work out if there's any impact? What would you be thinking in terms of documentation here?

Co-authored-by: Rhys Arkins <rhys@arkins.net>
@@ -22,7 +22,7 @@ export function updateDependency({
// newName will be available for replacement
const toPackageName = newName ?? fromPackageName;
// istanbul ignore if: should never happen
if (!fromPackageName || !toPackageName || !upgrade.managerData) {
if (!fromPackageName || !upgrade.managerData) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may need to undo this check to ensure that eslint knows that we've checked this

@jamietanna jamietanna mentioned this pull request Jul 4, 2024
6 tasks
jamietanna added a commit to jamietanna/renovate that referenced this pull request Jul 4, 2024
As part of a prefactor for renovatebot#29575, we should make this change
independently, to make the changes in renovatebot#29575 easier to review.

This is required as we will be adding replacements for `gomod` and so
we'll have both a `fromPackageName` and a `toPackageName`.
@jamietanna
Copy link
Contributor Author

Moved the renaming into #30030 - LMK if there's any more you think we could move out into a separate PR?

@jamietanna jamietanna requested a review from rarkins July 8, 2024 07:37
@jamietanna
Copy link
Contributor Author

jamietanna commented Jul 8, 2024

Sorry, re-requested review a bit early - will fix up

E: think we need both vars to do find/replace

@jamietanna jamietanna marked this pull request as draft July 20, 2024 11:00
@jamietanna jamietanna marked this pull request as ready for review July 20, 2024 11:31
@jamietanna
Copy link
Contributor Author

jamietanna commented Jul 20, 2024

While testing this - here - I've noticed two things:

Package update table

The package updates table presents the old package name with a replacement noted, like so:

Package Type Update Change
github.com/deepmap/oapi-codegen require replacement v1.12.4 -> v2.3.0

Should we instead show the new name?

Package Type Update Change
github.com/deepmap/oapi-codegen -> github.com/oapi-codegen/oapi-codegen require replacement v1.12.4 -> v2.3.0

This is likely a wider change, as it probably impacts other cases where we're doing replacements, so may be worth a separate PR.

gomodUpdateImportPaths

Also, I've noticed that the gomodUpdateImportPaths doesn't seem to be run - it looks like this is because of this line in which we only perform this check on a major update, but in this case, we're performing a major version bump.

Thoughts on whether these are things we should try and close off here before this PR goes in?

lib/modules/manager/gomod/update.ts Outdated Show resolved Hide resolved
lib/modules/manager/gomod/update.ts Outdated Show resolved Hide resolved
@jamietanna
Copy link
Contributor Author

Hmm I need to retry jamietanna/renovate-iss-oapi#2 and check it also works when we update the module import path

@jamietanna
Copy link
Contributor Author

OK, so retrying with an update to my test repo, I see jamietanna/renovate-iss-oapi#5 raised which does not take the postUpdateOptions into account 🤔

@jamietanna
Copy link
Contributor Author

Adding support for that looks like it could be a little more involved - separate PR?

@jamietanna
Copy link
Contributor Author

(This isn't yet working - I can't seem to trigger the postUpdateOptions for https://github.com/jamietanna/renovate-iss-oapi

@jamietanna
Copy link
Contributor Author

Any thoughts on why we may not be able to see postUpdateOptions working? 🤔

@@ -31,7 +31,7 @@ import { getExtraDepsNotice } from './artifacts-extra';
const { major, valid } = semver;

function getUpdateImportPathCmds(
updatedDeps: PackageDependency[],
updatedDeps: Upgrade[],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't quite correct, and why things aren't working

@@ -31,7 +31,7 @@ import { getExtraDepsNotice } from './artifacts-extra';
const { major, valid } = semver;

function getUpdateImportPathCmds(
updatedDeps: PackageDependency[],
updatedDeps: Upgrade[],
{ constraints }: UpdateArtifactsConfig,
): string[] {
// Check if we fail to parse any major versions and log that they're skipped
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, when we're seeing a replacement, we get the wrong data here 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants