name: Check cpp / md pair on: push: paths: - '*.cpp' - '*.md' permissions: contents: read jobs: check-md-header: name: Check markdown header runs-on: ubuntu-latest outputs: has_cpp: ${{ steps.check.outputs.has_cpp }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Validate md first line id: check run: | set -euo pipefail # 收集根目录下所有 .cpp / .md 文件(不含子目录) mapfile -t CPP_FILES < <(find . -maxdepth 1 -name '*.cpp' -type f | sed 's|^\./||' | sort) mapfile -t MD_FILES < <(find . -maxdepth 1 -name '*.md' -type f | sed 's|^\./||' | sort) CPP_COUNT=${#CPP_FILES[@]} MD_COUNT=${#MD_FILES[@]} echo "根目录下 .cpp 文件数: ${CPP_COUNT}" echo "根目录下 .md 文件数: ${MD_COUNT}" # 情况 1:仅有 cpp 无 md —— 输出日志后跳过 if [ "$CPP_COUNT" -gt 0 ] && [ "$MD_COUNT" -eq 0 ]; then echo "本次 push 根目录下仅有 .cpp 文件而无 .md 文件,跳过 md 首行配对检查。" echo "has_cpp=true" >> "$GITHUB_OUTPUT" exit 0 fi # 情况 2:仅有 md 无 cpp —— 同样跳过,且不检查 md 首行 if [ "$MD_COUNT" -gt 0 ] && [ "$CPP_COUNT" -eq 0 ]; then echo "本次 push 根目录下仅有 .md 文件而无 .cpp 文件,跳过 md 首行配对检查。" echo "has_cpp=false" >> "$GITHUB_OUTPUT" exit 0 fi # 情况 3:两者都不存在 —— 跳过 if [ "$CPP_COUNT" -eq 0 ] && [ "$MD_COUNT" -eq 0 ]; then echo "根目录下没有 .cpp/.md 文件,跳过检查。" echo "has_cpp=false" >> "$GITHUB_OUTPUT" exit 0 fi # 情况 4:cpp 和 md 都存在 —— 只检查每个 md 的首行 echo "has_cpp=true" >> "$GITHUB_OUTPUT" EXIT_CODE=0 for md_file in "${MD_FILES[@]}"; do base=$(basename "$md_file" .md) FIRST_LINE=$(head -n 1 "$md_file") if [[ "$FIRST_LINE" != "# ${base} "* ]]; then echo "::error file=${md_file},line=1::Markdown 第一行格式错误。期望以 '# ${base} ' 开头,实际为: ${FIRST_LINE}" EXIT_CODE=1 else echo "✅ ${md_file} 第一行格式正确: ${FIRST_LINE}" fi done exit $EXIT_CODE analyze: needs: check-md-header if: ${{ needs.check-md-header.outputs.has_cpp == 'true' && success() }} uses: ./.github/workflows/analyze.yml