2021-11-09 10:39:18 +01:00
|
|
|
def agent_root_folder = '/var/lib/jenkins/.m2'
|
2020-03-10 21:16:09 +01:00
|
|
|
def projects2artifacts = [:]
|
2020-03-11 03:36:20 +01:00
|
|
|
def artifacts2projects = [:]
|
2020-03-10 21:16:09 +01:00
|
|
|
def modules2deps = [:]
|
2020-03-12 18:52:59 +01:00
|
|
|
def alreadyInTheTree = []
|
2020-03-12 20:52:59 +01:00
|
|
|
def inputProject = params.jenkins_project.trim()
|
2020-03-11 05:21:44 +01:00
|
|
|
def report = [:]
|
2021-11-09 10:39:18 +01:00
|
|
|
|
2020-03-11 05:21:44 +01:00
|
|
|
report['project'] = inputProject
|
2020-03-10 18:40:40 +01:00
|
|
|
|
|
|
|
pipeline {
|
|
|
|
agent {
|
|
|
|
label 'CD'
|
|
|
|
}
|
2021-11-09 09:54:08 +01:00
|
|
|
|
|
|
|
environment {
|
|
|
|
AGENT_ROOT_FOLDER = "${agent_root_folder}"
|
|
|
|
PIPELINE_BUILD_NUMBER = "${env.BUILD_NUMBER}"
|
2021-11-09 10:39:18 +01:00
|
|
|
WALKER_NOTES = "${agent_root_folder}/walker_notes.${inputProject}.md"
|
2021-11-09 09:54:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-11 17:05:19 +01:00
|
|
|
parameters {
|
|
|
|
string(name: 'jenkins_project',
|
2020-03-12 16:13:24 +01:00
|
|
|
defaultValue: '',
|
|
|
|
description: 'The name of the Jenkins project to analyze.')
|
2020-03-11 17:05:19 +01:00
|
|
|
}
|
2020-03-10 18:40:40 +01:00
|
|
|
stages {
|
2020-03-11 17:11:38 +01:00
|
|
|
|
2020-03-10 18:40:40 +01:00
|
|
|
stage('walking projects') {
|
|
|
|
steps {
|
2020-03-12 16:13:24 +01:00
|
|
|
script {
|
2020-03-11 21:01:06 +01:00
|
|
|
Jenkins.get().getAllItems(TopLevelItem.class).each { p ->
|
2020-03-12 16:13:24 +01:00
|
|
|
projects2artifacts[p.name] = []
|
|
|
|
p.getAllJobs().each { j -> projects2artifacts[p.name] << j.name; artifacts2projects[j.name] = p.name }
|
2020-03-10 18:40:40 +01:00
|
|
|
}
|
|
|
|
println "FOUND ${projects2artifacts.size()} projects"
|
2020-03-12 15:33:09 +01:00
|
|
|
//projects2artifacts.each { k,v -> println ("PROJECT ${k} BUILDS ${v}") }
|
2020-03-12 16:13:24 +01:00
|
|
|
}
|
2020-03-10 18:40:40 +01:00
|
|
|
}
|
|
|
|
}
|
2020-03-11 17:11:38 +01:00
|
|
|
|
2020-03-10 18:40:40 +01:00
|
|
|
stage('walking maven modules') {
|
|
|
|
steps {
|
|
|
|
script {
|
|
|
|
// get all the maven modules and their dependencies
|
2020-03-11 21:01:06 +01:00
|
|
|
Jenkins.get().getAllItems(hudson.maven.MavenModule.class).each { m ->
|
2020-03-12 16:13:24 +01:00
|
|
|
modules2deps[m.name] = []
|
|
|
|
m.getDependencies().each { d -> modules2deps[m.name] << "${d.groupId}:${d.artifactId}" }
|
2020-03-10 18:40:40 +01:00
|
|
|
}
|
|
|
|
println "FOUND ${modules2deps.size()} modules"
|
2020-03-10 21:16:09 +01:00
|
|
|
//modules2deps.each { k,v -> println ("MODULE ${k} DEPENDS on ${v}") }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-11 17:11:38 +01:00
|
|
|
stage('analyze downstream projects') {
|
2020-03-12 16:13:24 +01:00
|
|
|
steps {
|
|
|
|
script {
|
|
|
|
// println "PROJECT ${inputProject} BUILDS ${projects2artifacts[inputProject]} artifacts"
|
|
|
|
// first, let's find out what components depend on the project's artifacts (i.e. downstream dependencies)
|
|
|
|
report['downstream_modules'] = [:]
|
|
|
|
report['downstream_projects'] = []
|
2020-03-12 20:52:59 +01:00
|
|
|
for ( level in 1..50 ) report['downstream_modules']["L${level}"] = [:] // can't initialize with withDefault closure in jenkins
|
2020-03-12 16:26:18 +01:00
|
|
|
projects2artifacts[inputProject].each { a ->
|
2020-03-12 16:27:45 +01:00
|
|
|
if (a.split(':').length > 1) { //skip the parent (only groupId)
|
2020-03-12 21:25:06 +01:00
|
|
|
report = analyzeDependency(modules2deps, alreadyInTheTree, artifacts2projects, report, a, 1)
|
2020-03-12 16:26:18 +01:00
|
|
|
}
|
2020-03-12 21:25:06 +01:00
|
|
|
}
|
2020-03-11 16:22:06 +01:00
|
|
|
}
|
2020-03-10 18:40:40 +01:00
|
|
|
}
|
2020-03-12 16:13:24 +01:00
|
|
|
}
|
2020-03-11 17:08:55 +01:00
|
|
|
|
2020-03-11 17:11:38 +01:00
|
|
|
stage('print report') {
|
|
|
|
steps {
|
|
|
|
script {
|
|
|
|
printReport(report)
|
2021-11-09 14:52:03 +01:00
|
|
|
// saveReport(report)
|
2020-03-11 17:11:38 +01:00
|
|
|
}
|
2020-03-11 17:08:55 +01:00
|
|
|
}
|
|
|
|
}
|
2020-03-12 16:13:24 +01:00
|
|
|
}
|
2021-11-09 09:54:08 +01:00
|
|
|
// post-build actions
|
|
|
|
post {
|
|
|
|
always {
|
|
|
|
script {
|
|
|
|
sh '''
|
|
|
|
cp $WALKER_NOTES ./walker_notes.${PIPELINE_BUILD_NUMBER}.md
|
2021-11-09 10:39:18 +01:00
|
|
|
cat ./walker_notes.${PIPELINE_BUILD_NUMBER}.md
|
2021-11-09 09:54:08 +01:00
|
|
|
'''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
success {
|
|
|
|
echo 'The dependencies walker pipeline worked!'
|
|
|
|
emailext to: 'jenkinsbuilds@d4science.org',
|
|
|
|
subject: "[Jenkins WalkerPipeline D4S] build ${currentBuild.fullDisplayName} worked",
|
|
|
|
body: "Build time: ${currentBuild.durationString}. See ${env.BUILD_URL}"
|
|
|
|
emailext attachmentsPattern: "**/walker_notes.${PIPELINE_BUILD_NUMBER}.md",
|
|
|
|
to: 'jenkinsreleases@d4science.org',
|
2021-11-09 12:27:58 +01:00
|
|
|
subject: "Dependency Report for gCube component ${inputProject} (build #${PIPELINE_BUILD_NUMBER})",
|
|
|
|
body: "Downstream dependencies of ${inputProject}. See ${env.BUILD_URL}"
|
2021-11-09 09:54:08 +01:00
|
|
|
}
|
|
|
|
failure {
|
|
|
|
echo 'The dependencies walker pipeline has failed'
|
|
|
|
emailext attachLog: true,
|
|
|
|
to: 'jenkinsbuilds@d4science.org',
|
2021-11-09 12:27:58 +01:00
|
|
|
subject: "[JenkinsDependenciesWalker D4S] build ${currentBuild.fullDisplayName} failed for component ${inputProject}",
|
2021-11-09 09:54:08 +01:00
|
|
|
body: "Something is wrong with ${env.BUILD_URL}"
|
|
|
|
}
|
|
|
|
}
|
2020-03-11 17:10:18 +01:00
|
|
|
|
2020-03-10 18:40:40 +01:00
|
|
|
}
|
2020-03-11 17:08:55 +01:00
|
|
|
// look for modules that use this artifact
|
2020-03-10 21:16:09 +01:00
|
|
|
def findDownstreamDependencies(modules2deps, artifact) {
|
|
|
|
def downdeps = []
|
2020-03-11 16:42:39 +01:00
|
|
|
//println "Looking for users of ${artifact}"
|
2020-03-12 16:13:24 +01:00
|
|
|
modules2deps.each { k, v -> if (v.contains("${artifact}")) downdeps << k }
|
2020-03-12 20:52:59 +01:00
|
|
|
return downdeps
|
2020-03-10 21:16:09 +01:00
|
|
|
}
|
|
|
|
|
2020-03-11 17:08:55 +01:00
|
|
|
//build the report of the given dependency, go recursive on its dependencies
|
2020-03-12 18:52:59 +01:00
|
|
|
def analyzeDependency(modules2deps, alreadyInTheTree, artifacts2projects, report, artifact, depth) {
|
2020-03-12 16:17:33 +01:00
|
|
|
def level = "L${depth}"
|
2020-03-12 18:52:59 +01:00
|
|
|
def downdeps = findDownstreamDependencies(modules2deps, artifact)
|
2020-03-12 18:57:17 +01:00
|
|
|
def skipTree = alreadyInTheTree.contains(artifact)
|
2020-03-12 18:52:59 +01:00
|
|
|
if (!skipTree) {
|
|
|
|
report['downstream_modules'][level][artifact] = ['dependencies': [], 'projects': []]
|
2020-03-11 16:51:14 +01:00
|
|
|
|
2020-03-12 18:52:59 +01:00
|
|
|
// get all downstream dependencies
|
|
|
|
report['downstream_modules'][level][artifact]['dependencies'].addAll(downdeps)
|
|
|
|
//println "${artifact} is used by ${report['downstream_modules'][level][artifact]['dependencies']}"
|
2020-03-11 16:22:06 +01:00
|
|
|
|
2020-03-12 18:52:59 +01:00
|
|
|
// add the project that builds the artifact
|
|
|
|
report['downstream_modules'][level][artifact]['projects'] << artifacts2projects[artifact]
|
|
|
|
report['downstream_projects'] << artifacts2projects[artifact]
|
|
|
|
alreadyInTheTree << artifact
|
|
|
|
}
|
2020-03-11 16:51:14 +01:00
|
|
|
|
|
|
|
// then we look for the projects that build the downstream dependencies and finally we go recursive
|
2020-03-12 20:52:59 +01:00
|
|
|
if (downdeps.size() > 0) {
|
2020-03-12 16:13:24 +01:00
|
|
|
def nextDepth = ++depth
|
2020-03-12 18:52:59 +01:00
|
|
|
downdeps.each { d ->
|
|
|
|
if (!skipTree) {
|
|
|
|
report['downstream_modules'][level][artifact]['projects'] << artifacts2projects[d]
|
|
|
|
report['downstream_projects'] << artifacts2projects[d]
|
|
|
|
}
|
2020-03-11 16:42:39 +01:00
|
|
|
// go recursive
|
2020-03-12 20:53:36 +01:00
|
|
|
analyzeDependency(modules2deps, alreadyInTheTree, artifacts2projects, report, d, nextDepth)
|
2020-03-11 16:42:39 +01:00
|
|
|
}
|
2020-03-11 16:22:06 +01:00
|
|
|
}
|
|
|
|
report
|
2020-03-10 21:16:09 +01:00
|
|
|
}
|
|
|
|
|
2020-03-11 17:08:55 +01:00
|
|
|
// print the final report
|
2020-03-11 05:21:44 +01:00
|
|
|
def printReport(report) {
|
2020-03-12 16:17:33 +01:00
|
|
|
def text = ''
|
|
|
|
def indent = '\t'
|
2020-03-12 20:56:01 +01:00
|
|
|
text += "Dependency Report for ${report['project']}"
|
2020-03-11 05:21:44 +01:00
|
|
|
text += "\n\n"
|
2020-03-12 15:29:12 +01:00
|
|
|
text += "|--Project Maven Modules\n"
|
2020-03-12 16:13:24 +01:00
|
|
|
report['downstream_modules'].each { depth, artifacts ->
|
|
|
|
artifacts.each { name, data ->
|
|
|
|
text += "${indent}|--Module: ${name}\n"
|
2020-03-12 20:56:01 +01:00
|
|
|
text += "${indent * 2}|--Deepest Dependency Level: ${depth}\n"
|
2020-03-12 16:13:24 +01:00
|
|
|
text += "${indent * 2}|--Used by (Maven Modules)\n"
|
|
|
|
data['dependencies'].each { d ->
|
|
|
|
text += "${indent * 3}|--${d}"
|
|
|
|
text += "\n"
|
2020-03-11 16:22:06 +01:00
|
|
|
}
|
2020-03-12 16:13:24 +01:00
|
|
|
text += "${indent * 2}|--Referred by (Jenkins Projects)\n"
|
|
|
|
data['projects'].each { p ->
|
|
|
|
text += "${indent * 3}|--${p}"
|
|
|
|
text += "\n"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-11 16:22:06 +01:00
|
|
|
|
2020-03-11 05:21:44 +01:00
|
|
|
text += "\n\n"
|
2020-03-11 19:16:39 +01:00
|
|
|
text += "|--All Downstream Projects\n"
|
2020-03-11 16:42:39 +01:00
|
|
|
report['downstream_projects'].unique().sort()
|
2020-03-11 05:21:44 +01:00
|
|
|
report['downstream_projects'].each { p ->
|
2020-03-12 16:13:24 +01:00
|
|
|
text += "${indent}|--${p}"
|
|
|
|
text += "\n"
|
2020-03-11 05:21:44 +01:00
|
|
|
}
|
|
|
|
println text
|
2021-11-09 14:58:53 +01:00
|
|
|
sh("""
|
|
|
|
printf "%s" $text > $WALKER_NOTES
|
|
|
|
""")
|
2021-11-09 10:39:18 +01:00
|
|
|
|
2020-03-11 05:21:44 +01:00
|
|
|
}
|
2021-11-09 09:54:08 +01:00
|
|
|
|
2021-11-09 12:27:58 +01:00
|
|
|
// print the final report
|
|
|
|
def saveReport(report) {
|
|
|
|
def text = ''
|
|
|
|
def indent = '\t'
|
|
|
|
sh("""
|
|
|
|
echo "Dependency Report for ${report['project']}" > $WALKER_NOTES
|
|
|
|
echo "\n\n" >> $WALKER_NOTES
|
|
|
|
echo "|--Project Maven Modules " >> $WALKER_NOTES
|
|
|
|
""")
|
|
|
|
report['downstream_modules'].each { depth, artifacts ->
|
|
|
|
artifacts.each { name, data ->
|
|
|
|
sh("""
|
|
|
|
echo "${indent}|--Module: ${name}\n" >> $WALKER_NOTES
|
|
|
|
echo "${indent * 2}|--Deepest Dependency Level: ${depth}\n" >> $WALKER_NOTES
|
|
|
|
echo "${indent * 2}|--Used by (Maven Modules)\n" >> $WALKER_NOTES
|
|
|
|
""")
|
|
|
|
data['dependencies'].each { d ->
|
|
|
|
sh("""
|
|
|
|
echo "${indent * 3}|--${d}" >> $WALKER_NOTES
|
|
|
|
echo "\n" >> $WALKER_NOTES
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
sh("""
|
|
|
|
echo "${indent * 2}|--Referred by (Jenkins Projects)\n" >> $WALKER_NOTES
|
|
|
|
""")
|
|
|
|
data['projects'].each { p ->
|
|
|
|
sh("""
|
|
|
|
echo "${indent * 3}|--${p}" >> $WALKER_NOTES
|
|
|
|
echo "\n" >> $WALKER_NOTES
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sh("""
|
|
|
|
echo "\n\n" >> $WALKER_NOTES
|
|
|
|
echo "|--All Downstream Projects\n" >> $WALKER_NOTES
|
|
|
|
""")
|
|
|
|
report['downstream_projects'].unique().sort()
|
|
|
|
report['downstream_projects'].each { p ->
|
|
|
|
sh("""
|
|
|
|
echo "${indent}|--${p}" >> $WALKER_NOTES
|
|
|
|
echo "\n" >> $WALKER_NOTES
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
|
2021-11-09 09:54:08 +01:00
|
|
|
}
|
|
|
|
|
2021-11-09 12:27:58 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2020-03-11 17:08:55 +01:00
|
|
|
// debug job
|
2020-03-10 18:40:40 +01:00
|
|
|
def printJob(job) {
|
2020-03-12 16:13:24 +01:00
|
|
|
println("fullname ${job.fullName}")
|
|
|
|
println("name ${job.name}")
|
|
|
|
println("display name ${job.displayName}")
|
|
|
|
job.getAllJobs().each { j -> println("dep: ${j.name}") }
|
2020-03-11 16:22:06 +01:00
|
|
|
}
|