From b1174f29af93dbe330a88d10a4e85c6bc8f2c7af Mon Sep 17 00:00:00 2001 From: Yasunobu <42543015+P4suta@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:49:14 +0900 Subject: [PATCH 1/3] chore: update template tooling and remove image publishing --- .github/workflows/ci.yml | 18 ++--- .github/workflows/codeql.yml | 2 +- .github/workflows/docker-publish.yml | 100 ------------------------- .pr-workflow/contexts.json | 1 + Dockerfile | 2 +- Dockerfile.toolchain | 4 +- README.md | 108 ++++----------------------- docs/development.md | 67 +++++++++++++++++ gradle/libs.versions.toml | 2 +- justfile | 6 +- mise.toml | 2 +- 11 files changed, 101 insertions(+), 211 deletions(-) delete mode 100644 .github/workflows/docker-publish.yml create mode 100644 .pr-workflow/contexts.json create mode 100644 docs/development.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a47cfd9..e796e5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Validate Gradle wrapper uses: gradle/actions/wrapper-validation@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 with: distribution: corretto java-version: "21" @@ -42,7 +42,7 @@ jobs: if-no-files-found: ignore cross-platform: - name: Build (${{ matrix.os }}) + name: Test (${{ matrix.os }}) strategy: fail-fast: false matrix: @@ -54,14 +54,14 @@ jobs: with: persist-credentials: false - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 with: distribution: corretto java-version: "21" - name: Set up Gradle uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 - - name: Build - run: ./gradlew clean build --console=plain + - name: Compile and test + run: ./gradlew clean test --console=plain lint: name: Lint & scan @@ -72,7 +72,7 @@ jobs: with: persist-credentials: false - name: Set up mise tools - uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0 + uses: jdx/mise-action@fc42bcc7ddbf51124c30f95a877a0c5168a3bfde # v5.2.1 with: experimental: true - name: typos (spell check) @@ -105,14 +105,14 @@ jobs: with: persist-credentials: false - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 with: distribution: corretto java-version: "21" - name: Set up Gradle uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 - - name: Build for release target - run: ./gradlew clean build -PjavaRelease=${{ matrix.release }} --console=plain + - name: Compile for release target + run: ./gradlew compileJava -PjavaRelease=${{ matrix.release }} --console=plain # The one status check branch protection requires, # named the same in every P4suta repository. diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a142552..3e150fb 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,7 +30,7 @@ jobs: with: persist-credentials: false - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 with: distribution: corretto java-version: "21" diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml deleted file mode 100644 index 29fd6ea..0000000 --- a/.github/workflows/docker-publish.yml +++ /dev/null @@ -1,100 +0,0 @@ ---- -name: Publish images - -on: - push: - branches: [main] - tags: ["v*"] - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: publish-${{ github.ref }} - cancel-in-progress: false - -jobs: - runtime: - name: Runtime image (distroless) - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - name: Set up QEMU - uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0 - - name: Set up Buildx - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - - name: Log in to GHCR - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Image metadata - id: meta - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=raw,value=latest,enable={{is_default_branch}} - type=ref,event=tag - type=semver,pattern={{version}} - type=sha - - name: Build & push - uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 - with: - context: . - file: Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - toolchain: - name: Toolchain image (JDK + tools) - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - name: Set up QEMU - uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0 - - name: Set up Buildx - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - - name: Log in to GHCR - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Image metadata - id: meta - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=raw,value=toolchain,enable={{is_default_branch}} - type=sha,prefix=toolchain- - - name: Build & push - uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 - with: - context: . - file: Dockerfile.toolchain - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.pr-workflow/contexts.json b/.pr-workflow/contexts.json new file mode 100644 index 0000000..59f9301 --- /dev/null +++ b/.pr-workflow/contexts.json @@ -0,0 +1 @@ +{"schema":1,"receipts":[{"context":{"schema":1,"destination":{"repository":"P4suta/java-gradle-template","repository_id":1274153059,"owner_id":42543015,"required":true},"issue":40,"branch":"chore/refresh-template-tooling","head":"1114afd4f3fe6074291f17bac97ef7d1d719a94b","tree":"a4bd3a06a7ad22a37f7c5af798a0a5acce391902","scopes":[".github/workflows/ci.yml",".github/workflows/codeql.yml",".github/workflows/docker-publish.yml","Dockerfile","Dockerfile.toolchain","gradle/libs.versions.toml","justfile","mise.toml","README.md","docs/development.md",".gradle/maintenance"],"initial_dirty":{},"adopted":false},"object":"9126cb07f96e5ce9587d9adf4921fdbec5037f8e","signed_commit":"tree a4bd3a06a7ad22a37f7c5af798a0a5acce391902\nparent 1114afd4f3fe6074291f17bac97ef7d1d719a94b\nauthor Yasunobu <42543015+P4suta@users.noreply.github.com> 1792456894 +0900\ncommitter Yasunobu <42543015+P4suta@users.noreply.github.com> 1792456894 +0900\ngpgsig -----BEGIN SSH SIGNATURE-----\n U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAggYuFWiqTPADsoSIEpaH7qKaADz\n KmGLmP6IPbTLrOaDQAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5\n AAAAQJJH/Lv10+37rdg7dgAU763QlhKHbHm6Zt6TLlStYLZJii9vqZpRB1qTqMaaSjXLIO\n 1ToVMvA6OBgYBWeXpXHQ4=\n -----END SSH SIGNATURE-----\n\n{\"schema\":1,\"destination\":{\"repository\":\"P4suta/java-gradle-template\",\"repository_id\":1274153059,\"owner_id\":42543015,\"required\":true},\"issue\":40,\"branch\":\"chore/refresh-template-tooling\",\"head\":\"1114afd4f3fe6074291f17bac97ef7d1d719a94b\",\"tree\":\"a4bd3a06a7ad22a37f7c5af798a0a5acce391902\",\"scopes\":[\".github/workflows/ci.yml\",\".github/workflows/codeql.yml\",\".github/workflows/docker-publish.yml\",\"Dockerfile\",\"Dockerfile.toolchain\",\"gradle/libs.versions.toml\",\"justfile\",\"mise.toml\",\"README.md\",\"docs/development.md\",\".gradle/maintenance\"],\"initial_dirty\":{},\"adopted\":false}"}]} diff --git a/Dockerfile b/Dockerfile index 131d67d..060984a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # Minimal runtime image for the App: build the jar, then run it on a distroless JRE. # ---- build: produce the runnable jar ---- -FROM gradle:8.14.5-jdk21 AS build +FROM gradle:9.8.1-jdk21@sha256:5ec5f726f14851a11a1bac6e6a5720e41062c33357053e7717eb0d189a6f1db9 AS build WORKDIR /app COPY . . RUN gradle --no-daemon --console=plain clean jar diff --git a/Dockerfile.toolchain b/Dockerfile.toolchain index 14ca618..6ab9137 100644 --- a/Dockerfile.toolchain +++ b/Dockerfile.toolchain @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -# Dev/CI toolchain image: JDK 21 + Gradle + lint tools, pinned via the same mise.toml. -# Example: docker run --rm -v "$PWD":/work ghcr.io/p4suta/java-gradle-template:toolchain ./gradlew build +# Local development image with the project's mise tools. +# Build: docker build -f Dockerfile.toolchain -t java-gradle-toolchain . FROM debian:bookworm-slim diff --git a/README.md b/README.md index 64ffc07..93e2892 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,26 @@ -# Coding-training template +# Java coding challenge template -A template for stdin → stdout coding challenges (algorithm / simulation). The scaffolding — -build, quality gates, differential test, dev tooling — is fixed; per challenge you write only the -solution. The initial stub echoes input, so a fresh clone is green immediately. +A Java 21 and Gradle starter for programming challenges that read stdin and write stdout. +The initial solution echoes its input. +Replace it alongside the independent reference, input generator, and sample cases. -## Quick start +## Start ```sh -mise trust && mise install # one-time: JDK 21 + just/lefthook/typos/... (downloads once) -just setup # install git hooks, warm the Gradle + dependency caches -just dev # fast loop: re-run tests on change +mise trust && mise install +just setup +just build ``` -`mise install` + `just setup` download the JDK, Gradle, and dependencies once (a few hundred MB); -after that, builds are incremental (seconds). No Docker required — append `USE_DOCKER=1` to any -recipe to run inside `gradle:8.14.1-jdk21` instead. - -## Start a new challenge - -1. Create a repo from this template ("Use this template") and clone it. -2. (Optional) rename the `track` package — see the checklist below. It works as-is. -3. Implement: - - `src/main/java/track/App.java` — `run(BufferedReader)`, the submitted solution. - - `src/test/java/track/ReferenceSystem.java` — an independent reference. - - `src/test/java/track/QueryGenerator.java` — input generator (bias toward boundaries). - - `src/test/resources/samples/` — `NN_name.in` / `NN_name.out` pairs (auto-discovered). -4. Run `just build` until green. - -## Target Java version (per submission) - -Judges differ in Java version, so the solution's compile target is a one-knob switch: +`just build` runs the tests, static analysis, and coverage checks. +The solution can target Java 8 through 21 while the build tools and tests use Java 21. ```sh -just release 8 # compile src/main against Java 8 (range 8..21; default 21) -./gradlew build -PjavaRelease=8 # or ad hoc, without persisting +just release 8 +just run-sample src/test/resources/samples/00_sample_00.in ``` -The toolchain, tests, CI, and Docker all stay on JDK 21 — only `src/main`'s bytecode/API level -changes (via `--release`), so newer-API usage is caught at build time. CI builds every target -(8 / 11 / 17 / 21) to keep the switch honest. - -## Commands - -| Command | What | -|---|---| -| `just setup` | Install hooks, warm caches (one-time) | -| `just dev` | Re-run tests on change (fast loop) | -| `just build` | All quality gates + tests + coverage | -| `just release ` | Set the solution's Java compile target (8..21) | -| `just test` | Tests only (sweep 2000) | -| `just sweep 30000` | Differential sweep with a given count | -| `just coverage` | Coverage report (HTML) | -| `just lint` | All linters + build over the whole tree | -| `just run-sample ` | Pipe a sample to stdin | -| `just clean` | Remove build outputs | -| `just init` | Docker cache volume (only with `USE_DOCKER=1`) | - -`./gradlew clean build` works directly too. - -## Quality gates - -`just build` fails if any of these fail: - -| Layer | Tool | Catches | -|---|---|---| -| Compile-time analysis | Error Prone + NullAway | null dereferences, known bug patterns | -| Style | Checkstyle (0 warnings) | unused imports, missing braces, ... | -| Bytecode analysis | SpotBugs (effort MAX) | bug patterns | -| Design | ArchUnit | I/O confined to the entry point, ... | -| Differential test | JUnit5 + reference + generator | App vs reference over random inputs | -| Coverage | JaCoCo | under-tested code (fails below threshold) | - -Coverage thresholds are at the top of `build.gradle` (`lineCoverageMin` / `branchCoverageMin`); -raise them per challenge after checking `just coverage`. - -## Dev tooling - -`mise install` provides tools wired into git hooks by lefthook: typos, taplo, yamllint, -shellcheck, editorconfig-checker, gitleaks, actionlint, hadolint. - -- pre-commit: lint staged files + `./gradlew build`. -- pre-push: re-run over the whole tree. - -Run it all manually with `just lint`. - -## CI & images - -- `.github/workflows/ci.yml` — build + test on Linux/Windows/macOS, plus the lint suite. -- `.github/workflows/codeql.yml` — CodeQL analysis. -- `.github/workflows/docker-publish.yml` — on push to `main`, publishes two GHCR images: - `:latest` (distroless runtime) and `:toolchain` (JDK + Gradle + lint tools). - -## Rename checklist (only to change `track`) - -- `settings.gradle` `rootProject.name` -- `build.gradle` `group`, `application.mainClass`, `NullAway:AnnotatedPackages` -- `src/main/java/track/`, `src/test/java/track/` directories and `package track;` declarations -- `justfile` `src/main/java/track/App.java` path -- `ArchitectureTest.java` `@AnalyzeClasses(packages = "track")` and the `App` name prefix - -## License +See the [development guide](docs/development.md) for challenge setup, commands, Docker usage, and renaming the package. +See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow. -Apache-2.0. See `LICENSE`. +Licensed under [Apache-2.0](LICENSE). diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..d127aec --- /dev/null +++ b/docs/development.md @@ -0,0 +1,67 @@ +# Development guide + +Use Java 21 with the committed Gradle wrapper. +The mise profile installs the development tools, and `just setup` installs Git hooks and warms build caches. + +## Create a challenge + +1. Create a repository from this template and clone it. +2. Implement `src/main/java/track/App.java`, whose `run` method owns the submitted solution. +3. Implement the independent reference in `src/test/java/track/ReferenceSystem.java`. +4. Update `src/test/java/track/QueryGenerator.java` to generate inputs near boundaries. +5. Add `NN_name.in` and `NN_name.out` pairs under `src/test/resources/samples/`. +6. Run `just build`. + +## Java target + +```sh +just release 8 +./gradlew build -PjavaRelease=8 +``` + +`just release` persists the selected target in `gradle.properties`. +The `-PjavaRelease` option applies to one command. +Both accept Java 8 through 21 and affect the solution's bytecode and API level. +The toolchain and tests stay on Java 21. +CI compiles all four supported targets and tests on Linux, Windows, and macOS. +Linux also runs the full static analysis and coverage gates. + +## Commands + +| Command | Purpose | +| --- | --- | +| `just dev` | Watch for changes and rerun tests with a small sweep | +| `just build` | Run the full build and quality checks | +| `just test` | Run tests with the default 2,000-case differential sweep | +| `just sweep 30000` | Run a larger differential sweep | +| `just coverage` | Write the coverage report | +| `just lint` | Run all local lint hooks | +| `just run-sample ` | Run the solution with a sample on stdin | +| `just clean` | Remove Gradle build outputs | + +The build includes Error Prone, NullAway, Checkstyle, SpotBugs, ArchUnit, and JaCoCo. +`build.gradle` defines the line and branch coverage thresholds. +Raise them when a challenge adds behavior. +The HTML coverage report is under `build/reports/jacoco/test/html/`. + +## Local containers + +The optional Docker path uses the same Gradle and Java 21 image, fixed by digest, as the runtime image's build stage. +Initialize its cache before the first build: + +```sh +USE_DOCKER=1 just init +USE_DOCKER=1 just build +``` + +`Dockerfile` builds a local runnable application image. +`Dockerfile.toolchain` builds a local image with the mise development tools. +CI does not build or publish registry images. + +## Rename the package + +Update `settings.gradle`, the group and main-class settings in `build.gradle`, and NullAway's annotated package. +Rename both source package directories and declarations. +Update the standalone path in `justfile` and the package and application checks in `ArchitectureTest.java`. + +See [CONTRIBUTING.md](../CONTRIBUTING.md). diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 14323ee..8792fa7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ errorprone = "2.50.0" nullaway = "0.14.2" junit = "6.1.3" archunit = "1.5.1" -checkstyle = "10.26.1" +checkstyle = "14.3.0" spotbugs = "4.10.5" jacoco = "0.8.15" diff --git a/justfile b/justfile index b4c815e..49f628e 100644 --- a/justfile +++ b/justfile @@ -1,12 +1,12 @@ -# Dev tasks. Native by default (mise's JDK + Gradle wrapper). Set USE_DOCKER=1 to run the -# same recipe inside gradle:8.14.1-jdk21 (no host JDK needed). +# Dev tasks use the Gradle wrapper and project tools. +# Set USE_DOCKER=1 to use the official Gradle container. # just build # native # USE_DOCKER=1 just build # Docker use_docker := env_var_or_default("USE_DOCKER", "0") uid := `id -u 2>/dev/null || echo 1000` gid := `id -g 2>/dev/null || echo 1000` -img := "gradle:8.14.1-jdk21" +img := "gradle:9.8.1-jdk21@sha256:5ec5f726f14851a11a1bac6e6a5720e41062c33357053e7717eb0d189a6f1db9" # Docker prefix, only when USE_DOCKER=1 (host user; deps cached in a named volume). _dr := if use_docker == "1" { "docker run --rm --user " + uid + ":" + gid + ' -e GRADLE_USER_HOME=/cache -e HOME=/tmp -v "$PWD":/work -v practice-gradle:/cache -w /work ' + img + " " } else { "" } diff --git a/mise.toml b/mise.toml index e154aaa..d725314 100644 --- a/mise.toml +++ b/mise.toml @@ -1,6 +1,6 @@ # Project-pinned tools. Global CLIs live in your own dotfiles; this pins what the repo needs. # Setup: `mise trust && mise install`, then `just setup`. -# Gradle comes from the wrapper (8.14.1); only the JDK and dev tools are pinned here. +# Gradle comes from the committed wrapper. [tools] # Match the judge runtime (Amazon Corretto 21); the code is JDK-vendor-neutral. From 5f1f42c1a9182050935b8114deb265680036d256 Mon Sep 17 00:00:00 2001 From: Yasunobu <42543015+P4suta@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:06:50 +0900 Subject: [PATCH 2/3] fix: pin container bases and run the full push check --- .pr-workflow/contexts.json | 2 +- Dockerfile | 2 +- Dockerfile.toolchain | 2 +- lefthook.yml | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.pr-workflow/contexts.json b/.pr-workflow/contexts.json index 59f9301..1a7bb6a 100644 --- a/.pr-workflow/contexts.json +++ b/.pr-workflow/contexts.json @@ -1 +1 @@ -{"schema":1,"receipts":[{"context":{"schema":1,"destination":{"repository":"P4suta/java-gradle-template","repository_id":1274153059,"owner_id":42543015,"required":true},"issue":40,"branch":"chore/refresh-template-tooling","head":"1114afd4f3fe6074291f17bac97ef7d1d719a94b","tree":"a4bd3a06a7ad22a37f7c5af798a0a5acce391902","scopes":[".github/workflows/ci.yml",".github/workflows/codeql.yml",".github/workflows/docker-publish.yml","Dockerfile","Dockerfile.toolchain","gradle/libs.versions.toml","justfile","mise.toml","README.md","docs/development.md",".gradle/maintenance"],"initial_dirty":{},"adopted":false},"object":"9126cb07f96e5ce9587d9adf4921fdbec5037f8e","signed_commit":"tree a4bd3a06a7ad22a37f7c5af798a0a5acce391902\nparent 1114afd4f3fe6074291f17bac97ef7d1d719a94b\nauthor Yasunobu <42543015+P4suta@users.noreply.github.com> 1792456894 +0900\ncommitter Yasunobu <42543015+P4suta@users.noreply.github.com> 1792456894 +0900\ngpgsig -----BEGIN SSH SIGNATURE-----\n U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAggYuFWiqTPADsoSIEpaH7qKaADz\n KmGLmP6IPbTLrOaDQAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5\n AAAAQJJH/Lv10+37rdg7dgAU763QlhKHbHm6Zt6TLlStYLZJii9vqZpRB1qTqMaaSjXLIO\n 1ToVMvA6OBgYBWeXpXHQ4=\n -----END SSH SIGNATURE-----\n\n{\"schema\":1,\"destination\":{\"repository\":\"P4suta/java-gradle-template\",\"repository_id\":1274153059,\"owner_id\":42543015,\"required\":true},\"issue\":40,\"branch\":\"chore/refresh-template-tooling\",\"head\":\"1114afd4f3fe6074291f17bac97ef7d1d719a94b\",\"tree\":\"a4bd3a06a7ad22a37f7c5af798a0a5acce391902\",\"scopes\":[\".github/workflows/ci.yml\",\".github/workflows/codeql.yml\",\".github/workflows/docker-publish.yml\",\"Dockerfile\",\"Dockerfile.toolchain\",\"gradle/libs.versions.toml\",\"justfile\",\"mise.toml\",\"README.md\",\"docs/development.md\",\".gradle/maintenance\"],\"initial_dirty\":{},\"adopted\":false}"}]} +{"schema":1,"receipts":[{"context":{"schema":1,"destination":{"repository":"P4suta/java-gradle-template","repository_id":1274153059,"owner_id":42543015,"required":true},"issue":40,"branch":"chore/refresh-template-tooling","head":"b1174f29af93dbe330a88d10a4e85c6bc8f2c7af","tree":"20b135198062fbfc9d8a0ece8da7634c7e82ab80","scopes":[".github/workflows/ci.yml",".github/workflows/codeql.yml",".github/workflows/docker-publish.yml","Dockerfile","Dockerfile.toolchain","gradle/libs.versions.toml","justfile","mise.toml","lefthook.yml","README.md","docs/development.md",".gradle/maintenance"],"initial_dirty":{},"adopted":false},"object":"ea25dbcc2bb9ade0155a82f4fd415ba0b9e1c1ff","signed_commit":"tree 20b135198062fbfc9d8a0ece8da7634c7e82ab80\nparent b1174f29af93dbe330a88d10a4e85c6bc8f2c7af\nauthor Yasunobu <42543015+P4suta@users.noreply.github.com> 1792458127 +0900\ncommitter Yasunobu <42543015+P4suta@users.noreply.github.com> 1792458127 +0900\ngpgsig -----BEGIN SSH SIGNATURE-----\n U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAggYuFWiqTPADsoSIEpaH7qKaADz\n KmGLmP6IPbTLrOaDQAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5\n AAAAQBXFIf22iGEQXb0aUH3+cI1lR/A8K8lbatyAFj2BD3x9/9vMhl7Hunjynq4w3WIemS\n Cs4W717YtjiQxOF4+rXQM=\n -----END SSH SIGNATURE-----\n\n{\"schema\":1,\"destination\":{\"repository\":\"P4suta/java-gradle-template\",\"repository_id\":1274153059,\"owner_id\":42543015,\"required\":true},\"issue\":40,\"branch\":\"chore/refresh-template-tooling\",\"head\":\"b1174f29af93dbe330a88d10a4e85c6bc8f2c7af\",\"tree\":\"20b135198062fbfc9d8a0ece8da7634c7e82ab80\",\"scopes\":[\".github/workflows/ci.yml\",\".github/workflows/codeql.yml\",\".github/workflows/docker-publish.yml\",\"Dockerfile\",\"Dockerfile.toolchain\",\"gradle/libs.versions.toml\",\"justfile\",\"mise.toml\",\"lefthook.yml\",\"README.md\",\"docs/development.md\",\".gradle/maintenance\"],\"initial_dirty\":{},\"adopted\":false}"}]} diff --git a/Dockerfile b/Dockerfile index 060984a..dba0c07 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ COPY . . RUN gradle --no-daemon --console=plain clean jar # ---- runtime: distroless JRE ---- -FROM gcr.io/distroless/java21-debian12:nonroot AS runtime +FROM gcr.io/distroless/java21-debian12:nonroot@sha256:7e37784d94dccbf5ccb195c73b295f5ad00cd266512dfbac12eb9c3c28f8077d AS runtime WORKDIR /app COPY --from=build /app/build/libs/*.jar /app/app.jar # Pipe input on stdin: docker run -i --rm < input.txt diff --git a/Dockerfile.toolchain b/Dockerfile.toolchain index 6ab9137..fc85f3f 100644 --- a/Dockerfile.toolchain +++ b/Dockerfile.toolchain @@ -2,7 +2,7 @@ # Local development image with the project's mise tools. # Build: docker build -f Dockerfile.toolchain -t java-gradle-toolchain . -FROM debian:bookworm-slim +FROM debian:bookworm-slim@sha256:7c7b2c966bc9ee8cedfeef67e0e279108992c77681fa595db4a9d65c06ccc587 # Fail on errors in piped commands (hadolint DL4006). SHELL ["/bin/bash", "-o", "pipefail", "-c"] diff --git a/lefthook.yml b/lefthook.yml index 0ca4795..2a76c2b 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -45,4 +45,5 @@ pre-push: parallel: true commands: all-files: + files: git ls-files run: lefthook run pre-commit --all-files From f2d136ef3e7924ab67a570422eba94114bb7fe25 Mon Sep 17 00:00:00 2001 From: Yasunobu <42543015+P4suta@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:39:06 +0900 Subject: [PATCH 3/3] build: share pinned mise tools between local checks and CI --- .github/workflows/ci.yml | 25 +++++++++++-------------- .github/workflows/codeql.yml | 7 +++---- .pr-workflow/contexts.json | 2 +- lefthook.yml | 4 ++-- mise.toml | 23 ++++++++++++----------- 5 files changed, 29 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e796e5b..961a29c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,11 +24,10 @@ jobs: persist-credentials: false - name: Validate Gradle wrapper uses: gradle/actions/wrapper-validation@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 - - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 + - name: Set up Java 21 from mise + uses: jdx/mise-action@fc42bcc7ddbf51124c30f95a877a0c5168a3bfde # v5.2.1 with: - distribution: corretto - java-version: "21" + install_args: java - name: Set up Gradle uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 - name: Build (quality gates + tests + coverage) @@ -53,11 +52,10 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 + - name: Set up Java 21 from mise + uses: jdx/mise-action@fc42bcc7ddbf51124c30f95a877a0c5168a3bfde # v5.2.1 with: - distribution: corretto - java-version: "21" + install_args: java - name: Set up Gradle uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 - name: Compile and test @@ -80,13 +78,13 @@ jobs: - name: taplo (TOML) run: taplo lint - name: yamllint - run: uvx --from yamllint yamllint -c .yamllint . + run: yamllint -c .yamllint . - name: editorconfig-checker run: editorconfig-checker - name: actionlint (workflows) run: actionlint - name: zizmor (workflow security) - run: uvx zizmor .github/workflows + run: zizmor .github/workflows - name: hadolint (Dockerfiles) run: hadolint Dockerfile Dockerfile.toolchain - name: gitleaks (secret scan) @@ -104,11 +102,10 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 + - name: Set up Java 21 from mise + uses: jdx/mise-action@fc42bcc7ddbf51124c30f95a877a0c5168a3bfde # v5.2.1 with: - distribution: corretto - java-version: "21" + install_args: java - name: Set up Gradle uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 - name: Compile for release target diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3e150fb..b291db9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -29,11 +29,10 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - name: Set up JDK 21 (Corretto) - uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 + - name: Set up Java 21 from mise + uses: jdx/mise-action@fc42bcc7ddbf51124c30f95a877a0c5168a3bfde # v5.2.1 with: - distribution: corretto - java-version: "21" + install_args: java - name: Initialize CodeQL uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 with: diff --git a/.pr-workflow/contexts.json b/.pr-workflow/contexts.json index 1a7bb6a..b73a317 100644 --- a/.pr-workflow/contexts.json +++ b/.pr-workflow/contexts.json @@ -1 +1 @@ -{"schema":1,"receipts":[{"context":{"schema":1,"destination":{"repository":"P4suta/java-gradle-template","repository_id":1274153059,"owner_id":42543015,"required":true},"issue":40,"branch":"chore/refresh-template-tooling","head":"b1174f29af93dbe330a88d10a4e85c6bc8f2c7af","tree":"20b135198062fbfc9d8a0ece8da7634c7e82ab80","scopes":[".github/workflows/ci.yml",".github/workflows/codeql.yml",".github/workflows/docker-publish.yml","Dockerfile","Dockerfile.toolchain","gradle/libs.versions.toml","justfile","mise.toml","lefthook.yml","README.md","docs/development.md",".gradle/maintenance"],"initial_dirty":{},"adopted":false},"object":"ea25dbcc2bb9ade0155a82f4fd415ba0b9e1c1ff","signed_commit":"tree 20b135198062fbfc9d8a0ece8da7634c7e82ab80\nparent b1174f29af93dbe330a88d10a4e85c6bc8f2c7af\nauthor Yasunobu <42543015+P4suta@users.noreply.github.com> 1792458127 +0900\ncommitter Yasunobu <42543015+P4suta@users.noreply.github.com> 1792458127 +0900\ngpgsig -----BEGIN SSH SIGNATURE-----\n U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAggYuFWiqTPADsoSIEpaH7qKaADz\n KmGLmP6IPbTLrOaDQAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5\n AAAAQBXFIf22iGEQXb0aUH3+cI1lR/A8K8lbatyAFj2BD3x9/9vMhl7Hunjynq4w3WIemS\n Cs4W717YtjiQxOF4+rXQM=\n -----END SSH SIGNATURE-----\n\n{\"schema\":1,\"destination\":{\"repository\":\"P4suta/java-gradle-template\",\"repository_id\":1274153059,\"owner_id\":42543015,\"required\":true},\"issue\":40,\"branch\":\"chore/refresh-template-tooling\",\"head\":\"b1174f29af93dbe330a88d10a4e85c6bc8f2c7af\",\"tree\":\"20b135198062fbfc9d8a0ece8da7634c7e82ab80\",\"scopes\":[\".github/workflows/ci.yml\",\".github/workflows/codeql.yml\",\".github/workflows/docker-publish.yml\",\"Dockerfile\",\"Dockerfile.toolchain\",\"gradle/libs.versions.toml\",\"justfile\",\"mise.toml\",\"lefthook.yml\",\"README.md\",\"docs/development.md\",\".gradle/maintenance\"],\"initial_dirty\":{},\"adopted\":false}"}]} +{"schema":1,"receipts":[{"context":{"schema":1,"destination":{"repository":"P4suta/java-gradle-template","repository_id":1274153059,"owner_id":42543015,"required":true},"issue":40,"branch":"chore/refresh-template-tooling","head":"5f1f42c1a9182050935b8114deb265680036d256","tree":"92bbc3000c62ab25d96f0c7db56a08dfe1d80cb1","scopes":[".github/workflows/ci.yml",".github/workflows/codeql.yml",".github/workflows/docker-publish.yml","Dockerfile","Dockerfile.toolchain","gradle/libs.versions.toml","justfile","mise.toml","lefthook.yml","README.md","docs/development.md",".gradle/maintenance"],"initial_dirty":{},"adopted":false},"object":"addae433f35e89122c7e2d91a3aa0058f5f83230","signed_commit":"tree 92bbc3000c62ab25d96f0c7db56a08dfe1d80cb1\nparent 5f1f42c1a9182050935b8114deb265680036d256\nauthor Yasunobu <42543015+P4suta@users.noreply.github.com> 1792459977 +0900\ncommitter Yasunobu <42543015+P4suta@users.noreply.github.com> 1792459977 +0900\ngpgsig -----BEGIN SSH SIGNATURE-----\n U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAggYuFWiqTPADsoSIEpaH7qKaADz\n KmGLmP6IPbTLrOaDQAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5\n AAAAQJHB2E5dBB4F+9fqp5P+kViHN08qINVrHQX8FfIOquSHp2zukNBfX6dNpw/uoiYzyR\n tuMI01W6+Afht6KFGpyg4=\n -----END SSH SIGNATURE-----\n\n{\"schema\":1,\"destination\":{\"repository\":\"P4suta/java-gradle-template\",\"repository_id\":1274153059,\"owner_id\":42543015,\"required\":true},\"issue\":40,\"branch\":\"chore/refresh-template-tooling\",\"head\":\"5f1f42c1a9182050935b8114deb265680036d256\",\"tree\":\"92bbc3000c62ab25d96f0c7db56a08dfe1d80cb1\",\"scopes\":[\".github/workflows/ci.yml\",\".github/workflows/codeql.yml\",\".github/workflows/docker-publish.yml\",\"Dockerfile\",\"Dockerfile.toolchain\",\"gradle/libs.versions.toml\",\"justfile\",\"mise.toml\",\"lefthook.yml\",\"README.md\",\"docs/development.md\",\".gradle/maintenance\"],\"initial_dirty\":{},\"adopted\":false}"}]} diff --git a/lefthook.yml b/lefthook.yml index 2a76c2b..5a74714 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -18,7 +18,7 @@ pre-commit: run: taplo lint {staged_files} glob: "*.toml" yamllint: - run: uvx --from yamllint yamllint -c .yamllint {staged_files} + run: yamllint -c .yamllint {staged_files} glob: "*.{yml,yaml}" shellcheck: run: shellcheck --severity=style --enable=all -x {staged_files} @@ -32,7 +32,7 @@ pre-commit: run: actionlint {staged_files} glob: ".github/workflows/*.{yml,yaml}" zizmor: - run: uvx zizmor {staged_files} + run: zizmor {staged_files} glob: ".github/workflows/*.{yml,yaml}" hadolint: run: hadolint {staged_files} diff --git a/mise.toml b/mise.toml index d725314..093615e 100644 --- a/mise.toml +++ b/mise.toml @@ -6,20 +6,21 @@ # Match the judge runtime (Amazon Corretto 21); the code is JDK-vendor-neutral. java = "corretto-21" -just = "latest" -lefthook = "latest" +just = "1.59.0" +lefthook = "2.2.2" # Lint tools invoked by the lefthook pre-commit hook. -"github:crate-ci/typos" = "latest" -taplo = "latest" -shellcheck = "latest" -"aqua:editorconfig-checker/editorconfig-checker" = "latest" -gitleaks = "latest" -actionlint = "latest" -hadolint = "latest" +"github:crate-ci/typos" = "1.51.1" +taplo = "0.10.0" +shellcheck = "0.11.0" +"aqua:editorconfig-checker/editorconfig-checker" = "4.0.2" +gitleaks = "8.30.1" +actionlint = "1.7.12" +hadolint = "2.15.1" -# uv runs yamllint and zizmor ephemerally via uvx. -uv = "latest" +uv = "0.13.1" +yamllint = "1.38.0" +zizmor = "1.31.1" [settings] experimental = true