<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marko Pavičić</title>
    <description>The latest articles on DEV Community by Marko Pavičić (@pavikaa).</description>
    <link>https://dev.to/pavikaa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1665930%2Ff625db69-ecbc-48a7-9796-0c7b4a4a3d2a.png</url>
      <title>DEV Community: Marko Pavičić</title>
      <link>https://dev.to/pavikaa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pavikaa"/>
    <language>en</language>
    <item>
      <title>Developing a Custom Gradle Plugin for Formatting and Static Analysis</title>
      <dc:creator>Marko Pavičić</dc:creator>
      <pubDate>Wed, 31 Jul 2024 07:05:43 +0000</pubDate>
      <link>https://dev.to/pavikaa/developing-a-custom-gradle-plugin-for-formatting-and-static-analysis-1oa4</link>
      <guid>https://dev.to/pavikaa/developing-a-custom-gradle-plugin-for-formatting-and-static-analysis-1oa4</guid>
      <description>&lt;p&gt;In our previous blogs, we explored how to integrate code formatting with ktfmt and static analysis with detekt into your projects. While these tools significantly improved our code quality and consistency, setting them up for each new project required much repetitive work. To streamline this process, we decided to develop a custom Gradle plugin that integrates both ktfmt and detekt, along with a pre-commit hook, ensuring consistent application across all our projects.&lt;/p&gt;

&lt;p&gt;This blog will guide you through creating and publishing a custom Gradle plugin that automates the integration of &lt;strong&gt;ktfmt&lt;/strong&gt; and &lt;strong&gt;detekt&lt;/strong&gt;, simplifying the setup process for new projects.&lt;/p&gt;

&lt;p&gt;We will cover publishing to a private Maven repository. If you want to publicly publish your plugin, refer to the &lt;a href="https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:usage" rel="noopener noreferrer"&gt;Gradle documentation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: We will cover publishing to a private Maven repository, therefore, this blog assumes you have a private Maven Repository Manager set up, such as Nexus, Artifactory, or similar. If you want to publish your plugin publicly to the Gradle Plugin Portal there are some small differences to this guide that you can check in this &lt;a href="https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; by the Gradle team.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This blog won't cover the specifics regarding ktfmt and detekt since that was covered in the previous blogs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrating Code Formatting into Your Android Projects:&lt;/strong&gt; &lt;a href="https://dev.to/pavikaa/integrating-code-formatting-into-your-android-projects-4gbj"&gt;dev.to&lt;/a&gt;, &lt;a href="https://medium.com/@mpavicic99/integrating-code-formatting-into-your-android-projects-663d0056dbe7" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enhancing Code Quality with detekt for Static Analysis:&lt;/strong&gt; &lt;a href="https://dev.to/pavikaa/enhancing-code-quality-with-detekt-for-static-analysis-18gc"&gt;dev.to&lt;/a&gt;, &lt;a href="https://medium.com/@mpavicic99/enhancing-code-quality-with-detekt-for-static-analysis-ebe225dcb14a" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start with a short introduction to Gradle plugins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Gradle Plugins
&lt;/h2&gt;

&lt;p&gt;Gradle plugins allow you to encapsulate reusable build logic, making it easy to apply standardized configurations across multiple projects. By developing a custom plugin, we can ensure that all our projects adhere to the same formatting and static analysis rules, reducing setup time and eliminating inconsistencies.&lt;/p&gt;

&lt;p&gt;For more information refer to the &lt;a href="https://docs.gradle.org/current/userguide/custom_plugins.html" rel="noopener noreferrer"&gt;Gradle documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's dive into the steps to create our Gradle plugin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Plugin Project
&lt;/h2&gt;

&lt;p&gt;First, we need to create a new Gradle project our plugin. This project will define the logic for integrating ktfmt and detekt and applying the pre-commit hook.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a new directory for your plugin project:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;mkdir &lt;/span&gt;precommit
  &lt;span class="nb"&gt;cd &lt;/span&gt;precommit
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialize a new Gradle project:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  gradle init
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Select the options to create a new Gradle plugin project, we will use &lt;strong&gt;Kotlin&lt;/strong&gt; and &lt;strong&gt;Kotlin DSL&lt;/strong&gt; in this guide.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvguvijk1d12rdvep4bkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvguvijk1d12rdvep4bkw.png" alt="Gradle plugin init" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure the &lt;code&gt;build.gradle.kts&lt;/code&gt; file:&lt;/strong&gt; Open the &lt;code&gt;build.gradle.kts&lt;/code&gt; file and add the following code in the plugins block:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;  &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;`kotlin-dsl`&lt;/span&gt;
      &lt;span class="n"&gt;`maven-publish`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In the code snippet above we apply the Kotlin DSL plugin and the Maven publish plugin which will be used upon publishing the plugin to a Maven repository.  &lt;/p&gt;

&lt;p&gt;Next, add the plugin project group and version:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;  &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example"&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.0.1"&lt;/span&gt; &lt;span class="c1"&gt;// You will use this version code when applying the plugin in other projects&lt;/span&gt;
  &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;After that, implement the ktfmt and detekt Gradle plugins:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;  &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.ncorti.ktfmt.gradle:0.19.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Replace with the latest version&lt;/span&gt;
      &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.6"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Replace with the latest version&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Lastly, you should configure your plugin's definition in the &lt;code&gt;gradlePlugin&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;  &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="c1"&gt;// Define the gradlePlugin block which contains the plugin configuration&lt;/span&gt;
  &lt;span class="nf"&gt;gradlePlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Define the plugins block which contains the individual plugin definitions&lt;/span&gt;
      &lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Create a new plugin configuration with the name "precommit"&lt;/span&gt;
          &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"precommit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="c1"&gt;// Set the unique identifier for the plugin&lt;/span&gt;
              &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example.precommit"&lt;/span&gt;
              &lt;span class="c1"&gt;// Set the display name for the plugin&lt;/span&gt;
              &lt;span class="n"&gt;displayName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"precommit"&lt;/span&gt;
              &lt;span class="c1"&gt;// Provide the plugin description&lt;/span&gt;
              &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
               &lt;span class="s"&gt;"Gradle plugin that adds a pre-commit hook to your project that runs detekt and ktfmt"&lt;/span&gt;
              &lt;span class="c1"&gt;// Assign tags to the plugin for easier discovery and categorization&lt;/span&gt;
              &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"detekt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ktfmt"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="c1"&gt;// Specify the fully qualified name of the class implementing the plugin&lt;/span&gt;
              &lt;span class="n"&gt;implementationClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example.PreCommitPlugin"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We want for the plugin to be configurable so it can be used across all Kotlin projects. We will allow the configurability by implementing a configuration interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Configuration Interface
&lt;/h2&gt;

&lt;p&gt;The plugin should be able to work across a wide variety of Kotlin projects, enable users to use the ktfmt style they prefer and allow the users to use Jetpack Compose specific detekt configuration when necessary. To do that we have to &lt;strong&gt;define a configuration interface:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the Configuration interface:&lt;/strong&gt; Inside the &lt;code&gt;src/main/kotlin/org/example&lt;/code&gt; directory, create a new Kotlin file named &lt;code&gt;PreCommitConfig.kt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PreCommitConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;ktfmtStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;injectHookTaskPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;GOOGLE_STYLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;KOTLIN_STYLE&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define the following configuration fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;composeEnabled&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;Indicates whether Compose-specific configuration is enabled. If set to true, detekt will include additional checks specific to Jetpack Compose projects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ktfmtStyle&lt;/td&gt;
&lt;td&gt;KtfmtStyle&lt;/td&gt;
&lt;td&gt;Specifies the ktfmt style to use for code formatting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;injectHookTaskPath&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Defines the path to the Gradle task before which the pre-commit hook script will be installed, &lt;em&gt;app:clean&lt;/em&gt; by default&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After defining configurability let's implement the plugin logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the Plugin Logic
&lt;/h2&gt;

&lt;p&gt;Next, we will create the plugin class and define the logic to apply ktfmt, detekt, and the pre-commit hook.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Creating the Plugin Class
&lt;/h4&gt;

&lt;p&gt;First, we define the &lt;code&gt;PreCommitPlugin&lt;/code&gt; class and create the &lt;code&gt;PreCommitConfig&lt;/code&gt; extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PreCommitPlugin&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create an extension for plugin configuration&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;ext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PreCommitConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"preCommitConfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Load the pre-commit script resource&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;preCommitScriptResource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;javaClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResourceAsStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scripts/pre-commit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;detektConfigResource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;javaClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResourceAsStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"detekt-config.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we set up the class and create an extension to hold configuration values. We also load resources for the pre-commit script and the detekt configuration.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Applying Plugins and Configurations
&lt;/h4&gt;

