chore: 重构 OpenCode 命令和技能文档体系
- 新增:统一的 git 命令文档(add/commit/push/pull 等) - 新增:整合的 Gitea 技能文档(API、运行器、工作流等) - 新增:工作流模板(Android、Go、Node.js 等) - 移除:已弃用的旧命令脚本和发布脚本 - 改进:.gitignore 添加敏感文件保护规则 - 改进:AGENTS.md 完善了开发规范和示例 此次重组统一了命令和技能的文档结构,便于后续维护和扩展。
This commit is contained in:
343
skill/gitea/SKILL.md
Normal file
343
skill/gitea/SKILL.md
Normal file
@@ -0,0 +1,343 @@
|
||||
---
|
||||
name: gitea
|
||||
description: Comprehensive Gitea management tool for creating runners, workflows, and repositories with interactive setup
|
||||
---
|
||||
|
||||
# Gitea Management Skill
|
||||
|
||||
完整的 Gitea 管理工具,提供 Runner、Workflow、仓库的创建和管理功能。
|
||||
|
||||
## 功能概览
|
||||
|
||||
| 功能模块 | 文档 | 说明 |
|
||||
|---------|------|------|
|
||||
| 环境配置 | [setup-guide.md](./setup-guide.md) | 首次使用引导,配置 Gitea URL 和 Token |
|
||||
| Runner 管理 | [runner-management.md](./runner-management.md) | 创建、注册、管理 Gitea Act Runner |
|
||||
| Workflow 生成 | [workflow-generator.md](./workflow-generator.md) | 根据项目类型生成 CI/CD workflow |
|
||||
| 仓库操作 | [repository-operations.md](./repository-operations.md) | 创建和配置 Gitea 仓库 |
|
||||
| API 参考 | [api-reference.md](./api-reference.md) | Gitea API 常用接口 |
|
||||
| 故障排查 | [troubleshooting.md](./troubleshooting.md) | 常见问题解决方案 |
|
||||
|
||||
## 触发条件
|
||||
|
||||
当用户提到以下关键词时自动加载此 skill:
|
||||
- "gitea"、"runner"、"workflow"
|
||||
- "创建 runner"、"配置 runner"、"注册 runner"
|
||||
- "生成 workflow"、"CI/CD"
|
||||
- "创建仓库"、"gitea 仓库"
|
||||
- "gitea 配置"、"gitea token"
|
||||
|
||||
## 首次使用
|
||||
|
||||
**重要:** 首次使用前需要配置 Gitea 连接信息。
|
||||
|
||||
- 配置文件:`~/.config/gitea/config.env`
|
||||
- 如果文件不存在,自动启动交互式配置向导
|
||||
- 使用 `/gitea-config` 命令查看当前配置
|
||||
- 使用 `/gitea-reset` 命令重置配置
|
||||
|
||||
**新增:Actions Variables 自动注册**
|
||||
- 初始化时会自动将配置注册为用户级 variables
|
||||
- `GITEA_USERNAME` → `USERNAME` variable
|
||||
- `GITEA_WEBHOOK_URL` → `WEBHOOK_URL` variable
|
||||
- 可在所有个人仓库的 Actions workflow 中使用
|
||||
- 使用方式:`${{ vars.USERNAME }}`、`${{ vars.WEBHOOK_URL }}`
|
||||
|
||||
**重要**:Gitea 不允许 variable 名称以 `GITEA_` 或 `GITHUB_` 开头
|
||||
|
||||
详见:[环境配置指南](./setup-guide.md)
|
||||
|
||||
## 快速命令
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `/gitea-config` | 查看当前 Gitea 配置和 Runner 状态 |
|
||||
| `/gitea-reset` | 重置 Gitea 配置(交互式向导) |
|
||||
| `/gitea-switch-org` | 切换默认组织 |
|
||||
| `/gitea-create-runner` | 创建并启动新 Runner(默认 host 模式) |
|
||||
| `/gitea-list-runners` | 列出所有 Runner 及其状态 |
|
||||
| `/gitea-delete-runner` | 删除指定 Runner |
|
||||
| `/gitea-list-variables` | 列出用户级 Variables |
|
||||
| `/gitea-sync-variables` | 同步本地配置到 Gitea Variables |
|
||||
| `/gitea-create-repo` | 创建新仓库 |
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 配置 Gitea 连接
|
||||
|
||||
首次使用时,系统会自动引导你完成配置:
|
||||
|
||||
```
|
||||
请输入 Gitea 实例地址: https://git.digitevents.com
|
||||
请输入 Personal Access Token: ****************
|
||||
请输入默认组织名称(可选): ai
|
||||
请输入 Gitea 用户名(用于 Actions): your_username
|
||||
请输入 Gitea 密码: ********
|
||||
请输入 Actions 通知 Webhook URL(可选): https://...
|
||||
|
||||
✓ 配置已保存到: ~/.config/gitea/config.env
|
||||
|
||||
正在注册用户级 Variables...
|
||||
✓ USERNAME 已创建 (来自 GITEA_USERNAME)
|
||||
✓ WEBHOOK_URL 已创建
|
||||
```
|
||||
|
||||
或使用命令:
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
### 2. 创建 Runner
|
||||
|
||||
```bash
|
||||
/gitea-create-runner
|
||||
```
|
||||
|
||||
输出示例:
|
||||
```
|
||||
检查 act_runner 安装状态...
|
||||
✓ act_runner 已安装: act_runner version 0.2.13
|
||||
|
||||
✓ 已加载 Gitea 配置
|
||||
URL: https://git.digitevents.com
|
||||
|
||||
生成 Runner 名称: runner-macbook-pro
|
||||
|
||||
检测系统环境...
|
||||
✓ 系统信息
|
||||
操作系统: Darwin (macOS)
|
||||
架构: arm64 (ARM64)
|
||||
|
||||
✓ Runner Labels (Host Mode)
|
||||
self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
|
||||
|
||||
[自动创建目录、生成配置、注册并启动]
|
||||
|
||||
✅ Runner 创建完成!
|
||||
名称: runner-macbook-pro
|
||||
级别: global
|
||||
状态: 🟢 运行中
|
||||
PID: 12345
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 默认使用 Host Mode(支持 Android SDK、iOS 构建等)
|
||||
- 自动检查并安装 act_runner(如未安装)
|
||||
- 自动检测系统环境并生成合适的 labels
|
||||
- 优先创建全局 Runner(需要管理员 Token)
|
||||
- 权限不足时自动降级到组织 Runner
|
||||
- 自动后台启动
|
||||
|
||||
### 3. 生成 Workflow
|
||||
|
||||
```
|
||||
用户: 为我的 Go 项目生成 workflow
|
||||
AI: 检测到 Go 项目,服务目录: ./backend
|
||||
是否需要构建 Docker 镜像?[Y/n]
|
||||
[自动生成 .gitea/workflows/backend.yml]
|
||||
```
|
||||
|
||||
### 4. 创建仓库
|
||||
|
||||
```
|
||||
用户: /gitea-create-repo my-project
|
||||
AI: [使用配置的 Gitea URL 和默认组织创建仓库]
|
||||
✓ 仓库创建成功: ai/my-project
|
||||
```
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 查看配置
|
||||
|
||||
```bash
|
||||
/gitea-config
|
||||
```
|
||||
|
||||
输出示例:
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
当前 Gitea 配置
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
URL: https://git.digitevents.com
|
||||
默认组织: ai
|
||||
Token 状态: ✓ 有效 (用户: your_username)
|
||||
配置文件: ~/.config/gitea/config.env
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Runner 信息
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
已配置 Runner 数量: 2
|
||||
Runner 目录: ~/.config/gitea/runners
|
||||
```
|
||||
|
||||
### 列出 Runners
|
||||
|
||||
```bash
|
||||
/gitea-list-runners
|
||||
```
|
||||
|
||||
### 切换组织
|
||||
|
||||
```bash
|
||||
/gitea-switch-org my-org
|
||||
```
|
||||
|
||||
### 重置配置
|
||||
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
## 配置文件结构
|
||||
|
||||
```
|
||||
~/.config/gitea/
|
||||
├── config.env # 主配置文件(含认证信息和 Webhook)
|
||||
├── runners/ # Runner 配置目录
|
||||
│ ├── runner-macbook-pro/
|
||||
│ │ ├── .runner # Runner 注册信息
|
||||
│ │ ├── config.yaml # Runner 配置
|
||||
│ │ ├── cache/ # Cache 目录
|
||||
│ │ └── workspace/ # 工作目录
|
||||
│ └── runner-mac-mini/
|
||||
│ └── ...
|
||||
└── .gitignore # 忽略敏感文件
|
||||
```
|
||||
|
||||
**config.env 包含的配置项**:
|
||||
- `GITEA_URL`: Gitea 实例地址
|
||||
- `GITEA_TOKEN`: Personal Access Token
|
||||
- `GITEA_DEFAULT_ORG`: 默认组织
|
||||
- `GITEA_USERNAME`: Gitea 用户名(自动注册为 `USERNAME` variable)
|
||||
- `GITEA_PASSWORD`: Gitea 密码(仅本地使用)
|
||||
- `GITEA_WEBHOOK_URL`: Actions 通知 Webhook(自动注册为 `WEBHOOK_URL` variable)
|
||||
|
||||
## 使用流程
|
||||
|
||||
### 典型的 Gitea 项目设置流程
|
||||
|
||||
1. **初始化配置**(仅首次)
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
2. **创建仓库**
|
||||
```bash
|
||||
/gitea-create-repo myorg/myproject
|
||||
```
|
||||
|
||||
3. **创建 Runner**(如果需要自托管 CI/CD)
|
||||
```bash
|
||||
/gitea-create-runner
|
||||
```
|
||||
|
||||
4. **生成 Workflow**
|
||||
```
|
||||
用户: 为这个项目生成 workflow
|
||||
```
|
||||
|
||||
5. **推送代码并触发 CI/CD**
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Runner 管理
|
||||
|
||||
### 创建 Runner
|
||||
|
||||
使用命令快速创建:
|
||||
```bash
|
||||
/gitea-create-runner
|
||||
```
|
||||
|
||||
特性:
|
||||
- 自动检查并安装 act_runner
|
||||
- 自动检测系统环境(OS、架构)
|
||||
- 默认使用 Host Mode(支持原生工具)
|
||||
- 自动生成配置并启动
|
||||
- 优先创建全局 Runner
|
||||
|
||||
详见:[Runner 管理](./runner-management.md)
|
||||
|
||||
### 查看 Runner 状态
|
||||
|
||||
```bash
|
||||
/gitea-list-runners
|
||||
```
|
||||
|
||||
显示:
|
||||
- 运行状态(运行中/已停止)
|
||||
- PID
|
||||
- 配置信息(容量、超时、labels)
|
||||
- 启动命令
|
||||
|
||||
### 删除 Runner
|
||||
|
||||
```bash
|
||||
/gitea-delete-runner runner-macbook-pro
|
||||
```
|
||||
|
||||
会自动:
|
||||
- 停止运行中的进程
|
||||
- 可选从 Gitea 服务器注销
|
||||
- 删除所有相关文件(配置、cache、workspace)
|
||||
|
||||
## Workflow 模板
|
||||
|
||||
支持以下项目类型的 workflow 模板:
|
||||
|
||||
| 类型 | 模板文档 | 适用场景 |
|
||||
|------|---------|---------|
|
||||
| Go 后端 | [go-backend.md](./workflow-templates/go-backend.md) | API 服务、微服务、CLI 工具 |
|
||||
| Node.js 前端 | [nodejs-frontend.md](./workflow-templates/nodejs-frontend.md) | React/Vue/Vite/Next.js |
|
||||
| Android 应用 | [android-app.md](./workflow-templates/android-app.md) | Kotlin/Java/Jetpack Compose |
|
||||
| 微信小程序 | [wechat-miniprogram.md](./workflow-templates/wechat-miniprogram.md) | 微信小程序 CI/CD |
|
||||
|
||||
AI 会自动:
|
||||
- 检测项目类型
|
||||
- 选择合适的模板
|
||||
- 填充项目特定的变量(路径、服务名等)
|
||||
- 生成完整的 workflow 文件
|
||||
|
||||
详见:[Workflow 生成器](./workflow-generator.md)
|
||||
|
||||
## API 调用
|
||||
|
||||
所有与 Gitea 服务器的交互都通过 API 完成,使用配置文件中的:
|
||||
- `GITEA_URL`: Gitea 实例地址
|
||||
- `GITEA_TOKEN`: Personal Access Token
|
||||
|
||||
详见:[API 参考](./api-reference.md)
|
||||
|
||||
## 安全性
|
||||
|
||||
- 配置文件权限:`600`(仅所有者可读写)
|
||||
- Token 不会在日志中显示
|
||||
- `.gitignore` 自动排除敏感文件
|
||||
- 删除 runner 时可选择从服务器注销
|
||||
|
||||
## 故障排查
|
||||
|
||||
常见问题:
|
||||
- 连接失败:检查 URL 和网络
|
||||
- Token 无效:检查 Token 权限和有效期
|
||||
- Runner 无法启动:检查端口占用和权限
|
||||
- Workflow 无法触发:检查 labels 匹配
|
||||
|
||||
详见:[故障排查](./troubleshooting.md)
|
||||
|
||||
## 版本
|
||||
|
||||
- **Skill Version**: 1.0
|
||||
- **Last Updated**: 2026-01-12
|
||||
- **整合内容**: gitea-runner + gitea-workflow
|
||||
- **新增功能**: 统一配置管理、Runner CRUD、智能 labels 检测
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Gitea 官方文档](https://docs.gitea.com/)
|
||||
- [Gitea Actions 文档](https://docs.gitea.com/usage/actions/overview)
|
||||
- [Gitea API 文档](https://docs.gitea.com/api/1.20/)
|
||||
- [Act Runner 文档](https://docs.gitea.com/usage/actions/act-runner)
|
||||
1083
skill/gitea/api-reference.md
Normal file
1083
skill/gitea/api-reference.md
Normal file
File diff suppressed because it is too large
Load Diff
693
skill/gitea/repository-operations.md
Normal file
693
skill/gitea/repository-operations.md
Normal file
@@ -0,0 +1,693 @@
|
||||
# Gitea 仓库操作
|
||||
|
||||
创建和管理 Gitea 仓库的完整指南。
|
||||
|
||||
## 概述
|
||||
|
||||
本文档介绍如何通过 Gitea API 创建和管理仓库,包括:
|
||||
- 创建组织/用户仓库
|
||||
- 初始化仓库结构
|
||||
- 配置 Actions 设置
|
||||
- 管理 Secrets 和 Variables
|
||||
- 设置 Webhooks
|
||||
|
||||
## 创建仓库
|
||||
|
||||
### 使用命令创建
|
||||
|
||||
**快速创建**(使用默认组织):
|
||||
|
||||
```bash
|
||||
/gitea-create-repo my-project
|
||||
```
|
||||
|
||||
**指定 owner**:
|
||||
|
||||
```bash
|
||||
/create-gitea-repo ai/my-project
|
||||
/create-gitea-repo username/my-project
|
||||
```
|
||||
|
||||
**指定可见性**:
|
||||
|
||||
```bash
|
||||
/create-gitea-repo ai/my-project public
|
||||
/create-gitea-repo ai/my-project private
|
||||
```
|
||||
|
||||
### 使用自然语言
|
||||
|
||||
```
|
||||
用户: 创建一个新的 gitea 仓库,名为 my-project
|
||||
用户: 在 ai 组织下创建仓库 test-repo
|
||||
用户: 创建公开仓库 open-source-project
|
||||
```
|
||||
|
||||
AI 会自动:
|
||||
1. 加载 Gitea 配置
|
||||
2. 解析仓库名称和 owner
|
||||
3. 调用 API 创建仓库
|
||||
4. 提示是否添加为 Git remote
|
||||
5. 显示仓库信息(URLs 等)
|
||||
|
||||
### 创建流程详解
|
||||
|
||||
#### 步骤 1: 加载配置
|
||||
|
||||
```bash
|
||||
config_file="$HOME/.config/gitea/config.env"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Gitea 未配置,请运行 /gitea-reset"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$config_file"
|
||||
```
|
||||
|
||||
#### 步骤 2: 解析输入
|
||||
|
||||
```bash
|
||||
input="$1"
|
||||
|
||||
# 解析 owner/repo
|
||||
if [[ "$input" =~ / ]]; then
|
||||
owner=$(echo "$input" | cut -d'/' -f1)
|
||||
repo=$(echo "$input" | cut -d'/' -f2)
|
||||
else
|
||||
# 使用默认组织或当前用户
|
||||
if [ -z "$GITEA_DEFAULT_ORG" ]; then
|
||||
# 获取当前用户
|
||||
owner=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/user" | jq -r '.login')
|
||||
|
||||
if [ -z "$owner" ] || [ "$owner" = "null" ]; then
|
||||
echo "❌ 无法获取当前用户信息,请使用 owner/repo 格式"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "使用当前用户: $owner"
|
||||
else
|
||||
owner="$GITEA_DEFAULT_ORG"
|
||||
echo "使用默认组织: $owner"
|
||||
fi
|
||||
repo="$input"
|
||||
fi
|
||||
|
||||
# 解析可见性
|
||||
visibility="${2:-private}"
|
||||
private_bool=$([ "$visibility" = "private" ] && echo "true" || echo "false")
|
||||
```
|
||||
|
||||
#### 步骤 3: 验证仓库名
|
||||
|
||||
```bash
|
||||
# 仓库名只能包含字母、数字、下划线、连字符和点
|
||||
if ! [[ "$repo" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
|
||||
echo "❌ 仓库名只能包含字母、数字、下划线、连字符和点"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
#### 步骤 4: 调用 API 创建
|
||||
|
||||
```bash
|
||||
echo "正在创建仓库: $owner/$repo ($visibility)"
|
||||
|
||||
# 尝试组织仓库
|
||||
response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"name\": \"${repo}\",
|
||||
\"private\": ${private_bool},
|
||||
\"auto_init\": false,
|
||||
\"default_branch\": \"main\"
|
||||
}" \
|
||||
"${GITEA_URL}/api/v1/orgs/${owner}/repos")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
# 如果 404,可能是用户而非组织
|
||||
if [ "$http_code" = "404" ]; then
|
||||
echo "⚠️ 组织不存在,尝试创建用户仓库..."
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"name\": \"${repo}\",
|
||||
\"private\": ${private_bool}
|
||||
}" \
|
||||
"${GITEA_URL}/api/v1/user/repos")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
fi
|
||||
|
||||
# 处理响应
|
||||
case "$http_code" in
|
||||
201)
|
||||
echo "✓ 仓库创建成功"
|
||||
;;
|
||||
409)
|
||||
echo "❌ 仓库已存在"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "❌ 创建失败 (HTTP $http_code)"
|
||||
echo "$body" | jq -r '.message // empty'
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
#### 步骤 5: 提取仓库信息
|
||||
|
||||
```bash
|
||||
html_url=$(echo "$body" | jq -r '.html_url')
|
||||
clone_url=$(echo "$body" | jq -r '.clone_url')
|
||||
ssh_url=$(echo "$body" | jq -r '.ssh_url')
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "仓库信息"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 名称: $owner/$repo"
|
||||
echo " 可见性: $visibility"
|
||||
echo " Web URL: $html_url"
|
||||
echo " HTTPS URL: $clone_url"
|
||||
echo " SSH URL: $ssh_url"
|
||||
echo ""
|
||||
```
|
||||
|
||||
#### 步骤 6: 添加 Git Remote
|
||||
|
||||
```bash
|
||||
read -p "是否将此仓库添加为 Git remote? [Y/n] " add_remote
|
||||
|
||||
if [[ ! "$add_remote" =~ ^[Nn]$ ]]; then
|
||||
# 检查是否是 Git 仓库
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "当前目录不是 Git 仓库"
|
||||
read -p "是否初始化 Git 仓库? [Y/n] " init_git
|
||||
|
||||
if [[ ! "$init_git" =~ ^[Nn]$ ]]; then
|
||||
git init
|
||||
echo "✓ Git 仓库已初始化"
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 检查 origin 是否已存在
|
||||
if git remote get-url origin >/dev/null 2>&1; then
|
||||
existing_url=$(git remote get-url origin)
|
||||
echo "⚠️ origin remote 已存在: $existing_url"
|
||||
read -p "是否覆盖? [y/N] " overwrite
|
||||
|
||||
if [[ "$overwrite" =~ ^[Yy]$ ]]; then
|
||||
git remote set-url origin "$clone_url"
|
||||
echo "✓ origin remote 已更新"
|
||||
fi
|
||||
else
|
||||
git remote add origin "$clone_url"
|
||||
echo "✓ origin remote 已添加"
|
||||
fi
|
||||
|
||||
# 显示 remote 信息
|
||||
echo ""
|
||||
echo "当前 remote:"
|
||||
git remote -v
|
||||
fi
|
||||
```
|
||||
|
||||
## 仓库初始化
|
||||
|
||||
### 初始化基本结构
|
||||
|
||||
创建常见的仓库文件:
|
||||
|
||||
```bash
|
||||
# README.md
|
||||
cat > README.md << 'EOF'
|
||||
# Project Name
|
||||
|
||||
项目描述
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 特性 1
|
||||
- 特性 2
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
make install
|
||||
|
||||
# 运行项目
|
||||
make run
|
||||
```
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
EOF
|
||||
|
||||
# .gitignore
|
||||
cat > .gitignore << 'EOF'
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
vendor/
|
||||
|
||||
# Build
|
||||
dist/
|
||||
build/
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.local
|
||||
EOF
|
||||
|
||||
# LICENSE
|
||||
cat > LICENSE << 'EOF'
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026
|
||||
|
||||
Permission is hereby granted...
|
||||
EOF
|
||||
|
||||
git add README.md .gitignore LICENSE
|
||||
git commit -m "Initial commit: Add basic project files"
|
||||
```
|
||||
|
||||
### 创建分支保护规则
|
||||
|
||||
```bash
|
||||
# 通过 API 设置分支保护(需要管理员权限)
|
||||
curl -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"enable_push": false,
|
||||
"enable_push_whitelist": true,
|
||||
"push_whitelist_usernames": ["admin"],
|
||||
"require_signed_commits": false,
|
||||
"enable_status_check": true,
|
||||
"status_check_contexts": ["continuous-integration/gitea"]
|
||||
}' \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/branch_protections"
|
||||
```
|
||||
|
||||
## Actions 配置
|
||||
|
||||
### 启用 Actions
|
||||
|
||||
Actions 在 Gitea 1.19+ 中默认启用,无需额外配置。
|
||||
|
||||
### 配置 Secrets
|
||||
|
||||
**方法 1: 通过 UI**
|
||||
|
||||
1. 打开仓库 → Settings → Secrets → Actions
|
||||
2. 点击 "New Secret"
|
||||
3. 输入 Name 和 Value
|
||||
4. 保存
|
||||
|
||||
**方法 2: 通过 API**
|
||||
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
|
||||
owner="ai"
|
||||
repo="my-project"
|
||||
secret_name="DEPLOY_KEY"
|
||||
secret_value="super-secret-key"
|
||||
|
||||
# Base64 编码
|
||||
encoded=$(echo -n "$secret_value" | base64)
|
||||
|
||||
# 创建 Secret
|
||||
curl -X PUT \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"data\":\"${encoded}\"}" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/actions/secrets/$secret_name"
|
||||
|
||||
echo "✓ Secret $secret_name 已创建"
|
||||
```
|
||||
|
||||
### 配置 Variables
|
||||
|
||||
Variables 用于非敏感配置:
|
||||
|
||||
```bash
|
||||
owner="ai"
|
||||
repo="my-project"
|
||||
var_name="ENVIRONMENT"
|
||||
var_value="production"
|
||||
|
||||
# 创建 Variable
|
||||
curl -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"value\":\"${var_value}\"}" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/actions/variables/$var_name"
|
||||
|
||||
echo "✓ Variable $var_name 已创建"
|
||||
```
|
||||
|
||||
### 批量配置 Secrets
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source ~/.config/gitea/config.env
|
||||
|
||||
owner="ai"
|
||||
repo="my-project"
|
||||
|
||||
# Secret 列表
|
||||
declare -A secrets=(
|
||||
["REGISTRY_PASSWORD"]="docker-password"
|
||||
["API_TOKEN"]="api-token-value"
|
||||
["DEPLOY_KEY"]="ssh-private-key"
|
||||
)
|
||||
|
||||
for name in "${!secrets[@]}"; do
|
||||
value="${secrets[$name]}"
|
||||
encoded=$(echo -n "$value" | base64)
|
||||
|
||||
curl -s -X PUT \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"data\":\"${encoded}\"}" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/actions/secrets/$name"
|
||||
|
||||
echo "✓ $name"
|
||||
done
|
||||
```
|
||||
|
||||
## Webhook 配置
|
||||
|
||||
### 创建 Webhook
|
||||
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
|
||||
owner="ai"
|
||||
repo="my-project"
|
||||
webhook_url="https://example.com/webhook"
|
||||
webhook_secret="webhook-secret-key"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"type\": \"gitea\",
|
||||
\"config\": {
|
||||
\"url\": \"${webhook_url}\",
|
||||
\"content_type\": \"json\",
|
||||
\"secret\": \"${webhook_secret}\"
|
||||
},
|
||||
\"events\": [\"push\", \"pull_request\", \"release\"],
|
||||
\"active\": true
|
||||
}" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/hooks"
|
||||
|
||||
echo "✓ Webhook 已创建"
|
||||
```
|
||||
|
||||
### 常用事件类型
|
||||
|
||||
| 事件 | 说明 |
|
||||
|------|------|
|
||||
| `push` | 代码推送 |
|
||||
| `pull_request` | PR 创建/更新 |
|
||||
| `issues` | Issue 创建/更新 |
|
||||
| `release` | Release 发布 |
|
||||
| `create` | 分支/标签创建 |
|
||||
| `delete` | 分支/标签删除 |
|
||||
|
||||
### 列出 Webhooks
|
||||
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/hooks" | jq .
|
||||
```
|
||||
|
||||
### 删除 Webhook
|
||||
|
||||
```bash
|
||||
hook_id=1
|
||||
|
||||
curl -X DELETE \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/hooks/$hook_id"
|
||||
```
|
||||
|
||||
## 仓库设置
|
||||
|
||||
### 更新仓库信息
|
||||
|
||||
```bash
|
||||
curl -X PATCH \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"description": "新的仓库描述",
|
||||
"website": "https://example.com",
|
||||
"private": false,
|
||||
"has_issues": true,
|
||||
"has_wiki": false,
|
||||
"default_branch": "main"
|
||||
}' \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo"
|
||||
```
|
||||
|
||||
### 启用/禁用功能
|
||||
|
||||
```bash
|
||||
# 禁用 Wiki
|
||||
curl -X PATCH \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"has_wiki": false}' \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo"
|
||||
|
||||
# 启用 Issues
|
||||
curl -X PATCH \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"has_issues": true}' \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo"
|
||||
```
|
||||
|
||||
## 协作者管理
|
||||
|
||||
### 添加协作者
|
||||
|
||||
```bash
|
||||
username="collaborator"
|
||||
|
||||
curl -X PUT \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"permission": "write"}' \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/collaborators/$username"
|
||||
|
||||
echo "✓ 已添加协作者: $username"
|
||||
```
|
||||
|
||||
**权限级别**:
|
||||
- `read`: 只读
|
||||
- `write`: 读写
|
||||
- `admin`: 管理员
|
||||
|
||||
### 列出协作者
|
||||
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/collaborators" | jq .
|
||||
```
|
||||
|
||||
### 移除协作者
|
||||
|
||||
```bash
|
||||
username="collaborator"
|
||||
|
||||
curl -X DELETE \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/collaborators/$username"
|
||||
```
|
||||
|
||||
## 常见操作
|
||||
|
||||
### 检查仓库是否存在
|
||||
|
||||
```bash
|
||||
repo_exists() {
|
||||
local owner="$1"
|
||||
local repo="$2"
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
[ "$http_code" = "200" ]
|
||||
}
|
||||
|
||||
if repo_exists "ai" "my-project"; then
|
||||
echo "仓库存在"
|
||||
else
|
||||
echo "仓库不存在"
|
||||
fi
|
||||
```
|
||||
|
||||
### 归档仓库
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo/archive"
|
||||
|
||||
echo "✓ 仓库已归档"
|
||||
```
|
||||
|
||||
### 删除仓库
|
||||
|
||||
```bash
|
||||
echo "⚠️ 警告: 此操作无法撤销!"
|
||||
read -p "确认删除仓库 $owner/$repo? 输入 'yes' 确认: " confirm
|
||||
|
||||
if [ "$confirm" = "yes" ]; then
|
||||
curl -X DELETE \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo"
|
||||
|
||||
echo "✓ 仓库已删除"
|
||||
else
|
||||
echo "已取消"
|
||||
fi
|
||||
```
|
||||
|
||||
## 批量操作
|
||||
|
||||
### 批量创建仓库
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source ~/.config/gitea/config.env
|
||||
|
||||
org="ai"
|
||||
repos=("project-a" "project-b" "project-c")
|
||||
|
||||
for repo in "${repos[@]}"; do
|
||||
echo "创建仓库: $repo"
|
||||
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"name\": \"${repo}\",
|
||||
\"private\": true,
|
||||
\"auto_init\": true
|
||||
}" \
|
||||
"$GITEA_URL/api/v1/orgs/$org/repos" | jq -r '.html_url'
|
||||
|
||||
sleep 1 # 避免请求过快
|
||||
done
|
||||
```
|
||||
|
||||
### 批量配置 Secrets
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source ~/.config/gitea/config.env
|
||||
|
||||
org="ai"
|
||||
repos=("repo1" "repo2" "repo3")
|
||||
secret_name="DEPLOY_KEY"
|
||||
secret_value="shared-secret"
|
||||
|
||||
encoded=$(echo -n "$secret_value" | base64)
|
||||
|
||||
for repo in "${repos[@]}"; do
|
||||
echo "配置 $repo..."
|
||||
|
||||
curl -s -X PUT \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"data\":\"${encoded}\"}" \
|
||||
"$GITEA_URL/api/v1/repos/$org/$repo/actions/secrets/$secret_name"
|
||||
|
||||
echo "✓ $repo"
|
||||
done
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 仓库创建失败
|
||||
|
||||
**症状**: HTTP 409 - 仓库已存在
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 列出所有仓库
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/orgs/$org/repos" | jq -r '.[].name'
|
||||
```
|
||||
|
||||
### Secret 配置失败
|
||||
|
||||
**症状**: HTTP 404 - 仓库不存在
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 检查仓库是否存在
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$owner/$repo"
|
||||
```
|
||||
|
||||
### 权限不足
|
||||
|
||||
**症状**: HTTP 403 - Forbidden
|
||||
|
||||
**解决**:
|
||||
- 检查 Token 是否有 `repo` 权限
|
||||
- 检查是否是仓库/组织的成员
|
||||
- 使用管理员账户
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Gitea API 文档](https://docs.gitea.com/api/1.20/)
|
||||
- [API 参考](./api-reference.md)
|
||||
- [环境配置](./setup-guide.md)
|
||||
- [Workflow 生成器](./workflow-generator.md)
|
||||
|
||||
## 版本
|
||||
|
||||
- **文档版本**: 1.0
|
||||
- **最后更新**: 2026-01-12
|
||||
808
skill/gitea/runner-management.md
Normal file
808
skill/gitea/runner-management.md
Normal file
@@ -0,0 +1,808 @@
|
||||
# Gitea Runner 管理
|
||||
|
||||
完整的 Gitea Act Runner 创建、注册、配置和管理指南。
|
||||
|
||||
## 概述
|
||||
|
||||
Gitea Act Runner 是 Gitea Actions 的 CI/CD 执行器,兼容 GitHub Actions workflow 语法。
|
||||
|
||||
### Runner 级别
|
||||
|
||||
| 级别 | 作用域 | 权限要求 | 适用场景 |
|
||||
|------|--------|---------|---------|
|
||||
| **全局 Runner** | 所有组织和仓库 | 管理员 Token | 共享资源、统一管理 |
|
||||
| **组织 Runner** | 特定组织 | 组织管理权限 | 组织内项目共享 |
|
||||
| **仓库 Runner** | 特定仓库 | 仓库管理权限 | 独立项目使用 |
|
||||
|
||||
**推荐**:
|
||||
- 小团队或个人使用:**全局 Runner**(统一管理,配置简单)
|
||||
- 企业多组织:**组织 Runner**(隔离资源,权限分离)
|
||||
|
||||
### 执行模式
|
||||
|
||||
| 模式 | 环境 | 适用场景 | Android SDK |
|
||||
|------|------|---------|-------------|
|
||||
| **Host Mode** | Native macOS/Linux | Android/iOS 构建、原生工具链 | macOS ARM64 支持 |
|
||||
| Docker Mode | Linux 容器 | 跨平台构建 | Linux ARM64 不支持 |
|
||||
|
||||
**推荐**:macOS ARM64 使用 **Host Mode** 以支持 Android SDK。
|
||||
|
||||
## Runner 目录结构
|
||||
|
||||
所有 Runner 配置统一管理在:
|
||||
|
||||
```
|
||||
~/.config/gitea/runners/
|
||||
├── runner-macbook-pro/ # Runner 1
|
||||
│ ├── .runner # 注册信息(JSON)
|
||||
│ ├── config.yaml # Runner 配置
|
||||
│ ├── cache/ # Cache 目录
|
||||
│ └── workspace/ # 工作目录
|
||||
└── runner-mac-mini/ # Runner 2
|
||||
└── ...
|
||||
```
|
||||
|
||||
## 前置要求
|
||||
|
||||
### 1. 安装 act_runner
|
||||
|
||||
```bash
|
||||
# 使用 Homebrew(推荐)
|
||||
brew install act_runner
|
||||
|
||||
# 或手动下载
|
||||
curl -sL https://gitea.com/gitea/act_runner/releases/download/v0.2.13/act_runner-0.2.13-darwin-arm64 \
|
||||
-o /usr/local/bin/act_runner
|
||||
chmod +x /usr/local/bin/act_runner
|
||||
|
||||
# 验证安装
|
||||
act_runner --version
|
||||
```
|
||||
|
||||
### 2. 安装开发工具(可选,根据需要)
|
||||
|
||||
```bash
|
||||
# Go(Go 项目构建)
|
||||
brew install go
|
||||
|
||||
# Node.js(前端项目构建)
|
||||
brew install node@22
|
||||
npm install -g pnpm
|
||||
|
||||
# JDK 17(Android 项目构建)
|
||||
brew install openjdk@17
|
||||
|
||||
# Docker(容器构建)
|
||||
# 从 https://docker.com 安装 Docker Desktop
|
||||
```
|
||||
|
||||
### 3. 安装 Android SDK(Android 项目构建)
|
||||
|
||||
```bash
|
||||
# 使用 Homebrew
|
||||
brew install --cask android-commandlinetools
|
||||
|
||||
# 或手动安装
|
||||
mkdir -p ~/android-sdk/cmdline-tools
|
||||
cd ~/android-sdk/cmdline-tools
|
||||
curl -sL https://dl.google.com/android/repository/commandlinetools-mac-11076708_latest.zip -o cmdline-tools.zip
|
||||
unzip cmdline-tools.zip
|
||||
mv cmdline-tools latest
|
||||
rm cmdline-tools.zip
|
||||
|
||||
# 接受许可并安装组件
|
||||
yes | sdkmanager --licenses
|
||||
sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0"
|
||||
```
|
||||
|
||||
### 4. 配置环境变量
|
||||
|
||||
添加到 `~/.zshrc` 或 `~/.bashrc`:
|
||||
|
||||
```bash
|
||||
# Go
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
|
||||
# Java
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@17
|
||||
export PATH=$PATH:$JAVA_HOME/bin
|
||||
|
||||
# Android SDK
|
||||
export ANDROID_HOME=~/android-sdk
|
||||
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
|
||||
export PATH=$PATH:$ANDROID_HOME/platform-tools
|
||||
```
|
||||
|
||||
重新加载配置:
|
||||
```bash
|
||||
source ~/.zshrc # 或 source ~/.bashrc
|
||||
```
|
||||
|
||||
### 5. 验证环境
|
||||
|
||||
```bash
|
||||
go version # Go 1.23+
|
||||
node --version # v22.x
|
||||
pnpm --version # Latest
|
||||
java -version # 17+
|
||||
echo $ANDROID_HOME # SDK 路径
|
||||
docker --version # Latest
|
||||
act_runner --version
|
||||
```
|
||||
|
||||
## 创建 Runner
|
||||
|
||||
### 使用命令快速创建
|
||||
|
||||
```bash
|
||||
/gitea-create-runner
|
||||
```
|
||||
|
||||
此命令会自动:
|
||||
1. 检查并安装 act_runner(如未安装)
|
||||
2. 加载 Gitea 配置(如不存在则提示初始化)
|
||||
3. 生成 runner 名称(基于主机名)
|
||||
4. 检测系统环境并生成 labels
|
||||
5. 创建 runner 目录结构
|
||||
6. 生成 host 模式配置文件
|
||||
7. 获取注册 token(优先全局)
|
||||
8. 注册并启动 runner
|
||||
|
||||
### 详细创建流程
|
||||
|
||||
当运行 `/gitea-create-runner` 命令时,会执行以下步骤:
|
||||
|
||||
#### 步骤 1: 检查 act_runner 安装
|
||||
|
||||
```bash
|
||||
if command -v act_runner &> /dev/null; then
|
||||
echo "✓ act_runner 已安装"
|
||||
else
|
||||
echo "⚠️ act_runner 未安装,正在安装..."
|
||||
brew install act_runner
|
||||
fi
|
||||
```
|
||||
|
||||
#### 步骤 2: 加载 Gitea 配置
|
||||
|
||||
```bash
|
||||
config_file="$HOME/.config/gitea/config.env"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Gitea 配置不存在,请先初始化: /gitea-reset"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$config_file"
|
||||
```
|
||||
|
||||
#### 步骤 3: 生成 Runner 名称
|
||||
|
||||
```bash
|
||||
# 基于主机名自动生成
|
||||
hostname=$(hostname -s)
|
||||
runner_name="runner-$hostname"
|
||||
|
||||
# 或使用命令参数
|
||||
# /gitea-create-runner my-custom-name
|
||||
```
|
||||
|
||||
#### 步骤 4: 智能检测系统环境和 Labels
|
||||
|
||||
```bash
|
||||
# 检测操作系统
|
||||
OS=$(uname -s)
|
||||
case "$OS" in
|
||||
Darwin) os_label="macOS" ;;
|
||||
Linux) os_label="ubuntu" ;;
|
||||
*) os_label="unknown" ;;
|
||||
esac
|
||||
|
||||
# 检测架构
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
arm64|aarch64) arch_label="ARM64" ;;
|
||||
x86_64) arch_label="x64" ;;
|
||||
*) arch_label="unknown" ;;
|
||||
esac
|
||||
|
||||
# 生成组合 label
|
||||
combined=$(echo "${OS}-${ARCH}" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# 生成建议的 labels
|
||||
suggested_labels="self-hosted:host,${os_label}:host,${arch_label}:host,${combined}:host"
|
||||
|
||||
echo ""
|
||||
echo "检测到系统环境:"
|
||||
echo " 操作系统: $OS ($os_label)"
|
||||
echo " 架构: $ARCH ($arch_label)"
|
||||
echo ""
|
||||
echo "建议的 Runner Labels:"
|
||||
echo " $suggested_labels"
|
||||
echo ""
|
||||
```
|
||||
|
||||
**输出示例**:
|
||||
```
|
||||
检测到系统环境:
|
||||
操作系统: Darwin (macOS)
|
||||
架构: arm64 (ARM64)
|
||||
|
||||
建议的 Runner Labels:
|
||||
self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
|
||||
```
|
||||
|
||||
#### 步骤 5: 创建 Runner 目录
|
||||
|
||||
```bash
|
||||
runners_dir="$HOME/.config/gitea/runners"
|
||||
runner_dir="$runners_dir/$runner_name"
|
||||
|
||||
# 检查是否已存在
|
||||
if [ -d "$runner_dir" ]; then
|
||||
echo "❌ Runner '$runner_name' 已存在"
|
||||
echo "请使用其他名称或先删除现有 runner: /gitea-delete-runner $runner_name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 创建目录结构
|
||||
mkdir -p "$runner_dir"/{cache,workspace}
|
||||
|
||||
echo "✓ 创建目录: $runner_dir"
|
||||
```
|
||||
|
||||
#### 步骤 6: 生成配置文件
|
||||
|
||||
**默认生成 Host Mode 配置**:
|
||||
|
||||
```yaml
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: $HOME/.config/gitea/runners/$runner_name/.runner
|
||||
capacity: ${GITEA_RUNNER_CAPACITY:-2}
|
||||
timeout: ${GITEA_RUNNER_TIMEOUT:-3h}
|
||||
shutdown_timeout: 30s
|
||||
insecure: false
|
||||
fetch_timeout: 5s
|
||||
fetch_interval: 2s
|
||||
labels:
|
||||
- "self-hosted:host"
|
||||
- "macOS:host"
|
||||
- "ARM64:host"
|
||||
- "darwin-arm64:host"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "$HOME/.config/gitea/runners/$runner_name/cache"
|
||||
host: "127.0.0.1"
|
||||
port: 9000
|
||||
|
||||
host:
|
||||
workdir_parent: "$HOME/.config/gitea/runners/$runner_name/workspace"
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 默认使用 Host Mode(支持 Android SDK、iOS 等原生工具)
|
||||
- 自动填充系统检测的 labels
|
||||
- 容量和超时可通过环境变量配置
|
||||
|
||||
#### 步骤 7: 获取注册 Token
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "正在获取 Runner 注册 Token..."
|
||||
|
||||
# 默认尝试全局 Runner(管理员权限)
|
||||
echo "尝试创建全局 Runner(可用于所有组织和仓库)..."
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/admin/runners/registration-token")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
# 如果全局 Runner 失败(权限不足),降级到组织 Runner
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "⚠️ 全局 Runner 权限不足 (HTTP $http_code)"
|
||||
echo " 全局 Runner 需要管理员 Token"
|
||||
echo ""
|
||||
echo "降级到组织 Runner..."
|
||||
|
||||
runner_level="organization"
|
||||
|
||||
if [ -n "$GITEA_DEFAULT_ORG" ]; then
|
||||
org_name="$GITEA_DEFAULT_ORG"
|
||||
else
|
||||
read -p "请输入组织名称: " org_input
|
||||
if [ -z "$org_input" ]; then
|
||||
echo "❌ 必须指定组织名称"
|
||||
exit 1
|
||||
fi
|
||||
org_name="$org_input"
|
||||
fi
|
||||
|
||||
echo "使用组织: $org_name"
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/orgs/$org_name/actions/runners/registration-token")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
else
|
||||
echo "✓ 使用全局 Runner"
|
||||
runner_level="global"
|
||||
fi
|
||||
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "❌ 获取注册 Token 失败 (HTTP $http_code)"
|
||||
echo "$body"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
registration_token=$(echo "$body" | jq -r '.token')
|
||||
echo "✓ 注册 Token 已获取"
|
||||
```
|
||||
|
||||
#### 步骤 8: 注册 Runner
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "正在注册 Runner..."
|
||||
|
||||
act_runner register \
|
||||
--config "$runner_dir/config.yaml" \
|
||||
--instance "$GITEA_URL" \
|
||||
--token "$registration_token" \
|
||||
--name "$runner_name" \
|
||||
--labels "$labels" \
|
||||
--no-interactive
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✓ Runner 注册成功"
|
||||
else
|
||||
echo "❌ Runner 注册失败"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
#### 步骤 9: 自动启动 Runner
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "正在启动 Runner..."
|
||||
|
||||
# 后台启动 Runner
|
||||
nohup act_runner daemon --config "$runner_dir/config.yaml" \
|
||||
> "$runner_dir/runner.log" 2>&1 &
|
||||
|
||||
runner_pid=$!
|
||||
|
||||
# 等待 2 秒让 runner 启动
|
||||
sleep 2
|
||||
|
||||
# 检查进程是否存在
|
||||
if ps -p $runner_pid > /dev/null 2>&1; then
|
||||
echo "✓ Runner 已启动 (PID: $runner_pid)"
|
||||
else
|
||||
echo "⚠️ Runner 启动失败,请查看日志:"
|
||||
echo " tail -f $runner_dir/runner.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Runner 创建完成!"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Runner 名称: $runner_name"
|
||||
echo "Runner 级别: ${runner_level}"
|
||||
if [ "$runner_level" = "organization" ]; then
|
||||
echo "所属组织: ${org_name}"
|
||||
fi
|
||||
echo "PID: $runner_pid"
|
||||
echo "配置文件: $runner_dir/config.yaml"
|
||||
echo "工作目录: $runner_dir/workspace"
|
||||
echo "Cache 目录: $runner_dir/cache"
|
||||
echo "日志文件: $runner_dir/runner.log"
|
||||
echo ""
|
||||
echo "管理命令:"
|
||||
echo " 查看日志: tail -f $runner_dir/runner.log"
|
||||
echo " 停止 Runner: pkill -f 'act_runner daemon --config.*$runner_name'"
|
||||
echo " 查看所有: /gitea-list-runners"
|
||||
echo " 删除 Runner: /gitea-delete-runner $runner_name"
|
||||
echo ""
|
||||
```
|
||||
|
||||
## Label 设计指南
|
||||
|
||||
### Label 格式
|
||||
|
||||
```
|
||||
label-name:mode
|
||||
```
|
||||
|
||||
**Mode 类型**:
|
||||
- `host`: Host Mode(原生执行)
|
||||
- `docker://image`: Docker Mode(容器执行)
|
||||
|
||||
### 推荐 Labels
|
||||
|
||||
#### macOS ARM64
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "self-hosted:host"
|
||||
- "macOS:host"
|
||||
- "ARM64:host"
|
||||
- "darwin-arm64:host"
|
||||
```
|
||||
|
||||
#### Linux x64
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "self-hosted:host"
|
||||
- "ubuntu:host"
|
||||
- "x64:host"
|
||||
- "linux-x64:host"
|
||||
```
|
||||
|
||||
#### Docker Mode
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"
|
||||
- "ubuntu-22.04:docker://catthehacker/ubuntu:act-latest"
|
||||
```
|
||||
|
||||
### Workflow 匹配
|
||||
|
||||
**方法 1: 组合 label(推荐,最精确)**
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: darwin-arm64
|
||||
```
|
||||
|
||||
**方法 2: Label 数组(匹配多个条件)**
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
```
|
||||
|
||||
**方法 3: 仅操作系统**
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macOS
|
||||
```
|
||||
|
||||
## Runner 配置详解
|
||||
|
||||
### Host Mode 配置
|
||||
|
||||
```yaml
|
||||
log:
|
||||
level: info # 日志级别:debug/info/warn/error
|
||||
|
||||
runner:
|
||||
file: /path/to/.runner # 注册信息文件
|
||||
capacity: 2 # 并发任务数
|
||||
timeout: 3h # 任务超时时间
|
||||
shutdown_timeout: 30s # 关闭超时时间
|
||||
insecure: false # 是否允许不安全连接
|
||||
fetch_timeout: 5s # 获取任务超时
|
||||
fetch_interval: 2s # 获取任务间隔
|
||||
labels:
|
||||
- "label-name:host" # Runner labels
|
||||
|
||||
cache:
|
||||
enabled: true # 启用缓存
|
||||
dir: "/path/to/cache" # 缓存目录
|
||||
host: "127.0.0.1" # 监听地址(仅本地)
|
||||
port: 9000 # 缓存服务端口
|
||||
|
||||
host:
|
||||
workdir_parent: "/path/to/workspace" # 工作目录父路径
|
||||
```
|
||||
|
||||
### Docker Mode 配置
|
||||
|
||||
```yaml
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: /path/to/.runner
|
||||
capacity: 2
|
||||
timeout: 3h
|
||||
labels:
|
||||
- "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "/path/to/cache"
|
||||
host: "192.168.0.103" # 主机 IP(非 127.0.0.1)
|
||||
port: 9000
|
||||
|
||||
container:
|
||||
options: "--platform=linux/amd64" # 容器选项
|
||||
network: "host" # 网络模式
|
||||
```
|
||||
|
||||
## 多 Runner 缓存共享
|
||||
|
||||
### 方案 A: Master-Slave 模式(推荐 2-3 个 runner)
|
||||
|
||||
**主 Runner(cache server)**:
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "$HOME/.config/gitea/runners/runner-primary/cache"
|
||||
host: "0.0.0.0" # 监听所有接口
|
||||
port: 9000
|
||||
```
|
||||
|
||||
**从 Runner(cache client)**:
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
enabled: true
|
||||
server: "http://192.168.0.103:9000" # 主 runner IP
|
||||
dir: "$HOME/.config/gitea/runners/runner-secondary/cache" # 本地备份
|
||||
host: "192.168.0.104" # 本 runner IP
|
||||
port: 9000
|
||||
```
|
||||
|
||||
### 方案 B: NFS 共享存储(企业级)
|
||||
|
||||
**1. 在主 Runner 上设置 NFS server**:
|
||||
|
||||
```bash
|
||||
# /etc/exports
|
||||
/Users/voson/.config/gitea/cache -alldirs -mapall=$(id -u):$(id -g) 192.168.0.0/24
|
||||
|
||||
sudo nfsd restart
|
||||
```
|
||||
|
||||
**2. 在从 Runner 上挂载**:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /mnt/runner-cache
|
||||
sudo mount -t nfs 192.168.0.103:/Users/voson/.config/gitea/cache /mnt/runner-cache
|
||||
```
|
||||
|
||||
### 方案 C: 独立缓存(默认)
|
||||
|
||||
每个 runner 维护自己的缓存。首次构建下载依赖,后续构建使用本地缓存。
|
||||
|
||||
## 缓存管理
|
||||
|
||||
### Host Mode 缓存位置
|
||||
|
||||
| 缓存类型 | 位置 | 行为 |
|
||||
|---------|------|------|
|
||||
| Runner cache service | `config.cache.dir` | act_runner 管理 |
|
||||
| Gradle | `~/.gradle/` | 跨构建持久化 |
|
||||
| npm/pnpm | `~/.npm/`, `~/.pnpm-store/` | 跨构建持久化 |
|
||||
| Go modules | `~/go/pkg/mod/` | 跨构建持久化 |
|
||||
|
||||
### 缓存清理脚本
|
||||
|
||||
创建 `~/.config/gitea/cleanup-cache.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "清理 Gitea Runner 缓存..."
|
||||
|
||||
runners_dir="$HOME/.config/gitea/runners"
|
||||
|
||||
# 1. Runner cache(超过 7 天)
|
||||
find "$runners_dir"/*/cache -type f -mtime +7 -delete 2>/dev/null || true
|
||||
echo "✓ Runner cache 已清理"
|
||||
|
||||
# 2. Gradle cache(超过 30 天)
|
||||
find ~/.gradle/caches -type f -mtime +30 -delete 2>/dev/null || true
|
||||
find ~/.gradle/caches -type d -empty -delete 2>/dev/null || true
|
||||
echo "✓ Gradle cache 已清理"
|
||||
|
||||
# 3. npm cache 验证
|
||||
npm cache verify
|
||||
echo "✓ npm cache 已验证"
|
||||
|
||||
# 4. Workspace 清理(超过 7 天)
|
||||
find "$runners_dir"/*/workspace -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \; 2>/dev/null || true
|
||||
echo "✓ Workspace 已清理"
|
||||
|
||||
# 显示缓存大小
|
||||
echo ""
|
||||
echo "当前缓存大小:"
|
||||
for runner in "$runners_dir"/*; do
|
||||
if [ -d "$runner" ]; then
|
||||
name=$(basename "$runner")
|
||||
size=$(du -sh "$runner/cache" 2>/dev/null | awk '{print $1}')
|
||||
echo " $name: ${size:-0B}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "✓ 清理完成"
|
||||
```
|
||||
|
||||
### 定时清理
|
||||
|
||||
```bash
|
||||
# 添加到 crontab
|
||||
chmod +x ~/.config/gitea/cleanup-cache.sh
|
||||
crontab -e
|
||||
|
||||
# 每周日凌晨 3 点清理
|
||||
0 3 * * 0 ~/.config/gitea/cleanup-cache.sh >> ~/.config/gitea/cleanup.log 2>&1
|
||||
```
|
||||
|
||||
## Runner 管理命令
|
||||
|
||||
### 列出所有 Runners
|
||||
|
||||
```bash
|
||||
/gitea-list-runners
|
||||
```
|
||||
|
||||
### 启动 Runner
|
||||
|
||||
```bash
|
||||
# 前台运行(调试用)
|
||||
act_runner daemon --config ~/.config/gitea/runners/runner-macbook-pro/config.yaml
|
||||
|
||||
# 后台运行
|
||||
nohup act_runner daemon --config ~/.config/gitea/runners/runner-macbook-pro/config.yaml \
|
||||
> ~/.config/gitea/runners/runner-macbook-pro/runner.log 2>&1 &
|
||||
```
|
||||
|
||||
### 停止 Runner
|
||||
|
||||
```bash
|
||||
# 查找进程
|
||||
ps aux | grep "act_runner daemon"
|
||||
|
||||
# 停止特定 runner
|
||||
pkill -f "act_runner daemon --config.*runner-macbook-pro"
|
||||
|
||||
# 停止所有 runners
|
||||
pkill -f "act_runner daemon"
|
||||
```
|
||||
|
||||
### 查看 Runner 日志
|
||||
|
||||
```bash
|
||||
# 实时查看
|
||||
tail -f ~/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
|
||||
# 查看最近 100 行
|
||||
tail -n 100 ~/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
```
|
||||
|
||||
### 删除 Runner
|
||||
|
||||
```bash
|
||||
/gitea-delete-runner runner-macbook-pro
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. Android SDK 未找到
|
||||
|
||||
```bash
|
||||
# 验证 ANDROID_HOME
|
||||
echo $ANDROID_HOME
|
||||
ls $ANDROID_HOME
|
||||
|
||||
# 确保 runner 以安装 SDK 的用户身份运行
|
||||
whoami
|
||||
```
|
||||
|
||||
### 2. JDK 版本错误
|
||||
|
||||
Android Gradle Plugin 8.x 需要 JDK 17+:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
# 应显示: openjdk version "17.x.x"
|
||||
|
||||
# 如果版本错误,更新 JAVA_HOME
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@17
|
||||
```
|
||||
|
||||
### 3. 权限问题
|
||||
|
||||
```bash
|
||||
# 确保 runner 用户拥有工作目录
|
||||
chown -R $(whoami) ~/.config/gitea/runners
|
||||
chmod -R 755 ~/.config/gitea/runners
|
||||
```
|
||||
|
||||
### 4. Label 不匹配
|
||||
|
||||
```bash
|
||||
# 检查注册的 labels
|
||||
cat ~/.config/gitea/runners/runner-macbook-pro/.runner | jq '.labels'
|
||||
|
||||
# 确保 workflow runs-on 匹配
|
||||
# Workflow: runs-on: darwin-arm64
|
||||
# Runner: "darwin-arm64:host" label
|
||||
```
|
||||
|
||||
### 5. 缓存服务端口冲突
|
||||
|
||||
```bash
|
||||
# 检查端口占用
|
||||
lsof -i :9000
|
||||
|
||||
# 如果冲突,修改配置使用其他端口
|
||||
vim ~/.config/gitea/runners/runner-macbook-pro/config.yaml
|
||||
# 修改: port: 9001
|
||||
```
|
||||
|
||||
### 6. Runner 无法连接 Gitea
|
||||
|
||||
```bash
|
||||
# 测试 Gitea 连接
|
||||
source ~/.config/gitea/config.env
|
||||
curl -s "$GITEA_URL/api/v1/version" | jq .
|
||||
|
||||
# 检查防火墙设置
|
||||
# 检查网络连接
|
||||
```
|
||||
|
||||
### 7. Runner 已注册但不在线
|
||||
|
||||
```bash
|
||||
# 检查 runner 进程
|
||||
ps aux | grep "act_runner daemon"
|
||||
|
||||
# 如果未运行,后台启动 runner(创建时会自动启动)
|
||||
nohup act_runner daemon --config ~/.config/gitea/runners/runner-macbook-pro/config.yaml \
|
||||
> ~/.config/gitea/runners/runner-macbook-pro/runner.log 2>&1 &
|
||||
|
||||
# 查看日志诊断问题
|
||||
tail -f ~/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| 任务 | 命令 |
|
||||
|------|------|
|
||||
| 安装 runner | `brew install act_runner` |
|
||||
| 创建 runner | `/gitea-create-runner`(自动安装、配置、启动)|
|
||||
| 列出 runners | `/gitea-list-runners` |
|
||||
| 删除 runner | `/gitea-delete-runner` |
|
||||
| 手动启动 | `nohup act_runner daemon --config <config.yaml> > <log> 2>&1 &` |
|
||||
| 停止 runner | `pkill -f "act_runner daemon --config.*<name>"` |
|
||||
| 查看状态 | `ps aux \| grep act_runner` |
|
||||
| 查看日志 | `tail -f <runner-dir>/runner.log` |
|
||||
| 清理缓存 | `~/.config/gitea/cleanup-cache.sh` |
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Gitea Actions 文档](https://docs.gitea.com/usage/actions/overview)
|
||||
- [Act Runner 文档](https://docs.gitea.com/usage/actions/act-runner)
|
||||
- [Android SDK 命令行工具](https://developer.android.com/studio/command-line)
|
||||
- [GitHub Actions Workflow 语法](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions)
|
||||
|
||||
## 版本
|
||||
|
||||
- **文档版本**: 1.0
|
||||
- **最后更新**: 2026-01-12
|
||||
- **兼容性**: act_runner 0.2.13+, macOS ARM64, Linux
|
||||
603
skill/gitea/setup-guide.md
Normal file
603
skill/gitea/setup-guide.md
Normal file
@@ -0,0 +1,603 @@
|
||||
# Gitea 环境配置指南
|
||||
|
||||
首次使用 Gitea skill 前的完整配置指南。
|
||||
|
||||
## 概述
|
||||
|
||||
Gitea skill 需要配置连接信息才能与你的 Gitea 实例交互。配置信息存储在:
|
||||
|
||||
```
|
||||
~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
## 配置目录结构
|
||||
|
||||
```
|
||||
~/.config/gitea/
|
||||
├── config.env # 主配置文件(包含 URL、Token、默认组织等)
|
||||
├── runners/ # Runner 配置目录
|
||||
│ └── runner-*/ # 各个 runner 的独立目录
|
||||
└── .gitignore # Git 忽略文件(保护敏感信息)
|
||||
```
|
||||
|
||||
## 快速配置
|
||||
|
||||
### 方法 1: 使用交互式向导(推荐)
|
||||
|
||||
运行配置命令:
|
||||
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
按照提示输入信息即可。
|
||||
|
||||
### 方法 2: 自然语言请求
|
||||
|
||||
直接告诉 AI:
|
||||
|
||||
```
|
||||
用户: 配置 gitea
|
||||
用户: 初始化 gitea 连接
|
||||
用户: 设置 gitea 环境
|
||||
```
|
||||
|
||||
AI 会自动启动配置向导。
|
||||
|
||||
### 方法 3: 手动创建配置文件
|
||||
|
||||
如果你熟悉配置格式,可以手动创建:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/gitea/runners
|
||||
cat > ~/.config/gitea/config.env << 'EOF'
|
||||
GITEA_URL=https://git.digitevents.com
|
||||
GITEA_TOKEN=your_personal_access_token
|
||||
GITEA_DEFAULT_ORG=your_org_name
|
||||
|
||||
GITEA_RUNNER_CAPACITY=2
|
||||
GITEA_RUNNER_TIMEOUT=3h
|
||||
EOF
|
||||
|
||||
chmod 600 ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
## 交互式配置流程
|
||||
|
||||
### 步骤 1: 输入 Gitea 实例地址
|
||||
|
||||
```
|
||||
请输入 Gitea 实例地址 (例如: https://git.digitevents.com):
|
||||
```
|
||||
|
||||
**要求**:
|
||||
- 必须以 `http://` 或 `https://` 开头
|
||||
- 不要包含尾随斜杠
|
||||
- 确保可以从当前网络访问
|
||||
|
||||
**示例**:
|
||||
```
|
||||
✓ https://git.digitevents.com
|
||||
✓ https://gitea.example.com
|
||||
✗ git.digitevents.com (缺少协议)
|
||||
✗ https://gitea.com/ (包含尾随斜杠)
|
||||
```
|
||||
|
||||
### 步骤 2: 输入 Personal Access Token
|
||||
|
||||
```
|
||||
请输入 Personal Access Token:
|
||||
```
|
||||
|
||||
**获取 Token 的步骤**:
|
||||
|
||||
1. 登录 Gitea
|
||||
2. 点击右上角头像 → **设置**
|
||||
3. 左侧菜单选择 **应用** → **访问令牌**
|
||||
4. 点击 **生成新令牌**
|
||||
5. 设置令牌名称(如 `opencode-cli`)
|
||||
6. 选择权限(见下方推荐权限)
|
||||
7. 点击 **生成令牌**
|
||||
8. 复制生成的 Token(只显示一次!)
|
||||
|
||||
**推荐权限**:
|
||||
|
||||
| 权限 | 用途 | 是否必需 |
|
||||
|------|------|---------|
|
||||
| `repo` | 创建和管理仓库 | ✅ 必需 |
|
||||
| `admin:org` | 创建组织级 Runner | ✅ 推荐 |
|
||||
| `write:runner` | 管理 Runner | ✅ 推荐 |
|
||||
| `write:user` | 创建用户级 Variables | ✅ 推荐 |
|
||||
| `admin:repo_hook` | 配置 Webhooks | ⚠️ 可选 |
|
||||
| `write:issue` | 创建 Release | ⚠️ 可选 |
|
||||
|
||||
**安全提示**:
|
||||
- Token 等同于密码,请妥善保管
|
||||
- 不要在公开场合分享 Token
|
||||
- 定期轮换 Token(建议每 3-6 个月)
|
||||
- 使用最小权限原则
|
||||
|
||||
### 步骤 3: 测试连接
|
||||
|
||||
```
|
||||
正在测试连接...
|
||||
✓ 连接成功!
|
||||
```
|
||||
|
||||
系统会调用 Gitea API 验证:
|
||||
- URL 是否可访问
|
||||
- Token 是否有效
|
||||
- 网络是否正常
|
||||
|
||||
**如果失败**:
|
||||
- 检查 URL 是否正确
|
||||
- 检查 Token 是否复制完整
|
||||
- 检查网络连接
|
||||
- 检查防火墙设置
|
||||
|
||||
### 步骤 4: 验证 Token 权限
|
||||
|
||||
```
|
||||
正在检查 Token 权限...
|
||||
✓ repo (仓库管理)
|
||||
✓ admin:org (组织管理)
|
||||
✓ write:runner (Runner 管理)
|
||||
⚠ 缺少 admin:repo_hook 权限(可能影响 Webhook 配置)
|
||||
```
|
||||
|
||||
系统会测试 Token 的实际权限,并给出建议。
|
||||
|
||||
**权限不足时**:
|
||||
- 如果缺少必需权限,建议重新创建 Token
|
||||
- 如果只缺少可选权限,可以继续使用
|
||||
- 后续需要时可以更新 Token
|
||||
|
||||
### 步骤 5: 输入默认组织(可选)
|
||||
|
||||
```
|
||||
请输入默认组织名称 (可选,回车跳过):
|
||||
```
|
||||
|
||||
**作用**:
|
||||
- 创建仓库时,如果不指定 owner,使用此默认组织
|
||||
- 创建组织级 Runner 时使用
|
||||
- 可以随时使用 `/gitea-switch-org` 切换
|
||||
|
||||
**示例**:
|
||||
```
|
||||
ai → 创建仓库时使用 ai/repo-name
|
||||
my-team → 创建仓库时使用 my-team/repo-name
|
||||
(留空) → 创建仓库时使用当前登录用户
|
||||
```
|
||||
|
||||
**注意**:留空是完全可以的,系统会自动使用当前登录用户创建个人仓库。
|
||||
|
||||
### 步骤 6: 输入 Gitea 用户名(用于 Actions Variables)
|
||||
|
||||
```
|
||||
请输入 Gitea 用户名 (将创建为用户级 variable):
|
||||
```
|
||||
|
||||
**作用**:
|
||||
- 此用户名将自动注册到 Gitea 用户级 variables(变量名:`USERNAME`)
|
||||
- 可在所有个人仓库的 Actions workflow 中通过 `${{ vars.USERNAME }}` 使用
|
||||
- 用于需要 Git 操作的 workflow(如推送代码、创建 tag 等)
|
||||
|
||||
**示例**:
|
||||
```
|
||||
your_username → 在 workflow 中可使用 ${{ vars.USERNAME }}
|
||||
john → 你的 Gitea 登录用户名
|
||||
```
|
||||
|
||||
**重要说明**:
|
||||
- Gitea 不允许 variable 名称以 `GITEA_` 或 `GITHUB_` 开头
|
||||
- 因此配置项 `GITEA_USERNAME` 会被注册为 `USERNAME` variable
|
||||
- 如果此 variable 已存在于 Gitea 服务器,系统会自动更新为新值
|
||||
|
||||
### 步骤 7: 输入 Gitea 密码(用于 Actions)
|
||||
|
||||
```
|
||||
请输入 Gitea 密码:
|
||||
```
|
||||
|
||||
**作用**:
|
||||
- 密码将存储在本地配置文件 `config.env` 中(权限 600)
|
||||
- 用于需要认证的 Git 操作
|
||||
- 也可以选择在 workflow 中使用 Secret 方式(需要手动创建)
|
||||
|
||||
**安全说明**:
|
||||
- ✅ 配置文件权限为 600(仅所有者可读写)
|
||||
- ✅ `.gitignore` 自动排除配置文件
|
||||
- ⚠️ 不建议在公共环境使用明文密码
|
||||
- 💡 建议使用 Personal Access Token 替代密码
|
||||
|
||||
**留空说明**:如果不需要在 workflow 中进行 Git 推送操作,可以留空。
|
||||
|
||||
### 步骤 8: 输入 Actions 通知 Webhook URL(可选)
|
||||
|
||||
```
|
||||
请输入 Actions 通知 Webhook URL (可选,回车跳过):
|
||||
```
|
||||
|
||||
**作用**:
|
||||
- 用于 workflow 完成后发送通知到第三方平台(如飞书、钉钉、企业微信等)
|
||||
- 此 URL 将自动注册到 Gitea 用户级 variables(变量名:`WEBHOOK_URL`)
|
||||
- 可在 workflow 中通过 `${{ vars.WEBHOOK_URL }}` 使用
|
||||
|
||||
**示例**:
|
||||
```
|
||||
https://www.feishu.cn/flow/api/trigger-webhook/xxx (飞书)
|
||||
https://oapi.dingtalk.com/robot/send?access_token=xxx (钉钉)
|
||||
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx (企业微信)
|
||||
```
|
||||
|
||||
**使用方式**:
|
||||
```yaml
|
||||
- name: 发送通知
|
||||
run: |
|
||||
curl -X POST "${{ vars.WEBHOOK_URL }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"msg_type":"text","content":{"text":"构建完成"}}'
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 留空则不创建 `WEBHOOK_URL` variable
|
||||
- 如果此 variable 已存在于 Gitea 服务器,系统会更新为新值
|
||||
|
||||
### 步骤 9: 注册用户级 Variables
|
||||
|
||||
```
|
||||
正在检查并注册用户级 Variables...
|
||||
检查 USERNAME...
|
||||
✓ USERNAME 已创建
|
||||
检查 WEBHOOK_URL...
|
||||
✓ WEBHOOK_URL 已创建
|
||||
```
|
||||
|
||||
系统会自动调用 Gitea API 创建以下用户级 variables:
|
||||
|
||||
| Variable 名称 | 来源配置 | 说明 |
|
||||
|--------------|---------|------|
|
||||
| `USERNAME` | `GITEA_USERNAME` | Gitea 用户名 |
|
||||
| `WEBHOOK_URL` | `GITEA_WEBHOOK_URL` | Actions 通知 Webhook |
|
||||
|
||||
**重要**:Gitea 不允许 variable 名称以 `GITEA_` 或 `GITHUB_` 开头,所以 `GITEA_USERNAME` 配置项会被注册为 `USERNAME` variable。
|
||||
|
||||
**API 端点**:
|
||||
```
|
||||
POST /api/v1/user/actions/variables/{variable_name}
|
||||
```
|
||||
|
||||
**在 Workflow 中使用**:
|
||||
```yaml
|
||||
steps:
|
||||
- name: 使用 Variables
|
||||
run: |
|
||||
echo "用户名: ${{ vars.USERNAME }}"
|
||||
echo "Webhook: ${{ vars.WEBHOOK_URL }}"
|
||||
```
|
||||
|
||||
**查看已创建的 Variables**:
|
||||
- 访问:`https://git.digitevents.com/user/settings/actions/variables`
|
||||
- 或使用命令:`/gitea-list-variables`
|
||||
|
||||
### 步骤 10: 保存配置
|
||||
|
||||
```
|
||||
✓ 配置已保存
|
||||
配置文件: ~/.config/gitea/config.env
|
||||
Runner 目录: ~/.config/gitea/runners
|
||||
```
|
||||
|
||||
配置文件内容:
|
||||
|
||||
```bash
|
||||
# Gitea Configuration
|
||||
# Generated at 2026-01-12 22:30:00
|
||||
|
||||
GITEA_URL=https://git.digitevents.com
|
||||
GITEA_TOKEN=git_xxxxxxxxxxxxxxxxxxxx
|
||||
GITEA_DEFAULT_ORG=ai
|
||||
|
||||
# Gitea 仓库认证信息(用于 Actions)
|
||||
GITEA_USERNAME=your_username
|
||||
GITEA_PASSWORD=your_password_here
|
||||
|
||||
# Actions 通知 Webhook(可选)
|
||||
GITEA_WEBHOOK_URL=https://www.feishu.cn/flow/api/trigger-webhook/xxx
|
||||
|
||||
# Runner Default Settings
|
||||
GITEA_RUNNER_CAPACITY=2
|
||||
GITEA_RUNNER_TIMEOUT=3h
|
||||
|
||||
# Optional: Override auto-detected labels
|
||||
# GITEA_RUNNER_LABELS=custom-label-1:host,custom-label-2:host
|
||||
```
|
||||
|
||||
## 配置验证
|
||||
|
||||
配置完成后,验证配置是否正确:
|
||||
|
||||
```bash
|
||||
/gitea-config
|
||||
```
|
||||
|
||||
应该看到:
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
当前 Gitea 配置
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
URL: https://git.digitevents.com
|
||||
默认组织: ai
|
||||
Token 状态: ✓ 有效 (用户: your_username)
|
||||
配置文件: ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
## 配置文件说明
|
||||
|
||||
### 必需配置项
|
||||
|
||||
| 配置项 | 说明 | 示例 |
|
||||
|--------|------|------|
|
||||
| `GITEA_URL` | Gitea 实例地址 | `https://git.digitevents.com` |
|
||||
| `GITEA_TOKEN` | Personal Access Token | `git_xxxxxxxxxx` |
|
||||
|
||||
### 推荐配置项(用于 Actions)
|
||||
|
||||
| 配置项 | 说明 | 示例 | 自动创建为 Variable |
|
||||
|--------|------|------|-------------------|
|
||||
| `GITEA_USERNAME` | Gitea 用户名 | `your_username` | ✅ 是 → `USERNAME` |
|
||||
| `GITEA_PASSWORD` | Gitea 密码 | `your_password` | ❌ 否(仅本地使用) |
|
||||
| `GITEA_WEBHOOK_URL` | Actions 通知 Webhook | `https://...` | ✅ 是 → `WEBHOOK_URL` |
|
||||
|
||||
**说明**:
|
||||
- 标记为 ✅ 的配置项会在初始化时自动创建为 Gitea 用户级 variables
|
||||
- 这些 variables 可在所有个人仓库的 Actions workflow 中使用
|
||||
- 使用方式:`${{ vars.USERNAME }}`、`${{ vars.WEBHOOK_URL }}`
|
||||
- **注意**:Gitea 不允许 variable 名称以 `GITEA_` 或 `GITHUB_` 开头,所以会自动转换名称
|
||||
|
||||
### 可选配置项
|
||||
|
||||
| 配置项 | 说明 | 默认值 |
|
||||
|--------|------|--------|
|
||||
| `GITEA_DEFAULT_ORG` | 默认组织名称 | 无 |
|
||||
| `GITEA_RUNNER_CAPACITY` | Runner 并发任务数 | `2` |
|
||||
| `GITEA_RUNNER_TIMEOUT` | Runner 任务超时时间 | `3h` |
|
||||
| `GITEA_RUNNER_LABELS` | 覆盖自动检测的 labels | 自动检测 |
|
||||
|
||||
### 自定义 Runner Labels
|
||||
|
||||
如果自动检测的 labels 不符合需求,可以手动覆盖:
|
||||
|
||||
```bash
|
||||
# 编辑配置文件
|
||||
vim ~/.config/gitea/config.env
|
||||
|
||||
# 取消注释并修改
|
||||
GITEA_RUNNER_LABELS=self-hosted:host,linux:host,x64:host,custom:host
|
||||
```
|
||||
|
||||
创建新 Runner 时会优先使用此配置。
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 查看当前配置
|
||||
|
||||
```bash
|
||||
/gitea-config
|
||||
```
|
||||
|
||||
显示:
|
||||
- Gitea URL
|
||||
- 默认组织
|
||||
- Token 状态和关联用户
|
||||
- 已配置的 Runner 数量
|
||||
- 配置文件路径
|
||||
|
||||
### 切换默认组织
|
||||
|
||||
```bash
|
||||
/gitea-switch-org new-org-name
|
||||
```
|
||||
|
||||
### 重置配置
|
||||
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
会重新启动配置向导,覆盖现有配置。
|
||||
|
||||
**警告**:重置配置不会影响已创建的 Runner,但 Runner 会继续使用旧的注册信息。
|
||||
|
||||
### 更新配置
|
||||
|
||||
#### 方法 1: 使用命令(推荐)
|
||||
|
||||
```bash
|
||||
/gitea-reset # 完整重置
|
||||
/gitea-switch-org my-org # 只切换组织
|
||||
```
|
||||
|
||||
#### 方法 2: 手动编辑
|
||||
|
||||
```bash
|
||||
vim ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
修改后无需重启,下次使用时自动生效。
|
||||
|
||||
## 多环境配置
|
||||
|
||||
如果需要管理多个 Gitea 实例,推荐做法:
|
||||
|
||||
### 方法 1: 使用不同的配置文件
|
||||
|
||||
```bash
|
||||
# 开发环境
|
||||
cp ~/.config/gitea/config.env ~/.config/gitea/config.dev.env
|
||||
|
||||
# 生产环境
|
||||
cp ~/.config/gitea/config.env ~/.config/gitea/config.prod.env
|
||||
|
||||
# 使用时手动切换
|
||||
cp ~/.config/gitea/config.prod.env ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
### 方法 2: 创建切换脚本
|
||||
|
||||
```bash
|
||||
# ~/.config/gitea/switch-env.sh
|
||||
#!/bin/bash
|
||||
|
||||
case "$1" in
|
||||
dev)
|
||||
cp ~/.config/gitea/config.dev.env ~/.config/gitea/config.env
|
||||
echo "✓ 切换到开发环境"
|
||||
;;
|
||||
prod)
|
||||
cp ~/.config/gitea/config.prod.env ~/.config/gitea/config.env
|
||||
echo "✓ 切换到生产环境"
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 {dev|prod}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
使用:
|
||||
```bash
|
||||
bash ~/.config/gitea/switch-env.sh dev
|
||||
```
|
||||
|
||||
## 安全最佳实践
|
||||
|
||||
### 1. 文件权限
|
||||
|
||||
确保配置文件只有所有者可读写:
|
||||
|
||||
```bash
|
||||
chmod 600 ~/.config/gitea/config.env
|
||||
```
|
||||
|
||||
### 2. Token 安全
|
||||
|
||||
- ✅ 使用最小权限原则
|
||||
- ✅ 定期轮换 Token
|
||||
- ✅ 不要将 Token 提交到 Git
|
||||
- ✅ 使用 `.gitignore` 排除配置文件
|
||||
- ❌ 不要在公开场合分享 Token
|
||||
- ❌ 不要使用永不过期的 Token
|
||||
|
||||
### 3. 配置备份
|
||||
|
||||
定期备份配置(移除 Token 后):
|
||||
|
||||
```bash
|
||||
# 创建备份(移除敏感信息)
|
||||
grep -v "GITEA_TOKEN" ~/.config/gitea/config.env > ~/gitea-config-backup.env
|
||||
```
|
||||
|
||||
### 4. .gitignore 配置
|
||||
|
||||
自动生成的 `.gitignore` 文件:
|
||||
|
||||
```
|
||||
# ~/.config/gitea/.gitignore
|
||||
config.env
|
||||
runners/*/.runner
|
||||
runners/*/.env
|
||||
```
|
||||
|
||||
确保敏感文件不会被意外提交。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 连接失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ 连接失败 (HTTP 404)
|
||||
请检查 URL 和 Token 是否正确
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
1. 检查 URL 是否正确(不要包含 `/api/v1`)
|
||||
2. 检查网络连接
|
||||
3. 尝试在浏览器中访问 URL
|
||||
4. 检查防火墙设置
|
||||
|
||||
### Token 无效
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ 连接失败 (HTTP 401)
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
1. Token 可能已过期,重新生成
|
||||
2. Token 可能被撤销,检查 Gitea 设置
|
||||
3. Token 复制不完整,重新复制
|
||||
4. 确认 Token 有足够的权限
|
||||
|
||||
### 权限不足
|
||||
|
||||
**症状**:
|
||||
```
|
||||
⚠ 缺少 admin:org 权限(可能影响组织 Runner 创建)
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
1. 重新创建 Token,选择更多权限
|
||||
2. 联系 Gitea 管理员提升权限
|
||||
3. 使用个人 Runner 而非组织 Runner
|
||||
|
||||
### 配置文件损坏
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ 配置文件不完整,请运行 /gitea-reset 重新配置
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
## 下一步
|
||||
|
||||
配置完成后,你可以:
|
||||
|
||||
1. **创建第一个 Runner**(自动后台启动):
|
||||
```
|
||||
用户: 创建一个 runner
|
||||
```
|
||||
- 默认创建全局 Runner(可用于所有组织和仓库)
|
||||
- 如果 Token 没有管理员权限,自动降级到组织 Runner
|
||||
- 创建后 Runner 会自动在后台运行
|
||||
|
||||
2. **创建仓库**:
|
||||
```bash
|
||||
/gitea-create-repo my-project
|
||||
```
|
||||
|
||||
3. **生成 Workflow**:
|
||||
```
|
||||
用户: 为我的项目生成 workflow
|
||||
```
|
||||
|
||||
4. **查看配置**:
|
||||
```bash
|
||||
/gitea-config
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
- [Runner 管理](./runner-management.md)
|
||||
- [Workflow 生成器](./workflow-generator.md)
|
||||
- [仓库操作](./repository-operations.md)
|
||||
- [API 参考](./api-reference.md)
|
||||
692
skill/gitea/troubleshooting.md
Normal file
692
skill/gitea/troubleshooting.md
Normal file
@@ -0,0 +1,692 @@
|
||||
# Gitea 故障排查
|
||||
|
||||
常见问题的诊断和解决方案。
|
||||
|
||||
## 配置问题
|
||||
|
||||
### 1. 配置文件不存在
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ Gitea 未配置,请运行 /gitea-reset
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 首次使用,未进行配置
|
||||
- 配置文件被删除或移动
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
按照提示完成配置。
|
||||
|
||||
---
|
||||
|
||||
### 2. Token 无效或已过期
|
||||
|
||||
**症状**:
|
||||
```
|
||||
Token 状态: ✗ 无效或已过期
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- Token 已过期
|
||||
- Token 被撤销
|
||||
- Token 复制不完整
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 重新生成 Token:
|
||||
- 登录 Gitea → 设置 → 应用 → 访问令牌
|
||||
- 生成新 Token(权限:repo, admin:org, write:runner)
|
||||
|
||||
2. 更新配置:
|
||||
```bash
|
||||
/gitea-reset
|
||||
```
|
||||
|
||||
3. 或手动编辑配置文件:
|
||||
```bash
|
||||
vim ~/.config/gitea/config.env
|
||||
# 更新 GITEA_TOKEN=new_token
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 连接 Gitea 失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ 连接失败 (HTTP 404)
|
||||
❌ 连接失败 (HTTP 500)
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- URL 错误
|
||||
- 网络问题
|
||||
- Gitea 服务器宕机
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查 URL:
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
echo $GITEA_URL
|
||||
```
|
||||
|
||||
2. 测试网络连接:
|
||||
```bash
|
||||
curl -s "$GITEA_URL/api/v1/version"
|
||||
```
|
||||
|
||||
3. 在浏览器中访问 URL
|
||||
|
||||
**解决方案**:
|
||||
- 修正 URL(不要包含 `/api/v1`)
|
||||
- 检查网络连接
|
||||
- 联系 Gitea 管理员
|
||||
|
||||
---
|
||||
|
||||
### 4. 权限不足
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ 权限不足 (HTTP 403)
|
||||
⚠ 缺少 admin:org 权限
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- Token 权限不足
|
||||
- 不是组织成员
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 重新创建 Token,选择更多权限
|
||||
2. 联系组织管理员添加为成员
|
||||
3. 使用个人仓库/Runner 代替组织级别
|
||||
|
||||
---
|
||||
|
||||
## Runner 问题
|
||||
|
||||
### 1. Runner 创建失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ 获取注册 Token 失败
|
||||
❌ Runner 注册失败
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- Token 缺少 `write:runner` 权限
|
||||
- 组织不存在
|
||||
- 网络问题
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查 Token 权限:
|
||||
```bash
|
||||
/gitea-config
|
||||
```
|
||||
|
||||
2. 验证组织存在:
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/orgs/$GITEA_DEFAULT_ORG"
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
- 更新 Token 权限
|
||||
- 设置正确的组织:`/gitea-switch-org <org>`
|
||||
|
||||
---
|
||||
|
||||
### 2. Runner 无法启动
|
||||
|
||||
**症状**:
|
||||
```bash
|
||||
act_runner daemon --config ...
|
||||
# 进程立即退出或报错
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- `act_runner` 未安装
|
||||
- 配置文件错误
|
||||
- 端口被占用(cache service)
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查 act_runner:
|
||||
```bash
|
||||
which act_runner
|
||||
act_runner --version
|
||||
```
|
||||
|
||||
2. 验证配置文件:
|
||||
```bash
|
||||
cat ~/.config/gitea/runners/runner-name/config.yaml
|
||||
```
|
||||
|
||||
3. 检查端口占用:
|
||||
```bash
|
||||
lsof -i :9000
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 安装 act_runner:
|
||||
```bash
|
||||
brew install act_runner
|
||||
```
|
||||
|
||||
2. 修复配置文件(确保路径正确)
|
||||
|
||||
3. 更改端口(如果 9000 被占用):
|
||||
```bash
|
||||
vim ~/.config/gitea/runners/runner-name/config.yaml
|
||||
# 修改 port: 9001
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Runner 已注册但不在线
|
||||
|
||||
**症状**:
|
||||
- Gitea 中看不到 Runner
|
||||
- Workflow 无法分配到 Runner
|
||||
|
||||
**原因**:
|
||||
- Runner 进程未运行
|
||||
- 网络连接问题
|
||||
- Labels 不匹配
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查 Runner 进程:
|
||||
```bash
|
||||
/gitea-list-runners
|
||||
```
|
||||
|
||||
2. 查看 Runner 日志:
|
||||
```bash
|
||||
tail -f ~/.config/gitea/runners/runner-name/runner.log
|
||||
```
|
||||
|
||||
3. 测试 Gitea 连接:
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
curl -s "$GITEA_URL/api/v1/version"
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 启动 Runner:
|
||||
```bash
|
||||
act_runner daemon --config ~/.config/gitea/runners/runner-name/config.yaml
|
||||
```
|
||||
|
||||
2. 检查网络和防火墙设置
|
||||
|
||||
3. 验证 Labels 匹配
|
||||
|
||||
---
|
||||
|
||||
### 4. Labels 不匹配
|
||||
|
||||
**症状**:
|
||||
```
|
||||
Workflow 一直 pending,不执行
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- Workflow 的 `runs-on` 与 Runner labels 不匹配
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查 Runner labels:
|
||||
```bash
|
||||
/gitea-list-runners
|
||||
# 或
|
||||
cat ~/.config/gitea/runners/runner-name/.runner | jq '.labels'
|
||||
```
|
||||
|
||||
2. 检查 Workflow:
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: darwin-arm64 # 这个 label 必须存在
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 修改 Workflow 的 `runs-on` 匹配 Runner labels
|
||||
2. 或重新创建 Runner 使用正确的 labels
|
||||
|
||||
---
|
||||
|
||||
## Workflow 问题
|
||||
|
||||
### 1. Workflow 不触发
|
||||
|
||||
**症状**:
|
||||
- 推送代码后 Workflow 不执行
|
||||
|
||||
**原因**:
|
||||
- 路径过滤不匹配
|
||||
- 分支不匹配
|
||||
- Runner 不在线
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查触发条件:
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/**' # 确保修改的文件在此路径下
|
||||
```
|
||||
|
||||
2. 检查 Runner 状态:
|
||||
```bash
|
||||
/gitea-list-runners
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
- 修改触发条件(删除或调整 `paths`)
|
||||
- 确保 Runner 在线
|
||||
- 检查 Gitea Actions 是否启用
|
||||
|
||||
---
|
||||
|
||||
### 2. Workflow 执行失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
Job failed
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 构建命令错误
|
||||
- 依赖缺失
|
||||
- Secret 未配置
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 查看 Workflow 运行日志(在 Gitea UI 中)
|
||||
2. 检查 Secrets 配置
|
||||
3. 在本地手动执行构建命令
|
||||
|
||||
**解决方案**:
|
||||
- 修复构建命令
|
||||
- 安装缺失的依赖
|
||||
- 配置必需的 Secrets
|
||||
|
||||
---
|
||||
|
||||
### 3. Cache 不生效
|
||||
|
||||
**症状**:
|
||||
- 每次构建都重新下载依赖
|
||||
- 构建时间没有减少
|
||||
|
||||
**原因**:
|
||||
- Cache key 每次都变化
|
||||
- Cache 目录不正确
|
||||
- Runner cache service 未启动
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查 cache key:
|
||||
```yaml
|
||||
key: cache-${{ hashFiles('**/lockfile') }}
|
||||
# 确保 lockfile 路径正确
|
||||
```
|
||||
|
||||
2. 检查 Runner 配置:
|
||||
```yaml
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "..."
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
- 修正 cache key 的 hash 文件路径
|
||||
- 确保 Runner cache service 启用
|
||||
- 检查 cache 目录权限
|
||||
|
||||
---
|
||||
|
||||
## 仓库操作问题
|
||||
|
||||
### 1. 创建仓库失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ 仓库已存在
|
||||
❌ Owner 不存在或无权限
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 仓库名冲突
|
||||
- 组织不存在
|
||||
- Token 权限不足
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查仓库是否存在:
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/owner/repo"
|
||||
```
|
||||
|
||||
2. 列出组织的所有仓库:
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_URL/api/v1/orgs/owner/repos" | jq -r '.[].name'
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
- 使用不同的仓库名
|
||||
- 验证组织名正确
|
||||
- 确保 Token 有 `repo` 权限
|
||||
|
||||
---
|
||||
|
||||
### 2. Git Remote 添加失败
|
||||
|
||||
**症状**:
|
||||
```
|
||||
❌ origin remote 已存在
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 已经配置了 origin remote
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 查看现有 remote:
|
||||
```bash
|
||||
git remote -v
|
||||
```
|
||||
|
||||
2. 更新 remote URL:
|
||||
```bash
|
||||
git remote set-url origin <new-url>
|
||||
```
|
||||
|
||||
3. 或删除后重新添加:
|
||||
```bash
|
||||
git remote remove origin
|
||||
git remote add origin <new-url>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 开发环境问题
|
||||
|
||||
### 1. Android SDK 未找到
|
||||
|
||||
**症状**:
|
||||
```
|
||||
ANDROID_HOME not set
|
||||
SDK location not found
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 未安装 Android SDK
|
||||
- 环境变量未配置
|
||||
- Runner 用户不同
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
1. 检查环境变量:
|
||||
```bash
|
||||
echo $ANDROID_HOME
|
||||
ls $ANDROID_HOME
|
||||
```
|
||||
|
||||
2. 检查 Runner 用户:
|
||||
```bash
|
||||
ps aux | grep act_runner
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 安装 Android SDK:
|
||||
```bash
|
||||
brew install --cask android-commandlinetools
|
||||
```
|
||||
|
||||
2. 配置环境变量(在 `~/.zshrc`):
|
||||
```bash
|
||||
export ANDROID_HOME=~/android-sdk
|
||||
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
|
||||
```
|
||||
|
||||
3. 确保 Runner 以正确用户运行
|
||||
|
||||
---
|
||||
|
||||
### 2. JDK 版本错误
|
||||
|
||||
**症状**:
|
||||
```
|
||||
Android Gradle Plugin requires Java 17
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- JDK 版本过低
|
||||
- JAVA_HOME 指向错误版本
|
||||
|
||||
**诊断步骤**:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
echo $JAVA_HOME
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 安装 JDK 17:
|
||||
```bash
|
||||
brew install openjdk@17
|
||||
```
|
||||
|
||||
2. 更新 JAVA_HOME:
|
||||
```bash
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@17
|
||||
export PATH=$PATH:$JAVA_HOME/bin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API 调用问题
|
||||
|
||||
### 1. API 返回 404
|
||||
|
||||
**原因**:
|
||||
- Endpoint 错误
|
||||
- 资源不存在
|
||||
- 组织/仓库名错误
|
||||
|
||||
**解决方案**:
|
||||
- 检查 API 路径
|
||||
- 验证资源存在
|
||||
- 参考 [API 文档](./api-reference.md)
|
||||
|
||||
---
|
||||
|
||||
### 2. API 返回 401
|
||||
|
||||
**原因**:
|
||||
- Token 无效
|
||||
- 未提供 Authorization header
|
||||
|
||||
**解决方案**:
|
||||
- 检查 Token
|
||||
- 确保 header 格式正确:`Authorization: token YOUR_TOKEN`
|
||||
|
||||
---
|
||||
|
||||
### 3. API 返回 403
|
||||
|
||||
**原因**:
|
||||
- 权限不足
|
||||
- Token 缺少必要权限
|
||||
|
||||
**解决方案**:
|
||||
- 重新创建 Token,选择更多权限
|
||||
- 联系管理员提升权限
|
||||
|
||||
---
|
||||
|
||||
## 性能问题
|
||||
|
||||
### 1. 构建速度慢
|
||||
|
||||
**原因**:
|
||||
- 未使用缓存
|
||||
- 依赖下载慢
|
||||
- Runner 性能不足
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 启用缓存:
|
||||
```yaml
|
||||
- uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache
|
||||
key: cache-${{ hashFiles('**/lockfile') }}
|
||||
```
|
||||
|
||||
2. 使用镜像源(如 Go proxy、npm registry)
|
||||
|
||||
3. 升级 Runner 硬件
|
||||
|
||||
---
|
||||
|
||||
### 2. Cache 占用空间大
|
||||
|
||||
**原因**:
|
||||
- 长时间未清理
|
||||
- 多个 Runner 共享 cache
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 定期清理:
|
||||
```bash
|
||||
~/.config/gitea/cleanup-cache.sh
|
||||
```
|
||||
|
||||
2. 设置 crontab 自动清理:
|
||||
```bash
|
||||
crontab -e
|
||||
# 添加: 0 3 * * 0 ~/.config/gitea/cleanup-cache.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 诊断工具
|
||||
|
||||
### 快速诊断脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
echo "=== Gitea 环境诊断 ==="
|
||||
echo ""
|
||||
|
||||
# 1. 配置文件
|
||||
echo "1. 配置文件:"
|
||||
config_file="$HOME/.config/gitea/config.env"
|
||||
if [ -f "$config_file" ]; then
|
||||
echo " ✓ 存在: $config_file"
|
||||
source "$config_file"
|
||||
echo " URL: $GITEA_URL"
|
||||
else
|
||||
echo " ✗ 不存在"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 2. Token 验证
|
||||
if [ -n "$GITEA_TOKEN" ]; then
|
||||
echo "2. Token 验证:"
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/user")
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
if [ "$http_code" = "200" ]; then
|
||||
echo " ✓ 有效"
|
||||
else
|
||||
echo " ✗ 无效 (HTTP $http_code)"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 3. Runner 状态
|
||||
echo "3. Runner 状态:"
|
||||
runners_dir="$HOME/.config/gitea/runners"
|
||||
if [ -d "$runners_dir" ]; then
|
||||
runner_count=$(ls -1 "$runners_dir" 2>/dev/null | wc -l | tr -d ' ')
|
||||
echo " 配置数量: $runner_count"
|
||||
|
||||
for runner in $(ls -1 "$runners_dir" 2>/dev/null); do
|
||||
config_file="$runners_dir/$runner/config.yaml"
|
||||
if pgrep -f "act_runner daemon --config $config_file" > /dev/null; then
|
||||
echo " ✓ $runner (运行中)"
|
||||
else
|
||||
echo " ✗ $runner (已停止)"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo " 未配置 Runner"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 4. 工具检查
|
||||
echo "4. 工具检查:"
|
||||
for tool in act_runner jq curl git; do
|
||||
if command -v $tool &> /dev/null; then
|
||||
echo " ✓ $tool"
|
||||
else
|
||||
echo " ✗ $tool (未安装)"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
保存为 `~/.config/gitea/diagnose.sh` 并执行:
|
||||
|
||||
```bash
|
||||
chmod +x ~/.config/gitea/diagnose.sh
|
||||
~/.config/gitea/diagnose.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取帮助
|
||||
|
||||
如果问题仍未解决:
|
||||
|
||||
1. **查看日志**:
|
||||
- Runner 日志:`~/.config/gitea/runners/runner-name/runner.log`
|
||||
- Gitea UI 中的 Workflow 运行日志
|
||||
|
||||
2. **检查文档**:
|
||||
- [环境配置](./setup-guide.md)
|
||||
- [Runner 管理](./runner-management.md)
|
||||
- [API 参考](./api-reference.md)
|
||||
|
||||
3. **联系支持**:
|
||||
- Gitea 官方文档:https://docs.gitea.com/
|
||||
- Gitea 社区论坛:https://discourse.gitea.io/
|
||||
|
||||
---
|
||||
|
||||
## 版本
|
||||
|
||||
- **文档版本**: 1.0
|
||||
- **最后更新**: 2026-01-12
|
||||
624
skill/gitea/workflow-generator.md
Normal file
624
skill/gitea/workflow-generator.md
Normal file
@@ -0,0 +1,624 @@
|
||||
# Gitea Workflow 生成器
|
||||
|
||||
根据项目类型自动生成 CI/CD workflow 文件。
|
||||
|
||||
## 概述
|
||||
|
||||
Gitea Actions 使用 GitHub Actions 兼容的 workflow 语法,定义在 `.gitea/workflows/*.yml` 文件中。
|
||||
|
||||
本 skill 提供:
|
||||
- 自动检测项目类型
|
||||
- 根据类型生成适配的 workflow 模板
|
||||
- 自动填充项目特定变量
|
||||
- 智能配置触发条件和缓存策略
|
||||
|
||||
## 项目类型模板
|
||||
|
||||
| 类型 | 模板文档 | 适用场景 |
|
||||
|------|---------|---------|
|
||||
| Go 后端 | [go-backend.md](./workflow-templates/go-backend.md) | API 服务、微服务、CLI 工具 |
|
||||
| Node.js 前端 | [nodejs-frontend.md](./workflow-templates/nodejs-frontend.md) | React/Vue/Vite/Next.js |
|
||||
| Android 应用 | [android-app.md](./workflow-templates/android-app.md) | Kotlin/Java/Jetpack Compose |
|
||||
| 微信小程序 | [wechat-miniprogram.md](./workflow-templates/wechat-miniprogram.md) | 微信小程序 CI/CD |
|
||||
|
||||
## 自动生成流程
|
||||
|
||||
### 步骤 1: 检测项目类型
|
||||
|
||||
当用户说"为我的项目生成 workflow"时,AI 会自动检测项目类型:
|
||||
|
||||
```bash
|
||||
# Go 项目特征
|
||||
if [ -f "go.mod" ] || [ -f "main.go" ]; then
|
||||
project_type="go"
|
||||
fi
|
||||
|
||||
# Node.js 项目特征
|
||||
if [ -f "package.json" ]; then
|
||||
project_type="nodejs"
|
||||
|
||||
# 细分类型
|
||||
if grep -q "\"react\"" package.json; then
|
||||
framework="react"
|
||||
elif grep -q "\"vue\"" package.json; then
|
||||
framework="vue"
|
||||
elif grep -q "\"vite\"" package.json; then
|
||||
framework="vite"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Android 项目特征
|
||||
if [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
||||
if [ -d "app/src/main/java" ] || [ -d "app/src/main/kotlin" ]; then
|
||||
project_type="android"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 微信小程序特征
|
||||
if [ -f "project.config.json" ] && [ -f "app.json" ]; then
|
||||
project_type="wechat-miniprogram"
|
||||
fi
|
||||
```
|
||||
|
||||
### 步骤 2: 提示用户确认
|
||||
|
||||
```
|
||||
检测到项目类型: Go 后端服务
|
||||
服务目录: ./backend
|
||||
是否正确? [Y/n]
|
||||
```
|
||||
|
||||
### 步骤 3: 收集项目信息
|
||||
|
||||
根据项目类型,收集必要信息:
|
||||
|
||||
**Go 项目**:
|
||||
- 服务目录(如 `./backend`)
|
||||
- 服务名称(如 `api-server`)
|
||||
- 是否需要 Docker 构建
|
||||
- Docker Registry 地址
|
||||
|
||||
**Node.js 项目**:
|
||||
- 项目目录
|
||||
- 包管理器(npm/pnpm/yarn)
|
||||
- 构建命令
|
||||
- 输出目录
|
||||
|
||||
**Android 项目**:
|
||||
- 模块名称(如 `app`)
|
||||
- 构建类型(release/debug)
|
||||
- 签名配置
|
||||
|
||||
**微信小程序**:
|
||||
- 项目目录
|
||||
- 版本号规则
|
||||
- 上传配置
|
||||
|
||||
### 步骤 4: 选择 Runner
|
||||
|
||||
```
|
||||
请选择 Runner:
|
||||
1) darwin-arm64 (macOS ARM64)
|
||||
2) ubuntu-latest (Docker)
|
||||
3) 自定义
|
||||
|
||||
[1]:
|
||||
```
|
||||
|
||||
### 步骤 5: 生成 Workflow 文件
|
||||
|
||||
基于模板生成 workflow,自动替换变量:
|
||||
|
||||
```yaml
|
||||
name: Backend Service - Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/**' # 自动填充:项目目录
|
||||
- '.gitea/workflows/backend.yml'
|
||||
tags:
|
||||
- 'backend-*' # 自动填充:服务前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: backend # 自动填充:服务名称
|
||||
SERVICE_DIR: backend # 自动填充:服务目录
|
||||
GOPROXY: https://goproxy.cn,direct
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
name: Build & Publish
|
||||
runs-on: darwin-arm64 # 自动填充:Runner
|
||||
# ... 其余配置
|
||||
```
|
||||
|
||||
### 步骤 6: 创建文件
|
||||
|
||||
```bash
|
||||
# 创建 .gitea/workflows 目录
|
||||
mkdir -p .gitea/workflows
|
||||
|
||||
# 写入 workflow 文件
|
||||
cat > .gitea/workflows/backend.yml << 'EOF'
|
||||
[生成的 workflow 内容]
|
||||
EOF
|
||||
|
||||
echo "✓ Workflow 已生成: .gitea/workflows/backend.yml"
|
||||
```
|
||||
|
||||
### 步骤 7: 提示配置 Secrets
|
||||
|
||||
根据 workflow 需求,提示用户配置 Secrets:
|
||||
|
||||
```
|
||||
需要配置以下 Secrets:
|
||||
- REGISTRY_PASSWORD: Docker Registry 密码
|
||||
- RELEASE_TOKEN: Gitea API Token(创建 Release 用)
|
||||
|
||||
配置方法:
|
||||
1. 在 Gitea 中打开仓库设置
|
||||
2. 进入 Settings → Secrets → Actions
|
||||
3. 添加上述 Secrets
|
||||
|
||||
或使用 API:
|
||||
source ~/.config/gitea/config.env
|
||||
echo -n "password" | base64 | xargs -I {} \
|
||||
curl -X PUT \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"data":"{}"}' \
|
||||
"$GITEA_URL/api/v1/repos/owner/repo/actions/secrets/REGISTRY_PASSWORD"
|
||||
```
|
||||
|
||||
## Workflow 基础结构
|
||||
|
||||
### 完整骨架
|
||||
|
||||
```yaml
|
||||
name: Service Name - Build & Publish
|
||||
|
||||
# 触发条件
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'service-dir/**'
|
||||
- '.gitea/workflows/this-workflow.yml'
|
||||
tags:
|
||||
- 'service-prefix-*'
|
||||
|
||||
# 并发控制
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# 环境变量
|
||||
env:
|
||||
SERVICE_PREFIX: service-name
|
||||
SERVICE_DIR: service-dir
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: darwin-arm64
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
version: ${{ steps.vars.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 项目特定的构建步骤
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/service-prefix-')
|
||||
steps:
|
||||
# Release 步骤
|
||||
```
|
||||
|
||||
## 触发条件配置
|
||||
|
||||
### 常用触发模式
|
||||
|
||||
```yaml
|
||||
on:
|
||||
# 分支推送
|
||||
push:
|
||||
branches: [main, develop]
|
||||
|
||||
# 路径过滤(推荐:仅相关文件变更时触发)
|
||||
push:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '*.yml'
|
||||
|
||||
# Tag 推送(用于 Release)
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- 'service-*'
|
||||
|
||||
# Pull Request
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
# 手动触发
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
description: 'Deploy environment'
|
||||
required: true
|
||||
default: 'staging'
|
||||
|
||||
# 定时触发
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # 每天凌晨 2 点
|
||||
```
|
||||
|
||||
### 并发控制
|
||||
|
||||
避免同一分支的多个 workflow 同时运行:
|
||||
|
||||
```yaml
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true # 取消旧的运行
|
||||
```
|
||||
|
||||
## 通用组件
|
||||
|
||||
### Checkout
|
||||
|
||||
```yaml
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # 完整历史,用于 git describe
|
||||
# fetch-depth: 1 # 仅最新提交,加快速度
|
||||
```
|
||||
|
||||
### 变量设置
|
||||
|
||||
```yaml
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
|
||||
|
||||
# 写入环境变量(当前 job 可用)
|
||||
{
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "registry=${registry}"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
# 写入输出(其他 job 可用)
|
||||
echo "version=${git_tag}" >> $GITHUB_OUTPUT
|
||||
```
|
||||
|
||||
### Cache Action
|
||||
|
||||
```yaml
|
||||
- name: Cache dependencies
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/directory
|
||||
./node_modules
|
||||
key: cache-name-${{ hashFiles('**/lockfile') }}
|
||||
restore-keys: cache-name-
|
||||
```
|
||||
|
||||
**各语言缓存路径**:
|
||||
|
||||
| 语言 | 缓存路径 | Key 文件 |
|
||||
|------|---------|----------|
|
||||
| Go | `~/go/pkg/mod`, `~/.cache/go-build` | `go.mod`, `go.sum` |
|
||||
| Node.js (pnpm) | `~/.pnpm-store`, `node_modules` | `pnpm-lock.yaml` |
|
||||
| Node.js (npm) | `~/.npm`, `node_modules` | `package-lock.json` |
|
||||
| Gradle | `~/.gradle/caches`, `~/.gradle/wrapper` | `*.gradle*`, `gradle-wrapper.properties` |
|
||||
|
||||
### Docker 构建推送
|
||||
|
||||
```yaml
|
||||
- name: Docker - Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.registry }}
|
||||
username: ${{ vars.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Docker - Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Build & Push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./service-dir
|
||||
file: ./service-dir/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
${{ env.registry }}/owner/image:latest
|
||||
${{ env.registry }}/owner/image:${{ env.git_tag }}
|
||||
cache-from: type=registry,ref=image:buildcache
|
||||
cache-to: type=registry,ref=image:buildcache,mode=max
|
||||
```
|
||||
|
||||
### Artifact 上传/下载
|
||||
|
||||
```yaml
|
||||
# 上传
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-artifact
|
||||
path: dist/
|
||||
|
||||
# 下载(另一个 job)
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build-artifact
|
||||
path: dist/
|
||||
```
|
||||
|
||||
### 通知 Webhook
|
||||
|
||||
```yaml
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && text="Build Success" || text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST \
|
||||
-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.SERVICE_PREFIX }} ${text}\"}}" \
|
||||
"$WEBHOOK_URL"
|
||||
```
|
||||
|
||||
### Release 创建(Gitea API)
|
||||
|
||||
```yaml
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传附件
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/artifact.zip" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
### 通用 Secrets
|
||||
|
||||
| Secret | 用途 | 适用项目 |
|
||||
|--------|------|---------|
|
||||
| `REGISTRY_PASSWORD` | Docker Registry 密码 | 需要 Docker 发布的项目 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌 | 需要创建 Release 的项目 |
|
||||
|
||||
### 安全最佳实践
|
||||
|
||||
1. **不要在日志中打印 secrets**
|
||||
2. **使用 `vars.` 存储非敏感变量**(如用户名、URL)
|
||||
3. **secrets 仅用于敏感信息**(如密码、密钥)
|
||||
4. **定期轮换密钥**
|
||||
|
||||
### 配置 Secrets
|
||||
|
||||
**方法 1: 通过 Gitea UI**
|
||||
|
||||
1. 打开仓库 → Settings → Secrets → Actions
|
||||
2. 点击 "Add Secret"
|
||||
3. 输入 Name 和 Value
|
||||
4. 保存
|
||||
|
||||
**方法 2: 通过 API**
|
||||
|
||||
```bash
|
||||
source ~/.config/gitea/config.env
|
||||
|
||||
secret_name="REGISTRY_PASSWORD"
|
||||
secret_value="my-password"
|
||||
|
||||
# Base64 编码
|
||||
encoded=$(echo -n "$secret_value" | base64)
|
||||
|
||||
# 调用 API
|
||||
curl -X PUT \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"data\":\"${encoded}\"}" \
|
||||
"$GITEA_URL/api/v1/repos/owner/repo/actions/secrets/$secret_name"
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 路径过滤
|
||||
|
||||
仅相关文件变更时触发,避免无关构建:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/**'
|
||||
- '.gitea/workflows/backend.yml'
|
||||
```
|
||||
|
||||
### 2. Tag 命名规范
|
||||
|
||||
使用前缀区分不同服务:
|
||||
|
||||
```bash
|
||||
git tag backend-1.0.0 && git push origin backend-1.0.0
|
||||
git tag frontend-1.0.0 && git push origin frontend-1.0.0
|
||||
git tag android-1.0.0 && git push origin android-1.0.0
|
||||
```
|
||||
|
||||
### 3. Job 输出传递
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
outputs:
|
||||
version: ${{ steps.vars.outputs.version }}
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
env:
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
```
|
||||
|
||||
### 4. 条件执行
|
||||
|
||||
```yaml
|
||||
# 仅 Tag 推送时执行
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
# 仅主分支执行
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
# 始终执行(用于通知)
|
||||
if: always()
|
||||
```
|
||||
|
||||
### 5. 使用缓存加速构建
|
||||
|
||||
合理使用缓存可以显著减少构建时间:
|
||||
|
||||
```yaml
|
||||
# Go 项目
|
||||
- name: Cache Go modules
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: go-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
# Node.js 项目
|
||||
- name: Cache pnpm store
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
```
|
||||
|
||||
## 项目特定模板
|
||||
|
||||
### Go 后端服务
|
||||
|
||||
详见:[Go 后端模板](./workflow-templates/go-backend.md)
|
||||
|
||||
**特点**:
|
||||
- 支持 monorepo 和 polyrepo
|
||||
- Docker 多阶段构建
|
||||
- 自动版本管理
|
||||
- Release 创建和附件上传
|
||||
|
||||
### Node.js 前端应用
|
||||
|
||||
详见:[Node.js 前端模板](./workflow-templates/nodejs-frontend.md)
|
||||
|
||||
**特点**:
|
||||
- pnpm/npm/yarn 支持
|
||||
- 依赖缓存优化
|
||||
- 静态资源构建
|
||||
- Docker 部署
|
||||
|
||||
### Android 应用
|
||||
|
||||
详见:[Android 应用模板](./workflow-templates/android-app.md)
|
||||
|
||||
**特点**:
|
||||
- Gradle 缓存优化
|
||||
- 多 flavor 支持
|
||||
- 签名配置
|
||||
- APK/AAB 生成
|
||||
|
||||
### 微信小程序
|
||||
|
||||
详见:[微信小程序模板](./workflow-templates/wechat-miniprogram.md)
|
||||
|
||||
**特点**:
|
||||
- 自动版本号管理
|
||||
- miniprogram-ci 集成
|
||||
- 预览/上传自动化
|
||||
- 体验版分发
|
||||
|
||||
## 快速参考
|
||||
|
||||
| 任务 | 命令/语法 |
|
||||
|------|----------|
|
||||
| 获取 git tag | `git describe --tags --abbrev=0 --always` |
|
||||
| 提取 registry | `echo ${{ github.server_url }} \| cut -d '/' -f 3` |
|
||||
| 设置环境变量 | `echo "KEY=value" >> $GITHUB_ENV` |
|
||||
| 设置输出 | `echo "key=value" >> $GITHUB_OUTPUT` |
|
||||
| 计算哈希 | `sha256sum file1 file2 \| sha256sum \| head -c 16` |
|
||||
|
||||
## 使用方式
|
||||
|
||||
1. **自然语言触发**:
|
||||
```
|
||||
用户: 为我的项目生成 workflow
|
||||
用户: 创建 CI/CD 配置
|
||||
用户: 添加自动化构建
|
||||
```
|
||||
|
||||
2. **AI 自动检测项目类型**
|
||||
|
||||
3. **填充项目特定信息**
|
||||
|
||||
4. **生成 workflow 文件**:`.gitea/workflows/*.yml`
|
||||
|
||||
5. **配置 Secrets**(如需要)
|
||||
|
||||
6. **推送代码触发**:
|
||||
```bash
|
||||
git add .gitea/workflows
|
||||
git commit -m "Add CI/CD workflow"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Gitea Actions 文档](https://docs.gitea.com/usage/actions/overview)
|
||||
- [GitHub Actions Workflow 语法](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions)
|
||||
- [环境配置指南](./setup-guide.md)
|
||||
- [Runner 管理](./runner-management.md)
|
||||
|
||||
## 版本
|
||||
|
||||
- **文档版本**: 1.0
|
||||
- **最后更新**: 2026-01-12
|
||||
- **整合内容**: gitea-workflow skill 的所有模板
|
||||
399
skill/gitea/workflow-templates/android-app.md
Normal file
399
skill/gitea/workflow-templates/android-app.md
Normal file
@@ -0,0 +1,399 @@
|
||||
# Android 应用 Workflow 模板
|
||||
|
||||
适用于 Android 应用的 CI/CD workflow,支持 APK 构建、签名和发布。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- Kotlin / Java Android 应用
|
||||
- Jetpack Compose 项目
|
||||
- 需要签名发布的 APK
|
||||
- 需要创建 Release 的项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| JDK 17+ | Runner 主机已安装 |
|
||||
| Android SDK | Runner 主机已安装 |
|
||||
| Gradle | 由 wrapper 管理 |
|
||||
|
||||
**重要**:必须使用 `darwin-arm64` 标签的 macOS Runner,因为 Google 不提供 Linux ARM64 版本的 Android SDK。
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Android - Build & Release APK
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'android/**' # 修改为实际目录
|
||||
- '.gitea/workflows/android.yml'
|
||||
tags:
|
||||
- 'android-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: android # 修改为实际服务名
|
||||
SERVICE_DIR: android # 修改为实际目录名
|
||||
APP_NAME: myapp-android # 修改为实际应用名
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Release APK
|
||||
runs-on: darwin-arm64 # macOS ARM64(必须)
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
version_name: ${{ steps.vars.outputs.version_name }}
|
||||
version_code: ${{ steps.vars.outputs.version_code }}
|
||||
apk_name: ${{ steps.vars.outputs.apk_name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify Java environment
|
||||
run: |
|
||||
java -version
|
||||
echo "JAVA_HOME=$JAVA_HOME"
|
||||
|
||||
- name: Setup Android SDK
|
||||
run: |
|
||||
if [ -n "$ANDROID_HOME" ] && [ -d "$ANDROID_HOME" ]; then
|
||||
echo "Using ANDROID_HOME: $ANDROID_HOME"
|
||||
else
|
||||
for SDK_PATH in ~/Library/Android/sdk ~/android-sdk /opt/homebrew/share/android-commandlinetools; do
|
||||
if [ -d "$SDK_PATH" ]; then
|
||||
export ANDROID_HOME=$SDK_PATH
|
||||
echo "Found Android SDK: $SDK_PATH"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$ANDROID_HOME" ] || [ ! -d "$ANDROID_HOME" ]; then
|
||||
echo "ERROR: Android SDK not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
||||
echo "$ANDROID_HOME/cmdline-tools/latest/bin" >> $GITHUB_PATH
|
||||
echo "$ANDROID_HOME/platform-tools" >> $GITHUB_PATH
|
||||
|
||||
- name: Get gradle-hashfiles
|
||||
id: hash-gradle
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum gradle/libs.versions.toml app/build.gradle.kts build.gradle.kts settings.gradle.kts 2>/dev/null | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ env.SERVICE_PREFIX }}-${{ steps.hash-gradle.outputs.hash }}
|
||||
restore-keys: gradle-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
# 从 build.gradle.kts 提取版本信息(按需修改路径和正则)
|
||||
version_name=$(grep 'versionName' ${{ env.SERVICE_DIR }}/app/build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
||||
version_code=$(grep 'versionCode' ${{ env.SERVICE_DIR }}/app/build.gradle.kts | head -1 | sed 's/[^0-9]*//g')
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
apk_name="${{ env.APP_NAME }}-${version_name}"
|
||||
|
||||
{
|
||||
echo "version_name=${version_name}"
|
||||
echo "version_code=${version_code}"
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "apk_name=${apk_name}"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "version_name=${version_name}" >> $GITHUB_OUTPUT
|
||||
echo "version_code=${version_code}" >> $GITHUB_OUTPUT
|
||||
echo "apk_name=${apk_name}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup signing
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
||||
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||
run: |
|
||||
# 创建 local.properties
|
||||
echo "sdk.dir=$ANDROID_HOME" > ${{ env.SERVICE_DIR }}/local.properties
|
||||
|
||||
# 配置签名(如果提供了 keystore)
|
||||
if [ -n "$KEYSTORE_BASE64" ]; then
|
||||
echo "$KEYSTORE_BASE64" | base64 -d > ${{ env.SERVICE_DIR }}/release.keystore
|
||||
{
|
||||
echo "KEYSTORE_FILE=../release.keystore"
|
||||
echo "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD"
|
||||
echo "KEY_ALIAS=$KEY_ALIAS"
|
||||
echo "KEY_PASSWORD=$KEY_PASSWORD"
|
||||
} >> ${{ env.SERVICE_DIR }}/local.properties
|
||||
echo "Signing configured"
|
||||
else
|
||||
echo "WARNING: No signing key provided, building unsigned APK"
|
||||
fi
|
||||
|
||||
- name: Build Release APK
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
|
||||
# ============================================
|
||||
# 用户自定义构建步骤(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 清理(按需启用)
|
||||
# ./gradlew clean
|
||||
|
||||
# 单元测试(按需启用)
|
||||
# ./gradlew test
|
||||
|
||||
# 构建 Release APK(必须)
|
||||
./gradlew assembleRelease --no-daemon
|
||||
|
||||
- name: Rename APK
|
||||
run: |
|
||||
mkdir -p dist
|
||||
cp ${{ env.SERVICE_DIR }}/app/build/outputs/apk/release/app-release.apk dist/${{ env.apk_name }}.apk
|
||||
cd dist
|
||||
sha256sum ${{ env.apk_name }}.apk > ${{ env.apk_name }}.apk.sha256
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-apk
|
||||
path: dist/
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.APP_NAME }} ${status_text}\\nVersion: ${{ env.version_name }}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-apk
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
VERSION_NAME: ${{ needs.build.outputs.version_name }}
|
||||
APK_NAME: ${{ needs.build.outputs.apk_name }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag} (v${VERSION_NAME})\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传 APK
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${APK_NAME}.apk" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
|
||||
# 上传校验和
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${APK_NAME}.apk.sha256" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 签名配置
|
||||
|
||||
### 1. 生成签名密钥
|
||||
|
||||
```bash
|
||||
keytool -genkey -v -keystore release.keystore \
|
||||
-alias myapp \
|
||||
-keyalg RSA \
|
||||
-keysize 2048 \
|
||||
-validity 10000
|
||||
```
|
||||
|
||||
### 2. Base64 编码
|
||||
|
||||
```bash
|
||||
base64 -i release.keystore -o keystore.base64
|
||||
# 将 keystore.base64 内容复制到 ANDROID_KEYSTORE_BASE64 secret
|
||||
```
|
||||
|
||||
### 3. build.gradle.kts 签名配置
|
||||
|
||||
```kotlin
|
||||
android {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
val props = Properties()
|
||||
val propsFile = rootProject.file("local.properties")
|
||||
if (propsFile.exists()) {
|
||||
props.load(propsFile.inputStream())
|
||||
val keystoreFile = props.getProperty("KEYSTORE_FILE", "")
|
||||
if (keystoreFile.isNotEmpty()) {
|
||||
storeFile = file(keystoreFile)
|
||||
storePassword = props.getProperty("KEYSTORE_PASSWORD", "")
|
||||
keyAlias = props.getProperty("KEY_ALIAS", "")
|
||||
keyPassword = props.getProperty("KEY_PASSWORD", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.gradle/caches # Gradle 依赖缓存
|
||||
~/.gradle/wrapper # Gradle wrapper
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
HASH=$(sha256sum gradle/libs.versions.toml app/build.gradle.kts build.gradle.kts settings.gradle.kts | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `ANDROID_KEYSTORE_BASE64` | Base64 编码的 keystore 文件 |
|
||||
| `ANDROID_KEYSTORE_PASSWORD` | keystore 密码 |
|
||||
| `ANDROID_KEY_ALIAS` | 密钥别名 |
|
||||
| `ANDROID_KEY_PASSWORD` | 密钥密码 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## Gradle 优化
|
||||
|
||||
### gradle.properties
|
||||
|
||||
```properties
|
||||
# CI 环境优化
|
||||
org.gradle.daemon=false
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
org.gradle.configureondemand=true
|
||||
|
||||
# Android 配置
|
||||
android.useAndroidX=true
|
||||
android.nonTransitiveRClass=true
|
||||
```
|
||||
|
||||
### 国内镜像(可选)
|
||||
|
||||
```properties
|
||||
# gradle-wrapper.properties
|
||||
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.13-bin.zip
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 版本提取
|
||||
|
||||
从 `build.gradle.kts` 提取版本信息:
|
||||
|
||||
```bash
|
||||
# versionName
|
||||
version_name=$(grep 'versionName' app/build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
||||
|
||||
# versionCode
|
||||
version_code=$(grep 'versionCode' app/build.gradle.kts | head -1 | sed 's/[^0-9]*//g')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见 Gradle 任务
|
||||
|
||||
| 任务 | 说明 |
|
||||
|------|------|
|
||||
| `./gradlew assembleRelease` | 构建 Release APK |
|
||||
| `./gradlew assembleDebug` | 构建 Debug APK |
|
||||
| `./gradlew bundleRelease` | 构建 AAB(App Bundle)|
|
||||
| `./gradlew test` | 运行单元测试 |
|
||||
| `./gradlew lint` | 运行 Lint 检查 |
|
||||
| `./gradlew clean` | 清理构建产物 |
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/android.yml`
|
||||
2. 修改 `SERVICE_PREFIX`、`SERVICE_DIR`、`APP_NAME` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 配置 `build.gradle.kts` 签名(参考上方示例)
|
||||
5. 配置 Secrets(keystore、密码等)
|
||||
6. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag android-1.0.0
|
||||
git push origin android-1.0.0
|
||||
```
|
||||
325
skill/gitea/workflow-templates/go-backend.md
Normal file
325
skill/gitea/workflow-templates/go-backend.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# Go 后端服务 Workflow 模板
|
||||
|
||||
适用于 Go 后端 API 服务、微服务、CLI 工具的 CI/CD workflow。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- Go HTTP API 服务
|
||||
- gRPC 微服务
|
||||
- CLI 工具
|
||||
- 需要构建 Docker 镜像的 Go 项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| Go 1.21+ | Runner 主机已安装 |
|
||||
| Docker | Runner 主机已安装 |
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Go Backend - Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'your-service/**' # 修改为实际目录
|
||||
- '.gitea/workflows/your-service.yml'
|
||||
tags:
|
||||
- 'your-service-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: your-service # 修改为实际服务名
|
||||
SERVICE_DIR: your-service # 修改为实际目录名
|
||||
GOPROXY: https://goproxy.cn,direct
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
name: Build & Publish
|
||||
runs-on: darwin-arm64
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
binary_name: ${{ steps.vars.outputs.binary_name }}
|
||||
git_tag: ${{ steps.vars.outputs.git_tag }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify Go environment
|
||||
run: |
|
||||
go version
|
||||
echo "GOPATH=$(go env GOPATH)"
|
||||
|
||||
- name: Get go-hashfiles
|
||||
id: hash-go
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum go.mod go.sum | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: go-${{ env.SERVICE_PREFIX }}-${{ steps.hash-go.outputs.hash }}
|
||||
restore-keys: go-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
|
||||
binary_name="${{ github.event.repository.name }}-${{ env.SERVICE_PREFIX }}"
|
||||
image_repo="${{ github.event.repository.name }}"
|
||||
|
||||
{
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "registry=${registry}"
|
||||
echo "binary_name=${binary_name}"
|
||||
echo "image_repo=${image_repo}"
|
||||
echo "latest_tag=${{ env.SERVICE_PREFIX }}-latest"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "binary_name=${binary_name}" >> $GITHUB_OUTPUT
|
||||
echo "git_tag=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
env:
|
||||
CGO_ENABLED: 0
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
run: |
|
||||
# ============================================
|
||||
# 用户自定义构建步骤(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 代码生成(按需启用)
|
||||
# go generate ./...
|
||||
# go tool ent generate ./schema
|
||||
# go tool wire ./...
|
||||
# go tool oapi-codegen -config oapi.yaml api.yaml
|
||||
# go tool stringer -type=MyType ./...
|
||||
|
||||
# 测试(按需启用)
|
||||
# go test ./...
|
||||
# go vet ./...
|
||||
|
||||
# 构建(必须)
|
||||
go build -o ${{ env.binary_name }} \
|
||||
-ldflags '-s -w -X main.GitTag=${{ env.git_tag }}'
|
||||
|
||||
chmod +x ${{ env.binary_name }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-binary-linux-amd64
|
||||
path: ${{ env.SERVICE_DIR }}/${{ env.binary_name }}
|
||||
|
||||
- name: Docker - Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.registry }}
|
||||
username: ${{ vars.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Docker - Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Build & Push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ${{ env.SERVICE_DIR }}
|
||||
file: ./${{ env.SERVICE_DIR }}/Dockerfile.ci
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.latest_tag }}
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.git_tag }}
|
||||
cache-from: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache
|
||||
cache-to: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache,mode=max
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.binary_name }} ${status_text}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build-and-publish
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-binary-linux-amd64
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
BINARY_NAME: ${{ needs.build-and-publish.outputs.binary_name }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 生成校验和
|
||||
cd dist
|
||||
sha256sum "${BINARY_NAME}" > "${BINARY_NAME}.sha256"
|
||||
cd ..
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传二进制文件
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${BINARY_NAME}" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
|
||||
# 上传校验和
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${BINARY_NAME}.sha256" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dockerfile.ci 模板
|
||||
|
||||
```dockerfile
|
||||
FROM alpine:latest
|
||||
|
||||
# 安装时区数据和证书
|
||||
RUN apk add --no-cache tzdata ca-certificates
|
||||
|
||||
# 设置时区
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
# 复制构建好的二进制文件
|
||||
# 注意:需要在 docker build 时通过 --build-arg 传递 BINARY_NAME
|
||||
# 或者直接写死二进制文件名
|
||||
ARG BINARY_NAME=server
|
||||
COPY ${BINARY_NAME} /app/server
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 健康检查(按需修改端口和路径)
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["/app/server"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/go/pkg/mod # Go 模块缓存
|
||||
~/.cache/go-build # Go 构建缓存
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
HASH=$(sha256sum go.mod go.sum | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 构建参数说明
|
||||
|
||||
```bash
|
||||
CGO_ENABLED=0 # 禁用 CGO,生成静态链接二进制
|
||||
GOOS=linux # 目标操作系统
|
||||
GOARCH=amd64 # 目标架构
|
||||
|
||||
-ldflags '-s -w' # 去除符号表和调试信息,减小体积
|
||||
-X main.GitTag=... # 注入版本信息
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `REGISTRY_PASSWORD` | Docker Registry 密码 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## 常见代码生成工具
|
||||
|
||||
根据项目使用的框架,在 Build 步骤中添加相应的生成命令:
|
||||
|
||||
| 框架/工具 | 命令 |
|
||||
|----------|------|
|
||||
| Ent (ORM) | `go tool ent generate ./schema` |
|
||||
| Wire (DI) | `go tool wire ./...` |
|
||||
| oapi-codegen | `go tool oapi-codegen -config oapi.yaml api.yaml` |
|
||||
| Stringer | `go tool stringer -type=MyType ./...` |
|
||||
| Protobuf | `protoc --go_out=. --go-grpc_out=. *.proto` |
|
||||
| go generate | `go generate ./...` |
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/your-service.yml`
|
||||
2. 修改 `SERVICE_PREFIX` 和 `SERVICE_DIR` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 根据项目需求填充 "用户自定义构建步骤" 部分
|
||||
5. 创建 `Dockerfile.ci` 文件
|
||||
6. 配置 Secrets
|
||||
7. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag your-service-1.0.0
|
||||
git push origin your-service-1.0.0
|
||||
```
|
||||
397
skill/gitea/workflow-templates/nodejs-frontend.md
Normal file
397
skill/gitea/workflow-templates/nodejs-frontend.md
Normal file
@@ -0,0 +1,397 @@
|
||||
# Node.js 前端 Workflow 模板
|
||||
|
||||
适用于 Node.js 前端项目的 CI/CD workflow,支持 React、Vue、Vite、Next.js 等框架。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- React / Vue / Angular 前端项目
|
||||
- Vite / Webpack 构建的 SPA
|
||||
- Next.js / Nuxt.js SSR 应用
|
||||
- 需要构建 Docker 镜像的前端项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| Node.js 20+ | Runner 主机已安装 |
|
||||
| pnpm / npm | Runner 主机已安装或动态安装 |
|
||||
| Docker | Runner 主机已安装 |
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Web Frontend - Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'web/**' # 修改为实际目录
|
||||
- '.gitea/workflows/web.yml'
|
||||
tags:
|
||||
- 'web-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: web # 修改为实际服务名
|
||||
SERVICE_DIR: web # 修改为实际目录名
|
||||
NPM_REGISTRY: https://registry.npmmirror.com
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
name: Build & Publish
|
||||
runs-on: darwin-arm64
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
git_tag: ${{ steps.vars.outputs.git_tag }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Verify Node.js environment
|
||||
run: |
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
- name: Set up pnpm
|
||||
run: |
|
||||
npm config set registry ${{ env.NPM_REGISTRY }}
|
||||
npm install -g pnpm@latest-10
|
||||
|
||||
- name: Get pnpm-hashfiles
|
||||
id: hash-pnpm
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum package.json pnpm-lock.yaml 2>/dev/null | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache pnpm modules
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.local/share/pnpm/store
|
||||
~/.pnpm-store
|
||||
${{ env.SERVICE_DIR }}/node_modules
|
||||
key: pnpm-${{ env.SERVICE_PREFIX }}-${{ steps.hash-pnpm.outputs.hash }}
|
||||
restore-keys: pnpm-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
|
||||
image_repo="${{ github.event.repository.name }}"
|
||||
|
||||
{
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "registry=${registry}"
|
||||
echo "image_repo=${image_repo}"
|
||||
echo "latest_tag=${{ env.SERVICE_PREFIX }}-latest"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "git_tag=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install & Build
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
env:
|
||||
NODE_ENV: production
|
||||
# ============================================
|
||||
# 用户自定义环境变量(按项目需求修改)
|
||||
# ============================================
|
||||
# VITE_API_URL: https://api.example.com
|
||||
# VITE_APP_TITLE: My App
|
||||
# NEXT_PUBLIC_API_URL: https://api.example.com
|
||||
run: |
|
||||
# 安装依赖
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# ============================================
|
||||
# 用户自定义构建步骤(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 类型检查(按需启用)
|
||||
# pnpm run typecheck
|
||||
# pnpm run lint
|
||||
|
||||
# 构建(必须)
|
||||
pnpm run build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-dist
|
||||
path: ${{ env.SERVICE_DIR }}/dist
|
||||
|
||||
- name: Docker - Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.registry }}
|
||||
username: ${{ vars.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Docker - Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Build & Push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./${{ env.SERVICE_DIR }}
|
||||
file: ./${{ env.SERVICE_DIR }}/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.latest_tag }}
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.git_tag }}
|
||||
cache-from: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache
|
||||
cache-to: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache,mode=max
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.image_repo }}-${{ env.SERVICE_PREFIX }} ${status_text}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build-and-publish
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-dist
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 打包构建产物
|
||||
cd dist
|
||||
zip -r "${{ env.SERVICE_PREFIX }}-dist.zip" .
|
||||
sha256sum "${{ env.SERVICE_PREFIX }}-dist.zip" > "${{ env.SERVICE_PREFIX }}-dist.zip.sha256"
|
||||
cd ..
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传附件
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${{ env.SERVICE_PREFIX }}-dist.zip" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dockerfile 模板
|
||||
|
||||
### 静态文件部署(Nginx)
|
||||
|
||||
```dockerfile
|
||||
FROM nginx:alpine
|
||||
|
||||
# 复制构建产物
|
||||
COPY dist /usr/share/nginx/html
|
||||
|
||||
# 复制 nginx 配置(可选)
|
||||
# COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
### SPA 路由配置(nginx.conf)
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# SPA 路由支持
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# 禁止缓存 HTML
|
||||
location ~* \.html$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### pnpm 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.local/share/pnpm/store # pnpm 全局存储
|
||||
~/.pnpm-store # 备选路径
|
||||
web/node_modules # 项目依赖
|
||||
```
|
||||
|
||||
### npm 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.npm
|
||||
web/node_modules
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
# pnpm
|
||||
HASH=$(sha256sum package.json pnpm-lock.yaml | sha256sum | awk '{print $1}' | head -c 16)
|
||||
|
||||
# npm
|
||||
HASH=$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 包管理器选择
|
||||
|
||||
### pnpm(推荐)
|
||||
|
||||
```yaml
|
||||
- name: Set up pnpm
|
||||
run: |
|
||||
npm install -g pnpm@latest-10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
### npm
|
||||
|
||||
```yaml
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
```
|
||||
|
||||
### yarn
|
||||
|
||||
```yaml
|
||||
- name: Set up yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 环境变量注入
|
||||
|
||||
### Vite
|
||||
|
||||
```yaml
|
||||
env:
|
||||
VITE_API_URL: https://api.example.com
|
||||
VITE_APP_TITLE: My App
|
||||
```
|
||||
|
||||
### Next.js
|
||||
|
||||
```yaml
|
||||
env:
|
||||
NEXT_PUBLIC_API_URL: https://api.example.com
|
||||
```
|
||||
|
||||
### Vue CLI / CRA
|
||||
|
||||
```yaml
|
||||
env:
|
||||
VUE_APP_API_URL: https://api.example.com
|
||||
REACT_APP_API_URL: https://api.example.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `REGISTRY_PASSWORD` | Docker Registry 密码 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## 常见构建命令
|
||||
|
||||
根据项目使用的框架,在 Build 步骤中添加相应的命令:
|
||||
|
||||
| 框架 | 构建命令 |
|
||||
|------|---------|
|
||||
| Vite | `pnpm run build` |
|
||||
| Next.js | `pnpm run build` |
|
||||
| Nuxt.js | `pnpm run generate` 或 `pnpm run build` |
|
||||
| Vue CLI | `pnpm run build` |
|
||||
| CRA | `npm run build` |
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/web.yml`
|
||||
2. 修改 `SERVICE_PREFIX` 和 `SERVICE_DIR` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 根据项目需求配置环境变量
|
||||
5. 创建 `Dockerfile` 文件
|
||||
6. 配置 Secrets
|
||||
7. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag web-1.0.0
|
||||
git push origin web-1.0.0
|
||||
```
|
||||
386
skill/gitea/workflow-templates/wechat-miniprogram.md
Normal file
386
skill/gitea/workflow-templates/wechat-miniprogram.md
Normal file
@@ -0,0 +1,386 @@
|
||||
# 微信小程序 Workflow 模板
|
||||
|
||||
适用于微信小程序的 CI/CD workflow,支持自动构建和上传体验版。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 微信小程序项目
|
||||
- 使用 miniprogram-ci 自动上传
|
||||
- TypeScript 小程序项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| Node.js 18+ | Runner 主机已安装 |
|
||||
| miniprogram-ci | 动态安装 |
|
||||
|
||||
## 前置配置
|
||||
|
||||
### 1. 获取小程序上传密钥
|
||||
|
||||
1. 登录 [微信公众平台](https://mp.weixin.qq.com/)
|
||||
2. 进入 **开发管理** → **开发设置**
|
||||
3. 下载 **代码上传密钥**
|
||||
|
||||
### 2. Base64 编码密钥
|
||||
|
||||
```bash
|
||||
cat private.key | base64 -w 0 > private.key.base64
|
||||
# 将内容复制到 MINIPROGRAM_PRIVATE_KEY secret
|
||||
```
|
||||
|
||||
### 3. 配置 IP 白名单
|
||||
|
||||
在微信公众平台添加 Runner 服务器的公网 IP 到白名单。
|
||||
|
||||
---
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Mini-Program - Build & Upload
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'mini-program/**' # 修改为实际目录
|
||||
- '.gitea/workflows/miniprogram.yml'
|
||||
tags:
|
||||
- 'miniprogram-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: miniprogram # 修改为实际服务名
|
||||
SERVICE_DIR: mini-program # 修改为实际目录名
|
||||
NPM_REGISTRY: https://registry.npmmirror.com
|
||||
APPID: wxYOUR_APPID_HERE # 修改为实际 AppID
|
||||
|
||||
jobs:
|
||||
build-and-upload:
|
||||
name: Build & Upload
|
||||
runs-on: darwin-arm64
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
outputs:
|
||||
version: ${{ steps.vars.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify Node.js environment
|
||||
run: |
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
- name: Configure npm registry
|
||||
run: npm config set registry ${{ env.NPM_REGISTRY }}
|
||||
|
||||
- name: Get npm-hashfiles
|
||||
id: hash-npm
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum package.json package-lock.json 2>/dev/null | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache npm modules
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
${{ env.SERVICE_DIR }}/node_modules
|
||||
key: npm-${{ env.SERVICE_PREFIX }}-${{ steps.hash-npm.outputs.hash }}
|
||||
restore-keys: npm-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
version=$(node -p "require('./package.json').version")
|
||||
commit_title=$(git log -1 --pretty=format:"%s")
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
|
||||
{
|
||||
echo "version=${version}"
|
||||
echo "commit_title=${commit_title}"
|
||||
echo "git_tag=${git_tag}"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: npm ci
|
||||
|
||||
- name: Build npm packages
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
npm install -g miniprogram-ci
|
||||
|
||||
# ============================================
|
||||
# 用户自定义 npm 包构建(按项目需求修改)
|
||||
# ============================================
|
||||
# 小程序不支持直接使用 node_modules,需要手动复制
|
||||
|
||||
mkdir -p miniprogram_npm
|
||||
|
||||
# 示例:复制 UI 组件库
|
||||
# if [ -d "node_modules/tdesign-miniprogram/miniprogram_dist" ]; then
|
||||
# cp -r node_modules/tdesign-miniprogram/miniprogram_dist miniprogram_npm/tdesign-miniprogram
|
||||
# fi
|
||||
|
||||
# 示例:复制工具库
|
||||
# for pkg in dayjs lodash; do
|
||||
# [ -d "node_modules/$pkg" ] && cp -r "node_modules/$pkg" miniprogram_npm/
|
||||
# done
|
||||
|
||||
echo "npm packages prepared"
|
||||
ls -la miniprogram_npm/ 2>/dev/null || echo "No npm packages"
|
||||
|
||||
- name: TypeScript check
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
# ============================================
|
||||
# 用户自定义类型检查(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 示例:TypeScript 类型检查
|
||||
# npx tsc --noEmit --skipLibCheck || echo "TypeScript check completed with warnings"
|
||||
|
||||
echo "Type check step (customize as needed)"
|
||||
|
||||
- name: Setup private key
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
env:
|
||||
MINIPROGRAM_PRIVATE_KEY: ${{ secrets.MINIPROGRAM_PRIVATE_KEY }}
|
||||
run: |
|
||||
if [ -n "$MINIPROGRAM_PRIVATE_KEY" ]; then
|
||||
echo "$MINIPROGRAM_PRIVATE_KEY" | base64 -d > private.key
|
||||
echo "Private key configured"
|
||||
else
|
||||
echo "WARNING: MINIPROGRAM_PRIVATE_KEY not set"
|
||||
fi
|
||||
|
||||
- name: Upload to WeChat
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
[ ! -f "private.key" ] && { echo "Skip upload: no private key"; exit 0; }
|
||||
|
||||
miniprogram-ci upload \
|
||||
--pp ./ \
|
||||
--pkp ./private.key \
|
||||
--appid ${{ env.APPID }} \
|
||||
--uv "${{ env.version }}" \
|
||||
--ud "${{ env.commit_title }}" \
|
||||
--robot 1 \
|
||||
-r 1 \
|
||||
--enable-es6 true \
|
||||
--enable-es7 true \
|
||||
--enable-minify true \
|
||||
--enable-minifyJS true \
|
||||
--enable-minifyWXML true \
|
||||
--enable-minifyWXSS true \
|
||||
--enable-autoPrefixWXSS true
|
||||
|
||||
echo "Upload success: v${{ env.version }}"
|
||||
|
||||
- name: Cleanup private key
|
||||
if: always()
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: rm -f private.key
|
||||
|
||||
- name: Create source package
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
mkdir -p ../dist
|
||||
tar --exclude='node_modules' \
|
||||
--exclude='.git' \
|
||||
--exclude='private.key' \
|
||||
-czf ../dist/${{ env.SERVICE_PREFIX }}-${{ env.version }}-source.tar.gz .
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-source
|
||||
path: dist/${{ env.SERVICE_PREFIX }}-${{ env.version }}-source.tar.gz
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Upload Success" || status_text="Upload Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"Miniprogram ${status_text}\\nVersion: ${{ env.version }}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build-and-upload
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-source
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
VERSION: ${{ needs.build-and-upload.outputs.version }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag} (v${VERSION})\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传源码包
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${{ env.SERVICE_PREFIX }}-${VERSION}-source.tar.gz" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## miniprogram-ci 参数说明
|
||||
|
||||
```bash
|
||||
miniprogram-ci upload \
|
||||
--pp ./ # 项目路径
|
||||
--pkp ./private.key # 私钥路径
|
||||
--appid wx123456789 # 小程序 AppID
|
||||
--uv "1.0.0" # 版本号
|
||||
--ud "提交描述" # 版本描述
|
||||
--robot 1 # 机器人编号 (1-30)
|
||||
-r 1 # 提交轮次
|
||||
--enable-es6 true # ES6 转 ES5
|
||||
--enable-es7 true # ES7 支持
|
||||
--enable-minify true # 压缩代码
|
||||
--enable-minifyJS true # 压缩 JS
|
||||
--enable-minifyWXML true # 压缩 WXML
|
||||
--enable-minifyWXSS true # 压缩 WXSS
|
||||
--enable-autoPrefixWXSS true # CSS 自动前缀
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.npm
|
||||
mini-program/node_modules
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
HASH=$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `MINIPROGRAM_PRIVATE_KEY` | Base64 编码的上传密钥 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## npm 包处理
|
||||
|
||||
小程序不支持直接使用 `node_modules`,需要手动复制到 `miniprogram_npm/`:
|
||||
|
||||
```bash
|
||||
# UI 组件库(使用 miniprogram_dist 目录)
|
||||
cp -r node_modules/tdesign-miniprogram/miniprogram_dist miniprogram_npm/tdesign-miniprogram
|
||||
cp -r node_modules/vant-weapp/lib miniprogram_npm/vant-weapp
|
||||
|
||||
# 工具库(直接复制)
|
||||
cp -r node_modules/dayjs miniprogram_npm/
|
||||
cp -r node_modules/lodash miniprogram_npm/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 版本管理
|
||||
|
||||
从 `package.json` 读取版本号:
|
||||
|
||||
```bash
|
||||
version=$(node -p "require('./package.json').version")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 体验版说明
|
||||
|
||||
- 上传成功后自动成为**体验版**
|
||||
- 需要在微信后台手动提交审核发布正式版
|
||||
- `--robot` 参数可区分不同 CI 环境(1-30)
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
mini-program/
|
||||
├── pages/ # 页面
|
||||
├── components/ # 组件
|
||||
├── miniprogram_npm/ # npm 包(构建生成)
|
||||
├── app.ts # 应用入口
|
||||
├── app.json # 应用配置
|
||||
├── project.config.json # 项目配置
|
||||
├── package.json # 依赖配置
|
||||
└── tsconfig.json # TypeScript 配置
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/miniprogram.yml`
|
||||
2. 修改 `SERVICE_PREFIX`、`SERVICE_DIR`、`APPID` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 根据项目需求填充 npm 包构建步骤
|
||||
5. 配置 Secrets(上传密钥)
|
||||
6. 在微信公众平台添加 IP 白名单
|
||||
7. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag miniprogram-1.0.0
|
||||
git push origin miniprogram-1.0.0
|
||||
```
|
||||
Reference in New Issue
Block a user