15
15
* limitations under the License.
16
16
*/
17
17
18
+ import groovy.json.JsonSlurper
19
+ import org.apache.commons.io.IOUtils
20
+ import org.apache.http.client.config.RequestConfig
21
+ import org.apache.http.client.methods.CloseableHttpResponse
22
+ import org.apache.http.client.methods.HttpGet
23
+ import org.apache.http.impl.client.CloseableHttpClient
24
+ import org.apache.http.impl.client.HttpClients
25
+ import org.apache.http.util.EntityUtils
26
+
27
+ import java.nio.charset.StandardCharsets
28
+ import java.nio.file.Files
29
+ import java.nio.file.Paths
18
30
import java.util.concurrent.TimeUnit
19
31
20
-
21
-
22
32
buildscript {
23
33
repositories {
24
- mavenLocal()
25
34
mavenCentral()
26
35
maven {
27
36
url " https://maven.aliyun.com/repository/public"
28
37
}
29
-
30
38
maven {
31
39
url " https://plugins.gradle.org/m2/"
32
40
}
@@ -35,11 +43,18 @@ buildscript {
35
43
dependencies {
36
44
classpath " com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.14"
37
45
classpath " io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE"
38
- classpath " com.github.jk1:gradle-license-report:1.17"
39
46
classpath " com.diffplug.spotless:spotless-plugin-gradle:6.13.0"
47
+
48
+ classpath " org.apache.httpcomponents:httpclient:4.5.13"
49
+ classpath " commons-io:commons-io:2.11.0"
40
50
}
41
51
}
42
52
53
+ plugins {
54
+ id ' org.cyclonedx.bom' version ' 1.8.2'
55
+ id ' com.github.jk1.dependency-license-report' version ' 2.6'
56
+ }
57
+
43
58
// Remove doclint warnings that pollute javadoc logs when building
44
59
if (JavaVersion . current(). isJava8()) {
45
60
allprojects {
@@ -53,16 +68,15 @@ allprojects {
53
68
apply plugin : ' java'
54
69
apply plugin : " eclipse"
55
70
apply plugin : " idea"
56
- apply plugin : " project-reports"
57
71
apply plugin : " maven-publish"
58
- apply plugin : " com.github.spotbugs"
59
72
apply plugin : " project-reports"
60
73
apply plugin : " jacoco"
61
74
apply plugin : " pmd"
62
75
apply plugin : " java-library"
63
76
apply plugin : ' signing'
64
77
apply plugin : ' checkstyle'
65
78
apply plugin : ' com.diffplug.spotless'
79
+ apply plugin : " com.github.spotbugs"
66
80
67
81
[compileJava, compileTestJava, javadoc]* . options* . encoding = ' UTF-8'
68
82
@@ -96,7 +110,6 @@ allprojects {
96
110
97
111
dependencies {
98
112
repositories {
99
- mavenLocal()
100
113
mavenCentral()
101
114
maven {
102
115
url " https://maven.aliyun.com/repository/public"
@@ -124,7 +137,6 @@ allprojects {
124
137
removeUnusedImports()
125
138
}
126
139
}
127
-
128
140
afterEvaluate {
129
141
tasks. forEach {task ->
130
142
if (task. name. contains(" spotlessJava" )) {
@@ -143,6 +155,7 @@ tasks.register('dist') {
143
155
subprojects. forEach { subProject ->
144
156
dependsOn(" ${ subProject.path} :jar" )
145
157
}
158
+ dependsOn(' generateDistLicense' , ' generateDistNotice' )
146
159
def includedProjects =
147
160
[" eventmesh-common" ,
148
161
" eventmesh-meta:eventmesh-meta-api" ,
@@ -184,7 +197,7 @@ tasks.register('dist') {
184
197
}
185
198
}
186
199
copy {
187
- from ' tools/third-party-licenses '
200
+ from ' tools/dist-license '
188
201
into rootProject. file(' dist' )
189
202
}
190
203
}
@@ -252,6 +265,206 @@ tasks.register('printProjects') {
252
265
})
253
266
}
254
267
268
+ cyclonedxBom {
269
+ includeConfigs = [" runtimeClasspath" ]
270
+ }
271
+
272
+ tasks. register(' generateDistLicense' ) {
273
+ dependsOn(' cyclonedxBom' ) // Task from 'org.cyclonedx.bom' plugin
274
+ doLast {
275
+ // Inputs
276
+ def bomFile = file(" $buildDir /reports/bom.json" )
277
+ def bom = new JsonSlurper (). parseText(bomFile. text)
278
+ def projectLicenseText = file(' LICENSE' ). text
279
+
280
+ // Outputs
281
+ def distLicenseFile = file(' tools/dist-license/LICENSE' )
282
+ def licensesDir = file(' tools/dist-license/licenses/java/' )
283
+ if (licensesDir. exists()) {
284
+ licensesDir. eachFile { it. delete() }
285
+ } else {
286
+ licensesDir. mkdirs()
287
+ }
288
+
289
+ List<Map<String , String > > thirdPartyArtifacts = new ArrayList<Map<String , String > > ()
290
+ // Parse BOM
291
+ bom. components. each { component ->
292
+ // Exclude project modules
293
+ if (! component. group. startsWith(' org.apache.eventmesh' )) {
294
+ component. licenses. each { artifactLicense ->
295
+ if (artifactLicense. license != null ) {
296
+ Map<String , String > artifact = new HashMap<String , String > ()
297
+ artifact. put(" name" , component. name)
298
+ artifact. put(" version" , component. version)
299
+ if (artifactLicense. license. id != null ) {
300
+ artifact. put(" license" , artifactLicense. license. id)
301
+ if (artifactLicense. license. text != null ) {
302
+ artifact. put(" licenseContent" , new String (artifactLicense. license. text. content. decodeBase64()))
303
+ }
304
+ } else {
305
+ artifact. put(" license" , artifactLicense. license. name)
306
+ artifact. put(" licenseContent" , artifactLicense. license. url)
307
+ }
308
+ thirdPartyArtifacts. add(artifact)
309
+ }
310
+ }
311
+ }
312
+ }
313
+ thirdPartyArtifacts. sort { a , b ->
314
+ def nameComparison = a. name <=> b. name
315
+ if (nameComparison == 0 ) {
316
+ return a. version <=> b. version
317
+ } else {
318
+ return nameComparison
319
+ }
320
+ }
321
+
322
+ def distLicenseText = projectLicenseText + " \n =======================================================================\n " +
323
+ " This distribution contains the following third-party artifacts:\n\n "
324
+ thirdPartyArtifacts. each { artifact ->
325
+ // Write licenses
326
+ def artifactLicenseFilename = artifact. license. replaceAll(" /" , " -" ) + " .txt"
327
+ def artifactLicenseFile = new File (licensesDir, artifactLicenseFilename)
328
+ if (artifact. licenseContent != null ) {
329
+ artifactLicenseFile. text = artifact. licenseContent
330
+ if (isURL(artifact. licenseContent)) {
331
+ def licenseUrlFilename = artifact. licenseContent. substring(artifact. licenseContent. lastIndexOf(" /" ) + 1 )
332
+ def downloadedLicenseFilename = artifact. license. replaceAll(" /" , " -" ) + " -downloaded-" + licenseUrlFilename
333
+ def downloadedLicenseFile = new File (licensesDir, downloadedLicenseFilename)
334
+ downloadFileFromURL(artifact. licenseContent, downloadedLicenseFile. path)
335
+ }
336
+ } else {
337
+ artifactLicenseFile. text = " No license content provided by the artifact."
338
+ logger. warn(" No '${ artifact.license} ' license content provided by ${ artifact.name} ${ artifact.version} . Please add manually." )
339
+ }
340
+
341
+ // Assemble LICENSE
342
+ distLicenseText + = " ${ artifact.name} ${ artifact.version} licensed under '${ artifact.license} '. " +
343
+ " For details see: licenses/${ artifactLicenseFilename} \n "
344
+ }
345
+ distLicenseFile. text = distLicenseText
346
+ }
347
+ }
348
+
349
+ static boolean isURL (String urlString ) {
350
+ if (! urlString. startsWith(" http" )) {
351
+ return false
352
+ }
353
+ try {
354
+ new URL (urlString)
355
+ return true
356
+ } catch (MalformedURLException e) {
357
+ return false
358
+ }
359
+ }
360
+
361
+ void downloadFileFromURL (String urlString , String destinationPath ) throws Exception {
362
+ int timeout = 5 * 1000
363
+ RequestConfig config = RequestConfig . custom()
364
+ .setConnectTimeout(timeout)
365
+ .setConnectionRequestTimeout(timeout)
366
+ .setSocketTimeout(timeout)
367
+ .build()
368
+
369
+ CloseableHttpClient httpClient = HttpClients . custom()
370
+ .setDefaultRequestConfig(config)
371
+ .build()
372
+
373
+ HttpGet httpGet = new HttpGet (urlString)
374
+ CloseableHttpResponse response
375
+ try {
376
+ response = httpClient. execute(httpGet)
377
+ } catch (Exception e) {
378
+ logger. error(" Failed to download " + urlString + " : " + e. getMessage())
379
+ return
380
+ }
381
+
382
+ if (response. getStatusLine(). getStatusCode() == 200 ) {
383
+ try (InputStream is = response. getEntity(). getContent()) {
384
+ String respContent = IOUtils . toString(is, StandardCharsets . UTF_8 )
385
+ if (respContent. startsWith(" ../" )) {
386
+ // Follow GitHub symlink
387
+ URL baseUrl = new URL (urlString);
388
+ URL absoluteUrl = new URL (baseUrl, respContent);
389
+ downloadFileFromURL(absoluteUrl. toString(), destinationPath);
390
+ } else {
391
+ Files . write(Paths . get(destinationPath), respContent. getBytes(StandardCharsets . UTF_8 ))
392
+ }
393
+ }
394
+ } else {
395
+ logger. error(" Failed to download " + urlString + " : " + response. getStatusLine())
396
+ }
397
+
398
+ EntityUtils . consume(response. getEntity())
399
+ response. close()
400
+ }
401
+
402
+ tasks. register(' checkDeniedLicense' ) {
403
+ dependsOn(' generateDistLicense' )
404
+ doLast {
405
+ def deniedLicenses = [
406
+ " MS-LPL" , " BUSL-1.1" ,
407
+ " CC-BY-NC-1.0" , " CC-BY-NC-2.0" , " CC-BY-NC-2.5" , " CC-BY-NC-3.0" , " CC-BY-NC-4.0" ,
408
+ " GPL-1.0" , " GPL-2.0" , " GPL-3.0" , " AGPL-3.0" , " LGPL-2.0" , " LGPL-2.1" , " LGPL-3.0" ,
409
+ " GPL-1.0-only" , " GPL-2.0-only" , " GPL-3.0-only" , " AGPL-3.0-only" , " LGPL-2.0-only" , " LGPL-2.1-only" , " LGPL-3.0-only" ,
410
+ " QPL-1.0" , " Sleepycat" , " SSPL-1.0" , " CPOL-1.02" ,
411
+ " BSD-4-Clause" , " BSD-4-Clause-UC" , " NPL-1.0" , " NPL-1.1" , " JSON"
412
+ ]
413
+ // Update exemptions according to https://github.com/apache/eventmesh/issues/4842
414
+ def allowedArtifacts = [" amqp-client" , " stax-api" , " javassist" , " hibernate-core" , " hibernate-commons-annotations" , " ST4" , " xsdlib" ]
415
+
416
+ def licenseFile = file(' tools/dist-license/LICENSE' )
417
+ def lines = licenseFile. readLines()
418
+ def hasFailed = false
419
+
420
+ lines. each { line ->
421
+ deniedLicenses. each { deniedLicense ->
422
+ if (line. contains(" '${ deniedLicense} '" )) {
423
+ def isAllowed = allowedArtifacts. any { allowedArtifact ->
424
+ line. contains(allowedArtifact)
425
+ }
426
+ if (! isAllowed) {
427
+ logger. warn(" Incompatible license '${ deniedLicense} ' found in line: ${ line} " )
428
+ hasFailed = true
429
+ }
430
+ }
431
+ }
432
+ }
433
+
434
+ if (hasFailed) {
435
+ throw new GradleException (" Check failed due to incompatible licenses found. Please remove these dependencies or add exemptions." )
436
+ } else {
437
+ logger. lifecycle(" Check passed, no incompatible licenses found." )
438
+ }
439
+ }
440
+ }
441
+
442
+ tasks. register(' generateDistNotice' ) {
443
+ dependsOn(' generateLicenseReport' ) // Task from 'com.github.jk1.dependency-license-report' plugin
444
+ doLast {
445
+ // Inputs
446
+ def reportsDir = file(" $buildDir /reports/dependency-license/" )
447
+ def projectNoticeText = file(' NOTICE' ). text
448
+
449
+ // Outputs
450
+ def distNoticeFile = file(' tools/dist-license/NOTICE' )
451
+
452
+ def distNoticeText = projectNoticeText
453
+ reportsDir. eachDir { dir ->
454
+ dir. eachFileRecurse (groovy.io.FileType . FILES ) { file ->
455
+ // Find NOTICE files
456
+ if (file. name. length() >= 6 && file. name. substring(0 , 6 ). equalsIgnoreCase(" NOTICE" )) {
457
+ def artifactName = dir. name. replace(" .jar" , " " )
458
+ distNoticeText + = " \n =======================================================================\n\n " +
459
+ " ${ artifactName} NOTICE\n " + " \n =======================================================================\n\n "
460
+ distNoticeText + = file. text
461
+ }
462
+ }
463
+ }
464
+ distNoticeFile. text = distNoticeText
465
+ }
466
+ }
467
+
255
468
subprojects {
256
469
257
470
apply plugin : " io.spring.dependency-management"
@@ -260,7 +473,6 @@ subprojects {
260
473
main {
261
474
java. srcDirs = [' src/main/java' ]
262
475
}
263
-
264
476
test {
265
477
java. srcDirs = [' src/test/java' ]
266
478
}
@@ -271,6 +483,9 @@ subprojects {
271
483
delete ' dist'
272
484
}
273
485
486
+ // Print all dependencies trees, useful for finding artifacts
487
+ tasks. register(' printAllDependencyTrees' , DependencyReportTask ) {}
488
+
274
489
jacoco {
275
490
toolVersion = " 0.8.6"
276
491
}
@@ -297,7 +512,6 @@ subprojects {
297
512
}
298
513
299
514
spotbugsMain {
300
-
301
515
reports {
302
516
xml. required = false
303
517
html {
@@ -374,7 +588,6 @@ subprojects {
374
588
}
375
589
376
590
repositories {
377
- mavenLocal()
378
591
mavenCentral()
379
592
maven { url " https://maven.aliyun.com/repository/public" }
380
593
}
@@ -539,7 +752,6 @@ subprojects {
539
752
540
753
dependency " software.amazon.awssdk:s3:2.20.29"
541
754
dependency " com.github.rholder:guava-retrying:2.0.0"
542
-
543
755
}
544
756
}
545
757
}
0 commit comments