netci.groovy 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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', // 'latest-or-auto' -> Windows Server 2008 R2 ~= Windows 7
  18. 'Windows_NT': 'Windows 8.1', // 'latest-or-auto' -> Windows Server 2012 R2 ~= Windows 8.1 aka Blue
  19. 'windows.10.amd64.clientrs4.devex.open': 'Windows 10', // = Windows 10 RS4 with Dev 15.7
  20. 'Ubuntu16.04': 'Ubuntu',
  21. 'OSX.1011.Amd64.Chakra.Open': 'OSX'
  22. ]
  23. def defaultMachineTag = 'latest-or-auto'
  24. def legacyWindows7Machine = 'Windows 7'
  25. def legacyWindows7MachineTag = defaultMachineTag
  26. def legacyWindows8Machine = 'Windows_NT'
  27. def legacyWindows8MachineTag = defaultMachineTag
  28. def latestWindowsMachine = 'windows.10.amd64.clientrs4.devex.open' // Windows 10 RS4 with Dev 15.7
  29. def latestWindowsMachineTag = null // all information is included in the machine name above
  30. def dailyRegex = 'dailies'
  31. // ---------------
  32. // HELPER CLOSURES
  33. // ---------------
  34. def CreateBuildTask = { isPR, buildArch, buildType, machine, machineTag, configTag, buildExtra, testExtra, runCodeAnalysis, excludeConfigIf, nonDefaultTaskSetup ->
  35. if (excludeConfigIf && excludeConfigIf(isPR, buildArch, buildType)) {
  36. return // early exit: we don't want to create a job for this configuration
  37. }
  38. def config = "${buildArch}_${buildType}"
  39. config = (configTag == null) ? config : "${configTag}_${config}"
  40. // params: Project, BaseTaskName, IsPullRequest (appends '_prtest')
  41. def jobName = Utilities.getFullJobName(project, config, isPR)
  42. def testableConfig = buildType in ['debug', 'test'] && buildArch != 'arm'
  43. def analysisConfig = buildType in ['release'] && runCodeAnalysis
  44. def buildScript = "call .\\jenkins\\buildone.cmd ${buildArch} ${buildType} "
  45. buildScript += buildExtra ?: ''
  46. buildScript += analysisConfig ? ' "/p:runcodeanalysis=true"' : ''
  47. def testScript = "call .\\jenkins\\testone.cmd ${buildArch} ${buildType} "
  48. testScript += testExtra ?: ''
  49. def analysisScript = '.\\Build\\scripts\\check_prefast_error.ps1 . CodeAnalysis.err'
  50. def newJob = job(jobName) {
  51. // This opens the set of build steps that will be run.
  52. // This looks strange, but it is actually a method call, with a
  53. // closure as a param, since Groovy allows method calls without parens.
  54. // (Compare with '.each' method used above.)
  55. steps {
  56. batchFile(buildScript) // run the parameter as if it were a batch file
  57. if (testableConfig) {
  58. batchFile(testScript)
  59. }
  60. if (analysisConfig) {
  61. powerShell(analysisScript)
  62. }
  63. }
  64. }
  65. def msbuildType = msbuildTypeMap.get(buildType)
  66. def msbuildFlavor = "build_${buildArch}${msbuildType}"
  67. def archivalString = "test/${msbuildFlavor}.*,test/logs/**"
  68. archivalString += analysisConfig ? ',CodeAnalysis.err' : ''
  69. Utilities.addArchival(newJob, archivalString,
  70. '', // no exclusions from archival
  71. false, // doNotFailIfNothingArchived=false ~= failIfNothingArchived
  72. false) // archiveOnlyIfSuccessful=false ~= archiveAlways
  73. if (machineTag == null) {
  74. // note: this is a different overload and not equivalent to calling setMachineAffinity(_,_,null)
  75. Utilities.setMachineAffinity(newJob, machine)
  76. } else {
  77. Utilities.setMachineAffinity(newJob, machine, machineTag)
  78. }
  79. Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
  80. if (nonDefaultTaskSetup == null) {
  81. if (isPR) {
  82. def osTag = machineTypeToOSTagMap.get(machine)
  83. Utilities.addGithubPRTriggerForBranch(newJob, branch, "${osTag} ${config}")
  84. } else {
  85. Utilities.addGithubPushTrigger(newJob)
  86. }
  87. } else {
  88. // nonDefaultTaskSetup is e.g. DailyBuildTaskSetup (which sets up daily builds)
  89. // These jobs will only be configured for the branch specified below,
  90. // which is the name of the branch netci.groovy was processed for.
  91. // See list of such branches at:
  92. // https://github.com/dotnet/dotnet-ci/blob/master/jobs/data/repolist.txt
  93. nonDefaultTaskSetup(newJob, isPR, config)
  94. }
  95. }
  96. def CreateBuildTasks = { machine, machineTag, configTag, buildExtra, testExtra, runCodeAnalysis, excludeConfigIf, nonDefaultTaskSetup ->
  97. [true, false].each { isPR ->
  98. ['x86', 'x64', 'arm'].each { buildArch ->
  99. ['debug', 'test', 'release'].each { buildType ->
  100. CreateBuildTask(isPR, buildArch, buildType, machine, machineTag, configTag, buildExtra, testExtra, runCodeAnalysis, excludeConfigIf, nonDefaultTaskSetup)
  101. }
  102. }
  103. }
  104. }
  105. def CreateXPlatBuildTask = { isPR, buildType, staticBuild, machine, platform, configTag,
  106. xplatBranch, nonDefaultTaskSetup, customOption, testVariant, extraBuildParams ->
  107. def config = (platform == "osx" ? "osx_${buildType}" : "linux_${buildType}")
  108. def numConcurrentCommand = (platform == "osx" ? "sysctl -n hw.logicalcpu" : "nproc")
  109. config = (configTag == null) ? config : "${configTag}_${config}"
  110. config = staticBuild ? "static_${config}" : "shared_${config}"
  111. config = customOption ? customOption.replaceAll(/[-]+/, "_") + "_" + config : config
  112. // params: Project, BaseTaskName, IsPullRequest (appends '_prtest')
  113. def jobName = Utilities.getFullJobName(project, config, isPR)
  114. def infoScript = "bash jenkins/get_system_info.sh --${platform}"
  115. def buildFlag = buildType == "release" ? "" : (buildType == "debug" ? "--debug" : "--test-build")
  116. def staticFlag = staticBuild ? "--static" : ""
  117. def swbCheckFlag = (platform == "linux" && buildType == "debug" && !staticBuild) ? "--wb-check" : "";
  118. def icuFlag = (platform == "osx" ? "--icu=/Users/DDITLABS/homebrew/opt/icu4c/include" : "")
  119. def compilerPaths = (platform == "osx") ? "" : "--cxx=/usr/bin/clang++-3.9 --cc=/usr/bin/clang-3.9"
  120. def buildScript = "bash ./build.sh ${staticFlag} -j=`${numConcurrentCommand}` ${buildFlag} " +
  121. "${swbCheckFlag} ${compilerPaths} ${icuFlag} ${customOption} ${extraBuildParams}"
  122. def icuLibFlag = (platform == "osx" ? "--iculib=/Users/DDITLABS/homebrew/opt/icu4c" : "")
  123. def testScript = "bash test/runtests.sh ${icuLibFlag} \"${testVariant}\""
  124. def newJob = job(jobName) {
  125. steps {
  126. shell(infoScript)
  127. shell(buildScript)
  128. shell(testScript)
  129. }
  130. }
  131. def archivalString = "out/build.log"
  132. Utilities.addArchival(newJob, archivalString,
  133. '', // no exclusions from archival
  134. true, // doNotFailIfNothingArchived=false ~= failIfNothingArchived (true ~= doNotFail)
  135. false) // archiveOnlyIfSuccessful=false ~= archiveAlways
  136. if (platform == "osx") {
  137. Utilities.setMachineAffinity(newJob, machine) // OSX machine string contains all info already
  138. } else {
  139. Utilities.setMachineAffinity(newJob, machine, defaultMachineTag)
  140. }
  141. Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
  142. if (nonDefaultTaskSetup == null) {
  143. if (isPR) {
  144. def osTag = machineTypeToOSTagMap.get(machine)
  145. Utilities.addGithubPRTriggerForBranch(newJob, xplatBranch, "${osTag} ${config}")
  146. } else {
  147. Utilities.addGithubPushTrigger(newJob)
  148. }
  149. } else {
  150. // nonDefaultTaskSetup is e.g. DailyBuildTaskSetup (which sets up daily builds)
  151. // These jobs will only be configured for the branch specified below,
  152. // which is the name of the branch netci.groovy was processed for.
  153. // See list of such branches at:
  154. // https://github.com/dotnet/dotnet-ci/blob/master/jobs/data/repolist.txt
  155. nonDefaultTaskSetup(newJob, isPR, config)
  156. }
  157. }
  158. // Generic task to trigger clang-based cross-plat build tasks
  159. def CreateXPlatBuildTasks = { machine, platform, configTag, xplatBranch, nonDefaultTaskSetup, extraBuildParams ->
  160. [true, false].each { isPR ->
  161. CreateXPlatBuildTask(isPR, "test", "", machine, platform,
  162. configTag, xplatBranch, nonDefaultTaskSetup, "--no-jit", "--variants disable_jit", extraBuildParams)
  163. ['debug', 'test', 'release'].each { buildType ->
  164. def staticBuildConfigs = [true, false]
  165. if (platform == "osx") {
  166. staticBuildConfigs = [true]
  167. }
  168. staticBuildConfigs.each { staticBuild ->
  169. CreateXPlatBuildTask(isPR, buildType, staticBuild, machine, platform,
  170. configTag, xplatBranch, nonDefaultTaskSetup, "", "", extraBuildParams)
  171. }
  172. }
  173. }
  174. }
  175. def DailyBuildTaskSetup = { newJob, isPR, triggerName, groupRegex ->
  176. // The addition of triggers makes the job non-default in GitHub.
  177. if (isPR) {
  178. def triggerRegex = "(${dailyRegex}|${groupRegex}|${triggerName})"
  179. Utilities.addGithubPRTriggerForBranch(newJob, branch,
  180. triggerName, // GitHub task name
  181. "(?i).*test\\W+${triggerRegex}.*")
  182. } else {
  183. Utilities.addPeriodicTrigger(newJob, '@daily')
  184. }
  185. }
  186. def CreateStyleCheckTasks = { taskString, taskName, checkName ->
  187. [true, false].each { isPR ->
  188. def jobName = Utilities.getFullJobName(project, taskName, isPR)
  189. def newJob = job(jobName) {
  190. steps {
  191. shell(taskString)
  192. }
  193. }
  194. Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
  195. if (isPR) {
  196. // Set PR trigger.
  197. Utilities.addGithubPRTriggerForBranch(newJob, branch, checkName)
  198. } else {
  199. // Set a push trigger
  200. Utilities.addGithubPushTrigger(newJob)
  201. }
  202. Utilities.setMachineAffinity(newJob, 'Ubuntu16.04', defaultMachineTag)
  203. }
  204. }
  205. // ----------------
  206. // INNER LOOP TASKS
  207. // ----------------
  208. // The latest machine seems to have a configuration problem preventing us from building ARM.
  209. // For now, build ARM on the LKG config, Legacy Windows 8.1 (Blue) config.
  210. // TODO When the Windows 10 configuration is updated to fix ARM builds, unify this config split.
  211. CreateBuildTasks(latestWindowsMachine, latestWindowsMachineTag, null, null, "-win10", true,
  212. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch == 'arm') }, null) // configures everything except ARM
  213. CreateBuildTasks(legacyWindows8Machine, legacyWindows8MachineTag, null, null, "-winBlue", true,
  214. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch != 'arm') }, null) // configures ARM
  215. // Add some additional daily configs to trigger per-PR as a quality gate:
  216. // x64_debug Slow Tests
  217. CreateBuildTask(true, 'x64', 'debug',
  218. latestWindowsMachine, latestWindowsMachineTag, 'ci_slow', null, '-win10 -includeSlow', false, null, null)
  219. // x64_debug DisableJIT
  220. CreateBuildTask(true, 'x64', 'debug',
  221. latestWindowsMachine, latestWindowsMachineTag, 'ci_disablejit', '"/p:BuildJIT=false"', '-win10 -disablejit', false, null, null)
  222. // x64_debug Lite
  223. CreateBuildTask(true, 'x64', 'debug',
  224. latestWindowsMachine, latestWindowsMachineTag, 'ci_lite', '"/p:BuildLite=true"', '-win10 -lite', false, null, null)
  225. // x64_debug Legacy (Windows 7)
  226. CreateBuildTask(true, 'x64', 'debug',
  227. legacyWindows7Machine, legacyWindows7MachineTag, 'ci_legacy7', 'msbuild14', '-win7 -includeSlow', false, null, null)
  228. // x64_debug Legacy (Windows 8.1 (Blue))
  229. CreateBuildTask(true, 'x64', 'debug',
  230. legacyWindows8Machine, legacyWindows8MachineTag, 'ci_legacy8', 'msbuild14', '-winBlue -includeSlow', false, null, null)
  231. // -----------------
  232. // DAILY BUILD TASKS
  233. // -----------------
  234. if (!branch.endsWith('-ci')) {
  235. // build and test on the legacy configuration (Windows 7 + VS 2015 (Dev14))
  236. CreateBuildTasks(legacyWindows7Machine, legacyWindows7MachineTag, 'daily_legacy7', 'msbuild14', '-win7 -includeSlow', false,
  237. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch == 'arm') }, // excludes ARM
  238. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  239. DailyBuildTaskSetup(newJob, isPR,
  240. "Windows 7 ${config}",
  241. 'legacy7?\\s+tests)')})
  242. // build and test on the legacy configuration (Windows 8.1 (Blue) + VS 2015 (Dev14))
  243. CreateBuildTasks(legacyWindows8Machine, legacyWindows8MachineTag, 'daily_legacy8', 'msbuild14', '-winBlue -includeSlow', false,
  244. /* excludeConfigIf */ null, // ARM builds previously worked on this configuration, so don't exclude them unless we explicitly drop support
  245. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  246. DailyBuildTaskSetup(newJob, isPR,
  247. "Windows 8 ${config}",
  248. 'legacy8?\\s+tests')})
  249. // build and test on the latest configuration (RS4 + VS 2017 Dev 15.7) with -includeSlow
  250. // TODO When the Windows 10 configuration is updated to fix ARM builds, unify this config split.
  251. CreateBuildTasks(latestWindowsMachine, latestWindowsMachineTag, 'daily_slow', null, '-win10 -includeSlow', false,
  252. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch == 'arm') }, // configures everything except ARM
  253. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  254. DailyBuildTaskSetup(newJob, isPR,
  255. "Windows ${config}",
  256. 'slow\\s+tests')})
  257. CreateBuildTasks(legacyWindows8Machine, legacyWindows8MachineTag, 'daily_slow', null, '-winBlue -includeSlow', false,
  258. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch != 'arm') }, // configures ARM
  259. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  260. DailyBuildTaskSetup(newJob, isPR,
  261. "Windows ${config}",
  262. 'slow\\s+tests')})
  263. // build and test on the latest configuration (RS4 + VS 2017 Dev 15.7) with JIT disabled
  264. // TODO When the Windows 10 configuration is updated to fix ARM builds, unify this config split.
  265. CreateBuildTasks(latestWindowsMachine, latestWindowsMachineTag, 'daily_disablejit', '"/p:BuildJIT=false"', '-win10 -disablejit', true,
  266. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch == 'arm') }, // configures everything except ARM
  267. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  268. DailyBuildTaskSetup(newJob, isPR,
  269. "Windows ${config}",
  270. '(disablejit|nojit)\\s+tests')})
  271. CreateBuildTasks(legacyWindows8Machine, legacyWindows8MachineTag, 'daily_disablejit', '"/p:BuildJIT=false"', '-winBlue -disablejit', true,
  272. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch != 'arm') }, // configures ARM
  273. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  274. DailyBuildTaskSetup(newJob, isPR,
  275. "Windows ${config}",
  276. '(disablejit|nojit)\\s+tests')})
  277. // build and test on the latest configuration (RS4 + VS 2017 Dev 15.7) with Lite build
  278. // TODO When the Windows 10 configuration is updated to fix ARM builds, unify this config split.
  279. CreateBuildTasks(latestWindowsMachine, latestWindowsMachineTag, 'daily_lite', '"/p:BuildLite=true"', '-win10 -lite', true,
  280. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch == 'arm') }, // configures everything except ARM
  281. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  282. DailyBuildTaskSetup(newJob, isPR,
  283. "Windows ${config}",
  284. 'lite\\s+tests')})
  285. CreateBuildTasks(legacyWindows8Machine, legacyWindows8MachineTag, 'daily_lite', '"/p:BuildLite=true"', '-winBlue -lite', true,
  286. /* excludeConfigIf */ { isPR, buildArch, buildType -> (buildArch != 'arm') }, // configures ARM
  287. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  288. DailyBuildTaskSetup(newJob, isPR,
  289. "Windows ${config}",
  290. 'lite\\s+tests')})
  291. }
  292. // ----------------
  293. // CODE STYLE TASKS
  294. // ----------------
  295. CreateStyleCheckTasks('./jenkins/check_copyright.sh', 'ubuntu_check_copyright', 'Copyright Check')
  296. CreateStyleCheckTasks('./jenkins/check_eol.sh', 'ubuntu_check_eol', 'EOL Check')
  297. CreateStyleCheckTasks('./jenkins/check_tabs.sh', 'ubuntu_check_tabs', 'Tab Check')
  298. // --------------
  299. // XPLAT BRANCHES
  300. // --------------
  301. // Explicitly enumerate xplat-incompatible branches, because we don't anticipate any future incompatible branches
  302. def isXPlatCompatibleBranch = !(branch in ['release/1.1', 'release/1.1-ci', 'release/1.2', 'release/1.2-ci'])
  303. // Include these explicitly-named branches
  304. def isXPlatDailyBranch = branch in ['master', 'linux', 'xplat']
  305. // Include some release/* branches (ignore branches ending in '-ci')
  306. if (branch.startsWith('release') && !branch.endsWith('-ci')) {
  307. // Allows all current and future release/* branches on which we should run daily builds of XPlat configs.
  308. // RegEx matches branch names we should ignore (e.g. release/1.1, release/1.2, release/1.2-pre)
  309. includeReleaseBranch = !(branch =~ /^release\/(1\.[12](\D.*)?)$/)
  310. isXPlatDailyBranch |= includeReleaseBranch
  311. }
  312. // -----------------
  313. // LINUX BUILD TASKS
  314. // -----------------
  315. if (isXPlatCompatibleBranch) {
  316. def osString = 'Ubuntu16.04'
  317. // PR and CI checks
  318. CreateXPlatBuildTasks(osString, "linux", "ubuntu", branch, null, "")
  319. // Create a PR/continuous task to check ubuntu/static/debug/no-icu
  320. [true, false].each { isPR ->
  321. CreateXPlatBuildTask(isPR, "debug", true, osString, "linux",
  322. "ubuntu", branch, null, "--no-icu", "--not-tag exclude_noicu", "")
  323. }
  324. // daily builds
  325. if (isXPlatDailyBranch) {
  326. CreateXPlatBuildTasks(osString, "linux", "daily_ubuntu", branch,
  327. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  328. DailyBuildTaskSetup(newJob, isPR,
  329. "Ubuntu ${config}",
  330. 'linux\\s+tests')},
  331. /* extraBuildParams */ "--extra-defines=PERFMAP_TRACE_ENABLED=1")
  332. }
  333. }
  334. // ---------------
  335. // OSX BUILD TASKS
  336. // ---------------
  337. if (isXPlatCompatibleBranch) {
  338. def osString = 'OSX.1011.Amd64.Chakra.Open'
  339. // PR and CI checks
  340. CreateXPlatBuildTasks(osString, "osx", "osx", branch, null, "")
  341. // daily builds
  342. if (isXPlatDailyBranch) {
  343. CreateXPlatBuildTasks(osString, "osx", "daily_osx", branch,
  344. /* nonDefaultTaskSetup */ { newJob, isPR, config ->
  345. DailyBuildTaskSetup(newJob, isPR,
  346. "OSX ${config}",
  347. 'linux\\s+tests')},
  348. /* extraBuildParams */ "")
  349. }
  350. }
  351. // ------------
  352. // HELP MESSAGE
  353. // ------------
  354. Utilities.createHelperJob(this, project, branch,
  355. "Welcome to the ${project} Repository", // This is prepended to the help message
  356. "For additional documentation on ChakraCore CI checks, please see:\n" +
  357. "\n" +
  358. "* https://github.com/Microsoft/ChakraCore/wiki/Jenkins-CI-Checks\n" +
  359. "* https://github.com/Microsoft/ChakraCore/wiki/Jenkins-Build-Triggers\n" +
  360. "* https://github.com/Microsoft/ChakraCore/wiki/Jenkins-Repro-Steps\n" +
  361. "\n" +
  362. "Have a nice day!") // This is appended to the help message. You might put known issues here.