LicensingPlugin.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.licensing
019 
020 import com.hierynomus.gradle.license.LicenseReportingPlugin
021 import com.hierynomus.gradle.license.tasks.LicenseCheck
022 import com.hierynomus.gradle.license.tasks.LicenseFormat
023 import groovy.transform.CompileDynamic
024 import groovy.transform.CompileStatic
025 import nl.javadude.gradle.plugins.license.DownloadLicenses
026 import nl.javadude.gradle.plugins.license.DownloadLicensesExtension
027 import nl.javadude.gradle.plugins.license.LicenseExtension
028 import nl.javadude.gradle.plugins.license.LicenseMetadata
029 import org.gradle.BuildAdapter
030 import org.gradle.api.Action
031 import org.gradle.api.Project
032 import org.gradle.api.invocation.Gradle
033 import org.gradle.api.tasks.TaskProvider
034 import org.kordamp.gradle.plugin.AbstractKordampPlugin
035 import org.kordamp.gradle.plugin.base.BasePlugin
036 import org.kordamp.gradle.plugin.base.ProjectConfigurationExtension
037 import org.kordamp.gradle.plugin.base.model.License
038 import org.kordamp.gradle.plugin.base.model.LicenseId
039 
040 import static org.kordamp.gradle.PluginUtils.resolveEffectiveConfig
041 import static org.kordamp.gradle.plugin.base.BasePlugin.isRootProject
042 
043 /**
044  @author Andres Almiray
045  @since 0.2.0
046  */
047 @CompileStatic
048 class LicensingPlugin extends AbstractKordampPlugin {
049     private static final LicenseMetadata LICENSE_APACHE_TWO = new LicenseMetadata('The Apache Software License, Version 2.0', LicenseId.APACHE_2_0.url())
050     private static final LicenseMetadata LICENSE_EPL1 = new LicenseMetadata('Eclipse Public License v1.0', LicenseId.EPL_1_0.url())
051     private static final LicenseMetadata LICENSE_EPL2 = new LicenseMetadata('Eclipse Public License v2.0', LicenseId.EPL_2_0.url())
052     private static final LicenseMetadata LICENSE_LGPL21 = new LicenseMetadata('GNU Lesser General Public License v2.1 or later', LicenseId.LGPL_2_1_OR_LATER.url())
053     private static final LicenseMetadata LICENSE_MIT = new LicenseMetadata('MIT License', LicenseId.MIT.url())
054     private static final LicenseMetadata LICENSE_BSD2 = new LicenseMetadata('BS2-Clause FreeBSD License', LicenseId.BSD_2_CLAUSE_FREEBSD.url())
055     private static final LicenseMetadata LICENSE_BSD3 = new LicenseMetadata('BS3-Clause "New" or "Revised" License', LicenseId.BSD_3_CLAUSE.url())
056 
057     private static final Map<LicenseId, LicenseMetadata> LICENSES_MAP = [
058         (LicenseId.APACHE_2_0)          : LICENSE_APACHE_TWO,
059         (LicenseId.EPL_1_0)             : LICENSE_EPL1,
060         (LicenseId.EPL_2_0)             : LICENSE_EPL2,
061         (LicenseId.LGPL_2_1_OR_LATER)   : LICENSE_LGPL21,
062         (LicenseId.MIT)                 : LICENSE_MIT,
063         (LicenseId.BSD_2_CLAUSE_FREEBSD): LICENSE_BSD2,
064         (LicenseId.BSD_3_CLAUSE)        : LICENSE_BSD3
065     ]
066 
067     private static final Map<LicenseMetadata, List<String>> DEFAULT_ALIASES = [
068         (LICENSE_APACHE_TWO)['The Apache Software License, Version 2.0',
069                                'The Apache Software License, version 2.0',
070                                'Apache Software License - Version 2.0',
071                                'Apache Software License - version 2.0',
072                                'the Apache License, ASL Version 2.0',
073                                'The Apache License, Version 2.0',
074                                'The Apache License Version 2.0',
075                                'Apache License, Version 2.0',
076                                'Apache License, version 2.0',
077                                'Apache License Version 2.0',
078                                'Apache License version 2.0',
079                                'The Apache License 2.0',
080                                'Apache 2.0 License',
081                                'Apache License 2.0',
082                                'Apache 2.0',
083                                'Apache-2.0',
084                                'Apache 2'],
085         (LICENSE_EPL1)      ['Eclipse Public License - Version 1.0',
086                                'Eclipse Public License v1.0',
087                                'Eclipse Public License 1.0',
088                                'Eclipse Public License',
089                                'EPL v1.0',
090                                'EP1.0',
091                                'EPL-1.0'],
092         (LICENSE_EPL2)      ['Eclipse Public License v2.0',
093                                'Eclipse Public License 2.0',
094                                'EPL v2.0',
095                                'EP2.0',
096                                'EPL-2.0'],
097         (LICENSE_LGPL21)    ['GNU Library General Public License v2.1 or later',
098                                'GNU Lesser General Public License v2.1 or later',
099                                'GNU Lesser General Public License, Version 2.1',
100                                'LGPL 2.1',
101                                'LGPL-2.1'],
102         (LICENSE_MIT)       ['The MIT License',
103                                'The MIT license',
104                                'MIT License',
105                                'MIT license',
106                                'MIT',],
107         (LICENSE_BSD2)      ['BS2-Clause FreeBSD License',
108                                'The BSD License',
109                                'The BSD license'],
110         (LICENSE_BSD3)      ['BS3-Clause "New" or "Revised" License',
111                                '3-Clause BSD License',
112                                '3-Clause BSD license',
113                                'Revised BSD License',
114                                'Revised BSD license',
115                                'BSD Revised License',
116                                'BSD Revised license',
117                                'New BSD License',
118                                'New BSD license',
119                                'BSD New License',
120                                'BSD New license',
121                                'BS3-Clause',
122                                'BS3-clause']
123     ]
124 
125     Project project
126 
127     void apply(Project project) {
128         this.project = project
129 
130         if (isRootProject(project)) {
131             if (project.childProjects.size()) {
132                 project.childProjects.values().each {
133                     configureProject(it)
134                 }
135             }
136             configureProject(project)
137         else {
138             configureProject(project)
139         }
140     }
141 
142     static void applyIfMissing(Project project) {
143         if (!project.plugins.findPlugin(LicensingPlugin)) {
144             project.plugins.apply(LicensingPlugin)
145         }
146     }
147 
148     private void configureProject(Project project) {
149         if (hasBeenVisited(project)) {
150             return
151         }
152         setVisited(project, true)
153 
154         BasePlugin.applyIfMissing(project)
155 
156         if (!project.plugins.findPlugin(LicenseReportingPlugin)) {
157             project.plugins.apply(LicenseReportingPlugin)
158         }
159         if (!project.plugins.findPlugin(nl.javadude.gradle.plugins.license.LicensePlugin)) {
160             project.plugins.apply(nl.javadude.gradle.plugins.license.LicensePlugin)
161         }
162 
163         preConfigureDownloadLicensesExtension(project)
164 
165         project.afterEvaluate {
166             configureLicenseExtension(project)
167             postConfigureDownloadLicensesExtension(project)
168         }
169 
170         if (isRootProject(project&& !project.childProjects.isEmpty()) {
171             TaskProvider<AggregateLicenseReportTask> task = project.tasks.register('aggregateLicenseReport', AggregateLicenseReportTask,
172                 new Action<AggregateLicenseReportTask>() {
173                     @Override
174                     void execute(AggregateLicenseReportTask t) {
175                         t.enabled = false
176                         t.group = 'Reporting'
177                         t.description = 'Generates an aggregate license report.'
178                     }
179                 })
180 
181             project.gradle.addBuildListener(new BuildAdapter() {
182                 @Override
183                 void projectsEvaluated(Gradle gradle) {
184                     configureAggregateLicenseReportTask(project, task)
185                 }
186             })
187         }
188     }
189 
190     @CompileDynamic
191     private void configureLicenseExtension(Project project) {
192         ProjectConfigurationExtension effectiveConfig = resolveEffectiveConfig(project)
193         setEnabled(effectiveConfig.licensing.enabled)
194 
195         if (!enabled || effectiveConfig.licensing.empty) {
196             project.tasks.withType(LicenseCheck).each it.enabled = false }
197             project.tasks.withType(LicenseFormat).each it.enabled = false }
198             return
199         }
200 
201         License lic = effectiveConfig.licensing.allLicenses()[0]
202         if (effectiveConfig.licensing.allLicenses().size() 1) {
203             lic = effectiveConfig.licensing.allLicenses().find {
204                 it.primary
205             ?: effectiveConfig.licensing.allLicenses()[0]
206         }
207 
208         LicenseExtension licenseExtension = project.extensions.findByType(LicenseExtension)
209 
210         licenseExtension.header = project.rootProject.file('gradle/LICENSE_HEADER')
211         licenseExtension.strictCheck = true
212         licenseExtension.mapping {
213             java = 'SLASHSTAR_STYLE'
214             groovy = 'SLASHSTAR_STYLE'
215         }
216         licenseExtension.ext.project = project.name
217         licenseExtension.ext {
218             projectName = effectiveConfig.info.name
219             copyrightYear = effectiveConfig.info.copyrightYear
220             author = effectiveConfig.info.getAuthors().join(', ')
221             license = lic.licenseId?.spdx()
222         }
223         licenseExtension.exclude '**/*.png'
224         licenseExtension.exclude '**/*.gif'
225         licenseExtension.exclude 'META-INF/services/*'
226     }
227 
228     private void preConfigureDownloadLicensesExtension(Project project) {
229         DownloadLicensesExtension extension = project.extensions.findByType(DownloadLicensesExtension)
230         extension.aliases = new LinkedHashMap<>(DEFAULT_ALIASES)
231     }
232 
233     @CompileDynamic
234     private void postConfigureDownloadLicensesExtension(Project project) {
235         ProjectConfigurationExtension effectiveConfig = resolveEffectiveConfig(project)
236 
237         Map<Object, List<Object>> defaultAliases = new LinkedHashMap<>(DEFAULT_ALIASES)
238         effectiveConfig.licensing.licenses.licenses.each { license ->
239             if (license.licenseId && license.aliases) {
240                 LicenseMetadata licenseMetadata = LICENSES_MAP.get(license.licenseId)
241                 if (!licenseMetadata) {
242                     licenseMetadata = new LicenseMetadata(license.name, license.url)
243                     LICENSES_MAP.put(license.licenseId, licenseMetadata)
244                 }
245 
246                 List<Object> aliases = defaultAliases.get(licenseMetadata)
247                 if (!aliases) {
248                     aliases = []
249                     defaultAliases.put(licenseMetadata, aliases)
250                 }
251                 List<String> combined = aliases + license.aliases
252                 combined = combined.unique() - aliases
253                 aliases.addAll(combined)
254             }
255         }
256 
257         DownloadLicensesExtension extension = project.extensions.findByType(DownloadLicensesExtension)
258         extension.aliases = new LinkedHashMap<>(defaultAliases)
259 
260         project.tasks.withType(DownloadLicenses) { DownloadLicenses task ->
261             task.aliases = defaultAliases
262         }
263     }
264 
265     private void configureAggregateLicenseReportTask(Project project, TaskProvider<AggregateLicenseReportTask> task) {
266         ProjectConfigurationExtension effectiveConfig = resolveEffectiveConfig(project)
267         if (!effectiveConfig.licensing.enabled) {
268             return
269         }
270 
271         Set<DownloadLicenses> tasks = new LinkedHashSet<>()
272         project.subprojects.each { prj ->
273             tasks.addAll(prj.tasks.withType(DownloadLicenses))
274         }
275 
276         task.configure(new Action<AggregateLicenseReportTask>() {
277             @Override
278             void execute(AggregateLicenseReportTask t) {
279                 t.dependsOn tasks
280                 t.enabled = true
281             }
282         })
283     }
284 }