Skip to content

Commit

Permalink
Rewrite Jenkins job validation
Browse files Browse the repository at this point in the history
The new script can read multiple files at once and uses a session. This
also improves its performance.
  • Loading branch information
ekohl committed Aug 2, 2019
1 parent f072e84 commit 488a974
Showing 1 changed file with 73 additions and 38 deletions.
111 changes: 73 additions & 38 deletions jenkins-lint.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,83 @@
import lxml.etree
import requests

JENKINS='https://ci.theforeman.org'
JENKINS = 'https://ci.theforeman.org'

parser = argparse.ArgumentParser(description='lint a Jenkinsfile using a remote Jenkins instance')
parser.add_argument('jenkinsfile', help='the file to lint')
parser.add_argument('--jenkins', help='Jenkins URL (default: %(default)s)', default=JENKINS)
parser.add_argument('--xml', action='store_true', help='treat the Jenkinsfile as an XML job definition')

args = parser.parse_args()
def get_crumb(session, jenkins):
url = '{}/crumbIssuer/api/json'.format(jenkins)

JENKINS_VALIDATE='{}/pipeline-model-converter/validateJenkinsfile'.format(args.jenkins)
JENKINS_CRUMB_ISSUER='{}/crumbIssuer/api/json'.format(args.jenkins)
jenkins_crumb_request = session.get(url)
jenkins_crumb_request.raise_for_status()

if args.xml:
jenkins_job = lxml.etree.parse(args.jenkinsfile)
jenkins_pipeline = jenkins_job.xpath("/flow-definition/definition/script/text()")[0]
else:
with open(args.jenkinsfile) as jenkinsfile:
jenkins_pipeline = jenkinsfile.read()


jenkins_crumb_request = requests.get(JENKINS_CRUMB_ISSUER)
if jenkins_crumb_request.status_code == requests.codes.ok:
jenkins_crumb_json = jenkins_crumb_request.json()
jenkins_crumb_field = jenkins_crumb_json['crumbRequestField']
jenkins_crumb = jenkins_crumb_json['crumb']
headers = {jenkins_crumb_field: jenkins_crumb}
else:
headers = {}


payload = {
'jenkinsfile': jenkins_pipeline
}
validation_result = requests.post(JENKINS_VALIDATE, headers=headers, data=payload)
validation_result.raise_for_status()

validation_result_json = validation_result.json()

if not (validation_result_json['status'] == 'ok' and validation_result_json['data']['result'] == 'success'):
for err in validation_result_json['data']['errors']:
print(err)
print("{}: NOT OK".format(args.jenkinsfile))
sys.exit(1)
else:
print("{}: OK".format(args.jenkinsfile))
session.headers[jenkins_crumb_field] = jenkins_crumb


def parse_xml(paths):
for path in sorted(paths):
jenkins_job = lxml.etree.parse(path)
content = jenkins_job.xpath("/flow-definition/definition/script/text()")
if content:
yield path, content[0]
else:
print("{}: No groovy content".format(path))


def parse_jenkinsfile(paths):
for path in sorted(paths):
with open(path) as jenkinsfile:
yield path, jenkinsfile.read()


def validate(session, jenkins, files):
url = '{}/pipeline-model-converter/validateJenkinsfile'.format(jenkins)

for path, content in files:
payload = {
'jenkinsfile': content,
}
validation_result = session.post(url, data=payload)
validation_result.raise_for_status()

validation_result_json = validation_result.json()

if not (validation_result_json['status'] == 'ok' and validation_result_json['data']['result'] == 'success'):
for err in validation_result_json['data']['errors']:
print(err)
print("{}: NOT OK".format(path))
yield path, validation_result_json['data']['errors']
else:
print("{}: OK".format(path))


def main():
parser = argparse.ArgumentParser(description='lint a Jenkinsfile using a remote Jenkins instance')
parser.add_argument('jenkinsfile', help='the file to lint', nargs='+')
parser.add_argument('--jenkins', help='Jenkins URL (default: %(default)s)', default=JENKINS)
parser.add_argument('--xml', action='store_true', help='treat the Jenkinsfile as an XML job definition')

args = parser.parse_args()

if args.xml:
files = list(parse_xml(args.jenkinsfile))
else:
files = list(parse_jenkinsfile(args.jenkinsfile))

session = requests.Session()
get_crumb(session, args.jenkins)
failures = list(validate(session, args.jenkins, files))

if failures:
print('Failed to validate files:', file=sys.stderr)
for path, errors in failures:
for error in errors:
print(error, file=sys.stderr)
print("{}: NOT OK".format(path), file=sys.stderr)
sys.exit(1)


if __name__ == '__main__':
main()

0 comments on commit 488a974

Please sign in to comment.