From d200cc224509bbbcd16950769bb12931956d86e2 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sun, 23 Aug 2026 17:09:44 +0200 Subject: [PATCH 1/3] Guard `setup-java`/`setup-node` version matchers on key and scalar `JsonPathMatcher.matches` walks the whole document: for a `..`-prefixed path `find0` starts at `cursorPath.get(0)`, so calling it from `visitMappingEntry` re-visits the enclosing document once per mapping entry. Testing the key name first skips that walk for every entry that cannot match. Visit time on a synthetic workflow, parse excluded, mean of 10 warmed runs: lines=74 0.40 ms -> 0.04 ms lines=284 2.80 ms -> 0.24 ms lines=1124 32.25 ms -> 2.49 ms The unchecked `(Yaml.Scalar) entry.getValue()` is a crash rather than a cost. The path matches the entry regardless of what its value holds, so a sequence value throws `ClassCastException`: java-version: - 11 - 17 Adding `instanceof Yaml.Scalar` leaves those unchanged, matching how the recipes already skip values they cannot interpret. `SetupJavaDistributionReplacerVisitor` carries the same two problems, so it gets the same guards, with the existing `originalDistributions` membership test moved ahead of the matcher for the same reason. --- .../SetupJavaDistributionReplacerVisitor.java | 5 +++- .../github/SetupJavaUpgradeJavaVersion.java | 4 +++- .../github/SetupNodeUpgradeNodeVersion.java | 4 +++- .../SetupJavaAdoptOpenJDKToTemurinTest.java | 21 +++++++++++++++++ .../SetupJavaUpgradeJavaVersionTest.java | 21 +++++++++++++++++ .../SetupNodeUpgradeNodeVersionTest.java | 23 +++++++++++++++++++ 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java b/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java index af4bc3b..4d93972 100644 --- a/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java +++ b/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java @@ -33,7 +33,10 @@ class SetupJavaDistributionReplacerVisitor extends YamlIsoVisitor spec.path(".github/workflows/ci.yml") + ) + ); + } } diff --git a/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java b/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java index 4f643c7..bcff7db 100644 --- a/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java +++ b/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java @@ -246,4 +246,25 @@ void doesNotUpdateVersionInOtherActions() { ) ); } + + @Test + void doesNotUpdateSequenceVersion() { + rewriteRun( + //language=yaml + yaml( + """ + jobs: + build: + steps: + - name: set-up-jdk + uses: actions/setup-java@v2.3.0 + with: + java-version: + - 11 + - 17 + """, + spec -> spec.path(".github/workflows/ci.yml") + ) + ); + } } diff --git a/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java b/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java index 992318a..93f18e8 100644 --- a/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java +++ b/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java @@ -335,4 +335,27 @@ void multipleJobsUpgrade() { ) ); } + + @Test + void doesNotUpdateSequenceVersion() { + rewriteRun( + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-node@v4 + with: + node-version: + - 18 + - 20 + """, + spec -> spec.path(".github/workflows/ci.yml") + ) + ); + } } From a097a067e8c511c72a800ac88dde531c06d847fb Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sun, 23 Aug 2026 17:13:48 +0200 Subject: [PATCH 2/3] Reindent `SetupNodeUpgradeNodeVersionTest` per `.editorconfig` `.editorconfig` sets `ij_continuation_indent_size = 2` for `src/test/java`, and every other test file in the repository follows it. This one used 8-space continuation steps, making it the sole outlier. Whitespace only; the text block contents are unchanged once the incidental indentation is stripped, which the tests confirm. --- .../SetupNodeUpgradeNodeVersionTest.java | 538 +++++++++--------- 1 file changed, 269 insertions(+), 269 deletions(-) diff --git a/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java b/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java index 93f18e8..53cb620 100644 --- a/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java +++ b/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java @@ -33,329 +33,329 @@ public void defaults(RecipeSpec spec) { @Test void upgradeNodeVersion() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '18' - - run: npm ci - - run: npm test - """, - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '24' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '18' + - run: npm ci + - run: npm test + """, + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '24' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void upgradeNodeVersionFromNode20() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '20' - - run: npm ci - - run: npm test - """, - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '24' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + - run: npm ci + - run: npm test + """, + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '24' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void upgradeNodeVersionFromVersionWithPatch() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 - with: - node-version: '18.17.1' - - run: npm ci - - run: npm test - """, - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 - with: - node-version: '24' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: '18.17.1' + - run: npm ci + - run: npm test + """, + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: '24' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void doNotUpgradeAlreadyCurrentVersion() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '24' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '24' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void doNotUpgradeNewerVersion() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '25' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '25' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void ignoreNonVersionValues() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 'lts/*' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void ignoreLatestKeyword() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 'latest' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 'latest' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void customMinimumVersion() { rewriteRun( - spec -> spec.recipe(new SetupNodeUpgradeNodeVersion(20)), - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '18' - - run: npm ci - - run: npm test - """, - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '20' - - run: npm ci - - run: npm test - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + spec -> spec.recipe(new SetupNodeUpgradeNodeVersion(20)), + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '18' + - run: npm ci + - run: npm test + """, + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + - run: npm ci + - run: npm test + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void multipleJobsUpgrade() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '16' - - run: npm test - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '18' - - run: npm run build - """, - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '24' - - run: npm test - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '24' - - run: npm run build - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '16' + - run: npm test + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '18' + - run: npm run build + """, + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '24' + - run: npm test + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '24' + - run: npm run build + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } @Test void doesNotUpdateSequenceVersion() { rewriteRun( - yaml( - """ - name: CI - on: - pull_request: - jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/setup-node@v4 - with: - node-version: - - 18 - - 20 - """, - spec -> spec.path(".github/workflows/ci.yml") - ) + yaml( + """ + name: CI + on: + pull_request: + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-node@v4 + with: + node-version: + - 18 + - 20 + """, + spec -> spec.path(".github/workflows/ci.yml") + ) ); } } From 256126f18c7650d9ac9453d9c4fa980e5d325f89 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sun, 23 Aug 2026 18:10:55 +0200 Subject: [PATCH 3/3] Cover valid matrix versions rather than sequences under `with` A sequence under `with` is not valid GitHub Actions input, so it is not worth covering. Drop those tests. `strategy.matrix.` is valid and common, though, and it is the case the new key comparison actually puts at risk: the key name alone no longer distinguishes a matrix declaration from a step input, so these tests pin down that only the latter is rewritten. That also removes the reason for the `instanceof Yaml.Scalar` guards, which only ever caught the invalid spelling. The one place they were load-bearing was `SetupJavaDistributionReplacerVisitor`, where hoisting the `originalDistributions` test above the matcher let a matrix sequence reach the cast; putting the matcher back in front fixes that without the extra guard, and the matcher was always the expensive half anyway. --- .../github/SetupJavaDistributionReplacerVisitor.java | 5 ++--- .../openrewrite/github/SetupJavaUpgradeJavaVersion.java | 1 - .../openrewrite/github/SetupNodeUpgradeNodeVersion.java | 1 - .../github/SetupJavaAdoptOpenJDKToTemurinTest.java | 8 +++++--- .../github/SetupJavaUpgradeJavaVersionTest.java | 9 +++++---- .../github/SetupNodeUpgradeNodeVersionTest.java | 9 +++++---- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java b/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java index 4d93972..a8ddb6d 100644 --- a/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java +++ b/src/main/java/org/openrewrite/github/SetupJavaDistributionReplacerVisitor.java @@ -34,9 +34,8 @@ class SetupJavaDistributionReplacerVisitor extends YamlIsoVisitor spec.path(".github/workflows/ci.yml") diff --git a/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java b/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java index bcff7db..fca31c0 100644 --- a/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java +++ b/src/test/java/org/openrewrite/github/SetupJavaUpgradeJavaVersionTest.java @@ -248,20 +248,21 @@ void doesNotUpdateVersionInOtherActions() { } @Test - void doesNotUpdateSequenceVersion() { + void doesNotUpdateMatrixVersion() { rewriteRun( //language=yaml yaml( """ jobs: build: + strategy: + matrix: + java-version: [11, 17] steps: - name: set-up-jdk uses: actions/setup-java@v2.3.0 with: - java-version: - - 11 - - 17 + java-version: ${{ matrix.java-version }} """, spec -> spec.path(".github/workflows/ci.yml") ) diff --git a/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java b/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java index 53cb620..1190c49 100644 --- a/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java +++ b/src/test/java/org/openrewrite/github/SetupNodeUpgradeNodeVersionTest.java @@ -337,7 +337,7 @@ void multipleJobsUpgrade() { } @Test - void doesNotUpdateSequenceVersion() { + void doesNotUpdateMatrixVersion() { rewriteRun( yaml( """ @@ -347,12 +347,13 @@ void doesNotUpdateSequenceVersion() { jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18, 20] steps: - uses: actions/setup-node@v4 with: - node-version: - - 18 - - 20 + node-version: ${{ matrix.node-version }} """, spec -> spec.path(".github/workflows/ci.yml") )