Skip to content

ci: port PR validation to GitHub Actions - #9441

Open
vaadin-bot wants to merge 12 commits into
mainfrom
ci/pr-validation-github-actions
Open

vaadin-bot wants to merge 12 commits into
mainfrom
ci/pr-validation-github-actions

Conversation

@vaadin-bot

Copy link
Copy Markdown
Contributor

Ports the two TeamCity builds that validate platform PRs — "Vaadin Platform PR validation" (bt210) and "Vaadin Platform PR validation (gradle)" (bt232) — into a single workflow, .github/workflows/pr-validation.yml.

Both TeamCity configs are the same 26-step template and differ only in which steps are enabled, so they become the two suite entries of a validate matrix. The Maven ITs and the Gradle test project run in parallel, each doing its own mvn install, the way the two TeamCity builds do on two agents.

ported to
steps 1-2 (CI rights, skip-ci) job guard
steps 3-5, 9-11 (BOMs, versions:set, install) validate, both suites
step 15 (npm ITs), step 25 (bower tests) validate, suite: maven
step 17 (gradle build), step 18 (jna check) validate, suite: gradle

Every step is mapped in a comment block at the top of the file, including the ones deliberately dropped.

Deviations from TeamCity

All marked DEVIATION in the workflow:

  • No Selenium grid, no Sauce Connect. The ITs use the Chrome preinstalled on the runner, so they cover one browser where the grid fanned them out across a browser set. For the Gradle suite that means leaving hubHostname unset, which makes TestBench fall back to a local Chrome — passing runLocally would not work, since build.gradle forwards only testsInParallel, test.use.hub and hubHostname into the test JVM.
  • CI-rights check reads author_association from the PR payload instead of calling /collaborators with a bot PAT.
  • TestBench licence comes from secrets.TB_LICENSE written to ~/.vaadin/proKey, as sbom.yml and pit.yml already do. TeamCity keeps it in an agent-wide parameter that every step inherits.
  • Java and node versions are pinned, not probed — TeamCity's build config is shared across branches (1.8/11/17/21), this workflow is not.
  • Not ported: the Java 8/11 and OSGi steps, everything already disabled in TeamCity, and the agent housekeeping in steps 3 and 26 (runners are ephemeral).

Left out for now

Steps 7 and 8, the version consistency test. Both are inert in TeamCity today — build #7711 has their node commands echo skip:-ed out — so porting them would only report on a state nobody is acting on. They want a job of their own whenever that changes, since they need neither the Maven build nor its local repository.

Notes for review

  • The duplicated mvn install costs runner minutes, not wall clock: the two suites install concurrently. Sharing it via a cached ~/.m2 would make PR feedback slower, because the Maven ITs also reuse the warm target/ and node_modules/ that the install leaves in the working tree.
  • Opening this PR exercises the workflow on itself, so the run on this PR is the first real test of both suites.

🤖 Generated with Claude Code

ZheSun88 and others added 3 commits September 15, 2026 08:54
Ports the two TeamCity builds that validate platform PRs — "Vaadin
Platform PR validation" (bt210) and "Vaadin Platform PR validation
(gradle)" (bt232) — into one workflow. Both configs are the same
26-step template and only differ in which steps are enabled, so they
become the two `suite` entries of a `validate` matrix: the Maven ITs
and the Gradle test project run in parallel, each doing its own
`mvn install`, the way the two TeamCity builds do on two agents.

The shared part (steps 1-11) is the contributor CI-rights and skip-ci
guard, BOM generation, `versions:set 99.0-SNAPSHOT` and the production
install. The Maven suite then runs step 15's ITs plus step 25's bower
tests on branches that still declare `bower-it`; the Gradle suite runs
step 17 (`./gradlew clean build`) and step 18 (the mismatched-jna
check).

Deviations from TeamCity, all commented in the workflow:

