blob: 731ab185fe71e21b90c9a6d19e1c50674d000999 [file] [log] [blame]
#!/usr/bin/python3
import os
import shutil
import signal
import string
import subprocess
import sys
import xml.etree.ElementTree
from distutils.spawn import find_executable
def findparentfiles(fname):
filelist = []
newlist = []
args = ['grep', '-rl', '--exclude-dir=.git', fname]
proc = subprocess.run(args, capture_output=True)
data = proc.stdout.decode()
if proc.returncode != 0:
return filelist
for filename in data.splitlines():
if filename.endswith('.yaml') and '/' not in filename:
filelist.append(filename)
else:
newlist = findparentfiles(filename)
for tempname in newlist:
filelist.append(tempname)
return filelist
jjb_cmd = find_executable('jenkins-jobs') or sys.exit('jenkins-jobs is not found.')
jjb_args = [jjb_cmd]
jjb_user = os.environ.get('JJB_USER')
jjb_password = os.environ.get('JJB_PASSWORD')
if jjb_user is not None and jjb_password is not None:
jenkins_jobs_ini = ('[job_builder]\n'
'ignore_cache=True\n'
'keep_descriptions=False\n'
'\n'
'[jenkins]\n'
'user=%s\n'
'password=%s\n'
'url=https://ci.trustedfirmware.org/\n' % (jjb_user, jjb_password))
with open('jenkins_jobs.ini', 'w') as f:
f.write(jenkins_jobs_ini)
jjb_args.append('--conf=jenkins_jobs.ini')
jjb_test_args = list(jjb_args)
jjb_delete_args = list(jjb_args)
# !!! "update" below and through out this file is replaced by "test" (using sed)
# !!! in the sanity-check job.
main_action = 'update'
jjb_args.extend([main_action, 'template.yaml'])
jjb_test_args.extend(['test', '-o', 'out/', 'template.yaml'])
jjb_delete_args.extend(['delete'])
if main_action == 'test':
# Dry-run, don't delete jobs.
jjb_delete_args.insert(0, 'echo')
try:
git_args = ['git', 'diff', '--raw',
os.environ.get('GIT_PREVIOUS_COMMIT'),
os.environ.get('GIT_COMMIT')]
proc = subprocess.run(git_args, capture_output=True)
except (OSError, ValueError) as e:
raise ValueError("%s" % e)
data = proc.stdout.decode()
if proc.returncode != 0:
raise ValueError("command has failed with code '%s'" % proc.returncode)
filelist = []
deletelist = []
files = []
for line in data.splitlines():
# Format of the git-diff; we only need OPERATION and FILE1
#
# :<OLD MODE> <NEW MODE> <OLD REF> <NEW REF> <OPERATION> <FILE1> <FILE2>
elems = line.split()
operation = elems[4][0]
filename = elems[5]
if filename.endswith('.yaml') and '/' not in filename:
# No point trying to test deleted jobs because they don't exist any
# more.
if operation == 'D':
deletelist.append(filename[:-5])
continue
# operation R100 is 100% rename, which means sixth element is the renamed file
if operation == 'R':
filename = elems[6]
# delete old job name
deletelist.append(elems[5][:-5])
filelist.append(filename)
else:
files = findparentfiles(filename)
for tempname in files:
filelist.append(tempname)
# Remove duplicate entries in the list
filelist = list(set(filelist))
for conf_filename in filelist:
with open(conf_filename) as f:
buffer = f.read()
template = string.Template(buffer)
buffer = template.safe_substitute(
AUTH_TOKEN=os.environ.get('AUTH_TOKEN'),
LT_QCOM_KEY=os.environ.get('LT_QCOM_KEY'),
LAVA_USER=os.environ.get('LAVA_USER'),
LAVA_TOKEN=os.environ.get('LAVA_TOKEN'))
with open('template.yaml', 'w') as f:
f.write(buffer)
try:
proc = subprocess.run(jjb_args, capture_output=True)
except (OSError, ValueError) as e:
raise ValueError("%s" % e)
data = proc.stdout.decode()
if proc.returncode != 0:
raise ValueError("command has failed with code '%s'" % proc.returncode)
try:
shutil.rmtree('out/', ignore_errors=True)
proc = subprocess.run(jjb_test_args, capture_output=True)
data = proc.stdout.decode()
if proc.returncode != 0:
raise ValueError("command has failed with code '%s'" % proc.returncode)
proc = subprocess.run(['ls', 'out/'], capture_output=True)
data = proc.stdout.decode()
if proc.returncode != 0:
raise ValueError("command has failed with code '%s'" % proc.returncode)
for filename in data.splitlines():
# old job conf might have been removed because the job is now generated through the template
# do not delete the job in this case
if filename in deletelist:
deletelist.remove(filename)
conf_name=os.path.splitext(conf_filename)[0]
conf_name=conf_name[:len(filename)]
if not filename.startswith(conf_name):
raise ValueError("Job name %s does not match the file it is in: %s" % (filename, conf_name))
try:
xmlroot = xml.etree.ElementTree.parse('out/' + filename).getroot()
disabled = next(xmlroot.iterfind('disabled')).text
if disabled != 'true':
continue
displayName = next(xmlroot.iterfind('displayName')).text
if displayName != 'DELETE ME':
continue
except:
continue
deletelist.append(filename)
except (OSError, ValueError) as e:
raise ValueError("%s" % e)
shutil.rmtree('out/', ignore_errors=True)
os.remove('template.yaml')
for deletejob in deletelist:
delete_args = list(jjb_delete_args)
delete_args.extend([deletejob])
try:
proc = subprocess.run(delete_args, capture_output=True)
data = proc.stdout.decode()
if proc.returncode != 0:
raise ValueError("command has failed with code '%s'" % proc.returncode)
print(data)
except (OSError, ValueError) as e:
raise ValueError("%s" % e)
if os.path.exists('jenkins_jobs.ini'):
os.remove('jenkins_jobs.ini')