Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jmcgeheeiv/8a7431aa2483a5a4f420 to your computer and use it in GitHub Desktop.
Save jmcgeheeiv/8a7431aa2483a5a4f420 to your computer and use it in GitHub Desktop.
Download the latest successful build artifacts from Jenkins using Python 3
#!/usr/bin/env python3
# Download the latest successful build artifacts from Jenkins using Python 3
# John McGehee 1/25/2016
#
# Based on the Python 2 version by supertom: https://gist.github.com/supertom/2759847
import argparse
import codecs
import io
import json
import os
import sys
try:
import pycurl
isPyCurlAvailable = True
except ImportError:
import urllib.request
isPyCurlAvailable = False
parser = argparse.ArgumentParser(description="Download the latest successful build artifacts from Jenkins.")
parser.add_argument('jobs', metavar='jobName', nargs='+',
help="List of job names from which to fetch the latest artifact, "
"including folder name(s). For example: 'folderName1/folderName2/jobName'.")
args = parser.parse_args()
assert isinstance(args.jobs, list) and args.jobs, "A list of at least one job must be specified"
##########
# configuration
build_host = "jenkins.johnnado.com"
lastBuildAPIURL = "http://" + build_host + "/job/%s/lastSuccessfulBuild/api/json"
lastBuildArtifactLURL = "http://" + build_host + "/job/%s/lastSuccessfulBuild/artifact/%s"
localSaveDir = "."
# Default for .tgz artifacts; change if yours are different, for example .apk files.
artifactExtension=".internal.tgz"
##########
# UDFs
def downloadFile(url, filename):
print("==> Downloading File: ", filename, " URL: ", url)
if isPyCurlAvailable:
fp = open(filename, "wb")
curl = pycurl.Curl()
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.WRITEDATA, fp)
curl.perform()
curl.close()
fp.close()
else:
urllib.request.urlretrieve(url, filename)
###########
# start
print("Fetching files from Jenkins")
if not os.path.exists(localSaveDir):
print("==> Creating Dir %s" % (localSaveDir))
os.makedirs(localSaveDir)
for job in args.jobs:
job = job.strip('/')
job = job.replace('/', '/job/')
jobURL = lastBuildAPIURL % (job)
if isPyCurlAvailable:
buf = io.BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, jobURL)
c.setopt(c.WRITEFUNCTION, buf.write)
c.perform()
jsonbytes = buf.getvalue()
buf.close()
else:
with urllib.request.urlopen(jobURL) as response:
jsonbytes = response.read() # a `bytes` object
jsonstr = jsonbytes.decode('utf-8')
jd = json.loads(jsonstr)
artifacts = jd['artifacts']
for art in artifacts:
if art['fileName'].find(artifactExtension) > -1:
artURL = lastBuildArtifactLURL % (job,art['relativePath'])
downloadFile(str(artURL),localSaveDir + "/" + str(art['fileName']))
@junguchina
Copy link

junguchina commented May 13, 2016

Hi jmcgeheeiv,
when I use the function named downloadFile(url,filename), the code raised an error:

curl.perform()
pycurl.error: (18, 'transfer closed with 933650432 bytes remaining to read')

Do you have any ideas?

@jmcgeheeiv
Copy link
Author

@junguchina, I am sorry, I do not know the solution to your problem. If you found the solution on your own, could you share it with us?

@matu3ba
Copy link

matu3ba commented Oct 4, 2022

No external dependency is needed to handle downloads.
For example, curl -s http://localhost:8000/job/test-job-1/lastSuccessfulBuild/api/json --user <your-username>:<authentication-token> |jq is enough, but of course python has everything necessary to handle HTML Get and parse the json.

@parkerlreed
Copy link

For anyone blind like me wondering why nothing is working, don't forget to set the extension variable

Thank you! Working great

@jmcgeheeiv
Copy link
Author

@parkerlreed is this "extension variable" artifactExtension? What did you set it to?

@matu3ba
Copy link

matu3ba commented Oct 19, 2022

@jmcgeheeiv Your code does not handle necessary authentication to jenkins via generated token and I found the documentation on jenkins side insufficient for hints what underlying protocol is used.

With curl, this looks like subprocess.run(["curl", (artifacturl + arti_fname), "--output", arti_fname, "--user", authinfo], check=True).
I tried unsuccessful the python session API via html.

Any ideas from your side?

@parkerlreed
Copy link

@parkerlreed is this "extension variable" artifactExtension? What did you set it to?

It just needs to be whatever you are pulling. Mine was an apk so I had to change that for it to download.

@jmcgeheeiv
Copy link
Author

I added a comment documenting artifactExtension. Thanks @parkerlreed!

@parkerlreed
Copy link

I added a comment documenting artifactExtension. Thanks @parkerlreed!

Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment