背景
目前社區(qū)軟件包存在大量編譯問(wèn)題:
版本迭代造成的編譯問(wèn)題(內(nèi)核文件改動(dòng)后,軟件包沒(méi)有去做版本控制)
架構(gòu)沖突以及 bsp 依賴問(wèn)題(某些軟件包只在特定的架構(gòu)或 bsp 中可用)
針對(duì)上述的問(wèn)題,誕生了 pkgs-test 工具,主要用于暴露出社區(qū)軟件包的相關(guān)編譯問(wèn)題。
使用場(chǎng)景
本地使用
對(duì)特定的軟件包,在一些指定的bsp、rt-thread版本上進(jìn)行測(cè)試。
指定某一個(gè)特定的版本或所有版本。
指定的軟件包集合。
作為Github Action使用,測(cè)試軟件包是否支持一些rtt版本和bsp。
軟件包開(kāi)發(fā)者
軟件包測(cè)試
更新軟件包的代碼之后,自動(dòng)對(duì)軟件包進(jìn)行測(cè)試。
rt-thread的master測(cè)試
定時(shí)對(duì)軟件包進(jìn)行測(cè)試,檢查是否支持rt-thread的master版本。
rt-thread社區(qū)維護(hù)人員
所有軟件包測(cè)試
定時(shí)對(duì)全部軟件包在master 分支或指定的一些版本上進(jìn)行測(cè)試,并發(fā)布測(cè)試結(jié)果到github pages。
軟件包索引更新測(cè)試
軟件包索引發(fā)生改動(dòng)時(shí),對(duì)改動(dòng)的部分軟件包進(jìn)行測(cè)試,在github pages上面更新這部分測(cè)試結(jié)果。
rt-thread版本發(fā)布測(cè)試
rt-thread版本發(fā)布后對(duì)全部的軟件包進(jìn)行測(cè)試。
精品軟件包集合測(cè)試(TODO)
對(duì)一些制定的精品軟件包集合進(jìn)行測(cè)試,比如當(dāng)rt-thread的master分支改動(dòng)時(shí),測(cè)試這些軟件包。
pkgs-test的class
pkgs-test工具內(nèi)部一共有6個(gè)類。
?PackagesIndex
從軟件包索引讀取軟件包信息,保存到一個(gè)字典中。
根據(jù)運(yùn)行時(shí)輸入的參數(shù)來(lái)選擇需要測(cè)試的軟件包列表。
Config
根據(jù)配置文件下載需要的資源rt-thread、toolchains。
下載env工具和軟件包索引。
根據(jù)運(yùn)行時(shí)輸入的參數(shù)來(lái)修改配置文件。
Logs
根據(jù)測(cè)試結(jié)果生成json。
根據(jù)json生成html頁(yè)面。
Build
執(zhí)行編譯,并輸出編譯日志到文件。
Change
檢查軟件包索引的改動(dòng)。
Check
檢查L(zhǎng)ogs生成的json。
pkgs-test的運(yùn)行過(guò)程
首先使用Config讀取配置文件。輸入?yún)?shù)args.config是配置文件目錄。
config = Config(args.config)
讀取輸入的軟件包名稱。
pkgs_name = config.get_pkgs_name(args.pkg)
如果有輸入就保存輸入的名稱,輸入為空就從配置文件內(nèi)讀取。
def get_pkgs_name(self, pkg=[]):
if pkg:
return pkg
elif not (self.config_data['pkgs'] == None or self.config_data['pkgs'] == []):
return list(self.config_data['pkgs'])
return []
接著下載需要的資源。這里在ci工具里面會(huì)事先下載好一些資源,比如軟件包索引,如果該目錄已經(jīng)存在,則不會(huì)被覆蓋,可以用于測(cè)試這些還沒(méi)有發(fā)布的資源。
config.get_resources()
讀取軟件包索引。如果輸入?yún)?shù)nolatest那么就不保存latest版本。
packages_index = PackagesIndex(os.path.join(
config.get_path('env'), 'packages/packages'))
packages_index.nolatest(args.nolatest)
接著選擇測(cè)試的軟件包。
if args.repository:
pkgs_config_dict = packages_index.repository_seek(args.repository)
else:
pkgs_config_dict = packages_index.name_seek(pkgs_name)
這里分為兩種情況,一種是作為ci使用,會(huì)輸出參數(shù)repository,另一種是本地使用,讀取前面保存的pkgs_name。
name_seek會(huì)判斷是不是測(cè)試全部軟件包,如果pkgs_name是all那么就會(huì)測(cè)試全部軟件包。
def name_seek(self, pkgs='all'):
if pkgs == 'all':
config_dict = self.dict
else:
config_dict = self.__get_config_pkgs(pkgs)
print(config_dict)
return config_dict
repository_seek會(huì)識(shí)別repository的類型,如果是軟件包倉(cāng)庫(kù)就會(huì)在軟件包索引里面尋找,如果是packages軟件包索引倉(cāng)庫(kù)就會(huì)使用Change尋找軟件包索引的改動(dòng),將改動(dòng)的軟件包保存到pkgs_config_dict里面。
def repository_seek(self, repository):
pkgs = []
repository_name = repository.split("/")[1]
if repository_name == 'packages':
change = Change(os.path.join(Config().get_path('env'),"packages/packages"))
return self.name_seek(change.get_change_pkg_name())
for pkg in self.dict:
if repository_name.lower() in pkg['repository'].lower():
pkgs.append(pkg)
if len(pkgs) > 1:
pkgs_copy = list(pkgs)
for pkg in pkgs_copy:
if not repository_name in pkg['repository']:
pkgs_copy.remove(pkg)
if pkgs_copy:
pkgs = pkgs_copy
if not pkgs:
print('You may have changed the warehouse name while forking!!!')
return []
for pkg in pkgs[0]['pkg']:
if 'URL' in pkg:
pkg['URL'] = 'https://github.com/' + repository + '.git'
return pkgs
創(chuàng)建一個(gè)Log類,用于生成測(cè)試結(jié)果,這里的append_res是開(kāi)啟從github pages下載舊的測(cè)試結(jié)果并且與新的合并。
logs = Logs('artifacts_export',
config.get_config_data(), pkgs_config_dict)
if args.append_res:
if args.pages_url:
logs.pages_url = args.pages_url
logs.append_res = True
最后執(zhí)行編譯,并根據(jù)編譯的log生成json和html。
build = Build(config, pkgs_config_dict, logs, args.j)
其中關(guān)于發(fā)布測(cè)試結(jié)果的部分在這里詳細(xì)說(shuō)明一下。
執(zhí)行Logs.logs()會(huì)根據(jù)編譯日志生成測(cè)試結(jié)果json與html頁(yè)面。
其中有兩個(gè)json文件,pkgs_res_single是本次執(zhí)行pkgs-test產(chǎn)生的測(cè)試結(jié)果,pkgs_res是與舊的測(cè)試結(jié)果合并后的,如果沒(méi)有合并那么兩個(gè)json相同。這里從代碼可以看到,兩個(gè)json文件都使用__build_res生成,如果傳入True那么就會(huì)合并,如果False那么就只有本次結(jié)果。
index.html則是根據(jù)pkgs_res生成的頁(yè)面。
def logs(self):
pkgs_res_single_dict = self.__build_res(False)
with open(os.path.join(self.logs_path, 'pkgs_res_single.json'), 'w') as f:
json.dump(pkgs_res_single_dict, f)
self.pkgs_res_dict = self.__build_res(self.append_res)
with open(os.path.join(self.logs_path, 'pkgs_res.json'), 'w') as f:
json.dump(self.pkgs_res_dict, f)
logs_html = self.__html_report()
with open(os.path.join(self.logs_path, 'index.html'), 'w') as f:
for log in logs_html:
f.write(log)
Workflow的運(yùn)行過(guò)程
workflow分為3個(gè)job,packages-test用于測(cè)試軟件包,check-errors用于檢查測(cè)試結(jié)果,Deploy-Pages發(fā)布測(cè)試結(jié)果頁(yè)面。
packages-test
首先是下載運(yùn)行的倉(cāng)庫(kù)和pkgs-tese倉(cāng)庫(kù)。
- uses: actions/checkout@v3
with:
path: repository- uses: actions/checkout@v3
with:
repository: '${{ inputs.pkgs-test-repository }}'
ref: '${{ inputs.pkgs-test-branch }}'
path: pkgs-test
接下來(lái)是安裝一些軟件和工具。
- uses: actions/checkout@v3
- name: Install Tools
shell: bash
run: |
sudo apt install python3 python3-pip gcc git libncurses5-dev tree -y
python3 -m pip install scons==4.4.0 requests tqdm wget dominate PyGithub requests pytz
如果運(yùn)行的倉(cāng)庫(kù)是軟件包索引,那么就把軟件包索引倉(cāng)庫(kù)復(fù)制到后面需要下載軟件包索引的路徑。 - name: Copy RT-Thread/packages to env
if: "${{ endsWith(github.repository, '/packages') == true }}"
shell: bash
run: |
cd ${{ github.workspace }}
mkdir -p ./pkgs-test/env/packages
cp -r ./repository ./pkgs-test/env/packages/packages
根據(jù)輸入的配置參數(shù)下載對(duì)應(yīng)的資源,rt-thread、bsp對(duì)應(yīng)的工具鏈、env工具、軟件包索引。 - name: Install Test Resources
shell: bash
run: |
cd ${{ github.workspace }}/pkgs-test
python pkgs-test.py config --rtthread='${{ inputs.rt-thread-versions }}'
python pkgs-test.py config --bsps='${{ inputs.bsps }}'
python pkgs-test.py download
執(zhí)行編譯測(cè)試,這里根據(jù)輸入的參數(shù)會(huì)選擇是否測(cè)試全部軟件包,是否測(cè)試軟件包latest版本,是否合并測(cè)試結(jié)果。 - name: Carry Out Packages Test
shell: bash
run: |
cd ${{ github.workspace }}/pkgs-test
echo 'Carry Out Packages Test.'
if [[ ${{ inputs.package-test-all}} == true ]]; then
COMMAND="python pkgs-test.py --pkg=all"
else
COMMAND="python pkgs-test.py --repository=${{ inputs.package-repository }}"
fi
if [[ ${{ inputs.package-test-nolatest}} == true ]]; then
echo 'nolatest.'
COMMAND="$COMMAND --nolatest"
fi
if [[ ${{ inputs.package-append-res}} == true ]]; then
echo 'Append test res to old res from githubpage.'
COMMAND="**COMMAND --append_res --pages_url='**{{ inputs.pages-url}}'"
fi
echo "$COMMAND"
eval "$COMMAND"
最后就是導(dǎo)出artifacts_export目錄的測(cè)試結(jié)果、一個(gè)是方便維護(hù)者下載、一個(gè)是用來(lái)發(fā)布頁(yè)面。 - uses: actions/upload-artifact@v3
with:
name: artifacts_export
path: ${{ github.workspace }}/pkgs-test/artifacts_export
check-errors
這個(gè)job比較簡(jiǎn)單,就是根據(jù)下載的測(cè)試結(jié)果執(zhí)行判斷。
check-errors:
runs-on: ubuntu-latest
needs: packages-test
if: "${{ inputs.check-errors }}"
steps:
- uses: actions/checkout@v3
with:
repository: '${{ inputs.pkgs-test-repository }}'
ref: '${{ inputs.pkgs-test-branch }}' - name: Download artifacts_export
uses: actions/download-artifact@v3
with:
name: artifacts_export - name: Install Tools
shell: bash
run: |
sudo apt install python3 python3-pip -y
python3 -m pip install requests tqdm wget dominate PyGithub requests pytz - name: Packages test whether or not error
shell: bash
run: |
python pkgs-test.py check --file='pkgs_res_single.json'
Deploy-Pages
Deploy-Pages就是將artifacts_export發(fā)布到github pages。
Deploy-Pages:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: packages-test
if: "${{ inputs.deploy-pages }}"
steps:
- name: Download artifacts_export
uses: actions/download-artifact@v3
with:
name: artifacts_export - name: Setup Pages
uses: actions/configure-pages@v3 - name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
Upload entire repository
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
作為Github Action使用
目前可以在軟件包索引倉(cāng)庫(kù)和軟件包倉(cāng)庫(kù)使用pkgs-test來(lái)測(cè)試軟件包的編譯情況。
Packages倉(cāng)庫(kù)
軟件包索引倉(cāng)庫(kù)里面目前有兩個(gè)功能,一個(gè)是當(dāng)發(fā)生改動(dòng)的時(shí)候測(cè)試改動(dòng)的軟件包,另外就是定時(shí)測(cè)試全部的軟件包。
改動(dòng)測(cè)試
這里是Packages倉(cāng)庫(kù)的軟件包測(cè)試workflow文件其中的一個(gè)job,目的是當(dāng)發(fā)生改動(dòng)的時(shí)候測(cè)試改動(dòng)的軟件包。
change:
if: ${{ github.event_name == 'pull_request' || github.event_name == 'push'}}
uses: RT-Thread/pkgs-test/.github/workflows/pkgs-action.yml@main
with:
package-append-res: true
deploy-pages: true
這里使用if進(jìn)行了判斷,當(dāng)workflow的觸發(fā)事件是pull_request或者push的時(shí)候,執(zhí)行change這個(gè)job。
傳入的參數(shù)有兩個(gè),package-append-res用來(lái)開(kāi)啟從github pages下載舊的測(cè)試結(jié)果并且與新的合并,deploy-pages用來(lái)開(kāi)啟將測(cè)試結(jié)果發(fā)布到github pagses。
定時(shí)全部測(cè)試
這里我舉出兩個(gè)jobs的例子,測(cè)試master內(nèi)核版本下兩個(gè)bsp的軟件包編譯情況。
master-stm32h750-artpi-test:
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'}}
uses: RT-Thread/pkgs-test/.github/workflows/pkgs-action.yml@main
with:
bsps: stm32/stm32h750-artpi:sourcery-arm
rt-thread-versions: branch:master
package-append-res: true
package-test-all: true
deploy-pages: true
check-errors: false
master-k210-test:
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'}}
needs: master-stm32h750-artpi-test
uses:
with:
bsps: k210:sourcery-riscv-none-embed
rt-thread-versions: branch:master
package-append-res: true
package-test-all: true
deploy-pages: true
check-errors: false
測(cè)試全部軟件包的觸發(fā)事件有兩個(gè),schedule定時(shí)測(cè)試和workflow_dispatch手動(dòng)觸發(fā),這里也是使用if來(lái)判斷的。
這里注意一下,測(cè)試全部軟件包需要一個(gè)接著一個(gè)按順序測(cè)試,不能并行進(jìn)行測(cè)試,不然發(fā)布測(cè)試結(jié)果會(huì)產(chǎn)生沖突,workflow文件也用了concurrency這個(gè)參數(shù)來(lái)確保每次只有一個(gè)workflow在運(yùn)行,讓其余的進(jìn)行等待。
concurrency:
group: pkgs-test
cancel-in-progress: false # wait for finish.
然后解釋一下傳入的參數(shù)。
bsps指的就是測(cè)試的bsp和其使用的工具鏈,用冒號(hào)進(jìn)行分隔。
rt-thread-versions指的就是內(nèi)核的版本,branch和tag有兩種不同的輸入方法branch:master tag:v4.1.1
package-append-res表示的是從github pages下載舊的測(cè)試結(jié)果并且與新的合并。
package-test-all就是最主要的一個(gè)參數(shù),表示測(cè)試全部軟件包。
deploy-pages表示發(fā)布測(cè)試結(jié)果到GitHub pages。
check-errors表示關(guān)閉錯(cuò)誤檢查,這里是因?yàn)橹饕康氖前l(fā)布測(cè)試結(jié)果,所以用不需要檢查是否有軟件包沒(méi)有通過(guò)編譯測(cè)試。
軟件包倉(cāng)庫(kù)
軟件包倉(cāng)庫(kù)的使用方法比較簡(jiǎn)單,不需要輸入任何參數(shù),它的測(cè)試過(guò)程和本地測(cè)試基本上一致。
它的workflow文件是這樣的。
name: RT-Thread_Packages_Test
on:
[push, pull_request]
jobs:
pkgs-test:
未來(lái)會(huì)實(shí)現(xiàn)的功能
定期測(cè)試全部軟件包后會(huì)通知給軟件包所有者:使用action打開(kāi)一個(gè)issue,在里面@有問(wèn)題的軟件包作者。
增加一個(gè)軟件包可用性分級(jí):1.有最新release版本可用。2.只有l(wèi)atest版本、或者最新版軟件包不可用但有舊版可用 3.全部失敗
再完善一下結(jié)果報(bào)告頁(yè)面,比如按類別給包分組。
針對(duì)rt-thread內(nèi)核的測(cè)試,對(duì)一個(gè)精選軟件包集合進(jìn)行測(cè)試。
-
BSP
+關(guān)注
關(guān)注
1文章
94瀏覽量
26967 -
RT-Thread
+關(guān)注
關(guān)注
32文章
1409瀏覽量
41962
發(fā)布評(píng)論請(qǐng)先 登錄
英飛凌MEMTOOL軟件介紹和使用方法
assessPort工具的使用方法
介紹SPI的使用方法
常用手機(jī)焊接工具使用方法
python中的字典(dict)對(duì)象以及其使用方法
面包板的結(jié)構(gòu)和使用方法詳細(xì)介紹

示波器的使用方法(三):示波器的使用方法詳解
動(dòng)態(tài)追蹤技術(shù)分類及其使用方法

內(nèi)網(wǎng)穿透工具的種類、原理和使用方法

評(píng)論