diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/GradleInsightsPlugin.kt b/src/main/kotlin/com/smplio/gradle/build/insights/GradleInsightsPlugin.kt index 95dff6c..b536cb8 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/GradleInsightsPlugin.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/GradleInsightsPlugin.kt @@ -3,6 +3,8 @@ package com.smplio.gradle.build.insights import com.smplio.gradle.build.insights.modules.graph.GraphBuilder import com.smplio.gradle.build.insights.modules.load.SystemLoadModule import com.smplio.gradle.build.insights.modules.timing.ExecutionTimeMeasurementModule +import com.smplio.gradle.build.insights.report.CompositeReportBuildService +import com.smplio.gradle.build.insights.report.impl.html.HTMLReporter import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.plugins.ReportingBasePlugin @@ -20,18 +22,41 @@ class GradleInsightsPlugin @Inject constructor(private val registry: BuildEvents project, ) - ExecutionTimeMeasurementModule( + val executionTimeMeasurementModule = ExecutionTimeMeasurementModule( project, registry, pluginConfig.getExecutionTimeMeasurementConfiguration(), - pluginConfig.gatherHtmlReport, - ).initialize() + ) + executionTimeMeasurementModule.initialize() - SystemLoadModule( + val systemLoadModule = SystemLoadModule( project, registry, - pluginConfig.gatherHtmlReport, - ).initialize() + ) + systemLoadModule.initialize() + + val compositeReportBuildService = project.gradle.sharedServices.registerIfAbsent( + CompositeReportBuildService::class.java.simpleName, + CompositeReportBuildService::class.java, + ) { buildServiceSpec -> + buildServiceSpec.parameters.reporters.set(mutableListOf( + pluginConfig.getExecutionTimeMeasurementConfiguration().executionTimeReporter.get(), + ).also { list -> + if (pluginConfig.gatherHtmlReport.get()) { + list.add(HTMLReporter(project)) + } + }) + executionTimeMeasurementModule.getConfigurationTimeReportProvider().let { + buildServiceSpec.parameters.configurationTimeReportProvider.set(it) + } + executionTimeMeasurementModule.getExecutionTimeReportProvider()?.let { + buildServiceSpec.parameters.executionTimeReportService.set(it) + } + systemLoadModule.getSystemLoadReportProvider()?.let { + buildServiceSpec.parameters.systemLoadReportService.set(it) + } + } + registry.onTaskCompletion(compositeReportBuildService) GraphBuilder().also { it.buildProjectDependencyGraph(project) diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/ISystemLoadReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/ISystemLoadReporter.kt deleted file mode 100644 index 5eb66ac..0000000 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/ISystemLoadReporter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.smplio.gradle.build.insights.modules.load - -import com.smplio.gradle.build.insights.reporters.IReporter -import java.util.concurrent.ConcurrentLinkedQueue - -interface ISystemLoadReporter: IReporter { - fun reportSystemLoad(measurements: ConcurrentLinkedQueue>>>) -} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/LocalCacheReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/LocalCacheReporter.kt index 6b458a8..97cc201 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/LocalCacheReporter.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/LocalCacheReporter.kt @@ -2,6 +2,7 @@ package com.smplio.gradle.build.insights.modules.load import com.codahale.metrics.* import com.codahale.metrics.Timer +import com.smplio.gradle.build.insights.report.load.ISystemLoadReportProvider import java.util.SortedMap import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.TimeUnit @@ -18,7 +19,7 @@ class LocalCacheReporter( filter, rateUnit, durationUnit, -) { +), ISystemLoadReportProvider { private val measurements: ConcurrentLinkedQueue>>> = ConcurrentLinkedQueue() override fun report( @@ -42,8 +43,8 @@ class LocalCacheReporter( measurements.add(measurementTime to measurementsValues) } - fun close(reporter: ISystemLoadReporter) { + override fun provideSystemLoadReport(): SystemLoadReport? { super.close() - reporter.reportSystemLoad(measurements) + return measurements } } \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadModule.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadModule.kt index 45e15af..64a3c78 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadModule.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadModule.kt @@ -1,39 +1,26 @@ package com.smplio.gradle.build.insights.modules.load -import com.smplio.gradle.build.insights.reporters.CompositeReporter -import com.smplio.gradle.build.insights.reporters.html.HTMLReporter import org.gradle.api.Project -import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.build.event.BuildEventsListenerRegistry class SystemLoadModule( private val project: Project, private val registry: BuildEventsListenerRegistry, - private val gatherHtmlReport: Property, ) { + private var systemLoadService: Provider? = null + fun initialize() { - val sharedServices = project.gradle.sharedServices - val systemLoadService = sharedServices.registerIfAbsent( + systemLoadService = project.gradle.sharedServices.registerIfAbsent( SystemLoadService::class.java.simpleName, - SystemLoadService::class.java, - ) {} - - project.gradle.taskGraph.whenReady { - val compositeReporter = CompositeReporter( - if (gatherHtmlReport.get()) { - listOf( - HTMLReporter( - project, - ), - ) - } else { - emptyList() - } - ) - val service = systemLoadService.get() - service.reporter = compositeReporter + SystemLoadService::class.java + ) {}.also { + registry.onTaskCompletion(it) } - registry.onTaskCompletion(systemLoadService) } -} \ No newline at end of file + + fun getSystemLoadReportProvider(): Provider? { + return systemLoadService + } +} diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadReport.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadReport.kt new file mode 100644 index 0000000..515a084 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadReport.kt @@ -0,0 +1,5 @@ +package com.smplio.gradle.build.insights.modules.load + +import java.util.concurrent.ConcurrentLinkedQueue + +typealias SystemLoadReport = ConcurrentLinkedQueue>>> diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadService.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadService.kt index d200249..3d85c85 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadService.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/load/SystemLoadService.kt @@ -1,6 +1,7 @@ package com.smplio.gradle.build.insights.modules.load import com.codahale.metrics.* +import com.smplio.gradle.build.insights.report.load.ISystemLoadReportProvider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters import org.gradle.tooling.events.FinishEvent @@ -9,12 +10,11 @@ import java.util.concurrent.TimeUnit abstract class SystemLoadService: BuildService, OperationCompletionListener, - AutoCloseable + ISystemLoadReportProvider { private val registry: MetricRegistry = MetricRegistry() private val metricsReporter: LocalCacheReporter - var reporter: ISystemLoadReporter? = null init { registry.register(SystemLoadMetric.SystemLoadAverageMetric()) @@ -33,11 +33,7 @@ abstract class SystemLoadService: BuildService, override fun onFinish(event: FinishEvent?) {} - override fun close() { - reporter?.let { - metricsReporter.close(it) - } ?: kotlin.run { - metricsReporter.close() - } + override fun provideSystemLoadReport(): SystemLoadReport? { + return metricsReporter.provideSystemLoadReport() } } \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementConfiguration.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementConfiguration.kt index 37f6c05..0d10f8d 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementConfiguration.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementConfiguration.kt @@ -1,7 +1,7 @@ package com.smplio.gradle.build.insights.modules.timing import com.smplio.gradle.build.insights.modules.timing.report.ConsoleExecutionTimeReporter -import com.smplio.gradle.build.insights.modules.timing.report.IExecutionTimeReporter +import com.smplio.gradle.build.insights.report.timing.ITaskExecutionTimeReportReceiver import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import javax.inject.Inject @@ -9,9 +9,9 @@ import javax.inject.Inject abstract class ExecutionTimeMeasurementConfiguration @Inject constructor(objects: ObjectFactory) { val enabled: Property = objects.property(Boolean::class.java).convention(true) - val executionTimeReporter: Property = (objects.property( - IExecutionTimeReporter::class.java - ) as Property).convention( + val executionTimeReporter: Property = (objects.property( + ITaskExecutionTimeReportReceiver::class.java + ) as Property).convention( ConsoleExecutionTimeReporter() ) } \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementModule.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementModule.kt index a19c194..0aae5df 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementModule.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementModule.kt @@ -1,71 +1,49 @@ package com.smplio.gradle.build.insights.modules.timing -import com.smplio.gradle.build.insights.reporters.CompositeReporter -import com.smplio.gradle.build.insights.reporters.html.HTMLReporter +import com.smplio.gradle.build.insights.report.timing.IConfigurationTimeReportProvider import org.gradle.api.Project -import org.gradle.api.provider.Property import org.gradle.build.event.BuildEventsListenerRegistry -import com.smplio.gradle.build.insights.modules.timing.ExecutionTimeMeasurementService.SerializableStartParameter -import com.smplio.gradle.build.insights.modules.timing.models.ConfigurationInfo -import com.smplio.gradle.build.insights.modules.timing.models.Measured -import java.util.concurrent.ConcurrentHashMap +import com.smplio.gradle.build.insights.modules.timing.report_providers.ConfigurationTimeReportProvider +import com.smplio.gradle.build.insights.modules.timing.report_providers.TaskTaskExecutionTimeMeasurementService +import org.gradle.api.provider.Provider class ExecutionTimeMeasurementModule( private val project: Project, private val registry: BuildEventsListenerRegistry, private val configuration: ExecutionTimeMeasurementConfiguration, - private val gatherHtmlReport: Property, ) { - fun initialize() { - val buildStartTime = System.currentTimeMillis() - val configurationStartTimes = ConcurrentHashMap() + private var taskExecutionTimeMeasurementService: Provider? = null + private val configurationTimeReportProvider = ConfigurationTimeReportProvider() - val configurationTimeline = mutableListOf>() + fun initialize() { + val buildStartTime = System.currentTimeMillis() project.gradle.beforeProject { - configurationStartTimes[it.displayName] = System.currentTimeMillis() + configurationTimeReportProvider.onBeforeProject(it) } project.gradle.afterProject { - val startTime = configurationStartTimes[it.displayName] ?: return@afterProject - configurationTimeline.add(Measured( - measuredInstance = ConfigurationInfo( - projectName = it.path, - ), - startTime = startTime, - endTime = System.currentTimeMillis(), - )) + configurationTimeReportProvider.onAfterProject(it) } - project.gradle.taskGraph.whenReady { - val default = CompositeReporter(mutableListOf( - configuration.executionTimeReporter.get(), - ).also { list -> - if (gatherHtmlReport.get()) { - list.add(HTMLReporter(project)) - } - }) - - if (configuration.enabled.get()) { - - val startParameter = SerializableStartParameter.create( - startParameter = project.gradle.startParameter, - taskExecutionGraph = it, - ) - - val sharedServices = project.gradle.sharedServices - val timerService = sharedServices.registerIfAbsent( - ExecutionTimeMeasurementService::class.java.simpleName, - ExecutionTimeMeasurementService::class.java, - ) { - it.parameters.startParameters.set(startParameter) - it.parameters.reporter.set(default) - it.parameters.buildStartTime.set(buildStartTime) - it.parameters.configurationsTimeline.set(configurationTimeline) - } - registry.onTaskCompletion(timerService) + if (configuration.enabled.get()) { + taskExecutionTimeMeasurementService = project.gradle.sharedServices.registerIfAbsent( + TaskTaskExecutionTimeMeasurementService::class.java.simpleName, + TaskTaskExecutionTimeMeasurementService::class.java, + ) { + it.parameters.buildStartTime.set(buildStartTime) + }.also { + registry.onTaskCompletion(it) } } } + + fun getConfigurationTimeReportProvider(): IConfigurationTimeReportProvider { + return configurationTimeReportProvider + } + + fun getExecutionTimeReportProvider(): Provider? { + return taskExecutionTimeMeasurementService + } } diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ConsoleExecutionTimeReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ConsoleExecutionTimeReporter.kt index 7404eae..878edaf 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ConsoleExecutionTimeReporter.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ConsoleExecutionTimeReporter.kt @@ -1,26 +1,68 @@ package com.smplio.gradle.build.insights.modules.timing.report +import com.smplio.gradle.build.insights.report.timing.IConfigurationTimeReportReceiver +import com.smplio.gradle.build.insights.report.timing.ITaskExecutionTimeReportReceiver import java.time.Duration -class ConsoleExecutionTimeReporter: IExecutionTimeReporter { - override fun reportExecutionTime(executionTimeReport: ExecutionTimeReport) { - val firstTaskStartTime = executionTimeReport.taskExecutionTimeline.minOf { it.startTime } - val lastTaskEndTime = executionTimeReport.taskExecutionTimeline.maxOf { it.endTime } - val totalTaskExecutionTime: Long = lastTaskEndTime - firstTaskStartTime - val longestTaskName: Int = executionTimeReport.taskExecutionTimeline.maxOf { it.measuredInstance.path.length } + 1 - - println("Build took: ${Duration.ofMillis(executionTimeReport.buildInfo.duration).seconds}s") - - for (measuredTaskInfo in executionTimeReport.taskExecutionTimeline) { - val taskInfo = measuredTaskInfo.measuredInstance - val taskDuration = Duration.ofMillis(measuredTaskInfo.duration).seconds - val progress = createProgressBar((measuredTaskInfo.duration) * 1.0f / totalTaskExecutionTime) - val taskNamePadded = taskInfo.path.padStart(longestTaskName).padEnd(longestTaskName + 1) - println("|${progress}| $taskNamePadded | ${"${taskDuration}s".padStart(4)}") - } +class ConsoleExecutionTimeReporter: IConfigurationTimeReportReceiver, ITaskExecutionTimeReportReceiver { + + private var configurationTimeReport: ConfigurationTimeReport? = null + private var taskExecutionTimeReport: TaskExecutionTimeReport? = null + + override fun reportConfigurationTime(configurationTimeReport: ConfigurationTimeReport) { + this.configurationTimeReport = configurationTimeReport + } + + override fun reportTaskExecutionTime(taskExecutionTimeReport: TaskExecutionTimeReport) { + this.taskExecutionTimeReport = taskExecutionTimeReport } private fun createProgressBar(progress: Float): String { val numberOfBars = ((progress * 25).toInt() - 1).coerceAtLeast(0) return "${"=".repeat(numberOfBars)}>${" ".repeat(24 - numberOfBars)}" } + + override fun submitReport() { + var firstConfigurationStartTime = 0L + var lastTaskEndTime = 0L + configurationTimeReport?.let { report -> + println("Configuration time:") + firstConfigurationStartTime = report.minOf { it.startTime } + val lastConfigurationEndTime = report.maxOf { it.endTime } + val totalConfigurationTime: Long = lastConfigurationEndTime - firstConfigurationStartTime + val longestProjectName: Int = report.maxOf { it.measuredInstance.projectName.length } + 1 + + for (measuredConfigurationInfo in report) { + val projectInfo = measuredConfigurationInfo.measuredInstance + val configurationDuration = Duration.ofMillis(measuredConfigurationInfo.duration).seconds + val progress = createProgressBar((measuredConfigurationInfo.duration) * 1.0f / totalConfigurationTime) + val projectNamePadded = projectInfo.projectName.padStart(longestProjectName).padEnd(longestProjectName + 1) + println("|${progress}| $projectNamePadded | ${"${configurationDuration}s".padStart(4)}") + } + } + + taskExecutionTimeReport?.let { report -> + println("Task execution time:") + val firstTaskStartTime = report.minOf { it.startTime } + + if (firstConfigurationStartTime == 0L) { + firstConfigurationStartTime = firstTaskStartTime + } + + lastTaskEndTime = report.maxOf { it.endTime } + val totalTaskExecutionTime: Long = lastTaskEndTime - firstTaskStartTime + val longestTaskName: Int = report.maxOf { it.measuredInstance.path.length } + 1 + + for (measuredTaskInfo in report) { + val taskInfo = measuredTaskInfo.measuredInstance + val taskDuration = Duration.ofMillis(measuredTaskInfo.duration).seconds + val progress = createProgressBar((measuredTaskInfo.duration) * 1.0f / totalTaskExecutionTime) + val taskNamePadded = taskInfo.path.padStart(longestTaskName).padEnd(longestTaskName + 1) + println("|${progress}| $taskNamePadded | ${"${taskDuration}s".padStart(4)}") + } + } + + if (firstConfigurationStartTime != 0L && lastTaskEndTime != 0L) { + println("Build took: ${Duration.ofMillis(lastTaskEndTime - firstConfigurationStartTime).seconds}s") + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ExecutionTimeReport.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ExecutionStats.kt similarity index 76% rename from src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ExecutionTimeReport.kt rename to src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ExecutionStats.kt index 55e3f71..04ce41c 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ExecutionTimeReport.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/ExecutionStats.kt @@ -6,12 +6,14 @@ import com.smplio.gradle.build.insights.modules.timing.models.Measured import com.smplio.gradle.build.insights.modules.timing.models.TaskInfo import java.net.InetAddress -data class ExecutionTimeReport( - val requestedTasks: List, +typealias ConfigurationTimeReport = List> +typealias TaskExecutionTimeReport = List> + +data class ExecutionStats( val buildHostInfo: BuildHostInfo, val buildInfo: Measured, - val configurationTimeline: List>, - val taskExecutionTimeline: List>, + val configurationTimeline: ConfigurationTimeReport?, + val taskExecutionTimeline: TaskExecutionTimeReport?, ) data class BuildHostInfo( diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/IExecutionTimeReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/IExecutionTimeReporter.kt deleted file mode 100644 index 7ee622f..0000000 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report/IExecutionTimeReporter.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.smplio.gradle.build.insights.modules.timing.report - -import com.smplio.gradle.build.insights.reporters.IReporter - -interface IExecutionTimeReporter: IReporter { - fun reportExecutionTime(executionTimeReport: ExecutionTimeReport) -} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report_providers/ConfigurationTimeReportProvider.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report_providers/ConfigurationTimeReportProvider.kt new file mode 100644 index 0000000..a935c57 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report_providers/ConfigurationTimeReportProvider.kt @@ -0,0 +1,33 @@ +package com.smplio.gradle.build.insights.modules.timing.report_providers + +import com.smplio.gradle.build.insights.modules.timing.models.ConfigurationInfo +import com.smplio.gradle.build.insights.modules.timing.models.Measured +import com.smplio.gradle.build.insights.modules.timing.report.ConfigurationTimeReport +import com.smplio.gradle.build.insights.report.timing.IConfigurationTimeReportProvider +import org.gradle.api.Project +import java.util.concurrent.ConcurrentHashMap + +class ConfigurationTimeReportProvider: IConfigurationTimeReportProvider { + + private val configurationStartTimes = ConcurrentHashMap() + private val configurationTimeline = mutableListOf>() + + override fun provideConfigurationTimeReport(): ConfigurationTimeReport? { + return configurationTimeline + } + + fun onBeforeProject(project: Project) { + configurationStartTimes[project.displayName] = System.currentTimeMillis() + } + + fun onAfterProject(project: Project) { + val startTime = configurationStartTimes[project.displayName] ?: return + configurationTimeline.add(Measured( + measuredInstance = ConfigurationInfo( + projectName = project.path, + ), + startTime = startTime, + endTime = System.currentTimeMillis(), + )) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementService.kt b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report_providers/TaskTaskExecutionTimeMeasurementService.kt similarity index 52% rename from src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementService.kt rename to src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report_providers/TaskTaskExecutionTimeMeasurementService.kt index aceada7..ded1bc3 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/ExecutionTimeMeasurementService.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/modules/timing/report_providers/TaskTaskExecutionTimeMeasurementService.kt @@ -1,13 +1,10 @@ -package com.smplio.gradle.build.insights.modules.timing +package com.smplio.gradle.build.insights.modules.timing.report_providers -import com.smplio.gradle.build.insights.modules.timing.models.BuildInfo -import com.smplio.gradle.build.insights.modules.timing.models.ConfigurationInfo import com.smplio.gradle.build.insights.modules.timing.models.Measured import com.smplio.gradle.build.insights.modules.timing.models.TaskInfo -import com.smplio.gradle.build.insights.modules.timing.report.* -import org.gradle.StartParameter -import org.gradle.api.execution.TaskExecutionGraph -import org.gradle.api.provider.ListProperty +import com.smplio.gradle.build.insights.modules.timing.report.TaskExecutionTimeReport +import com.smplio.gradle.build.insights.report.timing.ITaskExecutionTimeReportProvider +import com.smplio.gradle.build.insights.report.IReportProvider import org.gradle.api.provider.Property import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters @@ -17,19 +14,16 @@ import org.gradle.tooling.events.task.TaskFailureResult import org.gradle.tooling.events.task.TaskFinishEvent import org.gradle.tooling.events.task.TaskSkippedResult import org.gradle.tooling.events.task.TaskSuccessResult -import java.io.Serializable import java.util.concurrent.ConcurrentLinkedQueue -abstract class ExecutionTimeMeasurementService : BuildService, +abstract class TaskTaskExecutionTimeMeasurementService : BuildService, OperationCompletionListener, - AutoCloseable + ITaskExecutionTimeReportProvider, + IReportProvider { interface Parameters: BuildServiceParameters { - val startParameters: Property - val reporter: Property val buildStartTime: Property - val configurationsTimeline: ListProperty> } private var firstTaskStartTime: Long? = null @@ -86,46 +80,15 @@ abstract class ExecutionTimeMeasurementService : BuildService) : Serializable { - companion object { - fun create( - startParameter: StartParameter, - taskExecutionGraph: TaskExecutionGraph? = null, - ): SerializableStartParameter { - val taskNameToPathMapping = HashMap() - taskExecutionGraph?.allTasks?.forEach { taskNameToPathMapping[it.name] = it.path } - val startTaskNames = startParameter.taskNames.map { taskName -> taskNameToPathMapping[taskName] ?: taskName } - return SerializableStartParameter( - taskNames = startTaskNames, - ) - } - } + override fun provideTaskExecutionTimeReport(): TaskExecutionTimeReport? { + return taskExecutionTimeline.toList() } } \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/CompositeReportBuildService.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/CompositeReportBuildService.kt new file mode 100644 index 0000000..43b00ba --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/CompositeReportBuildService.kt @@ -0,0 +1,84 @@ +package com.smplio.gradle.build.insights.report + +import com.smplio.gradle.build.insights.report.load.ISystemLoadReportReceiver +import com.smplio.gradle.build.insights.modules.load.SystemLoadService +import com.smplio.gradle.build.insights.modules.timing.models.BuildInfo +import com.smplio.gradle.build.insights.modules.timing.models.Measured +import com.smplio.gradle.build.insights.modules.timing.models.TaskInfo +import com.smplio.gradle.build.insights.modules.timing.report.BuildHostInfo +import com.smplio.gradle.build.insights.modules.timing.report.ExecutionStats +import com.smplio.gradle.build.insights.report.timing.IConfigurationTimeReportProvider +import com.smplio.gradle.build.insights.report.timing.IConfigurationTimeReportReceiver +import com.smplio.gradle.build.insights.report.timing.ITaskExecutionTimeReportReceiver +import com.smplio.gradle.build.insights.modules.timing.report_providers.TaskTaskExecutionTimeMeasurementService +import com.smplio.gradle.build.insights.report.execution.IExecutionStatsReceiver +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.tooling.events.FinishEvent +import org.gradle.tooling.events.OperationCompletionListener +import kotlin.math.max +import kotlin.math.min + +abstract class CompositeReportBuildService : BuildService, + OperationCompletionListener, + AutoCloseable +{ + interface Parameters: BuildServiceParameters { + val reporters: ListProperty + val configurationTimeReportProvider: Property + val systemLoadReportService: Property + val executionTimeReportService: Property + } + + override fun close() { + val reporters = parameters.reporters.orNull ?: return + val systemLoadService = parameters.systemLoadReportService.orNull ?: return + val executionTimeReportService = parameters.executionTimeReportService.orNull ?: return + val configurationTimeReportProvider = parameters.configurationTimeReportProvider.orNull ?: return + + reporters.filterIsInstance().forEach { reporter -> + systemLoadService.provideSystemLoadReport()?.let { + reporter.reportSystemLoad(it) + } + } + + reporters.filterIsInstance().forEach { reporter -> + executionTimeReportService.provideTaskExecutionTimeReport()?.let { + reporter.reportTaskExecutionTime(it) + } + } + + reporters.filterIsInstance().forEach { reporter -> + configurationTimeReportProvider.provideConfigurationTimeReport()?.let { + reporter.reportConfigurationTime(it) + } + } + + reporters.filterIsInstance().forEach { reporter -> + val configurationTimeline = configurationTimeReportProvider.provideConfigurationTimeReport() + val taskExecutionTimeline = executionTimeReportService.provideTaskExecutionTimeReport() + reporter.reportExecutionStats(ExecutionStats( + buildHostInfo = BuildHostInfo(), + buildInfo = Measured( + measuredInstance = BuildInfo( + status = BuildInfo.ExecutionStatus.Success().takeIf { + !taskExecutionTimeline.isNullOrEmpty() && taskExecutionTimeline.none { it.measuredInstance.status is TaskInfo.ExecutionStatus.Failed } + } ?: BuildInfo.ExecutionStatus.Failed() + ), + startTime = min(configurationTimeline?.minOfOrNull { it.startTime } ?: 0L, taskExecutionTimeline?.minOfOrNull { it.startTime } ?: 0L), + endTime = max(configurationTimeline?.maxOfOrNull { it.endTime } ?: 0L, taskExecutionTimeline?.maxOfOrNull { it.endTime } ?: 0L), + ), + configurationTimeline = configurationTimeline, + taskExecutionTimeline = taskExecutionTimeline, + )) + } + + reporters.forEach { reporter -> + reporter.submitReport() + } + } + + override fun onFinish(event: FinishEvent?) {} +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/IReportProvider.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/IReportProvider.kt new file mode 100644 index 0000000..95db679 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/IReportProvider.kt @@ -0,0 +1,5 @@ +package com.smplio.gradle.build.insights.report + +import java.io.Serializable + +interface IReportProvider: Serializable \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/IReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/IReporter.kt new file mode 100644 index 0000000..d4cca61 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/IReporter.kt @@ -0,0 +1,7 @@ +package com.smplio.gradle.build.insights.report + +import java.io.Serializable + +interface IReporter: Serializable { + fun submitReport() +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/execution/IExecutionStatsProvider.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/execution/IExecutionStatsProvider.kt new file mode 100644 index 0000000..c933160 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/execution/IExecutionStatsProvider.kt @@ -0,0 +1,8 @@ +package com.smplio.gradle.build.insights.report.execution + +import com.smplio.gradle.build.insights.modules.timing.report.ExecutionStats +import com.smplio.gradle.build.insights.report.IReportProvider + +interface IExecutionStatsProvider: IReportProvider { + fun provideExecutionReport(): ExecutionStats +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/execution/IExecutionStatsReceiver.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/execution/IExecutionStatsReceiver.kt new file mode 100644 index 0000000..84d84e8 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/execution/IExecutionStatsReceiver.kt @@ -0,0 +1,7 @@ +package com.smplio.gradle.build.insights.report.execution + +import com.smplio.gradle.build.insights.modules.timing.report.ExecutionStats + +interface IExecutionStatsReceiver { + fun reportExecutionStats(stats: ExecutionStats) +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/reporters/html/HTMLReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/impl/html/HTMLReporter.kt similarity index 55% rename from src/main/kotlin/com/smplio/gradle/build/insights/reporters/html/HTMLReporter.kt rename to src/main/kotlin/com/smplio/gradle/build/insights/report/impl/html/HTMLReporter.kt index bda1ec8..1215b1f 100644 --- a/src/main/kotlin/com/smplio/gradle/build/insights/reporters/html/HTMLReporter.kt +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/impl/html/HTMLReporter.kt @@ -1,11 +1,10 @@ -package com.smplio.gradle.build.insights.reporters.html +package com.smplio.gradle.build.insights.report.impl.html -import com.smplio.gradle.build.insights.modules.load.ISystemLoadReporter -import com.smplio.gradle.build.insights.modules.timing.models.ConfigurationInfo -import com.smplio.gradle.build.insights.modules.timing.models.Measured -import com.smplio.gradle.build.insights.modules.timing.models.TaskInfo -import com.smplio.gradle.build.insights.modules.timing.report.ExecutionTimeReport -import com.smplio.gradle.build.insights.modules.timing.report.IExecutionTimeReporter +import com.smplio.gradle.build.insights.report.load.ISystemLoadReportReceiver +import com.smplio.gradle.build.insights.modules.timing.report.ConfigurationTimeReport +import com.smplio.gradle.build.insights.report.timing.IConfigurationTimeReportReceiver +import com.smplio.gradle.build.insights.modules.timing.report.TaskExecutionTimeReport +import com.smplio.gradle.build.insights.report.timing.ITaskExecutionTimeReportReceiver import org.gradle.api.Project import org.json.JSONArray import org.json.JSONObject @@ -18,24 +17,18 @@ import kotlin.io.path.absolutePathString class HTMLReporter( project: Project, -): IExecutionTimeReporter, ISystemLoadReporter { - private val baseReportFolder = project.layout.buildDirectory.get().dir("build-report").asFile - private val tasksFile = baseReportFolder.toPath().resolve("tasks.json").toFile() - private val systemLoadFile = baseReportFolder.toPath().resolve("systemLoad.json").toFile() - +): IConfigurationTimeReportReceiver, ITaskExecutionTimeReportReceiver, ISystemLoadReportReceiver { private val uniqueReportFolder = project.layout.buildDirectory.get().dir("build-report").dir(UUID.randomUUID().toString()).asFile private val styleCssPath = uniqueReportFolder.toPath().resolve("style.css").absolutePathString() private val reportHtmlFile = uniqueReportFolder.toPath().resolve("index.html").toFile() - private var taskExecutionTimeline: List>? = null - private var configurationTimeline: List>? = null - - override fun reportExecutionTime(executionTimeReport: ExecutionTimeReport) { - taskExecutionTimeline = executionTimeReport.taskExecutionTimeline - configurationTimeline = executionTimeReport.configurationTimeline + private var configurationTimeJson: String? = null + private var executionTimeJson: String? = null + private var systemLoadJson: String? = null + override fun reportTaskExecutionTime(taskExecutionTimeReport: TaskExecutionTimeReport) { val tasks = JSONArray() - for (measuredTaskInfo in executionTimeReport.taskExecutionTimeline) { + for (measuredTaskInfo in taskExecutionTimeReport) { val task = measuredTaskInfo.measuredInstance tasks.put(JSONObject().apply { put("type", "task") @@ -46,45 +39,35 @@ class HTMLReporter( put("status_description", task.status.description) }) } - for (measuredConfigurationInfo in executionTimeReport.configurationTimeline) { + executionTimeJson = tasks.toString(4) + } + + override fun reportConfigurationTime(configurationTimeReport: ConfigurationTimeReport) { + val projects = JSONArray() + for (measuredConfigurationInfo in configurationTimeReport) { val configurationInfo = measuredConfigurationInfo.measuredInstance - tasks.put(JSONObject().apply { + projects.put(JSONObject().apply { put("type", "configuration") put("name", configurationInfo.projectName) put("start", measuredConfigurationInfo.startTime) put("end", measuredConfigurationInfo.endTime) }) } - - baseReportFolder.mkdirs() - tasksFile.bufferedWriter(Charsets.UTF_8).use { - it.write(tasks.toString(4)) - } - - tryGenerateReport() + configurationTimeJson = projects.toString(4) } override fun reportSystemLoad(measurements: ConcurrentLinkedQueue>>>) { - val systemLoadJson = JSONArray().also { + systemLoadJson = JSONArray().also { measurements.forEach { measurementSet -> it.put(JSONObject().also { it.put("timestamp", measurementSet.first) for (measurement in measurementSet.second) { it.put(measurement.first, measurement.second) } })} - } - - baseReportFolder.mkdirs() - systemLoadFile.bufferedWriter(Charsets.UTF_8).use { - it.write(systemLoadJson.toString(4)) - } - - tryGenerateReport() + }.toString(4) } - private fun tryGenerateReport() { - if (!tasksFile.exists() || !systemLoadFile.exists()) return - + override fun submitReport() { uniqueReportFolder.mkdirs() val scriptJsText = javaClass.getResourceAsStream("/script.js")?.reader()?.use { it.readText() } @@ -92,8 +75,9 @@ class HTMLReporter( val buildChartsJsText = javaClass.getResourceAsStream("/build_charts.js")?.reader()?.use { it.readText() } val html = javaClass.getResourceAsStream("/index.html")?.reader()?.readText()?.format( - tasksFile.reader().use { it.readText() }, - systemLoadFile.reader().use { it.readText() }, + configurationTimeJson ?: "", + executionTimeJson ?: "", + systemLoadJson ?: "", scriptJsText, chartJsText, buildChartsJsText, @@ -109,9 +93,10 @@ class HTMLReporter( StandardCopyOption.REPLACE_EXISTING, ) - tasksFile.delete() - systemLoadFile.delete() + configurationTimeJson = null + executionTimeJson = null + systemLoadJson = null - println("Report is available in ${reportHtmlFile.absolutePath}") + println("Build insights report is available in ${reportHtmlFile.absolutePath}") } } \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/load/ISystemLoadReportProvider.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/load/ISystemLoadReportProvider.kt new file mode 100644 index 0000000..91f94cf --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/load/ISystemLoadReportProvider.kt @@ -0,0 +1,8 @@ +package com.smplio.gradle.build.insights.report.load + +import com.smplio.gradle.build.insights.modules.load.SystemLoadReport +import com.smplio.gradle.build.insights.report.IReportProvider + +interface ISystemLoadReportProvider: IReportProvider { + fun provideSystemLoadReport(): SystemLoadReport? +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/load/ISystemLoadReportReceiver.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/load/ISystemLoadReportReceiver.kt new file mode 100644 index 0000000..1b6d309 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/load/ISystemLoadReportReceiver.kt @@ -0,0 +1,8 @@ +package com.smplio.gradle.build.insights.report.load + +import com.smplio.gradle.build.insights.modules.load.SystemLoadReport +import com.smplio.gradle.build.insights.report.IReporter + +interface ISystemLoadReportReceiver: IReporter { + fun reportSystemLoad(measurements: SystemLoadReport) +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/IConfigurationTimeReportProvider.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/IConfigurationTimeReportProvider.kt new file mode 100644 index 0000000..5d0bb47 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/IConfigurationTimeReportProvider.kt @@ -0,0 +1,8 @@ +package com.smplio.gradle.build.insights.report.timing + +import com.smplio.gradle.build.insights.modules.timing.report.ConfigurationTimeReport +import com.smplio.gradle.build.insights.report.IReportProvider + +interface IConfigurationTimeReportProvider: IReportProvider { + fun provideConfigurationTimeReport(): ConfigurationTimeReport? +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/IConfigurationTimeReportReceiver.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/IConfigurationTimeReportReceiver.kt new file mode 100644 index 0000000..a0fbcda --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/IConfigurationTimeReportReceiver.kt @@ -0,0 +1,7 @@ +package com.smplio.gradle.build.insights.report.timing + +import com.smplio.gradle.build.insights.modules.timing.report.ConfigurationTimeReport + +interface IConfigurationTimeReportReceiver { + fun reportConfigurationTime(configurationTimeReport: ConfigurationTimeReport) +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/ITaskExecutionTimeReportProvider.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/ITaskExecutionTimeReportProvider.kt new file mode 100644 index 0000000..1dc32c8 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/ITaskExecutionTimeReportProvider.kt @@ -0,0 +1,8 @@ +package com.smplio.gradle.build.insights.report.timing + +import com.smplio.gradle.build.insights.modules.timing.report.TaskExecutionTimeReport +import com.smplio.gradle.build.insights.report.IReportProvider + +interface ITaskExecutionTimeReportProvider: IReportProvider { + fun provideTaskExecutionTimeReport(): TaskExecutionTimeReport? +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/ITaskExecutionTimeReportReceiver.kt b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/ITaskExecutionTimeReportReceiver.kt new file mode 100644 index 0000000..3ca2490 --- /dev/null +++ b/src/main/kotlin/com/smplio/gradle/build/insights/report/timing/ITaskExecutionTimeReportReceiver.kt @@ -0,0 +1,8 @@ +package com.smplio.gradle.build.insights.report.timing + +import com.smplio.gradle.build.insights.modules.timing.report.TaskExecutionTimeReport +import com.smplio.gradle.build.insights.report.IReporter + +interface ITaskExecutionTimeReportReceiver: IReporter { + fun reportTaskExecutionTime(taskExecutionTimeReport: TaskExecutionTimeReport) +} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/reporters/CompositeReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/reporters/CompositeReporter.kt deleted file mode 100644 index 0cbefc2..0000000 --- a/src/main/kotlin/com/smplio/gradle/build/insights/reporters/CompositeReporter.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.smplio.gradle.build.insights.reporters - -import com.smplio.gradle.build.insights.modules.load.ISystemLoadReporter -import com.smplio.gradle.build.insights.modules.timing.report.ExecutionTimeReport -import com.smplio.gradle.build.insights.modules.timing.report.IExecutionTimeReporter -import java.util.concurrent.ConcurrentLinkedQueue - -class CompositeReporter( - private val reporters: List, -): IExecutionTimeReporter, ISystemLoadReporter { - override fun reportExecutionTime(executionTimeReport: ExecutionTimeReport) { - reporters.filterIsInstance().forEach { reporter -> reporter.reportExecutionTime(executionTimeReport) } - } - - override fun reportSystemLoad(measurements: ConcurrentLinkedQueue>>>) { - reporters.filterIsInstance().forEach { reporter -> reporter.reportSystemLoad(measurements) } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/smplio/gradle/build/insights/reporters/IReporter.kt b/src/main/kotlin/com/smplio/gradle/build/insights/reporters/IReporter.kt deleted file mode 100644 index d2d8946..0000000 --- a/src/main/kotlin/com/smplio/gradle/build/insights/reporters/IReporter.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.smplio.gradle.build.insights.reporters - -import java.io.Serializable - -interface IReporter: Serializable \ No newline at end of file diff --git a/src/main/resources/index.html b/src/main/resources/index.html index 3a44a8e..062880a 100644 --- a/src/main/resources/index.html +++ b/src/main/resources/index.html @@ -31,6 +31,7 @@ diff --git a/src/main/resources/script.js b/src/main/resources/script.js index d5c9407..c6144b1 100644 --- a/src/main/resources/script.js +++ b/src/main/resources/script.js @@ -1,6 +1,6 @@ let timeScale = 1; -let timeWindowStart = Math.min(...tasks.map(value => value.start)); -let timeWindowEnd = Math.max(...tasks.map(value => value.end)); +let timeWindowStart = Math.min(...tasks.map(value => value.start), ...configurations.map(value => value.start)); +let timeWindowEnd = Math.max(...tasks.map(value => value.end), ...configurations.map(value => value.end)); const durationMs = timeWindowEnd - timeWindowStart; // Draggable time window and handles @@ -32,71 +32,82 @@ function formatTime(timestamp) { return dtFormat.format(new Date(timestamp)); } +// Render configurations based on the time window +function createConfigurations() { + configurations.forEach(project => { + createTimelineBlock(project) + }) +} + // Render tasks based on the time window function createTasks() { tasks.forEach(task => { - let taskEl; - if (task.name in taskToDivMap) { - taskEl = taskToDivMap[task.name]; - } else { - taskEl = document.createElement("div"); - taskEl.className = "timeline-item"; - taskEl.classList.add(task.type); - if (task.type === "task") { - let taskClass = ""; - switch(task.status) { - case "SKIPPED": - if (task.status_description === "FROM-CACHE") { - taskClass = "cached-task"; - } else { - taskClass = "skipped-task"; - } - break; - case "FAILED": - taskClass = "failed-task"; - break; - default: - taskClass = "successful-task"; - break; - } - taskEl.classList.add(taskClass); + createTimelineBlock(task) + }) +} + +function createTimelineBlock(task) { + let taskEl; + if (task.name in taskToDivMap) { + taskEl = taskToDivMap[task.name]; + } else { + taskEl = document.createElement("div"); + taskEl.className = "timeline-item"; + taskEl.classList.add(task.type); + if (task.type === "task") { + let taskClass = ""; + switch(task.status) { + case "SKIPPED": + if (task.status_description === "FROM-CACHE") { + taskClass = "cached-task"; + } else { + taskClass = "skipped-task"; + } + break; + case "FAILED": + taskClass = "failed-task"; + break; + default: + taskClass = "successful-task"; + break; } - taskEl.classList.add("tooltip"); - taskEl.style.top = `${task.rowIdx * 25}px`; + taskEl.classList.add(taskClass); + } + taskEl.classList.add("tooltip"); + taskEl.style.top = `${task.rowIdx * 25}px`; - taskNameEl = document.createElement("span"); - taskNameEl.textContent = task.name; - taskEl.appendChild(taskNameEl) + taskNameEl = document.createElement("span"); + taskNameEl.textContent = task.name; + taskEl.appendChild(taskNameEl) - tooltipEl = document.createElement("div"); - tooltipEl.className = "tooltiptext"; + tooltipEl = document.createElement("div"); + tooltipEl.className = "tooltiptext"; - let detailedStatus = task.status_description; - if (task.status === "SUCCESS") { - detailedStatus = ""; - } - let statusBadge = `Status: ${task.status}
${detailedStatus}

`; - if (task.type !== "task") { - statusBadge = ""; - } + let detailedStatus = task.status_description; + if (task.status === "SUCCESS") { + detailedStatus = ""; + } + let statusBadge = `Status: ${task.status}
${detailedStatus}

`; + if (task.type !== "task") { + statusBadge = ""; + } - tooltipEl.innerHTML = `${task.name}\n
${statusBadge}Started: ${formatTime(task.start)}\nFinished: ${formatTime(task.end)}`; + tooltipEl.innerHTML = `${task.name}\n
${statusBadge}Started: ${formatTime(task.start)}\nFinished: ${formatTime(task.end)}`; - taskEl.appendChild(tooltipEl); + taskEl.appendChild(tooltipEl); - taskToDivMap[task.name] = taskEl; - taskTimeline.appendChild(taskEl); - } + taskToDivMap[task.name] = taskEl; + taskTimeline.appendChild(taskEl); + } - taskEl.style.left = `${(task.start - timeWindowStart) * timeScale}px`; - taskEl.style.width = `${(task.end - task.start) * timeScale}px`; + taskEl.style.left = `${(task.start - timeWindowStart) * timeScale}px`; + taskEl.style.width = `${(task.end - task.start) * timeScale}px`; - if (task.end < timeWindowStart || task.start > timeWindowEnd) { - taskEl.style.visibility = "hidden"; - } else { - taskEl.style.visibility = "visible"; - } - }) + if (task.end < timeWindowStart || task.start > timeWindowEnd) { + taskEl.style.visibility = "hidden"; + } else { + taskEl.style.visibility = "visible"; + } } // Calculate overlapping task rows @@ -244,6 +255,7 @@ function updateTimeWindow() { // Render tasks updateRuler(); updateCharts(); + createConfigurations(); createTasks(); } @@ -313,5 +325,6 @@ window.addEventListener ("resize", e => { }); // Initial render +configurations = calculateRows(configurations); tasks = calculateRows(tasks); updateTimeWindow();