diff --git a/ci/.jenkinsfile b/ci/.jenkinsfile index fa0147a9644b2288cebc6af8a51a5328fc7f7041..bc6b3ea4304fa873e01f63fa49f89e3e4595fac0 100644 --- a/ci/.jenkinsfile +++ b/ci/.jenkinsfile @@ -28,7 +28,7 @@ string xenConfig = """ name = 'helloworld' vcpus = '1' memory = '4' -kernel = 'build/run_xen-x86_64_xen-x86_64.dbg' +kernel = 'workdir/build/run_xen-x86_64_xen-x86_64.dbg' """ /* fc配置文件内容 */ @@ -70,9 +70,23 @@ int tolNum = 10 int exeNum = 0 int sucNum = 0 int failNum = 0 +def prdata1 = [] +def prdata2 = [] +def prDescription = env.giteePullRequestDescription if (env.giteeActionType == "NOTE" && env.giteeTriggerPhrase.contains("skip_check")) { tolNum-- } +/*定义字典,定义处理某仓库的pr时所需的对应路径*/ +def mapping1 = [ + "app-helloworld":"app-helloworld", + "plat-raspi":"app-helloworld/workdir/unikraft/plat/raspi", +] + +def mapping2 = [ + "app-helloworld":"app-helloworld", + "lib-libc-test":"workdir/libs/libc-test", + "lib-musl":"workdir/libs/musl" +] /* pipeline 定义了整个测试流程中的工作 */ pipeline { @@ -110,6 +124,39 @@ pipeline { } } } + stage('获取相关依赖PR信息') { + when { + not { + expression {env.giteeActionType == "NOTE" && (env.giteeTriggerPhrase[0..3] == "help")} + } + } + steps { + script{ + /*获取相关依赖pr信息,如无相关pr则不影响*/ + /*获取相关PR:该字段后的内容*/ + def pattern = /相关PR:([\s\S]*)/ + def matcher1 = (prDescription =~ pattern) + if(matcher1.find()){ + /*获取相关PR的链接*/ + pattern = /\[(.+)\]\((.+)\)/ + def matcher = (matcher1.group(1) =~ pattern) + def prNumberAndRepo = "" + def prinfo = "" + while(matcher.find()){ + /*分离链接中的信息*/ + prNumberAndRepo = matcher.group(2) =~ /\/([^\/]+)\/([^\/]+)\/pulls\/(\d+)$/ + if (prNumberAndRepo.find()) { + prinfo = [owner:prNumberAndRepo.group(1),reponame:prNumberAndRepo.group(2),prnumber:prNumberAndRepo.group(3)] + if(mapping1[prinfo.reponame]) prdata1.add(prinfo) + else if(mapping1[prinfo.reponame]) prdata2.add(prinfo) + }else { + error "PR 描述中不存在相关 PR 字段" + } + } + } + } + } + } stage('初始化公共代码仓') { when { not { @@ -121,29 +168,45 @@ pipeline { script { /* 调用shell脚本,执行check测试。使用NAME = sh()形式可以防止shell脚本出错直接退出stage */ result = sh(script: """ - #!/bin/bash - cd $WORKSPACE - git clone $gitAppHelloWorldURL - cd app-helloworld - # 获取以下两次commit的中defconfig文件 - git cherry-pick -n 06ee0b7 438ca02 - mkdir .unikraft .unikraft/unikraft - cd - - # 将unikraft拷贝至app-helloworld/.unikraft/unikraft中 - cp -r `ls |grep -v 'app-helloworld'|xargs` app-helloworld/.unikraft/unikraft - # 默认使用与unikraft相同的分支 - # TODO: 应该提供一个能够从外部传入的参数指定这个分支,两个库同步修改的情况下需要用到 - git clone -b $targetBranch $gitPlatRaspiUrl app-helloworld/.unikraft/unikraft/plat/raspi - # 为每个测试项建立独立目录 - mkdir ut_self-test ut_libc-test run_qemu-x86_64 run_qemu-arm64 run_xen-x86_64 run_fc-x86_64 run_linuxu-x86_64 run_linuxu-arm64 - cp -r app-helloworld/. ut_libc-test - cp -r app-helloworld/. run_qemu-x86_64 - cp -r app-helloworld/. run_qemu-arm64 - cp -r app-helloworld/. run_xen-x86_64 - cp -r app-helloworld/. run_fc-x86_64 - cp -r app-helloworld/. run_linuxu-x86_64 - cp -r app-helloworld/. run_linuxu-arm64 - """, returnStatus: true) + #!/bin/bash + cd $WORKSPACE + git clone $gitAppHelloWorldURL + cd app-helloworld + mkdir workdir workdir/unikraft + cd - + # 将unikraft拷贝至app-helloworld/workdir/unikraft中 + cp -r `ls |grep -v 'app-helloworld'|xargs` app-helloworld/workdir/unikraft + # 默认使用与unikraft相同的分支 + # TODO: 应该提供一个能够从外部传入的参数指定这个分支,两个库同步修改的情况下需要用到 + git clone -b $targetBranch $gitPlatRaspiUrl app-helloworld/workdir/unikraft/plat/raspi + """, returnStatus: true) + /*处理相关pr信息,如无也不影响*/ + if (!prdata1.isEmpty()) { + prdata1.each{ pr -> + result = sh(script: """ + #!/bin/bash + cd $WORKSPACE + cd ${mapping1[pr.reponame]} + git fetch https://gitee.com/${pr.owner}/${pr.reponame}.git pull/${pr.prnumber}/head:pr_${pr.prnumber} + git merge pr_${pr.prnumber} + """, returnStatus: true) + if (result != 0) { + ret = "初始化依赖PR失败,详见任务链接" + error '初始化依赖PR失败' + } + } + } + result = sh(script: """ + # 为每个测试项建立独立目录 + mkdir ut_self-test ut_libc-test run_qemu-x86_64 run_qemu-arm64 run_xen-x86_64 run_fc-x86_64 run_linuxu-x86_64 run_linuxu-arm64 + cp -r app-helloworld/. ut_libc-test + cp -r app-helloworld/. run_qemu-x86_64 + cp -r app-helloworld/. run_qemu-arm64 + cp -r app-helloworld/. run_xen-x86_64 + cp -r app-helloworld/. run_fc-x86_64 + cp -r app-helloworld/. run_linuxu-x86_64 + cp -r app-helloworld/. run_linuxu-arm64 + """, returnStatus: true) if (result != 0) { ret = "初始化代码仓失败,详见任务链接" error '初始化代码仓失败' @@ -161,10 +224,10 @@ pipeline { script { exeNum++ result = sh(script: ''' - #!/bin/sh - cd $WORKSPACE - ./ci/scripts/check_pr_title.sh "$giteePullRequestTitle" - ''', returnStatus: true) + #!/bin/sh + cd $WORKSPACE + ./ci/scripts/check_pr_title.sh "$giteePullRequestTitle" + ''', returnStatus: true) /* 结果分支处理,将信息添加至ret中 */ if (result == 0) { sucNum++ @@ -177,59 +240,83 @@ pipeline { } } } - /* check测试步骤,进行commit信息规范与patch增量代码规范检查 */ - /* unikraft社区commit描述推荐格式 [selector]/[component name]: [Your short message] - * exp: lib/uktest: selftest - * 社区检查脚本只检查是否含有":",原则上commit信息需要符合社区规定 - */ - stage('社区commit规范检查') { - /* when 块可以控制本stage执行条件,此处当PR评论内容不为test_skip_check时才执行 */ - when { - not { - expression {env.giteeActionType == "NOTE" && - ((env.giteeTriggerPhrase[0..3] == "help") || (env.giteeTriggerPhrase.contains("skip_check")))} - } - } - steps { - script { - exeNum++ - result = sh(script: ''' - #!/bin/sh - cd $WORKSPACE - git format-patch HEAD~1 - ./support/scripts/checkpatch.uk ./000* --no-signoff - ''', returnStatus: true) - if (result == 0) { - sucNum++ - ret = ret + "\n|社区commit信息与代码规范检查|成功||" - } else { - failNum++ - ret = ret + "\n|社区commit信息与代码规范检查|**失败**|具体规范要求见任务链接|" - error '社区commit信息与代码规范检查失败' - } - } - } - } - + /* check测试步骤,进行commit信息规范与patch增量代码规范检查 */ + /* unikraft社区commit描述推荐格式 [selector]/[component name]: [Your short message] + * exp: lib/uktest: selftest + * 社区检查脚本只检查是否含有":",原则上commit信息需要符合社区规定 + */ + stage('社区commit规范检查') { + /* when 块可以控制本stage执行条件,此处当PR评论内容不为test_skip_check时才执行 */ + when { + not { + expression {env.giteeActionType == "NOTE" && + ((env.giteeTriggerPhrase[0..3] == "help") || (env.giteeTriggerPhrase.contains("skip_check")))} + } + } + steps { + script { + exeNum++ + result = sh(script: ''' + #!/bin/sh + cd $WORKSPACE + git format-patch HEAD~1 + ./support/scripts/checkpatch.uk ./000* --no-signoff + ''', returnStatus: true) + if (result == 0) { + sucNum++ + ret = ret + "\n|社区commit信息与代码规范检查|成功||" + } else { + failNum++ + ret = ret + "\n|社区commit信息与代码规范检查|**失败**|具体规范要求见任务链接|" + error '社区commit信息与代码规范检查失败' + } + } + } + } stage('初始化libmusl代码仓') { steps { /* script 块可以调用groovy方法 */ script { /* 调用shell脚本,执行check测试。使用NAME = sh()形式可以防止shell脚本出错直接退出stage */ result = sh(script: """ - #!/bin/bash - cd $WORKSPACE/ut_libc-test - git clone $gitAppHelloWorldURL - git clone $gitLibMuslUrl .unikraft/libs/musl - git clone $gitLibcTestUrl .unikraft/libs/libc-test - # 将musl库与libc-test库编入Makefile - sed -i '/^LIBS/{s/\$/\$(UK_LIBS)\\/musl:\$(UK_LIBS)\\/libc-test/}' Makefile - # 将libc-test库依赖的源码URL改为官网URL,源码URL下载不稳定 - sed -i '/LIBLIBCTEST_URL/s/git:\\/\\/nsz.repo.hu:49100\\/repo\\/libc-test/git:\\/\\/repo.or.cz\\/libc-test/g' .unikraft/libs/libc-test/Makefile.uk - # uktest测试库也需要musl编入 - cd .. - cp -r ut_libc-test/. ut_self-test - """, returnStatus: true) + #!/bin/bash + cd $WORKSPACE/ut_libc-test + git clone $gitAppHelloWorldURL + git clone $gitLibMuslUrl workdir/libs/musl + git clone $gitLibcTestUrl workdir/libs/libc-test + cd workdir/libs/musl + # 由于官网musl库获取tar包获取不稳定因此改为从fork的公司库获取 + sed -i 's|LIBMUSL_URL=https://www.musl-libc.org/releases/musl-\$(LIBMUSL_VERSION).tar.gz|LIBMUSL_URL=https://gitee.com/yingyitech/fork-musl/repository/archive/v\$(LIBMUSL_VERSION).zip|' Makefile.uk + sed -i 's|\$(eval \$(call patch,libmusl,\$(LIBMUSL_PATCHDIR),musl-\$(LIBMUSL_VERSION)))|\$(eval \$(call patch,libmusl,\$(LIBMUSL_PATCHDIR),fork-musl-v\$(LIBMUSL_VERSION)))|' Makefile.uk + sed -i 's|LIBMUSL_SUBDIR=musl-\$(LIBMUSL_VERSION)|LIBMUSL_SUBDIR=fork-musl-v\$(LIBMUSL_VERSION)|' Makefile.uk + """, returnStatus: true) + /*处理相关pr信息,如无也不影响*/ + if (!prdata2.isEmpty()) { + prdata2.each{ pr -> + result = sh(script: """ + #!/bin/bash + cd $WORKSPACE + cd ${mapping2[pr.reponame]} + git fetch https://gitee.com/${pr.owner}/${pr.reponame}.git pull/${pr.prnumber}/head:pr_${pr.prnumber} + git merge pr_${pr.prnumber} + """, returnStatus: true) + if (result != 0) { + ret = "初始化依赖PR失败,详见任务链接" + error '初始化依赖PR失败' + } + } + } + result = sh(script: """ + #!/bin/bash + cd $WORKSPACE/ut_libc-test + # 将musl库与libc-test库编入Makefile + sed -i '/^LIBS/{s/\$/\$(UK_LIBS)\\/musl:\$(UK_LIBS)\\/libc-test/}' Makefile + # 将libc-test库依赖的源码URL改为官网URL,源码URL下载不稳定 + sed -i '/LIBLIBCTEST_URL/s/git:\\/\\/nsz.repo.hu:49100\\/repo\\/libc-test/git:\\/\\/repo.or.cz\\/libc-test/g' workdir/libs/libc-test/Makefile.uk + # uktest测试库也需要musl编入 + cd .. + cp -r ut_libc-test/. ut_self-test + """, returnStatus: true) if (result != 0) { ret = ret + "\n\n初始化libmusl失败,详见任务链接" error '初始化libmusl失败' @@ -255,10 +342,10 @@ pipeline { script { exeNum++ result = sh(script: ''' - #!/bin/bash - cd $WORKSPACE/ut_libc-test - make defconfig UK_DEFCONFIG=$PWD/.unikraft/unikraft/ci/defconfigs/raspi-arm64-libc-test - ''', returnStatus: true) + #!/bin/bash + cd $WORKSPACE/ut_libc-test + make defconfig UK_DEFCONFIG=$PWD/workdir/unikraft/ci/defconfigs/raspi-arm64-libc-test + ''', returnStatus: true) if (result != 0) { failNum++ ret = ret + "\n|UT测试|**libc-test失败**|初始化make config配置失败|" @@ -271,10 +358,10 @@ pipeline { cd $WORKSPACE/ut_libc-test # 编译unikraft, make & run流程 make -j$nBuildThreads - raspiRoot=$PWD/.unikraft/unikraft/plat/raspi + raspiRoot=$PWD/workdir/unikraft/plat/raspi qemu-system-aarch64 -cpu cortex-a53 -machine raspi3b -nodefaults -display none \ - -pidfile $WORKSPACE/libc-test$BUILD_NUMBER.pid -serial file:$WORKSPACE/libc-test$BUILD_NUMBER.out \ - -kernel build/kernel8.img -dtb ${raspiRoot}/bootfiles/bcm2710-rpi-3-b-plus.dtb -append verbose & + -pidfile $WORKSPACE/libc-test$BUILD_NUMBER.pid -serial file:$WORKSPACE/libc-test$BUILD_NUMBER.out \ + -kernel workdir/build/kernel8.img -dtb ${raspiRoot}/bootfiles/bcm2710-rpi-3-b-plus.dtb -append verbose & # 后台运行,等待15s sleep 15s ''', returnStatus: true) @@ -307,9 +394,9 @@ pipeline { script { exeNum++ result = sh(script: ''' - cd $WORKSPACE/ut_self-test - make defconfig UK_DEFCONFIG=$PWD/.unikraft/unikraft/ci/defconfigs/raspi-arm64-uktest - ''', returnStatus: true) + cd $WORKSPACE/ut_self-test + make defconfig UK_DEFCONFIG=$PWD/workdir/unikraft/ci/defconfigs/raspi-arm64-uktest + ''', returnStatus: true) if (result != 0) { failNum++ ret = ret + "\n|UT测试|**self-test失败**|初始化make config配置失败|" @@ -319,23 +406,23 @@ pipeline { /* make & run*/ script { result = sh(script: ''' - cd $WORKSPACE/ut_self-test - # 编译unikraft, make & run流程 - make -j$nBuildThreads - raspiRoot=$PWD/.unikraft/unikraft/plat/raspi - qemu-system-aarch64 -cpu cortex-a53 -machine raspi3b -nodefaults -display none \ - -pidfile $WORKSPACE/self-test$BUILD_NUMBER.pid -serial file:$WORKSPACE/self-test$BUILD_NUMBER.out \ - -kernel build/kernel8.img -dtb ${raspiRoot}/bootfiles/bcm2710-rpi-3-b-plus.dtb -append verbose & - # 后台运行,等待15s - sleep 15s - ''', returnStatus: true) + cd $WORKSPACE/ut_self-test + # 编译unikraft, make & run流程 + make -j$nBuildThreads + raspiRoot=$PWD/workdir/unikraft/plat/raspi + qemu-system-aarch64 -cpu cortex-a53 -machine raspi3b -nodefaults -display none \ + -pidfile $WORKSPACE/self-test$BUILD_NUMBER.pid -serial file:$WORKSPACE/self-test$BUILD_NUMBER.out \ + -kernel workdir/build/kernel8.img -dtb ${raspiRoot}/bootfiles/bcm2710-rpi-3-b-plus.dtb -append verbose & + # 后台运行,等待15s + sleep 15s + ''', returnStatus: true) if (result == 0) { resultCheck = sh(script: ''' - cd $WORKSPACE/ - # 如果输出文件中包含Hello world!则判断运行成功 - cat $WORKSPACE/self-test$BUILD_NUMBER.out - grep -q "Hello" $WORKSPACE/self-test$BUILD_NUMBER.out - ''', returnStatus: true) + cd $WORKSPACE/ + # 如果输出文件中包含Hello world!则判断运行成功 + cat $WORKSPACE/self-test$BUILD_NUMBER.out + grep -q "Hello" $WORKSPACE/self-test$BUILD_NUMBER.out + ''', returnStatus: true) if (resultCheck == 0) { sucNum++ ret = ret + "\n|UT测试|self-test成功||" @@ -369,11 +456,11 @@ pipeline { script { exeNum++ result = sh(script:''' - cd $WORKSPACE/run_qemu-x86_64 - UK_DEFCONFIG=\$PWD/.config.helloworld-qemu-x86_64 make defconfig - make -j$nBuildThreads - qemu-system-x86_64 -kernel build/helloworld_qemu-x86_64 -nographic - ''', returnStatus: true) + cd $WORKSPACE/run_qemu-x86_64 + UK_DEFCONFIG=\$PWD/defconfigs/qemu-x86_64 make defconfig + make -j$nBuildThreads + qemu-system-x86_64 -kernel workdir/build/helloworld_qemu-x86_64 -nographic + ''', returnStatus: true) if (result == 0) { sucNum++ ret = ret + "\n|兼容性测试|helloworld (qemu, x86_64)成功||" @@ -391,11 +478,11 @@ pipeline { script { exeNum++ result = sh(script:''' - cd $WORKSPACE/run_qemu-arm64 - UK_DEFCONFIG=\$PWD/.config.helloworld-qemu-aarch64 make defconfig - make -j$nBuildThreads - qemu-system-aarch64 -kernel build/helloworld_qemu-arm64 -nographic -machine virt -cpu cortex-a57 - ''', returnStatus: true) + cd $WORKSPACE/run_qemu-arm64 + UK_DEFCONFIG=\$PWD/defconfigs/qemu-arm64 make defconfig + make -j$nBuildThreads + qemu-system-aarch64 -kernel workdir/build/helloworld_qemu-arm64 -nographic -machine virt -cpu cortex-a57 + ''', returnStatus: true) if (result == 0) { sucNum++ ret = ret + "\n|兼容性测试|helloworld (qemu, arm64)成功||" @@ -413,18 +500,18 @@ pipeline { script { exeNum++ result = sh(script:""" - #!/bin/bash - cd $WORKSPACE/run_xen-x86_64 - cat>helloworld.cfg<helloworld.cfg<fc-x86_64.json<fc-x86_64.json<