- The ITs use the Chrome preinstalled on the runner instead of the
  internal Selenium grid and the Sauce Connect tunnel around it, so
  they cover one browser where the grid fanned them out over a set.
  For the Gradle suite this means leaving `hubHostname` unset, which
  makes TestBench fall back to a local Chrome; passing `runLocally`
  would not work, as build.gradle forwards only `testsInParallel`,
  `test.use.hub` and `hubHostname` into the test JVM.
- The CI-rights check reads `author_association` from the PR payload
  rather than calling /collaborators with a bot PAT.
- TeamCity holds the TestBench licence in an agent-wide parameter that
  every step inherits; here it is written once to ~/.vaadin/proKey
  from secrets.TB_LICENSE, as sbom.yml and pit.yml already do.
- Java and node versions are pinned instead of probed, since this
  workflow lives on one branch. Steps that only exist for older
  branches (Java 8/11 builds, OSGi) and the disabled TeamCity steps
  are not ported, nor is the agent housekeeping of steps 3 and 26.

Steps 7 and 8, the version consistency test, are left out for now:
both are inert in TeamCity today, their node commands being
`echo skip:`-ed out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both suites failed in run #34934763370 with

  SessionNotCreatedException: session not created: Chrome instance exited

on every test — 178 Maven ITs and all 10 Gradle ITs. The runner has no X
display, and TestBench's local-driver path starts a plain, non-headless
Chrome, so the browser exits the moment it launches. TeamCity never hit
this: it points both suites at the internal Selenium grid, so no browser
has ever started on the build machine itself.

Wraps the three browser steps in `xvfb-run -a` and prints the Chrome and
xvfb-run locations in the environment info.

Xvfb rather than -Dcom.vaadin.testbench.Parameters.headless=true, which
TestBench does support, because build.gradle forwards only
testsInParallel, test.use.hub, the licence and hubHostname into the test
JVM — a system property set on the gradlew command line would never
reach TestBench. One mechanism for both suites is worth more here than
saving the virtual display.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`build-frontend` fails for vaadin-platform-react-hybrid-test-prod with

  Failed to generate OpenAPI spec: Failed to find browser-callable classes

Hilla discovers endpoints by forking Spring Boot's
SpringApplicationAotProcessor and reading the reachability-metadata.json
it produces. That process exits 1, and its report says why:

  SLF4J(W): Class path contains multiple SLF4J providers.
  SLF4J(W): Found provider [org.slf4j.simple.SimpleServiceProvider]
  SLF4J(W): Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider]
  SLF4J(I): Actual provider is of type [org.slf4j.simple.SimpleServiceProvider]
  Exception in thread "main" java.lang.IllegalStateException: LoggerFactory is
  not a Logback LoggerContext but Logback is on the classpath.

Both modules declare slf4j-simple as their provider but excluded
logback-classic from spring-boot-starter-web only, so Logback still
arrived through vaadin-spring-boot-starter, hilla-spring-boot-starter and
(in the security module) the security and validation starters. With two
providers present, which one wins is classpath-order dependent: when
slf4j-simple wins, Spring Boot's LogbackLoggingSystem asserts and the AOT
processor dies, taking Hilla's endpoint discovery with it.

Excludes spring-boot-starter-logging — logback-classic plus the
log4j/jul bridges — from every Spring Boot starter in both modules, so
slf4j-simple is the only provider regardless of classpath order.

