Skip to content

Commit

Permalink
Resolve relative csvFilePath relative to project
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhijit Sarkar authored and Abhijit Sarkar committed May 16, 2021
1 parent b2c202a commit 90d68d9
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 163 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ instructions.
If you are the fiddling type, you can customize the plugin as follows:

```
import com.asarkar.gradle.buildtimetracker.BuildTimeTrackerPluginExtension
// bunch of code
configure<BuildTimeTrackerPluginExtension> { // or buildTimeTracker {...}, for Groovy
buildTimeTracker {
barPosition = TRAILING or LEADING, default is TRAILING
sort = false or true, default is false
output = CONSOLE or CSV, default is CONSOLE
maxWidth = 120, default is 80
minTaskDuration = Duration.ofSeconds(1), don't show tasks that take less than a second to execute
showBars = false or true, default is true
csvFilePath = /path/to/csv, only relevant if output = CSV, default build/reports/buildTimeTracker/build.csv
reportsDir = only relevant if output = CSV, default $buildDir/reports/buildTimeTracker
}
```

> If you are using Kotlin build script, set the configuration properties using `property.set()` method.
:information_source: Due to a
[Gradle limitation](https://docs.gradle.org/6.5.1/userguide/upgrading_version_5.html#apis_buildlistener_buildstarted_and_gradle_buildstarted_have_been_deprecated)
, the build duration can't be calculated precisely. The bars and percentages are rounded off such that the output
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pluginImplementationClass = com.asarkar.gradle.buildtimetracker.BuildTimeTracker
pluginDeclarationName = buildTimeTrackerPlugin

projectGroup = com.asarkar.gradle
projectVersion = 3.0.0-rc
projectVersion = 3.0.0

junitVersion = latest.release
assertjVersion = latest.release
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,14 @@ import com.asarkar.gradle.buildtimetracker.Constants.PLUGIN_EXTENSION_NAME
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.plugins.ReportingBasePlugin
import org.gradle.api.reflect.TypeOf
import java.nio.file.Path
import java.nio.file.Paths
import java.time.Duration

enum class BarPosition {
LEADING, TRAILING
}

enum class Output {
CONSOLE, CSV
}

open class BuildTimeTrackerPluginExtension {
var barPosition: BarPosition = BarPosition.TRAILING
var sort: Boolean = false
var output: Output = Output.CONSOLE
var maxWidth: Int = 80
var minTaskDuration: Duration = Duration.ofSeconds(1)
var showBars: Boolean = true
var csvFilePath: Path = Paths.get("build")
.resolve("reports")
.resolve(PLUGIN_EXTENSION_NAME)
.resolve("build.csv")
}

class BuildTimeTrackerPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.pluginManager.apply(ReportingBasePlugin::class.java)
val ext = project.extensions.create(
PLUGIN_EXTENSION_NAME, BuildTimeTrackerPluginExtension::class.java
PLUGIN_EXTENSION_NAME, BuildTimeTrackerPluginExtension::class.java, project
)
(ext as ExtensionAware).extensions.add(
object : TypeOf<Map<String, Any>>() {},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.asarkar.gradle.buildtimetracker

import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.reporting.ReportingExtension
import java.time.Duration

enum class BarPosition {
LEADING, TRAILING
}

enum class Output {
CONSOLE, CSV
}

open class BuildTimeTrackerPluginExtension(private val project: Project) {
val barPosition: Property<BarPosition> = project.objects.property(BarPosition::class.java)
.convention(Constants.DEFAULT_BAR_POSITION)
val sort: Property<Boolean> = project.objects.property(Boolean::class.java)
.convention(Constants.DEFAULT_SORT)
val output: Property<Output> = project.objects.property(Output::class.java)
.convention(Constants.DEFAULT_OUTPUT)
val maxWidth: Property<Int> = project.objects.property(Int::class.java)
.convention(Constants.DEFAULT_MAX_WIDTH)
val minTaskDuration: Property<Duration> = project.objects.property(Duration::class.java)
.convention(Duration.ofSeconds(Constants.DEFAULT_MIN_TASK_DURATION))
val showBars: Property<Boolean> = project.objects.property(Boolean::class.java)
.convention(Constants.DEFAULT_SHOW_BARS)
val reportsDir: DirectoryProperty = project.objects.directoryProperty()
.convention(baseReportsDir.map { it.dir(Constants.PLUGIN_EXTENSION_NAME) })

private val baseReportsDir: DirectoryProperty
get() = project.extensions.getByType(ReportingExtension::class.java)
.baseDirectory
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,11 @@ object Constants {
const val PLUGIN_EXTENSION_NAME = "buildTimeTracker"
const val EXTRA_EXTENSION_NAME = "extra"
const val LOGGER_KEY = "logger"
val DEFAULT_BAR_POSITION = BarPosition.TRAILING
const val DEFAULT_SORT = false
val DEFAULT_OUTPUT = Output.CONSOLE
const val DEFAULT_MAX_WIDTH = 80
const val DEFAULT_MIN_TASK_DURATION = 1L
const val DEFAULT_SHOW_BARS = true
const val CSV_FILENAME = "build.csv"
}
34 changes: 21 additions & 13 deletions src/main/kotlin/com/asarkar/gradle/buildtimetracker/Printer.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.asarkar.gradle.buildtimetracker

import java.io.Closeable
import java.io.File
import java.io.PrintStream
import java.nio.charset.StandardCharsets
import java.nio.file.Files
Expand All @@ -13,7 +14,9 @@ import kotlin.math.round
data class PrinterInput(
val buildDuration: Long,
val taskDurations: List<Pair<String, Long>>,
val ext: BuildTimeTrackerPluginExtension
val maxWidth: Int,
val showBars: Boolean,
val barPosition: BarPosition
)

interface Printer : Closeable {
Expand All @@ -27,7 +30,7 @@ interface Printer : Closeable {
}

// scale the values to max column width so that the corresponding bars don't shoot out of the screen
val scalingFraction = minOf(input.ext.maxWidth.toLong(), maxDuration) / maxDuration.toDouble()
val scalingFraction = minOf(input.maxWidth.toLong(), maxDuration) / maxDuration.toDouble()
val maxNumBlocks = round(maxDuration * scalingFraction).toInt()
val maxFormattedPercentLen = maxDuration.percentOf(input.buildDuration)
.format()
Expand All @@ -42,9 +45,9 @@ interface Printer : Closeable {
it.first, delimiter, it.second.format(), delimiter, percent.format()
)

if (!input.ext.showBars) {
if (!input.showBars) {
out.println(common)
} else if (input.ext.barPosition == BarPosition.TRAILING) {
} else if (input.barPosition == BarPosition.TRAILING) {
out.printf("%s%s%s\n", common, delimiter, "$BLOCK_CHAR".repeat(numBlocks))
} else {
out.printf("%${maxNumBlocks}s%s%s\n", "$BLOCK_CHAR".repeat(numBlocks), delimiter, common)
Expand All @@ -68,19 +71,24 @@ interface Printer : Closeable {
private fun Int.format(): String = String.format("%d%%", this)

fun newInstance(ext: BuildTimeTrackerPluginExtension): Printer {
return when (ext.output) {
return when (ext.output.get()) {
Output.CONSOLE -> ConsolePrinter()
Output.CSV -> {
ext.csvFilePath.parent.toFile().mkdirs()
CsvPrinter(
PrintStream(
Files.newOutputStream(ext.csvFilePath, CREATE, WRITE, TRUNCATE_EXISTING),
false,
StandardCharsets.UTF_8.name()
)
)
val csvFile = ext.reportsDir.get()
.file(Constants.CSV_FILENAME)
.asFile
CsvPrinter(newOutputStream(csvFile))
}
}
}

internal fun newOutputStream(csvFile: File): PrintStream {
csvFile.parentFile.mkdirs()
return PrintStream(
Files.newOutputStream(csvFile.toPath(), CREATE, WRITE, TRUNCATE_EXISTING),
false,
StandardCharsets.UTF_8.name()
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.gradle.api.tasks.TaskState
import java.time.Duration
import java.time.Instant

class TimingRecorder(val ext: BuildTimeTrackerPluginExtension) : TaskExecutionListener, BuildAdapter() {
class TimingRecorder(private val ext: BuildTimeTrackerPluginExtension) : TaskExecutionListener, BuildAdapter() {
private lateinit var taskStarted: Instant
private lateinit var buildStarted: Instant
private val taskDurations = mutableListOf<Pair<String, Long>>()
Expand All @@ -23,7 +23,7 @@ class TimingRecorder(val ext: BuildTimeTrackerPluginExtension) : TaskExecutionLi

override fun afterExecute(task: Task, state: TaskState) {
val duration = Duration.between(taskStarted, Instant.now()).seconds
if (duration >= ext.minTaskDuration.seconds) {
if (duration >= ext.minTaskDuration.get().seconds) {
taskDurations.add(task.path to duration)
}
}
Expand All @@ -35,17 +35,24 @@ class TimingRecorder(val ext: BuildTimeTrackerPluginExtension) : TaskExecutionLi
)
(extra[Constants.LOGGER_KEY] as Logger).lifecycle(
"All tasks completed within the minimum threshold: {}s, no build summary to show",
ext.minTaskDuration.seconds
ext.minTaskDuration.get().seconds
)
return
}
val buildDuration = Duration.between(buildStarted, Instant.now()).seconds
if (ext.sort) {
if (ext.sort.get()) {
taskDurations.sortBy { -it.second }
}
Printer.newInstance(ext)
.use {
it.print(PrinterInput(buildDuration, taskDurations, ext))
val input = PrinterInput(
buildDuration,
taskDurations,
ext.maxWidth.get(),
ext.showBars.get(),
ext.barPosition.get()
)
it.print(input)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import org.assertj.core.api.Assertions.assertThat
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome.SUCCESS
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.nio.file.Files
Expand Down Expand Up @@ -43,17 +42,14 @@ class BuildTimeTrackerPluginFunctionalTest {
Properties().apply { load(it) }
}

@BeforeEach
fun beforeEach() {
buildFile = Files.createFile(testProjectDir.resolve("build.gradle.kts"))
private fun newBuildFile(name: String) {
buildFile = Files.createFile(testProjectDir.resolve(name))
Files.newBufferedWriter(buildFile, CREATE, WRITE, TRUNCATE_EXISTING).use {
it.write(
"""
import ${Thread::class.qualifiedName}
import ${BuildTimeTrackerPluginExtension::class.qualifiedName}
import ${Output::class.qualifiedName}
import ${Duration::class.qualifiedName}
import ${Paths::class.qualifiedName}
plugins {
id("${props.getProperty("pluginId")}")
Expand All @@ -72,11 +68,40 @@ class BuildTimeTrackerPluginFunctionalTest {
}

@Test
fun testConsoleOutput() {
fun testConsoleOutputKotlin() {
newBuildFile("build.gradle.kts")
Files.newBufferedWriter(buildFile, APPEND).use {
it.write(
"""
configure<${BuildTimeTrackerPluginExtension::class.simpleName}> {
${Constants.PLUGIN_EXTENSION_NAME} {
minTaskDuration.set(Duration.ofMillis(100))
}
""".trimIndent()
)
}

println(buildFile.readText())

val result = run()

assertThat(result.task(taskName)?.outcome == SUCCESS)
val lines = result.output
.lines()
.filter { it.isNotEmpty() }
assertThat(lines).hasSizeGreaterThanOrEqualTo(4)
assertThat(lines[0]).isEqualTo("> Task :$taskName")
assertThat(lines[1]).isEqualTo("Hello, World!")
assertThat(lines[2]).isEqualTo("== Build time summary ==")
assertThat(lines[3]).isEqualTo(":$taskName | 0S | 0% | ")
}

@Test
fun testConsoleOutputGroovy() {
newBuildFile("build.gradle")
Files.newBufferedWriter(buildFile, APPEND).use {
it.write(
"""
${Constants.PLUGIN_EXTENSION_NAME} {
minTaskDuration = Duration.ofMillis(100)
}
""".trimIndent()
Expand All @@ -99,16 +124,41 @@ class BuildTimeTrackerPluginFunctionalTest {
}

@Test
fun testCsvOutput() {
val csvFilePath = testProjectDir.resolve(BuildTimeTrackerPluginExtension().csvFilePath)
fun testCsvOutputKotlin() {
newBuildFile("build.gradle.kts")
Files.newBufferedWriter(buildFile, APPEND).use {
it.write(
"""
${Constants.PLUGIN_EXTENSION_NAME} {
minTaskDuration.set(Duration.ofMillis(100))
output.set(Output.CSV)
reportsDir.set(file("${testProjectDir.absolutePathString()}"))
}
""".trimIndent()
)
}

println(buildFile.readText())

val result = run()
val csvFile = testProjectDir.resolve(Constants.CSV_FILENAME)
assertThat(result.task(taskName)?.outcome == SUCCESS)
assertThat(Files.exists(csvFile)).isTrue
val lines = csvFile.readLines()
assertThat(lines).hasSize(1)
assertThat(lines.first()).isEqualTo(":$taskName,0S,0%,")
}

@Test
fun testCsvOutputGroovy() {
newBuildFile("build.gradle")
Files.newBufferedWriter(buildFile, APPEND).use {
it.write(
"""
configure<${BuildTimeTrackerPluginExtension::class.simpleName}> {
${Constants.PLUGIN_EXTENSION_NAME} {
minTaskDuration = Duration.ofMillis(100)
output = Output.CSV
csvFilePath = Paths.get("${csvFilePath.absolutePathString()}")
reportsDir = file("${testProjectDir.absolutePathString()}")
}
""".trimIndent()
)
Expand All @@ -117,10 +167,10 @@ class BuildTimeTrackerPluginFunctionalTest {
println(buildFile.readText())

val result = run()

val csvFile = testProjectDir.resolve(Constants.CSV_FILENAME)
assertThat(result.task(taskName)?.outcome == SUCCESS)
assertThat(Files.exists(csvFilePath)).isTrue
val lines = csvFilePath.readLines()
assertThat(Files.exists(csvFile)).isTrue
val lines = csvFile.readLines()
assertThat(lines).hasSize(1)
assertThat(lines.first()).isEqualTo(":$taskName,0S,0%,")
}
Expand Down
Loading

0 comments on commit 90d68d9

Please sign in to comment.