Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: openrewrite/rewrite
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: openrewrite/rewrite
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: tim/docker-arg-quoted-values
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 11 commits
  • 19 files changed
  • 1 contributor

Commits on Aug 21, 2026

  1. Docker: model quoted values and $VAR refs for ARG, ENV, WORKDIR, LABEL

    `DockerParserVisitor` had two ways of building a `Docker.Argument`. One
    walked tokens, stripping quotes into `Literal.quoteStyle` and splitting
    `$VAR` out into `Docker.EnvironmentVariable`. The other took the raw
    source substring into a single `Literal` with `quoteStyle = null`, and
    was used by ARG, ENV, WORKDIR, STOPSIGNAL and MAINTAINER.
    
    So `ARG A="x"` produced `Literal(text="\"x\"", quoteStyle=null)`, forcing
    recipes to match the quotes by hand, and `ARG A=$BASE` produced a plain
    `Literal("$BASE")` — meaning `hasEnvironmentVariables()` was false for
    every ARG and ENV, and `extractText()` returned `"$BASE"` as though it
    were a statically known value.
    
    Route all five through the token-walking path and delete the raw one.
    `Docker.Literal` already modelled quote style, and the printer already
    re-emitted quotes from it, so printing is unaffected.
    
    Separately, the `labelValue` grammar rule accepted a single token and
    omitted `ENV_VAR`, so `LABEL L=$VAL` failed the `labelKey EQUALS
    labelValue` alternative and silently fell through to the old-format
    branch, yielding `hasEquals=false` and a value of `["=", $VAL]`. Model it
    as `labelValueElement+` mirroring `envTextEquals`, excluding EQUALS so
    that `LABEL a=1 b=$X c=3` still splits into three pairs.
    
    Add public `getText()`, `getTextWithVariables()`, `getQuoteStyle()` and
    `hasEnvironmentVariables()` to `Docker.Argument`. Equivalent helpers
    existed on the package-private `DockerTraitMatcher`, out of reach of
    recipe authors, and an argument can hold several contents (`a"b"c`), so
    reading `getContents().get(0)` was already wrong. Those helpers now
    delegate, leaving one implementation.
    
    Verified round-trip printing is byte-identical across 142 real
    Dockerfiles, matching the pre-change baseline exactly.
    timtebeek committed Aug 21, 2026
    Configuration menu
    Copy the full SHA
    dd427f9 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    a4991f4 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    75e7715 View commit details
    Browse the repository at this point in the history
  4. Configuration menu
    Copy the full SHA
    628588d View commit details
    Browse the repository at this point in the history
  5. Configuration menu
    Copy the full SHA
    86eba51 View commit details
    Browse the repository at this point in the history
  6. Configuration menu
    Copy the full SHA
    2cbc401 View commit details
    Browse the repository at this point in the history
  7. Treat flag-shaped argument values as text

    Flags are options to commands. A value beginning with "--" inside an ARG,
    WORKDIR or MAINTAINER is not a flag, but the lexer emits `--name=value` as
    a single FLAG token wherever it appears, so such a value reached the model
    as one raw literal: `ARG X=--flag="a b"` kept its quotes, and
    `--flag=$VAR` never yielded an EnvironmentVariable.
    
    Decompose those tokens as text. `=` keeps its key/value meaning only where
    a command's flag value gives it one, so the caller passes that in.
    timtebeek committed Aug 21, 2026
    Configuration menu
    Copy the full SHA
    45669e9 View commit details
    Browse the repository at this point in the history
  8. Keep a value whole rather than splitting it into parts

    A value is one literal holding its source text, so a value spanning
    whitespace stays whole: `LABEL author "John Doe" of ACME` is a single
    literal rather than three, and `ARG X=--flag="a b"` is not taken apart as
    though it were an option to a command.
    
    Quote style is recorded only when the entire value is one quoted token, as
    in `ARG X="a b"`. Where only part of a value is quoted the quotes belong to
    its text, so getText() returns them.
    
    Environment variable references are still split out, since their value
    cannot be resolved from the source.
    
    This drops the fast path that produced the same single literal whenever a
    value happened to contain no quote, variable or comment; the general case
    now does that for every value.
    timtebeek committed Aug 21, 2026
    Configuration menu
    Copy the full SHA
    823b78c View commit details
    Browse the repository at this point in the history
  9. Split variable references out of a value's text, not its tokens

    Splitting on ENV_VAR tokens made the lexer's boundaries decide what counts
    as a variable, and it emits `--name=value` as a single token: the reference
    in `ARG X=--flag=$VAR` sat inside one and went unmodelled, while the one in
    `ARG X=${BASE}-suffix` did not. A value that reads as a literal `--flag=`
    followed by a variable should be modelled that way.
    
    Scan the value's text instead, which drops the token special case entirely.
    What counts as a reference follows the lexer's own ENV_VAR and SPECIAL_VAR
    rules, so `${BASE:-def}` keeps its default, and `$$`, `$1` and lowercase
    `$var` remain text.
    
    Quoting is unaffected: a wholly quoted value still records its style, and a
    partly quoted one still keeps its quotes as text.
    timtebeek committed Aug 21, 2026
    Configuration menu
    Copy the full SHA
    d097b85 View commit details
    Browse the repository at this point in the history
  10. Split variable references out of double-quoted values

    `ENV PATH="/opt/venv/bin:$PATH"` is among the most common lines in a
    Dockerfile, and its reference went unmodelled: a wholly quoted value became
    one literal, so hasEnvironmentVariables() was false and getText() offered
    the text as though it were static. Across 142 real Dockerfiles this covered
    22 of them, and modelling it lifts the references found from 58 to 112.
    
    A quoted value holding a reference is no longer one literal, so by the rule
    already in place its quotes become part of its text:
    
        ARG X="pre $V post"  ->  L<"pre >  V<V>  L< post">
    
    Only double quotes expand. Single quotes are literal in the shell and in
    Docker's own parser, so `'pre $V post'` stays whole, as does an escaped
    `\$`. The scan tracks single-quoted sections, so a value mixing both kinds
    of quoting expands only where it should.
    
    ImageReferences.tagColonIndex now ignores a colon inside quotes. Without
    that, `FROM "alpine:${TAG}"` would split at the colon it no longer holds in
    a single quoted literal, reporting an image name of `"alpine`.
    timtebeek committed Aug 21, 2026
    Configuration menu
    Copy the full SHA
    aa25a61 View commit details
    Browse the repository at this point in the history
  11. Drop the separator handling from Argument's text accessors

    Contents used to carry the whitespace between them in their prefixes, so
    reading a value back had to re-append it. A value is now a single literal
    holding its source text, which puts that whitespace inside the text: no
    content the parser produces has a prefix after the first, across all 142
    Dockerfiles in the corpus I round-trip against.
    timtebeek committed Aug 21, 2026
    Configuration menu
    Copy the full SHA
    5c2911c View commit details
    Browse the repository at this point in the history
Loading