-
Notifications
You must be signed in to change notification settings - Fork 2
/
_Jenkinsfile-check.sh
executable file
·140 lines (121 loc) · 5.05 KB
/
_Jenkinsfile-check.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/bin/bash
set -o pipefail
# A simple command-line parser that calls Jenkins REST API to validate syntax
# of a Jenkinsfile - helps get it "right" in the first approximation without
# hundreds of commits to try to build and run it. Or to update it when the
# (currently unreleased) Pipeline API syntax changes yet again ;)
#
# Run it from the workspace with the tested Jenkinsfile in current directory.
# Save sensitive config in ./.jenkinsfile-check or ~/.jenkinsfile-check
#
# Note that there are also other ways to achieve this or similar goal; this
# one is just the simple tool I use as long as it suffices ;)
# See also https://github.com/jenkinsci/pipeline-model-definition-plugin/wiki/Validating-(or-linting)-a-Declarative-Jenkinsfile-from-the-command-line
#
# Copyright (C) 2016-2019 by Jim Klimov
# Components for the URL below; override via ./.jenkinsfile-check in the repo
# (DO NOT git commit this file though!) or in ~/.jenkinsfile-check if you only
# have one (preferred) Jenkins to test against anyway.
JENKINS_USER="username"
JENKINS_PASS="my%2Fpass"
JENKINS_HOST="localhost"
JENKINS_PORT="8080"
JENKINS_ROOT="jenkins"
# Default pipeline script filename is Jenkinsfile, but some repos can host
# multiple pipeline scripts so they would be named differently
[ -z "$JENKINSFILE" ] && JENKINSFILE="Jenkinsfile" \
&& echo "NOTE: Using default JENKINSFILE='$JENKINSFILE' - if you want to test another, pass the envvar from caller"
# A copy of https://github.com/jimklimov/JSON.sh/blob/master/JSON.sh
# is used for normalize_errors() aka "-j" argument
# Note this has some needed differences from the upstream version!
JSONSH=JSON.sh
{ [ -x "`dirname $0`/JSON.sh" ] && JSONSH="`dirname $0`/JSON.sh"; } || \
{ [ -x "./JSON.sh" ] && JSONSH="./JSON.sh"; } || \
{ (which JSON.sh 2>/dev/null >/dev/null) && JSONSH="`which JSON.sh`" ; }
[ -f "${HOME}/.jenkinsfile-check" ] && source "${HOME}/.jenkinsfile-check"
[ -f .jenkinsfile-check ] && source .jenkinsfile-check
[ -z "$JENKINS_BASEURL" ] && \
JENKINS_BASEURL="http://$JENKINS_USER:$JENKINS_PASS@$JENKINS_HOST:$JENKINS_PORT/$JENKINS_ROOT"
[ -n "${JENKINSFILE-}" ] && [ -s "${JENKINSFILE}" ] || { echo "FATAL : Did not find a JENKINSFILE='$JENKINSFILE'" >&2 ; exit 1 ; }
[ -n "${JSONSH-}" ] && [ -s "${JSONSH}" ] && [ -x "${JSONSH}" ] || { echo "FATAL : Did not find a JSONSH='$JSONSH' (did you get one from https://github.com/jimklimov/JSON.sh/blob/master/JSON.sh ?)" >&2 ; exit 1 ; }
CURL_VERBOSE="-s"
[ x"${DEBUG-}" = xyes ] && CURL_VERBOSE="-v"
do_request() {
CRUMB="`curl -k $CURL_VERBOSE "$JENKINS_BASEURL/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)"`" || CRUMB=""
echo "$CRUMB" | grep -w 404 >/dev/null && CRUMB=""
[ -n "$CRUMB" ] || echo "NOTE : Did not get a crumb, so will not use one"
curl -k $CURL_VERBOSE ${CRUMB:+H "$CRUMB"} \
-X POST --form "jenkinsfile=<${JENKINSFILE}" \
"$JENKINS_BASEURL/pipeline-model-converter/validateJenkinsfile"
}
default_request() {
do_request ; REQ_RES=$?
printf "\n\n($REQ_RES)\n"
return $REQ_RES
}
normalize_errors() {
OUT="`do_request 2>/dev/null`" ; REQ_RES=$?
if [ "$REQ_RES" != 0 ]; then
echo "REQUEST to REST API has failed ($REQ_RES)! Dump of data follows:"
echo "====="
echo "$OUT"
echo "====="
return $REQ_RES
fi >&2
JSON_OUT="`echo "$OUT" | "$JSONSH" -x '"data","errors",0,"error",[0-9]+'`"
if [ $? != 0 ]; then
echo "FAILED to parse REST API output as JSON markup! Dump of data follows:"
echo "====="
echo "$OUT"
echo "====="
return 2
fi >&2
[ -n "$JSON_OUT" ] && echo "$JSON_OUT" | grep '"data","errors",0,"error",'
if [ $? = 0 ]; then
# got a hit
return 1
else
# grepped no errors, try another pattern
JSON_OUT="`echo "$OUT" | "$JSONSH" -x '"data","errors",0,"error"'`"
if [ $? != 0 ]; then
echo "FAILED to parse REST API output as JSON markup! Dump of data follows:"
echo "====="
echo "$OUT"
echo "====="
return 2
fi >&2
[ -n "$JSON_OUT" ] && echo "$JSON_OUT" | grep '"data","errors",0,"error"'
if [ $? = 0 ]; then
# got a hit
return 1
fi
fi
echo "SUCCESS: No errors reported against this pipeline script!" >&2
# got no hits
return 0
}
bump_git() {
OUT="`default_request`"
if echo "$OUT" | grep '"data":{"result":"success"}}' ; then
git add "${JENKINSFILE}" \
&& git commit -m "Bump ${JENKINSFILE} pipeline script" \
&& echo "COMMITTED OK, you can 'git push' any time now"
else
echo "$OUT"
echo "VALIDATION FAILED" >&2
return 1
fi
}
usage() {
cat << EOF
-j pipe listing of errors through JSON.sh (detect error reports)
-b if the report says syntax is OK, git-commit the bumped Jenkinsfile
anything else for raw output of the REST API - no interpretation of content
EOF
}
case "$1" in
-h) usage ;;
-j) normalize_errors ;;
-b) bump_git ;;
*) default_request ;;
esac