-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add task to generate pre commit hook that formats staged changes #270
base: main
Are you sure you want to change the base?
Conversation
Thanks for sending this over @gpopides |
Sure i will take a look again tomorrow. Locally they are passing but i will make sure it works on CI too! |
CI is still red apparentyl |
Indeed, the last failure was because of a detekt issue which i pushed a change to fix. This makes the macos and ubuntu builds pass but the windows one still fails. Looking at the artifact i see:
Unfortunately i don't have a windows machine nor i am that familiar with it. Do you happen to have any insights on why this might happen? Thanks |
...build/plugin/src/main/java/com/ncorti/ktfmt/gradle/tasks/worker/PreCommitHookFormatAction.kt
Outdated
Show resolved
Hide resolved
...build/plugin/src/main/java/com/ncorti/ktfmt/gradle/tasks/worker/PreCommitHookFormatAction.kt
Outdated
Show resolved
Hide resolved
hooksDirectory.createDirectory() | ||
} | ||
|
||
val hookFile = File("${hooksDirectory}/pre-commit") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
project.tasks.register("ktfmtPreCommitHook", KtfmtFormatTask::class.java) { | ||
it.source = project.fileTree(project.projectDir) | ||
it.doNotTrackState("Task does not require gradle cache") | ||
it.include("**/*.kt") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels wrong as you're basically recreating a format task that will reformat everything no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea behind this is that is based on the example in the readme which mentions that we can create a task to be used as pre commit. Here i tried to handle the case where the user has not added the specific task. I can remove it and check if the task (mentioned in the readme) is defined and use that. Do you think that's a better approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see. So first you can just use ktfmtFormat
. We don't need an extra task.
The problem is that it won't work well for all the source set tasks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for clarification. Just a note, trying to use ktfmtFormat
does not accept specific files --include-only
. What am i missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that it won't work well for all the source set tasks.
Yeah that's what I meant here.
Say you're applying ktfmt to a KMP project, you will have those tasks:
ktfmtFormatKmpAndroidTest - Run Ktfmt formatter validation for sourceSet 'kmp androidTest' on project 'example-kmp'
ktfmtFormatKmpAndroidTestDebug - Run Ktfmt formatter validation for sourceSet 'kmp androidTestDebug' on project 'example-kmp'
ktfmtFormatKmpAndroidTestRelease - Run Ktfmt formatter validation for sourceSet 'kmp androidTestRelease' on project 'example-kmp'
ktfmtFormatKmpCommonMain - Run Ktfmt formatter validation for sourceSet 'kmp commonMain' on project 'example-kmp'
ktfmtFormatKmpCommonTest - Run Ktfmt formatter validation for sourceSet 'kmp commonTest' on project 'example-kmp'
ktfmtFormatKmpDebug - Run Ktfmt formatter validation for sourceSet 'kmp debug' on project 'example-kmp'
ktfmtFormatKmpJvmMain - Run Ktfmt formatter validation for sourceSet 'kmp jvmMain' on project 'example-kmp'
ktfmtFormatKmpJvmTest - Run Ktfmt formatter validation for sourceSet 'kmp jvmTest' on project 'example-kmp'
ktfmtFormatKmpMain - Run Ktfmt formatter validation for sourceSet 'kmp main' on project 'example-kmp'
ktfmtFormatKmpRelease - Run Ktfmt formatter validation for sourceSet 'kmp release' on project 'example-kmp'
ktfmtFormatKmpTest - Run Ktfmt formatter validation for sourceSet 'kmp test' on project 'example-kmp'
ktfmtFormatKmpTestDebug - Run Ktfmt formatter validation for sourceSet 'kmp testDebug' on project 'example-kmp'
ktfmtFormatKmpTestFixtures - Run Ktfmt formatter validation for sourceSet 'kmp testFixtures' on project 'example-kmp'
ktfmtFormatKmpTestFixturesDebug - Run Ktfmt formatter validation for sourceSet 'kmp testFixturesDebug' on project 'example-kmp'
ktfmtFormatKmpTestFixturesRelease - Run Ktfmt formatter validation for sourceSet 'kmp testFixturesRelease' on project 'example-kmp'
ktfmtFormatKmpTestRelease - Run Ktfmt formatter validation for sourceSet 'kmp testRelease' on project 'example-kmp'
The pre-commit hook will have to invoke those tasks and pass the --include-only
flags to those
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alternative would be to use a Gradle Property, that you can set inside the commit source code as env variable to pass the --include-only
values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean setting for example ktfmtFormatKmpMain,ktfmtFormatKmpTestFixtures
as the env variable and passing the include files to these ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. I mean that we can instruct each task to read a Gradle property called ktfmt.gradle.includeOnly
. And then you'll be able to set an env variable called ORG_GRADLE_PROJECT_ktfmt.gradle.includeOnly=...
to specify the files to include.
More on this here:
https://docs.gradle.org/current/userguide/project_properties.html#sec:project_properties
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay now its more clear to me. Just to verify, that will require changing createFormatTask
to check this variable first and use it and if not present, use the existing defaultIncludes
.
Which means that if we set this variable as you have said, we can use just ktfmtFormat
Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah exactly
import org.gradle.workers.WorkerExecutor | ||
|
||
/** ktfmt-gradle Git hook task. Creates a git hook that runs ktfmt on git commit */ | ||
abstract class CreateGitPreCommitHookTask : SourceTask() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
abstract class CreateGitPreCommitHookTask : SourceTask() { | |
abstract class CreateGitPreCommitHookTask : DefaultTask() { |
@gpopides This is the cause of the Windows failure. This is not a Source Task as you're not populating the source
property. Windows is failing while attepting to MD5 the source field which is null here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the feedback, i will change that.
…s/worker/PreCommitHookFormatAction.kt Co-authored-by: Nicola Corti <[email protected]>
…s/worker/PreCommitHookFormatAction.kt Co-authored-by: Nicola Corti <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the amazing work so far @gpopides
I have added the include option as you suggested and have rebased your newest changes. Is there anything else that i have missed before going forward with this PR? |
* **Kotlin 1.4+**. In order to reformat Kotlin 1.4 code, you need run on **Gradle to 6.8+** (This is due to Gradle 6.7 | ||
embedding Kotlin 1.3.x - See [#12660](https://github.com/gradle/gradle/issues/12660)). | ||
|
||
* **Android**. `ktfmt-gradle` relies on features from **Android Gradle Plugin 4.1+**. So make sure you bump AGP before applying this plugin. | ||
* **Android**. `ktfmt-gradle` relies on features from **Android Gradle Plugin 4.1+**. So make sure you bump AGP before | ||
applying this plugin. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you amend this and other unrelated changes to the README?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, its because running the formatter.
@@ -132,10 +135,13 @@ tasks.register<KtfmtFormatTask>("ktfmtPrecommit") { | |||
} | |||
``` | |||
|
|||
You can then invoke the task with `--include-only` and a comma separated list of relative path of files: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we remove this sentence, then we would have to remove the entire section above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are probably right, my only thought is that you can still use a custom task without generating the hook. So i believe i should bring it back instead
// check if specific files are specified to be included. If not, use the default includes | ||
val includes = | ||
(project.findProperty("ktfmt.gradle.includeOnly") as String?) | ||
?.split(",") | ||
?.filter { file -> file.isNotEmpty() } | ||
?.takeIf { files -> files.isNotEmpty() } ?: KtfmtPlugin.defaultIncludes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I left a comment here but I apparently I haven't (couldn't find it anymore).
My question is: have you tried this? As setIncludes
below expects a glob, and not a list of files. If you see:
val defaultIncludes = listOf("**/*.kt", "**/*.kts")
so I'm unsure how it ends up working if you pass a list of files.
|
||
// check if specific files are specified to be included. If not, use the default includes | ||
val includes = | ||
(project.findProperty("ktfmt.gradle.includeOnly") as String?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're not handling the interaction between this Gradle property AND the use also specifying a --include-only
.
I think instead of passing the setIncludes
here, we should read the Gradle Preperty inside KtfmtBaseTask
. So the logic would be:
- If you specified a
--include-only
flag, we honor it. - If not, if you specified the
"ktfmt.gradle.includeOnly"
property, we honor it - Otherwise we just process the default includes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, makes sense. I will move it to the task while keeping the same significance order
🚀 Description
I have added 2 tasks. 1 is intented to be used by the user (
ktfmtGeneratePreCommitHook
) and 1 internal (ktfmtPreCommitHook
).ktfmtPreCommitHook
Acts pretty much the same with the example in the readme. The pre commit hook will use this task to format staged kotlin files. I have added this task in order to avoid asking the user to add the pre commit example that is present in the readme.To generate the file, the user needs to run
gradlew ktfmtGeneratePreCommitHook
The hook will be generated if :
pre-commit
hook in the hooks directory📄 Motivation and Context
This PR tries to address this issue about generating a git pre commit hook for running ktformat on commit
🧪 How Has This Been Tested?
Integration tests + manual tests on a different project.
Tested on Arch linux with Kotlin 2.0.0-Beta4 and Gradle 8.6
📦 Types of changes
✅ Checklist