Skip to content

Commit

Permalink
Add sources
Browse files Browse the repository at this point in the history
  • Loading branch information
fluxroot committed Jun 7, 2024
1 parent a26dfbd commit c5665a6
Show file tree
Hide file tree
Showing 18 changed files with 781 additions and 0 deletions.
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,73 @@
Todo Checker
============

The Todo Checker plugin looks for the pattern `(?i)(TODO|FIXME)\\s+($jiraProject-\\d+)` (e.g. "TODO MYPROJECT-123: some
comment") in text files. If any of the referenced Jira issues are resolved, it will report the file together with the
issue owner or reporter. There should be no TODO markers in the source code for resolved issues.

## Configure Todo Checker in Gradle

```kotlin
todoChecker {
jiraUrl.set(URI.create("https://jira.mycompany.com"))
jiraUsername.set(providers.environmentVariable("TODOCHECKER_USERNAME"))
jiraPassword.set(providers.environmentVariable("TODOCHECKER_PASSWORD"))
jiraProject.set("MYPROJECT")
}
```

## Execute the task

```shell
./gradlew checkTodo
```

## Configuration

You can use the following settings to configure the plugin.

| Parameter | Default value | Required | Description |
|-------------------------|-------------------------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| directory | project directory | no | The directory to scan for TODO markers. |
| exclusions | empty list | no | A file containing a Java Glob per line for files that the plugin should NOT scan. |
| inclusions | empty list | no | A file containing a Java Glob per line for files that the plugin should always scan.<br/>Otherwise, files that don't match will be tested for text content. |
| jiraUrl | - | yes | The Jira URL. |
| jiraUsername | - | no | The username to connect to Jira (use this OR jiraPersonalAccessToken). May also be passed as gradle property, e.g. set in gradle.properties. |
| jiraPassword | - | no | The password to connect to Jira (use this OR jiraPersonalAccessToken). May also be passed as gradle property, e.g. set in gradle.properties. |
| jiraPersonalAccessToken | - | no | Personal access token (may be used instead of username+password). May also be passed as gradle property, e.g. set in gradle.properties. |
| jiraProject | - | yes | The Jira project key to match TODO markers. |
| jiraResolvedStatuses | "Done" status category | no | A list of statuses in which an issue is considered resolved.<br/>If not set, all issues that have a "Done" status category are considered resolved. |
| todoRegex | ```(?i)(TODO\|FIXME)\s+(?<ticket>$jiraProject-\d+)``` | no | The regex used for searching TODOs and recognizing associated JIRA tickets. Must contain a named capture group "ticket" which is used to extract the matched JIRA ticket. |

### Exclusion file example

An exclusion file looks as follows.

```text
**/.gradle/**
.git/**
.idea/**
**/node_modules/**
**/build/**
```

### Inclusion file example

An inclusion file could look like this.

```text
**.java
**.jsp
**.js
**.kt
**.kts
**.ts
**.gradle
**.properties
**.xml
**.go
```

License
-------
Todo Checker is released under the [MIT License](LICENSE).
63 changes: 63 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile

plugins {
`java-gradle-plugin`
alias(libs.plugins.detekt)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.spotless)
}

group = "ch.ergon.todochecker"

gradlePlugin {
plugins {
register("todoChecker") {
id = "ch.ergon.todochecker"
implementationClass = "ch.ergon.todochecker.TodoCheckerPlugin"
}
}
}

dependencies {
compileOnly(libs.jira.rest.java.client)
}

dependencyLocking {
lockAllConfigurations()
}

kotlin {
jvmToolchain(11)
}

tasks.withType<KotlinJvmCompile> {
compilerOptions {
allWarningsAsErrors.set(true)
}
}

java {
consistentResolution {
useCompileClasspathVersions()
}
}

detekt {
buildUponDefaultConfig = true
}

spotless {
kotlin {
ktlint()
}
}

