netci.groovy 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // Import the utility functionality.
  6. import jobs.generation.Utilities
  7. // Grab the github project name passed in
  8. def project = GithubProject
  9. def branch = GithubBranchName
  10. def msbuildTypeMap = [
  11. 'debug':'chk',
  12. 'test':'test',
  13. 'release':'fre'
  14. ]
  15. // convert `machine` parameter to OS component of PR task name
  16. def machineTypeToOSTagMap = [
  17. 'Windows 7': 'Windows 7', // Windows Server 2008 R2, equivalent to Windows 7
  18. 'Windows_NT': 'Windows', // Windows Server 2012 R2, equivalent to Windows 8.1 (aka Blue)
  19. 'Ubuntu16.04': 'Ubuntu',
  20. 'OSX': 'OSX'
  21. ]
  22. def dailyRegex = 'dailies'
  23. // ---------------
  24. // HELPER CLOSURES
  25. // ---------------
  26. def CreateBuildTask = { isPR, buildArch, buildType, machine, configTag, buildExtra, testExtra, runCodeAnalysis, excludeConfigIf, nonDefaultTaskSetup ->
  27. if (excludeConfigIf && excludeConfigIf(isPR, buildArch, buildType)) {
  28. return // early exit: we don't want to create a job for this configuration
  29. }
  30. def config = "${buildArch}_${buildType}"
  31. config = (configTag == null) ? config : "${configTag}_${config}"
  32. // params: Project, BaseTaskName, IsPullRequest (appends '_prtest')
  33. def jobName = Utilities.getFullJobName(project, config, isPR)
  34. def testableConfig = buildType in ['debug', 'test'] && buildArch != 'arm'
  35. def analysisConfig = buildType in ['release'] && runCodeAnalysis
  36. def buildScript = "call .\\jenkins\\buildone.cmd ${buildArch} ${buildType} "
  37. buildScript += buildExtra ?: ''
  38. buildScript += analysisConfig ? ' "/p:runcodeanalysis=true"' : ''
  39. def testScript = "call .\\jenkins\\testone.cmd ${buildArch} ${buildType} "
  40. testScript += testExtra ?: ''
  41. def analysisScript = '.\\Build\\scripts\\check_prefast_error.ps1 . CodeAnalysis.err'
  42. def newJob = job(jobName) {
  43. // This opens the set of build steps that will be run.
  44. // This looks strange, but it is actually a method call, with a
  45. // closure as a param, since Groovy allows method calls without parens.
  46. // (Compare with '.each' method used above.)
  47. steps {
  48. batchFile(buildScript) // run the parameter as if it were a batch file
  49. if (testableConfig) {
  50. batchFile(testScript)
  51. }
  52. if (analysisConfig) {
  53. powerShell(analysisScript)
  54. }
  55. }
  56. }
  57. def msbuildType = msbuildTypeMap.get(buildType)
  58. def msbuildFlavor = "build_${buildArch}${msbuildType}"
  59. def archivalString = "test/${msbuildFlavor}.*,test/logs/**"
  60. archivalString += analysisConfig ? ',CodeAnalysis.err' : ''
  61. Utilities.addArchival(newJob, archivalString,
  62. '', // no exclusions from archival
  63. false, // doNotFailIfNothingArchived=false ~= failIfNothingArchived
  64. false) // archiveOnlyIfSuccessful=false ~= archiveAlways
  65. Utilities.setMachineAffinity(newJob, machine, 'latest-or-auto')
  66. Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
  67. if (nonDefaultTaskSetup == null) {
  68. if (isPR) {
  69. def osTag = machineTypeToOSTagMap.get(machine)
  70. Utilities.addGithubPRTriggerForBranch(newJob, branch, "${osTag} ${config}")
  71. } else {
  72. Utilities.addGithubPushTrigger(newJob)
  73. }
  74. } else {
  75. // nonDefaultTaskSetup is e.g. DailyBuildTaskSetup (which sets up daily builds)
  76. // These jobs will only be configured for the branch specified below,
  77. // which is the name of the branch netci.groovy was processed for.
  78. // See list of such branches at:
  79. // https://github.com/dotnet/dotnet-ci/blob/master/jobs/data/repolist.txt
  80. nonDefaultTaskSetup(newJob, isPR, config)
  81. }
  82. }
  83. def CreateBuildTasks = { machine, configTag, buildExtra, testExtra, runCodeAnalysis, excludeConfigIf, nonDefaultTaskSetup ->
  84. [true, false].each { isPR ->
  85. ['x86', 'x64', 'arm'].each { buildArch ->
  86. ['debug', 'test', 'release'].each { buildType ->
  87. CreateBuildTask(isPR, buildArch, buildType, machine, configTag, buildExtra, testExtra, runCodeAnalysis, excludeConfigIf, nonDefaultTaskSetup)
  88. }
  89. }
  90. }
  91. }
  92. def CreateXPlatBuildTask = { isPR, buildType, staticBuild, machine, platform, configTag,
  93. xplatBranch, nonDefaultTaskSetup, customOption, testVariant ->
  94. def config = (platform == "osx" ? "osx_${buildType}" : "linux_${buildType}")
  95. def numConcurrentCommand = (platform == "osx" ? "sysctl -n hw.logicalcpu" : "nproc")
  96. config = (configTag == null) ? config : "${configTag}_${config}"
  97. config = staticBuild ? "static_${config}" : "shared_${config}"
  98. config = customOption ? customOption.replaceAll(/[-]+/, "_") + "_" + config : config
  99. // params: Project, BaseTaskName, IsPullRequest (appends '_prtest')
  100. def jobName = Utilities.getFullJobName(project, config, isPR)
  101. def infoScript = "bash jenkins/get_system_info.sh --${platform}"
  102. def buildFlag = buildType == "release" ? "" : (buildType == "debug" ? "--debug" : "--test-build")
  103. def staticFlag = staticBuild ? "--static" : ""
  104. def swbCheckFlag = (platform == "linux" && buildType == "debug" && !staticBuild) ? "--wb-check" : "";
  105. def icuFlag = (platform == "osx" ? "--icu=/usr/local/opt/icu4c/include" : "")
  106. def compilerPaths = (platform == "osx") ? "" : "--cxx=/usr/bin/clang++-3.9 --cc=/usr/bin/clang-3.9"
  107. def buildScript = "bash ./build.sh ${staticFlag} -j=`${numConcurrentCommand}` ${buildFlag} " +
  108. "${swbCheckFlag} ${compilerPaths} ${icuFlag} ${customOption}"
  109. def testScript = "bash test/runtests.sh \"${testVariant}\""
  110. def newJob = job(jobName) {
  111. steps {
  112. shell(infoScript)
  113. shell(buildScript)
  114. shell(testScript)
  115. }
  116. }
  117. def archivalString = "out/build.log"
  118. Utilities.addArchival(newJob, archivalString,
  119. '', // no exclusions from archival
  120. true, // doNotFailIfNothingArchived=false ~= failIfNothingArchived (true ~= doNotFail)
  121. false) // archiveOnlyIfSuccessful=false ~= archiveAlways
  122. Utilities.setMachineAffinity(newJob, machine, 'latest-or-auto')
  123. Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
  124. if (nonDefaultTaskSetup == null) {
  125. if (isPR) {
  126. def osTag = machineTypeToOSTagMap.get(machine)
  127. Utilities.addGithubPRTriggerForBranch(newJob, xplatBranch, "${osTag} ${config}")
  128. } else {
  129. Utilities.addGithubPushTrigger(newJob)
  130. }
  131. } else {
  132. // nonDefaultTaskSetup is e.g. DailyBuildTaskSetup (which sets up daily builds)
  133. // These jobs will only be configured for the branch specified below,
  134. // which is the name of the branch netci.groovy was processed for.
  135. // See list of such branches at:
  136. // https://github.com/dotnet/dotnet-ci/blob/master/jobs/data/repolist.txt
  137. nonDefaultTaskSetup(newJob, isPR, config)
  138. }
  139. }
  140. // Generic task to trigger clang-based cross-plat build tasks
  141. def CreateXPlatBuildTasks = { machine, platform, configTag, xplatBranch, nonDefaultTaskSetup ->
  142. [true, false].each { isPR ->
  143. CreateXPlatBuildTask(isPR, "test", "", machine, platform,
  144. configTag, xplatBranch, nonDefaultTaskSetup, "--no-jit", "--variants disable_jit")
  145. ['debug', 'test', 'release'].each { buildType ->
  146. def staticBuildConfigs = [true, false]
  147. if (platform == "osx") {
  148. staticBuildConfigs = [true]
  149. }
  150. staticBuildConfigs.each { staticBuild ->
  151. CreateXPlatBuildTask(isPR, buildType, staticBuild, machine, platform,
  152. configTag, xplatBranch, nonDefaultTaskSetup, "", "")
  153. }
  154. }
  155. }
  156. }
  157. def DailyBuildTaskSetup = { newJob, isPR, triggerName, groupRegex ->
  158. // The addition of triggers makes the job non-default in GitHub.
  159. if (isPR) {
  160. def triggerRegex = "(${dailyRegex}|${groupRegex}|${triggerName})"
  161. Utilities.addGithubPRTriggerForBranch(newJob, branch,
  162. triggerName, // GitHub task name
  163. "(?i).*test\\W+${triggerRegex}.*")
  164. } else {
  165. Utilities.addPeriodicTrigger(newJob, '@daily')
  166. }
  167. }
  168. def CreateStyleCheckTasks = { taskString, taskName, checkName ->
  169. [true, false].each { isPR ->
  170. def jobName = Utilities.getFullJobName(project, taskName, isPR)
  171. def newJob = job(jobName) {
  172. steps {
  173. shell(taskString)
  174. }
  175. }
  176. Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
  177. if (isPR) {
  178. // Set PR trigger.
  179. Utilities.addGithubPRTriggerForBranch(newJob, branch, checkName)
  180. } else {
  181. // Set a push trigger
  182. Utilities.addGithubPushTrigger(newJob)
  183. }
  184. Utilities.setMachineAffinity(newJob, 'Ubuntu16.04', 'latest-or-auto')
  185. }
  186. }
  187. // ----------------
  188. // INNER LOOP TASKS
  189. // ----------------
  190. CreateBuildTasks('Windows_NT', null, null, "-winBlue", true, null, null)
  191. // Add some additional daily configs to trigger per-PR as a quality gate:
  192. // x64_debug Slow Tests
  193. CreateBuildTask(true, 'x64', 'debug',
  194. 'Windows_NT', 'ci_slow', null, '-winBlue -includeSlow', false, null, null)
  195. // x64_debug DisableJIT
  196. CreateBuildTask(true, 'x64', 'debug',
  197. 'Windows_NT', 'ci_disablejit', '"/p:BuildJIT=false"', '-winBlue -disablejit', false, null, null)
  198. // x64_debug Legacy
  199. CreateBuildTask(true, 'x64', 'debug',
  200. 'Windows 7', 'ci_dev12', 'msbuild12', '-win7 -includeSlow', false, null, null)
  201. // -----------------
  202. // DAILY BUILD TASKS
  203. // -----------------
  204. if (!branch.endsWith('-ci')) {
  205. // build and test on Windows 7 with VS 2013 (Dev12/MsBuild12)
  206. CreateBuildTasks('Windows 7', 'daily_dev12', 'msbuild12', '-win7 -includeSlow', false,
  207. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch == 'arm') },
  208. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  209. DailyBuildTaskSetup(newJob, isPR,
  210. "Windows 7 ${config}",
  211. '(dev12|legacy)\\s+tests')})
  212. // build and test on the usual configuration (VS 2015) with -includeSlow
  213. CreateBuildTasks('Windows_NT', 'daily_slow', null, '-winBlue -includeSlow', false,
  214. /* excludeConfigIf */ null,
  215. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  216. DailyBuildTaskSetup(newJob, isPR,
  217. "Windows ${config}",
  218. 'slow\\s+tests')})
  219. // build and test on the usual configuration (VS 2015) with JIT disabled
  220. CreateBuildTasks('Windows_NT', 'daily_disablejit', '"/p:BuildJIT=false"', '-winBlue -disablejit', true,
  221. /* excludeConfigIf */ null,
  222. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  223. DailyBuildTaskSetup(newJob, isPR,
  224. "Windows ${config}",
  225. '(disablejit|nojit)\\s+tests')})
  226. }
  227. // ----------------
  228. // CODE STYLE TASKS
  229. // ----------------
  230. CreateStyleCheckTasks('./jenkins/check_copyright.sh', 'ubuntu_check_copyright', 'Copyright Check')
  231. CreateStyleCheckTasks('./jenkins/check_eol.sh', 'ubuntu_check_eol', 'EOL Check')
  232. CreateStyleCheckTasks('./jenkins/check_tabs.sh', 'ubuntu_check_tabs', 'Tab Check')
  233. // --------------
  234. // XPLAT BRANCHES
  235. // --------------
  236. // Explicitly enumerate xplat-incompatible branches, because we don't anticipate any future incompatible branches
  237. def isXPlatCompatibleBranch = !(branch in ['release/1.1', 'release/1.1-ci', 'release/1.2', 'release/1.2-ci'])
  238. // Include these explicitly-named branches
  239. def isXPlatDailyBranch = branch in ['master', 'linux', 'xplat']
  240. // Include some release/* branches (ignore branches ending in '-ci')
  241. if (branch.startsWith('release') && !branch.endsWith('-ci')) {
  242. // Allows all current and future release/* branches on which we should run daily builds of XPlat configs.
  243. // RegEx matches branch names we should ignore (e.g. release/1.1, release/1.2, release/1.2-pre)
  244. includeReleaseBranch = !(branch =~ /^release\/(1\.[12](\D.*)?)$/)
  245. isXPlatDailyBranch |= includeReleaseBranch
  246. }
  247. // -----------------
  248. // LINUX BUILD TASKS
  249. // -----------------
  250. if (isXPlatCompatibleBranch) {
  251. def osString = 'Ubuntu16.04'
  252. // PR and CI checks
  253. CreateXPlatBuildTasks(osString, "linux", "ubuntu", branch, null)
  254. // daily builds
  255. if (isXPlatDailyBranch) {
  256. CreateXPlatBuildTasks(osString, "linux", "daily_ubuntu", branch,
  257. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  258. DailyBuildTaskSetup(newJob, isPR,
  259. "Ubuntu ${config}",
  260. 'linux\\s+tests')})
  261. }
  262. }
  263. // ---------------
  264. // OSX BUILD TASKS
  265. // ---------------
  266. if (isXPlatCompatibleBranch) {
  267. def osString = 'OSX'
  268. // PR and CI checks
  269. CreateXPlatBuildTasks(osString, "osx", "osx", branch, null)
  270. // daily builds
  271. if (isXPlatDailyBranch) {
  272. CreateXPlatBuildTasks(osString, "osx", "daily_osx", branch,
  273. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  274. DailyBuildTaskSetup(newJob, isPR,
  275. "OSX ${config}",
  276. 'linux\\s+tests')})
  277. }
  278. }
  279. // ------------
  280. // HELP MESSAGE
  281. // ------------
  282. Utilities.createHelperJob(this, project, branch,
  283. "Welcome to the ${project} Repository", // This is prepended to the help message
  284. "For additional documentation on ChakraCore CI checks, please see:\n" +
  285. "\n" +
  286. "* https://github.com/Microsoft/ChakraCore/wiki/Jenkins-CI-Checks\n" +
  287. "* https://github.com/Microsoft/ChakraCore/wiki/Jenkins-Build-Triggers\n" +
  288. "* https://github.com/Microsoft/ChakraCore/wiki/Jenkins-Repro-Steps\n" +
  289. "\n" +
  290. "Have a nice day!") // This is appended to the help message. You might put known issues here.