Verify Artifactory download in Jenkins pipeline - jenkins

I'm using the Jfrog Artifactory plugin in my Jenkins pipeline to pull some in-house utilities that the pipelines use. I specify which version of the utility I want using a parameter.
After executing the server.download, I'd like to verify and report which version of the file was actually downloaded, but I can't seem to find any way at all to do that. I do get a buildInfo object returned from the server.download call, but I can find any way to pull information from that object. I just get an object reference if I try to print the buildInfo object. I'd like to abort the build and send a report out if the version of the utility downloaded is incorrect.
The question I have is, "How does one verify that a file specified by a download spec is successfully downloaded?"

This functionality is only available on scripted pipeline at the moment, and is described in the documentation.
For example:
node {
def server = Artifactory.server SERVER_ID
def downloadSpec = readFile 'downloadSpec.json'
def buildInfo = server.download spec: downloadSpec
if (buildInfo.getDependencies().size() > 0) {
def localPath = buildInfo.getDependencies()[0].getLocalPath()
def remotePath = buildInfo.getDependencies()[0].getRemotePath()
def md5 = buildInfo.getDependencies()[0].getMd5()
def sha1 = buildInfo.getDependencies()[0].getSha1()
echo localPath
}
server.publishBuildInfo buildInfo
}

Related

How to access file from node inside Jenkins shared library script

I am calling a shared library groovy script from my Jenkins pipeline.
Using the pwd() method I can properly get the workspace path and I can even see the required file in the exact same location in the Jenkins node.
Still I am getting following error:
java.io.FileNotFoundException: C:\Jenkins\workspace\Demo\test\target\site\xyz\abc.csv (No such file or directory)
I have the groovy-scripts/vars/generateHtml.groovy shared library which is being called from the pipeline as generateHtml(). The relevant code snippet:
def call() {
def ws = pwd()
echo "path ${ws}: generateHtml>start"
def targetPath = "${ws}\\target\\"
def resultFile = targetPath + 'site\\xyz\\abc.csv'
def data = parseCsv(new File(resultFile).getText('UTF-8'))
...
Reading a file in Jenkins Pipelines goes via readFile. Don't use plain groovy for I/O.

How to download the artifact md5 checksum from Jenkins pipeline artifactory plugin

When I download a gz file from artifactory in Jenkins pipeline, I would like to verify the md5 checksum to validate the download. While I can see the checksum in artifactory UI, I am not finding a way to download the same in Jenkins pipeline.
I am using the following piece of code to download and it downloads fine.
script {
def server = Artifactory.server '<myserver>'
def downloadSpec = """{
"files": [
{
"pattern": "<my artifact>.tar.gz",
"target": "tmp/"
}
]
}"""
server.download(downloadSpec)
}
When I upload the and the .md5 , the artifactory uses the md5 to just validate against its own checksum but does not store the md5 as a separate file.
I have perused the plugin documentation at https://www.jfrog.com/confluence/display/RTF/Jenkins+Artifactory+Plug-in and the REST API https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API and neither describes a way to donwload the checksum.
Appreciate any help
Use this in jenkins pipeline:
-> sh 'md5sum <filepath> | awk \'{print $1}\''
to create an MD5 hashcheck for your file.
Reference : cmd and shell script
Thanks
Change your server.download(downloadSpec) line to read:
buildInfo = server.download(downloadSpec)
for ( dep in buildInfo.getDependencies() ) {
md5 = dep.getMd5()
// ...
}

Get BuildInfo From Artifactory Using Jenkins

Using Jenkins DSL I can create and publish build info using Artifactory.newBuildInfo but am looking for the complementary method to read the BuildInfo JSON data that is generated on Artifactory. Have trolled through many resources. Any suggestions would be appreciated.
From Artifactory REST API it sure looks like you can retrieve buildInfo. I'd expect this must be exposed from the jenkins plugin as well.
Build Info
Description: Build Info
Since: 2.2.0
Security: Requires a privileged user with deploy permissions (can be anonymous)
Usage: GET /api/build/{buildName}/{buildNumber}
Produces: application/vnd.org.jfrog.build.BuildInfo+json
...
JFrog's project examples on github is a fabulous resource as is their jenkins plugin
From a quick search it looks like you'd define a download spec and then use server.download method (see Working with Pipeline Jobs in Jenkins
def buildInfo1 = server.download downloadSpec
The previous answer creates a new buildInfo, it does not download the original buildInfo into I've been trying for days to try to figure out how to do what the original poster wants to do. The best I've succeeded at is downloading the buildinfo into a hashtable, work with that, then upload the changes doing REST calls.
def curlstr = "curl -H 'X-JFrog-Art-Api:${password}' ${arturl}api/build/${buildName}/${buildNumber}"
def buildInfoString = sh(
script: curlstr,
returnStdout: true
).trim()
buildInfo = (new JsonSlurperClassic().parseText(buildInfoString))
sh("echo '${JsonOutput.toJson(buildInfo)}'|curl -XPUT -H 'X-JFrog-Art-Api:${password}' -H 'Content-Type: application/json' ${arturl}api/build --upload-file - ")
I was able to modify the buildInfo in the artifactory repository using this technique. Not as clean as I would like. I've been unable to get the jfrogCLI to modify existing buildInfo files either.
For whatever it's worth the intent of what I'm trying to do is promote a docker artifact and change the name while doing it. There is no way I've found to express this to artifactory not involving downloading the artifact to docker and then pushing it again. I'd love it if someone from #jfrog could clue me in how to do it.
UPDATE: Attention! I've got the question wrong. This is how you get the local BuildInfo-Object in a declarative pipeline script.
I managed this by using an internal api from jenkins-artifactory-plugin.
// found in org.jfrog.hudson.pipeline.declarative.utils.DeclarativePipelineUtils
/**
* Get build info as defined in previous rtBuildInfo{...} scope.
*
* #param rootWs - Step's root workspace.
* #param build - Step's build.
* #param customBuildName - Step's custom build name if exist.
* #param customBuildNumber - Step's custom build number if exist.
* #return build info object as defined in previous rtBuildInfo{...} scope or a new build info.
*/
public static BuildInfo getBuildInfo(FilePath rootWs, Run<?, ?> build, String customBuildName, String customBuildNumber, String project) throws IOException, InterruptedException {
...
}
Whith this code you can fetch the BuildInfo inside a declarative pipeline script step.
def buildInfo = org.jfrog.hudson.pipeline.declarative.utils.DeclarativePipelineUtils.getBuildInfo(new hudson.FilePath(new java.io.File(env.WORKSPACE)), currentBuild.rawBuild, null, null, null);
UPDATE: Beware of custom build names and numbers. I you have defined a custom build name and/or build number, you have to provide it with the getBuildInfo call.

Share Workspace with Jobs triggered From Workflow Script

I want to use the Workspace from my workflow Task in other tasks whom I trigger via the 'build' command.
I need to make this Flexible since I want to be able to trigger those jobs from various workflows with different Workspaces, this is why I cannot provide a hardcoded workspace Path.
Here is some Code:
node {
git branch: branchName, credentialsId: '1337', url: 'https://i-didnt-provide-this.but-this-is-working.git'
def buildType = 'xxx'
def buildFlavor = 'yyy'
def hockeyAppId = 'zzz'
def buildTypeParam = new hudson.model.StringParameterValue('buildType', buildType)
def buildFlavorParam = new hudson.model.StringParameterValue('buildFlavor', buildFlavor)
def hockeyAppIdParam = new hudson.model.StringParameterValue('hockeyAppId', hockeyAppId)
def outputApkFilenameParam = new hudson.model.StringParameterValue('fileName', '*-{buildFlavor}-{buildType}.apk')
def proguardMappingParam = new hudson.model.StringParameterValue('mappingFile', '{buildFlavor}/{buildType}/mapping.txt')
build job: 'android_compile', parameters: [buildTypeParam, buildFlavorParam] //This needs the same workspace
build job: 'android_lint', parameters: [buildTypeParam, buildFlavorParam] //same here
build job: 'android_upload_hockey', parameters: [hockeyAppIdParam, outputApkFilenameParam, proguardMappingParam] //and here
}
Thanks for Help in Advance
Rather than trying to share a workspace, which will not work, archive any files you need from downstream jobs. They can then access those files using the Copy Artifact plugin.
In this case, if you just want to check out the same Git revision in your downstream jobs, determine its commit hash and pass that to downstream builds as a parameter. JENKINS-26100 would save you from manually running git rev-parse HEAD or the like.

Jenkins plugin, how to execute system command on remote node?

Our company's Jenkins has master and two slave nodes. I am writing plugin for it. One of the things for plugin to do is to checkout some files from svn. This action cannot be extracted from plugin.
To do this I execute console command "svn checkout" from java code of my plugin. The problem is that files from svn are checked out to master, rather than to slave nodes.
How can I make files be checked out to slave?
First you have these objects, usually received as parameters for perform method:
Launcher launcher;
AbstractBuild<?, ?> build;
BuildListener listener;
Then you have created and added arguments to an argumentListBuilder, maybe something like:
ArgumentListBuilder command = new ArgumentListBuilder();
command.addTokenized("xcopy /?");
Then, do something like:
ProcStarter ps = launcher.new ProcStarter();
ps = ps.cmds(command).stdout(listener);
ps = ps.pwd(build.getWorkspace()).envs(build.getEnvironment(listener));
Proc proc = launcher.launch(ps);
int retcode = proc.join();
ProcStarter will run the command at the node specified by the launcher instance. But please at least glance over the javadocs of all above classes before using, above is not direct copy-paste from working code.
Here is code based on Hyde's answer, suitable for the Groovy script console (at /script)
def static Run(nodeName, runCommand)
{
def output = new java.io.ByteArrayOutputStream();
def listener = new hudson.util.StreamTaskListener(output);
def node = hudson.model.Hudson.instance.getNode(nodeName);
def launcher = node.createLauncher(listener);
def command = new hudson.util.ArgumentListBuilder();
command.addTokenized(runCommand);
def ps = launcher.launch();
ps = ps.cmds(command).stdout(listener);
// ps = ps.pwd(build.getWorkspace()).envs(build.getEnvironment(listener));
def proc = launcher.launch(ps);
int retcode = proc.join();
return [retcode, output.toString()]
}
// for (aSlave in hudson.model.Hudson.instance.slaves) {
(recode, output) = Run("build-slave9", "xcopy /?");
println output;
(Caveats: untested for programs that read stdin. Note the ByteArrayOutputStream, so don't run programs with very long output. Untested for non-ASCII output.)

Resources