Skip to content

Commit ea10ba9

Browse files
committed
ci check to make sure that all libraries have their source code verified as well
Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
1 parent 3ff319b commit ea10ba9

File tree

2 files changed

+127
-49
lines changed

2 files changed

+127
-49
lines changed

.github/workflows/pre-review.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,26 @@ jobs:
8282
cache-disabled: true
8383
- name: Gradle Compile
8484
run: ./gradlew build -x test -x spotlessCheck
85+
verify-source-metadata:
86+
name: "Verify Dependency Source Metadata"
87+
runs-on: ubuntu-latest
88+
needs: [spotless-checkLicense, gradle-wrapper, repolint]
89+
steps:
90+
- name: Checkout Repo
91+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
92+
with:
93+
ref: ${{ github.event.pull_request.head.sha || github.ref }}
94+
- name: Set up Java
95+
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
96+
with:
97+
distribution: temurin
98+
java-version: 21
99+
- name: Setup Gradle
100+
uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1
101+
with:
102+
cache-disabled: true
103+
- name: Verify source artifacts recorded in verification-metadata.xml
104+
run: ./gradlew verifySourceArtifacts
85105
unitTests:
86106
runs-on: besu-research-ubuntu-16 # more cores
87107
needs: [spotless-checkLicense, gradle-wrapper, repolint]
@@ -126,7 +146,7 @@ jobs:
126146
unittests-passed:
127147
name: "unittests-passed"
128148
runs-on: ubuntu-latest
129-
needs: [compile, unitTests]
149+
needs: [compile, unitTests, verify-source-metadata]
130150
permissions:
131151
checks: write
132152
statuses: write

build.gradle

Lines changed: 106 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -474,66 +474,80 @@ configure(allprojects - project(':platform')) {
474474
}
475475
}
476476

