Setup Java Spring Boot GitHub Workflows
| This documentation was generated with the assistance of AI. Please report any inaccuracies. |
Creates the GitHub Actions workflows a Spring Boot service needs: one that builds, tests, analyses, and publishes
documentation (optionally running a Hilla frontend’s tests too); one that deploys (as a staged rollout when rolling deployments are enabled, with a further promote.yml to advance
or roll it back); one that stops or destroys an environment; and one that runs dependency/code/secret security scans, plus a Dependabot config.
Purpose
iru-setup-java-springboot-github-workflows is the service-shaped counterpart to
Setup Java GitHub Workflows. A service is not published to Maven Central and is not
GPG-signed — it is built into a container image and deployed — so the publish, sign, and version-sync stages are
replaced by image build, OpenTofu apply, and teardown. The shared stages (test, analyse, Sonar, Antora, GitHub
Pages) follow the same house pattern, so the two remain recognisably related.
The skill announces whether it is creating the workflows from scratch or updating existing ones, and asks per
existing file whether to Update, Keep as is, Replace, or Stop (or applies on-existing). It also resolves
visibility-aware CI choices: visibility, sonar, ci-tests (unit runs Surefire only with -DskipITs; full
also runs Failsafe against Testcontainers) and pages (no uploads the built docs as a workflow artifact instead of
publishing to GitHub Pages). For private or internal repositories it states the Actions-minutes cost
(2,000/month on Free, 3,000 on Pro and Team, 50,000 on Enterprise Cloud; Linux 2-core $0.006/min) and that GitHub
Pages needs Pro, Team or Enterprise Cloud and is public on the internet unless Enterprise Cloud access control is
used.
The build.yml Sonar step is no longer offered reactively: it reads the manifest’s sonar.mode
(cloud/self-hosted/none, defaulting to cloud for a manifest written before the field existed) as the source
of truth and drops the step entirely — rather than disabling it with a permanently-false condition — when
sonar.mode: none. When the manifest’s frontend field is hilla, build.yml also sets up Node, runs the
frontend’s Vitest suite with coverage (after the Maven build, since the frontend’s generated config imports
compiled helpers that only exist once Maven has reached vaadin:prepare-frontend), and packages with
-Pproduction -Dvaadin.ci.build=true.
| Workflow | Trigger | Does |
|---|---|---|
|
Push to the integration/main branch, and every pull request |
Build, unit tests (Surefire), Testcontainers integration tests (Failsafe, only when |
|
|
Build and push the container image, authenticate via keyless OIDC, |
|
|
Advance a rollout one step, or roll it back or abort it. Stateless: it reads the current traffic split from the cloud (ECS weighted target groups, Cloud Run traffic tags, Argo Rollouts) and sets the next one. It needs no GitHub Environment reviewers, so it works on any GitHub plan |
|
|
Scale to zero (the reversible default) or destroy an environment, behind a typed-confirmation check and a protected GitHub Environment |
|
Push to the main branch, every pull request, and a weekly schedule |
Dependency review, CodeQL (with a |
|
n/a — configuration, not a workflow |
Grouped weekly updates for the |
No credential is ever written into a workflow file: cloud access is keyless via OIDC, and everything else is a
repository or environment secret referenced by name. Where the registry supports it, even the registry credential is
derived from the OIDC session (amazon-ecr-login, gcloud auth configure-docker) rather than stored.
The guards on undeploy.yml are the feature rather than ceremony: stop is the default and is reversible, data-bearing
resources are expected to carry deletion protection so destroy fails on them rather than silently deleting a
production database, and the skill recommends restricting prod to required reviewers plus a deployment branch rule
— and considering omitting prod from the destroy path entirely.
Language and build tool
project.language (java/kotlin, absent means java) and project.buildTool (maven/gradle, absent means
maven; Gradle only ever appears with Kotlin) select one of three variants, confirmed against the disk (pom.xml,
settings.gradle.kts plus gradlew, src/main/kotlin) — if the manifest and the disk disagree, the disk wins for
the run and the report says so.
| Variant | What changes |
|---|---|
|
The base templates, unchanged. |
|
Static analysis is detekt plus ktlint instead of Checkstyle/PMD/SpotBugs, and code documentation is Dokka instead of
Javadoc; every |
|
Every job uses |
Rolling deployments
When the manifest’s deploy.rolling.enabled is true (or rolling: yes arrives in args), deploy.yml becomes a
staged rollout instead of one job: build and push the image, deploy the new version ("green") at 0 % traffic, smoke-test
its candidate URL, shift traffic in the configured steps behind a metric gate, and roll back automatically on a breach.
How far it goes unattended depends on advance: auto runs the gate alone, hybrid adds a human confirmation through
promote.yml on prod (auto-advancing on dev), and manual ends the run once green is deployed so a human runs
promote.yml for each step. Strategy blue-green is a single cutover (steps: [100]), canary and linear use the
manifest’s steps with bakeMinutes of soak, and strategy rolling keeps the single-job deploy.yml (the runtime’s
native rolling update) and generates no promote.yml. The first deploy of an environment, which has no rollout outputs
yet, is applied at 100 % and the staged jobs are skipped.
The rollout shell functions are runtime-specific (ECS Fargate, Cloud Run, or Argo Rollouts on EKS/GKE) and embedded in
deploy.yml, promote.yml and undeploy.yml; the workflows rely on the rollout_* outputs and resource naming that
Setup Java Spring Boot Platform produces. deploy.yml, promote.yml and undeploy.yml share one
concurrency group per environment so a deploy, a promotion and a teardown never interleave, and undeploy.yml resets
the traffic split first. Rolling disabled or absent keeps today’s single-job deploy.yml unchanged, with no
promote.yml; with ci: no there are no workflows at all, hence no rolling. Because a rollout in flight must not be
orphaned, replacing or updating an existing deploy.yml across this behavioural change needs an explicit yes. The
report also advises who may dispatch promote.yml, since a workflow_dispatch workflow is open to anyone with write
access. See Spring Boot Rolling Deployments.
Plugin
Shipped by the iru-springboot plugin of the ai-catalog marketplace (install with /plugin install iru-springboot@ai-catalog; see Plugins).
Invocation
/iru-setup-java-springboot-github-workflows
/iru-setup-java-springboot-github-workflows <args: key: value lines>
Inputs
| Argument | Required | Description | Default |
|---|---|---|---|
|
No |
|
|
|
No |
|
|
|
No |
|
|
|
No |
|
Manifest values |
|
No |
|
Rolling disabled |
|
No |
|
None |
|
No |
|
|
On-disk survey |
Yes |
The workflows must match reality, so the skill reads: the reactor’s modules and the |
None — derived |
Existing workflow files |
No |
Covers |
None — user must choose |
Outputs
-
.github/workflows/build.yml— abuildjob (checkout with full history for Sonar blame, JDK with Maven cache,mvn clean verify— ormvn clean verify -DskipITswithci.tests: unit— the site report, the Sonar scan skipped on fork pull requests, and test reports uploaded even on failure) plus adocsjob gated to main-branch pushes (renamedBuild documentationand ending in an artifact upload rather than agh-pagesdeploy whenci.pages: no, in which case it also dropscontents: writeand the.nojekylltouch). Thedocsjob generates the Maven site and the OpenAPI/protobuf documentation, then runs the two npm-driven generators as their own steps against the toolchains committed inapis/messaging/docsandapis/graphql-server/docs— validating and rendering the AsyncAPI specification, and rendering the GraphQL SDL through SpectaQL and (optionally) Voyager. It then builds the Antora site and merges everything: a "Merge documentation" step copies the contents of everytarget/generated-docsdirectory in the reactor underdoc/api/, sorest-server/,grpc-server/,graphql-server/andmessaging/land side by side without the workflow needing to know which module produced which. The published result includesdoc/api/messaging/v1/index.htmlanddoc/api/graphql-server/v1/index.htmlwith the Voyager graph beneath it. Both npm generators are skipped in Maven (-Dasyncapi.docs.skip=true -Dgraphql.docs.skip=true) in this job so the work isn’t done twice — thebuildjob’smvn clean verifystill exercises thefrontend-maven-pluginwiring — and each step is guarded byhashFiles(…), so deleting a contract directory doesn’t require a workflow edit. Their loops over-async-api-v.yamland-v.graphqlsmean a new contract version needs no workflow change either.One detail the merge step protects by accident and would break if simplified: Voyager's page loads `voyager.standalone.js` and `voyager.css` by relative path, so those files must travel with `index.html`. Copying whole directories preserves that; copying only `index.html` files would publish a blank graph.
When `frontend: hilla`, `ci.tests` is `full` and the web module has a `playwright.config.ts` (written by xref:skills/iru-setup-java-springboot-hilla.adoc[]), the `build` job also gets a `Frontend UI tests` step (installs Chromium and runs `npx playwright test` in the web module with `UI_SCREENSHOTS_DIR` pointing at the workspace's `.ui-screenshots/`) and an `Upload UI screenshots` step (`if: always()`, 7-day `ui-screenshots` artifact, `if-no-files-found: ignore`), per the catalog's UI contract (see xref:guides/building-user-interfaces.adoc[Building user interfaces]). When `.ui-quality.yml` sets `accessibility: none`, no accessibility report is collected or uploaded and no accessibility-only job or step is emitted. Both steps are dropped otherwise; with `ci.tests: unit` the UI tests stay a local stage so no Chromium download is paid on every run. * `.github/workflows/deploy.yml` — with `id-token: write`, a concurrency group per environment that never cancels in progress, the GitHub Environment as the approval gate, buildpack image build and push, and `tofu apply` of the previously produced plan file. * `.github/workflows/deploy.yml` when rolling deployments are enabled (and the strategy is not `rolling`) — jobs `build-image`, `deploy-green` (apply at 0 % traffic), `smoke-candidate` (health-check the candidate URL), `shift` (step through the manifest's percentages with the metric gate; omitted for `advance: manual`) and `rollback` (return traffic to the stable version on any failure), in the same per-environment concurrency group as `promote.yml` and `undeploy.yml`. Per-runtime variants authenticate and drive ECS (weighted target groups on the ALB listener), Cloud Run (revision tags and traffic percentages) or Argo Rollouts (`kubectl argo rollouts`). * `.github/workflows/promote.yml` — only with rolling deployments and a strategy other than `rolling`: a `promote` job that advances the rollout one step or rolls it back or aborts it, deliberately without Environment reviewers. * `.github/workflows/undeploy.yml` — with the typed-confirmation check, the same concurrency group as `deploy.yml` so the two can never run at once, and separate `stop` and `destroy` paths; with rolling deployments it resets the traffic split first. * `.github/workflows/security.yml` — a `dependency-review` job (pull requests only), on Gradle a `dependency-submission` job, a `codeql` job (matrix `java-kotlin`, plus `javascript-typescript` when `frontend: hilla`), an `osv-scanner` job (the `google/osv-scanner-action` reusable workflow), and a `gitleaks` job (full checkout history) — each job present only when its `security-*` flag is `yes`. If all four flags are `no`, the file is skipped entirely rather than written with no jobs. * `.github/dependabot.yml` — always generated: grouped weekly updates for `maven` (or `gradle`), `docker`, and `github-actions`, plus an `npm` entry (directory set to the real web module, normally `/boot`) whenever the manifest's `frontend` isn't `none`, and a further `npm` entry per documentation toolchain (`docs/`, `apis/messaging/docs/`, `apis/graphql-server/docs/`) that already has its own committed `package-lock.json`. * A report including the full table of required repository secrets, environment secrets, environment variables, and GitHub Environments — plus the settings that are easy to miss: GitHub Pages served from `gh-pages` (only when `ci.pages: yes`), an OIDC trust policy scoped to the repository *and* the environment, and (for `security.yml`) Code scanning and Dependency graph enabled in repository settings so CodeQL and dependency review have somewhere to report into. The report also states whether rolling deployments were enabled (strategy, advance, steps, bake minutes), whether the run created or updated the workflows, the action taken per file (created / updated / replaced / kept as is, with each mismatch for kept files), how `visibility`, `ci.tests` and `ci.pages` were resolved, and the Actions-minutes note for private/internal repositories.
The generated files' bytes come from template files under templates/ (and, where a template needs variant-specific notes, reference/) in .claude/skills/iru-setup-java-springboot-github-workflows/; the skill reads only the files for the variant it resolved, not the whole set, which keeps its SKILL.md small.
Execution flow
deploy.yml and undeploy.yml are deliberately never triggered as a test. The skill instead recommends a dry run of
build.yml on a throwaway branch, and a first deploy.yml run against dev only, watched to completion.
Dependencies
Invokes
-
Setup Java Spring Boot Poms — Step 0 (conditional), only offered when the survey finds the pom’s (or Gradle build’s) Sonar wiring missing although
sonar.modeisn’tnone; the skill reports the drift and offers to re-run it rather than generating a Sonar step that is certain to fail.
Otherwise it reads springboot-stack.yml and surveys the repository, then writes workflow YAML.
Invoked by
-
Spring Boot Rolling Deployments — when enabling or disabling rolling deployments on an existing service, it re-runs this skill so
deploy.ymlis regenerated andpromote.ymladded or removed. -
Setup Java Spring Boot — Step 8, build/deploy/promote/undeploy/security workflows, skipped when ci is no, via the
iru-isolated-skill-executoragent.
Also runs standalone (/iru-setup-java-springboot-github-workflows).
Related agents
-
iru-gate-runner— spawned in Step 5 to run the workflow’s Maven (or Gradle) commands locally first, on the principle that a workflow whose commands were never run locally is a guess.
Source
SKILL.md on GitHub — the file this page was generated from.