├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE ├── renovate.json └── workflows │ ├── gradle-wrapper-validation.yml │ ├── pre-merge.yaml │ └── publish-plugin.yaml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── config └── detekt │ └── detekt.yml ├── example └── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin-build ├── build.gradle.kts ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── ncorti │ │ │ └── kotlin │ │ │ └── gradle │ │ │ └── template │ │ │ └── plugin │ │ │ ├── TemplateExampleTask.kt │ │ │ ├── TemplateExtension.kt │ │ │ └── TemplatePlugin.kt │ │ └── test │ │ └── java │ │ └── com │ │ └── ncorti │ │ └── kotlin │ │ └── gradle │ │ └── template │ │ └── plugin │ │ └── TemplatePluginTest.kt └── settings.gradle.kts ├── renovate.json └── settings.gradle.kts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_size = 4 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*{.yml,yaml}] 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.bat text eol=crlf 4 | *.jar binary -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | --- 5 | 6 | ## 🐛 Describe the bug 7 | 8 | 9 | ## ⚠️ Current behavior 10 | 11 | 12 | ## ✅ Expected behavior 13 | 14 | 15 | ## 💣 Steps to reproduce 16 | 17 | 18 | ## 📷 Screenshots 19 | 20 | 21 | ## 📱 Tech info 22 | - Device: 23 | - OS: 24 | - Library/App version: 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | --- 5 | 6 | ## ⚠️ Is your feature request related to a problem? Please describe 7 | 8 | 9 | ## 💡 Describe the solution you'd like 10 | 11 | 12 | ## 🤚 Do you want to develop this feature yourself? 13 | 14 | - [ ] Yes 15 | - [ ] No 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 🚀 Description 4 | 5 | 6 | ## 📄 Motivation and Context 7 | 8 | 9 | 10 | ## 🧪 How Has This Been Tested? 11 | 12 | 13 | 14 | 15 | ## 📦 Types of changes 16 | 17 | - [ ] Bug fix (non-breaking change which fixes an issue) 18 | - [ ] New feature (non-breaking change which adds functionality) 19 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 20 | 21 | ## ✅ Checklist 22 | 23 | 24 | - [ ] My code follows the code style of this project. 25 | - [ ] My change requires a change to the documentation. 26 | - [ ] I have updated the documentation accordingly. -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "labels": [ 3 | "dependencies" 4 | ], 5 | "extends": [ 6 | "config:base" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.github/workflows/gradle-wrapper-validation.yml: -------------------------------------------------------------------------------- 1 | name: Validate Gradle Wrapper 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - '*' 9 | 10 | jobs: 11 | validation: 12 | name: Validation 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout latest code 16 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 17 | - name: Validate Gradle Wrapper 18 | uses: gradle/actions/wrapper-validation@v4 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/pre-merge.yaml: -------------------------------------------------------------------------------- 1 | name: Pre Merge Checks 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | gradle: 13 | strategy: 14 | matrix: 15 | os: [ ubuntu-latest, macos-latest, windows-latest ] 16 | runs-on: ${{ matrix.os }} 17 | env: 18 | GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} 19 | GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} 20 | if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} 21 | steps: 22 | - name: Checkout Repo 23 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 24 | - name: Cache Gradle Caches 25 | uses: gradle/actions/setup-gradle@v4 26 | - name: Run Gradle tasks 27 | run: ./gradlew preMerge --continue 28 | 29 | # We do a run of the new task `templateExample` created by the plugin 30 | - name: Run the plugin 31 | run: ./gradlew templateExample --message="Test Run" --tag=CI 32 | if: success() 33 | # And we verify that the output of the file is correct. 34 | - name: Verify the plugin output 35 | run: grep -Fxq "[CI] Test Run" ./example/build/template-example.txt 36 | if: success() 37 | -------------------------------------------------------------------------------- /.github/workflows/publish-plugin.yaml: -------------------------------------------------------------------------------- 1 | name: Publish Plugin to Portal 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | gradle: 10 | runs-on: ubuntu-latest 11 | env: 12 | GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} 13 | GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} 14 | if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} 15 | steps: 16 | - name: Checkout Repo 17 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 18 | - name: Cache Gradle Caches 19 | uses: gradle/actions/setup-gradle@v4 20 | - name: Run Gradle tasks 21 | run: ./gradlew preMerge --continue 22 | - name: Publish on Plugin Portal 23 | run: ./gradlew --project-dir plugin-build setupPluginUploadFromEnvironment publishPlugins 24 | if: success() 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .DS_Store 3 | .gradle 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | build 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kotlin-gradle-plugin-template 🐘 2 | 3 | [![Use this template](https://img.shields.io/badge/-Use%20this%20template-brightgreen)](https://github.com/cortinico/kotlin-gradle-plugin-template/generate) [![Pre Merge Checks](https://github.com/cortinico/kotlin-gradle-plugin-template/workflows/Pre%20Merge%20Checks/badge.svg)](https://github.com/cortinico/kotlin-gradle-plugin-template/actions?query=workflow%3A%22Pre+Merge+Checks%22) [![License](https://img.shields.io/github/license/cortinico/kotlin-android-template.svg)](LICENSE) ![Language](https://img.shields.io/github/languages/top/cortinico/kotlin-android-template?color=blue&logo=kotlin) 4 | 5 | A simple Github template that lets you create a **Gradle Plugin** 🐘 project using **100% Kotlin** and be up and running in a **few seconds**. 6 | 7 | This template is focused on delivering a project with **static analysis** and **continuous integration** already in place. 8 | 9 | ## How to use 👣 10 | 11 | Just click on [![Use this template](https://img.shields.io/badge/-Use%20this%20template-brightgreen)](https://github.com/cortinico/kotlin-gradle-plugin-template/generate) button to create a new repo starting from this template. 12 | 13 | Once created don't forget to update the: 14 | - [gradle.properties](plugin-build/gradle.properties) 15 | - Plugin Usages (search for [com.ncorti.kotlin.gradle.template](https://github.com/cortinico/kotlin-gradle-plugin-template/search?q=com.ncorti.kotlin.gradle.template&unscoped_q=com.ncorti.kotlin.gradle.template) in the repo and replace it with your ID). 16 | 17 | ## Features 🎨 18 | 19 | - **100% Kotlin-only template**. 20 | - Plugin build setup with **composite build**. 21 | - 100% Gradle Kotlin DSL setup. 22 | - Dependency versions managed via Gradle Versions Catalog (`libs.versions.toml`). 23 | - CI Setup with GitHub Actions. 24 | - Kotlin Static Analysis via `ktlint` and `detekt`. 25 | - Publishing-ready to Gradle Portal. 26 | - Issues Template (bug report + feature request) 27 | - Pull Request Template. 28 | 29 | ## Composite Build 📦 30 | 31 | This template is using a [Gradle composite build](https://docs.gradle.org/current/userguide/composite_builds.html) to build, test and publish the plugin. This means that you don't need to run Gradle twice to test the changes on your Gradle plugin (no more `publishToMavenLocal` tricks or so). 32 | 33 | The included build is inside the [plugin-build](plugin-build) folder. 34 | 35 | ### `preMerge` task 36 | 37 | A `preMerge` task on the top level build is already provided in the template. This allows you to run all the `check` tasks both in the top level and in the included build. 38 | 39 | You can easily invoke it with: 40 | 41 | ``` 42 | ./gradlew preMerge 43 | ``` 44 | 45 | If you need to invoke a task inside the included build with: 46 | 47 | ``` 48 | ./gradlew -p plugin-build 49 | ``` 50 | 51 | 52 | ### Dependency substitution 53 | 54 | Please note that the project relies on module name/group in order for [dependency substitution](https://docs.gradle.org/current/userguide/resolution_rules.html#sec:dependency_substitution_rules) to work properly. If you change only the plugin ID everything will work as expected. If you change module name/group, things might break and you probably have to specify a [substitution rule](https://docs.gradle.org/current/userguide/resolution_rules.html#sub:project_to_module_substitution). 55 | 56 | 57 | ## Publishing 🚀 58 | 59 | This template is ready to let you publish to [Gradle Portal](https://plugins.gradle.org/). 60 | 61 | The [![Publish Plugin to Portal](https://github.com/cortinico/kotlin-gradle-plugin-template/workflows/Publish%20Plugin%20to%20Portal/badge.svg?branch=1.0.0)](https://github.com/cortinico/kotlin-gradle-plugin-template/actions?query=workflow%3A%22Publish+Plugin+to+Portal%22) Github Action will take care of the publishing whenever you **push a tag**. 62 | 63 | Please note that you need to configure two secrets: `GRADLE_PUBLISH_KEY` and `GRADLE_PUBLISH_SECRET` with the credentials you can get from your profile on the Gradle Portal. 64 | 65 | ## 100% Kotlin 🅺 66 | 67 | This template is designed to use Kotlin everywhere. The build files are written using [**Gradle Kotlin DSL**](https://docs.gradle.org/current/userguide/kotlin_dsl.html) as well as the [Plugin DSL](https://docs.gradle.org/current/userguide/plugins.html#sec:plugins_block) to setup the build. 68 | 69 | Dependencies are centralized inside the [libs.versions.toml](gradle/libs.versions.toml). 70 | 71 | Moreover, a minimalistic Gradle Plugin is already provided in Kotlin to let you easily start developing your own around it. 72 | 73 | ## Static Analysis 🔍 74 | 75 | This template is using [**ktlint**](https://github.com/pinterest/ktlint) with the [ktlint-gradle](https://github.com/jlleitschuh/ktlint-gradle) plugin to format your code. To reformat all the source code as well as the buildscript you can run the `ktlintFormat` gradle task. 76 | 77 | This template is also using [**detekt**](https://github.com/arturbosch/detekt) to analyze the source code, with the configuration that is stored in the [detekt.yml](config/detekt/detekt.yml) file (the file has been generated with the `detektGenerateConfig` task). 78 | 79 | ## CI ⚙️ 80 | 81 | This template is using [**GitHub Actions**](https://github.com/cortinico/kotlin-android-template/actions) as CI. You don't need to setup any external service and you should have a running CI once you start using this template. 82 | 83 | There are currently the following workflows available: 84 | - [Validate Gradle Wrapper](.github/workflows/gradle-wrapper-validation.yml) - Will check that the gradle wrapper has a valid checksum 85 | - [Pre Merge Checks](.github/workflows/pre-merge.yaml) - Will run the `preMerge` tasks as well as trying to run the Gradle plugin. 86 | - [Publish to Plugin Portal](.github/workflows/publish-plugin.yaml) - Will run the `publishPlugin` task when pushing a new tag. 87 | 88 | ## Contributing 🤝 89 | 90 | Feel free to open a issue or submit a pull request for any bugs/improvements. 91 | 92 | ## License 📄 93 | 94 | This template is licensed under the MIT License - see the [License](LICENSE) file for details. 95 | Please note that the generated template is offering to start with a MIT license but you can change it to whatever you wish, as long as you attribute under the MIT terms that you're using the template. 96 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask 2 | import io.gitlab.arturbosch.detekt.Detekt 3 | 4 | plugins { 5 | alias(libs.plugins.kotlin) apply false 6 | alias(libs.plugins.detekt) 7 | alias(libs.plugins.ktlint) 8 | alias(libs.plugins.versionCheck) 9 | } 10 | 11 | subprojects { 12 | apply { 13 | plugin(rootProject.libs.plugins.detekt.get().pluginId) 14 | plugin(rootProject.libs.plugins.ktlint.get().pluginId) 15 | } 16 | 17 | ktlint { 18 | debug.set(false) 19 | verbose.set(true) 20 | android.set(false) 21 | outputToConsole.set(true) 22 | ignoreFailures.set(false) 23 | enableExperimentalRules.set(true) 24 | filter { 25 | exclude("**/generated/**") 26 | include("**/kotlin/**") 27 | } 28 | } 29 | 30 | detekt { 31 | config.setFrom(rootProject.files("config/detekt/detekt.yml")) 32 | } 33 | } 34 | 35 | tasks.withType().configureEach { 36 | reports { 37 | html.required.set(true) 38 | html.outputLocation.set(file("build/reports/detekt.html")) 39 | } 40 | } 41 | 42 | tasks.withType { 43 | rejectVersionIf { 44 | candidate.version.isNonStable() 45 | } 46 | } 47 | 48 | fun String.isNonStable() = "^[0-9,.v-]+(-r)?$".toRegex().matches(this).not() 49 | 50 | tasks.register("clean", Delete::class.java) { 51 | delete(rootProject.layout.buildDirectory) 52 | } 53 | 54 | tasks.register("reformatAll") { 55 | description = "Reformat all the Kotlin Code" 56 | 57 | dependsOn("ktlintFormat") 58 | dependsOn(gradle.includedBuild("plugin-build").task(":plugin:ktlintFormat")) 59 | } 60 | 61 | tasks.register("preMerge") { 62 | description = "Runs all the tests/verification tasks on both top level and included build." 63 | 64 | dependsOn(":example:check") 65 | dependsOn(gradle.includedBuild("plugin-build").task(":plugin:check")) 66 | dependsOn(gradle.includedBuild("plugin-build").task(":plugin:validatePlugins")) 67 | } 68 | 69 | tasks.wrapper { 70 | distributionType = Wrapper.DistributionType.ALL 71 | } 72 | -------------------------------------------------------------------------------- /config/detekt/detekt.yml: -------------------------------------------------------------------------------- 1 | build: 2 | maxIssues: 0 3 | excludeCorrectable: false 4 | weights: 5 | # complexity: 2 6 | # LongParameterList: 1 7 | # style: 1 8 | # comments: 1 9 | 10 | config: 11 | validation: true 12 | warningsAsErrors: false 13 | checkExhaustiveness: false 14 | # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' 15 | excludes: '' 16 | 17 | processors: 18 | active: true 19 | exclude: 20 | - 'DetektProgressListener' 21 | # - 'KtFileCountProcessor' 22 | # - 'PackageCountProcessor' 23 | # - 'ClassCountProcessor' 24 | # - 'FunctionCountProcessor' 25 | # - 'PropertyCountProcessor' 26 | # - 'ProjectComplexityProcessor' 27 | # - 'ProjectCognitiveComplexityProcessor' 28 | # - 'ProjectLLOCProcessor' 29 | # - 'ProjectCLOCProcessor' 30 | # - 'ProjectLOCProcessor' 31 | # - 'ProjectSLOCProcessor' 32 | # - 'LicenseHeaderLoaderExtension' 33 | 34 | console-reports: 35 | active: true 36 | exclude: 37 | - 'ProjectStatisticsReport' 38 | - 'ComplexityReport' 39 | - 'NotificationReport' 40 | - 'FindingsReport' 41 | - 'FileBasedFindingsReport' 42 | # - 'LiteFindingsReport' 43 | 44 | output-reports: 45 | active: true 46 | exclude: 47 | # - 'TxtOutputReport' 48 | # - 'XmlOutputReport' 49 | # - 'HtmlOutputReport' 50 | # - 'MdOutputReport' 51 | 52 | comments: 53 | active: true 54 | AbsentOrWrongFileLicense: 55 | active: false 56 | licenseTemplateFile: 'license.template' 57 | licenseTemplateIsRegex: false 58 | CommentOverPrivateFunction: 59 | active: false 60 | CommentOverPrivateProperty: 61 | active: false 62 | DeprecatedBlockTag: 63 | active: false 64 | EndOfSentenceFormat: 65 | active: false 66 | endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' 67 | KDocReferencesNonPublicProperty: 68 | active: false 69 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 70 | OutdatedDocumentation: 71 | active: false 72 | matchTypeParameters: true 73 | matchDeclarationsOrder: true 74 | allowParamOnConstructorProperties: false 75 | UndocumentedPublicClass: 76 | active: false 77 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 78 | searchInNestedClass: true 79 | searchInInnerClass: true 80 | searchInInnerObject: true 81 | searchInInnerInterface: true 82 | searchInProtectedClass: false 83 | UndocumentedPublicFunction: 84 | active: false 85 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 86 | searchProtectedFunction: false 87 | UndocumentedPublicProperty: 88 | active: false 89 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 90 | searchProtectedProperty: false 91 | 92 | complexity: 93 | active: true 94 | CognitiveComplexMethod: 95 | active: false 96 | threshold: 15 97 | ComplexCondition: 98 | active: true 99 | threshold: 4 100 | ComplexInterface: 101 | active: false 102 | threshold: 10 103 | includeStaticDeclarations: false 104 | includePrivateDeclarations: false 105 | ignoreOverloaded: false 106 | CyclomaticComplexMethod: 107 | active: true 108 | threshold: 15 109 | ignoreSingleWhenExpression: false 110 | ignoreSimpleWhenEntries: false 111 | ignoreNestingFunctions: false 112 | nestingFunctions: 113 | - 'also' 114 | - 'apply' 115 | - 'forEach' 116 | - 'isNotNull' 117 | - 'ifNull' 118 | - 'let' 119 | - 'run' 120 | - 'use' 121 | - 'with' 122 | LabeledExpression: 123 | active: false 124 | ignoredLabels: [] 125 | LargeClass: 126 | active: true 127 | threshold: 600 128 | LongMethod: 129 | active: true 130 | threshold: 60 131 | LongParameterList: 132 | active: true 133 | functionThreshold: 6 134 | constructorThreshold: 7 135 | ignoreDefaultParameters: false 136 | ignoreDataClasses: true 137 | ignoreAnnotatedParameter: [] 138 | MethodOverloading: 139 | active: false 140 | threshold: 6 141 | NamedArguments: 142 | active: false 143 | threshold: 3 144 | ignoreArgumentsMatchingNames: false 145 | NestedBlockDepth: 146 | active: true 147 | threshold: 4 148 | NestedScopeFunctions: 149 | active: false 150 | threshold: 1 151 | functions: 152 | - 'kotlin.apply' 153 | - 'kotlin.run' 154 | - 'kotlin.with' 155 | - 'kotlin.let' 156 | - 'kotlin.also' 157 | ReplaceSafeCallChainWithRun: 158 | active: false 159 | StringLiteralDuplication: 160 | active: false 161 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 162 | threshold: 3 163 | ignoreAnnotation: true 164 | excludeStringsWithLessThan5Characters: true 165 | ignoreStringsRegex: '$^' 166 | TooManyFunctions: 167 | active: true 168 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 169 | thresholdInFiles: 11 170 | thresholdInClasses: 11 171 | thresholdInInterfaces: 11 172 | thresholdInObjects: 11 173 | thresholdInEnums: 11 174 | ignoreDeprecated: false 175 | ignorePrivate: false 176 | ignoreOverridden: false 177 | 178 | coroutines: 179 | active: true 180 | GlobalCoroutineUsage: 181 | active: false 182 | InjectDispatcher: 183 | active: true 184 | dispatcherNames: 185 | - 'IO' 186 | - 'Default' 187 | - 'Unconfined' 188 | RedundantSuspendModifier: 189 | active: true 190 | SleepInsteadOfDelay: 191 | active: true 192 | SuspendFunWithCoroutineScopeReceiver: 193 | active: false 194 | SuspendFunWithFlowReturnType: 195 | active: true 196 | 197 | empty-blocks: 198 | active: true 199 | EmptyCatchBlock: 200 | active: true 201 | allowedExceptionNameRegex: '_|(ignore|expected).*' 202 | EmptyClassBlock: 203 | active: true 204 | EmptyDefaultConstructor: 205 | active: true 206 | EmptyDoWhileBlock: 207 | active: true 208 | EmptyElseBlock: 209 | active: true 210 | EmptyFinallyBlock: 211 | active: true 212 | EmptyForBlock: 213 | active: true 214 | EmptyFunctionBlock: 215 | active: true 216 | ignoreOverridden: false 217 | EmptyIfBlock: 218 | active: true 219 | EmptyInitBlock: 220 | active: true 221 | EmptyKtFile: 222 | active: true 223 | EmptySecondaryConstructor: 224 | active: true 225 | EmptyTryBlock: 226 | active: true 227 | EmptyWhenBlock: 228 | active: true 229 | EmptyWhileBlock: 230 | active: true 231 | 232 | exceptions: 233 | active: true 234 | ExceptionRaisedInUnexpectedLocation: 235 | active: true 236 | methodNames: 237 | - 'equals' 238 | - 'finalize' 239 | - 'hashCode' 240 | - 'toString' 241 | InstanceOfCheckForException: 242 | active: true 243 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 244 | NotImplementedDeclaration: 245 | active: false 246 | ObjectExtendsThrowable: 247 | active: false 248 | PrintStackTrace: 249 | active: true 250 | RethrowCaughtException: 251 | active: true 252 | ReturnFromFinally: 253 | active: true 254 | ignoreLabeled: false 255 | SwallowedException: 256 | active: true 257 | ignoredExceptionTypes: 258 | - 'InterruptedException' 259 | - 'MalformedURLException' 260 | - 'NumberFormatException' 261 | - 'ParseException' 262 | allowedExceptionNameRegex: '_|(ignore|expected).*' 263 | ThrowingExceptionFromFinally: 264 | active: true 265 | ThrowingExceptionInMain: 266 | active: false 267 | ThrowingExceptionsWithoutMessageOrCause: 268 | active: true 269 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 270 | exceptions: 271 | - 'ArrayIndexOutOfBoundsException' 272 | - 'Exception' 273 | - 'IllegalArgumentException' 274 | - 'IllegalMonitorStateException' 275 | - 'IllegalStateException' 276 | - 'IndexOutOfBoundsException' 277 | - 'NullPointerException' 278 | - 'RuntimeException' 279 | - 'Throwable' 280 | ThrowingNewInstanceOfSameException: 281 | active: true 282 | TooGenericExceptionCaught: 283 | active: true 284 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 285 | exceptionNames: 286 | - 'ArrayIndexOutOfBoundsException' 287 | - 'Error' 288 | - 'Exception' 289 | - 'IllegalMonitorStateException' 290 | - 'IndexOutOfBoundsException' 291 | - 'NullPointerException' 292 | - 'RuntimeException' 293 | - 'Throwable' 294 | allowedExceptionNameRegex: '_|(ignore|expected).*' 295 | TooGenericExceptionThrown: 296 | active: true 297 | exceptionNames: 298 | - 'Error' 299 | - 'Exception' 300 | - 'RuntimeException' 301 | - 'Throwable' 302 | 303 | naming: 304 | active: true 305 | BooleanPropertyNaming: 306 | active: false 307 | allowedPattern: '^(is|has|are)' 308 | ignoreOverridden: true 309 | ClassNaming: 310 | active: true 311 | classPattern: '[A-Z][a-zA-Z0-9]*' 312 | ConstructorParameterNaming: 313 | active: true 314 | parameterPattern: '[a-z][A-Za-z0-9]*' 315 | privateParameterPattern: '[a-z][A-Za-z0-9]*' 316 | excludeClassPattern: '$^' 317 | ignoreOverridden: true 318 | EnumNaming: 319 | active: true 320 | enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' 321 | ForbiddenClassName: 322 | active: false 323 | forbiddenName: [] 324 | FunctionMaxLength: 325 | active: false 326 | maximumFunctionNameLength: 30 327 | FunctionMinLength: 328 | active: false 329 | minimumFunctionNameLength: 3 330 | FunctionNaming: 331 | active: true 332 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 333 | functionPattern: '[a-z][a-zA-Z0-9]*' 334 | excludeClassPattern: '$^' 335 | ignoreOverridden: true 336 | FunctionParameterNaming: 337 | active: true 338 | parameterPattern: '[a-z][A-Za-z0-9]*' 339 | excludeClassPattern: '$^' 340 | ignoreOverridden: true 341 | InvalidPackageDeclaration: 342 | active: true 343 | rootPackage: '' 344 | requireRootInDeclaration: false 345 | LambdaParameterNaming: 346 | active: false 347 | parameterPattern: '[a-z][A-Za-z0-9]*|_' 348 | MatchingDeclarationName: 349 | active: true 350 | mustBeFirst: true 351 | MemberNameEqualsClassName: 352 | active: true 353 | ignoreOverridden: true 354 | NoNameShadowing: 355 | active: true 356 | NonBooleanPropertyPrefixedWithIs: 357 | active: false 358 | ObjectPropertyNaming: 359 | active: true 360 | constantPattern: '[A-Za-z][_A-Za-z0-9]*' 361 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 362 | privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' 363 | PackageNaming: 364 | active: true 365 | packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' 366 | TopLevelPropertyNaming: 367 | active: true 368 | constantPattern: '[A-Z][_A-Z0-9]*' 369 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 370 | privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' 371 | VariableMaxLength: 372 | active: false 373 | maximumVariableNameLength: 64 374 | VariableMinLength: 375 | active: false 376 | minimumVariableNameLength: 1 377 | VariableNaming: 378 | active: true 379 | variablePattern: '[a-z][A-Za-z0-9]*' 380 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' 381 | excludeClassPattern: '$^' 382 | ignoreOverridden: true 383 | 384 | performance: 385 | active: true 386 | ArrayPrimitive: 387 | active: true 388 | CouldBeSequence: 389 | active: false 390 | threshold: 3 391 | ForEachOnRange: 392 | active: true 393 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 394 | SpreadOperator: 395 | active: true 396 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 397 | UnnecessaryPartOfBinaryExpression: 398 | active: false 399 | UnnecessaryTemporaryInstantiation: 400 | active: true 401 | 402 | potential-bugs: 403 | active: true 404 | AvoidReferentialEquality: 405 | active: true 406 | forbiddenTypePatterns: 407 | - 'kotlin.String' 408 | CastToNullableType: 409 | active: false 410 | Deprecation: 411 | active: false 412 | DontDowncastCollectionTypes: 413 | active: false 414 | DoubleMutabilityForCollection: 415 | active: true 416 | mutableTypes: 417 | - 'kotlin.collections.MutableList' 418 | - 'kotlin.collections.MutableMap' 419 | - 'kotlin.collections.MutableSet' 420 | - 'java.util.ArrayList' 421 | - 'java.util.LinkedHashSet' 422 | - 'java.util.HashSet' 423 | - 'java.util.LinkedHashMap' 424 | - 'java.util.HashMap' 425 | ElseCaseInsteadOfExhaustiveWhen: 426 | active: false 427 | EqualsAlwaysReturnsTrueOrFalse: 428 | active: true 429 | EqualsWithHashCodeExist: 430 | active: true 431 | ExitOutsideMain: 432 | active: false 433 | ExplicitGarbageCollectionCall: 434 | active: true 435 | HasPlatformType: 436 | active: true 437 | IgnoredReturnValue: 438 | active: true 439 | restrictToConfig: true 440 | returnValueAnnotations: 441 | - '*.CheckResult' 442 | - '*.CheckReturnValue' 443 | ignoreReturnValueAnnotations: 444 | - '*.CanIgnoreReturnValue' 445 | returnValueTypes: 446 | - 'kotlin.sequences.Sequence' 447 | - 'kotlinx.coroutines.flow.*Flow' 448 | - 'java.util.stream.*Stream' 449 | ignoreFunctionCall: [] 450 | ImplicitDefaultLocale: 451 | active: true 452 | ImplicitUnitReturnType: 453 | active: false 454 | allowExplicitReturnType: true 455 | InvalidRange: 456 | active: true 457 | IteratorHasNextCallsNextMethod: 458 | active: true 459 | IteratorNotThrowingNoSuchElementException: 460 | active: true 461 | LateinitUsage: 462 | active: false 463 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 464 | ignoreOnClassesPattern: '' 465 | MapGetWithNotNullAssertionOperator: 466 | active: true 467 | MissingPackageDeclaration: 468 | active: false 469 | excludes: ['**/*.kts'] 470 | NullCheckOnMutableProperty: 471 | active: false 472 | NullableToStringCall: 473 | active: false 474 | UnconditionalJumpStatementInLoop: 475 | active: false 476 | UnnecessaryNotNullCheck: 477 | active: false 478 | UnnecessaryNotNullOperator: 479 | active: true 480 | UnnecessarySafeCall: 481 | active: true 482 | UnreachableCatchBlock: 483 | active: true 484 | UnreachableCode: 485 | active: true 486 | UnsafeCallOnNullableType: 487 | active: true 488 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 489 | UnsafeCast: 490 | active: true 491 | UnusedUnaryOperator: 492 | active: true 493 | UselessPostfixExpression: 494 | active: true 495 | WrongEqualsTypeParameter: 496 | active: true 497 | 498 | style: 499 | active: true 500 | AlsoCouldBeApply: 501 | active: false 502 | CanBeNonNullable: 503 | active: false 504 | CascadingCallWrapping: 505 | active: false 506 | includeElvis: true 507 | ClassOrdering: 508 | active: false 509 | CollapsibleIfStatements: 510 | active: false 511 | DataClassContainsFunctions: 512 | active: false 513 | conversionFunctionPrefix: 514 | - 'to' 515 | DataClassShouldBeImmutable: 516 | active: false 517 | DestructuringDeclarationWithTooManyEntries: 518 | active: true 519 | maxDestructuringEntries: 3 520 | EqualsNullCall: 521 | active: true 522 | EqualsOnSignatureLine: 523 | active: false 524 | ExplicitCollectionElementAccessMethod: 525 | active: false 526 | ExplicitItLambdaParameter: 527 | active: true 528 | ExpressionBodySyntax: 529 | active: false 530 | includeLineWrapping: false 531 | ForbiddenComment: 532 | active: true 533 | values: 534 | - 'FIXME:' 535 | - 'STOPSHIP:' 536 | - 'TODO:' 537 | allowedPatterns: '' 538 | customMessage: '' 539 | ForbiddenImport: 540 | active: false 541 | imports: [] 542 | forbiddenPatterns: '' 543 | ForbiddenMethodCall: 544 | active: false 545 | methods: 546 | - reason: 'print does not allow you to configure the output stream. Use a logger instead.' 547 | value: 'kotlin.io.print' 548 | - reason: 'println does not allow you to configure the output stream. Use a logger instead.' 549 | value: 'kotlin.io.println' 550 | ForbiddenSuppress: 551 | active: false 552 | rules: [] 553 | ForbiddenVoid: 554 | active: true 555 | ignoreOverridden: false 556 | ignoreUsageInGenerics: false 557 | FunctionOnlyReturningConstant: 558 | active: true 559 | ignoreOverridableFunction: true 560 | ignoreActualFunction: true 561 | excludedFunctions: [] 562 | LoopWithTooManyJumpStatements: 563 | active: true 564 | maxJumpCount: 1 565 | MagicNumber: 566 | active: true 567 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts'] 568 | ignoreNumbers: 569 | - '-1' 570 | - '0' 571 | - '1' 572 | - '2' 573 | ignoreHashCodeFunction: true 574 | ignorePropertyDeclaration: false 575 | ignoreLocalVariableDeclaration: false 576 | ignoreConstantDeclaration: true 577 | ignoreCompanionObjectPropertyDeclaration: true 578 | ignoreAnnotation: false 579 | ignoreNamedArgument: true 580 | ignoreEnums: false 581 | ignoreRanges: false 582 | ignoreExtensionFunctions: true 583 | MandatoryBracesIfStatements: 584 | active: false 585 | MandatoryBracesLoops: 586 | active: false 587 | MaxChainedCallsOnSameLine: 588 | active: false 589 | maxChainedCalls: 5 590 | MaxLineLength: 591 | active: true 592 | maxLineLength: 120 593 | excludePackageStatements: true 594 | excludeImportStatements: true 595 | excludeCommentStatements: false 596 | excludeRawStrings: true 597 | MayBeConst: 598 | active: true 599 | ModifierOrder: 600 | active: true 601 | MultilineLambdaItParameter: 602 | active: false 603 | MultilineRawStringIndentation: 604 | active: false 605 | indentSize: 4 606 | NestedClassesVisibility: 607 | active: true 608 | NewLineAtEndOfFile: 609 | active: true 610 | NoTabs: 611 | active: false 612 | NullableBooleanCheck: 613 | active: false 614 | ObjectLiteralToLambda: 615 | active: true 616 | OptionalAbstractKeyword: 617 | active: true 618 | OptionalUnit: 619 | active: false 620 | OptionalWhenBraces: 621 | active: false 622 | PreferToOverPairSyntax: 623 | active: false 624 | ProtectedMemberInFinalClass: 625 | active: true 626 | RedundantExplicitType: 627 | active: false 628 | RedundantHigherOrderMapUsage: 629 | active: true 630 | RedundantVisibilityModifierRule: 631 | active: false 632 | ReturnCount: 633 | active: true 634 | max: 2 635 | excludedFunctions: 636 | - 'equals' 637 | excludeLabeled: false 638 | excludeReturnFromLambda: true 639 | excludeGuardClauses: false 640 | SafeCast: 641 | active: true 642 | SerialVersionUIDInSerializableClass: 643 | active: true 644 | SpacingBetweenPackageAndImports: 645 | active: false 646 | ThrowsCount: 647 | active: true 648 | max: 2 649 | excludeGuardClauses: false 650 | TrailingWhitespace: 651 | active: false 652 | TrimMultilineRawString: 653 | active: false 654 | UnderscoresInNumericLiterals: 655 | active: false 656 | acceptableLength: 4 657 | allowNonStandardGrouping: false 658 | UnnecessaryAbstractClass: 659 | active: true 660 | UnnecessaryAnnotationUseSiteTarget: 661 | active: false 662 | UnnecessaryApply: 663 | active: true 664 | UnnecessaryBackticks: 665 | active: false 666 | UnnecessaryFilter: 667 | active: true 668 | UnnecessaryInheritance: 669 | active: true 670 | UnnecessaryInnerClass: 671 | active: false 672 | UnnecessaryLet: 673 | active: false 674 | UnnecessaryParentheses: 675 | active: false 676 | allowForUnclearPrecedence: false 677 | UntilInsteadOfRangeTo: 678 | active: false 679 | UnusedImports: 680 | active: false 681 | UnusedPrivateClass: 682 | active: true 683 | UnusedPrivateMember: 684 | active: true 685 | allowedNames: '(_|ignored|expected|serialVersionUID)' 686 | UseAnyOrNoneInsteadOfFind: 687 | active: true 688 | UseArrayLiteralsInAnnotations: 689 | active: true 690 | UseCheckNotNull: 691 | active: true 692 | UseCheckOrError: 693 | active: true 694 | UseDataClass: 695 | active: false 696 | allowVars: false 697 | UseEmptyCounterpart: 698 | active: false 699 | UseIfEmptyOrIfBlank: 700 | active: false 701 | UseIfInsteadOfWhen: 702 | active: false 703 | UseIsNullOrEmpty: 704 | active: true 705 | UseOrEmpty: 706 | active: true 707 | UseRequire: 708 | active: true 709 | UseRequireNotNull: 710 | active: true 711 | UseSumOfInsteadOfFlatMapSize: 712 | active: false 713 | UselessCallOnNotNull: 714 | active: true 715 | UtilityClassWithPublicConstructor: 716 | active: true 717 | VarCouldBeVal: 718 | active: true 719 | ignoreLateinitVar: false 720 | WildcardImport: 721 | active: true 722 | excludeImports: 723 | - 'java.util.*' 724 | -------------------------------------------------------------------------------- /example/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("com.ncorti.kotlin.gradle.template.plugin") 4 | } 5 | 6 | templateExampleConfig { 7 | message.set("Just trying this gradle plugin...") 8 | } 9 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536m 2 | org.gradle.parallel=true 3 | 4 | # Kotlin code style for this project: "official" or "obsolete": 5 | kotlin.code.style=official 6 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | detekt = "1.23.8" 3 | kotlin = "2.1.21" 4 | ktlintGradle = "12.3.0" 5 | pluginPublish = "1.3.1" 6 | versionCheck = "0.52.0" 7 | 8 | [plugins] 9 | detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt"} 10 | kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"} 11 | ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlintGradle"} 12 | pluginPublish = { id = "com.gradle.plugin-publish", version.ref = "pluginPublish"} 13 | versionCheck = { id = "com.github.ben-manes.versions", version.ref = "versionCheck"} 14 | 15 | [libraries] 16 | junit = "junit:junit:4.13.2" 17 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cortinico/kotlin-gradle-plugin-template/245f4c267a04e206ff0204e3096a250a75910e77/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /plugin-build/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.gitlab.arturbosch.detekt.Detekt 2 | 3 | plugins { 4 | alias(libs.plugins.kotlin) apply false 5 | alias(libs.plugins.pluginPublish) apply false 6 | alias(libs.plugins.detekt) 7 | alias(libs.plugins.ktlint) 8 | alias(libs.plugins.versionCheck) 9 | } 10 | 11 | allprojects { 12 | group = property("GROUP").toString() 13 | version = property("VERSION").toString() 14 | 15 | apply { 16 | plugin(rootProject.libs.plugins.detekt.get().pluginId) 17 | plugin(rootProject.libs.plugins.ktlint.get().pluginId) 18 | } 19 | 20 | ktlint { 21 | debug.set(false) 22 | verbose.set(true) 23 | android.set(false) 24 | outputToConsole.set(true) 25 | ignoreFailures.set(false) 26 | enableExperimentalRules.set(true) 27 | filter { 28 | exclude("**/generated/**") 29 | include("**/kotlin/**") 30 | } 31 | } 32 | 33 | detekt { 34 | config.setFrom(rootProject.files("../config/detekt/detekt.yml")) 35 | } 36 | } 37 | 38 | tasks.withType().configureEach { 39 | reports { 40 | html.required.set(true) 41 | html.outputLocation.set(file("build/reports/detekt.html")) 42 | } 43 | } 44 | 45 | tasks.register("clean", Delete::class.java) { 46 | delete(rootProject.layout.buildDirectory) 47 | } 48 | 49 | tasks.wrapper { 50 | distributionType = Wrapper.DistributionType.ALL 51 | } 52 | -------------------------------------------------------------------------------- /plugin-build/gradle.properties: -------------------------------------------------------------------------------- 1 | ID=com.ncorti.kotlin.gradle.template.plugin 2 | VERSION=1.0.0 3 | GROUP=com.ncorti.kotlin.gradle.template 4 | DISPLAY_NAME=An empty Gradle Plugin from a template 5 | DESCRIPTION=An empty Gradle plugin created from a template 6 | WEBSITE=https://github.com/cortinico/kotlin-gradle-plugin-template 7 | VCS_URL=https://github.com/cortinico/kotlin-gradle-plugin-template 8 | IMPLEMENTATION_CLASS=com.ncorti.kotlin.gradle.template.plugin.TemplatePlugin 9 | -------------------------------------------------------------------------------- /plugin-build/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cortinico/kotlin-gradle-plugin-template/245f4c267a04e206ff0204e3096a250a75910e77/plugin-build/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /plugin-build/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /plugin-build/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /plugin-build/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /plugin-build/plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") 5 | `java-gradle-plugin` 6 | alias(libs.plugins.pluginPublish) 7 | } 8 | 9 | dependencies { 10 | implementation(kotlin("stdlib")) 11 | implementation(gradleApi()) 12 | 13 | testImplementation(libs.junit) 14 | } 15 | 16 | java { 17 | sourceCompatibility = JavaVersion.VERSION_1_8 18 | targetCompatibility = JavaVersion.VERSION_1_8 19 | } 20 | 21 | tasks.withType { 22 | kotlinOptions { 23 | jvmTarget = JavaVersion.VERSION_1_8.toString() 24 | } 25 | } 26 | 27 | gradlePlugin { 28 | plugins { 29 | create(property("ID").toString()) { 30 | id = property("ID").toString() 31 | implementationClass = property("IMPLEMENTATION_CLASS").toString() 32 | version = property("VERSION").toString() 33 | description = property("DESCRIPTION").toString() 34 | displayName = property("DISPLAY_NAME").toString() 35 | // Note: tags cannot include "plugin" or "gradle" when publishing 36 | tags.set(listOf("sample", "template")) 37 | } 38 | } 39 | } 40 | 41 | gradlePlugin { 42 | website.set(property("WEBSITE").toString()) 43 | vcsUrl.set(property("VCS_URL").toString()) 44 | } 45 | 46 | // Use Detekt with type resolution for check 47 | tasks.named("check").configure { 48 | this.setDependsOn( 49 | this.dependsOn.filterNot { 50 | it is TaskProvider<*> && it.name == "detekt" 51 | } + tasks.named("detektMain"), 52 | ) 53 | } 54 | 55 | tasks.create("setupPluginUploadFromEnvironment") { 56 | doLast { 57 | val key = System.getenv("GRADLE_PUBLISH_KEY") 58 | val secret = System.getenv("GRADLE_PUBLISH_SECRET") 59 | 60 | if (key == null || secret == null) { 61 | throw GradleException("gradlePublishKey and/or gradlePublishSecret are not defined environment variables") 62 | } 63 | 64 | System.setProperty("gradle.publish.key", key) 65 | System.setProperty("gradle.publish.secret", secret) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /plugin-build/plugin/src/main/java/com/ncorti/kotlin/gradle/template/plugin/TemplateExampleTask.kt: -------------------------------------------------------------------------------- 1 | package com.ncorti.kotlin.gradle.template.plugin 2 | 3 | import org.gradle.api.DefaultTask 4 | import org.gradle.api.file.RegularFileProperty 5 | import org.gradle.api.provider.Property 6 | import org.gradle.api.tasks.Input 7 | import org.gradle.api.tasks.Optional 8 | import org.gradle.api.tasks.OutputFile 9 | import org.gradle.api.tasks.TaskAction 10 | import org.gradle.api.tasks.options.Option 11 | 12 | abstract class TemplateExampleTask : DefaultTask() { 13 | init { 14 | description = "Just a sample template task" 15 | 16 | // Don't forget to set the group here. 17 | // group = BasePlugin.BUILD_GROUP 18 | } 19 | 20 | @get:Input 21 | @get:Option(option = "message", description = "A message to be printed in the output file") 22 | abstract val message: Property 23 | 24 | @get:Input 25 | @get:Option(option = "tag", description = "A Tag to be used for debug and in the output file") 26 | @get:Optional 27 | abstract val tag: Property 28 | 29 | @get:OutputFile 30 | abstract val outputFile: RegularFileProperty 31 | 32 | @TaskAction 33 | fun sampleAction() { 34 | val prettyTag = tag.orNull?.let { "[$it]" }.orEmpty() 35 | 36 | logger.lifecycle("$prettyTag message is: ${message.orNull}") 37 | logger.lifecycle("$prettyTag tag is: ${tag.orNull}") 38 | logger.lifecycle("$prettyTag outputFile is: ${outputFile.orNull}") 39 | 40 | outputFile.get().asFile.writeText("$prettyTag ${message.get()}") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /plugin-build/plugin/src/main/java/com/ncorti/kotlin/gradle/template/plugin/TemplateExtension.kt: -------------------------------------------------------------------------------- 1 | package com.ncorti.kotlin.gradle.template.plugin 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.api.file.RegularFileProperty 5 | import org.gradle.api.provider.Property 6 | import javax.inject.Inject 7 | 8 | const val DEFAULT_OUTPUT_FILE = "template-example.txt" 9 | 10 | @Suppress("UnnecessaryAbstractClass") 11 | abstract class TemplateExtension 12 | @Inject 13 | constructor(project: Project) { 14 | private val objects = project.objects 15 | 16 | // Example of a property that is mandatory. The task will 17 | // fail if this property is not set as is annotated with @Optional. 18 | val message: Property = objects.property(String::class.java) 19 | 20 | // Example of a property that is optional. 21 | val tag: Property = objects.property(String::class.java) 22 | 23 | // Example of a property with a default set with .convention 24 | val outputFile: RegularFileProperty = 25 | objects.fileProperty().convention( 26 | project.layout.buildDirectory.file(DEFAULT_OUTPUT_FILE), 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /plugin-build/plugin/src/main/java/com/ncorti/kotlin/gradle/template/plugin/TemplatePlugin.kt: -------------------------------------------------------------------------------- 1 | package com.ncorti.kotlin.gradle.template.plugin 2 | 3 | import org.gradle.api.Plugin 4 | import org.gradle.api.Project 5 | 6 | const val EXTENSION_NAME = "templateExampleConfig" 7 | const val TASK_NAME = "templateExample" 8 | 9 | @Suppress("UnnecessaryAbstractClass") 10 | abstract class TemplatePlugin : Plugin { 11 | override fun apply(project: Project) { 12 | // Add the 'template' extension object 13 | val extension = project.extensions.create(EXTENSION_NAME, TemplateExtension::class.java, project) 14 | 15 | // Add a task that uses configuration from the extension object 16 | project.tasks.register(TASK_NAME, TemplateExampleTask::class.java) { 17 | it.tag.set(extension.tag) 18 | it.message.set(extension.message) 19 | it.outputFile.set(extension.outputFile) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugin-build/plugin/src/test/java/com/ncorti/kotlin/gradle/template/plugin/TemplatePluginTest.kt: -------------------------------------------------------------------------------- 1 | package com.ncorti.kotlin.gradle.template.plugin 2 | 3 | import org.gradle.testfixtures.ProjectBuilder 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.junit.Assert.assertEquals 7 | import org.junit.Assert.assertNotNull 8 | import org.junit.Rule 9 | import org.junit.Test 10 | import org.junit.rules.TemporaryFolder 11 | import java.io.File 12 | 13 | class TemplatePluginTest { 14 | @JvmField 15 | @Rule 16 | var testProjectDir: TemporaryFolder = TemporaryFolder() 17 | 18 | @Test 19 | fun `plugin is applied correctly to the project`() { 20 | val project = ProjectBuilder.builder().build() 21 | project.pluginManager.apply("com.ncorti.kotlin.gradle.template.plugin") 22 | 23 | assert(project.tasks.getByName("templateExample") is TemplateExampleTask) 24 | } 25 | 26 | @Test 27 | fun `extension templateExampleConfig is created correctly`() { 28 | val project = ProjectBuilder.builder().build() 29 | project.pluginManager.apply("com.ncorti.kotlin.gradle.template.plugin") 30 | 31 | assertNotNull(project.extensions.getByName("templateExampleConfig")) 32 | } 33 | 34 | @Test 35 | fun `parameters are passed correctly from extension to task`() { 36 | val project = ProjectBuilder.builder().build() 37 | project.pluginManager.apply("com.ncorti.kotlin.gradle.template.plugin") 38 | val aFile = File(project.projectDir, ".tmp") 39 | (project.extensions.getByName("templateExampleConfig") as TemplateExtension).apply { 40 | tag.set("a-sample-tag") 41 | message.set("just-a-message") 42 | outputFile.set(aFile) 43 | } 44 | 45 | val task = project.tasks.getByName("templateExample") as TemplateExampleTask 46 | 47 | assertEquals("a-sample-tag", task.tag.get()) 48 | assertEquals("just-a-message", task.message.get()) 49 | assertEquals(aFile, task.outputFile.get().asFile) 50 | } 51 | 52 | @Test 53 | fun `task generates file with message`() { 54 | val message = "Just trying this gradle plugin..." 55 | testProjectDir.root.removeRecursively() 56 | File(testProjectDir.root, "build.gradle") 57 | .writeText( 58 | generateBuildFile("message.set(\"$message\")\ntag.set(\"tag\")"), 59 | ) 60 | 61 | val gradleResult = executeGradleRun("templateExample") 62 | assert(gradleResult.output.contains("message is: $message")) 63 | 64 | val generatedFileText = (testProjectDir.root / "build" / "template-example.txt").readText() 65 | assert(generatedFileText == "[tag] $message") 66 | } 67 | 68 | private fun executeGradleRun(task: String): BuildResult = 69 | GradleRunner 70 | .create() 71 | .withProjectDir(testProjectDir.root) 72 | .withArguments(task) 73 | .withPluginClasspath() 74 | .build() 75 | 76 | private fun generateBuildFile(config: String) = 77 | """ 78 | plugins { 79 | id 'com.ncorti.kotlin.gradle.template.plugin' 80 | } 81 | templateExampleConfig { 82 | $config 83 | } 84 | """.trimIndent() 85 | } 86 | 87 | private fun File.removeRecursively() = 88 | this 89 | .walkBottomUp() 90 | .filter { it != this } 91 | .forEach { it.deleteRecursively() } 92 | 93 | private operator fun File.div(s: String): File = this.resolve(s) 94 | -------------------------------------------------------------------------------- /plugin-build/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | dependencyResolutionManagement { 9 | repositories { 10 | google() 11 | mavenCentral() 12 | } 13 | 14 | versionCatalogs { 15 | create("libs") { 16 | from(files("../gradle/libs.versions.toml")) 17 | } 18 | } 19 | } 20 | 21 | plugins { 22 | id("com.gradle.develocity") version "3.19.2" 23 | } 24 | 25 | develocity { 26 | buildScan.termsOfUseUrl = "https://gradle.com/terms-of-service" 27 | buildScan.termsOfUseAgree = "yes" 28 | buildScan.publishing.onlyIf { 29 | System.getenv("GITHUB_ACTIONS") == "true" && 30 | it.buildResult.failures.isNotEmpty() 31 | } 32 | } 33 | 34 | rootProject.name = ("com.ncorti.kotlin.gradle.template") 35 | 36 | include(":plugin") 37 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":automergeMinor" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | dependencyResolutionManagement { 9 | repositories { 10 | mavenCentral() 11 | google() 12 | } 13 | } 14 | 15 | plugins { 16 | id("com.gradle.develocity") version "3.19.2" 17 | } 18 | 19 | develocity { 20 | buildScan.termsOfUseUrl = "https://gradle.com/terms-of-service" 21 | buildScan.termsOfUseAgree = "yes" 22 | buildScan.publishing.onlyIf { 23 | System.getenv("GITHUB_ACTIONS") == "true" && 24 | it.buildResult.failures.isNotEmpty() 25 | } 26 | } 27 | 28 | rootProject.name = "kotlin-gradle-plugin-template" 29 | 30 | include(":example") 31 | includeBuild("plugin-build") 32 | --------------------------------------------------------------------------------