This is why TeamCity has been green on commits that fail on GitHub
Actions: the two CIs land on opposite sides of that election, so the bug
is latent on TeamCity rather than absent. Neither module has a
simplelogger.properties or logback.xml, so no logging config changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ZheSun88
ZheSun88 force-pushed the ci/pr-validation-github-actions branch from cf058a2 to 1e68129 Compare September 15, 2026 07:37
@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Dependencies Report

  • 🚫 Vulnerabilities:

  • 🟠 Known Vulnerabilities:

    • Vulnerabilities in: pkg:npm/%40apidevtools/json-schema-ref-parser@11.7.2 [CVE-2026-15195] (oss-bomber)
      👌 The cve carries a git only range with no version mapping. The affected releases are 15.3.0 to 15.3.5, fixed in 15.3.6, while 11.7.2 predates that line by 17 months. It arrives through swagger-parser 10.1.1, which pins it exactly.
      ·
    • Vulnerabilities in: pkg:npm/source-map-js@1.2.1 [CVE-2026-93749] (oss-bomber)
      👌 Build-time only: source-map-js is a dev dependency of postcss used by Vite during build/dev and is not shipped in production bundles. Exploitation requires feeding a crafted indexed source map into the developer's own build (event-loop DoS only). No fixed version is published on npm yet (1.2.1 is latest); upgrade once available.
      ·
    • Vulnerabilities in: pkg:maven/me.friwi/jcef-api@jcef-ca49ada%2Bcef-135.0.20%2Bge7de5c3%2Bchromium-135.0.7049.85 [CVE-2024-21639, CVE-2024-21640, CVE-2024-9410] (owasp)
      👌 Wait for the update from the jcefmaven community. Meanwhile the swing-kit is supposed to be used with fixed websites and not to browse the internet, we have a check for that, so the only possible attacker would be the same person that created the swing application, aka our customer devs. so this vulnerability is not classified by us as critical issue
      · cpe:2.3:a:chromiumembedded:chromium_embedded_framework::::::::
      · cpe:2.3:a:ada:ada::::::::
    • Vulnerabilities in: pkg:maven/io.opentelemetry/opentelemetry-api@1.65.0 [CVE-2026-54285] (owasp)
      👌 False positive: the advisory is for opentelemetry-js (@opentelemetry/core W3CBaggagePropagator.extract(), fixed in JS 2.8.0) and its only CPE targets node.js. io.opentelemetry is opentelemetry-java, an unrelated codebase on its own 1.x line, so the version range matches only by CPE collision; osv-scanner and ossindex report nothing for this coordinate. It reaches the sbom transitively through selenium-remote-driver under vaadin-testbench, a test only dependency.
      · cpe:2.3:a:opentelemetry:opentelemetry::::::node.js::*
    • Vulnerabilities in: pkg:maven/com.vaadin/vaadin-swing-kit-flow@3.0.1 [CVE-2021-33604] (owasp)
      👌 false report: this CVE is targeting Vaadin version prior 20, swing-kit-flow is using vaadin 24+ version, the related issue has been fixed.
      · cpe:2.3:a:vaadin:flow-server::::::::
      · cpe:2.3:a:vaadin:vaadin::::::::
  • 📔 No Core License Issues

  • 📔 No License Issues

  • 🟠 Changes in 25.4-SNAPSHOT since V25.3.0-rc1

    • 20 packages removed (17 external, 3 vaadin)
    • 1 packages added (1 external, 0 vaadin)
    • 248 packages modified (24 external, 224 vaadin)
    • 380 packages same (365 external, 15 vaadin)

[Click for more Details]

ZheSun88 and others added 8 commits September 15, 2026 10:58
The runs carried a deprecation annotation for every pinned action:
checkout, setup-java, setup-node, upload-artifact and setup-maven all
targeted Node 20 and were being forced onto Node 24.

Two of the five needed more than a v5 pin, so each is on its first
Node 24 release rather than uniformly v5:

  actions/checkout          v4 -> v5    (node24)
  actions/setup-node        v4 -> v5    (node24)
  actions/setup-java        v4 -> v5    (node24)
  actions/upload-artifact   v4 -> v6    (v5 is still node20)
  stCarolas/setup-maven     v5 -> v5.1  (v5 is still node20; pit.yml uses v5.1)

upload-artifact v6 keeps every input this workflow uses. Newer majors
exist (checkout/upload-artifact/setup-node are at v7, setup-java at v6);
this stops at the first release that clears the warning rather than
taking those breaking changes on in a CI-migration PR.

