1
0

lint 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Define the maximum time, in hours, that a test run should run for
  2. def global_timeout = 3
  3. def salt_target_branch = '2019.2'
  4. properties([
  5. buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '10')),
  6. ])
  7. def shell_header
  8. node('lint') {
  9. timeout(time: global_timeout, unit: 'HOURS') {
  10. ansiColor('xterm') {
  11. timestamps {
  12. try {
  13. // Set the GH status even before cloning the repo
  14. if (env.NODE_NAME.startsWith('jenkins-pr-')) {
  15. stage('github-pending') {
  16. githubNotify credentialsId: 'test-jenkins-credentials',
  17. description: 'Python lint begins...',
  18. status: 'PENDING',
  19. context: "jenkins/pr/lint"
  20. }
  21. shell_header = 'export PYENV_ROOT="/usr/local/pyenv"\nexport PATH="$PYENV_ROOT/bin:$PATH"'
  22. } else {
  23. shell_header = ''
  24. }
  25. withEnv(["SALT_TARGET_BRANCH=${salt_target_branch}"]) {
  26. // Checkout the repo
  27. stage('checkout-scm') {
  28. cleanWs notFailBuild: true
  29. checkout scm
  30. sh 'git fetch --no-tags https://github.com/saltstack/salt.git +refs/heads/${SALT_TARGET_BRANCH}:refs/remotes/origin/${SALT_TARGET_BRANCH}'
  31. }
  32. // Setup the kitchen required bundle
  33. stage('Setup') {
  34. sh shell_header + '''
  35. # Need -M to detect renames otherwise they are reported as Delete and Add, need -C to detect copies, -C includes -M
  36. # -M is on by default in git 2.9+
  37. git diff --name-status -l99999 -C "origin/${SALT_TARGET_BRANCH}" > file-list-status.log
  38. # the -l increase the search limit, lets use awk so we do not need to repeat the search above.
  39. gawk 'BEGIN {FS="\\t"} {if ($1 != "D") {print $NF}}' file-list-status.log > file-list-changed.log
  40. gawk 'BEGIN {FS="\\t"} {if ($1 == "D") {print $NF}}' file-list-status.log > file-list-deleted.log
  41. (git diff --name-status -l99999 -C "origin/${SALT_TARGET_BRANCH}" "origin/$BRANCH_NAME";echo "---";git diff --name-status -l99999 -C "origin/$BRANCH_NAME";printenv|grep -E '=[0-9a-z]{40,}+$|COMMIT=|BRANCH') > file-list-experiment.log
  42. eval "$(pyenv init -)"
  43. pyenv --version
  44. pyenv install --skip-existing 2.7.15
  45. pyenv shell 2.7.15
  46. python --version
  47. pip install tox
  48. tox --version
  49. '''
  50. }
  51. archiveArtifacts artifacts: 'file-list-status.log,file-list-changed.log,file-list-deleted.log,file-list-experiment.log'
  52. }
  53. stage('Lint Changes') {
  54. try {
  55. parallel(
  56. lintSalt: {
  57. stage('Lint Salt Changes') {
  58. if (readFile('file-list-changed.log') =~ /(?i)(^|\n)(salt\/.*\.py|setup\.py)\n/) {
  59. sh shell_header + '''
  60. eval "$(pyenv init - --no-rehash)"
  61. pyenv shell 2.7.15
  62. # tee makes the exit/return code always 0
  63. grep -Ei '^salt/.*\\.py$|^setup\\.py$' file-list-changed.log | (xargs -r '--delimiter=\\n' tox -e pylint-salt ; echo "$?" > pylint-salt-chg.exit) | tee pylint-report-salt-chg.log
  64. # remove color escape coding
  65. sed -ri 's/\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' pylint-report-salt-chg.log
  66. read rc_exit < pylint-salt-chg.exit
  67. exit "$rc_exit"
  68. '''
  69. }
  70. }
  71. },
  72. lintTests: {
  73. stage('Lint Test Changes') {
  74. if (readFile('file-list-changed.log') =~ /(?i)(^|\n)tests\/.*\.py\n/) {
  75. sh shell_header + '''
  76. eval "$(pyenv init - --no-rehash)"
  77. pyenv shell 2.7.15
  78. # tee makes the exit/return code always 0
  79. grep -Ei '^tests/.*\\.py$' file-list-changed.log | (xargs -r '--delimiter=\\n' tox -e pylint-tests ; echo "$?" > pylint-tests-chg.exit) | tee pylint-report-tests-chg.log
  80. # remove color escape coding
  81. sed -ri 's/\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' pylint-report-tests-chg.log
  82. read rc_exit < pylint-tests-chg.exit
  83. exit "$rc_exit"
  84. '''
  85. }
  86. }
  87. }
  88. )
  89. } finally {
  90. def changed_logs_pattern = 'pylint-report-*-chg.log'
  91. archiveArtifacts artifacts: changed_logs_pattern, allowEmptyArchive: true
  92. if (env.NODE_NAME.startsWith('jenkins-pr-')) {
  93. step([$class: 'WarningsPublisher',
  94. parserConfigurations: [[
  95. parserName: 'PyLint',
  96. pattern: changed_logs_pattern
  97. ]],
  98. failedTotalAll: '0',
  99. useDeltaValues: false,
  100. canRunOnFailed: true,
  101. usePreviousBuildAsReference: true
  102. ])
  103. } else {
  104. recordIssues(enabledForFailure: true, tool: pyLint(pattern: changed_logs_pattern, reportEncoding: 'UTF-8'))
  105. }
  106. }
  107. }
  108. stage('Lint Full') {
  109. if (env.CHANGE_BRANCH =~ /(?i)^merge[._-]/) {
  110. // perform a full linit if this is a merge forward and the change only lint passed.
  111. try {
  112. if (env.NODE_NAME.startsWith('jenkins-pr-')) {
  113. githubNotify credentialsId: 'test-jenkins-credentials',
  114. description: 'Python lint on everything begins...',
  115. status: 'PENDING',
  116. context: "jenkins/pr/lint"
  117. }
  118. parallel(
  119. lintSaltFull: {
  120. stage('Lint Salt Full') {
  121. sh shell_header + '''
  122. eval "$(pyenv init - --no-rehash)"
  123. pyenv shell 2.7.15
  124. # tee makes the exit/return code always 0
  125. (tox -e pylint-salt ; echo "$?" > pylint-salt-full.exit) | tee pylint-report-salt-full.log
  126. # remove color escape coding
  127. sed -ri 's/\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' pylint-report-salt-full.log
  128. read rc_exit < pylint-salt-full.exit
  129. '''
  130. }
  131. },
  132. lintTestsFull: {
  133. stage('Lint Tests Full') {
  134. sh shell_header + '''
  135. eval "$(pyenv init - --no-rehash)"
  136. pyenv shell 2.7.15
  137. # tee makes the exit/return code always 0
  138. (tox -e pylint-tests ; echo "$?" > pylint-tests-full.exit) | tee pylint-report-tests-full.log
  139. # remove color escape coding
  140. sed -ri 's/\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' pylint-report-tests-full.log
  141. read rc_exit < pylint-tests-full.exit
  142. exit "$rc_exit"
  143. '''
  144. }
  145. }
  146. )
  147. } finally {
  148. def full_logs_pattern = 'pylint-report-*-full.log'
  149. archiveArtifacts artifacts: full_logs_pattern, allowEmptyArchive: true
  150. if (env.NODE_NAME.startsWith('jenkins-pr-')) {
  151. step([$class: 'WarningsPublisher',
  152. parserConfigurations: [[
  153. parserName: 'PyLint',
  154. pattern: full_logs_pattern
  155. ]],
  156. failedTotalAll: '0',
  157. useDeltaValues: false,
  158. canRunOnFailed: true,
  159. usePreviousBuildAsReference: true
  160. ])
  161. } else {
  162. recordIssues(enabledForFailure: true, tool: pyLint(pattern: full_logs_pattern, reportEncoding: 'UTF-8'))
  163. }
  164. }
  165. }
  166. }
  167. } catch (Exception e) {
  168. currentBuild.result = 'FAILURE'
  169. } finally {
  170. cleanWs notFailBuild: true
  171. if (currentBuild.resultIsBetterOrEqualTo('SUCCESS')) {
  172. if (env.NODE_NAME.startsWith('jenkins-pr-')) {
  173. githubNotify credentialsId: 'test-jenkins-credentials',
  174. description: 'The lint test passed',
  175. status: 'SUCCESS',
  176. context: "jenkins/pr/lint"
  177. }
  178. } else {
  179. if (env.NODE_NAME.startsWith('jenkins-pr-')) {
  180. githubNotify credentialsId: 'test-jenkins-credentials',
  181. description: 'The lint test failed',
  182. status: 'FAILURE',
  183. context: "jenkins/pr/lint"
  184. }
  185. try {
  186. slackSend channel: "#jenkins-prod-pr",
  187. color: '#FF0000',
  188. message: "FAILED: PR-Job: '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
  189. } catch (Exception e) {
  190. sh 'echo Failed to send the Slack notification'
  191. }
  192. }
  193. }
  194. }
  195. }
  196. }
  197. }
  198. // vim: ft=groovy