RT-Thread中一共有五个Github Action(rt-thread/.github/workflow)
分别是:
RT-Thread BSP build check(.github/workflows/action.yml)
ToolsCI(.github/workflows/action_tools.yml)
AutoTestCI(.github/workflows/action_utest.yml)
Check File Format and License(.github/workflows/file_check.yml)
Static code analysis(.github/workflows/static_code_analysis.yml)
下面分别讲解这五个Github Action。
RT-Thread BSP build check总的来说,这个Action会通过matrix尝试编译多个BSP,并记录编译成功和失败的信息。执行脚本中的每个BSP编译步骤都在日志中创建了一个分组,以便在编译成功或失败时可以更好地显示和记录相关信息。
matrix列表中每个元素有三个属性,分别是
RTT_BSP:这组BSP的名字,后续输出日志时会用到
RTT_TOOL_CHAIN:编译这组BSP使用的工具链
SUB_RTT_BSP:各个BSP的目录
RT-Thread BSP build check的第一步:
首先先安装gcc和menuconfig依赖的包
调用tools目录下的menuconfig的touch_env
这个函数主要是创建一系列后续会使用到的文件夹,并且拉取远程的packages
以及修改Kconfig
设置一些RT-Thread自己的环境遍历,供后续使用
1name: Install Tools
2shell: bash
3run: |
4 sudo apt-get update
5 sudo apt-get -qq install gcc-multilib libncurses5 libncurses5-dev libncursesw5-dev scons
6 sudo python -m pip install --upgrade pip -qq
7 pip install requests -qq
8 git config --global http.postBuffer 524288000
9 python -c "import tools.menuconfig; tools.menuconfig.touch_env()"
10 echo "RTT_ROOT=${{ github.workspace }}" >> $GITHUB_ENV
11 echo "RTT_CC=gcc" >> $GITHUB_ENV
RT-Thread BSP build check的第二步:
会根据matrix.legs.RTT_TOOL_CHAIN判断需要安装什么工具链
RT-Thread BSP build check的第三步:
第三步是这次BSP编译测试的核心
首先会遍历所有的SUB_RTT_BSP
根据scons命令执行的成功与否(||前一个命令执行失败、&&前一个命令执行成功)来判断执行成功还是失败的逻辑
输出的时候会在GitHub Actions日志中创建一个分组,用于显示BSP编译的信息
计算总共花费的时间,输出BSP编译成功或者失败的信息,输出至$GITHUB_STEP_SUMMARY
1name: Bsp Scons Compile
2if: ${{ success() }}
3shell: bash
4env:
5 RTT_BSP: ${{ matrix.legs.RTT_BSP }}
6 RTT_TOOL_CHAIN: ${{ matrix.legs.RTT_TOOL_CHAIN }}
7 SRTT_BSP: ${{ join(matrix.legs.SUB_RTT_BSP, ',') }}
8run: |
9 source ~/.env/env.sh
10 failed=0
11 count=0
12 for bsp in $(echo $SRTT_BSP | tr ',' '
'); do
13 count=$((count+1))
14 echo "::Compiling BSP: ==$count=== $bsp ===="
15 echo bsp/$bsp
16 pushd bsp/$bsp && pkgs --update && popd
17 scons -C bsp/$bsp -j$(nproc) --debug=time | tee output.log ||
18 { total_time=$(grep "Total command execution time" output.log | awk '{print $5}');
19 failed=$((failed+1)) ; echo "::" ; echo "::build $bsp failed" ;
20 echo "- build $bsp failed in $total_time seconds " >> $GITHUB_STEP_SUMMARY ; } &&
21 { total_time=$(grep "Total command execution time" output.log | awk '{print $5}');
22 echo "- build $bsp success in $total_time seconds " >> $GITHUB_STEP_SUMMARY ; echo "::" ; }
23 done
24 exit $failed
ToolsCI
总的来说,ToolsCI这个Action比较简单,会去尝试Build一个BSP、生成其它工程文件等等,用来测试使用。
关于scons一些参数的使用可以参考:SCons (rt-thread.org)
1name: ToolsCI
2# Controls when the action will run. Triggers the workflow on push or pull request
3# events but only for the master branch
4on:
5 # Runs at 16:00 UTC (BeiJing 00:00) on the 1st of every month
6 schedule:
7 - cron: '0 16 1 * *'
8 push:
9 branches:
10 - master
11 paths-ignore:
12 - documentation/**
13 - '**/README.md'
14 - '**/README_zh.md'
15 - '**/*.c'
16 - '**/*.h'
17 - '**/*.cpp'
18 pull_request:
19 branches:
20 - master
21 paths-ignore:
22 - documentation/**
23 - '**/README.md'
24 - '**/README_zh.md'
25 - '**/*.c'
26 - '**/*.h'
27 - '**/*.cpp'
28permissions:
29 contents: read # to fetch code (actions/checkout)
30jobs:
31 test:
32 runs-on: ubuntu-latest
33 name: Tools
34 strategy:
35 fail-fast: false
36 env:
37 TEST_BSP_ROOT: bsp/stm32/stm32f407-atk-explorer
38 steps:
39 - uses: actions/checkout@v3
40 - name: Install Tools
41 shell: bash
42 run: |
43 sudo apt-get update
44 sudo apt-get -yqq install scons
45 - name: Install Arm ToolChains
46 if: ${{ success() }}
47 shell: bash
48 run: |
49 wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/v1.3/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
50 sudo tar xjf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 -C /opt
51 /opt/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi-gcc --version
52 echo "RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin" >> $GITHUB_ENV
53 - name: Build Tools
54 run: |
55 scons --pyconfig-silent -C $TEST_BSP_ROOT
56 scons -j$(nproc) -C $TEST_BSP_ROOT
57 - name: Project generate Tools
58 if: ${{ success() }}
59 run: |
60 echo "Test to generate eclipse project"
61 scons --target=eclipse -s -C $TEST_BSP_ROOT
62 echo "Test to generate cmake project"
63 scons --target=cmake -s -C $TEST_BSP_ROOT
64 echo "Test to generate makefile project"
65 scons --target=makefile -s -C $TEST_BSP_ROOT
66 - name: Project dist Tools
67 if: ${{ success() }}
68 run: |
69 echo "Test to dist project"
70 scons --dist -C $TEST_BSP_ROOT
71 scons --dist-ide -C $TEST_BSP_ROOT
72 ls $TEST_BSP_ROOT
73 ls $TEST_BSP_ROOT/dist
74 scons -C $TEST_BSP_ROOT/dist/project
75 scons -C $TEST_BSP_ROOT/rt-studio-project
AutoTestCI
总的来说,这个Action的主要目标是根据matrix中的不同参数组合,安装必要的工具链、构建和测试代码。具体的步骤包括检出代码、安装所需工具、设置环境变量、构建代码,然后在qemu中运行测试并输出日志。根据参数的不同,这个工作流可以自动处理多个平台和架构的测试。
matrix列表中每个元素有五个属性,分别是
UTEST:这组BSP的名字,后续输出日志时会用到
RTT_BSP:测试使用的BSP
QEMU_ARCH:QEMU使用的平台架构
QEMU_MACHINE:选择QEMU的板级支持包
CONFIG_FILE:RT-Thread条件编译使用的CONFIG
SD_FILE:使用的sd.bin
RUN:是否启动
AutoTestCI的第一步:
安装必要的工具:scons、qemu、git
AutoTestCI的第二步:
根据matrix的属性选择安装相应的编译工具链
比如要测试arm架构和rtsmart/arm时,我们就选择安装arm-linux-musleabi_for_x86_64-pc-linux-g工具链
1name: Install Arm Musl ToolChains
2if: ${{ matrix.legs.QEMU_ARCH == 'arm' && matrix.legs.UTEST == 'rtsmart/arm' && success() }}
3shell: bash
4run: |
5 wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/v1.7/arm-linux-musleabi_for_x86_64-pc-linux-g
6 sudo tar xjf arm-linux-musleabi_for_x86_64-pc-linux-gnu_stable.tar.bz2 -C /opt
7 /opt/arm-linux-musleabi_for_x86_64-pc-linux-gnu/bin/arm-linux-musleabi-gcc --version
8 echo "RTT_EXEC_PATH=/opt/arm-linux-musleabi_for_x86_64-pc-linux-gnu/bin" >> $GITHUB_ENV
9 echo "RTT_CC_PREFIX=arm-linux-musleabi-" >> $GITHUB_ENV
AutoTestCI的第三步:
第三步主要完成$TEST_BSP_ROOT下BSP的编译,以供后续在qemu上使用
1name: Build BSP
2run: |
3 echo CONFIG_RT_USING_UTESTCASES=y >> $TEST_BSP_ROOT/.config
4 cat examples/utest/configs/$TEST_CONFIG_FILE >> $TEST_BSP_ROOT/.config
5 scons --pyconfig-silent -C $TEST_BSP_ROOT
6 scons -j$(nproc) --strict -C $TEST_BSP_ROOT
AutoTestCI的第四步:
第四步也是最重要的一步,开始测试相关用例
1name: Start run Test
2if: ${{matrix.legs.RUN == 'yes' && success() }}
3run: |
4 git clone https://github.com/armink/UtestRunner.git
5 pushd $TEST_BSP_ROOT
6 dd if=/dev/zero of=sd.bin bs=1024 count=65536
7 popd
8 pushd UtestRunner
9 if [ $TEST_SD_FILE != "None" ]; then
10 python3 qemu_runner.py --system $TEST_QEMU_ARCH --machine $TEST_QEMU_MACHINE --elf ../$TEST_BSP_ROOT/rtthread
11 else
12 python3 qemu_runner.py --system $TEST_QEMU_ARCH --machine $TEST_QEMU_MACHINE --elf ../$TEST_BSP_ROOT/rtthread
13 fi
14 cat rtt_console.log
15 popd
拉取RT-Thread自动化测试机器人
制作sd.bin
使用需要测试的BSP启动qemu
最后输出相关日志
这个Action主要是用来检查文件的格式化和版权信息的,主要工作都由tools/ci/file_check.py完成,在此之前主要先检出当前仓库的代码和安装Python脚本依赖的包。
1name: Check File Format and License
2on: [pull_request]
3jobs:
4 scancode_job:
5 runs-on: ubuntu-latest
6 name: Scan code format and license
7 steps:
8 - uses: actions/checkout@v3
9 - name: Set up Python
10 uses: actions/setup-python@v3
11 with:
12 python-version: 3.8
13 - name: Check Format and License
14 shell: bash
15 run: |
16 pip install click chardet PyYaml
17 python tools/ci/file_check.py check 'https://github.com/RT-Thread/rt-thread' 'master'
file_check.py
我们可以先忽略使用的click命令行库,或者也可以从命名和使用方式猜测出它们的功能。
因为这个文件比较简单,所以我们可以猜测函数的入口就是check()。主函数里的逻辑是十分简单的,可以看到通过checkout.get_new_file()获得了一个文件列表,然后传递给了FormatCheck和LicenseCheck,它们又分别调用了自身的check函数,最后根据它们返回值判断是否检查出错误。
1def check(check_license, repo, branch):
2 """
3 check files license and format.
4 """
5 init_logger()
6 # get modified files list
7 checkout = CheckOut(repo, branch)
8 file_list = checkout.get_new_file()
9 if file_list is None:
10 logging.error("checkout files fail")
11 sys.exit(1)
12 # check modified files format
13 format_check = FormatCheck(file_list)
14 format_check_result = format_check.check()
15 license_check_result = True
16 if check_license:
17 license_check = LicenseCheck(file_list)
18 license_check_result = license_check.check()
19 if not format_check_result or not license_check_result:
20 logging.error("file format check or license check fail.")
21 sys.exit(1)
22 logging.info("check success.")
23 sys.exit(0)
checkout.get_new_file()获得的文件列表是需要检查的文件列表,而FormatCheck和LicenseCheck执行各自的检查逻辑。
首先是get_new_file,具体的逻辑也比较简单:
1. 通过git命令获得新增和修改的文件列表
2. 然后遍历这个文件列表
3. 遍历这个文件列表中的文件路径的每一层目录,看是否存在.ignore_format.yml文件
4. 然后根据.ignore_format.yml的属性来判断当前文件是否需要被检查
而FormatCheck主要完成的工作是:
1. 搜索所有.c和.h文件
2. 然后检查行首、行尾以及tab
而LicenseCheck的逻辑也比较简单,主要就是判断当前的Copyright的年份是否正确。
1if 'Copyright' in file[1] and 'SPDX-License-Identifier: Apache-2.0' in file[3]:
2 try:
3 license_year = re.search(r'2006-d{4}', file[1]).group()
4 true_year = '2006-{}'.format(current_year)
5 if license_year != true_year:
6 logging.warning("[{0}]: license year: {} is not true: {}, please update.".fo
7 else:
8 logging.info("[{0}]: license check success.".format(file_path))
9 except Exception as e:
10 logging.error(e)
11else:
12 logging.error("[{0}]: license check fail.".format(file_path))
13 check_result = False
Static code analysis
这个Action和Check File Format and License是很类似的,主要流程都是相同的。
最重要的就是利用cppcheck完成静态代码检查的功能:
1. 从文件列表中再一次过滤出C/C++相关文件2. 然后使用cppcheck逐个检查文件列表,并且捕获标准错误流
1class CPPCheck:
2 def __init__(self, file_list):
3 self.file_list = file_list
4 def check(self):
5 file_list_filtered = [file for file in self.file_list if file.endswith(('.c', '.cpp', '.cc', '.cxx'))]
6 logging.info("Start to static code analysis.")
7 check_result = True
8 for file in file_list_filtered:
9 result = subprocess.run(['cppcheck', '--enable=warning', 'performance', 'portability', '--inline-suppr', '--error-exitcode=1', '--force', file], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
10 logging.info(result.stdout.decode())
11 logging.info(result.stderr.decode())
12 if result.stderr:
13 check_result = False
14 return check_result
15@click.group()
16@click.pass_context
17def cli(ctx):
18 pass
19@cli.command()
20def check():
21 """
22 static code analysis(cppcheck).
23 """
24 format_ignore.init_logger()
25 # get modified files list
26 checkout = format_ignore.CheckOut()
27 file_list = checkout.get_new_file()
28 if file_list is None:
29 logging.error("checkout files fail")
30 sys.exit(1)
31 # use cppcheck
32 cpp_check = CPPCheck(file_list)
33 cpp_check_result = cpp_check.check()
34 if not cpp_check_result:
35 logging.error("static code analysis(cppcheck) fail.")
36 sys.exit(1)
37 logging.info("check success.")
38 sys.exit(0)
39if __name__ == '__main__':
40 cli()
原文:https://club.rt-thread.org/ask/article/102cc126ad4dbfd8.html
———————End———————
RT-Thread线下入门培训
6月 - 郑州、杭州、深圳
1.免费 2.动手实验+理论 3.主办方免费提供开发板 4.自行携带电脑,及插线板用于笔记本电脑充电 5.参与者需要有C语言、单片机(ARM Cortex-M核)基础,请提前安装好RT-Thread Studio 开发环境
立即扫码报名
报名链接
https://jinshuju.net/f/UYxS2k
巡回城市:青岛、北京、西安、成都、武汉、郑州、杭州、深圳、上海、南京
你可以添加微信:rtthread2020 为好友,注明:公司+姓名,拉进RT-Thread官方微信交流群!
点击阅读原文,进入RT-Thread 官网
原文标题:RT-Thread中的Github Actions
文章出处:【微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。
全部0条评论
快来发表一下你的评论吧 !