&lt;p&gt;Next, we apply the &lt;code&gt;ktfmt&lt;/code&gt; and &lt;code&gt;detekt&lt;/code&gt; plugins and configure them based on the provided extension values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;afterEvaluate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Read configuration values, providing defaults if not set&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;composeEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orNull&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;ktfmtStyle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ktfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orNull&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KOTLIN_STYLE&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;injectHookTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;injectHookTaskPath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orNull&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;"app:clean"&lt;/span&gt;

            &lt;span class="c1"&gt;// Configure all subprojects&lt;/span&gt;
            &lt;span class="nf"&gt;allprojects&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Apply ktfmt plugin and configure based on the chosen style&lt;/span&gt;
                &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.ncorti.ktfmt.gradle"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KtfmtExtension&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ktfmtStyle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GOOGLE_STYLE&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;googleStyle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KOTLIN_STYLE&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;kotlinLangStyle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Apply detekt plugin and configure&lt;/span&gt;
                &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"io.gitlab.arturbosch.detekt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DetektExtension&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// Use a specific config file for Compose projects&lt;/span&gt;
                        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$projectDir/config/detekt-config.yml"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                        &lt;span class="n"&gt;buildUponDefaultConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="n"&gt;allRules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// Don't enable all rules&lt;/span&gt;
                    &lt;span class="n"&gt;autoCorrect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Enable auto-correction&lt;/span&gt;
                    &lt;span class="n"&gt;parallel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Run detekt in parallel&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Add Compose detekt rules if Compose is enabled&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"detektPlugins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"io.nlopez.compose.rules:detekt:0.4.5"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Replace with latest version&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we apply the necessary plugins and configure them according to the extension settings, including applying specific styles for &lt;code&gt;ktfmt&lt;/code&gt; and setting up &lt;code&gt;detekt&lt;/code&gt; with optional support for Compose projects.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Configuring detekt Reports
&lt;/h4&gt;

&lt;p&gt;We ensure that the &lt;code&gt;detekt&lt;/code&gt; tasks generate the desired report formats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;                        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
                  &lt;span class="c1"&gt;// Configure detekt tasks for reporting&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Detekt&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;configureEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;reports&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Enable the generation of an HTML report&lt;/span&gt;
                    &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="c1"&gt;// Enable the generation of a TXT report&lt;/span&gt;
                    &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="c1"&gt;// Enable the generation of a Markdown (MD) report&lt;/span&gt;
                    &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sets up &lt;code&gt;detekt&lt;/code&gt; to generate HTML, text, and markdown reports.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Copying Configuration Files
&lt;/h4&gt;

&lt;p&gt;Next, we define a task to copy the configuration file for &lt;code&gt;detekt&lt;/code&gt; from the plugin resources to the project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
            &lt;span class="c1"&gt;// Task to copy the detekt config&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyDetektConfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                    &lt;span class="s"&gt;"Copies the detekt config from the plugin's directory to the app/config folder."&lt;/span&gt;
                &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"detektConfig"&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detektConfigResource&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Use a temporary file to handle the resource stream&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTempDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"detekt-config-temp"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"detekt-config.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;detektConfigResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPath&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                            &lt;span class="nc"&gt;StandardCopyOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE_EXISTING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying detekt config from: ${tempFile.absolutePath}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Failed to copy detekt config resource: ${e.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;detektConfigResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Close the resource stream&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"detekt config resource not found in the plugin."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${rootDir}/app/config/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying detekt config to: ${rootDir}/app/config/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following code defines a task that copies the git hook from the plugin's resources to the project's git hooks directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
            &lt;span class="c1"&gt;// Task to copy the pre-commit hook script&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Copies the git hooks from the plugin's directory to the .git folder."&lt;/span&gt;
                &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gitHooks"&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preCommitScriptResource&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Use a temporary file to handle the resource stream&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTempDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"git-hooks-temp"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;preCommitScriptResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPath&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                            &lt;span class="nc"&gt;StandardCopyOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE_EXISTING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying git hooks from: ${tempFile.absolutePath}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Failed to copy git hooks resource: ${e.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;preCommitScriptResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Close the resource stream&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Git hooks resource not found in the plugin."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${rootDir}/.git/hooks/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying git hooks to: ${rootDir}/.git/hooks/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyDetektConfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Installing Git Hooks
&lt;/h4&gt;

&lt;p&gt;Finally, we create a task to make the git hooks executable and inject this task as a dependency of another specified task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
            &lt;span class="c1"&gt;// Task to install (make executable) the pre-commit hook&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"installGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Installs the pre-commit git hooks."&lt;/span&gt;
                &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gitHooks"&lt;/span&gt;
                &lt;span class="n"&gt;workingDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rootDir&lt;/span&gt;
                &lt;span class="n"&gt;commandLine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"chmod"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-R"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"+x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".git/hooks/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;doLast&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Git hook installed successfully."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Make the specified build task depend on installing the git hooks&lt;/span&gt;
            &lt;span class="nf"&gt;afterEvaluate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;injectHookTask&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":installGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This task ensures the pre-commit hook script is executable and sets it up to run as a dependency of another specified task (e.g., &lt;code&gt;app:clean&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The specified task depends on the installGitHooks task, &lt;code&gt;installGitHooks&lt;/code&gt; depends on &lt;code&gt;copyGitHooks&lt;/code&gt; and &lt;code&gt;copyGitHooks&lt;/code&gt; depends on &lt;code&gt;copyDetektConfig&lt;/code&gt;, in that way, we ensure all tasks are run as a dependency on the specified task.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;PreCommitPlugin.kt&lt;/code&gt; should now look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PreCommitPlugin&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create an extension for plugin configuration&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;ext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PreCommitConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"preCommitConfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Load the pre-commit script resource&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;preCommitScriptResource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;javaClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResourceAsStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scripts/pre-commit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;detektConfigResource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;javaClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResourceAsStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"detekt-config.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;afterEvaluate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Read configuration values, providing defaults if not set&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;composeEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orNull&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;ktfmtStyle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ktfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orNull&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KOTLIN_STYLE&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;injectHookTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;injectHookTaskPath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orNull&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;"app:clean"&lt;/span&gt;

            &lt;span class="c1"&gt;// Configure all subprojects&lt;/span&gt;
            &lt;span class="nf"&gt;allprojects&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Apply ktfmt plugin and configure based on chosen style&lt;/span&gt;
                &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.ncorti.ktfmt.gradle"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KtfmtExtension&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ktfmtStyle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GOOGLE_STYLE&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;googleStyle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KOTLIN_STYLE&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;kotlinLangStyle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Apply detekt plugin and configure&lt;/span&gt;
                &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"io.gitlab.arturbosch.detekt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DetektExtension&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// Use a specific config file for Compose projects&lt;/span&gt;
                        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$projectDir/config/detekt-config.yml"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                        &lt;span class="n"&gt;buildUponDefaultConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="n"&gt;allRules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// Don't enable all rules&lt;/span&gt;
                    &lt;span class="n"&gt;autoCorrect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Enable auto-correction&lt;/span&gt;
                    &lt;span class="n"&gt;parallel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Run detekt in parallel&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Add Compose detekt rules if Compose is enabled&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"detektPlugins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"io.nlopez.compose.rules:detekt:0.4.5"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Configure detekt tasks for reporting&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Detekt&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;configureEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;reports&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Enable the generation of an HTML report&lt;/span&gt;
                    &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="c1"&gt;// Enable the generation of a TXT report&lt;/span&gt;
                    &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="c1"&gt;// Enable the generation of a Markdown (MD) report&lt;/span&gt;
                    &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Task to copy the detekt config&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyDetektConfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                    &lt;span class="s"&gt;"Copies the detekt config from the plugin's directory to the app/config folder."&lt;/span&gt;
                &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"detektConfig"&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detektConfigResource&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Use a temporary file to handle the resource stream&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTempDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"detekt-config-temp"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"detekt-config.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;detektConfigResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPath&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                            &lt;span class="nc"&gt;StandardCopyOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE_EXISTING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying detekt config from: ${tempFile.absolutePath}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Failed to copy detekt config resource: ${e.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;detektConfigResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Close the resource stream&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"detekt config resource not found in the plugin."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${rootDir}/app/config/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying detekt config to: ${rootDir}/app/config/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Task to copy the pre-commit hook script&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Copies the git hooks from the plugin's directory to the .git folder."&lt;/span&gt;
                &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gitHooks"&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preCommitScriptResource&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Use a temporary file to handle the resource stream&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTempDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"git-hooks-temp"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tempFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;preCommitScriptResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPath&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                            &lt;span class="nc"&gt;StandardCopyOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE_EXISTING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying git hooks from: ${tempFile.absolutePath}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Failed to copy git hooks resource: ${e.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;preCommitScriptResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Close the resource stream&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Git hooks resource not found in the plugin."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${rootDir}/.git/hooks/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Copying git hooks to: ${rootDir}/.git/hooks/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;composeEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyDetektConfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Task to install (make executable) the pre-commit hook&lt;/span&gt;
            &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"installGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Installs the pre-commit git hooks."&lt;/span&gt;
                &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gitHooks"&lt;/span&gt;
                &lt;span class="n"&gt;workingDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rootDir&lt;/span&gt;
                &lt;span class="n"&gt;commandLine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"chmod"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-R"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"+x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".git/hooks/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"copyGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;doLast&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Git hook installed successfully."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Make the specified build task depend on installing the git hooks&lt;/span&gt;
            &lt;span class="nf"&gt;afterEvaluate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;injectHookTask&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":installGitHooks"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will add the pre-commit script and detekt configuration files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Pre-Commit Script and detekt Configuration
