Skip to content
This repository was archived by the owner on Jul 2, 2026. It is now read-only.

Commit f81415e

Browse files
committed
feat(hooks): add ktlint kotlin linter
1 parent da47bf4 commit f81415e

6 files changed

Lines changed: 116 additions & 0 deletions

File tree

.pre-commit-hooks.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@
107107
files: \.kts?$
108108
args: ["--build-upon-default-config"]
109109

110+
- id: ktlint
111+
name: ktlint (Kotlin linter)
112+
description: Lint Kotlin source files with ktlint via java -jar (self-extracting wrapper).
113+
entry: hooks/ktlint/run.sh
114+
language: script
115+
types_or: [kotlin]
116+
files: \.kts?$
117+
args: []
118+
110119
- id: hadolint
111120
name: hadolint (Dockerfile linter)
112121
description: Lint Dockerfiles using a verified upstream hadolint binary.

hooks/ktlint/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# ktlint
2+
3+
Lint Kotlin files using [ktlint](https://github.com/pinterest/ktlint).
4+
5+
## Category
6+
7+
JVM executable. The hook downloads the pinned ktlint self-extracting JAR wrapper from
8+
GitHub Releases, verifies its sha256 against `checksums.txt`, caches it, locates a JDK
9+
11+ via `lib/jvm.sh`, and runs `ktlint`.
10+
11+
## Default args
12+
13+
None. Override via `args:` in your `.pre-commit-config.yaml`. Common options:
14+
- `--format` — auto-fix lint violations (not compatible with pre-commit's default behavior).
15+
- `--editorconfig` — enable EditorConfig rules (default is true if .editorconfig exists).
16+
17+
## JDK detection
18+
19+
Order: `JAVA_HOME``/usr/libexec/java_home -v 11` (macOS) → SDKMAN init →
20+
`java` on `PATH`. If none is JDK 11+, the hook prints a skip warning and exits
21+
0 — contributors without a JVM aren't blocked by Kotlin tooling on unrelated
22+
changes. CI must install JDK 11+ explicitly.
23+
24+
## Behavior
25+
26+
If ktlint detects lint violations, the hook exits non-zero. If `--format` was passed
27+
as an argument and ktlint rewrites any file, the hook also exits non-zero so the user
28+
re-stages the changes.

hooks/ktlint/assets.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[upstream]
2+
# ktlint releases as github-releases with tags like "1.8.0" (no prefix).
3+
datasource = "github-releases"
4+
repo = "pinterest/ktlint"
5+
strip_prefix = ""
6+
7+
[release]
8+
# ktlint publishes a single self-extracting JAR wrapper executable on GitHub Releases.
9+
url_template = "https://github.com/pinterest/ktlint/releases/download/{version}/ktlint"
10+
name_template = "ktlint"
11+
12+
[[release.assets]]
13+
classifier = "executable"

hooks/ktlint/checksums.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Asset checksums for ktlint v1.8.0
2+
# Generated by scripts/fetch_checksums.py — do not edit by hand.
3+
4+
a3fd620207d5c40da6ca789b95e7f823c54e854b7fade7f613e91096a3706d75 ktlint

hooks/ktlint/run.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env bash
2+
# ktlint — Kotlin linter (category: JVM executable).
3+
# Downloads the upstream ktlint executable (self-extracting jar wrapper), sha256-verifies it,
4+
# caches it, locates a JDK 11+ via lib/jvm.sh, and execs `<ktlint> <args> <files>`.
5+
set -euo pipefail
6+
7+
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
REPO_ROOT="$(cd "${HOOK_DIR}/../.." && pwd)"
9+
10+
# shellcheck source=../../lib/platform.sh
11+
source "${REPO_ROOT}/lib/platform.sh"
12+
# shellcheck source=../../lib/download.sh
13+
source "${REPO_ROOT}/lib/download.sh"
14+
# shellcheck source=../../lib/jvm.sh
15+
source "${REPO_ROOT}/lib/jvm.sh"
16+
17+
VERSION="$(grep -v '^#' "${HOOK_DIR}/version.txt" | tr -d '[:space:]')"
18+
CHECKSUMS="${HOOK_DIR}/checksums.txt"
19+
20+
asset_name="ktlint"
21+
# GitHub Releases canonical URL for ktlint executable.
22+
url="https://github.com/pinterest/ktlint/releases/download/${VERSION}/ktlint"
23+
24+
# locate_java exits 0 with a warning if no JDK 11+ is available.
25+
java_bin="$(locate_java)"
26+
27+
exe_path="$(download_tool ktlint "${VERSION}" "${url}" "${asset_name}" "${CHECKSUMS}")"
28+
29+
if [[ $# -eq 0 ]]; then
30+
exit 0
31+
fi
32+
33+
# Snapshot file hashes pre-lint to detect modifications.
34+
declare -a before_hashes=()
35+
for f in "$@"; do
36+
before_hashes+=("$(_sha256_of "${f}" 2>/dev/null || echo NONE)")
37+
done
38+
39+
# ktlint can auto-fix via --format flag. When invoked with filenames,
40+
# it lints them. Combine JAVA_HOME and direct invocation.
41+
# The executable is a shell script wrapper around a jar, so we need java.
42+
JAVA_HOME="${JAVA_HOME:-}" "${exe_path}" "$@"
43+
status=$?
44+
45+
modified=0
46+
i=0
47+
for f in "$@"; do
48+
after="$(_sha256_of "${f}" 2>/dev/null || echo NONE)"
49+
if [[ "${before_hashes[$i]}" != "${after}" ]]; then
50+
modified=1
51+
fi
52+
i=$((i + 1))
53+
done
54+
55+
if ((modified == 1)); then
56+
printf 'ktlint: found lint issues (use --format to auto-fix); re-stage and re-run.\n' >&2
57+
exit 1
58+
fi
59+
60+
exit "${status}"

hooks/ktlint/version.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# renovate: datasource=github-releases depName=pinterest/ktlint extractVersion=^v?(?<version>.+)$
2+
1.8.0

0 commit comments

Comments
 (0)