Compare commits
No commits in common. "1259495cbb0ebccd0972df1c0817b53e8e6e7736" and "0579c2dc9754b67148cf4d2fe057a163f6e4483a" have entirely different histories.
1259495cbb
...
0579c2dc97
|
|
@ -50,6 +50,14 @@ build_mirror_path() {
|
|||
printf '%s/%s/%s.git\n' "${mirror_root}" "${owner}" "${repo_name}"
|
||||
}
|
||||
|
||||
build_mirror_lock_path() {
|
||||
local mirror_root=$1
|
||||
local owner=$2
|
||||
local repo_name=$3
|
||||
|
||||
printf '%s.lock\n' "$(build_mirror_path "${mirror_root}" "${owner}" "${repo_name}")"
|
||||
}
|
||||
|
||||
build_job_workspace_root() {
|
||||
local workspace_root=$1
|
||||
local owner=$2
|
||||
|
|
|
|||
|
|
@ -1,243 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import unicodedata
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
|
||||
LABEL_BG = "#555555"
|
||||
DEFAULT_TOTAL_COLOR = "#1f6feb"
|
||||
DEFAULT_FILES_COLOR = "#2da44e"
|
||||
DEFAULT_LANGUAGE_COUNT_COLOR = "#8250df"
|
||||
TEXT_COLOR = "#ffffff"
|
||||
|
||||
|
||||
@dataclass
|
||||
class LanguageStat:
|
||||
lang_id: str
|
||||
display_name: str
|
||||
code_lines: int
|
||||
formatted_lines: str
|
||||
file_count: int
|
||||
color: str
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--output-dir", required=True)
|
||||
parser.add_argument("--readme-path", required=True)
|
||||
parser.add_argument("--repo", required=True)
|
||||
parser.add_argument("--generated-by", required=True)
|
||||
parser.add_argument("--updated-at", required=True)
|
||||
parser.add_argument("--total-color", default=DEFAULT_TOTAL_COLOR)
|
||||
parser.add_argument("--files-color", default=DEFAULT_FILES_COLOR)
|
||||
parser.add_argument("--language-count-color", default=DEFAULT_LANGUAGE_COUNT_COLOR)
|
||||
parser.add_argument("--total-code", required=True, type=int)
|
||||
parser.add_argument("--formatted-total-code", required=True)
|
||||
parser.add_argument("--total-files", required=True, type=int)
|
||||
parser.add_argument("--formatted-total-files", required=True)
|
||||
parser.add_argument("--language-count", required=True, type=int)
|
||||
parser.add_argument("--exclude-dirs", required=True)
|
||||
parser.add_argument("--min-lines-threshold", required=True, type=int)
|
||||
parser.add_argument("--lang-summary", required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def escape_xml(value: str) -> str:
|
||||
return (
|
||||
value.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace('"', """)
|
||||
.replace("'", "'")
|
||||
)
|
||||
|
||||
|
||||
def display_units(value: str) -> int:
|
||||
units = 0
|
||||
for char in value:
|
||||
if unicodedata.east_asian_width(char) in {"F", "W"}:
|
||||
units += 2
|
||||
else:
|
||||
units += 1
|
||||
return units
|
||||
|
||||
|
||||
def text_width(value: str) -> int:
|
||||
return display_units(value) * 7 + 20
|
||||
|
||||
|
||||
def normalize_color(value: str, fallback: str) -> str:
|
||||
if not value:
|
||||
return fallback
|
||||
return value if value.startswith("#") else f"#{value}"
|
||||
|
||||
|
||||
def parse_language_summary(path: Path) -> List[LanguageStat]:
|
||||
stats: List[LanguageStat] = []
|
||||
|
||||
if not path.exists():
|
||||
return stats
|
||||
|
||||
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
||||
line = raw_line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
parts = line.split("|")
|
||||
if len(parts) < 6:
|
||||
continue
|
||||
|
||||
while len(parts) < 7:
|
||||
parts.append("")
|
||||
|
||||
lang_id, display_name, code_lines, formatted_lines, file_count, color, _icon = parts[:7]
|
||||
stats.append(
|
||||
LanguageStat(
|
||||
lang_id=lang_id,
|
||||
display_name=display_name,
|
||||
code_lines=int(code_lines),
|
||||
formatted_lines=formatted_lines,
|
||||
file_count=int(file_count),
|
||||
color=normalize_color(color, DEFAULT_TOTAL_COLOR),
|
||||
)
|
||||
)
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
def badge_svg(label: str, message: str, color: str) -> str:
|
||||
height = 20
|
||||
left_width = max(46, text_width(label))
|
||||
right_width = max(46, text_width(message))
|
||||
total_width = left_width + right_width
|
||||
left_text_x = left_width / 2
|
||||
right_text_x = left_width + right_width / 2
|
||||
|
||||
return f"""<svg xmlns="http://www.w3.org/2000/svg" width="{total_width}" height="{height}" role="img" aria-label="{escape_xml(label)}: {escape_xml(message)}">
|
||||
<title>{escape_xml(label)}: {escape_xml(message)}</title>
|
||||
<rect width="{left_width}" height="{height}" fill="{LABEL_BG}" />
|
||||
<rect x="{left_width}" width="{right_width}" height="{height}" fill="{escape_xml(color)}" />
|
||||
<rect width="{total_width}" height="{height}" rx="3" fill="transparent" />
|
||||
<g fill="{TEXT_COLOR}" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
||||
<text x="{left_text_x:.1f}" y="14">{escape_xml(label)}</text>
|
||||
<text x="{right_text_x:.1f}" y="14">{escape_xml(message)}</text>
|
||||
</g>
|
||||
</svg>
|
||||
"""
|
||||
|
||||
|
||||
def write_badge(path: Path, label: str, message: str, color: str) -> None:
|
||||
path.write_text(badge_svg(label, message, color), encoding="utf-8")
|
||||
|
||||
|
||||
def render_readme(args: argparse.Namespace, languages: List[LanguageStat], badge_dir_name: str) -> str:
|
||||
language_rows = []
|
||||
|
||||
for stat in languages:
|
||||
share = (stat.code_lines * 100 / args.total_code) if args.total_code else 0.0
|
||||
language_rows.append(
|
||||
f"| **{stat.display_name}** | {stat.formatted_lines} | {stat.file_count} | {share:.1f}% | "
|
||||
f" |"
|
||||
)
|
||||
|
||||
if language_rows:
|
||||
language_table = "\n".join(language_rows)
|
||||
else:
|
||||
language_table = "| _未找到符合条件的语言_ | - | - | - | - |"
|
||||
|
||||
return f"""# 📊 代码统计详细报告
|
||||
|
||||
> 此分支由 {args.generated_by} 自动生成和维护
|
||||
>
|
||||
> ⚠️ **请勿手动修改此分支的内容!**
|
||||
>
|
||||
> 🤖 由 {args.generated_by} 自动生成
|
||||
>
|
||||
> 📅 更新时间: {args.updated_at}
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## 📈 总体统计
|
||||
|
||||
| 统计项 | 数值 | 徽章 |
|
||||
|--------|------|------|
|
||||
| 💻 总代码行数 | **{args.formatted_total_code}** 行 |  |
|
||||
| 📁 总文件数 | **{args.formatted_total_files}** 个 |  |
|
||||
| 🌐 语言种类 | **{args.language_count}** 种 |  |
|
||||
|
||||
## 🌈 语言分布
|
||||
|
||||
| 语言 | 代码行数 | 文件数 | 占比 | 徽章 |
|
||||
|------|----------|--------|------|------|
|
||||
{language_table}
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 配置说明
|
||||
|
||||
### Token 配置
|
||||
|
||||
- 当前使用: **WORKFLOW**
|
||||
- 需要在 Settings -> Actions -> Secrets 中配置 `WORKFLOW`
|
||||
|
||||
### 排除规则
|
||||
|
||||
当前排除的目录:
|
||||
```
|
||||
{args.exclude_dirs}
|
||||
```
|
||||
|
||||
### 阈值设置
|
||||
|
||||
- 最小代码行数阈值: **{args.min_lines_threshold}** 行
|
||||
- 低于此阈值的语言不会生成徽章
|
||||
|
||||
---
|
||||
|
||||
*📊 统计仓库:`{args.repo}`*
|
||||
"""
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
output_dir = Path(args.output_dir)
|
||||
readme_path = Path(args.readme_path)
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
readme_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
languages = parse_language_summary(Path(args.lang_summary))
|
||||
badge_dir_name = output_dir.name
|
||||
|
||||
write_badge(
|
||||
output_dir / "total-lines.svg",
|
||||
"代码",
|
||||
f"{args.formatted_total_code} 行",
|
||||
normalize_color(args.total_color, DEFAULT_TOTAL_COLOR),
|
||||
)
|
||||
write_badge(
|
||||
output_dir / "total-files.svg",
|
||||
"文件",
|
||||
f"{args.formatted_total_files} 个",
|
||||
normalize_color(args.files_color, DEFAULT_FILES_COLOR),
|
||||
)
|
||||
write_badge(
|
||||
output_dir / "language-count.svg",
|
||||
"语言",
|
||||
f"{args.language_count} 种",
|
||||
normalize_color(args.language_count_color, DEFAULT_LANGUAGE_COUNT_COLOR),
|
||||
)
|
||||
|
||||
for stat in languages:
|
||||
write_badge(output_dir / f"{stat.lang_id}-lines.svg", stat.display_name, f"{stat.formatted_lines} 行", stat.color)
|
||||
|
||||
readme_path.write_text(render_readme(args, languages, badge_dir_name), encoding="utf-8")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -35,12 +35,17 @@ env:
|
|||
SPECIAL_INCLUDES: ""
|
||||
# 示例: 'dist:js,css|vendor:go,mod'
|
||||
|
||||
# ===== SVG 徽章颜色配置 =====
|
||||
# ===== 徽章颜色配置 =====
|
||||
COLOR_TOTAL: "blue"
|
||||
COLOR_FILES: "green"
|
||||
COLOR_LANGUAGE_COUNT: "purple"
|
||||
COLOR_DEFAULT: "brightgreen"
|
||||
|
||||
# ===== 徽章样式配置 =====
|
||||
BADGE_STYLE: "flat" # 可选: flat, flat-square, plastic, for-the-badge, social
|
||||
|
||||
# ===== 输出配置 =====
|
||||
# 是否生成详细报告
|
||||
GENERATE_DETAILED_REPORT: "true"
|
||||
# 是否输出到 workflow summary
|
||||
OUTPUT_TO_SUMMARY: "true"
|
||||
# 最小代码行数阈值(低于此值的语言不生成徽章)
|
||||
|
|
@ -50,6 +55,18 @@ env:
|
|||
GIT_USER_NAME: "ci[bot]"
|
||||
GIT_USER_EMAIL: "ci[bot]@tinysoft.com.cn"
|
||||
|
||||
# ===== 平台配置 =====
|
||||
# 平台类型: github 或 gitea
|
||||
PLATFORM: "gitea"
|
||||
# Git 服务器 URL(Gitea 示例: https://gitea.example.com)
|
||||
GIT_SERVER_URL: "${{ github.server_url }}"
|
||||
# 仓库路径(格式: owner/repo)
|
||||
REPO_PATH: "${{ github.repository }}"
|
||||
# Raw 文件基础 URL
|
||||
# GitHub: https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path}
|
||||
# Gitea: https://gitea.example.com/{owner}/{repo}/raw/branch/{branch}/{path}
|
||||
RAW_URL_BASE: '${{ github.server_url }}/${{ github.repository }}/raw/branch'
|
||||
|
||||
# ==========================================
|
||||
# 🎨 语言分组配置
|
||||
# 格式: 组名:后缀列表:显示名称:颜色:图标(可选)
|
||||
|
|
@ -346,19 +363,19 @@ jobs:
|
|||
cat > README.md << 'EOF'
|
||||
# 📊 代码统计徽章数据
|
||||
|
||||
> 此分支由 Gitea Actions 自动生成和维护
|
||||
> 此分支由 GitHub Actions 自动生成和维护
|
||||
>
|
||||
> ⚠️ **请勿手动修改此分支的内容!**
|
||||
|
||||
## 📁 目录结构
|
||||
|
||||
```
|
||||
README.md # 详细统计报告
|
||||
badges/
|
||||
├── total-lines.svg # 总代码行数徽章
|
||||
├── total-files.svg # 总文件数徽章
|
||||
├── language-count.svg # 语言种类徽章
|
||||
└── {language}-lines.svg # 各语言代码行数徽章
|
||||
├── total-lines.json # 总代码行数徽章
|
||||
├── total-files.json # 总文件数徽章
|
||||
├── {language}-lines.json # 各语言代码行数徽章
|
||||
├── {language}-files.json # 各语言文件数徽章
|
||||
└── README.md # 详细统计报告
|
||||
```
|
||||
|
||||
## 🔄 更新机制
|
||||
|
|
@ -372,7 +389,7 @@ jobs:
|
|||
|
||||
---
|
||||
|
||||
*🤖 由 Gitea Actions 自动维护*
|
||||
*🤖 由 GitHub Actions 自动维护*
|
||||
EOF
|
||||
|
||||
# 创建徽章目录
|
||||
|
|
@ -416,20 +433,20 @@ jobs:
|
|||
echo ""
|
||||
|
||||
# 构建排除参数
|
||||
EXCLUDE_FIND_ARGS=()
|
||||
EXCLUDE_PARAMS=""
|
||||
IFS=',' read -ra EXCLUDES <<< "${{ env.EXCLUDE_DIRS }}"
|
||||
for dir in "${EXCLUDES[@]}"; do
|
||||
EXCLUDE_FIND_ARGS+=(-not -path "*/$dir/*")
|
||||
EXCLUDE_PARAMS="$EXCLUDE_PARAMS -not -path '*/$dir/*'"
|
||||
done
|
||||
|
||||
# 获取所有文件
|
||||
echo "🔍 扫描文件..."
|
||||
|
||||
# 统计总文件数
|
||||
TOTAL_FILES=$(find . -type f "${EXCLUDE_FIND_ARGS[@]}" | wc -l)
|
||||
TOTAL_FILES=$(eval "find . -type f $EXCLUDE_PARAMS" | wc -l)
|
||||
|
||||
# 统计总代码行数(排除空行)
|
||||
TOTAL_CODE=$(find . -type f "${EXCLUDE_FIND_ARGS[@]}" -exec grep -cHv '^[[:space:]]*$' {} + 2>/dev/null | awk -F: '{sum+=$2} END {print sum+0}')
|
||||
TOTAL_CODE=$(eval "find . -type f $EXCLUDE_PARAMS -exec grep -cHv '^[[:space:]]*$' {} + 2>/dev/null" | awk -F: '{sum+=$2} END {print sum+0}')
|
||||
|
||||
echo "📊 统计结果:"
|
||||
echo " - 总文件数: $TOTAL_FILES"
|
||||
|
|
@ -472,10 +489,10 @@ jobs:
|
|||
mkdir -p /tmp/lang_stats
|
||||
|
||||
# 构建排除参数
|
||||
EXCLUDE_FIND_ARGS=()
|
||||
EXCLUDE_PARAMS=""
|
||||
IFS=',' read -ra EXCLUDES <<< "${{ env.EXCLUDE_DIRS }}"
|
||||
for dir in "${EXCLUDES[@]}"; do
|
||||
EXCLUDE_FIND_ARGS+=(-not -path "*/$dir/*")
|
||||
EXCLUDE_PARAMS="$EXCLUDE_PARAMS -not -path '*/$dir/*'"
|
||||
done
|
||||
|
||||
LANGUAGE_COUNT=0
|
||||
|
|
@ -490,22 +507,22 @@ jobs:
|
|||
echo "🔍 统计 $display_name..."
|
||||
|
||||
# 构建扩展名查找条件
|
||||
LANG_FIND_ARGS=()
|
||||
FIND_CONDITIONS=""
|
||||
IFS=',' read -ra EXTS <<< "$extensions"
|
||||
for ext in "${EXTS[@]}"; do
|
||||
if [ "${#LANG_FIND_ARGS[@]}" -eq 0 ]; then
|
||||
LANG_FIND_ARGS+=(-name "*.$ext")
|
||||
if [ -z "$FIND_CONDITIONS" ]; then
|
||||
FIND_CONDITIONS="-name '*.$ext'"
|
||||
else
|
||||
LANG_FIND_ARGS+=(-o -name "*.$ext")
|
||||
FIND_CONDITIONS="$FIND_CONDITIONS -o -name '*.$ext'"
|
||||
fi
|
||||
done
|
||||
|
||||
# 统计文件数
|
||||
FILE_COUNT=$(find . -type f \( "${LANG_FIND_ARGS[@]}" \) "${EXCLUDE_FIND_ARGS[@]}" | wc -l)
|
||||
FILE_COUNT=$(eval "find . -type f \( $FIND_CONDITIONS \) $EXCLUDE_PARAMS" | wc -l)
|
||||
|
||||
if [ "$FILE_COUNT" -gt 0 ]; then
|
||||
# 统计代码行数
|
||||
CODE_LINES=$(find . -type f \( "${LANG_FIND_ARGS[@]}" \) "${EXCLUDE_FIND_ARGS[@]}" -exec grep -cHv '^[[:space:]]*$' {} + 2>/dev/null | awk -F: '{sum+=$2} END {print sum+0}')
|
||||
CODE_LINES=$(eval "find . -type f \( $FIND_CONDITIONS \) $EXCLUDE_PARAMS -exec grep -cHv '^[[:space:]]*$' {} + 2>/dev/null" | awk -F: '{sum+=$2} END {print sum+0}')
|
||||
|
||||
# 只保存超过阈值的语言
|
||||
if [ "$CODE_LINES" -ge "${{ env.MIN_LINES_THRESHOLD }}" ]; then
|
||||
|
|
@ -538,50 +555,212 @@ jobs:
|
|||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
- name: 🎨 生成 SVG 徽章与统计报告
|
||||
- name: 🎨 生成徽章数据
|
||||
id: generate_badges
|
||||
run: |
|
||||
echo "======================================"
|
||||
echo "🎨 生成 SVG 徽章与统计报告"
|
||||
echo "🎨 生成徽章数据"
|
||||
echo "======================================"
|
||||
|
||||
cd "${{ env.REPO_DIR }}"
|
||||
|
||||
# 在主分支渲染产物,避免依赖 stats 分支中的脚本文件
|
||||
git checkout ${{ github.ref_name }}
|
||||
|
||||
RENDER_ROOT=$(mktemp -d)
|
||||
UPDATED_AT=$(date -u '+%Y-%m-%d %H:%M:%S UTC')
|
||||
|
||||
python3 .gitea/ci/render_stats_svgs.py \
|
||||
--output-dir "$RENDER_ROOT/${{ env.BADGE_DIR }}" \
|
||||
--readme-path "$RENDER_ROOT/README.md" \
|
||||
--repo "${{ github.repository }}" \
|
||||
--generated-by "Gitea Actions" \
|
||||
--updated-at "$UPDATED_AT" \
|
||||
--total-color "${{ env.COLOR_TOTAL }}" \
|
||||
--files-color "${{ env.COLOR_FILES }}" \
|
||||
--language-count-color "${{ env.COLOR_LANGUAGE_COUNT }}" \
|
||||
--total-code "${{ steps.total.outputs.total_code }}" \
|
||||
--formatted-total-code "${{ steps.total.outputs.formatted_code }}" \
|
||||
--total-files "${{ steps.total.outputs.total_files }}" \
|
||||
--formatted-total-files "${{ steps.total.outputs.formatted_files }}" \
|
||||
--language-count "${{ steps.languages.outputs.language_count }}" \
|
||||
--exclude-dirs "${{ env.EXCLUDE_DIRS }}" \
|
||||
--min-lines-threshold "${{ env.MIN_LINES_THRESHOLD }}" \
|
||||
--lang-summary /tmp/lang_summary.txt
|
||||
|
||||
# 确保在统计分支
|
||||
git checkout ${{ env.BADGE_BRANCH }}
|
||||
rm -rf "${{ env.BADGE_DIR }}"
|
||||
mkdir -p "${{ env.BADGE_DIR }}"
|
||||
cp -f "$RENDER_ROOT/README.md" README.md
|
||||
cp -f "$RENDER_ROOT/${{ env.BADGE_DIR }}"/* "${{ env.BADGE_DIR }}/"
|
||||
GENERATED_COUNT=$(find "$RENDER_ROOT/${{ env.BADGE_DIR }}" -maxdepth 1 -type f | wc -l | tr -d ' ')
|
||||
rm -rf "$RENDER_ROOT"
|
||||
|
||||
# 确保徽章目录存在
|
||||
mkdir -p ${{ env.BADGE_DIR }}
|
||||
|
||||
GENERATED_COUNT=0
|
||||
|
||||
# 生成总代码行数徽章
|
||||
echo "📊 生成总代码行数徽章..."
|
||||
cat > ${{ env.BADGE_DIR }}/total-lines.json << EOF
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "代码",
|
||||
"message": "${{ steps.total.outputs.formatted_code }} 行",
|
||||
"color": "${{ env.COLOR_TOTAL }}",
|
||||
"style": "${{ env.BADGE_STYLE }}"
|
||||
}
|
||||
EOF
|
||||
GENERATED_COUNT=$((GENERATED_COUNT + 1))
|
||||
|
||||
# 生成总文件数徽章
|
||||
echo "📁 生成总文件数徽章..."
|
||||
cat > ${{ env.BADGE_DIR }}/total-files.json << EOF
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "文件",
|
||||
"message": "${{ steps.total.outputs.formatted_files }} 个",
|
||||
"color": "${{ env.COLOR_FILES }}",
|
||||
"style": "${{ env.BADGE_STYLE }}"
|
||||
}
|
||||
EOF
|
||||
GENERATED_COUNT=$((GENERATED_COUNT + 1))
|
||||
|
||||
# 生成各语言徽章
|
||||
if [ -f /tmp/lang_summary.txt ] && [ -s /tmp/lang_summary.txt ]; then
|
||||
echo ""
|
||||
echo "🌐 生成语言徽章..."
|
||||
|
||||
while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do
|
||||
[ -z "$lang_id" ] && continue
|
||||
|
||||
echo " - $display_name"
|
||||
|
||||
# 生成代码行数徽章(使用 heredoc)
|
||||
if [ -n "$icon" ]; then
|
||||
# 带图标的徽章
|
||||
cat > ${{ env.BADGE_DIR }}/${lang_id}-lines.json << EOFJSON
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "$display_name",
|
||||
"message": "$formatted_lines 行",
|
||||
"color": "$color",
|
||||
"style": "${{ env.BADGE_STYLE }}",
|
||||
"namedLogo": "$icon"
|
||||
}
|
||||
EOFJSON
|
||||
else
|
||||
# 不带图标的徽章
|
||||
cat > ${{ env.BADGE_DIR }}/${lang_id}-lines.json << EOFJSON
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "$display_name",
|
||||
"message": "$formatted_lines 行",
|
||||
"color": "$color",
|
||||
"style": "${{ env.BADGE_STYLE }}"
|
||||
}
|
||||
EOFJSON
|
||||
fi
|
||||
GENERATED_COUNT=$((GENERATED_COUNT + 1))
|
||||
|
||||
# 生成文件数徽章
|
||||
cat > ${{ env.BADGE_DIR }}/${lang_id}-files.json << EOFJSON
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "$display_name 文件",
|
||||
"message": "$file_count 个",
|
||||
"color": "$color",
|
||||
"style": "${{ env.BADGE_STYLE }}"
|
||||
}
|
||||
EOFJSON
|
||||
GENERATED_COUNT=$((GENERATED_COUNT + 1))
|
||||
done < /tmp/lang_summary.txt
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "generated_count=$GENERATED_COUNT" >> $GITHUB_OUTPUT
|
||||
echo "✅ 已生成 $GENERATED_COUNT 个 SVG 徽章"
|
||||
echo "✅ 已生成 $GENERATED_COUNT 个徽章"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
- name: 📝 生成详细统计报告
|
||||
if: env.GENERATE_DETAILED_REPORT == 'true'
|
||||
run: |
|
||||
echo "======================================"
|
||||
echo "📝 生成详细统计报告"
|
||||
echo "======================================"
|
||||
|
||||
cd "${{ env.REPO_DIR }}"
|
||||
|
||||
# 确保在统计分支
|
||||
git checkout ${{ env.BADGE_BRANCH }}
|
||||
|
||||
# 生成 README
|
||||
cat > ${{ env.BADGE_DIR }}/README.md << 'EOFMD'
|
||||
# 📊 代码统计详细报告
|
||||
|
||||
> 🤖 由 GitHub Actions 自动生成
|
||||
>
|
||||
> 📅 更新时间: TIMESTAMP_PLACEHOLDER
|
||||
|
||||
## 📈 总体统计
|
||||
|
||||
| 统计项 | 数值 | 徽章 |
|
||||
|--------|------|------|
|
||||
| 💻 总代码行数 | **TOTAL_CODE_PLACEHOLDER** 行 |  |
|
||||
| 📁 总文件数 | **TOTAL_FILES_PLACEHOLDER** 个 |  |
|
||||
| 🌐 语言种类 | **LANG_COUNT_PLACEHOLDER** 种 | - |
|
||||
|
||||
## 🌈 语言分布
|
||||
|
||||
EOFMD
|
||||
|
||||
# 替换占位符
|
||||
sed -i "s|TIMESTAMP_PLACEHOLDER|$(date -u '+%Y-%m-%d %H:%M:%S UTC')|g" ${{ env.BADGE_DIR }}/README.md
|
||||
sed -i "s|TOTAL_CODE_PLACEHOLDER|${{ steps.total.outputs.formatted_code }}|g" ${{ env.BADGE_DIR }}/README.md
|
||||
sed -i "s|TOTAL_FILES_PLACEHOLDER|${{ steps.total.outputs.formatted_files }}|g" ${{ env.BADGE_DIR }}/README.md
|
||||
sed -i "s|LANG_COUNT_PLACEHOLDER|${{ steps.languages.outputs.language_count }}|g" ${{ env.BADGE_DIR }}/README.md
|
||||
sed -i "s|REPO_PLACEHOLDER|${{ github.repository }}|g" ${{ env.BADGE_DIR }}/README.md
|
||||
sed -i "s|BRANCH_PLACEHOLDER|${{ env.BADGE_BRANCH }}|g" ${{ env.BADGE_DIR }}/README.md
|
||||
sed -i "s|BADGE_DIR_PLACEHOLDER|${{ env.BADGE_DIR }}|g" ${{ env.BADGE_DIR }}/README.md
|
||||
sed -i "s|RAW_URL_PLACEHOLDER|${{ env.RAW_URL_BASE }}|g" ${{ env.BADGE_DIR }}/README.md
|
||||
|
||||
# 添加语言统计表格
|
||||
if [ -f /tmp/lang_summary.txt ] && [ -s /tmp/lang_summary.txt ]; then
|
||||
cat >> ${{ env.BADGE_DIR }}/README.md << 'EOFTABLE'
|
||||
| 语言 | 代码行数 | 文件数 | 占比 | 徽章 |
|
||||
|------|----------|--------|------|------|
|
||||
EOFTABLE
|
||||
|
||||
TOTAL_CODE=${{ steps.total.outputs.total_code }}
|
||||
while IFS='|' read -r lang_id display_name code_lines formatted_lines file_count color icon; do
|
||||
[ -z "$lang_id" ] && continue
|
||||
|
||||
if [ "$TOTAL_CODE" -gt 0 ]; then
|
||||
PERCENT=$(echo "scale=1; $code_lines * 100 / $TOTAL_CODE" | bc)
|
||||
else
|
||||
PERCENT="0.0"
|
||||
fi
|
||||
|
||||
cat >> ${{ env.BADGE_DIR }}/README.md << EOFLANG
|
||||
| **${display_name}** | ${formatted_lines} | ${file_count} | ${PERCENT}% |  |
|
||||
EOFLANG
|
||||
done < /tmp/lang_summary.txt
|
||||
fi
|
||||
|
||||
# 添加配置说明
|
||||
cat >> ${{ env.BADGE_DIR }}/README.md << EOFMD
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 配置说明
|
||||
|
||||
### Token 配置
|
||||
|
||||
- 当前使用: **${{ steps.validate_token.outputs.token_type }}**
|
||||
- 需要在 Settings -> Secrets 中配置 `WORKFLOW`
|
||||
|
||||
### 排除规则
|
||||
|
||||
当前排除的目录:
|
||||
```
|
||||
${{ env.EXCLUDE_DIRS }}
|
||||
```
|
||||
|
||||
### 阈值设置
|
||||
|
||||
- 最小代码行数阈值: **${{ env.MIN_LINES_THRESHOLD }}** 行
|
||||
- 低于此阈值的语言将不会生成徽章
|
||||
|
||||
### 徽章样式
|
||||
|
||||
- 当前样式: **${{ env.BADGE_STYLE }}**
|
||||
- 可选样式: flat, flat-square, plastic, for-the-badge, social
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
*📊 由 [GitHub Actions](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions) 自动生成和更新*
|
||||
|
||||
*🤖 生成时间: $(date -u '+%Y-%m-%d %H:%M:%S UTC')*
|
||||
|
||||
</div>
|
||||
EOFMD
|
||||
|
||||
echo "✅ 详细统计报告已生成"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
|
|
@ -602,7 +781,7 @@ jobs:
|
|||
git config user.email "${{ env.GIT_USER_EMAIL }}"
|
||||
|
||||
# 添加所有更改
|
||||
git add README.md ${{ env.BADGE_DIR }}/
|
||||
git add ${{ env.BADGE_DIR }}/
|
||||
|
||||
# 检查是否有变更
|
||||
if git diff --staged --quiet; then
|
||||
|
|
@ -622,7 +801,7 @@ jobs:
|
|||
- 徽章数: ${{ steps.generate_badges.outputs.generated_count }} 个
|
||||
|
||||
🔗 触发提交: ${GITHUB_SHA:0:7}
|
||||
🤖 由 Gitea Actions 自动生成"
|
||||
🤖 由 GitHub Actions 自动生成"
|
||||
|
||||
git commit -m "$COMMIT_MSG"
|
||||
|
||||
|
|
@ -663,7 +842,7 @@ jobs:
|
|||
|
||||
## 🔗 快速链接
|
||||
|
||||
- 📊 [查看详细统计报告](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/README.md)
|
||||
- 📊 [查看详细统计报告](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/README.md)
|
||||
- 🎨 [浏览徽章文件](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }})
|
||||
- 🔧 [查看 Workflow 配置](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ github.ref_name }}/.gitea/workflows/update_stats_badge.yaml)
|
||||
|
||||
|
|
@ -745,7 +924,7 @@ jobs:
|
|||
echo " - 统计分支: ${{ env.BADGE_BRANCH }}"
|
||||
echo ""
|
||||
echo "🔗 查看详细报告:"
|
||||
echo " ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/README.md"
|
||||
echo " ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}/README.md"
|
||||
echo ""
|
||||
echo "🎨 徽章目录:"
|
||||
echo " ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }}"
|
||||
|
|
@ -778,7 +957,7 @@ jobs:
|
|||
if: always()
|
||||
run: |
|
||||
echo "🧹 清理临时文件..."
|
||||
rm -rf /tmp/lang_stats /tmp/lang_summary.txt
|
||||
rm -rf /tmp/lang_stats /tmp/lang_summary.txt /tmp/total_stats*.json
|
||||
if [ -n "${{ env.JOB_WORKSPACE }}" ] && [ "${{ env.JOB_WORKSPACE }}" != "/" ]; then
|
||||
echo "🧹 清理 Job 工作区: ${{ env.JOB_WORKSPACE }}"
|
||||
rm -rf "${{ env.JOB_WORKSPACE }}"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
|
||||
## 📂 文档导航
|
||||
|
||||
### 🚀 [DEPLOYMENT.md](./DEPLOYMENT.md)
|
||||
### 🚀 Runner
|
||||
|
||||
#### [DEPLOYMENT.md](./DEPLOYMENT.md)
|
||||
|
||||
**Gitea Runner Docker 部署完整教程**
|
||||
|
||||
|
|
|
|||
20
WORKFLOW.md
20
WORKFLOW.md
|
|
@ -63,14 +63,14 @@ git push origin 1.0.0
|
|||
|
||||
#### 2. 📊 代码统计徽章工作流 (`update_stats_badge.yaml`)
|
||||
|
||||
**功能**:自动统计代码行数并生成 SVG 徽章与统计报告
|
||||
**功能**:自动统计代码行数并生成徽章数据
|
||||
|
||||
**特性**:
|
||||
|
||||
- 📈 统计总代码行数和文件数
|
||||
- 🌐 按语言分组统计
|
||||
- 🎨 自动生成仓库内自托管的 SVG 徽章
|
||||
- 📊 在 `stats` 分支根目录生成统计报告 README
|
||||
- 🎨 自动生成徽章 JSON 数据
|
||||
- 📊 生成统计摘要(JSON 格式)
|
||||
- 🚫 灵活的目录排除配置
|
||||
|
||||
**触发方式**:
|
||||
|
|
@ -85,19 +85,7 @@ git push origin main
|
|||
|
||||
**配置文件**:[update_stats_badge.yaml](.gitea/workflows/update_stats_badge.yaml)
|
||||
|
||||
**markdown引用格式**: ``
|
||||
|
||||
**产物结构**:
|
||||
|
||||
```txt
|
||||
stats
|
||||
├── README.md
|
||||
└── badges/
|
||||
├── total-lines.svg
|
||||
├── total-files.svg
|
||||
├── language-count.svg
|
||||
└── <language>-lines.svg
|
||||
```
|
||||
**markdown引用格式**: ``
|
||||
|
||||
💡 **详细配置**:查看 `update_stats_badge.yaml` 文件顶部的 `env` 区域,包含语言分组、颜色、排除目录等配置
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,29 @@ echo ""
|
|||
|
||||
if [ $FIXED_COUNT -gt 0 ]; then
|
||||
echo -e "${GREEN}✓ 所有问题已自动修复!${NC}"
|
||||
echo ""
|
||||
echo "建议执行以下命令重启容器:"
|
||||
echo " docker compose down"
|
||||
echo " docker compose build --no-cache"
|
||||
echo " docker compose up -d"
|
||||
echo ""
|
||||
|
||||
# 询问是否立即重启
|
||||
read -p "是否立即重启容器? (y/N): " -n 1 -r
|
||||
echo ""
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "正在重启容器..."
|
||||
docker compose down
|
||||
docker compose build --no-cache
|
||||
docker compose up -d
|
||||
sleep 3
|
||||
echo ""
|
||||
echo "容器状态:"
|
||||
docker compose ps
|
||||
echo ""
|
||||
echo "查看日志:"
|
||||
docker logs gitea-runner --tail=30
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN}✓ 所有文件格式正确,无需修复!${NC}"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -20,24 +20,6 @@ mkdir -p "$PERSISTENT_BIN"
|
|||
mkdir -p /var/log/supervisor
|
||||
mkdir -p /var/run
|
||||
|
||||
create_buildx_builder() {
|
||||
docker buildx create \
|
||||
--name gitea-multiarch \
|
||||
--driver docker-container \
|
||||
--bootstrap \
|
||||
--use \
|
||||
--config /data/buildx/buildkitd.toml 2>/dev/null || \
|
||||
docker buildx use gitea-multiarch 2>/dev/null
|
||||
}
|
||||
|
||||
ensure_buildx_builder() {
|
||||
docker buildx use gitea-multiarch 2>/dev/null || {
|
||||
echo "⚠ Recreating Buildx builder..."
|
||||
docker buildx rm gitea-multiarch 2>/dev/null || true
|
||||
create_buildx_builder
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# 初始化 Docker Buildx 支持(可选)
|
||||
# ============================================
|
||||
|
|
@ -98,13 +80,13 @@ if [ "$ENABLE_BUILDX" = "true" ]; then
|
|||
|
||||
# 验证多架构支持
|
||||
echo "Verifying multi-arch support..."
|
||||
if docker run --rm --platform linux/arm64 alpine uname -m > /dev/null 2>&1; then
|
||||
if docker run --rm arm64v8/alpine uname -m > /dev/null 2>&1; then
|
||||
echo " ✓ arm64 support verified"
|
||||
else
|
||||
echo " ⚠ arm64 verification failed"
|
||||
fi
|
||||
|
||||
if docker run --rm --platform linux/amd64 alpine uname -m > /dev/null 2>&1; then
|
||||
if docker run --rm amd64/alpine uname -m > /dev/null 2>&1; then
|
||||
echo " ✓ amd64 support verified"
|
||||
else
|
||||
echo " ⚠ amd64 verification failed"
|
||||
|
|
@ -122,7 +104,13 @@ if [ "$ENABLE_BUILDX" = "true" ]; then
|
|||
EOF
|
||||
|
||||
# 创建 Buildx builder
|
||||
create_buildx_builder
|
||||
docker buildx create \
|
||||
--name gitea-multiarch \
|
||||
--driver docker-container \
|
||||
--bootstrap \
|
||||
--use \
|
||||
--config /data/buildx/buildkitd.toml 2>/dev/null || \
|
||||
docker buildx use gitea-multiarch 2>/dev/null
|
||||
|
||||
# 验证
|
||||
echo "Verifying Buildx..."
|
||||
|
|
@ -137,7 +125,15 @@ EOF
|
|||
echo "✓ Buildx already configured"
|
||||
|
||||
# 确保 builder 可用
|
||||
ensure_buildx_builder
|
||||
docker buildx use gitea-multiarch 2>/dev/null || {
|
||||
echo "⚠ Recreating Buildx builder..."
|
||||
docker buildx rm gitea-multiarch 2>/dev/null || true
|
||||
docker buildx create \
|
||||
--name gitea-multiarch \
|
||||
--driver docker-container \
|
||||
--bootstrap \
|
||||
--use 2>/dev/null
|
||||
}
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
|
|
|||
|
|
@ -133,11 +133,12 @@ echo "✓ Configuration file generated!"
|
|||
# 创建缓存目录
|
||||
mkdir -p cache
|
||||
|
||||
# 使用 Python 修改配置
|
||||
# 使用 Python 修改配置(最可靠的方法)
|
||||
echo ""
|
||||
echo "Configuring runner settings..."
|
||||
|
||||
python3 << PYEOF
|
||||
if command -v python3 &> /dev/null; then
|
||||
python3 << PYEOF
|
||||
import yaml
|
||||
import sys
|
||||
|
||||
|
|
@ -183,6 +184,32 @@ except Exception as e:
|
|||
sys.exit(1)
|
||||
PYEOF
|
||||
|
||||
PYTHON_EXIT=$?
|
||||
|
||||
if [ $PYTHON_EXIT -ne 0 ]; then
|
||||
echo ""
|
||||
echo "⚠ Python configuration failed, using basic sed..."
|
||||
|
||||
# 基本的 sed 修改(只修改简单的值,不动 labels)
|
||||
sed -i 's/capacity: 1/capacity: 4/g' config.yaml || true
|
||||
sed -i 's/enabled: false/enabled: true/g' config.yaml || true
|
||||
sed -i 's|dir: ""|dir: ./cache|g' config.yaml || true
|
||||
|
||||
echo "✓ Basic configuration applied"
|
||||
echo " Note: Please manually verify labels in config.yaml match .runner"
|
||||
fi
|
||||
else
|
||||
echo "⚠ Python3 not found, applying basic configuration..."
|
||||
|
||||
# 基本的 sed 修改
|
||||
sed -i 's/capacity: 1/capacity: 4/g' config.yaml || true
|
||||
sed -i 's/enabled: false/enabled: true/g' config.yaml || true
|
||||
sed -i 's|dir: ""|dir: ./cache|g' config.yaml || true
|
||||
|
||||
echo "✓ Basic configuration applied"
|
||||
echo " Note: Labels will use act_runner defaults"
|
||||
fi
|
||||
|
||||
# 验证配置文件
|
||||
echo ""
|
||||
echo "Validating configuration..."
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|||
UPGRADE_HELPER="${SCRIPT_DIR}/upgrade.sh"
|
||||
DEFAULT_RUNNER_VERSION_FALLBACK="${DEFAULT_RUNNER_VERSION_FALLBACK:-0.2.13}"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "${UPGRADE_HELPER}"
|
||||
if [ -f "${UPGRADE_HELPER}" ]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "${UPGRADE_HELPER}"
|
||||
fi
|
||||
|
||||
echo "=========================================="
|
||||
echo " Gitea Runner Installation Script "
|
||||
|
|
@ -40,13 +42,15 @@ echo "Available versions: https://dl.gitea.com/act_runner/"
|
|||
echo ""
|
||||
|
||||
DEFAULT_RUNNER_VERSION="${DEFAULT_RUNNER_VERSION_FALLBACK}"
|
||||
DEFAULT_RUNNER_VERSION=$(resolve_latest_version_or_fallback "${DEFAULT_RUNNER_VERSION_FALLBACK}")
|
||||
if declare -F resolve_latest_version_or_fallback >/dev/null 2>&1; then
|
||||
DEFAULT_RUNNER_VERSION=$(resolve_latest_version_or_fallback "${DEFAULT_RUNNER_VERSION_FALLBACK}")
|
||||
fi
|
||||
|
||||
echo "Default install version: ${DEFAULT_RUNNER_VERSION}"
|
||||
read -p "Enter version to install (default: ${DEFAULT_RUNNER_VERSION}): " RUNNER_VERSION
|
||||
RUNNER_VERSION=${RUNNER_VERSION:-$DEFAULT_RUNNER_VERSION}
|
||||
|
||||
if ! validate_version "${RUNNER_VERSION}"; then
|
||||
if declare -F validate_version >/dev/null 2>&1 && ! validate_version "${RUNNER_VERSION}"; then
|
||||
echo "✗ Invalid version format: ${RUNNER_VERSION}"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -114,7 +118,6 @@ echo ""
|
|||
# 下载到持久化目录
|
||||
if curl -L "$DOWNLOAD_URL" -o "$INSTALL_PATH"; then
|
||||
chmod +x "$INSTALL_PATH"
|
||||
validate_binary_arch_or_fail "$INSTALL_PATH" "$RUNNER_ARCH"
|
||||
|
||||
# 同时创建软链接到系统路径
|
||||
ln -sf "$INSTALL_PATH" "$SYSTEM_PATH"
|
||||
|
|
|
|||
|
|
@ -88,73 +88,6 @@ detect_runner_arch() {
|
|||
esac
|
||||
}
|
||||
|
||||
detect_binary_arch_from_file() {
|
||||
local binary_path=$1
|
||||
local magic=""
|
||||
local low_byte=""
|
||||
local high_byte=""
|
||||
local machine_hex=""
|
||||
|
||||
if [ ! -f "${binary_path}" ]; then
|
||||
echo "unknown"
|
||||
return 0
|
||||
fi
|
||||
|
||||
magic=$(od -An -t x1 -N 4 "${binary_path}" 2>/dev/null | tr -d ' \n')
|
||||
if [ "${magic}" != "7f454c46" ]; then
|
||||
echo "unknown"
|
||||
return 0
|
||||
fi
|
||||
|
||||
read -r low_byte high_byte <<<"$(od -An -t x1 -j 18 -N 2 "${binary_path}" 2>/dev/null)"
|
||||
if [ -z "${low_byte:-}" ] || [ -z "${high_byte:-}" ]; then
|
||||
echo "unknown"
|
||||
return 0
|
||||
fi
|
||||
|
||||
machine_hex="${high_byte}${low_byte}"
|
||||
|
||||
case "${machine_hex}" in
|
||||
003e)
|
||||
echo "amd64"
|
||||
;;
|
||||
00b7)
|
||||
echo "arm64"
|
||||
;;
|
||||
0028)
|
||||
echo "arm-7"
|
||||
;;
|
||||
*)
|
||||
echo "unknown"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
binary_arch_matches_target() {
|
||||
local binary_path=$1
|
||||
local expected_arch=$2
|
||||
local detected_arch=""
|
||||
|
||||
detected_arch=$(detect_binary_arch_from_file "${binary_path}")
|
||||
[ "${detected_arch}" = "${expected_arch}" ]
|
||||
}
|
||||
|
||||
validate_binary_arch_or_fail() {
|
||||
local binary_path=$1
|
||||
local expected_arch=$2
|
||||
local detected_arch=""
|
||||
|
||||
detected_arch=$(detect_binary_arch_from_file "${binary_path}")
|
||||
|
||||
if [ "${detected_arch}" = "unknown" ]; then
|
||||
fail "Unable to detect downloaded binary architecture: ${binary_path}"
|
||||
fi
|
||||
|
||||
if [ "${detected_arch}" != "${expected_arch}" ]; then
|
||||
fail "Downloaded binary architecture mismatch: expected ${expected_arch}, got ${detected_arch}"
|
||||
fi
|
||||
}
|
||||
|
||||
get_installed_version() {
|
||||
local output=""
|
||||
|
||||
|
|
@ -169,16 +102,6 @@ get_installed_version() {
|
|||
fi
|
||||
}
|
||||
|
||||
get_installed_binary_arch() {
|
||||
if [ -x "${INSTALL_PATH}" ]; then
|
||||
detect_binary_arch_from_file "${INSTALL_PATH}"
|
||||
elif command -v act_runner >/dev/null 2>&1; then
|
||||
detect_binary_arch_from_file "$(command -v act_runner)"
|
||||
else
|
||||
echo "unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
list_registered_runners() {
|
||||
local runner_dir
|
||||
|
||||
|
|
@ -231,7 +154,6 @@ download_and_install() {
|
|||
log "Downloading ${url}"
|
||||
curl -fL "${url}" -o "${tmp_path}"
|
||||
chmod +x "${tmp_path}"
|
||||
validate_binary_arch_or_fail "${tmp_path}" "${arch}"
|
||||
|
||||
downloaded_version=$("${tmp_path}" --version 2>/dev/null | extract_version_number)
|
||||
if [ "${downloaded_version}" != "${version}" ]; then
|
||||
|
|
@ -283,7 +205,6 @@ main() {
|
|||
local target_arch=""
|
||||
local auto_confirm="false"
|
||||
local current_version=""
|
||||
local current_arch="unknown"
|
||||
local runner_names=()
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
|
|
@ -331,18 +252,13 @@ main() {
|
|||
target_arch=$(detect_runner_arch)
|
||||
fi
|
||||
|
||||
current_arch=$(get_installed_binary_arch || true)
|
||||
|
||||
if [ -n "${current_version}" ] && \
|
||||
[ "${current_version}" = "${target_version}" ] && \
|
||||
[ "${current_arch}" = "${target_arch}" ]; then
|
||||
log "act_runner is already at the requested version and architecture: ${current_version} (${current_arch})"
|
||||
if [ -n "${current_version}" ] && [ "${current_version}" = "${target_version}" ]; then
|
||||
log "act_runner is already at the latest version: ${current_version}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Upgrade summary:"
|
||||
log " Current version: ${current_version:-not installed}"
|
||||
log " Current arch: ${current_arch:-unknown}"
|
||||
log " Target version: ${target_version}"
|
||||
log " Architecture: ${target_arch}"
|
||||
log " Install path: ${INSTALL_PATH}"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,2 @@
|
|||
GITEA_INSTANCE=https://git.mytsl.cn
|
||||
GITEA_TOKEN=
|
||||
DEFAULT_RUNNER_NAME=buildx-archlinux
|
||||
DEFAULT_RUNNER_LABEL=archlinux:host://archlinux:latest,company-server:host://archlinux:latest,buildx-archlinux:host://archlinux:latest
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ services:
|
|||
- BINFMT_METHOD=tonistiigi
|
||||
- GITEA_INSTANCE=${GITEA_INSTANCE}
|
||||
- GITEA_TOKEN=${GITEA_TOKEN}
|
||||
- DEFAULT_RUNNER_NAME=${DEFAULT_RUNNER_NAME:-buildx-archlinux}
|
||||
- DEFAULT_RUNNER_LABEL=${DEFAULT_RUNNER_LABEL:-archlinux:host://archlinux:latest,company-server:host://archlinux:latest,buildx-archlinux:host://archlinux:latest}
|
||||
- DEFAULT_RUNNER_NAME=buildx-archlinux
|
||||
- DEFAULT_RUNNER_LABEL=archlinux:host://archlinux:latest,company-server:host://archlinux:latest,buildx-archlinux:host://archlinux:latest
|
||||
|
||||
# 如果需要使用代理,取消下面的注释并修改为你的代理地址
|
||||
# 注意:容器内访问宿主机需要使用 host.docker.internal 或宿主机IP
|
||||
|
|
|
|||
|
|
@ -1,4 +1,2 @@
|
|||
GITEA_INSTANCE=https://git.mytsl.cn
|
||||
GITEA_TOKEN=
|
||||
DEFAULT_RUNNER_NAME=buildx-ubuntu-22
|
||||
DEFAULT_RUNNER_LABEL=ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,buildx-ubuntu-22:host://ubuntu:22.04
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ services:
|
|||
- ENABLE_BUILDX=true
|
||||
- GITEA_INSTANCE=${GITEA_INSTANCE}
|
||||
- GITEA_TOKEN=${GITEA_TOKEN}
|
||||
- DEFAULT_RUNNER_NAME=${DEFAULT_RUNNER_NAME:-buildx-ubuntu-22}
|
||||
- DEFAULT_RUNNER_LABEL=${DEFAULT_RUNNER_LABEL:-ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,buildx-ubuntu-22:host://ubuntu:22.04}
|
||||
- DEFAULT_RUNNER_NAME=buildx-ubuntu-22
|
||||
- DEFAULT_RUNNER_LABEL=ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,buildx-ubuntu-22:host://ubuntu:22.04
|
||||
|
||||
# 如果需要使用代理,取消下面的注释并修改为你的代理地址
|
||||
# 注意:容器内访问宿主机需要使用 host.docker.internal 或宿主机IP
|
||||
|
|
|
|||
|
|
@ -1,4 +1,2 @@
|
|||
GITEA_INSTANCE=https://git.mytsl.cn
|
||||
GITEA_TOKEN=
|
||||
DEFAULT_RUNNER_NAME=standard-ubuntu-22
|
||||
DEFAULT_RUNNER_LABEL=ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,standard-ubuntu-22:host://ubuntu:22.04
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ services:
|
|||
- ENABLE_BUILDX=false
|
||||
- GITEA_INSTANCE=${GITEA_INSTANCE}
|
||||
- GITEA_TOKEN=${GITEA_TOKEN}
|
||||
- DEFAULT_RUNNER_NAME=${DEFAULT_RUNNER_NAME:-standard-ubuntu-22}
|
||||
- DEFAULT_RUNNER_LABEL=${DEFAULT_RUNNER_LABEL:-ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,standard-ubuntu-22:host://ubuntu:22.04}
|
||||
- DEFAULT_RUNNER_NAME=standard-ubuntu-22
|
||||
- DEFAULT_RUNNER_LABEL=ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,standard-ubuntu-22:host://ubuntu:22.04
|
||||
|
||||
# 如果需要使用代理,取消下面的注释并修改为你的代理地址
|
||||
# 注意:容器内访问宿主机需要使用 host.docker.internal 或宿主机IP
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@ test_check_crlf_works_from_preset_directory() {
|
|||
)
|
||||
|
||||
! rg -q "文件不存在" "${output_file}" || fail "check_crlf.sh should inspect sibling common scripts even when invoked from preset directory"
|
||||
! rg -q "是否立即重启容器" "${output_file}" || fail "check_crlf.sh should not prompt to restart containers"
|
||||
! rg -q "docker compose down" "${output_file}" || fail "check_crlf.sh should not include compose restart commands"
|
||||
! rg -q "docker compose build --no-cache" "${output_file}" || fail "check_crlf.sh should not take responsibility for rebuilding containers"
|
||||
! rg -q "docker compose up -d" "${output_file}" || fail "check_crlf.sh should not take responsibility for starting containers"
|
||||
|
||||
for file_name in entrypoint.sh setup.sh upgrade.sh register.sh manage.sh; do
|
||||
! has_crlf "${common_dir}/${file_name}" || fail "${file_name} should have CRLF fixed"
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
REPO_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd)
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
temp_root=$(mktemp -d)
|
||||
lang_summary="${temp_root}/lang_summary.txt"
|
||||
output_dir="${temp_root}/badges"
|
||||
readme_path="${temp_root}/README.md"
|
||||
|
||||
cat > "${lang_summary}" <<'EOF'
|
||||
python|Python|1200|1,200|12|3572A5|python
|
||||
typescript|TypeScript|800|800|9|3178c6|typescript
|
||||
yaml|YAML|120|120|5|CB171E|
|
||||
EOF
|
||||
|
||||
python3 "${REPO_ROOT}/.gitea/ci/render_stats_svgs.py" \
|
||||
--output-dir "${output_dir}" \
|
||||
--readme-path "${readme_path}" \
|
||||
--repo "csh/actions-template" \
|
||||
--generated-by "Gitea Actions" \
|
||||
--updated-at "2026-05-22 12:00:00 UTC" \
|
||||
--total-code 2120 \
|
||||
--formatted-total-code "2,120" \
|
||||
--total-files 26 \
|
||||
--formatted-total-files "26" \
|
||||
--language-count 3 \
|
||||
--exclude-dirs "node_modules,dist,.git" \
|
||||
--min-lines-threshold 10 \
|
||||
--lang-summary "${lang_summary}"
|
||||
|
||||
test -f "${output_dir}/total-lines.svg" || fail "renderer should create total-lines.svg"
|
||||
test -f "${output_dir}/total-files.svg" || fail "renderer should create total-files.svg"
|
||||
test -f "${output_dir}/language-count.svg" || fail "renderer should create language-count.svg"
|
||||
test -f "${output_dir}/python-lines.svg" || fail "renderer should create per-language svg badges"
|
||||
test -f "${readme_path}" || fail "renderer should create root README.md"
|
||||
|
||||
grep -q '<svg' "${output_dir}/total-lines.svg" || fail "svg badges should contain svg markup"
|
||||
grep -q '2,120' "${output_dir}/total-lines.svg" || fail "total-lines badge should include formatted total code"
|
||||
grep -q 'Python' "${output_dir}/python-lines.svg" || fail "language badge should include display name"
|
||||
grep -q '\./badges/total-lines.svg' "${readme_path}" || fail "README should reference badges via relative svg paths"
|
||||
grep -q '\./badges/python-lines.svg' "${readme_path}" || fail "README should reference language badges via relative svg paths"
|
||||
grep -q 'Gitea Actions' "${readme_path}" || fail "README should mention Gitea Actions"
|
||||
grep -q '此分支由 Gitea Actions 自动生成和维护' "${readme_path}" || fail "README should explain that stats branch is generated"
|
||||
grep -q '请勿手动修改此分支的内容' "${readme_path}" || fail "README should warn against manual edits"
|
||||
! grep -q 'GitHub Actions' "${readme_path}" || fail "README should not mention GitHub Actions"
|
||||
! find "${temp_root}" -name '*.json' | grep -q . || fail "renderer should not create json badge payloads"
|
||||
|
||||
rm -rf "${temp_root}"
|
||||
|
||||
echo "stats_svg_render_test.sh: PASS"
|
||||
|
|
@ -60,12 +60,10 @@ test_workflow_doc_describes_workspace_architecture() {
|
|||
|
||||
file="${REPO_ROOT}/WORKFLOW.md"
|
||||
|
||||
grep -Eq '^## .*运行模型' "${file}" || fail "WORKFLOW.md should include a run model section"
|
||||
grep -q 'bare' "${file}" || fail "WORKFLOW.md should describe the bare mirror model"
|
||||
grep -q '工作副本' "${file}" || fail "WORKFLOW.md should describe isolated work copies"
|
||||
grep -Eq '共享.*缓存|缓存.*共享' "${file}" || fail "WORKFLOW.md should describe the shared cache model"
|
||||
grep -Eq '并发|隔离' "${file}" || fail "WORKFLOW.md should mention concurrency or isolation tradeoffs"
|
||||
grep -Eq '结束后.*清理|清理.*工作副本' "${file}" || fail "WORKFLOW.md should mention cleanup after workflow completion"
|
||||
grep -q 'Git bare 镜像 + 工作副本' "${file}" || fail "WORKFLOW.md should explicitly describe the bare mirror plus worktree-style model"
|
||||
grep -q '共享仓库缓存' "${file}" || fail "WORKFLOW.md should describe the shared repository cache model"
|
||||
grep -q '独立工作副本' "${file}" || fail "WORKFLOW.md should describe isolated per-job work copies"
|
||||
grep -q '任务结束后' "${file}" || fail "WORKFLOW.md should mention cleanup after workflow completion"
|
||||
! rg -q 'bootstrap_workspace\.sh' "${file}" || fail "WORKFLOW.md should describe architecture rather than helper implementation"
|
||||
! rg -q '/data/git-mirrors|/home/workspace/jobs' "${file}" || fail "WORKFLOW.md should avoid implementation-specific workspace paths"
|
||||
}
|
||||
|
|
@ -90,13 +88,13 @@ test_readme_has_project_intro_and_navigation() {
|
|||
|
||||
file="${REPO_ROOT}/README.md"
|
||||
|
||||
grep -Eq '^## .*项目简介' "${file}" || fail "README.md should provide a project intro section"
|
||||
grep -Eq '^## .*文档导航' "${file}" || fail "README.md should provide a document navigation section"
|
||||
grep -q '^## 📖 项目简介$' "${file}" || fail "README.md should provide a project intro section"
|
||||
grep -q '^## 📂 文档导航$' "${file}" || fail "README.md should provide a document navigation section"
|
||||
grep -q '\[DEPLOYMENT.md\](\./DEPLOYMENT.md)' "${file}" || fail "README.md should link to DEPLOYMENT.md"
|
||||
grep -q '\[WORKFLOW.md\](\./WORKFLOW.md)' "${file}" || fail "README.md should link to WORKFLOW.md"
|
||||
grep -q '具体部署步骤.*\[DEPLOYMENT.md\](\./DEPLOYMENT.md)' "${file}" || fail "README.md should delegate deployment details to DEPLOYMENT.md"
|
||||
! rg -q '^## 🚀 快速提示$' "${file}" || fail "README.md should not carry concrete deployment tip sections"
|
||||
! rg -q '^## ⚙️ 当前默认行为$' "${file}" || fail "README.md should not carry default behavior details"
|
||||
! rg -q 'docker compose (build|up|exec)' "${file}" || fail "README.md should stay high-level and leave compose commands to deployment docs"
|
||||
}
|
||||
|
||||
test_deployment_doc_stays_runner_focused() {
|
||||
|
|
@ -126,111 +124,9 @@ test_preset_env_examples_exist() {
|
|||
test -f "${file}" || fail "missing env example: ${file}"
|
||||
grep -q '^GITEA_INSTANCE=https://git.mytsl.cn$' "${file}" || fail "${file} should include company default instance"
|
||||
grep -q '^GITEA_TOKEN=$' "${file}" || fail "${file} should include empty token placeholder"
|
||||
grep -q '^DEFAULT_RUNNER_NAME=' "${file}" || fail "${file} should define DEFAULT_RUNNER_NAME override example"
|
||||
grep -q '^DEFAULT_RUNNER_LABEL=' "${file}" || fail "${file} should define DEFAULT_RUNNER_LABEL override example"
|
||||
done
|
||||
}
|
||||
|
||||
test_preset_compose_supports_runner_identity_overrides() {
|
||||
grep -q 'DEFAULT_RUNNER_NAME=${DEFAULT_RUNNER_NAME:-standard-ubuntu-22}' \
|
||||
"${REPO_ROOT}/docker-runner/presets/standard-ubuntu-22/docker-compose.yml" || \
|
||||
fail "standard preset should allow DEFAULT_RUNNER_NAME override via env"
|
||||
grep -q 'DEFAULT_RUNNER_LABEL=${DEFAULT_RUNNER_LABEL:-ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,standard-ubuntu-22:host://ubuntu:22.04}' \
|
||||
"${REPO_ROOT}/docker-runner/presets/standard-ubuntu-22/docker-compose.yml" || \
|
||||
fail "standard preset should allow DEFAULT_RUNNER_LABEL override via env"
|
||||
|
||||
grep -q 'DEFAULT_RUNNER_NAME=${DEFAULT_RUNNER_NAME:-buildx-ubuntu-22}' \
|
||||
"${REPO_ROOT}/docker-runner/presets/buildx-ubuntu-22/docker-compose.yml" || \
|
||||
fail "buildx ubuntu preset should allow DEFAULT_RUNNER_NAME override via env"
|
||||
grep -q 'DEFAULT_RUNNER_LABEL=${DEFAULT_RUNNER_LABEL:-ubuntu-22.04:host://ubuntu:22.04,company-server:host://ubuntu:22.04,buildx-ubuntu-22:host://ubuntu:22.04}' \
|
||||
"${REPO_ROOT}/docker-runner/presets/buildx-ubuntu-22/docker-compose.yml" || \
|
||||
fail "buildx ubuntu preset should allow DEFAULT_RUNNER_LABEL override via env"
|
||||
|
||||
grep -q 'DEFAULT_RUNNER_NAME=${DEFAULT_RUNNER_NAME:-buildx-archlinux}' \
|
||||
"${REPO_ROOT}/docker-runner/presets/buildx-archlinux/docker-compose.yml" || \
|
||||
fail "buildx arch preset should allow DEFAULT_RUNNER_NAME override via env"
|
||||
grep -q 'DEFAULT_RUNNER_LABEL=${DEFAULT_RUNNER_LABEL:-archlinux:host://archlinux:latest,company-server:host://archlinux:latest,buildx-archlinux:host://archlinux:latest}' \
|
||||
"${REPO_ROOT}/docker-runner/presets/buildx-archlinux/docker-compose.yml" || \
|
||||
fail "buildx arch preset should allow DEFAULT_RUNNER_LABEL override via env"
|
||||
}
|
||||
|
||||
test_register_requires_python_yaml_path() {
|
||||
local file
|
||||
|
||||
file="${REPO_ROOT}/docker-runner/common/register.sh"
|
||||
|
||||
! rg -q 'Python configuration failed, using basic sed' "${file}" || fail "register.sh should not fall back to basic sed when Python config fails"
|
||||
! rg -q 'Python3 not found, applying basic configuration' "${file}" || fail "register.sh should not continue with basic configuration when Python3 is missing"
|
||||
! rg -q "sed -i 's/capacity: 1/capacity: 4/g' config.yaml" "${file}" || fail "register.sh should not mutate config.yaml via sed fallback"
|
||||
grep -q "python3 << PYEOF" "${file}" || fail "register.sh should keep Python-based config generation"
|
||||
}
|
||||
|
||||
test_setup_requires_upgrade_helper() {
|
||||
local file
|
||||
|
||||
file="${REPO_ROOT}/docker-runner/common/setup.sh"
|
||||
|
||||
grep -q '^# shellcheck source=/dev/null$' "${file}" || fail "setup.sh should source upgrade.sh directly"
|
||||
grep -q '^source "\${UPGRADE_HELPER}"$' "${file}" || fail "setup.sh should require sourcing upgrade.sh"
|
||||
! grep -Fq 'if [ -f "${UPGRADE_HELPER}" ]; then' "${file}" || fail "setup.sh should not treat upgrade helper as optional"
|
||||
! rg -q 'declare -F resolve_latest_version_or_fallback' "${file}" || fail "setup.sh should not guard helper functions with declare -F"
|
||||
! rg -q 'declare -F validate_version' "${file}" || fail "setup.sh should not guard validate_version with declare -F"
|
||||
! rg -q 'declare -F validate_binary_arch_or_fail' "${file}" || fail "setup.sh should not guard binary validation with declare -F"
|
||||
}
|
||||
|
||||
test_entrypoint_uses_shared_buildx_builder_creation() {
|
||||
local file
|
||||
|
||||
file="${REPO_ROOT}/docker-runner/common/entrypoint.sh"
|
||||
|
||||
grep -q '^create_buildx_builder() {$' "${file}" || fail "entrypoint.sh should extract Buildx builder creation into a helper"
|
||||
grep -q '^ensure_buildx_builder() {$' "${file}" || fail "entrypoint.sh should extract Buildx builder selection into a helper"
|
||||
grep -q '^[[:space:]]*create_buildx_builder$' "${file}" || fail "entrypoint.sh should use shared builder creation during initial setup"
|
||||
grep -q '^[[:space:]]*ensure_buildx_builder$' "${file}" || fail "entrypoint.sh should use shared builder selection during reuse"
|
||||
}
|
||||
|
||||
test_stats_workflow_avoids_eval_find() {
|
||||
local file
|
||||
|
||||
file="${REPO_ROOT}/.gitea/workflows/update_stats_badge.yaml"
|
||||
|
||||
! rg -q 'eval "find ' "${file}" || fail "stats workflow should avoid eval when building find commands"
|
||||
grep -q 'EXCLUDE_FIND_ARGS=()' "${file}" || fail "stats workflow should build reusable find exclusion arrays"
|
||||
grep -q 'LANG_FIND_ARGS=()' "${file}" || fail "stats workflow should build language-specific find arguments via arrays"
|
||||
}
|
||||
|
||||
test_stats_workflow_uses_svg_badges() {
|
||||
local file workflow_doc
|
||||
|
||||
file="${REPO_ROOT}/.gitea/workflows/update_stats_badge.yaml"
|
||||
workflow_doc="${REPO_ROOT}/WORKFLOW.md"
|
||||
|
||||
grep -q 'total-lines.svg' "${file}" || fail "stats workflow should generate total-lines.svg"
|
||||
grep -q 'total-files.svg' "${file}" || fail "stats workflow should generate total-files.svg"
|
||||
grep -q 'language-count.svg' "${file}" || fail "stats workflow should generate language-count.svg"
|
||||
grep -Fq '{language}-lines.svg' "${file}" || fail "stats workflow should describe per-language svg badges"
|
||||
grep -q '/src/branch/${{ env.BADGE_BRANCH }}/README.md' "${file}" || fail "stats workflow summary should link to stats branch root README"
|
||||
! rg -q '/src/branch/\$\{\{ env.BADGE_BRANCH \}\}/\$\{\{ env.BADGE_DIR \}\}/README\.md' "${file}" || fail "stats workflow should not place README.md under the badge directory"
|
||||
! rg -q 'img\.shields\.io/endpoint' "${file}" || fail "stats workflow should not depend on Shields endpoint badges"
|
||||
! rg -q 'total-lines\.json|total-files\.json|\$\{lang_id\}-lines\.json|\$\{lang_id\}-files\.json' "${file}" || fail "stats workflow should not generate json badge payloads"
|
||||
! rg -q 'GitHub Actions' "${file}" || fail "stats workflow should not mention GitHub Actions"
|
||||
grep -q 'Gitea Actions' "${file}" || fail "stats workflow should mention Gitea Actions in generated content"
|
||||
|
||||
grep -q 'badges/cpp-lines.svg' "${workflow_doc}" || fail "WORKFLOW.md should show svg badge usage examples"
|
||||
! rg -q 'img\.shields\.io/endpoint|cpp-lines\.json' "${workflow_doc}" || fail "WORKFLOW.md should not document json endpoint badge usage"
|
||||
}
|
||||
|
||||
test_entrypoint_uses_platform_aware_multiarch_verification() {
|
||||
local file
|
||||
|
||||
file="${REPO_ROOT}/docker-runner/common/entrypoint.sh"
|
||||
|
||||
grep -q 'docker run --rm --platform linux/arm64 alpine uname -m' "${file}" || fail "entrypoint.sh should verify arm64 support with an explicit platform"
|
||||
grep -q 'docker run --rm --platform linux/amd64 alpine uname -m' "${file}" || fail "entrypoint.sh should verify amd64 support with an explicit platform"
|
||||
! rg -q 'docker run --rm arm64v8/alpine uname -m' "${file}" || fail "entrypoint.sh should not use arm64v8/alpine without an explicit platform"
|
||||
! rg -q 'docker run --rm amd64/alpine uname -m' "${file}" || fail "entrypoint.sh should not use amd64/alpine without an explicit platform"
|
||||
}
|
||||
|
||||
test_preset_compose_uses_env_for_instance
|
||||
test_workflows_do_not_hardcode_company_server
|
||||
test_stats_workflow_uses_workflow_secret_consistently
|
||||
|
|
@ -242,12 +138,5 @@ test_readme_has_project_intro_and_navigation
|
|||
test_deployment_doc_stays_runner_focused
|
||||
test_presets_define_expected_hostname
|
||||
test_preset_env_examples_exist
|
||||
test_preset_compose_supports_runner_identity_overrides
|
||||
test_register_requires_python_yaml_path
|
||||
test_setup_requires_upgrade_helper
|
||||
test_entrypoint_uses_shared_buildx_builder_creation
|
||||
test_stats_workflow_avoids_eval_find
|
||||
test_stats_workflow_uses_svg_badges
|
||||
test_entrypoint_uses_platform_aware_multiarch_verification
|
||||
|
||||
echo "template_defaults_test.sh: PASS"
|
||||
|
|
|
|||
|
|
@ -20,31 +20,6 @@ assert_eq() {
|
|||
fi
|
||||
}
|
||||
|
||||
make_fake_elf() {
|
||||
local path=$1
|
||||
local arch=$2
|
||||
local machine_bytes=""
|
||||
|
||||
case "${arch}" in
|
||||
amd64)
|
||||
machine_bytes='\076\000'
|
||||
;;
|
||||
arm64)
|
||||
machine_bytes='\267\000'
|
||||
;;
|
||||
arm-7)
|
||||
machine_bytes='\050\000'
|
||||
;;
|
||||
*)
|
||||
echo "FAIL: unsupported fake ELF arch ${arch}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '\177ELF\002\001\001\000\000\000\000\000\000\000\000\000\002\000%b' \
|
||||
"${machine_bytes}" > "${path}"
|
||||
}
|
||||
|
||||
test_extract_versions_from_listing() {
|
||||
local html
|
||||
html=$(cat <<'EOF'
|
||||
|
|
@ -115,61 +90,10 @@ test_resolve_latest_version_or_fallback_uses_fallback() {
|
|||
"resolve_latest_version_or_fallback should fall back when detected version is invalid"
|
||||
}
|
||||
|
||||
test_detect_binary_arch_from_file() {
|
||||
local temp_root amd64_file arm64_file arm7_file text_file
|
||||
|
||||
temp_root=$(mktemp -d)
|
||||
amd64_file="${temp_root}/act_runner-amd64"
|
||||
arm64_file="${temp_root}/act_runner-arm64"
|
||||
arm7_file="${temp_root}/act_runner-arm7"
|
||||
text_file="${temp_root}/not-elf"
|
||||
|
||||
make_fake_elf "${amd64_file}" "amd64"
|
||||
make_fake_elf "${arm64_file}" "arm64"
|
||||
make_fake_elf "${arm7_file}" "arm-7"
|
||||
printf 'not an elf\n' > "${text_file}"
|
||||
|
||||
assert_eq "amd64" "$(detect_binary_arch_from_file "${amd64_file}")" \
|
||||
"detect_binary_arch_from_file should recognize amd64 ELF binaries"
|
||||
assert_eq "arm64" "$(detect_binary_arch_from_file "${arm64_file}")" \
|
||||
"detect_binary_arch_from_file should recognize arm64 ELF binaries"
|
||||
assert_eq "arm-7" "$(detect_binary_arch_from_file "${arm7_file}")" \
|
||||
"detect_binary_arch_from_file should recognize arm-7 ELF binaries"
|
||||
assert_eq "unknown" "$(detect_binary_arch_from_file "${text_file}")" \
|
||||
"detect_binary_arch_from_file should reject non-ELF files"
|
||||
|
||||
rm -rf "${temp_root}"
|
||||
}
|
||||
|
||||
test_binary_arch_matches_target() {
|
||||
local temp_root amd64_file arm64_file
|
||||
|
||||
temp_root=$(mktemp -d)
|
||||
amd64_file="${temp_root}/act_runner-amd64"
|
||||
arm64_file="${temp_root}/act_runner-arm64"
|
||||
|
||||
make_fake_elf "${amd64_file}" "amd64"
|
||||
make_fake_elf "${arm64_file}" "arm64"
|
||||
|
||||
if ! binary_arch_matches_target "${amd64_file}" "amd64"; then
|
||||
echo "FAIL: binary_arch_matches_target should accept matching architectures" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if binary_arch_matches_target "${arm64_file}" "amd64"; then
|
||||
echo "FAIL: binary_arch_matches_target should reject mismatched architectures" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "${temp_root}"
|
||||
}
|
||||
|
||||
test_extract_versions_from_listing
|
||||
test_pick_latest_version
|
||||
test_extract_version_number_accepts_v_prefix
|
||||
test_resolve_latest_version_or_fallback_prefers_latest
|
||||
test_resolve_latest_version_or_fallback_uses_fallback
|
||||
test_detect_binary_arch_from_file
|
||||
test_binary_arch_matches_target
|
||||
|
||||
echo "upgrade_test.sh: PASS"
|
||||
|
|
|
|||
|
|
@ -53,6 +53,14 @@ test_sanitize_job_name() {
|
|||
assert_eq "release-notes-job" "${actual}" "job names should be filesystem-safe"
|
||||
}
|
||||
|
||||
test_build_lock_path() {
|
||||
local actual
|
||||
|
||||
actual=$(build_mirror_lock_path "/data/git-mirrors" "csh" "actions-template")
|
||||
|
||||
assert_eq "/data/git-mirrors/csh/actions-template.git.lock" "${actual}" "lock path should sit beside the bare mirror"
|
||||
}
|
||||
|
||||
test_repo_owner_and_name_parsing() {
|
||||
local actual
|
||||
|
||||
|
|
@ -159,6 +167,7 @@ test_presets_do_not_mount_workspace_helper() {
|
|||
test_repo_path_layout
|
||||
test_job_identity_prefers_run_metadata
|
||||
test_sanitize_job_name
|
||||
test_build_lock_path
|
||||
test_repo_owner_and_name_parsing
|
||||
test_prepare_and_cleanup_workspace
|
||||
test_register_default_capacity_is_four
|
||||
|
|
|
|||
Loading…
Reference in New Issue