&lt;/h2&gt;

&lt;p&gt;For our plugin to work, we need to include the pre-commit script and detekt configuration file in our plugin resources. We created these files in the previous blogs, so we will just share the code for them, for more information please refer to the blogs mentioned at the top.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create the pre-commit script:&lt;/strong&gt; Inside the &lt;code&gt;src/main/resources/scripts&lt;/code&gt; directory, create a file named &lt;code&gt;pre-commit&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
===================================
|  Formatting code with ktfmt...  |
==================================="&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; ./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; ktfmtFormat &lt;span class="nt"&gt;--stacktrace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ktfmt failed"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
=======================
|  Running detekt...  |
======================="&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; ./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; detekt &lt;span class="nt"&gt;--stacktrace&lt;/span&gt; &lt;span class="nt"&gt;-PdisablePreDex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"detekt failed"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; git &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Git could not be found"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;git add &lt;span class="nt"&gt;-u&lt;/span&gt;

&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create the pre-commit script:&lt;/strong&gt; Inside the &lt;code&gt;src/main/resources&lt;/code&gt; directory, create a file named &lt;code&gt;detekt-config.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Compose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;ComposableAnnotationNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ComposableNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ComposableParamOrder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;CompositionLocalAllowlist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="na"&gt;allowedCompositionLocals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LocalCustomColorsPalette,LocalCustomTypography&lt;/span&gt;
 &lt;span class="na"&gt;CompositionLocalNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ContentEmitterReturningValues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;DefaultsVisibility&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;LambdaParameterInRestartableEffect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ModifierClickableOrder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ModifierComposable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ModifierMissing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ModifierNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ModifierNotUsedAtRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ModifierReused&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ModifierWithoutDefault&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;MultipleEmitters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;MutableParams&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;MutableStateParam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;PreviewAnnotationNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;PreviewPublic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;RememberMissing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;RememberContentMissing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;UnstableCollections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ViewModelForwarding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ViewModelInjection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;naming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;FunctionNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;ignoreAnnotated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Composable'&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
 &lt;span class="na"&gt;TopLevelPropertyNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;constantPattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[A-Z][A-Za-z0-9]*'&lt;/span&gt;

&lt;span class="na"&gt;complexity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;LongParameterList&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;functionThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
   &lt;span class="na"&gt;ignoreDefaultParameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

 &lt;span class="na"&gt;LongMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;MagicNumber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
 &lt;span class="na"&gt;UnusedPrivateMember&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;ignoreAnnotated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Preview'&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that's it, you implemented a Gradle plugin that will apply ktfmt and detekt, neccessary configuration and a pre-commit hook on any project. By doing this you avoided repeating the project for every project. But, before you can apply it to your projects, there is one thing left to do and that is the publishing of your plugin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing the Gradle Plugin to a private repository
&lt;/h2&gt;

&lt;p&gt;After implementing the plugin, the final step is to publish it so you can use it across your projects. This process involves setting up your project for publication and configuring the necessary details for publishing to a repository. We will cover publishing to a private Maven repository. If you want to publish your plugin publicly, please check the notes at the beginning of this blog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Check Requirements
&lt;/h3&gt;

&lt;p&gt;Ensure the &lt;code&gt;maven-publish&lt;/code&gt; plugin is applied in your &lt;code&gt;build.gradle.kts&lt;/code&gt;. This plugin provides the necessary tasks and configurations to publish your artifacts to a Maven repository. Also, make sure you have set up the &lt;code&gt;gradlePlugin&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;`maven-publish`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;gradlePlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"precommit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example.precommit"&lt;/span&gt;
            &lt;span class="n"&gt;displayName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"PreCommit"&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Gradle plugin that adds a pre-commit hook to your project that runs detekt and ktfmt"&lt;/span&gt;
            &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"detekt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ktfmt"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;implementationClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.example.PreCommitPlugin"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Prepare for Publication
&lt;/h3&gt;

&lt;p&gt;Ensure your project is set up with the necessary metadata and credentials to publish the plugin. To tell the &lt;code&gt;maven-publish&lt;/code&gt; plugin where to publish the plugin, you need to set up the publishing block. Define the URL to your Maven repository and the accompanying credentials. Since we are working with sensitive information, store these inside the &lt;code&gt;gradle.properties&lt;/code&gt; file, which should be inside the &lt;code&gt;.gitignore&lt;/code&gt; file to avoid leaking credentials. Your &lt;code&gt;gradle.properties&lt;/code&gt; should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;username&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_username&lt;/span&gt;
&lt;span class="py"&gt;password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_password&lt;/span&gt;
&lt;span class="py"&gt;url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://nexus.example.org/repository/kotlin-packages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up the &lt;code&gt;publishing&lt;/code&gt; block by adding the following code to your &lt;code&gt;build.gradle.kts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;publishing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;maven&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;credentials&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Publish the Plugin
&lt;/h3&gt;

&lt;p&gt;With everything configured, you can now publish your plugin. Use the following command to publish the plugin to your repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will build the plugin and upload it to the specified Maven repository. Ensure you have network access and the correct credentials configured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Using the Published Plugin
&lt;/h3&gt;

