Skip to content

Commit f7f3226

Browse files
author
Sergey Mashkov
committed
Add artifact verifier
1 parent e17671f commit f7f3226

File tree

3 files changed

+205
-0
lines changed

3 files changed

+205
-0
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ ext.globalM2 = "$buildDir/m2"
2626
ext.publishLocal = project.hasProperty("publishLocal")
2727

2828
apply from: "gradle/experimental.gradle"
29+
apply from: 'gradle/verifier.gradle'
2930

3031
/**
3132
* `darwin` is subset of `posix`.

gradle/publish.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ publishing {
4949
url 'https://dl.bintray.com/kotlin/ktor'
5050
}
5151
}
52+
maven { name = "testLocal"; url = "$rootProject.buildDir/m2" }
5253
}
5354
publications.all {
5455
pom.withXml(configureMavenCentralMetadata)

gradle/verifier.gradle

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import groovy.io.FileType
2+
import groovy.json.JsonSlurper
3+
import org.xml.sax.ErrorHandler
4+
import org.xml.sax.SAXException
5+
import org.xml.sax.SAXParseException
6+
7+
import java.util.regex.Matcher
8+
9+
task cleanPublications(type: Delete) {
10+
delete new File(rootProject.buildDir, 'm2')
11+
}
12+
13+
def isBadTextNode(node) {
14+
return node == null || node.size() != 1 || !node.text().trim()
15+
}
16+
17+
def isEmptyTagList(node) {
18+
return node == null || node.size() == 0
19+
}
20+
21+
def verifyArtifact(File versionDir, List<File> files, String ext, String kind) {
22+
if (files.count { it.name.toLowerCase().endsWith(ext) } == 0) {
23+
throw new GradleException("No $ext artifact found at $versionDir (kind $kind)")
24+
}
25+
}
26+
27+
def validatePom(File file) {
28+
def parser = new XmlSlurper(false, true, false)
29+
def errors = []
30+
31+
parser.errorHandler = new ErrorHandler() {
32+
33+
@Override
34+
void warning(SAXParseException exception) throws SAXException {
35+
}
36+
37+
@Override
38+
void error(SAXParseException exception) throws SAXException {
39+
errors += exception
40+
}
41+
42+
@Override
43+
void fatalError(SAXParseException exception) throws SAXException {
44+
errors += exception
45+
}
46+
}
47+
48+
def xml = parser.parse(file)
49+
50+
if (!errors.isEmpty()) {
51+
throw errors[0]
52+
}
53+
54+
if (isBadTextNode(xml.name)) {
55+
errors += ['<name> tag is missing']
56+
}
57+
58+
if (isBadTextNode(xml.description)) {
59+
errors += ['<description> tag is missing']
60+
}
61+
62+
if (isBadTextNode(xml.url)) {
63+
errors += ['<url> tag is missing']
64+
}
65+
66+
def licenses = xml.licenses.license
67+
if (isEmptyTagList(licenses)) {
68+
errors += 'No licenses specified'
69+
} else if (licenses.any { isBadTextNode(it.name) || isBadTextNode(it.url) || isBadTextNode(it.distribution) }) {
70+
errors += 'License section is incomplete'
71+
}
72+
73+
def developers = xml.developers.developer
74+
if (isEmptyTagList(developers)) {
75+
errors += 'No developers specified'
76+
} else if (developers.any { isBadTextNode(it.id) || isBadTextNode(it.name) || isBadTextNode(it.organization) || isBadTextNode(it.organizationUrl)}) {
77+
errors += 'Developer section is incomplete'
78+
}
79+
80+
def scm = xml.scm.url
81+
if (isEmptyTagList(scm)) {
82+
errors += 'No scm specified'
83+
}
84+
85+
if (!errors.isEmpty()) {
86+
throw new GradleException("Pom verification failed for $file.name: ${errors.join(', ')}")
87+
}
88+
}
89+
90+
String packaging(File moduleDir) {
91+
def pomFile = moduleDir.listFiles()?.find { it.name.endsWith('.pom') }
92+
if (pomFile == null || !pomFile.exists()) {
93+
throw new GradleException("POM file is missing at $moduleDir")
94+
}
95+
96+
def packaing = new XmlSlurper(false, true, false).parse(pomFile).packaging.text()
97+
if (!packaing?.trim()) return 'jar'
98+
return packaing
99+
}
100+
101+
def lookupTasks = {
102+
def targetNames = kotlin.targets.collect { it.name }
103+
def tasks = []
104+
105+
allprojects {
106+
tasks += targetNames.collect { project.tasks.findByName("publish${it.capitalize()}PublicationToTestLocalRepository") }
107+
.findAll()
108+
}
109+
110+
return [cleanPublications] + tasks
111+
}
112+
113+
// returns jvm, js, native or some native target name
114+
String guessModuleKind(File dir, File pomFile) {
115+
def artifactId_ = new XmlSlurper(false, true).parse(pomFile).artifactId.text()
116+
def kind = null
117+
118+
allprojects {
119+
project.publishing.publications.findAll { !it.name.contains('-test') && it.artifactId == artifactId_ }.each {
120+
kind = it.name
121+
}
122+
}
123+
124+
if (!kind) {
125+
allprojects { project ->
126+
println "project $project.name"
127+
project.publishing.publications.each {
128+
println "publication $it.name with ${it.artifactId} (looking for $artifactId_, found = ${it.artifactId == artifactId_})"
129+
}
130+
}
131+
throw new GradleException("Not found")
132+
}
133+
134+
return kind
135+
}
136+
137+
task verifyPublications(dependsOn: lookupTasks) {
138+
doLast {
139+
def m2 = new File(rootProject.buildDir, 'm2')
140+
def pomFiles = []
141+
def moduleFiles = []
142+
143+
m2.eachFileRecurse(FileType.FILES) { child ->
144+
if (child.name.toLowerCase() != 'maven-metadata.xml') {
145+
def ext = child.name.split(/\./).last().toLowerCase()
146+
switch (ext) {
147+
case 'pom':
148+
pomFiles += child
149+
break
150+
case 'module':
151+
moduleFiles += child
152+
break
153+
}
154+
}
155+
}
156+
157+
pomFiles.each { File file ->
158+
validatePom(file)
159+
}
160+
161+
def groupDir = new File(m2, project.group.replaceAll(/\./, Matcher.quoteReplacement(File.separator)))
162+
def verified = 0
163+
164+
groupDir.eachDir { artifactDir ->
165+
def versionDir = new File(artifactDir, project.version)
166+
167+
if (versionDir.exists()) {
168+
def files = versionDir.listFiles()?.findAll { it.isFile() } ?: []
169+
170+
def moduleKind = guessModuleKind(versionDir, files.find { it.name.endsWith(".pom") })
171+
172+
def packaging = '.' + packaging(versionDir)
173+
verifyArtifact(versionDir, files, packaging, moduleKind)
174+
verifyArtifact(versionDir, files, '-javadoc.jar', moduleKind)
175+
verifyArtifact(versionDir, files, '-sources.jar', moduleKind)
176+
177+
if (moduleKind != 'js' && moduleKind != 'jvm' && moduleKind != 'jvmWithJava' && moduleKind != 'metadata') {
178+
verifyArtifact(versionDir, files, '.module', moduleKind)
179+
}
180+
181+
verified ++
182+
}
183+
}
184+
185+
if (verified == 0) {
186+
throw new GradleException("No installed modules were found at $groupDir")
187+
}
188+
189+
moduleFiles.each { File file ->
190+
def moduleFile = new JsonSlurper().parse(file)
191+
192+
if (moduleFile.variants.name.isEmpty()) {
193+
throw new GradleException("No variants found in module file $file")
194+
}
195+
}
196+
}
197+
}
198+
199+
tasks.whenTaskAdded { task ->
200+
if (task.name.startsWith('publish') && task.name.endsWith('TestLocalRepository')) {
201+
tasks.getByName('verifyPublications').dependsOn(task)
202+
}
203+
}

0 commit comments

Comments
 (0)