tasks.register("resolveAndLockAll") {
doFirst {
require(gradle.startParameter.isWriteDependencyLocks)
}

doLast {
configurations.filter { it.isCanBeResolved }.forEach { it.resolve() }
}
}
99 changes: 99 additions & 0 deletions gradle.lockfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.atlassian.event:atlassian-event:4.1.3=compileClasspath,compileOnlyDependenciesMetadata
com.atlassian.httpclient:atlassian-httpclient-api:2.1.5=compileClasspath,compileOnlyDependenciesMetadata
com.atlassian.httpclient:atlassian-httpclient-library:2.1.5=compileClasspath,compileOnlyDependenciesMetadata
com.atlassian.jira:jira-rest-java-client-api:5.2.5=compileClasspath,compileOnlyDependenciesMetadata
com.atlassian.jira:jira-rest-java-client-core:5.2.5=compileClasspath,compileOnlyDependenciesMetadata
com.atlassian.sal:sal-api:4.4.4=compileClasspath,compileOnlyDependenciesMetadata
com.beust:jcommander:1.82=detekt
com.google.code.findbugs:jsr305:3.0.2=compileClasspath,compileOnlyDependenciesMetadata
com.google.errorprone:error_prone_annotations:2.5.1=compileClasspath,compileOnlyDependenciesMetadata
com.google.guava:failureaccess:1.0.1=compileClasspath,compileOnlyDependenciesMetadata
com.google.guava:guava:30.1.1-jre=compileClasspath,compileOnlyDependenciesMetadata
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=compileClasspath,compileOnlyDependenciesMetadata
com.google.j2objc:j2objc-annotations:1.3=compileClasspath,compileOnlyDependenciesMetadata
commons-codec:commons-codec:1.15=compileClasspath,compileOnlyDependenciesMetadata
commons-logging:commons-logging:1.2=compileClasspath,compileOnlyDependenciesMetadata
io.atlassian.util.concurrent:atlassian-util-concurrent:4.0.1=compileClasspath,compileOnlyDependenciesMetadata
io.github.davidburstrom.contester:contester-breakpoint:0.2.0=detekt
io.github.detekt.sarif4k:sarif4k-jvm:0.4.0=detekt
io.github.detekt.sarif4k:sarif4k:0.4.0=detekt
io.gitlab.arturbosch.detekt:detekt-api:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-cli:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-core:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-metrics:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-parser:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-psi-utils:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-html:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-md:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-sarif:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-txt:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-report-xml:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-complexity:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-coroutines:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-documentation:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-empty:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-errorprone:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-exceptions:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-naming:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-performance:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules-style:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-rules:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-tooling:1.23.0=detekt
io.gitlab.arturbosch.detekt:detekt-utils:1.23.0=detekt
jakarta.annotation:jakarta.annotation-api:1.3.5=compileClasspath,compileOnlyDependenciesMetadata
jakarta.ws.rs:jakarta.ws.rs-api:2.1.6=compileClasspath,compileOnlyDependenciesMetadata
joda-time:joda-time:2.9.9=compileClasspath,compileOnlyDependenciesMetadata
net.java.dev.jna:jna:5.6.0=detekt,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.apache.commons:commons-lang3:3.5=compileClasspath,compileOnlyDependenciesMetadata
org.apache.httpcomponents:httpasyncclient-cache:4.1.4=compileClasspath,compileOnlyDependenciesMetadata
org.apache.httpcomponents:httpasyncclient:4.1.4=compileClasspath,compileOnlyDependenciesMetadata
org.apache.httpcomponents:httpclient-cache:4.5.13=compileClasspath,compileOnlyDependenciesMetadata
org.apache.httpcomponents:httpclient:4.5.13=compileClasspath,compileOnlyDependenciesMetadata
org.apache.httpcomponents:httpcore-nio:4.4.10=compileClasspath,compileOnlyDependenciesMetadata
org.apache.httpcomponents:httpcore:4.4.13=compileClasspath,compileOnlyDependenciesMetadata
org.apache.httpcomponents:httpmime:4.5.13=compileClasspath,compileOnlyDependenciesMetadata
org.checkerframework:checker-qual:3.8.0=compileClasspath,compileOnlyDependenciesMetadata
org.codehaus.jettison:jettison:1.5.4=compileClasspath,compileOnlyDependenciesMetadata
org.glassfish.hk2.external:jakarta.inject:2.6.1=compileClasspath,compileOnlyDependenciesMetadata
org.glassfish.hk2:osgi-resource-locator:1.0.3=compileClasspath,compileOnlyDependenciesMetadata
org.glassfish.jersey.core:jersey-client:2.35=compileClasspath,compileOnlyDependenciesMetadata
org.glassfish.jersey.core:jersey-common:2.35=compileClasspath,compileOnlyDependenciesMetadata
org.glassfish.jersey.media:jersey-media-jaxb:2.35=compileClasspath,compileOnlyDependenciesMetadata
org.glassfish.jersey.media:jersey-media-json-jettison:2.35=compileClasspath,compileOnlyDependenciesMetadata
org.jetbrains.intellij.deps:trove4j:1.0.20200330=detekt,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.8.21=detekt
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.8.22=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.8.21=detekt
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.8.22=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.8.22=kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-reflect:1.8.21=detekt
org.jetbrains.kotlin:kotlin-script-runtime:1.8.21=detekt
org.jetbrains.kotlin:kotlin-script-runtime:1.8.22=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.8.22=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.8.22=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.8.22=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-jvm:1.8.22=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=detekt
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.21=detekt
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21=detekt
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.8.21=detekt
org.jetbrains.kotlin:kotlin-stdlib:1.8.22=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-html-jvm:0.8.1=detekt
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.4.1=detekt
org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1=detekt
org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1=detekt
org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1=detekt
org.jetbrains:annotations:13.0=apiDependenciesMetadata,compileClasspath,detekt,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.36=compileClasspath,compileOnlyDependenciesMetadata
org.snakeyaml:snakeyaml-engine:2.6=detekt
org.springframework:spring-beans:5.3.25=compileClasspath,compileOnlyDependenciesMetadata
org.springframework:spring-core:5.3.25=compileClasspath,compileOnlyDependenciesMetadata
org.springframework:spring-jcl:5.3.25=compileClasspath,compileOnlyDependenciesMetadata
empty=annotationProcessor,detektPlugins,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
version=1.0.0-SNAPSHOT
kotlin.code.style=official
13 changes: 13 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[versions]
detekt = "1.23.0"
jira-rest-java-client = "5.2.5"
kotlin = "1.8.22"
spotless = "6.19.0"