&lt;p&gt;Since you published your plugin to the private Maven repository, you need to provide the URL and credentials so it can be downloaded into your projects. If you published your plugin publicly or to the local Maven repository, you can skip this step. Inside your project, create a &lt;code&gt;local.properties&lt;/code&gt; file and add it to &lt;code&gt;.gitignore&lt;/code&gt;. Add the following contents to &lt;code&gt;local.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;username&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_username&lt;/span&gt;
&lt;span class="py"&gt;password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_password&lt;/span&gt;
&lt;span class="py"&gt;url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://nexus.example.org/repository/kotlin-packages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, define the Maven repository inside &lt;code&gt;settings.gradle.kts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;localProperties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FileInputStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"local.properties"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;maven&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;credentials&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localProperties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localProperties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localProperties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding the Maven URL and credentials, you can apply the plugin inside your project by including it in the top-level &lt;code&gt;build.gradle.kts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.example.precommit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"0.0.1"&lt;/span&gt; &lt;span class="c1"&gt;// The plugin version we defined in the plugin build.gradle.kts&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;preKommitConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;composeEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;ktfmtStyle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KtfmtStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KOTLIN_STYLE&lt;/span&gt;
    &lt;span class="n"&gt;injectHookTaskPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"app:preBuild"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By doing this, you apply ktfmt and detekt to all of your project modules, ensuring consistent code quality and code styling across your entire codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By developing a custom Gradle plugin, we've streamlined the process of integrating &lt;code&gt;ktfmt&lt;/code&gt; and &lt;code&gt;detekt&lt;/code&gt; across multiple projects. This plugin ensures consistent code formatting and static analysis, reducing setup time and improving code quality. This blog covered the essential steps to create, configure, and publish a Gradle plugin that automates the integration of &lt;code&gt;ktfmt&lt;/code&gt; and &lt;code&gt;detekt&lt;/code&gt;, along with setting up a pre-commit hook. With this plugin, you can ensure that all your projects follow the same standards with minimal effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/pavikaa/integrating-code-formatting-into-your-android-projects-4gbj"&gt;Integrating Code Formatting into Your Android Projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pavikaa/enhancing-code-quality-with-detekt-for-static-analysis-18gc"&gt;Enhancing Code Quality with detekt for Static Analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html" rel="noopener noreferrer"&gt;Publishing Plugins to the Gradle Plugin Portal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kotlin</category>
      <category>gradle</category>
      <category>codequality</category>
      <category>formatting</category>
    </item>
    <item>
      <title>Enhancing Code Quality with detekt for Static Analysis</title>
      <dc:creator>Marko Pavičić</dc:creator>
      <pubDate>Tue, 16 Jul 2024 09:02:18 +0000</pubDate>
      <link>https://dev.to/pavikaa/enhancing-code-quality-with-detekt-for-static-analysis-18gc</link>
      <guid>https://dev.to/pavikaa/enhancing-code-quality-with-detekt-for-static-analysis-18gc</guid>
      <description>&lt;p&gt;When our team began migrating to &lt;strong&gt;Jetpack Compose&lt;/strong&gt;, we wanted to avoid common mistakes due to our limited expertise. We discovered &lt;a href="https://github.com/detekt/detekt" rel="noopener noreferrer"&gt;detekt&lt;/a&gt;, a tool that provides static code analysis for Kotlin projects, and &lt;a href="https://github.com/mrmans0n/compose-rules" rel="noopener noreferrer"&gt;compose-rules&lt;/a&gt;, which integrates Jetpack Compose-specific checks into detekt. We also wanted to implement these tools into the pre-commit hook we implemented in the previous blog post (&lt;a href="https://dev.to/pavikaa/integrating-code-formatting-into-your-android-projects-4gbj"&gt;dev.to&lt;/a&gt;, &lt;a href="https://medium.com/@mpavicic99/integrating-code-formatting-into-your-android-projects-663d0056dbe7" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This blog will guide you through the steps to integrate detekt into your projects and fine-tune its configuration to optimize performance for Jetpack Compose projects.&lt;/p&gt;

&lt;p&gt;Let's start with a short introduction to static code analysis and its purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Static Code Analysis
&lt;/h2&gt;

&lt;p&gt;Static code analysis helps in identifying potential issues, enforcing coding standards, and ensuring code quality and maintainability. By catching issues early in the development process, it can save time and effort, ultimately leading to more robust and reliable software.&lt;/p&gt;

&lt;p&gt;Our tool of choice was &lt;strong&gt;detekt&lt;/strong&gt;, here's a quick overview of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to detekt
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/detekt/detekt" rel="noopener noreferrer"&gt;detekt&lt;/a&gt; is a static code analysis tool for Kotlin projects. We chose it for our projects due to its comprehensive set of rules, ease of integration, and active community support. It offers features such as customizable rules, reporting capabilities, and integration with popular build tools, making it a valuable addition to our development workflow.&lt;/p&gt;

&lt;p&gt;Let's set it up in our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up detekt
&lt;/h2&gt;

&lt;p&gt;To implement detekt into your projects, simply add the detekt dependency to your Top-level &lt;code&gt;build.gradle&lt;/code&gt; or &lt;code&gt;build.gradle.kts&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.gitlab.arturbosch.detekt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.23.6"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Replace with latest version&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After adding the detekt Gradle plugin, here's how you can configure it to better match your requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;detekt offers a lot of customizability, which allowed us to use it effectively on our Jetpack Compose projects. You can fine-tune the rules, console reports, output reports, and similar. &lt;/p&gt;

&lt;p&gt;When you use it on &lt;strong&gt;Jetpack Compose&lt;/strong&gt; projects, it requires some additional configuration via the &lt;code&gt;detekt-config.yml&lt;/code&gt; file. While researching detekt and its configuration, we also came across &lt;a href="https://github.com/mrmans0n/compose-rules" rel="noopener noreferrer"&gt;compose-rules&lt;/a&gt; which came to rescue when we were migrating from XML to Jetpack Compose. From their overview:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Compose Rules is a set of custom Ktlint / detekt rules to ensure that your composables don't fall into common pitfalls, that might be easy to miss in code reviews.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For detekt to work properly and efficiently on Jetpack Compose projects, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to your project's root directory, e.g., &lt;code&gt;~/projects/SampleProject/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new directory named &lt;code&gt;configs&lt;/code&gt; and inside it, create a new file named &lt;code&gt;detekt-config.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your file tree should look like this when viewing your project from the Project view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tdxh53wnvx4pnhnmstu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tdxh53wnvx4pnhnmstu.png" alt="config_file_tree"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the file with a text editor and paste the configuration found &lt;a href="https://mrmans0n.github.io/compose-rules/detekt/#enabling-rules" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the Jetpack Compose-specific detekt &lt;a href="https://detekt.dev/docs/introduction/compose" rel="noopener noreferrer"&gt;configuration&lt;/a&gt; at the end of the file&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;naming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;FunctionNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;ignoreAnnotated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Composable'&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
 &lt;span class="na"&gt;TopLevelPropertyNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;constantPattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[A-Z][A-Za-z0-9]*'&lt;/span&gt;

&lt;span class="na"&gt;complexity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;LongParameterList&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;functionThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
   &lt;span class="na"&gt;ignoreDefaultParameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

 &lt;span class="na"&gt;LongMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;MagicNumber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
 &lt;span class="na"&gt;UnusedPrivateMember&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;ignoreAnnotated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Preview'&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration is added to avoid false positives, for example, the default &lt;code&gt;functionThreshold&lt;/code&gt; value inside the &lt;code&gt;LongParameterList&lt;/code&gt;  rule is &lt;strong&gt;6&lt;/strong&gt; which can easily be exceeded with complex Composable functions.&lt;/p&gt;

&lt;p&gt;The complete &lt;code&gt;detekt-config.yml&lt;/code&gt; should look like this:&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Compose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;ComposableAnnotationNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ComposableNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally disable the checks in this rule for regex matches against the composable name (e.g. molecule presenters)&lt;/span&gt;
   &lt;span class="c1"&gt;# allowedComposableFunctionNames: .*Presenter,.*MoleculePresenter&lt;/span&gt;
 &lt;span class="na"&gt;ComposableParamOrder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally have a list of types to be treated as lambdas (e.g. typedefs or fun interfaces not picked up automatically)&lt;/span&gt;
   &lt;span class="c1"&gt;# treatAsLambda: MyLambdaType&lt;/span&gt;
 &lt;span class="na"&gt;CompositionLocalAllowlist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="na"&gt;allowedCompositionLocals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LocalCustomColorsPalette,LocalCustomTypography&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally define a list of CompositionLocals that are allowed here&lt;/span&gt;
   &lt;span class="c1"&gt;# allowedCompositionLocals: LocalSomething,LocalSomethingElse&lt;/span&gt;
 &lt;span class="na"&gt;CompositionLocalNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ContentEmitterReturningValues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own composables here&lt;/span&gt;
   &lt;span class="c1"&gt;# contentEmitters: MyComposable,MyOtherComposable&lt;/span&gt;
 &lt;span class="na"&gt;DefaultsVisibility&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;LambdaParameterInRestartableEffect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally have a list of types to be treated as lambdas (e.g. typedefs or fun interfaces not picked up automatically)&lt;/span&gt;
   &lt;span class="c1"&gt;# treatAsLambda: MyLambdaType&lt;/span&gt;
 &lt;span class="na"&gt;ModifierClickableOrder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own Modifier types&lt;/span&gt;
   &lt;span class="c1"&gt;# customModifiers: BananaModifier,PotatoModifier&lt;/span&gt;
 &lt;span class="na"&gt;ModifierComposable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own Modifier types&lt;/span&gt;
   &lt;span class="c1"&gt;# customModifiers: BananaModifier,PotatoModifier&lt;/span&gt;
 &lt;span class="na"&gt;ModifierMissing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally control the visibility of which composables to check for here&lt;/span&gt;
   &lt;span class="c1"&gt;# -- Possible values are: `only_public`, `public_and_internal` and `all` (default is `only_public`)&lt;/span&gt;
   &lt;span class="c1"&gt;# checkModifiersForVisibility: only_public&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own Modifier types&lt;/span&gt;
   &lt;span class="c1"&gt;# customModifiers: BananaModifier,PotatoModifier&lt;/span&gt;
 &lt;span class="na"&gt;ModifierNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own Modifier types&lt;/span&gt;
   &lt;span class="c1"&gt;# customModifiers: BananaModifier,PotatoModifier&lt;/span&gt;
 &lt;span class="na"&gt;ModifierNotUsedAtRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own composables here&lt;/span&gt;
   &lt;span class="c1"&gt;# contentEmitters: MyComposable,MyOtherComposable&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own Modifier types&lt;/span&gt;
   &lt;span class="c1"&gt;# customModifiers: BananaModifier,PotatoModifier&lt;/span&gt;
 &lt;span class="na"&gt;ModifierReused&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own Modifier types&lt;/span&gt;
   &lt;span class="c1"&gt;# customModifiers: BananaModifier,PotatoModifier&lt;/span&gt;
 &lt;span class="na"&gt;ModifierWithoutDefault&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;MultipleEmitters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own composables here that will count as content emitters&lt;/span&gt;
   &lt;span class="c1"&gt;# contentEmitters: MyComposable,MyOtherComposable&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can add composables here that you don't want to count as content emitters (e.g. custom dialogs or modals)&lt;/span&gt;
   &lt;span class="c1"&gt;# contentEmittersDenylist: MyNonEmitterComposable&lt;/span&gt;
 &lt;span class="na"&gt;MutableParams&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;MutableStateParam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;PreviewAnnotationNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;PreviewPublic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;RememberMissing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;RememberContentMissing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;UnstableCollections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="na"&gt;ViewModelForwarding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally use this rule on things other than types ending in "ViewModel" or "Presenter" (which are the defaults). You can add your own via a regex here:&lt;/span&gt;
   &lt;span class="c1"&gt;# allowedStateHolderNames: .*ViewModel,.*Presenter&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add an allowlist for Composable names that won't be affected by this rule&lt;/span&gt;
   &lt;span class="c1"&gt;# allowedForwarding: .*Content,.*FancyStuff&lt;/span&gt;
 &lt;span class="na"&gt;ViewModelInjection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="c1"&gt;# -- You can optionally add your own ViewModel factories here&lt;/span&gt;
   &lt;span class="c1"&gt;# viewModelFactories: hiltViewModel,potatoViewModel&lt;/span&gt;

&lt;span class="na"&gt;naming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;FunctionNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;ignoreAnnotated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Composable'&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
 &lt;span class="na"&gt;TopLevelPropertyNaming&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;constantPattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[A-Z][A-Za-z0-9]*'&lt;/span&gt;

&lt;span class="na"&gt;complexity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;LongParameterList&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;functionThreshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
   &lt;span class="na"&gt;ignoreDefaultParameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

 &lt;span class="na"&gt;LongMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;MagicNumber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
 &lt;span class="na"&gt;UnusedPrivateMember&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;ignoreAnnotated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Preview'&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration enables the compose-rules and modifies some of detekt's default rule sets and their configuration options to avoid incorrect detection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the file and close the editor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;At your Top-level &lt;code&gt;build.gradle&lt;/code&gt; or &lt;code&gt;build.gradle.kts&lt;/code&gt; add the following code:&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;   &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
   &lt;span class="nf"&gt;allprojects&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
       &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"io.gitlab.arturbosch.detekt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="c1"&gt;// Configure the detekt plugin&lt;/span&gt;
       &lt;span class="nf"&gt;detekt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="c1"&gt;// Set the detekt configuration from previous steps&lt;/span&gt;
           &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$projectDir/config/detekt-config.yml"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

           &lt;span class="c1"&gt;// Build upon the default detekt configuration, instead of replacing it&lt;/span&gt;
           &lt;span class="n"&gt;buildUponDefaultConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;

           &lt;span class="c1"&gt;// Do not activate all detekt rules&lt;/span&gt;
           &lt;span class="n"&gt;allRules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;

           &lt;span class="c1"&gt;// Enable automatic correction of issues found by detekt&lt;/span&gt;
           &lt;span class="n"&gt;autoCorrect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;

           &lt;span class="c1"&gt;// Run detekt in parallel mode for better performance&lt;/span&gt;
           &lt;span class="n"&gt;parallel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code snippet above configures the detekt plugin to build upon the default configuration and apply the configuration we defined inside the &lt;code&gt;detekt-config.yml&lt;/code&gt; file. We set &lt;code&gt;allRules&lt;/code&gt; to false so unstable rules aren't applied. &lt;code&gt;autoCorrect&lt;/code&gt; is set to true so that if a rule supports auto correction it is applied to the code, &lt;code&gt;parallel&lt;/code&gt; ensures parallel compilation and analysis of source files.&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="c1"&gt;// Configure each detekt task&lt;/span&gt;
&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Detekt&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;configureEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;reports&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Enable the generation of an HTML report&lt;/span&gt;
        &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"build/reports/detekt.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="c1"&gt;// Enable the generation of a TXT report&lt;/span&gt;
        &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"build/reports/detekt.txt"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="c1"&gt;// Enable the generation of a Markdown (MD) report&lt;/span&gt;
        &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"build/reports/detekt.md"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code snippet above cofigures all detekt tasks to generate HTML, TXT and Markdown reports and to save them in the &lt;code&gt;build/reports&lt;/code&gt; directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;At your Top-level &lt;code&gt;build.gradle&lt;/code&gt; or &lt;code&gt;build.gradle.kts&lt;/code&gt; add the following code to apply the compose-rules detekt rule set:&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;   &lt;span class="nf"&gt;allprojects&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
   &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
       &lt;span class="nf"&gt;detektPlugins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.nlopez.compose.rules:detekt:0.4.4"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Replace with latest version&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sync your project with Gradle Files&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These steps provide you with somewhat of a basic setup when using detekt on Jetpack Compose projects, feel free to modify it and try out different configurations that better suit your needs. For a complete list of configuration fields, please refer to: &lt;a href="https://detekt.dev/docs/gettingstarted/gradle#options-for-detekt-configuration-closure" rel="noopener noreferrer"&gt;Options for detekt configuration closure&lt;/a&gt; and &lt;a href="https://detekt.dev/docs/introduction/configurations" rel="noopener noreferrer"&gt;detekt Configuration File&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After you implemented and configured detekt to run on your project, it's time to run it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Running detekt
&lt;/h2&gt;

&lt;p&gt;After implementing the necessary dependencies for detekt, applying the configuration, and syncing your project with Gradle Files, you can run the detekt Gradle task. That can be done by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Gradle tool window:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the Gradle tool window&lt;/li&gt;
&lt;li&gt;Navigate to Tasks/verification&lt;/li&gt;
&lt;li&gt;Double-click on the detekt task (or right-click and click on Run)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7r5f85sb4fn5c8soadc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7r5f85sb4fn5c8soadc.png" alt="gradle_tool_window"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The terminal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the Terminal window inside Android Studio&lt;/li&gt;
&lt;li&gt;Run the following command: &lt;code&gt;./gradlew detekt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl96grmfguzo4aa24rcd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl96grmfguzo4aa24rcd.png" alt="terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The task failed because code issues were detected, we will dive deeper into reading these reports in a section below.&lt;/p&gt;

&lt;p&gt;Since we implemented a pre-commit hook for ktmft we will make use of it for detekt as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding detekt to the pre-commit hook
&lt;/h3&gt;

&lt;p&gt;To avoid having to run this task manually, we can make use of the pre-commit hook we implemented in the previous blog in the series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to your project's root directory, e.g., &lt;code&gt;~/projects/SampleProject/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Toggle hidden files and folders visibility [&lt;a href="https://support.microsoft.com/en-us/windows/view-hidden-files-and-folders-in-windows-97fbc472-c603-9d90-91d0-1166d1d9f4b5" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;, &lt;a href="https://discussions.apple.com/thread/7581737?sortBy=best" rel="noopener noreferrer"&gt;MacOS&lt;/a&gt;, &lt;a href="https://gcore.com/learning/how-to-show-hidden-files-in-linux/" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to &lt;code&gt;rootProjectDir/.git/hooks&lt;/code&gt; and open the file named &lt;code&gt;pre-commit&lt;/code&gt;, which we created previously with a text editor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the file with a text editor and add the following code: &lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;... 
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
=======================
|  Running detekt...  |
======================="&lt;/span&gt;

&lt;span class="c"&gt;# Run detekt static code analysis with Gradle&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; ./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; detekt &lt;span class="nt"&gt;--stacktrace&lt;/span&gt; &lt;span class="nt"&gt;-PdisablePreDex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
   &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"detekt failed"&lt;/span&gt;
   &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
... 

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The complete script should now look like this:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Exit immediately if a command exits with a non-zero status&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
===================================
|  Formatting code with ktfmt...  |
==================================="&lt;/span&gt;

&lt;span class="c"&gt;# Run ktfmt formatter on the specified files using Gradle&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; ./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; ktfmtPrecommitFormat&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
   &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ktfmt failed"&lt;/span&gt;
   &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
=======================
|  Running detekt...  |
======================="&lt;/span&gt;

&lt;span class="c"&gt;# Run detekt static code analysis with Gradle&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; ./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; detekt &lt;span class="nt"&gt;--stacktrace&lt;/span&gt; &lt;span class="nt"&gt;-PdisablePreDex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
   &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"detekt failed"&lt;/span&gt;
   &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Check if git is available&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; git &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
   &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"git could not be found"&lt;/span&gt;
   &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Add all updated files to the git staging area&lt;/span&gt;
git add &lt;span class="nt"&gt;-u&lt;/span&gt;

&lt;span class="c"&gt;# Exit the script successfully&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the file and close the editor&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After we ran detekt, we found some issues, now we will dive deeper into reading those reports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspecting detekt reports
&lt;/h2&gt;

&lt;p&gt;When we configured detekt we enabled HTML, text and Markdown reports. We will focus on the HTML report, but other output formats are very similar.&lt;/p&gt;

&lt;p&gt;detekt found issues when we first ran it in the section above, let's see that report in HTML: &lt;/p&gt;

&lt;h3&gt;
  
  
  Metrics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;number of properties&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;number of functions&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;number of classes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;number of packages&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;number of kt files&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ehbtopanxjots3nyfh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ehbtopanxjots3nyfh1.png" alt="metrics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity Report
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;lines of code (loc):&lt;/strong&gt; The total number of lines in the codebase, including all code, comments, and whitespace. This gives an overall sense of the size of the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;source lines of code (sloc):&lt;/strong&gt; This metric includes only the lines that contain actual source code, excluding comments and whitespace. It's a more accurate representation of the amount of code written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;logical lines of code (lloc):&lt;/strong&gt; This includes lines of code that represent executable statements, ignoring comments, whitespace, and block delimiters. It provides a clearer picture of the code's functional size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;comment lines of code (cloc):&lt;/strong&gt; The total number of lines that contain comments. This helps in understanding the documentation level within the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cyclomatic complexity (mcc):&lt;/strong&gt; A measure of the code's complexity, calculated by counting the number of linearly independent paths through the code. Higher values indicate more complex code, which is harder to test and maintain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cognitive complexity:&lt;/strong&gt; This measures how difficult the code is to understand. Unlike cyclomatic complexity, which focuses on the structure, cognitive complexity considers the human aspect of code comprehension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;number of total code smells:&lt;/strong&gt; Code smells are indicators of potential problems in the code. This metric counts all identified code smells, which can help in prioritizing refactoring efforts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;comment source ratio:&lt;/strong&gt; This is the ratio of comment lines to source lines of code (cloc/sloc). A higher ratio typically indicates better-documented code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mcc per 1,000 lloc:&lt;/strong&gt; This normalizes cyclomatic complexity by logical lines of code, showing how complex the code is on a per 1,000 lines basis. It helps compare complexity across different-sized projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;code smells per 1,000 lloc:&lt;/strong&gt; This metric normalizes the number of code smells by logical lines of code, providing a density measure that helps in identifying areas that may need more attention regardless of the project's size.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7c33swsgafg95xp4syh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7c33swsgafg95xp4syh.png" alt="complexity_report"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Findings
&lt;/h3&gt;

&lt;p&gt;The Findings section in a detekt report identifies specific issues in the codebase that need attention. These issues are categorized by type and include details such as location, message, and relevant code snippets.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Total:&lt;/strong&gt; The total number of findings detected by detekt, indicating the overall number of issues in the codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  [Category]
&lt;/h4&gt;

&lt;p&gt;Each category represents a specific type of issue detected. Examples of categories include "Compose", "style", "formatting", etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;RuleName:&lt;/strong&gt; Each rule represents a specific coding standard or best practice that the code should adhere to. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation:&lt;/strong&gt; A link to detailed documentation about the rule. This documentation provides more in-depth information about why the rule exists, examples of violations, and how to resolve them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; This indicates the exact file and line number where the issue is found. It helps developers quickly locate the problematic code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message:&lt;/strong&gt; A description of the issue, explaining what is wrong and why it should be fixed. This often includes guidance on how to correct the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Snippet:&lt;/strong&gt; A portion of the code where the issue is detected is highlighted to give context to the finding.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi7w6ostj468gds1bx9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi7w6ostj468gds1bx9z.png" alt="findings_1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The finding above comes from the compose-rules rule set and the findings below from detekt's rule set.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66v32229w4d97ilpbv2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66v32229w4d97ilpbv2e.png" alt="findings_2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some issues detekt reports could be acceptable to you, and you don't want to change your code. To avoid detekt reporting these issues, you can suppress them, which we will describe below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suppressing Issues
&lt;/h2&gt;

&lt;p&gt;Since we implemented detekt in a pre-commit hook that will block the commit if there are any issues, you will quickly encounter an issue that blocks the commit, but you and the team have no concern with it. &lt;/p&gt;

&lt;p&gt;To suppress issues in detekt you can add the &lt;code&gt;@Suppress&lt;/code&gt; annotation.&lt;br&gt;
Inside the values field of the &lt;code&gt;@Suppress&lt;/code&gt; annotation, you need to write the &lt;code&gt;RuleName&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Preview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showBackground&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;GreetingPreview&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;BlogSampleTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Android"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This block of code produces the following issue: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PreviewPublic: 1 Composables annotated with @Preview that are used only for previewing the UI should not be public.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To suppress this issue you can add the &lt;code&gt;@Suppress&lt;/code&gt; annotation like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Suppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PreviewPublic"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Preview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showBackground&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;GreetingPreview&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;BlogSampleTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Android"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can also suppress issues at the file level. In the previous example, you could have added the following line at the very top of the file: &lt;code&gt;@file:Suppress("PreviewPublic")&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits and Challenges
&lt;/h2&gt;

&lt;p&gt;Since integrating detekt, we have observed several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Migration from XML to Jetpack Compose:&lt;/strong&gt; Our migration process has been greatly impacted by implementing detekt, the migration and learning process were accelerated, and some common mistakes were caught on time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved Code Quality:&lt;/strong&gt; detekt has helped us identify and address code smells, resulting in cleaner and more maintainable code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent Standards:&lt;/strong&gt;  By enforcing coding standards, detekt ensures that all team members adhere to the same guidelines, improving code consistency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced Learning:&lt;/strong&gt;  The feedback provided by detekt has been instrumental in helping developers learn and adopt best practices.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, we also faced some challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuration Complexity:&lt;/strong&gt;  Initial configuration and customization of detekt to suit our specific needs required some effort and research.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;False Positives:&lt;/strong&gt;  In some cases, detekt flagged issues that were not necessarily problematic, requiring us to fine-tune the rules or suppress them.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you for taking the time to read this post. We hope it has provided valuable insights into the benefits of using detekt and inspired you to implement it in your projects.&lt;/p&gt;

&lt;p&gt;Initially, we implemented detekt on a single project. This setup, described above, involved configuring rules and integrating it into our build process. However, when we moved to implement detekt on another project, we quickly realized we needed to go through the entire configuration process again for each new project. This repetition highlighted the need for a more streamlined and reusable setup method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We will address this issue in the next blog post in this series.&lt;/strong&gt; In the meantime check out our &lt;a href="https://www.barrage.net/blog" rel="noopener noreferrer"&gt;Barrage blog&lt;/a&gt; for more interesting topics.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>android</category>
      <category>codequality</category>
      <category>detekt</category>
    </item>
    <item>
      <title>Integrating Code Formatting into Your Android Projects</title>
      <dc:creator>Marko Pavičić</dc:creator>
      <pubDate>Mon, 01 Jul 2024 10:03:02 +0000</pubDate>
      <link>https://dev.to/pavikaa/integrating-code-formatting-into-your-android-projects-4gbj</link>
      <guid>https://dev.to/pavikaa/integrating-code-formatting-into-your-android-projects-4gbj</guid>
      <description>&lt;p&gt;This is the first blog in the series where we will share our journey of implementing and automating code formatting and static code analysis in Android projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation for the Series
&lt;/h2&gt;

&lt;p&gt;In our projects, we initially relied on IntelliJ's &lt;a href="https://www.jetbrains.com/help/idea/reformat-and-rearrange-code.html" rel="noopener noreferrer"&gt;Reformat Code&lt;/a&gt; feature with the default code style settings. This helped &lt;strong&gt;maintain the readability and consistency of our codebase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since it was a manual step it was easy to forget after &lt;em&gt;every&lt;/em&gt; change. And if we weren't diligent, we'd end up with a messy project with code all over the place, remembering to reformat code added extra overhead to the development process.&lt;/p&gt;

&lt;p&gt;To address these issues, we sought automated solutions to ensure consistent formatting. We implemented a pre-commit hook script that runs ktfmt for Kotlin code formatting.&lt;/p&gt;

&lt;p&gt;When our team began migrating to Jetpack Compose, we wanted to avoid common mistakes due to our limited expertise. We discovered &lt;a href="https://github.com/detekt/detekt" rel="noopener noreferrer"&gt;detekt&lt;/a&gt; and &lt;a href="https://github.com/mrmans0n/compose-rules?ref=nacho-lopez" rel="noopener noreferrer"&gt;compose-rules&lt;/a&gt; for static code analysis which was also added to our pre-commit hook.&lt;/p&gt;

&lt;p&gt;Integrating this pre-commit hook maintained a high code quality and consistency across the team, streamlined our workflow, and reduced manual overhead. Overall, it significantly improved our development process by enforcing consistent code formatting and static analysis practices effortlessly.&lt;/p&gt;

&lt;p&gt;Since this proved incredibly useful for us, we decided to share our experience in the following article series.&lt;/p&gt;

&lt;h2&gt;
  
  
  Series Overview
&lt;/h2&gt;

&lt;p&gt;This series is divided into the following parts, each focusing on a specific aspect of our process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Integrating Code Formatting into Your Android Projects&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An introduction to the importance of code formatting and how to integrate tools like ktfmt. We’ll cover the benefits of code formatting and provide a step-by-step guide to setting up ktfmt in your project which will automatically run before each commit using a pre-commit hook.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enhancing Code Quality with detekt for Static Analysis&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A deep dive into using detekt for static code analysis in Android projects. This article will explore how detekt helps in identifying code smells, enforcing coding standards, and improving overall code quality. To automate the static analysis project detekt will be added to our pre-commit hook&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Developing a Custom Gradle Plugin for Formatting and Static Analysis&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step-by-step guide to creating and publishing a custom Gradle plugin that integrates both ktfmt and detekt and applies our pre-commit hook. This plugin will ensure that code formatting and static analysis are consistently applied and automatically ran on each commit across all your projects, simplifying the setup process for new projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this series, you'll have the tools and knowledge to maintain a clean, consistent, and high-quality codebase in your Android projects.&lt;/p&gt;

&lt;p&gt;Let's look into integrating ktfmt first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Code Formatting into Your Android Projects
&lt;/h2&gt;

&lt;p&gt;This blog will take you through the implementation of code formatting with ktfmt. We will explain its purpose and present the benefits we discovered after the integration.&lt;/p&gt;

&lt;p&gt;Firstly, a brief introduction to ktfmt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to ktfmt
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/facebook/ktfmt" rel="noopener noreferrer"&gt;ktfmt&lt;/a&gt; is a tool developed by Facebook that pretty-prints (formats) Kotlin code based on google-java-format. It always produces the same result, regardless of how the code looks initially, allowing developers to focus on the essence of their code.&lt;/p&gt;

&lt;p&gt;One of the key features of ktfmt is its non-customizability, which is designed to promote consistency. Initially, we used ktlint, but after research and testing, we found ktfmt to be more consistent and simpler to set up. This comment on Reddit also highlights the reliability of ktfmt: &lt;a href="https://www.reddit.com/r/Kotlin/comments/10v042b/comment/j7ewfiq/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button" rel="noopener noreferrer"&gt;Reddit Comment&lt;/a&gt;. You can also find the differences in the official &lt;a href="https://github.com/facebook/ktfmt#ktfmt-vs-ktlint-vs-intellij" rel="noopener noreferrer"&gt;ktfmt readme&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's set it up in our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up ktfmt
&lt;/h2&gt;

&lt;p&gt;To integrate ktfmt, you can use the command-line interface (CLI) tool, but for this guide, we will focus on using the &lt;strong&gt;ktfmt Gradle plugin&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Simply apply the latest plugin version inside your Top-level &lt;code&gt;build.gradle&lt;/code&gt; or &lt;code&gt;build.gradle.kts&lt;/code&gt; file, sync your project, and you're good to go.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.ncorti.ktfmt.gradle"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.18.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Replace with latest version&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now that you have the plugin integrated, let's look into configuring it for your specific use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring ktfmt
&lt;/h2&gt;

&lt;p&gt;Since ktfmt isn't very customizable, it means it's easy to adhere to a strict formatting system. With complex customization options, you can fall into the trap of having too many custom rules. This can hurt your codebase in the long run, as more and more rules mean there is less consistency overall.&lt;/p&gt;

&lt;p&gt;The plugin gives you the option to choose which code style you want to use. The main difference between the code styles is the number of spaces used for block indentations.&lt;/p&gt;

&lt;p&gt;For our purposes, we decided to use the &lt;a href="https://kotlinlang.org/docs/coding-conventions.html#formatting" rel="noopener noreferrer"&gt;Kotlin Lang code style&lt;/a&gt; (4 space block indentation), but feel free to try to use any one you prefer.&lt;/p&gt;

&lt;p&gt;To configure the ktfmt Gradle plugin to use the Kotlin Lang code style, add the following code to your Top-level &lt;code&gt;build.gradle&lt;/code&gt; or &lt;code&gt;build.gradle.kts&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;allprojects&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.ncorti.ktfmt.gradle"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;ktfmt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
        &lt;span class="nf"&gt;kotlinLangStyle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the snippet above, we did the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opened the configuration block of &lt;code&gt;ktfmt&lt;/code&gt;. All of the configuration goes within this block. Some configuration examples are line break width, various indents, import handling, and similar. The complete list of configurable fields can be found &lt;a href="https://github.com/cortinico/ktfmt-gradle#configuring-" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Applied the Kotlin Lang style, feel free to apply any code style you like.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that you've applied the plugin, you can finally run the formatting!&lt;/p&gt;

&lt;h2&gt;
  
  
  Running ktfmtFormat
&lt;/h2&gt;

&lt;p&gt;After you've applied the plugin and synced your project with Gradle plugins you can run the ktfmtFormat Gradle task.&lt;br&gt;
That can be done from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Gradle tool window:

&lt;ul&gt;
&lt;li&gt;Open the Gradle tool window&lt;/li&gt;
&lt;li&gt;Navigate to Tasks/formatting&lt;/li&gt;
&lt;li&gt;Double click on the ktfmtFormat task (or right-click and click on Run)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvt1qo2xnxflipsa3w38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvt1qo2xnxflipsa3w38.png" alt="gradle-tool-window"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The terminal:

&lt;ul&gt;
&lt;li&gt;Open the Terminal window inside Android Studio&lt;/li&gt;
&lt;li&gt;Run the following command: &lt;code&gt;./gradlew ktfmtFormat&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s82z7ovgnptn9dkrs4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s82z7ovgnptn9dkrs4c.png" alt="terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far, we have implemented a consistent code formatting style, but we haven't fixed the main problem, having to manually reformat the code.&lt;/p&gt;

&lt;p&gt;To fix this issue we will implement a pre-commit &lt;a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks" rel="noopener noreferrer"&gt;hook&lt;/a&gt; for our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a pre-commit hook
&lt;/h2&gt;

&lt;p&gt;To avoid having to manually run the ktfmtFormat Gradle task before each commit, we've decided to implement a pre-commit hook script.&lt;/p&gt;

&lt;p&gt;Firstly, make sure Git is set up for your project before you continue with the next steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to your project's root directory, e.g., &lt;code&gt;~/projects/SampleProject/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Toggle hidden files and folders visibility [&lt;a href="https://support.microsoft.com/en-us/windows/view-hidden-files-and-folders-in-windows-97fbc472-c603-9d90-91d0-1166d1d9f4b5" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;, &lt;a href="https://discussions.apple.com/thread/7581737?sortBy=best" rel="noopener noreferrer"&gt;MacOS&lt;/a&gt;, &lt;a href="https://gcore.com/learning/how-to-show-hidden-files-in-linux/" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;rootProjectDir/.git/hooks&lt;/code&gt; and create a new file named &lt;code&gt;pre-commit&lt;/code&gt; without an extension&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the file with a text editor and paste the following code: &lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Exit immediately if a command exits with a non-zero status&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
===================================
|  Formatting code with ktfmt...  |
==================================="&lt;/span&gt;

&lt;span class="c"&gt;# Run ktfmt formatter on the specified files using Gradle&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; ./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; ktfmtFormat&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ktfmt failed"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Check if git is available&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; git &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"git could not be found"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Add all updated files to the git staging area&lt;/span&gt;
git add &lt;span class="nt"&gt;-u&lt;/span&gt;

&lt;span class="c"&gt;# Exit the script successfully&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;0 
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the file and close the editor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the execution permission for your pre-commit hook script, on Mac, open the Terminal, navigate to the &lt;code&gt;rootProjectDir&lt;/code&gt; directory and run the following command: &lt;code&gt;chmod +x .git/hooks/*&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What this does is run the code from the pre-commit script before each commit. If any of the commands failed, the commit would be aborted. Currently, the pre-commit hook we created runs the ktfmtFormat Gradle task, but it will be expanded in the following parts of this series.&lt;/p&gt;

&lt;p&gt;Try initiating a commit; your project's files should be automatically formatted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cmxs02isd6jain8t47p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cmxs02isd6jain8t47p.gif" alt="pre-commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, this script will run the formatting on all &lt;code&gt;.kt&lt;/code&gt; and &lt;code&gt;.kts&lt;/code&gt; project files. You can run the formatting on specific files only, here's an example of how you can run formatting on staged files only.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applying Formatting only on specific project files
&lt;/h3&gt;

&lt;p&gt;If you want to run the script on only some of the files, you can take advantage of the ktfmt &lt;code&gt;--include-only&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;To do that, go to your Top-level &lt;code&gt;build.gradle&lt;/code&gt; or &lt;code&gt;build.gradle.kts&lt;/code&gt; file and paste the following code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KtfmtFormatTask&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"ktfmtPrecommitFormat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"formatting"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Runs ktfmt on kotlin files in the project"&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fileTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"**/*.kt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"**/*.kts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The code snippet above registers a new Gradle task named &lt;code&gt;ktfmPrecommitFormat&lt;/code&gt;, we defined the tasks group and added a description. We've set the source to include all of the &lt;code&gt;.kt&lt;/code&gt; and &lt;code&gt;.kts&lt;/code&gt; files inside the project&lt;/p&gt;

&lt;p&gt;Here's how you can implement a pre-commit hook script that runs ktfmt only on staged git files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Reading staged files and processing them&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ktfmt takes in a &lt;code&gt;--include-only&lt;/code&gt; argument which is a String of joint file names which we want to format separated by a semicolon (;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
===================================
|  Formatting code with ktfmt...  |
==================================="&lt;/span&gt;

&lt;span class="c"&gt;# Get the list of staged files from git, filtering by their status and paths&lt;/span&gt;
&lt;span class="nv"&gt;git_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nt"&gt;--no-pager&lt;/span&gt; diff &lt;span class="nt"&gt;--name-status&lt;/span&gt; &lt;span class="nt"&gt;--no-color&lt;/span&gt; &lt;span class="nt"&gt;--cached&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;file_array&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
&lt;span class="nv"&gt;file_names&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;

&lt;span class="c"&gt;# Process each line of git output&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; line&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
   &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
   &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $2}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
   &lt;span class="c"&gt;# Include only .kt and .kts files that are not marked for deletion&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"D"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="se"&gt;\.&lt;/span&gt;kts&lt;span class="nv"&gt;$|&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;kt&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
       &lt;span class="c"&gt;# Extract relative paths starting from 'src/'&lt;/span&gt;
       &lt;span class="nv"&gt;relative_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/.*\(src\/.*\)/\1/'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
       file_array+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$relative_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
       file_names+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;fi
