Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

- fix [#374](https://github.com/JLLeitschuh/ktlint-gradle/issues/374): fix pre-commit hook path handling for projects in subdirectories [#996](https://github.com/JLLeitschuh/ktlint-gradle/pull/996)

## [14.0.1] - 2025-11-10

- Update build to work with gradle 9.1 and Java 25 [#962](https://github.com/JLLeitschuh/ktlint-gradle/pull/962)
Expand Down
14 changes: 8 additions & 6 deletions plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/GitHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,18 @@ private fun generateGitCommand(
): String = if (gradleRootDirPrefix.isEmpty()) {
"git --no-pager diff --name-status --no-color --cached"
} else {
"git --no-pager diff --name-status --no-color --cached -- $gradleRootDirPrefix/"
"git --no-pager diff --name-status --no-color --cached --relative=$gradleRootDirPrefix -- $gradleRootDirPrefix/"
}

private fun postCheck(
shouldUpdateCommit: Boolean
shouldUpdateCommit: Boolean,
gradleRootDirPrefix: String
): String = if (shouldUpdateCommit) {
val filePrefix = if (gradleRootDirPrefix.isNotEmpty()) "$gradleRootDirPrefix/" else ""
"""
echo "${'$'}CHANGED_FILES" | while read -r file; do
if [ -f ${'$'}file ]; then
git add ${'$'}file
if [ -f $filePrefix${'$'}file ]; then
git add $filePrefix${'$'}file
fi
done
"""
Expand Down Expand Up @@ -91,7 +93,7 @@ internal fun generateGitHook(
gradle_command_exit_code=${'$'}?

echo "Completed ktlint run."
${postCheck(shouldUpdateCommit)}
${postCheck(shouldUpdateCommit, gradleRootDirPrefix)}

if [ -s ${'$'}diff ]; then
git apply --ignore-whitespace ${'$'}diff
Expand Down Expand Up @@ -188,7 +190,7 @@ open class KtlintInstallGitHookTask @Inject constructor(
gitHookFile.createNewFile()
gitHookFile.setExecutable(true)
}
val gradleRootDirPrefix = File(rootDirectory.get()).relativeTo(repo.workTree).path
val gradleRootDirPrefix = File(rootDirectory.get()).relativeTo(repo.workTree).path.replace(File.separator, "/")

if (gitHookFile.length() == 0L) {
gitHookFile.writeText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,75 @@ class GitHookTasksTest : AbstractPluginTest() {
}
}

@DisplayName("Check hook should use --relative flag when Gradle project is in subdirectory")
@CommonTest
fun checkHookUsesRelativeFlagInSubdirectory(gradleVersion: GradleVersion) {
val gradleRoot = projectRoot.resolve("project/submodule/").also { it.mkdirs() }
val gitDir = projectRoot.initGit()

project(gradleVersion, projectPath = gradleRoot) {
build(":$INSTALL_GIT_HOOK_CHECK_TASK") {
assertThat(task(":$INSTALL_GIT_HOOK_CHECK_TASK")?.outcome).isEqualTo(TaskOutcome.SUCCESS)
val hookText = gitDir.preCommitGitHook().readText()
assertThat(hookText).contains("--relative=project/submodule")
assertThat(hookText).contains("-- project/submodule/")
}
}
}

@DisplayName("Format hook should use --relative flag and correct file paths when Gradle project is in subdirectory")
@CommonTest
fun formatHookUsesRelativeFlagInSubdirectory(gradleVersion: GradleVersion) {
val gradleRoot = projectRoot.resolve("project/submodule/").also { it.mkdirs() }
val gitDir = projectRoot.initGit()

project(gradleVersion, projectPath = gradleRoot) {
build(":$INSTALL_GIT_HOOK_FORMAT_TASK") {
assertThat(task(":$INSTALL_GIT_HOOK_FORMAT_TASK")?.outcome).isEqualTo(TaskOutcome.SUCCESS)
val hookText = gitDir.preCommitGitHook().readText()
// Should use --relative flag for git diff
assertThat(hookText).contains("--relative=project/submodule")
assertThat(hookText).contains("-- project/submodule/")
// Should prefix file paths in git add command
assertThat(hookText).contains("if [ -f project/submodule/\$file ]; then")
assertThat(hookText).contains("git add project/submodule/\$file")
}
}
}

@DisplayName("Check hook should not use --relative flag when Gradle project is at git root")
@CommonTest
fun checkHookDoesNotUseRelativeFlagAtGitRoot(gradleVersion: GradleVersion) {
project(gradleVersion) {
val gitDir = projectPath.initGit()

build(":$INSTALL_GIT_HOOK_CHECK_TASK") {
assertThat(task(":$INSTALL_GIT_HOOK_CHECK_TASK")?.outcome).isEqualTo(TaskOutcome.SUCCESS)
val hookText = gitDir.preCommitGitHook().readText()
// Should NOT use --relative flag when at git root
assertThat(hookText).doesNotContain("--relative=")
}
}
}

@DisplayName("Format hook should not use --relative flag when Gradle project is at git root")
@CommonTest
fun formatHookDoesNotUseRelativeFlagAtGitRoot(gradleVersion: GradleVersion) {
project(gradleVersion) {
val gitDir = projectPath.initGit()

build(":$INSTALL_GIT_HOOK_FORMAT_TASK") {
assertThat(task(":$INSTALL_GIT_HOOK_FORMAT_TASK")?.outcome).isEqualTo(TaskOutcome.SUCCESS)
val hookText = gitDir.preCommitGitHook().readText()
// Should NOT use --relative flag when at git root
assertThat(hookText).doesNotContain("--relative=")
// Should NOT prefix file paths
assertThat(hookText).contains("if [ -f \$file ]; then")
assertThat(hookText).doesNotContain("if [ -f /\$file ]; then")
}
}
}

@DisplayName("Check hook should not include files into git commit")
@CommonTest
fun checkHookShouldNotIncludeFilesIntoGitCommit(gradleVersion: GradleVersion) {
Expand Down
Loading