Skip to content

Package Size Test [clean, No.5, @latest] #63

Package Size Test [clean, No.5, @latest]

Package Size Test [clean, No.5, @latest] #63

Workflow file for this run

name: Package Size Test
run-name: Package Size Test [${{ inputs.CONFIG_BASE }}, No.${{ inputs.device_choice }}, @${{ inputs.commit_sha }}]
on:
workflow_dispatch:
inputs:
device_choice:
description: '选择型号(device-env.sh中的编号)'
required: false
default: 5
type: number
CONFIG_BASE:
type: choice
required: true
description: '选择基准配置版本'
default: 'clean'
options:
- clean
- basic
- func
- test
COMMIT_SHA:
description: '使用指定的commit(可选)'
required: false
default: 'latest'
use_cache:
description: '尝试使用缓存的tool和toolchain'
required: false
default: true
type: boolean
TEST_PER_JOB_MAX:
description: '单作业最大测试数(免费用户并行作业数上限为20)'
required: false
default: '10'
env:
# REPO_URL: https://github.com/openwrt/openwrt
# REPO_BRANCH: master
FEEDS_CONF: feeds.conf.default
CONFIG_FILE: .config
COMMIT_SHA: ${{ inputs.commit_sha }}
DIY_P1_SH: diy-part1.sh
# DIY_P2_SH: ${{ inputs.DIY_P2_FILE }}
TZ: Asia/Shanghai
# SEQ_FILE: ${{ inputs.SEQ_FILE }}
jobs:
init:
runs-on: ubuntu-22.04
outputs:
DEVICE_TAG: ${{steps.job_tagging.outputs.DEVICE_TAG}}
steps:
- uses: actions/checkout@main
- name: Load Environment Variable
run: |
chmod +x $GITHUB_WORKSPACE/device-env.sh
$GITHUB_WORKSPACE/device-env.sh ${{ inputs.device_choice }}
- name: job_tagging
id: job_tagging
run: |
# notifications
# echo "::set-output name=DEVICE_TAG::${DEVICE_TAG}"
echo "DEVICE_TAG=${DEVICE_TAG}" >> $GITHUB_OUTPUT
echo "::notice title=Target::[No.${{ inputs.device_choice }}]${DEVICE_TAG} with ${{ inputs.config_tag }}.config"
# 若指定了 commit 提个醒
if [ "$USE_COMMIT_SHA" == "latest" ]; then
LATEST_SHA=$(curl "https://api.github.com/repos/$REPO_USE/commits/$REPO_BRANCH" | grep sha | head -n1 | cut -d\" -f4)
echo "::notice title=Using commit::[latest] https://github.com/$REPO_USE/tree/$LATEST_SHA"
else
echo "::notice title=Using commit::[specific] https://github.com/$REPO_USE/tree/$USE_COMMIT_SHA"
fi
Factory:
runs-on: ubuntu-22.04
needs: init
name: ${{needs.init.outputs.DEVICE_TAG}}
outputs:
matrix: ${{ steps.setup_worker_matrix.outputs.json_content }}
TimeStamp: ${{ steps.info.outputs.TimeStamp }}
steps:
- uses: actions/checkout@main
- name: Load Environment Variable
id: load_env
run: |
chmod +x $GITHUB_WORKSPACE/device-env.sh
$GITHUB_WORKSPACE/device-env.sh ${{ inputs.device_choice }}
- name: List Test Sequence
id: info
run: |
# cd $GITHUB_WORKSPACE
# 时间戳,组成Artifact的文件名
date +"%Y%m%d%H%M"
# echo "::set-output name=TimeStamp::$(date +"%Y%m%d-%H%M")"
echo "TimeStamp=$(date +"%Y%m%d-%H%M")" >> $GITHUB_OUTPUT
# 打印序列信息和目录
echo '====================序列内容===================='
cat "${SEQ_FILE}" -An
echo '====================测试目录===================='
grep '@' "${SEQ_FILE}" -n | cat -n
# 从DIY_P2_SH中截取型号信息
grep '^CONFIG_TARGET.*DEVICE.*=y' "${DIY_P2_SH}" | sed -r 's/.*DEVICE_(.*)=y/\1/' > DEVICE_NAME
[ -s DEVICE_NAME ] && echo "::notice title=Device@.config:: $(cat DEVICE_NAME)" && echo "DEVICE_NAME=$(cat DEVICE_NAME)" >> $GITHUB_ENV
# 分任务
- name: Assign Jobs(Setup Worker Matrix)
id: setup_worker_matrix
run: |
# cd $GITHUB_WORKSPACE
# 分析列表
lines_num=$(wc -l "${SEQ_FILE}" | cut -f1 -d' ')
tests_num=$(grep '@' "${SEQ_FILE}" -c)
title_line_num_list=($(grep '@' "${SEQ_FILE}" -n | cut -d: -f1))
# 输出分析结果
echo "测试序列:共${lines_num}行,包含${tests_num}条测试任务"
echo '====================标题清单===================='
echo '(序列格式: [测试序号]标题行行编号)'
for i in $(seq ${tests_num}); do
echo -n "[$i]${title_line_num_list[i-1]}p "
done
echo
# 根据单作业最大测试数,计算总作业数及每个作业分配的测试数
TEST_PER_JOB_MAX=${{ inputs.TEST_PER_JOB_MAX }}
if [ $(( tests_num % TEST_PER_JOB_MAX )) -eq 0 ]; then
# 可平均分配
job_num=$((tests_num/TEST_PER_JOB_MAX))
tests_per_job=${TEST_PER_JOB_MAX}
else
# 非平均分配
job_num=$((tests_num/TEST_PER_JOB_MAX+1))
if [ $(( tests_num % job_num )) -eq 0 ]; then
tests_per_job=$((tests_num/job_num))
else
tests_per_job=$((tests_num/job_num+1))
fi
fi
spliter_seq=($(seq 1 ${tests_per_job} ${tests_num})) # job的起始test编号
spliter_seq[job_num]=$((tests_num+1)) # 为循环补充一个开点
# 生成job matrix,配置格式为json | 同时打印日志
# {
# "include":[
# {
# "Worker_ID":"1",
# "Sed_Script":"1,11p",
# "First_Job_No":"1"
# },...
# ]
# }
json_content='{"include":['
echo "${tests_num} 条测试任务分 ${job_num} 个作业并行,分工依次为:"
for i in $(seq 1 ${job_num}); do
job_no_from=${spliter_seq[i-1]}
job_no_to=$((spliter_seq[i]-1))
seq_line_from=${title_line_num_list[job_no_from-1]}
seq_line_to=$((title_line_num_list[job_no_to]-1))
[[ $seq_line_to -eq -1 ]] && seq_line_to=${lines_num} # 越界返回0,打个补丁
Sed_Script="${seq_line_from},${seq_line_to}p"
echo "[Job $i]Test ${job_no_from}-${job_no_to}" "|" "行号:${Sed_Script}"
json_content="${json_content}{\"Worker_ID\":\"${i}\",\"Sed_Script\":\"${Sed_Script}\",\"First_Job_No\":\"${job_no_from}\"},"
done
# 去掉最后一个逗号,然后封底
json_content=${json_content%?}']}'
echo "[json_content] ${json_content}"
# 输出到output作为matrix
# echo "::set-output name=json_content::${json_content}"
echo "json_content=${json_content}" >> $GITHUB_OUTPUT
Workers:
runs-on: ubuntu-22.04
needs: Factory
strategy:
matrix: ${{fromJSON(needs.Factory.outputs.matrix)}}
env:
Worker_ID: ${{ matrix.Worker_ID }}
Sed_Script: ${{ matrix.Sed_Script }}
First_Job_No: ${{ matrix.First_Job_No }}
steps:
- uses: actions/checkout@main
- name: Load Environment Variable
id: load_env
run: |
chmod +x $GITHUB_WORKSPACE/device-env.sh
$GITHUB_WORKSPACE/device-env.sh ${{ inputs.device_choice }}
- name: Read Job Sequence
run: |
# 依据作业分配到的行号,截取对应序列输出到文件
sed -n ${Sed_Script} "${SEQ_FILE}" > JobTest.list
# 打印序列信息和目录
echo "====================作业${Worker_ID}测试序列(${Sed_Script})===================="
cat JobTest.list -An
echo "====================测试目录(计数器初始值为${First_Job_No})===================="
grep '@' JobTest.list -n | cat -n
- name: Initialize Environment
env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo rm -rf /etc/apt/sources.list.d/* /usr/share/dotnet /usr/local/lib/android /opt/ghc
sudo -E apt-get -qq update
sudo -E apt-get -qq install $DEPENDS
sudo -E apt-get -qq autoremove --purge
sudo -E apt-get -qq clean
# docker image prune -a -f
sudo timedatectl set-timezone "$TZ"
sudo mkdir -p /workdir
sudo chown $USER:$GROUPS /workdir
- name: Clone Source Code
working-directory: /workdir
run: |
git clone https://github.com/$REPO_USE -b $REPO_BRANCH openwrt
ln -sf /workdir/openwrt $GITHUB_WORKSPACE/openwrt
# 若指定了 commit
if [ "$USE_COMMIT_SHA" != "latest" ]; then
cd openwrt
git checkout "$USE_COMMIT_SHA"
cd ..
fi
echo "[Check disk usage]"
df -hT .
echo "[Check space usage] $PWD"
du -h --max-depth=2
- name: Cache
uses: klever1988/cachewrtbuild@main
if: ${{ inputs.use_cache }}
with:
ccache: 'false'
prefix: ${{ github.workspace }}/openwrt
- name: Load Custom Feeds
run: |
[ -e $FEEDS_CONF ] && mv $FEEDS_CONF openwrt/feeds.conf.default
chmod +x $DIY_P1_SH
cd openwrt
$GITHUB_WORKSPACE/$DIY_P1_SH
- name: Update & Install Feeds
working-directory: /workdir/openwrt
run: |
./scripts/feeds update -a
./scripts/feeds install -a
echo "[Check disk usage]"
df -hT .
echo "[Check space usage] $PWD"
du -h --max-depth=1
- name: Load Custom Configuration and Download Packages
id: download
run: |
[ -e files ] && mv files openwrt/files
# [ -e $CONFIG_FILE ] && mv $CONFIG_FILE openwrt/.config
chmod +x "${DIY_P2_SH}"
cd openwrt
$GITHUB_WORKSPACE/"${DIY_P2_SH}" ${{ inputs.CONFIG_BASE }} # 生成配置基准(.config baseline)
cp -v .config clean.config # 保留副本,每次编译都以此为起点
sed -e '/[@#]/d' $GITHUB_WORKSPACE/JobTest.list >> .config # 去掉标题(@开头)/不勾选(#开头)的行,增补到配置文件以下载全部内容
make defconfig
# 下载包,如若出错生成警告
make download -j8 | tee make_download.log
grep 'ERROR:' make_download.log | xargs -i echo "::warning:: [Download Try 1]" {}
find dl -size -1024c -exec ls -l {} \;
find dl -size -1024c -exec rm -f {} \;
# 二次尝试
grep 'ERROR:' -q make_download.log && make download -j1 V=s | tee make_download.log
grep 'ERROR:' make_download.log | xargs -i echo "::warning:: [Download Try 2]" {}
find dl -size -1024c -exec ls -l {} \;
find dl -size -1024c -exec rm -f {} \;
echo "[Check disk usage]"
df -hT .
echo "[Check space usage] $PWD"
du -h --max-depth=1
- name: Compile & Log Filesize
id: compile
working-directory: /workdir/openwrt
run: |
# 测试序列预处理,去除win换行符中的CR(\r),否则上传artifacts时会出错
sed -i 's/\r//' "${GITHUB_WORKSPACE}/JobTest.list"
# 按标题识别位点'@'切分测试序列,组合成一系列配置文件
(mkdir config_seq; cd config_seq; csplit --prefix=patch "${GITHUB_WORKSPACE}/JobTest.list" /@/ {*} -sz)
# 创建产物目录
ARTIFACTS_DIR=$(mkdir ARTIFACTS_DIR; cd ARTIFACTS_DIR; pwd)
echo "[ARTIFACTS_DIR]${ARTIFACTS_DIR}"
# echo "::set-output name=ARTIFACTS_DIR::${ARTIFACTS_DIR}"
echo "ARTIFACTS_DIR=${ARTIFACTS_DIR}" >> $GITHUB_OUTPUT
# 后台记录CPU占用
mkdir ${ARTIFACTS_DIR}/vmstat_log
vmstat 10 >> ${ARTIFACTS_DIR}/vmstat_log/worker_${Worker_ID}.log &
# 依次执行任务列表
test_no=$((First_Job_No-1)) # 轮次计数器初始化,因为一开始就++所以先-1
for patch_file in config_seq/patch*
do
# 计时起点,启动打点计时器
start_time=$(date +%s)
( while true; do echo "...Timer.$[ $(date +%s)-${start_time} ]s" >&2 && sleep 20; done ) &
TIMER_PID=$!
title=$(head "${patch_file}" -n1) # 原汁原味的标题,保留所有特殊符号
echo "[Test No.$((++test_no))] $title, start at $(date +"%Y-%m-%d %H:%M")"
cp -vf clean.config .config # 起点,重置为基准配置
echo "============[Test $test_no] Patch Content============"
sed '/@/d' "${patch_file}" | tee -a .config # 去掉标题行,增写配置
echo "===============[Test $test_no] .config==============="
bash "$GITHUB_WORKSPACE/conflict-clamer.sh" # 尝试解决一些已知的冲突项
cat .config
echo "==============================================="
# 给测试起个名:测试序号+标题,例:1@ Clean
TEST_NAME="${test_no}${title}"
# 测试成品存放目录
TEST_RESULT_DIR="${ARTIFACTS_DIR}/${TEST_NAME}"
mkdir "${TEST_RESULT_DIR}"
echo "[TEST_RESULT_DIR] ${TEST_RESULT_DIR}"
# 测试日志文件
TEST_LOG_FILE="${TEST_RESULT_DIR}/${TEST_NAME}_compile.log"
SIZE_LOG_FILE="${TEST_RESULT_DIR}/${TEST_NAME}_size.log"
cp -v "$patch_file" "${TEST_RESULT_DIR}/config.patch"
echo "[TEST_LOG_FILE] ${TEST_LOG_FILE}"
# 补全默认值
make defconfig
# 分析配置文件是否包含补丁
subset_check=$(comm -23 <(sed '/@/d' "${patch_file}" | sort | uniq) <(sort .config | uniq) | tee .notfound)
if [[ -z $subset_check ]]; then
echo 补丁是 .conifg 的子集
else
echo 补丁不是 .conifg 的子集!以下 patch 行未在 .config 中找到
cat .notfound
echo "=====================EOF======================="
echo "::warning title=Test ${test_no} ${title}:: Patch is not a subset of .config, please check..."
fi
# 执行编译
echo "[Test ${test_no}] Try $(($(nproc)+1)) thread compile first" | tee "$TEST_LOG_FILE"
# try
( make -j $(($(nproc)+1)) || make -j1 || make -j1 V=s ) 2>&1 | tee -a "$TEST_LOG_FILE"
# 根据第一节管道返回值判断编译结果
if [ ${PIPESTATUS[0]} -ne 0 ]; then
# Exception
echo "::error title=[${test_no} ${title}] Test Failed:: Error(s) occurred during compile, please check..."
touch "${TEST_RESULT_DIR}/test_failed"
# 保留配置文件
mv -v .config "${TEST_RESULT_DIR}/"
else
# no Exception
echo "[Test ${test_no}] Compile success..."
echo 'in path ' ./bin/targets/*/*
ls -lah ./bin/targets/*/*
echo "==============================================="
# 截取bytes换算为MB(精度-两位小数),记录到文件
echo "[Test ${test_no}] Logging filesize..."
du -ab --max-depth=1 ./bin/targets/*/* | awk '{printf "%8.2fM",$1/2^20; $1=""; print}' | tee "${SIZE_LOG_FILE}"
# 复制保留有用文件
# ./bin/targets/ramips/mt7621/packages
mv -v .config ./bin/targets/*/*/*.{buildinfo,manifest} "${TEST_RESULT_DIR}/"
cp -urv --parents ./bin/targets/*/*/packages "${ARTIFACTS_DIR}" # 不移走会被覆盖/删除掉
# bin太大不留了,连带其校验码文件删除
echo "[Test ${test_no}] Cleaning for the next test..."
rm -v ./bin/targets/*/*/*.bin ./bin/targets/*/*/sha256sums
echo "[Test $test_no] --Finished--" $(date +"%Y-%m-%d %H:%M")
fi
# 计时终点,关闭打点计时器
kill -15 $TIMER_PID
end_time=$(date +%s)
cost_time=$[ ${end_time}-${start_time} ]
echo "==============================================="
echo -ne "Start Time:\t${start_time}\nEnd Time:\t${end_time}\nCost Time:\t${cost_time}\n" | tee "${TEST_RESULT_DIR}/Timer.log"
echo "==============================================="
done
find ./bin/targets/*/* -maxdepth 1 -type f -exec rm -v {} \;
# 保留所有的ipk
cp -uvr ./bin "${ARTIFACTS_DIR}/"
# 保留测试序列和DIY脚本2
cp -v "${GITHUB_WORKSPACE}/${SEQ_FILE}" ${GITHUB_WORKSPACE}/"${DIY_P2_SH}" "${ARTIFACTS_DIR}/"
echo "[Check disk usage]"
df -hT .
echo "[Check space usage] $PWD"
du -h --max-depth=1
echo "------------------------End of Job------------------------"
- name: Upload Artifact Directory
uses: actions/upload-artifact@main
# if: steps.compile.conclusion == 'success'
with:
name: SizeTest_${{ inputs.CONFIG_BASE }}_${{ needs.Factory.outputs.TimeStamp }}
path: ${{ steps.compile.outputs.ARTIFACTS_DIR }}
- name: SSH Debug
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: false
if: ${{ failure() }}
delete-workflow-run:
runs-on: ubuntu-latest
needs: Workers
if: ${{ always() }}
steps:
- uses: Mattraks/delete-workflow-runs@main
with:
retain_days: 30
keep_minimum_runs: 5