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

Commit 3f8463e

Browse files
committed
fix(swift-doc-coverage, ktlint): skip unresolvable binaryTarget; default ktlint to --format
swift-doc-coverage: SwiftPM resolves all dependencies before any subcommand runs. Polyglot repos using alef's swift scaffold ship a root Package.swift whose binaryTarget URL contains placeholder tokens substituted at release time; locally that URL 404s and the hook fails before generate-documentation ever runs. Detect the exact SwiftPM phrasing (failed downloading ... badResponseStatusCode|invalidChecksum| noChecksum) and skip with a notice. ktlint: split args into flags/files, inject --format if not present, and update the modified-files exit message to say 'auto-fixed; re-stage' instead of the misleading 'use --format to auto-fix'. Aligns ktlint with the shared-hook policy that any tool capable of auto-fixing should do so by default.
1 parent 093149c commit 3f8463e

3 files changed

Lines changed: 79 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.1.20] - 2026-05-26
11+
12+
### Fixed
13+
14+
- `swift-doc-coverage`: gracefully skip when SwiftPM cannot resolve a
15+
`.binaryTarget` artifact bundle (e.g. polyglot repos using alef's swift
16+
scaffold ship a root `Package.swift` whose binaryTarget URL contains
17+
placeholder tokens like `v__ALEF_SWIFT_VERSION__/...artifactbundle.zip`
18+
that the publish workflow substitutes at release time — locally that URL
19+
404s). SwiftPM resolves all dependencies (including binaryTargets) before
20+
any subcommand runs, so an unresolvable artifact bundle aborts the run
21+
with `failed downloading ... badResponseStatusCode(404)` before
22+
`generate-documentation` ever executes. The hook now detects that exit
23+
pattern (also `invalidChecksum` and `noChecksum`) and skips with a notice
24+
instead of failing the commit, matching the existing graceful-skip paths
25+
for "swift not on PATH" and "swift-docc-plugin not declared".
26+
(`hooks/swift-doc-coverage/run.sh`)
27+
28+
- `ktlint`: apply `--format` (auto-fix) by default and update the
29+
modified-files exit message accordingly. Previously the hook ran ktlint in
30+
lint-only mode and produced a misleading "use --format to auto-fix"
31+
message even when the consumer's `args:` block already passed `--format`.
32+
The hook now splits incoming args into flag/file groups, injects
33+
`--format` if absent, and emits `auto-fixed lint issues; re-stage the
34+
changed files and re-run.` on the exit-1 modified-files path. Aligns with
35+
the shared-hook policy that any tool capable of auto-fixing should do so
36+
by default. (`hooks/ktlint/run.sh`)
37+
1038
## [1.1.19] - 2026-05-26
1139

1240
### Added