done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$git_output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Join file array into a semicolon-separated string&lt;/span&gt;
&lt;span class="nv"&gt;files_string&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file_array&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Formatting specified files after processing&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run ktfmt formatter on the specified files&lt;/span&gt;
./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; ktfmtPrecommitFormat &lt;span class="nt"&gt;--include-only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$files_string&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;ktfmtStatus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="c"&gt;# If ktfmt fails, print a message and exit with the failure code&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ktfmtStatus&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ktfmt failed with exit code &lt;/span&gt;&lt;span class="nv"&gt;$ktfmtStatus&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Re-add the modified files to Git&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a pre-commit hook modifies files (e.g., formats them), the modified versions of these files need to be staged again for commit. This is because the files are initially staged (added to the index) before the hook runs. If the hook changes these files (e.g., through formatting), the changes are made in the working directory but not in the index.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if git is available&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; git &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"git could not be found"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Re-add the formatted files to the git index with the original paths&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!file_array[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file_names&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;git add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The complete script file should look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
===================================
|  Formatting code with ktfmt...  |
==================================="&lt;/span&gt;

&lt;span class="c"&gt;# Get the list of staged files from git, filtering by their status and paths&lt;/span&gt;
&lt;span class="nv"&gt;git_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nt"&gt;--no-pager&lt;/span&gt; diff &lt;span class="nt"&gt;--name-status&lt;/span&gt; &lt;span class="nt"&gt;--no-color&lt;/span&gt; &lt;span class="nt"&gt;--cached&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;file_array&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
&lt;span class="nv"&gt;file_names&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;