477-
task resolveSourceArtifacts {
478-
group = 'verification'
479-
description = 'Resolves source artifacts for all configurations so they can be included in dependency verification metadata'
480-
doLast {
481-
def componentIds = new HashSet()
482-
def unresolvedConfigs = 0
483-
484-
def collectComponentIds = { configs, String label ->
485-
configs.matching { it.canBeResolved }.each { config ->
486-
try {
487-
config.incoming.resolutionResult.allComponents.each { component ->
488-
componentIds.add(component.id)
489-
}
490-
} catch (Exception e) {
491-
unresolvedConfigs++
492-
logger.info("Could not resolve ${label} '${config.name}': ${e.message}")
477+
ext.collectExternalComponentIds = {
478+
->
479+
def componentIds = new HashSet()
480+
def unresolvedConfigs = 0
481+
482+
def collectComponentIds = { configs, String label ->
483+
configs.matching { it.canBeResolved }.each { config ->
484+
try {
485+
config.incoming.resolutionResult.allComponents.each { component ->
486+
componentIds.add(component.id)
493487
}
488+
} catch (Exception e) {
489+
unresolvedConfigs++
490+
logger.info("Could not resolve ${label} '${config.name}': ${e.message}")
494491
}
495492
}
493+
}
496494

497-
allprojects.each { proj ->
498-
collectComponentIds(proj.configurations, "${proj.path} config")
499-
collectComponentIds(proj.buildscript.configurations, "${proj.path} buildscript config")
500-
}
495+
allprojects.each { proj ->
496+
collectComponentIds(proj.configurations, "${proj.path} config")
497+
collectComponentIds(proj.buildscript.configurations, "${proj.path} buildscript config")
498+
}
501499

502-
if (unresolvedConfigs > 0) {
503-
logger.warn("${unresolvedConfigs} configurations could not be resolved (run with --info for details)")
504-
}
500+
if (unresolvedConfigs > 0) {
501+
logger.warn("${unresolvedConfigs} configurations could not be resolved (run with --info for details)")
502+
}
505503

506-
def externalIds = componentIds.findAll { it instanceof org.gradle.api.artifacts.component.ModuleComponentIdentifier }
507-
logger.lifecycle("Resolving sources for ${externalIds.size()} external dependencies...")
504+
return componentIds.findAll { it instanceof org.gradle.api.artifacts.component.ModuleComponentIdentifier }
505+
}
508506

509-
// Populated by resolveSources across both project and buildscript repository calls
510-
def resolvedComponentIds = new HashSet()
511-
def resolveSources = { depHandler, componentIdsToResolve, String label ->
512-
def sizeBefore = resolvedComponentIds.size()
513-
def result = depHandler.createArtifactResolutionQuery()
514-
.forComponents(componentIdsToResolve)
515-
.withArtifacts(JvmLibrary, SourcesArtifact)
516-
.execute()
517-
result.resolvedComponents.each { component ->
518-
component.getArtifacts(SourcesArtifact).each { source ->
519-
if (source instanceof ResolvedArtifactResult) {
520-
source.file // access .file to trigger download and register with verification metadata
521-
resolvedComponentIds.add(component.id)
522-
} else {
523-
logger.warn("Could not download sources for ${component.id}: ${source}")
524-
}
507+
// Retries buildscript repositories (which include the Gradle Plugin Portal) for any
508+
// components whose sources did not resolve against the project repositories.
509+
ext.forEachResolvedSourceArtifact = { Collection externalIds, Closure action ->
510+
def resolvedComponentIds = new HashSet()
511+
512+
def resolveSources = { depHandler, componentIdsToResolve, String label ->
513+
def sizeBefore = resolvedComponentIds.size()
514+
def result = depHandler.createArtifactResolutionQuery()
515+
.forComponents(componentIdsToResolve)
516+
.withArtifacts(JvmLibrary, SourcesArtifact)
517+
.execute()
518+
result.resolvedComponents.each { component ->
519+
component.getArtifacts(SourcesArtifact).each { source ->
520+
if (source instanceof ResolvedArtifactResult) {
521+
action(component.id, source)
522+
resolvedComponentIds.add(component.id)
523+
} else {
524+
logger.info("Could not resolve sources for ${component.id}: ${source}")
525525
}
526526
}
527-
def count = resolvedComponentIds.size() - sizeBefore
528-
logger.lifecycle("Resolved sources for ${count} components from ${label}")
529527
}
528+
def count = resolvedComponentIds.size() - sizeBefore
529+
logger.lifecycle("Resolved sources for ${count} components from ${label}")
530+
}
530531

531-
resolveSources(dependencies, externalIds, "project repositories")
532+
resolveSources(dependencies, externalIds, "project repositories")
532533

533-
// Retry unresolved sources using buildscript repositories (includes Gradle Plugin Portal)
534-
def unresolvedIds = externalIds.findAll { !resolvedComponentIds.contains(it) }
535-
if (!unresolvedIds.isEmpty()) {
536-
resolveSources(buildscript.dependencies, unresolvedIds, "buildscript repositories")
534+
def unresolvedIds = externalIds.findAll { !resolvedComponentIds.contains(it) }
535+
if (!unresolvedIds.isEmpty()) {
536+
resolveSources(buildscript.dependencies, unresolvedIds, "buildscript repositories")
537+
}
538+
539+
return resolvedComponentIds
540+
}
541+
542+
task resolveSourceArtifacts {
543+
group = 'verification'
544+
description = 'Resolves source artifacts for all configurations so they can be included in dependency verification metadata'
545+
doLast {
546+
def externalIds = collectExternalComponentIds()
547+
logger.lifecycle("Resolving sources for ${externalIds.size()} external dependencies...")
548+
549+
def resolvedComponentIds = forEachResolvedSourceArtifact(externalIds) { id, source ->
550+
source.file // access .file to trigger download and register with verification metadata
537551
}
538552

539553
def finalUnresolved = externalIds.size() - resolvedComponentIds.size()
@@ -544,6 +558,50 @@ task resolveSourceArtifacts {
544558
}
545559
}
546560

561+
task verifySourceArtifacts {
562+
group = 'verification'
563+
description = 'Fails the build if gradle/verification-metadata.xml is missing source artifact entries for any resolvable dependency'
564+
doLast {
565+
def metadataFile = rootProject.file('gradle/verification-metadata.xml')
566+
def slurper = new groovy.xml.XmlSlurper()
567+
slurper.setFeature('http://xml.org/sax/features/namespaces', false)
568+
def metadata = slurper.parse(metadataFile)
569+
570+
def componentsWithRecordedSources = new HashSet()
571+
metadata.components.component.each { comp ->
572+
def group = comp.@group.text()
573+
def name = comp.@name.text()
574+
def version = comp.@version.text()
575+
def expected = "${name}-${version}-sources.jar".toString()
576+
if (comp.artifact.any { it.@name.text() == expected }) {
577+
componentsWithRecordedSources.add("${group}:${name}:${version}".toString())
578+
}
579+
}
580+
581+
def externalIds = collectExternalComponentIds()
582+
def missing = new TreeSet()
583+
forEachResolvedSourceArtifact(externalIds) { id, source ->
584+
def key = "${id.group}:${id.module}:${id.version}".toString()
585+
if (!componentsWithRecordedSources.contains(key)) {
586+
missing.add(key)
587+
}
588+
}
589+
590+
if (!missing.isEmpty()) {
591+
def list = missing.collect { " - ${it}" }.join('\n')
592+
throw new GradleException(
593+
"gradle/verification-metadata.xml is missing source artifact entries for ${missing.size()} " +
594+
"${missing.size() == 1 ? 'dependency' : 'dependencies'}:\n" +
595+
"${list}\n\n" +
596+
"Regenerate the metadata by running:\n" +
597+
" ./gradlew --write-verification-metadata sha256 resolveSourceArtifacts\n" +
598+
"and commit the updated gradle/verification-metadata.xml.")
599+
}
600+
601+
logger.lifecycle("verification-metadata.xml contains source entries for all resolvable external components.")
602+
}
603+
}
604+
547605
task deploy() {}
548606

549607
task checkMavenCoordinateCollisions {

0 commit comments

Comments
 (0)