hooks/ktlint/run.sh

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,40 @@ if [[ $# -eq 0 ]]; then
3030
exit 0
3131
fi
3232

33+
# Split args into flags (leading dashes) and files (the rest). ktlint expects
34+
# `<flags> <files>` ordering and treats positional non-dash tokens as paths.
35+
# pre-commit appends file paths after any `args:` block from the consumer
36+
# config, so we can rely on flags arriving before files.
37+
declare -a flags=()
38+
declare -a files=()
39+
have_format=0
40+
for arg in "$@"; do
41+
if [[ "${arg}" == --format || "${arg}" == -F ]]; then
42+
have_format=1
43+
flags+=("${arg}")
44+
elif [[ "${arg}" == -* ]]; then
45+
flags+=("${arg}")
46+
else
47+
files+=("${arg}")
48+
fi
49+
done
50+
51+
# Apply autofix by default — `--format` is ktlint's auto-fix flag and
52+
# matches the shared-hook policy that any tool capable of auto-fixing
53+
# should do so without consumers having to opt in. Consumers can still
54+
# explicitly pass `--format` (no-op) or any other ktlint flag via the
55+
# `args:` block.
56+
if ((have_format == 0)); then
57+
flags+=(--format)
58+
fi
59+
3360
# Snapshot file hashes pre-lint to detect modifications.
3461
declare -a before_hashes=()
35-
for f in "$@"; do
62+
for f in "${files[@]}"; do
3663
before_hashes+=("$(_sha256_of "${f}" 2>/dev/null || echo NONE)")
3764
done
3865

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.
66+
# ktlint is a self-extracting jar wrapper, so we need java.
4267
# `jvm_quiet_flags` adds `--sun-misc-unsafe-memory-access=allow` on JDK 23+ via
4368
# JAVA_OPTS, silencing the noisy "terminally deprecated sun.misc.Unsafe"
4469
# runtime warnings that ktlint's bundled kotlinc dependencies trigger.
@@ -47,12 +72,12 @@ java_for_probe="${JAVA_HOME:+${JAVA_HOME}/bin/java}"
4772
java_for_probe="${java_for_probe:-java}"
4873
mapfile -t quiet_flags < <(jvm_quiet_flags "${java_for_probe}")
4974
extra_java_opts="${quiet_flags[*]}"
50-
JAVA_HOME="${JAVA_HOME:-}" JAVA_OPTS="${JAVA_OPTS:-} ${extra_java_opts}" "${exe_path}" "$@"
75+
JAVA_HOME="${JAVA_HOME:-}" JAVA_OPTS="${JAVA_OPTS:-} ${extra_java_opts}" "${exe_path}" "${flags[@]}" "${files[@]}"
5176
status=$?
5277

5378
modified=0
5479
i=0
55-
for f in "$@"; do
80+
for f in "${files[@]}"; do
5681
after="$(_sha256_of "${f}" 2>/dev/null || echo NONE)"
5782
if [[ "${before_hashes[$i]}" != "${after}" ]]; then
5883
modified=1
@@ -61,7 +86,7 @@ for f in "$@"; do
6186
done
6287

6388
if ((modified == 1)); then
64-
printf 'ktlint: found lint issues (use --format to auto-fix); re-stage and re-run.\n' >&2
89+
printf 'ktlint: auto-fixed lint issues; re-stage the changed files and re-run.\n' >&2
6590
exit 1
6691
fi
6792

hooks/swift-doc-coverage/run.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,25 @@ for root in "${roots[@]}"; do
8989
continue
9090
fi
9191

92+
# `swift package` resolves all package dependencies — including `.binaryTarget`
93+
# entries — before any subcommand runs. Polyglot repos using alef's swift
94+
# scaffold ship a root Package.swift with a `.binaryTarget` URL containing
95+
# placeholder tokens (e.g. `v__ALEF_SWIFT_VERSION__/...artifactbundle.zip`)
96+
# that the publish workflow substitutes at release time. Locally that URL
97+
# 404s and SwiftPM exits with `badResponseStatusCode(404)` before
98+
# `generate-documentation` even runs. There is nothing the hook can do
99+
# about an unresolvable binaryTarget on a developer's machine, so detect
100+
# that exact failure mode and skip with a notice. The placeholder token
101+
# and the `failed downloading ... badResponseStatusCode` SwiftPM phrasing
102+
# are both stable and unique enough to detect reliably.
103+
if ((rc != 0)) && grep -E -q "failed downloading .* (badResponseStatusCode|invalidChecksum|noChecksum)" "${log_file}"; then
104+
printf 'swift-doc-coverage: skipping %s — binaryTarget artifact is unresolvable (likely a placeholder URL substituted only at publish time).\n' "${root}" >&2
105+
printf ' run the hook in CI against a tagged build, or substitute the placeholder locally to enable this hook.\n' >&2
106+
rm -f "${log_file}"
107+
trap - EXIT
108+
continue
109+
fi
110+
92111
cat "${log_file}" >&2
93112

94113
if ((rc != 0)); then

0 commit comments

Comments
 (0)