&lt;span class="c"&gt;# Process each line of git output&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; line&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $2}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# Include only .kt and .kts files that are not marked for deletion&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"D"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="se"&gt;\.&lt;/span&gt;kts&lt;span class="nv"&gt;$|&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;kt&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="c"&gt;# Extract relative paths starting from 'src/'&lt;/span&gt;
        &lt;span class="nv"&gt;relative_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/.*\(src\/.*\)/\1/'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
        file_array+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$relative_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        file_names+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$git_output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Join file array into a semicolon-separated string&lt;/span&gt;
&lt;span class="nv"&gt;files_string&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file_array&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Run ktfmt formatter on the specified files&lt;/span&gt;
./gradlew &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; ktfmtPrecommitFormat &lt;span class="nt"&gt;--include-only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$files_string&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;ktfmtStatus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="c"&gt;# If ktfmt fails, print a message and exit with the failure code&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ktfmtStatus&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ktfmt failed with exit code &lt;/span&gt;&lt;span class="nv"&gt;$ktfmtStatus&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Check if git is available&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; git &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"git could not be found"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Re-add the formatted files to the git index with the original paths&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!file_array[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file_names&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;git add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Comparing Non-Formatted and Formatted Code
&lt;/h2&gt;

&lt;p&gt;Here is an example of how ktfmt can transform your code. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-Formatted Code:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;ScreenContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;showGreetingText&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxSize&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;verticalArrangement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrangement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spacedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showGreetingText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Android"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;align&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Alignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CenterHorizontally&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;={&lt;/span&gt;&lt;span class="n"&gt;showGreetingText&lt;/span&gt;&lt;span class="p"&gt;=!&lt;/span&gt;&lt;span class="n"&gt;showGreetingText&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;align&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Alignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CenterHorizontally&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showGreetingText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"Hide greeting text"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;"Show greeting text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Formatted Code:&lt;/strong&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;ScreenContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;showGreetingText&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxSize&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;verticalArrangement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrangement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spacedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showGreetingText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Android"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;align&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Alignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CenterHorizontally&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;showGreetingText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;showGreetingText&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;align&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Alignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CenterHorizontally&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showGreetingText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"Hide greeting text"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;"Show greeting text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, the formatted code is much cleaner and easier to read, which helps in maintaining the codebase and avoiding errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Integrating ktfmt
&lt;/h2&gt;

