Docker: one definition of the registry in an image reference - #8599
Merged
Conversation
Whether the first path component of an image name is a registry cannot be decided from the syntax: `mcr.microsoft.com/windows/servercore` names a registry, while `redhat/ubi9-minimal` names an organisation on Docker Hub. Docker resolves this by treating the component as a registry only when it holds a `.` or a `:`, is exactly `localhost`, or carries an uppercase character, which a path component may not. `ImageName` applies that rule once, decomposing a name into its registry, namespace and repository and giving the two other spellings of the same image: the familiar one that drops a Docker Hub prefix, and the canonical one that writes it out. `DockerImageReference` exposes it, so a `FROM` and a `COPY --from` are served by the same implementation. That replaces `NormalizeDockerHubImageName`'s own regular expression and `EolImage`'s own `library/` prefix strip, adds a registry column to the base image data table, and lets an image name pattern match a name that spells the same image differently, so `ubuntu` finds `docker.io/library/ubuntu` and the other way round.
Familiarizing the pattern as well as the name dropped a registry the pattern wrote, so `docker.io/*`, `library/*` and `docker.io/library/*` all collapsed to `*` and matched every image on every registry. Only the canonical spelling, which fills in what a name leaves out rather than dropping what a pattern states, can be compared. `ChangeFrom` captures its backrefs from that spelling for the same reason.
timtebeek
marked this pull request as ready for review
August 21, 2026 23:09
timtebeek
added a commit
to openrewrite/rewrite-migrate-java
that referenced
this pull request
Aug 22, 2026
…ns (#1213)" (#1215) This reverts commit d33eca3. The recipe reached for rewrite-docker API that no released version of rewrite carries yet. `Docker.Argument.getText()`, `getTextWithVariables()` and `hasEnvironmentVariables()` arrived in openrewrite/rewrite#8576, and `org.openrewrite.docker.trait.ImageName` in openrewrite/rewrite#8599, both landed 2026-08-21, one day after v8.90.3. The Moderne CLI loads the LST classes in its own classloader, so a recipe runs against the rewrite-docker the CLI bundles rather than the one this artifact resolves. CLI 4.6.3 bundles rewrite-docker 8.90.3, where `Docker.Argument` exposes only `getContents()` and `ImageName` does not exist. `visitFile` reads a global `ARG` through `getText()` and `visitFrom` opens with `hasEnvironmentVariables()`, so the first `FROM` of every Dockerfile would raise `NoSuchMethodError`, surfacing as error markup on every Dockerfile of every `UpgradeToJava*` run. Nothing is lost by waiting: v3.42.1 predates this commit, so the breakage has not shipped. The state restored here is the #1212 fix, which reads an image reference through `DockerFrom` alone and so links against 8.90.3. Reapplied in a follow-up PR, to merge once a rewrite release carries #8576, #8590 and #8599 and the CLI picks it up.
timtebeek
added a commit
to openrewrite/rewrite-migrate-java
that referenced
this pull request
Aug 22, 2026
… for rewrite release) (#1216) * Revert "Upgrade `ARG` default values used in Docker `FROM` instructions (#1213)" This reverts commit d33eca3. The recipe reached for rewrite-docker API that no released version of rewrite carries yet. `Docker.Argument.getText()`, `getTextWithVariables()` and `hasEnvironmentVariables()` arrived in openrewrite/rewrite#8576, and `org.openrewrite.docker.trait.ImageName` in openrewrite/rewrite#8599, both landed 2026-08-21, one day after v8.90.3. The Moderne CLI loads the LST classes in its own classloader, so a recipe runs against the rewrite-docker the CLI bundles rather than the one this artifact resolves. CLI 4.6.3 bundles rewrite-docker 8.90.3, where `Docker.Argument` exposes only `getContents()` and `ImageName` does not exist. `visitFile` reads a global `ARG` through `getText()` and `visitFrom` opens with `hasEnvironmentVariables()`, so the first `FROM` of every Dockerfile would raise `NoSuchMethodError`, surfacing as error markup on every Dockerfile of every `UpgradeToJava*` run. Nothing is lost by waiting: v3.42.1 predates this commit, so the breakage has not shipped. The state restored here is the #1212 fix, which reads an image reference through `DockerFrom` alone and so links against 8.90.3. Reapplied in a follow-up PR, to merge once a rewrite release carries #8576, #8590 and #8599 and the CLI picks it up. * Upgrade `ARG` default values used in Docker `FROM` instructions Reapplies #1213, reverted in #1215 because the rewrite-docker API it reads `ARG` defaults through had not been released yet. Hold until a rewrite release carries openrewrite/rewrite#8576 (the `Docker.Argument` accessors), #8590 (the image reference grammar) and #8599 (`ImageName`), and confirm the Moderne CLI bundles that release, as the CLI loads the LST classes in its own classloader and so decides which rewrite-docker a recipe actually links against. * Revert "Merge branch 'main' into tim/docker-arg-defaults-redo" This reverts commit 901210a, keeping the branch side. Merging main in pulled #1215 across, and #1215 is the revert of the very commit this branch exists to reapply. The merge base still carried the `ARG` work and main had removed it, so the merge resolved to main's removal and emptied the branch: `git diff main...HEAD` came back with nothing, leaving the pull request proposing no change at all. Reverting the merge rather than dropping it also settles the branch. The merge stays in history, so main's revert counts as already merged here and undone on purpose. A later `main` merge brings its new commits without resurrecting the removal, which resetting the branch would leave it open to on the next `Update branch`. * Read an argument's text through `ArgumentContents` openrewrite/rewrite#8608 moves `getText()`, `getTextWithVariables()`, `getQuoteStyle()` and `hasEnvironmentVariables()` off `Docker.Argument` and into `org.openrewrite.docker.internal.ArgumentContents`, then drops them from the LST type. That matters because of how the Moderne CLI splits one rewrite-docker jar across two classloaders: `org.openrewrite.docker.tree` resolves to the rewrite-docker the CLI bundles, while recipes, traits and `internal` load child-first from the recipe artifact. Reading an argument through the LST type therefore linked against the CLI's copy, which is where #1215 came from. The helpers now sit on the recipe's side of that split and read only members that predate the CLIs in the field, so they travel with this artifact. `ImageName` already sits on that side, so it needed no change. Verified against the pull request rather than assumed: rewrite-docker built at 6f5fd253 and published locally, and every one of the fifteen `org.openrewrite.docker.tree` members this recipe links against confirmed present in the 8.90.3 jar CLI 4.6.3 bundles, matching on descriptor.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Whether the first path component of an image name is a registry cannot be decided from the syntax —
mcr.microsoft.com/windows/servercorenames a registry, whileredhat/ubi9-minimalnames an organisation on Docker Hub — so this stays out of the grammar and applies Docker's own rule (a registry only when the component holds a.or a:, is exactlylocalhost, or carries an uppercase character) once, in a newImageNamevalue object that decomposes a name into its registry, namespace and repository and gives the familiar and canonical spellings of the same image.DockerImageReferenceexposes it throughgetImage(),getRegistry(),getFamiliarImageName()andgetCanonicalImageName(), so aFROMand aCOPY --fromare served by one implementation; that replacesNormalizeDockerHubImageName's own regular expression andEolImage's ownlibrary/prefix strip, and adds a registry column to the base image data table.Image name matching now also matches a name that spells the same image differently, so
ubuntufindsdocker.io/library/ubuntuand the other way round; this is a strict superset of what matched before, andChangeFromcaptures a$Nbackref from whichever spelling matched.NormalizeDockerHubImageNamealso gains two fixes along the way: it now normalizes a barelibrary/ubuntu, and it keeps anEnvironmentVariablenode in the image name rather than flattening it to a literal.Verified beyond the suite by decomposing every
FROMin a 335-Dockerfiledocker-librarycorpus: 350 named references, no round-trip loss, andredhat/ubi9-minimalcorrectly classified as implicitdocker.iorather than a registry.