SourceStatsPlugin.groovy
001 /*
002  * SPDX-License-Identifier: Apache-2.0
003  *
004  * Copyright 2018-2019 Andres Almiray.
005  *
006  * Licensed under the Apache License, Version 2.0 (the "License");
007  * you may not use this file except in compliance with the License.
008  * You may obtain a copy of the License at
009  *
010  *     http://www.apache.org/licenses/LICENSE-2.0
011  *
012  * Unless required by applicable law or agreed to in writing, software
013  * distributed under the License is distributed on an "AS IS" BASIS,
014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015  * See the License for the specific language governing permissions and
016  * limitations under the License.
017  */
018 package org.kordamp.gradle.plugin.stats
019 
020 import groovy.transform.CompileStatic
021 import org.gradle.BuildAdapter
022 import org.gradle.api.Action
023 import org.gradle.api.Project
024 import org.gradle.api.invocation.Gradle
025 import org.gradle.api.tasks.TaskProvider
026 import org.kordamp.gradle.PluginUtils
027 import org.kordamp.gradle.plugin.AbstractKordampPlugin
028 import org.kordamp.gradle.plugin.base.BasePlugin
029 import org.kordamp.gradle.plugin.base.ProjectConfigurationExtension
030 import org.kordamp.gradle.plugin.base.plugins.Stats
031 
032 import static org.kordamp.gradle.PluginUtils.resolveEffectiveConfig
033 import static org.kordamp.gradle.plugin.base.BasePlugin.isRootProject
034 
035 /**
036  @author Andres Almiray
037  @since 0.5.0
038  */
039 @CompileStatic
040 class SourceStatsPlugin extends AbstractKordampPlugin {
041     static final String AGGREGATE_STATS_TASK_NAME = 'aggregateSourceStats'
042 
043     Project project
044 
045     void apply(Project project) {
046         this.project = project
047 
048         if (isRootProject(project)) {
049             project.childProjects.values().each {
050                 configureProject(it)
051             }
052         }
053         configureProject(project)
054     }
055 
056     static void applyIfMissing(Project project) {
057         if (!project.plugins.findPlugin(SourceStatsPlugin)) {
058             project.plugins.apply(SourceStatsPlugin)
059         }
060     }
061 
062     private void configureProject(Project project) {
063         if (hasBeenVisited(project)) {
064             return
065         }
066         setVisited(project, true)
067 
068         BasePlugin.applyIfMissing(project)
069 
070         project.afterEvaluate {
071             ProjectConfigurationExtension effectiveConfig = resolveEffectiveConfig(project)
072             setEnabled(effectiveConfig.stats.enabled)
073 
074             if (enabled) {
075                 if (isRootProject(project&& project.childProjects.isEmpty()) {
076                     maybeCreateStatsTask(project)
077                 else if (!isRootProject(project)) {
078                     maybeCreateStatsTask(project)
079                 }
080             }
081         }
082 
083         if (isRootProject(project&& !project.childProjects.isEmpty()) {
084             TaskProvider<AggregateSourceStatsReportTask> task = project.tasks.register(
085                 AGGREGATE_STATS_TASK_NAME,
086                 AggregateSourceStatsReportTask,
087                 new Action<AggregateSourceStatsReportTask>() {
088                     @Override
089                     void execute(AggregateSourceStatsReportTask t) {
090                         t.enabled = false
091                         t.group = 'Reporting'
092                         t.description = 'Aggregate source stats reports.'
093                     }
094                 })
095 
096             project.gradle.addBuildListener(new BuildAdapter() {
097                 @Override
098                 void projectsEvaluated(Gradle gradle) {
099                     applyAggregateStats(project, task)
100                 }
101             })
102         }
103     }
104 
105     private void maybeCreateStatsTask(Project project) {
106         try {
107             // see if the project supports sourceSets
108             PluginUtils.resolveSourceSets(project)
109             createStatsTask(project)
110         catch (MissingPropertyException ignored) {
111             // incompatible project, skip it
112         }
113     }
114 
115     private void createStatsTask(Project project) {
116         ProjectConfigurationExtension effectiveConfig = resolveEffectiveConfig(project)
117 
118         TaskProvider<SourceStatsTask> statsTask = project.tasks.register('sourceStats', SourceStatsTask,
119             new Action<SourceStatsTask>() {
120                 @Override
121                 void execute(SourceStatsTask t) {
122                     t.enabled = effectiveConfig.stats.enabled
123                     t.group = 'Reporting'
124                     t.description = 'Generates a report on lines of code'
125                     t.paths = effectiveConfig.stats.paths
126                     t.formats = effectiveConfig.stats.formats
127                     t.counters = effectiveConfig.stats.counters
128                 }
129             })
130 
131         if (effectiveConfig.stats.enabled) {
132             effectiveConfig.stats.projects() << project
133             effectiveConfig.stats.statsTasks() << statsTask
134         }
135     }
136 
137     private void applyAggregateStats(Project project, TaskProvider<AggregateSourceStatsReportTask> task) {
138         ProjectConfigurationExtension effectiveConfig = resolveEffectiveConfig(project)
139 
140         Set<TaskProvider<?>> allStatsTasks = new LinkedHashSet<>(effectiveConfig.stats.statsTasks())
141 
142         project.childProjects.values().each {
143             Stats stats = resolveEffectiveConfig(it).stats
144             if (stats.enabled) {
145                 allStatsTasks.addAll(stats.statsTasks())
146             }
147         }
148 
149         task.configure(new Action<AggregateSourceStatsReportTask>() {
150             @Override
151             void execute(AggregateSourceStatsReportTask t) {
152                 t.enabled = effectiveConfig.stats.enabled
153                 t.dependsOn allStatsTasks
154                 t.formats = effectiveConfig.stats.formats
155             }
156         })
157     }
158 }