&lt;p&gt;Integrating ktfmt into our projects has provided several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistency:&lt;/strong&gt;  The codebase is consistently formatted, which enhances readability and maintainability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Human Error:&lt;/strong&gt;  Automated formatting reduces the likelihood of human error, ensuring that the code adheres to a standard style.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Focus on Code Essence:&lt;/strong&gt;  Developers can focus more on the logic and functionality of the code rather than worrying about formatting.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;To dive deeper into ktfmt, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/facebook/ktfmt" rel="noopener noreferrer"&gt;ktfmt GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cortinico/ktfmt-gradle" rel="noopener noreferrer"&gt;ktfmt Gradle plugin GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://facebook.github.io/ktfmt/" rel="noopener noreferrer"&gt;ktfmt demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing code formatting tools like ktfmt proved essential for maintaining a high-quality codebase. Implementing ktfmt improved code readability, reduced human errors, and facilitated better collaboration among team members. While there may be some initial challenges as to which formatting tool to use, how to set up and configure the plugin and the pre-commit hook, the long-term benefits far outweigh them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned for the next article, where we will delve into enhancing code quality with Detekt for static analysis.&lt;/strong&gt; In the meantime check out our &lt;a href="https://www.barrage.net/blog" rel="noopener noreferrer"&gt;Barrage blog&lt;/a&gt; for more interesting topics.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>android</category>
      <category>codequality</category>
      <category>format</category>
    </item>
  </channel>
</rss>