[libraries]
jira-rest-java-client = { module = "com.atlassian.jira:jira-rest-java-client-core", version.ref = "jira-rest-java-client" }

[plugins]
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
4 changes: 4 additions & 0 deletions settings-gradle.lockfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
empty=incomingCatalogForLibs0
9 changes: 9 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
rootProject.name = "todo-checker"

dependencyResolutionManagement {
repositories {
mavenCentral()
maven {
url = uri("https://packages.atlassian.com/mvn/maven-external/")
}
}
}
51 changes: 51 additions & 0 deletions src/main/kotlin/ch/ergon/todochecker/CreateOutput.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ch.ergon.todochecker

import com.atlassian.jira.rest.client.api.domain.Issue
import java.nio.file.Path

internal fun createOutput(
users: Map<JiraUser?, Set<Issue>>,
todos: Map<JiraIssueKey, Set<Path>>,
): String =
users.entries.asSequence()
.map { entry -> createOutputForUser(entry, todos) }
.joinToString(System.lineSeparator() + System.lineSeparator())

private fun createOutputForUser(
entry: Map.Entry<JiraUser?, Set<Issue>>,
todos: Map<JiraIssueKey, Set<Path>>,
): String =
createUsername(entry.key) +
System.lineSeparator() +
createIssueList(entry.value, todos)

private fun createUsername(user: JiraUser?): String =
user?.run { "$displayName:" } ?: "Unknown User:"

private fun createIssueList(
issues: Set<Issue>,
todos: Map<JiraIssueKey, Set<Path>>,
): String =
issues.asSequence()
.map { issue -> createOutputForIssue(issue, todos) }
.joinToString(System.lineSeparator())

private fun createOutputForIssue(
issue: Issue,
todos: Map<JiraIssueKey, Set<Path>>,
): String =
createIssueKey(issue) +
System.lineSeparator() +
createFileList(issue, todos)

private fun createIssueKey(issue: Issue): String = "- ${issue.key}"

private fun createFileList(
issue: Issue,
todos: Map<JiraIssueKey, Set<Path>>,
): String =
todos[JiraIssueKey(issue.key)].orEmpty().asSequence()
.map(::createOutputForFile)
.joinToString(System.lineSeparator())

private fun createOutputForFile(path: Path): String = " - $path"
17 changes: 17 additions & 0 deletions src/main/kotlin/ch/ergon/todochecker/JiraCredentials.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ch.ergon.todochecker

import java.io.Serializable

sealed interface JiraCredentials {
data class UsernamePassword(val username: String, val password: String) : JiraCredentials, Serializable {
companion object {
private const val serialVersionUID: Long = 1
}
}

data class PersonalAccessToken(val token: String) : JiraCredentials, Serializable {
companion object {
private const val serialVersionUID: Long = 1
}
}
}
3 changes: 3 additions & 0 deletions src/main/kotlin/ch/ergon/todochecker/JiraIssueKey.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package ch.ergon.todochecker

internal data class JiraIssueKey(val value: String)
Loading

0 comments on commit c5665a6

Please # to comment.