Also gives vaadin-platform-hybrid-test the same logging exclusion as the
react-hybrid modules. It has one Spring Boot starter and is not in this
build's reactor, so it is not broken today, but it carries the same
logback-classic-only exclusion next to an slf4j-simple dependency.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1e68129 and 3e637ba kept slf4j-simple as the SLF4J provider and
excluded spring-boot-starter-logging from every Spring Boot starter, so
Logback could not win the provider election and break the AOT processor
behind Hilla's endpoint discovery.

That needs one exclusion per starter, because a Maven exclusion only
cuts the path it is declared on, and any starter added later silently
brings Logback back. Nothing needs slf4j-simple: none of the modules has
a simplelogger.properties, and the dependency was copied in with the
modules. Dropping it leaves Logback as the only provider, which is what
Spring Boot's LoggingSystem expects, and removes every exclusion.

Verified with -Pproduction package on all three modules: build-frontend
passes, and the security module's UserInfoService endpoint is still
generated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bumps NODE_VERSION from 24.21.0 to 26.10.0, the latest 26.x release.
TeamCity still installs Node 24, so this workflow now runs the build on
a newer Node than TeamCity does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The check lived inline in the build, which means it cannot be changed
in a pull request, reviewed, or run by hand, and every branch runs
whatever the build configuration says rather than what the branch
declares.

The script does what the two build steps did together: it reads the
versions out of versions.json, where the first step ran jq, and then
runs the comparisons the second step wrote out to a file. A version may
still be passed in the environment, so the build can keep setting them
while it is moved over.

Only the branch a pull request targets and the token are read from the
environment now, as neither can be worked out from the sources.
versions.json no longer lists the web components one by one, so
versions.core.button.jsVersion is undefined and the check compared
flow-components against the string 'null'. @vaadin/react-components is
released in lockstep with the web components, so its jsVersion is the
web component version now.

That makes the React-components-versus-web-components comparison compare
the version with itself, so it is removed, along with the rcVersion
override that only fed it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…on top

The two suites each ran the full preparation and `mvn install`, the way
TeamCity's two builds do on two agents. Now a `build` job installs the
platform modules once and publishes everything under com/vaadin and
dev/hilla, which after the purge at its start is exactly this build: the
modules it installed and the Flow, Hilla and component snapshots it
resolved. Four jobs run in parallel on top of it:

- npm-tests:    vaadin-platform-test and the reload benchmark (step 15),
                plus the bower tests on branches that have them (step 25)
- react-tests:  the two react-hybrid modules (step 15)
- javadocs:     the release's -Pjavadocs build of vaadin-platform-javadoc,
                which PR validation did not cover before
- gradle-tests: the Gradle test project and the jna check (steps 17/18)

The test jobs pass -DskipPlatform, so only the test modules are built
and the platform modules come from what `build` installed. `build`
itself drops the npm-it, react-hybrid and hybrid-security profiles,
which only add test modules.

The shared preparation moves into a local composite action,
prepare-build, which every build job runs: the BOMs and the javadoc pom
are generated and git-ignored, so each job has to generate them and
set the reactor version the same way before using the artifacts.

Steps 7 and 8, the version consistency test, come back as their own
job running scripts/versionConsistency.js. It needs no Maven build, so
it runs beside `build` and a mismatch does not hold up the tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The step piped `mvn -U help:all-profiles` into `grep -q ... &&
bower=true || bower=false`, so a Maven failure read as "no bower
profile", the step passed, and Maven's output went to grep instead of
the log. When maven.vaadin.com/vaadin-prereleases stopped serving
com/vaadin, this was the step that failed to resolve flow-bom, yet the
error only showed up in the versions:set step after it, as a failure
cached "during a previous attempt".

help:all-profiles reads every module, BOM imports included, so it is
the first step to hit an unresolvable artifact. Its output now goes to
a file: the step fails and prints it when Maven fails, and greps it
otherwise.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pack step collected its directories with `ls -d com/vaadin
dev/hilla`, and ls exits 2 when any of its paths is missing. Hilla is
published under com.vaadin now, so dev/hilla is never there, and under
`bash -e` the step died on that exit status before tar ran, with no
output.

Each directory is now tested with `if [ -d ]` and packed when present.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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