chore: 重构 OpenCode 命令和技能文档体系
- 新增:统一的 git 命令文档(add/commit/push/pull 等) - 新增:整合的 Gitea 技能文档(API、运行器、工作流等) - 新增:工作流模板(Android、Go、Node.js 等) - 移除:已弃用的旧命令脚本和发布脚本 - 改进:.gitignore 添加敏感文件保护规则 - 改进:AGENTS.md 完善了开发规范和示例 此次重组统一了命令和技能的文档结构,便于后续维护和扩展。
This commit is contained in:
12
.gitignore
vendored
12
.gitignore
vendored
@@ -6,3 +6,15 @@ env.sh
|
||||
bin/opencode
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
|
||||
# 敏感配置文件
|
||||
config.env
|
||||
.env
|
||||
.env.*
|
||||
*.pem
|
||||
*.key
|
||||
*.p12
|
||||
*.jks
|
||||
|
||||
# Gitea 配置(如果不小心复制到这里)
|
||||
gitea-config.env
|
||||
|
||||
303
AGENTS.md
303
AGENTS.md
@@ -8,17 +8,25 @@
|
||||
|
||||
## 语言偏好
|
||||
|
||||
### 用户交互
|
||||
**重要:请始终使用中文(简体中文)与用户交流。**
|
||||
|
||||
所有回复、解释、错误消息、建议和对话都应该使用中文,除非:
|
||||
- 代码注释需要使用英文(根据项目规范)
|
||||
- 用户明确要求使用其他语言
|
||||
- 技术术语在中文中没有合适的翻译(可以中英文混用,如 "React Hooks")
|
||||
|
||||
### 代码注释
|
||||
- **默认使用中文**
|
||||
- 遵循项目规范(如果项目有特殊要求,以项目规范为准)
|
||||
|
||||
### 独立文档文件
|
||||
- **默认使用英文**(.md、.txt、.rst 等文档文件)
|
||||
- 只有用户明确要求使用中文时才使用中文
|
||||
|
||||
### 重要注意事项
|
||||
|
||||
1. **不要因为文档、命令或代码是英文就切换语言**
|
||||
- 即使项目文档是英文的,回复时仍然用中文解释
|
||||
- 即使项目文档是英文的,对话回复时仍然用中文解释
|
||||
- 即使执行的命令是英文的,回复时仍然用中文说明
|
||||
- 即使错误信息是英文的,回复时仍然用中文分析
|
||||
|
||||
@@ -31,11 +39,202 @@
|
||||
- 所有对话、提问、确认都用中文
|
||||
- 所有建议、总结、分析都用中文
|
||||
- 所有错误解释和问题诊断都用中文
|
||||
- 专有名词可以使用英文
|
||||
|
||||
这是用户的个人偏好设置,适用于所有项目和所有交互场景。
|
||||
|
||||
---
|
||||
|
||||
## 回复展示规范
|
||||
|
||||
### 内容展示限制
|
||||
**重要:回复中不得直接展示超过 100 行的内容。**
|
||||
|
||||
适用范围:
|
||||
- 文档内容(.md、.txt、.rst 等)
|
||||
- 代码文件(.js、.ts、.py、.go 等)
|
||||
- 配置文件
|
||||
- 任何其他文本内容
|
||||
|
||||
### 长内容处理原则
|
||||
|
||||
1. **创建文件时(超过 100 行)**
|
||||
- 首先考虑:是否可以拆分成多个模块?
|
||||
- 优先使用模块化设计,拆分成多个小文件
|
||||
- 如果确实应该保持单一文件(如:配置文件、工具类等):
|
||||
- 只告知用户文件已创建
|
||||
- 提供文件路径
|
||||
- 说明文件用途和关键特性
|
||||
- 不要在回复中粘贴完整内容
|
||||
|
||||
2. **展示修改时**
|
||||
- 只展示核心、关键的改动部分
|
||||
- 使用代码片段展示(通常 10-30 行)
|
||||
- 用省略号(...)表示被省略的部分
|
||||
- 说明改动的位置和目的
|
||||
|
||||
3. **提供概览时**
|
||||
- 使用摘要和要点列表
|
||||
- 展示关键函数签名或接口定义
|
||||
- 提供文件路径供用户自行查看
|
||||
|
||||
### 回复简洁性要求
|
||||
|
||||
**必须隐藏的内容:**
|
||||
- 完整的文件内容(超过 100 行)
|
||||
- 详细的执行日志(除非有错误需要诊断)
|
||||
- 重复性的代码模式
|
||||
- 自动生成的代码(如类型定义、配置模板等)
|
||||
|
||||
**必须展示的内容:**
|
||||
- 核心改动代码片段(< 50 行)
|
||||
- 关键错误信息
|
||||
- 重要的配置修改
|
||||
- 用户需要注意的变更点
|
||||
|
||||
### 文件操作展示规范
|
||||
|
||||
**重要:CRUD 文件时,只需总结操作结果,无需展示具体变更内容。**
|
||||
|
||||
适用于以下操作:
|
||||
- **Create(创建)**:创建新文件
|
||||
- **Read(读取)**:读取文件内容(除非用户明确要求展示)
|
||||
- **Update(更新)**:修改现有文件
|
||||
- **Delete(删除)**:删除文件
|
||||
|
||||
**展示原则:**
|
||||
- ✅ 说明操作类型(创建、修改、删除)
|
||||
- ✅ 提供文件路径
|
||||
- ✅ 简要说明改动的目的和影响
|
||||
- ❌ 不展示具体的代码变更内容
|
||||
- ❌ 不展示文件的完整内容
|
||||
|
||||
**示例:**
|
||||
|
||||
✅ **正确做法:**
|
||||
```
|
||||
已修改 src/config/settings.ts,更新了数据库连接配置。
|
||||
```
|
||||
|
||||
❌ **错误做法:**
|
||||
```
|
||||
已修改 src/config/settings.ts:
|
||||
[展示修改前后的代码对比]
|
||||
```
|
||||
|
||||
### 避免重复命令输出
|
||||
|
||||
**重要:不要重复或总结命令输出中已有的内容。**
|
||||
|
||||
当命令输出已经包含完整信息时(如:状态、操作步骤、使用说明等):
|
||||
- ✅ 直接展示命令输出即可
|
||||
- ❌ 不要在命令输出后再次总结相同的内容
|
||||
- ❌ 不要重复命令中已提供的操作指令
|
||||
|
||||
**例外情况:**
|
||||
- 命令出错需要分析和解释
|
||||
- 需要提取关键信息进行下一步操作
|
||||
- 用户明确要求总结
|
||||
|
||||
**示例:**
|
||||
|
||||
❌ **错误做法:**
|
||||
```
|
||||
[命令输出:包含完整的 runner 列表、状态、启动命令]
|
||||
|
||||
✅ 已成功列出所有 Gitea Runners!
|
||||
|
||||
当前状态:
|
||||
- 总计:1 个 runner
|
||||
- 名称:runner-mac-mini4
|
||||
- 状态:已停止
|
||||
|
||||
快速操作:
|
||||
如需启动,执行:[重复命令输出中的启动命令]
|
||||
```
|
||||
|
||||
✅ **正确做法:**
|
||||
```
|
||||
[命令输出:包含完整的 runner 列表、状态、启动命令]
|
||||
|
||||
(直接展示命令输出,无需额外总结)
|
||||
```
|
||||
|
||||
### 任务完成后的回复规范
|
||||
|
||||
**重要:避免冗余的总结报告,保持简洁。**
|
||||
|
||||
任务完成后,只需要提供一个简短的总结,包含:
|
||||
1. ✅ 已完成的操作(使用要点列表,不超过 5 条)
|
||||
2. 📝 核心修改内容(1-2 句话概括)
|
||||
3. ⚠️ 需要注意的事项(如果有)
|
||||
|
||||
**禁止的做法:**
|
||||
- ❌ 生成详细的表格报告(如"检查报告"、"修复报告")
|
||||
- ❌ 生成多个总结("总结报告" + "最终总结")
|
||||
- ❌ 使用大量装饰性符号和分隔线
|
||||
- ❌ 重复描述已经执行过的步骤
|
||||
- ❌ 生成统计数据(除非用户明确要求)
|
||||
|
||||
**推荐的做法:**
|
||||
```
|
||||
✅ 已完成:
|
||||
- 修改了 7 个文件,替换用户名为占位符
|
||||
- 更新 .gitignore,添加敏感文件保护规则
|
||||
|
||||
核心修改:用户名已脱敏,配置文件保护已加强。
|
||||
```
|
||||
|
||||
**例外情况(可以提供详细报告):**
|
||||
- 用户明确要求生成报告
|
||||
- 复杂的检查任务需要呈现检查结果
|
||||
- 错误诊断需要详细分析
|
||||
|
||||
### 示例
|
||||
|
||||
❌ **错误做法:**
|
||||
```
|
||||
我创建了 src/utils/helper.ts 文件,内容如下:
|
||||
[粘贴 200 行完整代码]
|
||||
```
|
||||
|
||||
✅ **正确做法:**
|
||||
```
|
||||
已创建 src/utils/helper.ts(200 行),包含 formatDate、debounce、throttle、deepClone 等工具函数。
|
||||
```
|
||||
|
||||
❌ **错误做法(冗余总结):**
|
||||
```
|
||||
[执行了一系列操作]
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
✅ 操作完成报告
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
【详细的表格和统计】
|
||||
【重复的操作描述】
|
||||
【多个章节的报告】
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
[然后又生成一个"最终总结"]
|
||||
|
||||
## ✅ 最终总结
|
||||
|
||||
【再次总结相同的内容】
|
||||
```
|
||||
|
||||
✅ **正确做法(简洁总结):**
|
||||
```
|
||||
✅ 已完成:
|
||||
- 修改 git-add.md,添加未跟踪文件的一站式选项
|
||||
- 新增 all/u 选项可一次暂存所有文件
|
||||
|
||||
核心改进:不再需要运行两次命令。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 代码风格偏好
|
||||
|
||||
### JavaScript/TypeScript
|
||||
@@ -57,10 +256,14 @@
|
||||
## 开发流程
|
||||
|
||||
### Git 提交规范
|
||||
- 遵循 [Conventional Commits](https://www.conventionalcommits.org/) 规范
|
||||
- **格式**:`<type>(<scope>): <subject>`
|
||||
- **类型**:feat(功能)、fix(修复)、docs(文档)、style(格式)、refactor(重构)、test(测试)、chore(维护)
|
||||
- **类型**:feat(功能)、fix(修复)、docs(文档)、style(格式)、refactor(重构)、test(测试)、chore(维护)、ci、build、perf
|
||||
- **主题**:使用中文,简洁明了,不超过 50 字
|
||||
- **描述**:如有需要,空一行后补充详细说明
|
||||
- **主分支**:默认使用 `main`(不是 master)
|
||||
|
||||
> 详细的 Git 工作流程、版本管理、Tag 规范等请参考 `skill/git/SKILL.md`
|
||||
|
||||
### 分支命名
|
||||
- 功能分支:`feature/描述`
|
||||
@@ -74,9 +277,90 @@
|
||||
- 修复所有 linter 和类型检查错误
|
||||
|
||||
### 发布流程
|
||||
- 主分支(main/master)始终保持可部署状态
|
||||
- 主分支(main)始终保持可部署状态
|
||||
- 不直接推送到主分支,必须通过 PR
|
||||
- 标签格式:`v<major>.<minor>.<patch>`
|
||||
- **标签格式**:
|
||||
- 单仓库(polyrepo):`<major>.<minor>.<patch>`(如 `1.2.0`)
|
||||
- 多仓库(monorepo):`<subproject>-<major>.<minor>.<patch>`(如 `ios-1.2.0`)
|
||||
|
||||
> 详细的版本管理、Tag 规范和 Git 工作流程请参考 `skill/git/SKILL.md`
|
||||
|
||||
---
|
||||
|
||||
## 批量修改策略
|
||||
|
||||
### 先验证再批量修改原则
|
||||
|
||||
**重要:在进行批量修改时,必须遵循"先修改一个,验证通过后再批量修改"的原则。**
|
||||
|
||||
适用范围:
|
||||
- **Command(命令)**:修改或新增多个命令时
|
||||
- **Skill(技能)**:修改或新增多个技能时
|
||||
- **代码功能**:批量修改多个文件或多个函数时
|
||||
- **配置文件**:批量修改多个配置项时
|
||||
|
||||
### 执行步骤
|
||||
|
||||
1. **选择样本**
|
||||
- 从批量修改的目标中选择 1 个作为样本
|
||||
- 优先选择最具代表性或最复杂的一个
|
||||
|
||||
2. **修改样本**
|
||||
- 完成样本的修改
|
||||
- 确保代码质量和规范
|
||||
|
||||
3. **验证样本**
|
||||
- 运行相关测试
|
||||
- 检查功能是否正常
|
||||
- 确认修改符合预期
|
||||
|
||||
4. **批量应用**
|
||||
- 验证通过后,将相同的修改应用到其他目标
|
||||
- 保持一致性和规范性
|
||||
|
||||
5. **最终验证**
|
||||
- 批量修改完成后,运行全局测试
|
||||
- 确保所有修改都正常工作
|
||||
|
||||
### 示例场景
|
||||
|
||||
**场景 1:批量修改多个命令**
|
||||
```
|
||||
用户要求:给所有命令添加错误处理逻辑
|
||||
|
||||
正确做法:
|
||||
1. 选择 1 个命令作为样本(如:最复杂的命令)
|
||||
2. 添加错误处理逻辑
|
||||
3. 测试该命令是否正常工作
|
||||
4. 验证通过后,批量应用到其他命令
|
||||
5. 运行所有命令的测试
|
||||
```
|
||||
|
||||
**场景 2:批量重构代码**
|
||||
```
|
||||
用户要求:重构 10 个相似的函数,改用新的设计模式
|
||||
|
||||
正确做法:
|
||||
1. 选择 1 个函数进行重构
|
||||
2. 编写测试确保功能正确
|
||||
3. Code Review 确认设计合理
|
||||
4. 批量重构其他 9 个函数
|
||||
5. 运行完整的测试套件
|
||||
```
|
||||
|
||||
### 为什么要这样做?
|
||||
|
||||
- **降低风险**:避免一次性批量修改导致大规模错误
|
||||
- **快速发现问题**:在样本阶段就能发现设计或实现上的问题
|
||||
- **提高质量**:样本验证通过后,批量应用的质量更有保障
|
||||
- **节省时间**:虽然看似多一步,但能避免批量回退和重做
|
||||
|
||||
### 例外情况
|
||||
|
||||
以下情况可以跳过样本验证:
|
||||
- 非常简单的修改(如:批量重命名变量)
|
||||
- 已有充分测试覆盖的修改
|
||||
- 用户明确要求直接批量修改
|
||||
|
||||
---
|
||||
|
||||
@@ -119,7 +403,7 @@
|
||||
### 测试要求
|
||||
- **单元测试**:新功能必须包含测试
|
||||
- **集成测试**:API 和跨模块交互需要测试
|
||||
- **目标覆盖率**:>= 80%
|
||||
- **目标覆盖率**:>= 50%
|
||||
- 运行测试:提交前必须本地通过全部测试
|
||||
|
||||
### 构建和类型检查
|
||||
@@ -159,13 +443,6 @@
|
||||
|
||||
## 常见问题和快速参考
|
||||
|
||||
### 如何列出所有可用命令?
|
||||
按下 `ctrl+p` 可查看 OpenCode 的所有可用操作。
|
||||
|
||||
### 如何获取帮助或反馈?
|
||||
- 在 GitHub 提交 issue:https://github.com/anomalyco/opencode
|
||||
- 查看官方文档:https://opencode.ai/docs
|
||||
|
||||
### 何时创建新文件 vs 编辑现有文件?
|
||||
- **优先编辑**:修改现有代码和配置
|
||||
- **仅在必要时创建**:添加全新的功能模块或配置文件
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
---
|
||||
description: Auto-generate commit message, commit and create tag
|
||||
agent: build
|
||||
---
|
||||
|
||||
# auto-commit
|
||||
|
||||
Auto-generate commit message for staged files, commit to local repository.
|
||||
|
||||
## Features
|
||||
|
||||
- **Create tag**: Automatically generate version number and create tag by default
|
||||
- **Skip tag**: Skip creating tag when user inputs "skip" or "skip tag"
|
||||
|
||||
> Version number update is **consistent** with git tag: AI will automatically update version number based on project type and changes, and create tag with the same version number.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Check Staging Area
|
||||
|
||||
Run `git diff --cached --name-only` to check if there are files in staging area.
|
||||
|
||||
**If staging area is empty**:
|
||||
- Output prompt: "No files in staging area, please use `git add` to add files first."
|
||||
- **Terminate command execution**, do not continue
|
||||
|
||||
### 2. Collect Information (Execute in parallel)
|
||||
|
||||
- Run `git status` to view current status
|
||||
- Run `git diff --cached` to view specific changes in staging area
|
||||
- Run `git log --oneline -10` to view recent commit history, understand project's commit style
|
||||
- Run `git tag --list | sort -V | tail -5` to view recent tags
|
||||
- Read `AGENTS.md` file (if exists), understand project type, structure and **version update rules**
|
||||
|
||||
### 3. Detect Repository Type
|
||||
|
||||
**Detect repository type (polyrepo or monorepo)**:
|
||||
|
||||
- Check if `AGENTS.md` file indicates **monorepo**, if `AGENTS.md` doesn't exist or doesn't clearly indicate, default to **polyrepo**
|
||||
|
||||
**If monorepo, analyze change scope**:
|
||||
|
||||
- Based on changed files from step 1, analyze if changes only affect a specific subproject
|
||||
- If only single subproject is affected, record subproject name (e.g., extract `user-service` from path `packages/user-service/src/index.ts`)
|
||||
|
||||
### 4. Detect Project Type and Determine Version Number
|
||||
|
||||
**Prioritize reading version update rules from AGENTS.md**:
|
||||
|
||||
If `AGENTS.md` defines version update rules (such as version file path, version field name, etc.), prioritize using that rule.
|
||||
|
||||
**Auto-detect project type** (when AGENTS.md is not defined):
|
||||
|
||||
AI needs to intelligently identify project type and determine version file, common project types include but not limited to:
|
||||
|
||||
| Project Type | Version File | Version Field/Location |
|
||||
| --- | --- | --- |
|
||||
| iOS | `*.xcodeproj/project.pbxproj` | `MARKETING_VERSION` |
|
||||
| npm/Node.js | `package.json` | `version` |
|
||||
| Android (Groovy) | `app/build.gradle` | `versionName` |
|
||||
| Android (Kotlin DSL) | `app/build.gradle.kts` | `versionName` |
|
||||
| Python (pyproject) | `pyproject.toml` | `[project] version` or `[tool.poetry] version` |
|
||||
| Python (setup) | `setup.py` | `version` parameter |
|
||||
| Rust | `Cargo.toml` | `[package] version` |
|
||||
| Go | Usually only uses git tag | - |
|
||||
| Flutter | `pubspec.yaml` | `version` |
|
||||
| .NET | `*.csproj` | `<Version>` or `<PackageVersion>` |
|
||||
|
||||
> AI should determine project type based on files that actually exist in repository, can check multiple possible version files if necessary.
|
||||
|
||||
**Read current version number**:
|
||||
|
||||
1. Read current version number from identified version file
|
||||
2. Parse as `major.minor.patch`:
|
||||
- If parsing fails or doesn't exist: treat as `0.1.0`
|
||||
- If current version only has `major.minor` format, auto-complete to `major.minor.0`
|
||||
|
||||
**Calculate new version number** (based on change type):
|
||||
|
||||
Version number uses **semantic versioning format**: `0.1.0`, `0.2.0`, ..., `0.9.0`, `1.0.0`, `1.1.0`, `1.1.1`...
|
||||
- **Default starting version**: `0.1.0`
|
||||
- **Increment rules**:
|
||||
- **Major/breaking changes**: `1.2.3` -> `2.0.0` (major +1, minor and patch reset to zero)
|
||||
- **New feature (feat)**: `1.2.3` -> `1.3.0` (minor +1, patch reset to zero)
|
||||
- **Bug fix (fix)**: `1.2.3` -> `1.2.4` (patch +1)
|
||||
|
||||
**Determine if version number update is needed**:
|
||||
|
||||
> Core principle: **Version number reflects "user-perceivable changes"**. Ask yourself: Has the product that users download/use changed?
|
||||
|
||||
**Need to update version number** (packaged into final product, user-perceivable):
|
||||
|
||||
| commit type | version change | description |
|
||||
| --- | --- | --- |
|
||||
| `feat` | minor +1 | new feature |
|
||||
| `fix` | patch +1 | user-perceivable bug fix |
|
||||
| `perf` | patch +1 | performance optimization (user-perceivable improvement) |
|
||||
| breaking change (`!`) | major +1 | API/protocol incompatible changes |
|
||||
|
||||
**No need to update version number** (doesn't affect final product, user-imperceptible):
|
||||
|
||||
| commit type | description | example |
|
||||
| --- | --- | --- |
|
||||
| `chore` | miscellaneous/toolchain | build scripts, CI config, dependency updates |
|
||||
| `ci` | CI/CD config | `.github/workflows/*.yml`, `release.mjs` |
|
||||
| `docs` | documentation | README, comments, API docs |
|
||||
| `test` | test code | unit tests, E2E tests |
|
||||
| `refactor` | refactoring | code reorganization without changing external behavior |
|
||||
| `style` | code style | formatting, spaces, semicolons |
|
||||
| `build` | build config | `tsconfig.json`, `biome.json`, `webpack.config.js` |
|
||||
|
||||
**Judgment tips**:
|
||||
|
||||
1. **Will the file be packaged into final product?**
|
||||
- `scripts/`, `.github/`, `*.config.js` -> No -> Don't update version
|
||||
- `src/`, `lib/`, `app/` -> Yes -> May need to update version
|
||||
|
||||
2. **Does the change only affect developers?**
|
||||
- Dev tool config, CI scripts, build process -> Only affects developers -> Don't update version
|
||||
- Feature code, UI, API -> Affects users -> Update version
|
||||
|
||||
3. **If project type cannot be identified or no version file** -> Only create git tag, don't update version file
|
||||
|
||||
### 5. Generate Commit Message
|
||||
|
||||
Based on changes in staging area, **analyze and generate meaningful commit message by AI**:
|
||||
|
||||
- Analyze changed code content, understand the purpose and intent of this modification
|
||||
- Reference project's commit history style
|
||||
- Use [Conventional Commits](https://www.conventionalcommits.org/) specification
|
||||
- Commit message should concisely but accurately describe "why" rather than just "what"
|
||||
- Common types: `feat` (new feature), `fix` (fix), `docs` (documentation), `refactor` (refactoring), `chore` (miscellaneous), `test` (test), etc.
|
||||
- **Language selection**:
|
||||
- **Default (macOS/Linux)**: Use Chinese (中文) for commit messages
|
||||
- **Windows**: Use English due to encoding issues with Cursor Shell tool
|
||||
- **If monorepo and this commit only affects single subproject, include subproject name in commit message**:
|
||||
- Format: `<type>(<scope>): <description>`, where `<scope>` is subproject name
|
||||
- Example (Chinese): `feat(ios): 支持 OGG Opus 上传` or `fix(electron): 修复剪贴板注入失败`
|
||||
- Example (English): `feat(ios): support OGG Opus upload` or `fix(electron): fix clipboard injection failure`
|
||||
- If affecting multiple subprojects or entire repository, no need to add scope
|
||||
|
||||
### 6. Update Project Version Number
|
||||
|
||||
> Only execute when step 4 determines version number update is needed and version file is identified
|
||||
|
||||
**Execution steps**:
|
||||
|
||||
1. Based on version file and field identified in step 4, update version number to calculated new version
|
||||
2. Add version file to staging area: `git add <version file>`
|
||||
3. **Verify staging area**: Run `git diff --cached --name-only` to confirm version file is in staging area
|
||||
|
||||
### 7. Execute Commit
|
||||
|
||||
Execute commit with generated commit message (staging area now includes user's changes and version number update).
|
||||
|
||||
**Commit message language by platform:**
|
||||
|
||||
**macOS/Linux** (use Chinese commit messages):
|
||||
|
||||
```bash
|
||||
# Single line commit
|
||||
git commit -m "feat(android): 添加新功能"
|
||||
|
||||
# Multi-line commit (recommended)
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat(android): 添加新功能
|
||||
|
||||
- 详细说明 1
|
||||
- 详细说明 2
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
**Windows** (use English commit messages):
|
||||
|
||||
Due to Cursor's Shell tool encoding issues on Windows, **must use English** commit messages.
|
||||
|
||||
```powershell
|
||||
# Single line commit
|
||||
git commit -m "feat(android): add new feature"
|
||||
|
||||
# Multi-line commit (use --message multiple times)
|
||||
git commit --message="fix(android): fix code review issues" --message="- Fix syntax error" --message="- Use JSONObject instead of manual JSON"
|
||||
```
|
||||
|
||||
**Windows prohibited methods** (will cause garbled text):
|
||||
- No Chinese commit messages - Cursor Shell tool encoding error when passing Chinese parameters
|
||||
- No `Out-File -Encoding utf8` - writes UTF-8 with BOM
|
||||
- No Write tool to write temp files - encoding uncontrollable
|
||||
- No PowerShell here-string `@"..."@` - newline parsing issues
|
||||
|
||||
### 8. Create Tag
|
||||
|
||||
> **Executed by default**. Only skip this step when user explicitly inputs "skip" or "skip tag".
|
||||
> Only create tag when step 4 determines version number update is needed (docs/chore types don't create tag).
|
||||
|
||||
**Tag annotation content requirements**:
|
||||
|
||||
- **Use the same content as commit message for tag annotation**
|
||||
- Tag annotation will be used as Release notes by CI/CD scripts, should include detailed change content
|
||||
- If commit message has multiple lines, tag annotation should also be multi-line
|
||||
|
||||
**polyrepo**:
|
||||
```bash
|
||||
git tag -a "<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
|
||||
```
|
||||
|
||||
**monorepo**:
|
||||
```bash
|
||||
git tag -a "<subproject>-<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
|
||||
```
|
||||
|
||||
Examples (single line commit):
|
||||
- polyrepo: `git tag -a "1.2.0" -m "feat: add user authentication"`
|
||||
- monorepo: `git tag -a "android-1.2.0" -m "feat(android): add user authentication"`
|
||||
|
||||
Examples (multi-line commit, more recommended):
|
||||
- polyrepo:
|
||||
```bash
|
||||
git tag -a "1.2.1" -m "fix: resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
|
||||
```
|
||||
- monorepo:
|
||||
```bash
|
||||
git tag -a "android-1.2.1" -m "fix(android): resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Staging area check first**: Must check if staging area has files first, if not, terminate immediately, don't execute any subsequent operations.
|
||||
- **AGENTS.md priority**: If `AGENTS.md` defines version update rules, prioritize using that rule; otherwise AI auto-detects project type.
|
||||
- **Smart detection**: AI should intelligently determine project type and version file location based on files that actually exist in repository.
|
||||
- **Version number and tag consistency**: Project version number and git tag use the same version number, ensure consistency.
|
||||
- **Version number format**: Use `major.minor.patch` semantic versioning format (e.g., `0.1.0`, `1.1.0`, `1.1.1`), default starting `0.1.0`.
|
||||
- **Create tag by default**: Unless user inputs "skip" or "skip tag", create tag by default.
|
||||
- **Update version before commit**: First determine version number and modify version file, then commit at once, avoid using `--amend`.
|
||||
- **Version file must be verified**: After updating version number and `git add`, must run `git diff --cached --name-only` to confirm version file is in staging area before executing commit.
|
||||
- **Commit message language**: Default use Chinese (macOS/Linux); Windows must use English due to Cursor Shell tool encoding issues.
|
||||
- **monorepo scope**: If staging area only affects single subproject, commit message should have scope; if affecting multiple subprojects, no scope needed.
|
||||
- **monorepo tag format**: Use `<subproject>-<version>` format (e.g., `ios-0.1.0`, `android-1.1.0`).
|
||||
- **No version file case**: If project type cannot be identified or no version file (like pure Go project), only create git tag, don't update any files.
|
||||
@@ -1,259 +0,0 @@
|
||||
---
|
||||
description: Auto-generate commit, create tag, and push to remote
|
||||
agent: build
|
||||
---
|
||||
|
||||
# commit-push
|
||||
|
||||
Auto-generate commit message for staged files, commit to local repository, then push to remote repository origin.
|
||||
|
||||
## Features
|
||||
|
||||
- **Create tag**: Automatically generate version number and create tag by default, push to remote
|
||||
- **Skip tag**: Skip creating tag when user inputs "skip" or "skip tag"
|
||||
|
||||
> Version number update is **consistent** with git tag: AI will automatically update version number based on project type and changes, and create tag with the same version number.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Check Staging Area
|
||||
|
||||
Run `git diff --cached --name-only` to check if there are files in staging area.
|
||||
|
||||
**If staging area is empty**:
|
||||
- Output prompt: "No files in staging area, please use `git add` to add files first."
|
||||
- **Terminate command execution**, do not continue
|
||||
|
||||
### 2. Collect Information (Execute in parallel)
|
||||
|
||||
- Run `git status` to view current status
|
||||
- Run `git diff --cached` to view specific changes in staging area
|
||||
- Run `git log --oneline -10` to view recent commit history, understand project's commit style
|
||||
- Run `git tag --list | sort -V | tail -5` to view recent tags
|
||||
- Read `AGENTS.md` file (if exists), understand project type, structure and **version update rules**
|
||||
|
||||
### 3. Detect Repository Type
|
||||
|
||||
**Detect repository type (polyrepo or monorepo)**:
|
||||
|
||||
- Check if `AGENTS.md` file indicates **monorepo**, if `AGENTS.md` doesn't exist or doesn't clearly indicate, default to **polyrepo**
|
||||
|
||||
**If monorepo, analyze change scope**:
|
||||
|
||||
- Based on changed files from step 1, analyze if changes only affect a specific subproject
|
||||
- If only single subproject is affected, record subproject name (e.g., extract `user-service` from path `packages/user-service/src/index.ts`)
|
||||
|
||||
### 4. Detect Project Type and Determine Version Number
|
||||
|
||||
**Prioritize reading version update rules from AGENTS.md**:
|
||||
|
||||
If `AGENTS.md` defines version update rules (such as version file path, version field name, etc.), prioritize using that rule.
|
||||
|
||||
**Auto-detect project type** (when AGENTS.md is not defined):
|
||||
|
||||
AI needs to intelligently identify project type and determine version file, common project types include but not limited to:
|
||||
|
||||
| Project Type | Version File | Version Field/Location |
|
||||
| --- | --- | --- |
|
||||
| iOS | `*.xcodeproj/project.pbxproj` | `MARKETING_VERSION` |
|
||||
| npm/Node.js | `package.json` | `version` |
|
||||
| Android (Groovy) | `app/build.gradle` | `versionName` |
|
||||
| Android (Kotlin DSL) | `app/build.gradle.kts` | `versionName` |
|
||||
| Python (pyproject) | `pyproject.toml` | `[project] version` or `[tool.poetry] version` |
|
||||
| Python (setup) | `setup.py` | `version` parameter |
|
||||
| Rust | `Cargo.toml` | `[package] version` |
|
||||
| Go | Usually only uses git tag | - |
|
||||
| Flutter | `pubspec.yaml` | `version` |
|
||||
| .NET | `*.csproj` | `<Version>` or `<PackageVersion>` |
|
||||
|
||||
> AI should determine project type based on files that actually exist in repository, can check multiple possible version files if necessary.
|
||||
|
||||
**Read current version number**:
|
||||
|
||||
1. Read current version number from identified version file
|
||||
2. Parse as `major.minor.patch`:
|
||||
- If parsing fails or doesn't exist: treat as `0.1.0`
|
||||
- If current version only has `major.minor` format, auto-complete to `major.minor.0`
|
||||
|
||||
**Calculate new version number** (based on change type):
|
||||
|
||||
Version number uses **semantic versioning format**: `0.1.0`, `0.2.0`, ..., `0.9.0`, `1.0.0`, `1.1.0`, `1.1.1`...
|
||||
- **Default starting version**: `0.1.0`
|
||||
- **Increment rules**:
|
||||
- **Major/breaking changes**: `1.2.3` -> `2.0.0` (major +1, minor and patch reset to zero)
|
||||
- **New feature (feat)**: `1.2.3` -> `1.3.0` (minor +1, patch reset to zero)
|
||||
- **Bug fix (fix)**: `1.2.3` -> `1.2.4` (patch +1)
|
||||
|
||||
**Determine if version number update is needed**:
|
||||
|
||||
> Core principle: **Version number reflects "user-perceivable changes"**. Ask yourself: Has the product that users download/use changed?
|
||||
|
||||
**Need to update version number** (packaged into final product, user-perceivable):
|
||||
|
||||
| commit type | version change | description |
|
||||
| --- | --- | --- |
|
||||
| `feat` | minor +1 | new feature |
|
||||
| `fix` | patch +1 | user-perceivable bug fix |
|
||||
| `perf` | patch +1 | performance optimization (user-perceivable improvement) |
|
||||
| breaking change (`!`) | major +1 | API/protocol incompatible changes |
|
||||
|
||||
**No need to update version number** (doesn't affect final product, user-imperceptible):
|
||||
|
||||
| commit type | description | example |
|
||||
| --- | --- | --- |
|
||||
| `chore` | miscellaneous/toolchain | build scripts, CI config, dependency updates |
|
||||
| `ci` | CI/CD config | `.github/workflows/*.yml`, `release.mjs` |
|
||||
| `docs` | documentation | README, comments, API docs |
|
||||
| `test` | test code | unit tests, E2E tests |
|
||||
| `refactor` | refactoring | code reorganization without changing external behavior |
|
||||
| `style` | code style | formatting, spaces, semicolons |
|
||||
| `build` | build config | `tsconfig.json`, `biome.json`, `webpack.config.js` |
|
||||
|
||||
**Judgment tips**:
|
||||
|
||||
1. **Will the file be packaged into final product?**
|
||||
- `scripts/`, `.github/`, `*.config.js` -> No -> Don't update version
|
||||
- `src/`, `lib/`, `app/` -> Yes -> May need to update version
|
||||
|
||||
2. **Does the change only affect developers?**
|
||||
- Dev tool config, CI scripts, build process -> Only affects developers -> Don't update version
|
||||
- Feature code, UI, API -> Affects users -> Update version
|
||||
|
||||
3. **If project type cannot be identified or no version file** -> Only create git tag, don't update version file
|
||||
|
||||
### 5. Generate Commit Message
|
||||
|
||||
Based on changes in staging area, **analyze and generate meaningful commit message by AI**:
|
||||
|
||||
- Analyze changed code content, understand the purpose and intent of this modification
|
||||
- Reference project's commit history style
|
||||
- Use [Conventional Commits](https://www.conventionalcommits.org/) specification
|
||||
- Commit message should concisely but accurately describe "why" rather than just "what"
|
||||
- Common types: `feat` (new feature), `fix` (fix), `docs` (documentation), `refactor` (refactoring), `chore` (miscellaneous), `test` (test), etc.
|
||||
- **Language selection**:
|
||||
- **Default (macOS/Linux)**: Use Chinese (中文) for commit messages
|
||||
- **Windows**: Use English due to encoding issues with Cursor Shell tool
|
||||
- **If monorepo and this commit only affects single subproject, include subproject name in commit message**:
|
||||
- Format: `<type>(<scope>): <description>`, where `<scope>` is subproject name
|
||||
- Example (Chinese): `feat(ios): 支持 OGG Opus 上传` or `fix(electron): 修复剪贴板注入失败`
|
||||
- Example (English): `feat(ios): support OGG Opus upload` or `fix(electron): fix clipboard injection failure`
|
||||
- If affecting multiple subprojects or entire repository, no need to add scope
|
||||
|
||||
### 6. Update Project Version Number
|
||||
|
||||
> Only execute when step 4 determines version number update is needed and version file is identified
|
||||
|
||||
**Execution steps**:
|
||||
|
||||
1. Based on version file and field identified in step 4, update version number to calculated new version
|
||||
2. Add version file to staging area: `git add <version file>`
|
||||
3. **Verify staging area**: Run `git diff --cached --name-only` to confirm version file is in staging area
|
||||
|
||||
### 7. Execute Commit
|
||||
|
||||
Execute commit with generated commit message (staging area now includes user's changes and version number update).
|
||||
|
||||
**Commit message language by platform:**
|
||||
|
||||
**macOS/Linux** (use Chinese commit messages):
|
||||
|
||||
```bash
|
||||
# Single line commit
|
||||
git commit -m "feat(android): 添加新功能"
|
||||
|
||||
# Multi-line commit (recommended)
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat(android): 添加新功能
|
||||
|
||||
- 详细说明 1
|
||||
- 详细说明 2
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
**Windows** (use English commit messages):
|
||||
|
||||
Due to Cursor's Shell tool encoding issues on Windows, **must use English** commit messages.
|
||||
|
||||
```powershell
|
||||
# Single line commit
|
||||
git commit -m "feat(android): add new feature"
|
||||
|
||||
# Multi-line commit (use --message multiple times)
|
||||
git commit --message="fix(android): fix code review issues" --message="- Fix syntax error" --message="- Use JSONObject instead of manual JSON"
|
||||
```
|
||||
|
||||
**Windows prohibited methods** (will cause garbled text):
|
||||
- No Chinese commit messages - Cursor Shell tool encoding error when passing Chinese parameters
|
||||
- No `Out-File -Encoding utf8` - writes UTF-8 with BOM
|
||||
- No Write tool to write temp files - encoding uncontrollable
|
||||
- No PowerShell here-string `@"..."@` - newline parsing issues
|
||||
|
||||
### 8. Create Tag
|
||||
|
||||
> **Executed by default**. Only skip this step when user explicitly inputs "skip" or "skip tag".
|
||||
> Only create tag when step 4 determines version number update is needed (docs/chore types don't create tag).
|
||||
|
||||
**Tag annotation content requirements**:
|
||||
|
||||
- **Use the same content as commit message for tag annotation**
|
||||
- Tag annotation will be used as Release notes by CI/CD scripts, should include detailed change content
|
||||
- If commit message has multiple lines, tag annotation should also be multi-line
|
||||
|
||||
**polyrepo**:
|
||||
```bash
|
||||
git tag -a "<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
|
||||
```
|
||||
|
||||
**monorepo**:
|
||||
```bash
|
||||
git tag -a "<subproject>-<version>" -m "<commit title>" -m "" -m "<commit body line 1>" -m "<commit body line 2>" ...
|
||||
```
|
||||
|
||||
Examples (single line commit):
|
||||
- polyrepo: `git tag -a "1.2.0" -m "feat: add user authentication"`
|
||||
- monorepo: `git tag -a "android-1.2.0" -m "feat(android): add user authentication"`
|
||||
|
||||
Examples (multi-line commit, more recommended):
|
||||
- polyrepo:
|
||||
```bash
|
||||
git tag -a "1.2.1" -m "fix: resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
|
||||
```
|
||||
- monorepo:
|
||||
```bash
|
||||
git tag -a "android-1.2.1" -m "fix(android): resolve bluetooth connection timeout" -m "" -m "- Increase connection timeout to 30s" -m "- Add retry mechanism for failed connections" -m "- Improve error messages"
|
||||
```
|
||||
|
||||
### 9. Push to Remote Repository
|
||||
|
||||
```bash
|
||||
# Push current branch
|
||||
git push origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
**If tag was created, also push tag**:
|
||||
|
||||
**polyrepo**:
|
||||
```bash
|
||||
git push origin <version>
|
||||
```
|
||||
|
||||
**monorepo**:
|
||||
```bash
|
||||
git push origin <subproject>-<version>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Staging area check first**: Must check if staging area has files first, if not, terminate immediately, don't execute any subsequent operations.
|
||||
- **AGENTS.md priority**: If `AGENTS.md` defines version update rules, prioritize using that rule; otherwise AI auto-detects project type.
|
||||
- **Smart detection**: AI should intelligently determine project type and version file location based on files that actually exist in repository.
|
||||
- **Version number and tag consistency**: Project version number and git tag use the same version number, ensure consistency.
|
||||
- **Version number format**: Use `major.minor.patch` semantic versioning format (e.g., `0.1.0`, `1.1.0`, `1.1.1`), default starting `0.1.0`.
|
||||
- **Create tag by default**: Unless user inputs "skip" or "skip tag", create and push tag by default.
|
||||
- **Update version before commit**: First determine version number and modify version file, then commit at once, avoid using `--amend`.
|
||||
- **Version file must be verified**: After updating version number and `git add`, must run `git diff --cached --name-only` to confirm version file is in staging area before executing commit.
|
||||
- **Commit message language**: Default use Chinese (macOS/Linux); Windows must use English due to Cursor Shell tool encoding issues.
|
||||
- **monorepo scope**: If staging area only affects single subproject, commit message should have scope; if affecting multiple subprojects, no scope needed.
|
||||
- **monorepo tag format**: Use `<subproject>-<version>` format (e.g., `ios-0.1.0`, `android-1.1.0`).
|
||||
- **No version file case**: If project type cannot be identified or no version file (like pure Go project), only create git tag, don't update any files.
|
||||
@@ -1,130 +0,0 @@
|
||||
---
|
||||
description: Create a new Git repository on Gitea
|
||||
agent: build
|
||||
---
|
||||
|
||||
# create-gitea-repo
|
||||
|
||||
Create a new Git repository on Gitea.
|
||||
|
||||
## Features
|
||||
|
||||
- Create new repository under specified organization or user via Gitea API
|
||||
- Support creating private or public repositories
|
||||
- Automatically add remote repository address after successful creation
|
||||
|
||||
## User Input Format
|
||||
|
||||
User can specify parameters in the following format:
|
||||
|
||||
```
|
||||
<owner>/<repo> [private|public]
|
||||
```
|
||||
|
||||
- `owner`: Organization name or username (required)
|
||||
- `repo`: Repository name (required)
|
||||
- `private|public`: Visibility (optional, default `private`)
|
||||
|
||||
**Examples**:
|
||||
- `ai/my-project` - Create private repository my-project under ai organization
|
||||
- `ai/my-project public` - Create public repository my-project under ai organization
|
||||
- `voson/test private` - Create private repository test under voson user
|
||||
|
||||
## Configuration
|
||||
|
||||
Use the following configuration when executing command:
|
||||
|
||||
| Config Item | Value |
|
||||
| --- | --- |
|
||||
| Gitea Server URL | `https://git.digitevents.com/` |
|
||||
| API Token | `{env:GITEA_API_TOKEN}` |
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Parse User Input
|
||||
|
||||
Parse from user input:
|
||||
- `owner`: Organization name or username
|
||||
- `repo`: Repository name
|
||||
- `visibility`: `private` (default) or `public`
|
||||
|
||||
**Input validation**:
|
||||
- If user didn't provide `owner/repo` format input, prompt user for correct format and terminate execution
|
||||
- Repository name can only contain letters, numbers, underscores, hyphens and dots
|
||||
|
||||
### 2. Call Gitea API to Create Repository
|
||||
|
||||
Use curl to call Gitea API:
|
||||
|
||||
```bash
|
||||
curl -s -X POST "https://git.digitevents.com/api/v1/orgs/<owner>/repos" \
|
||||
-H "Authorization: token $GITEA_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "<repo>",
|
||||
"private": <true|false>
|
||||
}'
|
||||
```
|
||||
|
||||
> Note: If owner is personal user instead of organization, API path should be `/api/v1/user/repos`, but usually try organization API first.
|
||||
|
||||
### 3. Handle Response
|
||||
|
||||
**Success** (HTTP 201):
|
||||
- Extract repository info from response:
|
||||
- `html_url`: Repository web URL
|
||||
- `clone_url`: HTTPS clone URL
|
||||
- `ssh_url`: SSH clone URL
|
||||
- Output creation success message
|
||||
|
||||
**Failure**:
|
||||
- If 404 error, owner may not exist or no permission
|
||||
- If 409 error, repository already exists
|
||||
- Output error message and terminate
|
||||
|
||||
### 4. Ask Whether to Add Remote Repository
|
||||
|
||||
Ask user whether to add the newly created repository as current project's remote repository.
|
||||
|
||||
**If user confirms**:
|
||||
|
||||
1. Check if current directory is a Git repository:
|
||||
```bash
|
||||
git rev-parse --is-inside-work-tree
|
||||
```
|
||||
|
||||
2. If not a Git repository, ask whether to initialize:
|
||||
```bash
|
||||
git init
|
||||
```
|
||||
|
||||
3. Check if origin remote already exists:
|
||||
```bash
|
||||
git remote get-url origin
|
||||
```
|
||||
|
||||
4. Add or update remote repository:
|
||||
- If no origin: `git remote add origin <clone_url>`
|
||||
- If origin exists: Ask whether to overwrite, after confirmation execute `git remote set-url origin <clone_url>`
|
||||
|
||||
### 5. Output Result Summary
|
||||
|
||||
Output creation result summary table:
|
||||
|
||||
```
|
||||
Repository created successfully!
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Repository Name | owner/repo |
|
||||
| Web URL | https://git.digitevents.com/owner/repo |
|
||||
| Clone URL (HTTPS) | https://git.digitevents.com/owner/repo.git |
|
||||
| Clone URL (SSH) | git@git.digitevents.com:owner/repo.git |
|
||||
| Private | Yes/No |
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Permission check**: Ensure Token has permission to create repository
|
||||
- **Organization vs User**: Creating organization repository and user repository use different API endpoints
|
||||
- **Repository naming**: Follow Gitea naming rules, avoid special characters
|
||||
321
command/git-add.md
Normal file
321
command/git-add.md
Normal file
@@ -0,0 +1,321 @@
|
||||
---
|
||||
description: Stage changes with automatic filtering of sensitive files
|
||||
---
|
||||
|
||||
# git-add
|
||||
|
||||
Intelligently stage changes while automatically filtering security-sensitive files.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Detects all unstaged changes
|
||||
- Automatically excludes common sensitive files (credentials, secrets, etc.)
|
||||
- Previews files that will be staged
|
||||
- Asks for confirmation before staging
|
||||
- Shows excluded sensitive files for awareness
|
||||
|
||||
## Quick Start
|
||||
|
||||
Use this command when you want to safely stage changes without accidentally committing sensitive information.
|
||||
|
||||
## Sensitive Files Filtered
|
||||
|
||||
**Always excluded:**
|
||||
- `.env*` - Environment files
|
||||
- `*.key`, `*.pem`, `*.p8` - Private keys
|
||||
- `.aws/*`, `.gcloud/*` - Cloud credentials
|
||||
- `.ssh/*` - SSH keys
|
||||
- `credentials.json`, `secrets.json` - Credential files
|
||||
- `package-lock.json`, `yarn.lock` (optional, can override)
|
||||
- `node_modules/`, `vendor/`, `.venv/` - Dependencies
|
||||
- `dist/`, `build/`, `.next/` - Build artifacts
|
||||
- `.DS_Store`, `Thumbs.db` - System files
|
||||
|
||||
**Custom exclusions:**
|
||||
- Can be specified in project `.gitignore` or `.secretsignore`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Detect All Unstaged Changes
|
||||
|
||||
```bash
|
||||
git status --porcelain
|
||||
git diff --name-only
|
||||
```
|
||||
|
||||
Categories:
|
||||
- Modified files (M)
|
||||
- Deleted files (D)
|
||||
- Untracked files (??) - **重要:第一次就显示并提供选项**
|
||||
|
||||
### 2. Filter Sensitive Files
|
||||
|
||||
Build exclusion list:
|
||||
- Read `.gitignore` for patterns
|
||||
- Read `.secretsignore` if exists (project-specific rules)
|
||||
- Apply built-in security patterns
|
||||
- Check for `.env*`, `*.key`, `credentials.json`, etc.
|
||||
|
||||
Separate files into:
|
||||
- **Modified/Deleted files (tracked)**: 已跟踪的修改和删除
|
||||
- **Untracked files (safe)**: 未跟踪但安全的新文件
|
||||
- **Sensitive files**: 敏感文件(需要 force 才能暂存)
|
||||
|
||||
**关键逻辑:**
|
||||
- 默认选项 (y): 只暂存已跟踪的修改/删除
|
||||
- all/u 选项: 暂存所有安全文件(包括未跟踪)
|
||||
- force 选项: 暂存所有文件(包括敏感)
|
||||
- 一次性显示所有选项,不需要二次运行命令
|
||||
|
||||
### 3. Display Preview
|
||||
|
||||
Show clear summary in format:
|
||||
|
||||
```
|
||||
=== 将要暂存的文件 (3) ===
|
||||
M src/index.js
|
||||
M src/utils.js
|
||||
D old-file.js
|
||||
|
||||
=== 未跟踪的文件 (2) ===
|
||||
?? new-feature.js
|
||||
?? tests/new-test.js
|
||||
|
||||
=== 敏感文件已过滤 (2) ===
|
||||
⚠ .env.local (Environment file)
|
||||
⚠ config/secrets.json (Credential file)
|
||||
|
||||
=== 操作选项 ===
|
||||
- 输入 "y" 或 "yes" 暂存已修改/已删除的文件(不包括未跟踪文件)
|
||||
- 输入 "all" 暂存所有文件(包括未跟踪文件,但排除敏感文件)
|
||||
- 输入 "with-untracked" 或 "u" 暂存所有文件(包括未跟踪文件)
|
||||
- 输入 "force" 强制暂存所有文件(包括敏感文件,谨慎使用)
|
||||
- 输入 "no" 或 "cancel" 取消操作
|
||||
- 输入文件路径 暂存特定文件
|
||||
```
|
||||
|
||||
### 4. User Confirmation
|
||||
|
||||
Prompt user:
|
||||
```
|
||||
是否确认暂存上述文件? (y/all/u/no)
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `y` or `yes`: Stage modified/deleted files only (exclude untracked)
|
||||
- `all` or `with-untracked` or `u`: Stage all including untracked files (exclude sensitive)
|
||||
- `force`: Stage everything including sensitive files (show warning)
|
||||
- `no` or `cancel`: Abort
|
||||
- File path: Stage only specific file(s)
|
||||
|
||||
**智能提示:**
|
||||
- 如果没有未跟踪文件,只显示 y/no 选项
|
||||
- 如果有未跟踪文件,显示 y/all/u/no 选项,并高亮推荐使用 "all" 或 "u"
|
||||
- 如果有敏感文件,额外显示 force 选项并警告风险
|
||||
|
||||
### 5. Execute Staging
|
||||
|
||||
If user confirms:
|
||||
|
||||
```bash
|
||||
# Option 1: Stage modified/deleted only (y)
|
||||
git add <modified-file-1> <modified-file-2> ...
|
||||
|
||||
# Option 2: Stage all including untracked (all/u)
|
||||
git add <all-safe-files-including-untracked>
|
||||
|
||||
# Option 3: Stage everything including sensitive (force)
|
||||
git add .
|
||||
```
|
||||
|
||||
**Warning for "force" option:**
|
||||
```
|
||||
⚠️ 警告:你选择暂存所有文件,包括敏感文件!
|
||||
请确认这是有意的,避免意外提交凭证或密钥。
|
||||
|
||||
已暂存的敏感文件:
|
||||
- .env.local
|
||||
- config/secrets.json
|
||||
|
||||
输入 "confirm" 继续,或 "cancel" 取消操作
|
||||
```
|
||||
|
||||
**Success message for "all/u" option:**
|
||||
```
|
||||
✓ 已暂存所有文件(包括未跟踪文件)
|
||||
|
||||
已暂存 5 个文件:
|
||||
M src/index.js
|
||||
M src/utils.js
|
||||
D old-file.js
|
||||
A new-feature.js
|
||||
A tests/new-test.js
|
||||
|
||||
敏感文件已自动过滤并排除。
|
||||
```
|
||||
|
||||
### 6. Display Result
|
||||
|
||||
Show success message in Chinese:
|
||||
|
||||
```
|
||||
✓ 暂存成功
|
||||
|
||||
已暂存 3 个文件:
|
||||
M src/index.js
|
||||
M src/utils.js
|
||||
A command/git-add.md
|
||||
|
||||
敏感文件已过滤并排除,保护了你的凭证信息。
|
||||
|
||||
下一步:
|
||||
- 运行 /git-commit 生成提交信息并提交
|
||||
- 运行 /git-status 查看暂存区状态
|
||||
```
|
||||
|
||||
## Safety Features
|
||||
|
||||
### Automatic Filters
|
||||
|
||||
| Pattern | Why | Can Override |
|
||||
|---------|-----|--------------|
|
||||
| `.env*` | Environment variables | No |
|
||||
| `*.key`, `*.pem` | Private keys | No |
|
||||
| `credentials.json` | API credentials | No |
|
||||
| `secrets.json` | Secrets | No |
|
||||
| `.aws/*`, `.gcloud/*` | Cloud credentials | No |
|
||||
| `.ssh/*` | SSH keys | No |
|
||||
| `package-lock.json` | Lock files (optional) | Yes |
|
||||
|
||||
### Warnings
|
||||
|
||||
- Show count of filtered files
|
||||
- List filtered file names for transparency
|
||||
- Warn when using "all" option
|
||||
- Explain why each sensitive file was excluded
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Stage changes safely before commit
|
||||
- Prevent accidental credential leaks
|
||||
- Review what will be committed before staging
|
||||
- Follow security best practices
|
||||
|
||||
## Related Commands
|
||||
|
||||
- `/git-status` - Check file changes before staging
|
||||
- `/git-commit` - Commit staged files
|
||||
- `/git-push` - Push commits to remote
|
||||
|
||||
## Examples
|
||||
|
||||
### Normal Usage (无未跟踪文件)
|
||||
```bash
|
||||
/git-add
|
||||
# 显示:3 个已修改文件
|
||||
# 提示:是否确认暂存? (y/no)
|
||||
# 输入 "y" 暂存所有已修改文件
|
||||
```
|
||||
|
||||
### 包含未跟踪文件的情况
|
||||
```bash
|
||||
/git-add
|
||||
# 显示:
|
||||
# - 3 个已修改/已删除文件
|
||||
# - 2 个未跟踪文件
|
||||
# 提示:是否确认暂存? (y/all/u/no)
|
||||
# 输入 "y" 仅暂存已修改文件
|
||||
# 输入 "all" 或 "u" 暂存所有文件(包括未跟踪)
|
||||
```
|
||||
|
||||
### 强制暂存敏感文件
|
||||
```bash
|
||||
/git-add
|
||||
# 显示:包含 2 个敏感文件
|
||||
# 提示:是否确认暂存? (y/all/force/no)
|
||||
# 输入 "force" 强制暂存所有文件
|
||||
# ⚠️ 显示二次确认警告
|
||||
```
|
||||
|
||||
### 暂存特定文件
|
||||
```bash
|
||||
/git-add
|
||||
# 显示预览
|
||||
# 输入文件路径:src/index.js
|
||||
# 仅暂存指定的文件
|
||||
```
|
||||
|
||||
### 取消操作
|
||||
```bash
|
||||
/git-add
|
||||
# 显示预览
|
||||
# 输入 "no" 或 "cancel"
|
||||
# 操作中止
|
||||
```
|
||||
|
||||
## Implementation Guide
|
||||
|
||||
### 关键实现要点
|
||||
|
||||
**1. 文件分类逻辑**
|
||||
```bash
|
||||
# 获取所有状态
|
||||
git status --porcelain
|
||||
|
||||
# 分类处理
|
||||
tracked_modified=() # M 状态
|
||||
tracked_deleted=() # D 状态
|
||||
untracked_safe=() # ?? 状态且非敏感
|
||||
untracked_sensitive=() # ?? 状态且敏感
|
||||
tracked_sensitive=() # M/D 状态但匹配敏感规则
|
||||
```
|
||||
|
||||
**2. 选项显示逻辑**
|
||||
```python
|
||||
if has_untracked_files:
|
||||
if has_sensitive_files:
|
||||
prompt = "是否确认暂存? (y/all/force/no)"
|
||||
options = {
|
||||
"y": "仅暂存已跟踪的修改/删除",
|
||||
"all/u": "暂存所有安全文件(含未跟踪)",
|
||||
"force": "暂存所有文件(含敏感)⚠️",
|
||||
"no": "取消操作"
|
||||
}
|
||||
else:
|
||||
prompt = "是否确认暂存? (y/all/no)"
|
||||
options = {
|
||||
"y": "仅暂存已跟踪的修改/删除",
|
||||
"all/u": "暂存所有文件(含未跟踪)✓ 推荐",
|
||||
"no": "取消操作"
|
||||
}
|
||||
else:
|
||||
prompt = "是否确认暂存? (y/no)"
|
||||
```
|
||||
|
||||
**3. 执行逻辑**
|
||||
```bash
|
||||
case $choice in
|
||||
y|yes)
|
||||
git add "${tracked_modified[@]}" "${tracked_deleted[@]}"
|
||||
;;
|
||||
all|u|with-untracked)
|
||||
git add "${tracked_modified[@]}" "${tracked_deleted[@]}" "${untracked_safe[@]}"
|
||||
;;
|
||||
force)
|
||||
# 二次确认
|
||||
read -p "⚠️ 确认暂存敏感文件? (输入 confirm): " confirm
|
||||
if [[ "$confirm" == "confirm" ]]; then
|
||||
git add .
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- This command prioritizes security over convenience
|
||||
- Sensitive files must be explicitly forced to stage
|
||||
- **重要:第一次运行就显示所有选项,不需要用户多次运行命令**
|
||||
- Untracked files are displayed upfront with clear options
|
||||
- Use `.secretsignore` file for project-specific exclusion patterns
|
||||
- Consider setting up git hooks for additional security
|
||||
189
command/git-commit.md
Normal file
189
command/git-commit.md
Normal file
@@ -0,0 +1,189 @@
|
||||
---
|
||||
description: Commit staged files with auto-generated message and create version tag
|
||||
---
|
||||
|
||||
# git-commit
|
||||
|
||||
Auto-generate commit message for staged files, commit to local repository, and create version tag.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Analyzes staged changes
|
||||
- Auto-generates meaningful commit message following Conventional Commits
|
||||
- Detects project type and updates version number if needed
|
||||
- Creates appropriate git tag (polyrepo or monorepo format)
|
||||
- Does NOT push to remote (local only)
|
||||
|
||||
## Quick Start
|
||||
|
||||
Use this command when you have files in staging area and want to commit with proper version tagging.
|
||||
|
||||
## Workflow
|
||||
|
||||
This command follows the git workflow defined in `skill/git/SKILL.md`:
|
||||
|
||||
1. ✓ Check staging area (must have files)
|
||||
2. ✓ Analyze changes and repository type
|
||||
3. ✓ Detect project type and version file
|
||||
4. ✓ Generate commit message (Conventional Commits)
|
||||
5. ✓ Update version number if needed
|
||||
6. ✓ Commit with generated message
|
||||
7. ✓ Create version tag
|
||||
8. ✗ Skip push (use `/git-push` to push)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
**Staging area must not be empty:**
|
||||
```bash
|
||||
git add <files>
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
User can optionally input:
|
||||
- **"skip tag"** or **"skip"**: Skip tag creation, only commit
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Check Staging Area
|
||||
|
||||
```bash
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
**If empty:**
|
||||
- Display: "暂存区为空,请先使用 `git add` 添加文件。"
|
||||
- **Terminate execution**
|
||||
|
||||
### 2. Collect Information (parallel)
|
||||
|
||||
```bash
|
||||
git status
|
||||
git diff --cached
|
||||
git log --oneline -10
|
||||
git tag --list | sort -V | tail -5
|
||||
```
|
||||
|
||||
If `AGENTS.md` exists, read it for:
|
||||
- Repository type (polyrepo/monorepo)
|
||||
- Version update rules
|
||||
- Project structure
|
||||
|
||||
### 3. Detect Repository Type
|
||||
|
||||
- **Polyrepo**: Single project, tag format `1.2.0`
|
||||
- **Monorepo**: Multiple subprojects, tag format `<subproject>-1.2.0`
|
||||
|
||||
Detection:
|
||||
- Check `AGENTS.md` for monorepo indicator
|
||||
- Check directory structure (`packages/`, `apps/`, etc.)
|
||||
- Analyze changed file paths for subproject scope
|
||||
|
||||
### 4. Detect Project Type and Version
|
||||
|
||||
Follow `skill/git/SKILL.md` guidelines:
|
||||
|
||||
**Common project types:**
|
||||
- iOS: `*.xcodeproj/project.pbxproj` → `MARKETING_VERSION`
|
||||
- Node.js: `package.json` → `version`
|
||||
- Android: `build.gradle(.kts)` → `versionName`
|
||||
- Go: Git tag only (no version file)
|
||||
- etc.
|
||||
|
||||
**Version increment rules:**
|
||||
- `feat`: minor +1 → `1.2.0` → `1.3.0`
|
||||
- `fix`: patch +1 → `1.2.3` → `1.2.4`
|
||||
- `perf`: patch +1
|
||||
- Breaking change: major +1 → `1.2.3` → `2.0.0`
|
||||
|
||||
**Only update version for user-perceivable changes:**
|
||||
- ✓ feat, fix, perf, breaking changes
|
||||
- ✗ docs, test, refactor, style, chore, ci, build
|
||||
|
||||
### 5. Generate Commit Message
|
||||
|
||||
Follow Conventional Commits specification:
|
||||
|
||||
**Format:**
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
```
|
||||
|
||||
**Commit language:**
|
||||
- macOS/Linux: Chinese (中文)
|
||||
- Windows: English (encoding issue)
|
||||
|
||||
**Monorepo scope:**
|
||||
- If changes affect single subproject: `feat(ios): 添加新功能`
|
||||
- If multiple subprojects: `feat: 添加新功能`
|
||||
|
||||
### 6. Update Version Number
|
||||
|
||||
If version update is needed:
|
||||
|
||||
1. Update version file with new version
|
||||
2. Add version file to staging: `git add <version-file>`
|
||||
3. Verify: `git diff --cached --name-only`
|
||||
|
||||
### 7. Commit Changes
|
||||
|
||||
```bash
|
||||
# macOS/Linux (Chinese)
|
||||
git commit -m "feat(android): 添加用户认证"
|
||||
|
||||
# Windows (English)
|
||||
git commit -m "feat(android): add user authentication"
|
||||
|
||||
# Multi-line (macOS/Linux)
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat: add user authentication
|
||||
|
||||
- Add OAuth2 support
|
||||
- Implement JWT tokens
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
### 8. Create Tag
|
||||
|
||||
**Only if:**
|
||||
- Version update occurred
|
||||
- User didn't input "skip tag"
|
||||
|
||||
**Tag format:**
|
||||
- Polyrepo: `git tag -a "1.2.0" -m "feat: add feature"`
|
||||
- Monorepo: `git tag -a "ios-1.2.0" -m "feat(ios): add feature"`
|
||||
|
||||
**Tag annotation:**
|
||||
- Use same content as commit message
|
||||
- Multi-line commits → multi-line annotations
|
||||
|
||||
### 9. Display Result
|
||||
|
||||
Show summary in Chinese:
|
||||
```
|
||||
✓ 提交成功
|
||||
|
||||
提交信息:feat(android): 添加用户认证
|
||||
版本标签:android-1.3.0
|
||||
|
||||
要推送到远程仓库,请运行:/git-push
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Commit staged changes with proper versioning
|
||||
- Create local version tag for release preparation
|
||||
- Follow semantic versioning automatically
|
||||
|
||||
## Related Commands
|
||||
|
||||
- `/git-status` - Check file changes before commit
|
||||
- `/git-push` - Push commits and tags to remote
|
||||
- `/git-push-tags` - Push tags only
|
||||
|
||||
## Reference
|
||||
|
||||
Complete workflow documentation: `skill/git/SKILL.md`
|
||||
85
command/git-pull.md
Normal file
85
command/git-pull.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
description: Pull latest changes from remote repository
|
||||
---
|
||||
|
||||
# git-pull
|
||||
|
||||
Pull latest changes from remote repository for current branch.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Fetches latest changes from remote
|
||||
- Merges remote changes into local branch
|
||||
- Updates working directory
|
||||
|
||||
## Quick Start
|
||||
|
||||
Use this command to synchronize your local branch with the latest remote changes.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Execute Pull
|
||||
|
||||
```bash
|
||||
git pull
|
||||
```
|
||||
|
||||
This command will:
|
||||
- Fetch updates from remote repository
|
||||
- Automatically merge changes into current branch
|
||||
- Update your working directory
|
||||
|
||||
### 2. Handle Conflicts (if any)
|
||||
|
||||
If merge conflicts occur:
|
||||
- Git will mark conflicting files
|
||||
- Resolve conflicts manually
|
||||
- Stage resolved files: `git add <file>`
|
||||
- Complete merge: `git commit`
|
||||
|
||||
Or use: `/git-status` to check conflict status
|
||||
|
||||
### 3. Display Result
|
||||
|
||||
Show result message:
|
||||
|
||||
```
|
||||
✓ 拉取成功
|
||||
|
||||
分支已更新至最新状态。
|
||||
```
|
||||
|
||||
Or if conflicts:
|
||||
|
||||
```
|
||||
⚠️ 发生合并冲突
|
||||
|
||||
请解决以下文件中的冲突:
|
||||
- src/index.js
|
||||
- README.md
|
||||
|
||||
然后运行:
|
||||
git add <file>
|
||||
git commit
|
||||
|
||||
或使用 /git-status 查看详细状态
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Sync local branch with remote updates
|
||||
- Get latest changes from team
|
||||
- Before starting new feature work
|
||||
- Before pushing your changes
|
||||
|
||||
## Related Commands
|
||||
|
||||
- `/git-status` - Check file changes and merge status
|
||||
- `/git-push` - Push local changes to remote
|
||||
- `/git-commit` - Commit local changes
|
||||
|
||||
## Notes
|
||||
|
||||
- Pulls from tracking remote branch (usually origin/main)
|
||||
- Uses default merge strategy (recursive merge)
|
||||
- If conflicts occur, resolve them before committing
|
||||
91
command/git-push-tags.md
Normal file
91
command/git-push-tags.md
Normal file
@@ -0,0 +1,91 @@
|
||||
---
|
||||
description: Push all local tags to remote repository
|
||||
---
|
||||
|
||||
# git-push-tags
|
||||
|
||||
Push all local tags to the remote repository.
|
||||
|
||||
## What It Does
|
||||
|
||||
1. Lists all local tags
|
||||
2. Shows which tags are not yet on remote
|
||||
3. Pushes all tags to remote (origin)
|
||||
4. Confirms successful push
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. List Local Tags
|
||||
|
||||
```bash
|
||||
echo "=== Local Tags ==="
|
||||
git tag --list | sort -V
|
||||
```
|
||||
|
||||
### 2. Check Remote Tags
|
||||
|
||||
```bash
|
||||
echo "=== Remote Tags ==="
|
||||
git ls-remote --tags origin | awk '{print $2}' | sed 's|refs/tags/||' | sort -V
|
||||
```
|
||||
|
||||
### 3. Identify Unpushed Tags
|
||||
|
||||
Compare local and remote tags to identify which tags need to be pushed.
|
||||
|
||||
### 4. Confirm Before Push
|
||||
|
||||
Display summary in Chinese:
|
||||
```
|
||||
本地标签总数:15 个
|
||||
远程标签总数:12 个
|
||||
待推送标签:3 个
|
||||
- 1.3.0
|
||||
- 1.3.1
|
||||
- ios-2.0.0
|
||||
|
||||
确认推送所有标签到 origin?
|
||||
```
|
||||
|
||||
If user confirms or no confirmation needed, proceed to push.
|
||||
|
||||
### 5. Push All Tags
|
||||
|
||||
```bash
|
||||
git push --tags
|
||||
# or
|
||||
git push origin --tags
|
||||
```
|
||||
|
||||
### 6. Verify Push
|
||||
|
||||
```bash
|
||||
echo "=== Push Result ==="
|
||||
git ls-remote --tags origin | tail -5
|
||||
```
|
||||
|
||||
Display confirmation in Chinese:
|
||||
```
|
||||
✓ 已成功推送所有标签到 origin
|
||||
|
||||
最近 5 个远程标签:
|
||||
- 1.3.0
|
||||
- 1.3.1
|
||||
- ios-2.0.0
|
||||
- android-1.5.0
|
||||
- electron-3.0.0
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
- After creating multiple local tags
|
||||
- Sync tags with remote repository
|
||||
- Before triggering CI/CD release workflows
|
||||
- Share version tags with team
|
||||
|
||||
## Notes
|
||||
|
||||
- **Safe operation**: Pushing tags does not affect commits
|
||||
- **No force push**: Uses standard push, won't overwrite existing tags
|
||||
- **All tags**: Pushes ALL local tags, not just one
|
||||
- If you only want to push a specific tag, use: `git push origin <tag-name>`
|
||||
190
command/git-push.md
Normal file
190
command/git-push.md
Normal file
@@ -0,0 +1,190 @@
|
||||
---
|
||||
description: Commit staged files, create version tag, and push to remote repository
|
||||
---
|
||||
|
||||
# git-push
|
||||
|
||||
Complete workflow: auto-generate commit message, create version tag, and push everything to remote repository.
|
||||
|
||||
## What It Does
|
||||
|
||||
This is the **all-in-one command** that:
|
||||
1. ✓ Analyzes and commits staged changes (like `/git-commit`)
|
||||
2. ✓ Creates version tag if needed
|
||||
3. ✓ Pushes commit to remote repository
|
||||
4. ✓ Pushes tag to remote repository
|
||||
|
||||
## Quick Start
|
||||
|
||||
Use this command when you want to commit AND push in one step.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
**Staging area must have files:**
|
||||
```bash
|
||||
git add <files>
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
User can optionally input:
|
||||
- **"skip tag"** or **"skip"**: Skip tag creation, only commit and push
|
||||
|
||||
## Workflow
|
||||
|
||||
This command combines `/git-commit` + push operations:
|
||||
|
||||
1. ✓ Check staging area
|
||||
2. ✓ Analyze changes and repository type
|
||||
3. ✓ Detect project type and version
|
||||
4. ✓ Generate commit message
|
||||
5. ✓ Update version number if needed
|
||||
6. ✓ Commit with generated message
|
||||
7. ✓ Create version tag
|
||||
8. ✓ Push commit to remote
|
||||
9. ✓ Push tag to remote
|
||||
|
||||
## Steps
|
||||
|
||||
### 1-8. Commit and Tag
|
||||
|
||||
Execute the same steps as `/git-commit`:
|
||||
- Check staging area (must not be empty)
|
||||
- Collect information (status, diff, logs, tags, AGENTS.md)
|
||||
- Detect repository type (polyrepo/monorepo)
|
||||
- Detect project type and version file
|
||||
- Generate commit message (Conventional Commits, Chinese/English)
|
||||
- Update version number if needed
|
||||
- Commit changes
|
||||
- Create tag if needed
|
||||
|
||||
Refer to `/git-commit` for detailed steps or see `skill/git/SKILL.md`.
|
||||
|
||||
### 9. Push Commit to Remote
|
||||
|
||||
```bash
|
||||
# Push current branch to origin
|
||||
git push origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
### 10. Push Tag to Remote
|
||||
|
||||
**Only if tag was created:**
|
||||
|
||||
**Polyrepo:**
|
||||
```bash
|
||||
git push origin <version>
|
||||
# Example: git push origin 1.2.0
|
||||
```
|
||||
|
||||
**Monorepo:**
|
||||
```bash
|
||||
git push origin <subproject>-<version>
|
||||
# Example: git push origin ios-1.2.0
|
||||
```
|
||||
|
||||
### 11. Display Result
|
||||
|
||||
Show summary in Chinese:
|
||||
```
|
||||
✓ 提交并推送成功
|
||||
|
||||
分支:main
|
||||
提交信息:feat(android): 添加用户认证
|
||||
版本标签:android-1.3.0
|
||||
|
||||
已推送到远程仓库:origin
|
||||
- 提交:a1b2c3d
|
||||
- 标签:android-1.3.0
|
||||
```
|
||||
|
||||
## Comparison with Other Commands
|
||||
|
||||
| Command | Commit | Tag | Push Commit | Push Tag |
|
||||
|---------|--------|-----|-------------|----------|
|
||||
| `/git-commit` | ✓ | ✓ | ✗ | ✗ |
|
||||
| `/git-push` | ✓ | ✓ | ✓ | ✓ |
|
||||
| `/git-push-tags` | ✗ | ✗ | ✗ | ✓ (all tags) |
|
||||
|
||||
## Use Cases
|
||||
|
||||
- **Quick workflow**: Commit and push in one command
|
||||
- **Release preparation**: Create version tag and push for CI/CD
|
||||
- **Daily development**: Commit and sync with remote immediately
|
||||
|
||||
## When to Use Which Command
|
||||
|
||||
**Use `/git-commit`** (local only):
|
||||
- You want to review before pushing
|
||||
- Working on feature branch not ready to share
|
||||
- Creating multiple commits before one push
|
||||
|
||||
**Use `/git-push`** (commit + push):
|
||||
- Ready to share changes immediately
|
||||
- Main branch development with CI/CD
|
||||
- Quick fixes that should be synced now
|
||||
|
||||
**Use `/git-push-tags`** (tags only):
|
||||
- Already committed but forgot to push tags
|
||||
- Want to push multiple accumulated tags at once
|
||||
- Tag-only sync without new commits
|
||||
|
||||
## Error Handling
|
||||
|
||||
### If Staging Area is Empty
|
||||
|
||||
```
|
||||
暂存区为空,请先使用 `git add` 添加文件。
|
||||
```
|
||||
**Action:** Terminate, user must stage files first.
|
||||
|
||||
### If Push Fails
|
||||
|
||||
Common reasons:
|
||||
- Remote branch protection
|
||||
- Need to pull first (diverged history)
|
||||
- No permission to push
|
||||
|
||||
**Action:** Display error in Chinese, suggest solutions:
|
||||
```
|
||||
✗ 推送失败
|
||||
|
||||
原因:远程分支有更新,需要先拉取
|
||||
|
||||
建议操作:
|
||||
1. git pull --rebase origin main
|
||||
2. 解决冲突(如有)
|
||||
3. 重新运行 /git-push
|
||||
```
|
||||
|
||||
### If Remote Rejects Tag
|
||||
|
||||
If tag already exists on remote:
|
||||
```
|
||||
✗ 标签推送失败
|
||||
|
||||
原因:远程仓库已存在标签 1.2.0
|
||||
|
||||
建议操作:
|
||||
1. 删除本地标签:git tag -d 1.2.0
|
||||
2. 更新版本号后重新提交
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Main branch**: Default push target is `main` (not `master`)
|
||||
- **Conventional Commits**: Auto-generated messages follow standard format
|
||||
- **Semantic Versioning**: Automatic version bumping based on change type
|
||||
- **Polyrepo/Monorepo**: Automatically detects and uses correct tag format
|
||||
- **Platform-specific**: Commit messages in Chinese (macOS/Linux) or English (Windows)
|
||||
|
||||
## Related Commands
|
||||
|
||||
- `/git-status` - Check changes before committing
|
||||
- `/git-commit` - Commit locally without pushing
|
||||
- `/git-push-tags` - Push only tags (no commits)
|
||||
|
||||
## Reference
|
||||
|
||||
Complete git workflow guide: `skill/git/SKILL.md`
|
||||
Quick command reference: `skill/git/quick-reference.md`
|
||||
54
command/git-status.md
Normal file
54
command/git-status.md
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
description: Check git working directory status and file changes
|
||||
---
|
||||
|
||||
# git-status
|
||||
|
||||
Check current git repository status and display file changes in a clear format.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Shows current branch
|
||||
- Lists changed files (unstaged and staged)
|
||||
|
||||
## Steps
|
||||
|
||||
Execute the following commands in parallel:
|
||||
|
||||
```bash
|
||||
# Current branch
|
||||
git branch --show-current
|
||||
|
||||
# Repository status
|
||||
git status
|
||||
|
||||
# List changed files only
|
||||
echo "=== Unstaged Changes ==="
|
||||
git diff --name-only
|
||||
|
||||
echo "=== Staged Changes ==="
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
Present the information in Chinese with clear sections:
|
||||
|
||||
```
|
||||
当前分支:main
|
||||
|
||||
未暂存的文件 (3):
|
||||
- src/index.js
|
||||
- src/utils.js
|
||||
- README.md
|
||||
|
||||
已暂存的文件 (2):
|
||||
- package.json
|
||||
- src/config.js
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Quick status check before committing
|
||||
- Review what files have changed
|
||||
- Check if you're on the correct branch
|
||||
168
command/gitea-config.md
Normal file
168
command/gitea-config.md
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
description: View current Gitea configuration and runner status
|
||||
---
|
||||
|
||||
# gitea-config
|
||||
|
||||
查看当前 Gitea 配置信息和 Runner 状态。
|
||||
|
||||
## Features
|
||||
|
||||
- 显示配置的 Gitea URL
|
||||
- 显示默认组织
|
||||
- 验证 Token 状态和关联用户
|
||||
- 显示已配置的 Runner 数量和列表
|
||||
- 显示配置文件路径
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Check Configuration File
|
||||
|
||||
```bash
|
||||
config_dir="$HOME/.config/gitea"
|
||||
config_file="$config_dir/config.env"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Gitea 未配置"
|
||||
echo "请运行 /gitea-reset 进行配置"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Load and Display Configuration
|
||||
|
||||
```bash
|
||||
source "$config_file"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "当前 Gitea 配置"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " URL: $GITEA_URL"
|
||||
echo " 默认组织: ${GITEA_DEFAULT_ORG:-<未设置>}"
|
||||
echo " 配置文件: $config_file"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 3. Validate Token and Display User Info
|
||||
|
||||
```bash
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/user")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [ "$http_code" = "200" ]; then
|
||||
username=$(echo "$body" | jq -r '.login')
|
||||
email=$(echo "$body" | jq -r '.email // "<未设置>"')
|
||||
echo " Token 状态: ✓ 有效"
|
||||
echo " 登录用户: $username"
|
||||
echo " 邮箱: $email"
|
||||
else
|
||||
echo " Token 状态: ✗ 无效或已过期"
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. Display Runner Information
|
||||
|
||||
```bash
|
||||
runners_dir="$config_dir/runners"
|
||||
|
||||
if [ -d "$runners_dir" ]; then
|
||||
runner_count=$(ls -1 "$runners_dir" 2>/dev/null | wc -l | tr -d ' ')
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Runner 信息"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 已配置 Runner 数量: $runner_count"
|
||||
echo " Runner 目录: $runners_dir"
|
||||
|
||||
if [ "$runner_count" -gt 0 ]; then
|
||||
echo ""
|
||||
echo " 已配置的 Runners:"
|
||||
ls -1 "$runners_dir" | while read runner; do
|
||||
# Check if running
|
||||
config_file="$runners_dir/$runner/config.yaml"
|
||||
if [ -f "$config_file" ]; then
|
||||
if pgrep -f "act_runner daemon --config $config_file" > /dev/null; then
|
||||
status="🟢"
|
||||
else
|
||||
status="🔴"
|
||||
fi
|
||||
echo " $status $runner"
|
||||
else
|
||||
echo " ⚠️ $runner (配置文件缺失)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Runner 信息"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 未配置任何 Runner"
|
||||
fi
|
||||
```
|
||||
|
||||
### 5. Display Management Commands
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "管理命令"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 重置配置: /gitea-reset"
|
||||
echo " 切换组织: /gitea-switch-org <org-name>"
|
||||
echo " 列出 Runners: /gitea-list-runners"
|
||||
echo " 创建仓库: /create-gitea-repo <repo-name>"
|
||||
echo ""
|
||||
```
|
||||
|
||||
## Output Example
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
当前 Gitea 配置
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
URL: https://git.digitevents.com
|
||||
默认组织: ai
|
||||
配置文件: /Users/voson/.config/gitea/config.env
|
||||
|
||||
Token 状态: ✓ 有效
|
||||
登录用户: your_username
|
||||
邮箱: your_username@example.com
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Runner 信息
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
已配置 Runner 数量: 2
|
||||
Runner 目录: /Users/voson/.config/gitea/runners
|
||||
|
||||
已配置的 Runners:
|
||||
🟢 runner-macbook-pro
|
||||
🔴 runner-mac-mini
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
管理命令
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
重置配置: /gitea-reset
|
||||
切换组织: /gitea-switch-org <org-name>
|
||||
列出 Runners: /gitea-list-runners
|
||||
创建仓库: /create-gitea-repo <repo-name>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- 使用 `jq` 解析 JSON 响应
|
||||
- 检查 runner 进程使用 `pgrep`
|
||||
- Token 验证通过调用 `/api/v1/user` endpoint
|
||||
- Runner 状态:🟢 运行中、🔴 已停止、⚠️ 配置异常
|
||||
256
command/gitea-create-repo.md
Normal file
256
command/gitea-create-repo.md
Normal file
@@ -0,0 +1,256 @@
|
||||
---
|
||||
description: Create a new Git repository on Gitea
|
||||
---
|
||||
|
||||
# gitea-create-repo
|
||||
|
||||
Create a new Git repository on Gitea.
|
||||
|
||||
## Features
|
||||
|
||||
- Create new repository under specified organization or user via Gitea API
|
||||
- Support creating private or public repositories
|
||||
- Automatically add remote repository address after successful creation
|
||||
|
||||
## User Input Format
|
||||
|
||||
User can specify parameters in the following format:
|
||||
|
||||
```
|
||||
[<owner>/]<repo> [private|public]
|
||||
```
|
||||
|
||||
- `owner`: Organization name or username (optional, uses `GITEA_DEFAULT_ORG` if set, otherwise uses current user)
|
||||
- `repo`: Repository name (required)
|
||||
- `private|public`: Visibility (optional, default `private`)
|
||||
|
||||
**Examples**:
|
||||
- `my-project` - Create private repository under default organization (or current user if not set)
|
||||
- `ai/my-project` - Create private repository my-project under ai organization
|
||||
- `ai/my-project public` - Create public repository my-project under ai organization
|
||||
- `username/test private` - Create private repository test under username user
|
||||
|
||||
## Configuration
|
||||
|
||||
Load configuration from `~/.config/gitea/config.env`:
|
||||
|
||||
| Config Item | Source |
|
||||
| --- | --- |
|
||||
| Gitea Server URL | `GITEA_URL` from config.env |
|
||||
| API Token | `GITEA_TOKEN` from config.env |
|
||||
| Default Organization | `GITEA_DEFAULT_ORG` from config.env (optional) |
|
||||
|
||||
## Steps
|
||||
|
||||
### 0. Load Configuration
|
||||
|
||||
Before executing, load Gitea configuration:
|
||||
|
||||
```bash
|
||||
config_file="$HOME/.config/gitea/config.env"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Gitea 未配置,请运行 /gitea-reset 进行初始化"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$config_file"
|
||||
|
||||
# Validate required variables
|
||||
if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
|
||||
echo "❌ 配置文件不完整,请运行 /gitea-reset 重新配置"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 1. Parse User Input
|
||||
|
||||
Parse from user input:
|
||||
- `owner`: Organization name or username
|
||||
- `repo`: Repository name
|
||||
- `visibility`: `private` (default) or `public`
|
||||
|
||||
**Input parsing logic**:
|
||||
|
||||
```bash
|
||||
input="$1"
|
||||
visibility="${2:-private}"
|
||||
|
||||
# Parse owner/repo
|
||||
if [[ "$input" =~ / ]]; then
|
||||
owner=$(echo "$input" | cut -d'/' -f1)
|
||||
repo=$(echo "$input" | cut -d'/' -f2)
|
||||
else
|
||||
# Use default organization if available, otherwise use current user
|
||||
if [ -z "$GITEA_DEFAULT_ORG" ]; then
|
||||
# Get current user from Gitea API
|
||||
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
|
||||
|
||||
# Convert visibility to boolean
|
||||
private_bool=$([ "$visibility" = "private" ] && echo "true" || echo "false")
|
||||
```
|
||||
|
||||
**Input validation**:
|
||||
- Repository name can only contain letters, numbers, underscores, hyphens and dots
|
||||
|
||||
```bash
|
||||
if ! [[ "$repo" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
|
||||
echo "❌ 仓库名只能包含字母、数字、下划线、连字符和点"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Call Gitea API to Create Repository
|
||||
|
||||
Use curl to call Gitea API with configuration:
|
||||
|
||||
```bash
|
||||
echo "正在创建仓库: $owner/$repo ($visibility)"
|
||||
|
||||
# Try organization repository first
|
||||
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')
|
||||
|
||||
# If 404, try user repository
|
||||
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},
|
||||
\"auto_init\": false,
|
||||
\"default_branch\": \"main\"
|
||||
}" \
|
||||
"${GITEA_URL}/api/v1/user/repos")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
fi
|
||||
```
|
||||
|
||||
> Note: First try organization API, if 404 then try user API.
|
||||
|
||||
### 3. Handle Response
|
||||
|
||||
```bash
|
||||
case "$http_code" in
|
||||
201)
|
||||
echo "✓ 仓库创建成功"
|
||||
;;
|
||||
409)
|
||||
echo "❌ 仓库已存在: $owner/$repo"
|
||||
echo "查看仓库: ${GITEA_URL}/$owner/$repo"
|
||||
exit 1
|
||||
;;
|
||||
404)
|
||||
echo "❌ Owner 不存在或无权限: $owner"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "❌ 创建失败 (HTTP $http_code)"
|
||||
echo "$body" | jq -r '.message // empty'
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Extract repository info
|
||||
html_url=$(echo "$body" | jq -r '.html_url')
|
||||
clone_url=$(echo "$body" | jq -r '.clone_url')
|
||||
ssh_url=$(echo "$body" | jq -r '.ssh_url')
|
||||
```
|
||||
|
||||
**Response Handling**:
|
||||
- **HTTP 201**: Repository created successfully
|
||||
- **HTTP 409**: Repository already exists
|
||||
- **HTTP 404**: Owner does not exist or no permission
|
||||
- **Other**: API error, display error message
|
||||
|
||||
### 4. Ask Whether to Add Remote Repository
|
||||
|
||||
Ask user whether to add the newly created repository as current project's remote repository.
|
||||
|
||||
**If user confirms**:
|
||||
|
||||
1. Check if current directory is a Git repository:
|
||||
```bash
|
||||
git rev-parse --is-inside-work-tree
|
||||
```
|
||||
|
||||
2. If not a Git repository, ask whether to initialize:
|
||||
```bash
|
||||
git init
|
||||
```
|
||||
|
||||
3. Check if origin remote already exists:
|
||||
```bash
|
||||
git remote get-url origin
|
||||
```
|
||||
|
||||
4. Add or update remote repository:
|
||||
- If no origin: `git remote add origin <clone_url>`
|
||||
- If origin exists: Ask whether to overwrite, after confirmation execute `git remote set-url origin <clone_url>`
|
||||
|
||||
### 5. Output Result Summary
|
||||
|
||||
Output creation result summary:
|
||||
|
||||
```bash
|
||||
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 ""
|
||||
```
|
||||
|
||||
**Example Output**:
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
仓库创建成功
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
名称: ai/my-project
|
||||
可见性: private
|
||||
Web URL: https://git.digitevents.com/ai/my-project
|
||||
HTTPS URL: https://git.digitevents.com/ai/my-project.git
|
||||
SSH URL: git@git.digitevents.com:ai/my-project.git
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Permission check**: Ensure Token has permission to create repository
|
||||
- **Organization vs User**: Creating organization repository and user repository use different API endpoints
|
||||
- **Repository naming**: Follow Gitea naming rules, avoid special characters
|
||||
662
command/gitea-create-runner.md
Normal file
662
command/gitea-create-runner.md
Normal file
@@ -0,0 +1,662 @@
|
||||
---
|
||||
description: Create and start a Gitea Actions runner (default host mode)
|
||||
---
|
||||
|
||||
# gitea-create-runner
|
||||
|
||||
创建并启动 Gitea Actions Runner(默认 host 模式)。
|
||||
|
||||
## 命令说明
|
||||
|
||||
此命令用于快速创建和启动一个 Gitea Actions Runner。默认使用 host 模式,自动检测系统环境并配置。
|
||||
|
||||
**重要**:这是一个可执行命令,AI 应该按照以下步骤执行操作。
|
||||
|
||||
## Features
|
||||
|
||||
- 自动检查并安装 act_runner(如果未安装)
|
||||
- 自动加载 Gitea 配置(如果不存在则提示初始化)
|
||||
- 默认使用 host 模式(支持 Android SDK、iOS 构建等原生工具)
|
||||
- 智能检测系统环境(OS、架构)并生成合适的 labels
|
||||
- 自动注册并后台启动 runner
|
||||
- 优先尝试创建全局 runner(需要管理员权限)
|
||||
- 权限不足时自动降级到组织 runner
|
||||
|
||||
## User Input Format
|
||||
|
||||
无需参数,运行后自动创建。可选提供 runner 名称。
|
||||
|
||||
```bash
|
||||
/gitea-create-runner
|
||||
# 或
|
||||
/gitea-create-runner my-runner-name
|
||||
```
|
||||
|
||||
## AI 执行指导
|
||||
|
||||
当用户调用此命令时,AI 应该:
|
||||
|
||||
1. **检查 act_runner 安装**:如果未安装,自动安装
|
||||
2. **加载 Gitea 配置**:如果不存在,提示用户先初始化
|
||||
3. **生成 runner 名称**:基于主机名或用户输入
|
||||
4. **检测系统环境**:自动生成 labels
|
||||
5. **创建 runner 目录**:在 `~/.config/gitea/runners/` 下创建
|
||||
6. **生成配置文件**:默认 host 模式配置
|
||||
7. **获取注册 token**:优先全局,失败则降级到组织
|
||||
8. **注册 runner**:使用 act_runner register
|
||||
9. **启动 runner**:后台启动并显示状态
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### 1. Check act_runner Installation
|
||||
|
||||
**AI 执行**:检查 act_runner 是否已安装,如果没有则自动安装。
|
||||
|
||||
```bash
|
||||
echo "检查 act_runner 安装状态..."
|
||||
|
||||
if command -v act_runner &> /dev/null; then
|
||||
version=$(act_runner --version 2>&1 | head -n1)
|
||||
echo "✓ act_runner 已安装: $version"
|
||||
else
|
||||
echo "⚠️ act_runner 未安装"
|
||||
echo "正在使用 Homebrew 安装..."
|
||||
|
||||
if ! command -v brew &> /dev/null; then
|
||||
echo "❌ 需要先安装 Homebrew"
|
||||
echo " 安装命令: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
brew install act_runner
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
version=$(act_runner --version 2>&1 | head -n1)
|
||||
echo "✓ act_runner 安装成功: $version"
|
||||
else
|
||||
echo "❌ act_runner 安装失败"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 2. Load Gitea Configuration
|
||||
|
||||
**AI 执行**:加载 Gitea 配置,如果不存在则提示初始化。
|
||||
|
||||
```bash
|
||||
config_file="$HOME/.config/gitea/config.env"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Gitea 配置不存在"
|
||||
echo ""
|
||||
echo "请先初始化 Gitea 配置:"
|
||||
echo " /gitea-reset"
|
||||
echo ""
|
||||
echo "或使用以下命令查看配置:"
|
||||
echo " /gitea-config"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$config_file"
|
||||
|
||||
if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
|
||||
echo "❌ Gitea 配置不完整"
|
||||
echo " 需要 GITEA_URL 和 GITEA_TOKEN"
|
||||
echo ""
|
||||
echo "请重新初始化配置:"
|
||||
echo " /gitea-reset"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 已加载 Gitea 配置"
|
||||
echo " URL: $GITEA_URL"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 3. Generate Runner Name
|
||||
|
||||
**AI 执行**:生成 runner 名称(基于主机名或用户输入)。
|
||||
|
||||
```bash
|
||||
# Check if runner name provided as argument
|
||||
# 如果用户提供了名称参数,使用该参数;否则基于主机名生成
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
runner_name="$1"
|
||||
echo "使用指定的 Runner 名称: $runner_name"
|
||||
else
|
||||
hostname=$(hostname -s 2>/dev/null || echo "unknown")
|
||||
runner_name="runner-$hostname"
|
||||
echo "生成 Runner 名称: $runner_name"
|
||||
echo " (基于主机名: $hostname)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Validate runner name
|
||||
if [[ ! "$runner_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
||||
echo "❌ Runner 名称只能包含字母、数字、下划线和连字符"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. Check Runner Existence
|
||||
|
||||
**AI 执行**:检查 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_dir"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " 1. 使用其他名称: /gitea-create-runner <新名称>"
|
||||
echo " 2. 删除现有 runner: /gitea-delete-runner"
|
||||
echo " 3. 查看所有 runners: /gitea-list-runners"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 5. Detect System Environment
|
||||
|
||||
**AI 执行**:智能检测系统环境并生成 labels。
|
||||
|
||||
```bash
|
||||
echo "检测系统环境..."
|
||||
|
||||
# Detect OS
|
||||
OS=$(uname -s)
|
||||
case "$OS" in
|
||||
Darwin) os_label="macOS" ;;
|
||||
Linux) os_label="ubuntu" ;;
|
||||
*) os_label="unknown" ;;
|
||||
esac
|
||||
|
||||
# Detect architecture
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
arm64|aarch64) arch_label="ARM64" ;;
|
||||
x86_64) arch_label="x64" ;;
|
||||
*) arch_label="unknown" ;;
|
||||
esac
|
||||
|
||||
# Generate combined label
|
||||
combined=$(echo "${OS}-${ARCH}" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Generate labels for host mode
|
||||
labels="self-hosted:host,${os_label}:host,${arch_label}:host,${combined}:host"
|
||||
|
||||
echo "✓ 系统信息"
|
||||
echo " 操作系统: $OS ($os_label)"
|
||||
echo " 架构: $ARCH ($arch_label)"
|
||||
echo " 组合标签: $combined"
|
||||
echo ""
|
||||
echo "✓ Runner Labels (Host Mode)"
|
||||
echo " $labels"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 6. Create Runner Directory
|
||||
|
||||
**AI 执行**:创建 runner 目录结构。
|
||||
|
||||
```bash
|
||||
echo "创建 Runner 目录..."
|
||||
|
||||
mkdir -p "$runner_dir"/{cache,workspace}
|
||||
|
||||
if [ ! -d "$runner_dir" ]; then
|
||||
echo "❌ 创建目录失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 目录创建成功"
|
||||
echo " 路径: $runner_dir"
|
||||
echo " - cache/"
|
||||
echo " - workspace/"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 7. Generate Configuration File
|
||||
|
||||
**AI 执行**:生成 host 模式配置文件。
|
||||
|
||||
```bash
|
||||
echo "生成配置文件..."
|
||||
|
||||
# Get environment-specific settings (with defaults)
|
||||
runner_capacity="${GITEA_RUNNER_CAPACITY:-2}"
|
||||
runner_timeout="${GITEA_RUNNER_TIMEOUT:-3h}"
|
||||
|
||||
# Generate config.yaml for host mode
|
||||
cat > "$runner_dir/config.yaml" << EOF
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: $runner_dir/.runner
|
||||
capacity: $runner_capacity
|
||||
timeout: $runner_timeout
|
||||
shutdown_timeout: 30s
|
||||
insecure: false
|
||||
fetch_timeout: 5s
|
||||
fetch_interval: 2s
|
||||
labels:
|
||||
- "self-hosted:host"
|
||||
- "${os_label}:host"
|
||||
- "${arch_label}:host"
|
||||
- "${combined}:host"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "$runner_dir/cache"
|
||||
host: "127.0.0.1"
|
||||
port: 9000
|
||||
|
||||
host:
|
||||
workdir_parent: "$runner_dir/workspace"
|
||||
EOF
|
||||
|
||||
if [ ! -f "$runner_dir/config.yaml" ]; then
|
||||
echo "❌ 配置文件生成失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 配置文件已生成"
|
||||
echo " 文件: $runner_dir/config.yaml"
|
||||
echo " 模式: Host Mode (原生执行)"
|
||||
echo " 容量: $runner_capacity 并发任务"
|
||||
echo " 超时: $runner_timeout"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 8. Get Registration Token
|
||||
|
||||
**AI 执行**:获取注册 token(优先全局,失败则降级到组织)。
|
||||
|
||||
```bash
|
||||
echo "获取 Runner 注册 Token..."
|
||||
echo ""
|
||||
|
||||
# Try global runner first (requires admin token)
|
||||
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')
|
||||
|
||||
# Check for admin permission
|
||||
if [ "$http_code" = "200" ]; then
|
||||
echo "✓ 使用全局 Runner"
|
||||
runner_level="global"
|
||||
registration_token=$(echo "$body" | jq -r '.token')
|
||||
else
|
||||
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"
|
||||
echo "使用默认组织: $org_name"
|
||||
else
|
||||
echo "❌ 未配置默认组织"
|
||||
echo " 请在配置文件中设置 GITEA_DEFAULT_ORG"
|
||||
echo " 或重新初始化配置: /gitea-reset"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
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')
|
||||
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "❌ 获取注册 Token 失败 (HTTP $http_code)"
|
||||
echo " 响应: $body"
|
||||
echo ""
|
||||
echo "可能的原因:"
|
||||
echo " 1. 组织不存在"
|
||||
echo " 2. Token 没有组织管理权限"
|
||||
echo " 3. 网络连接问题"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
registration_token=$(echo "$body" | jq -r '.token')
|
||||
echo "✓ 组织 Runner Token 已获取"
|
||||
fi
|
||||
|
||||
if [ -z "$registration_token" ] || [ "$registration_token" = "null" ]; then
|
||||
echo "❌ 无法解析注册 Token"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 注册 Token 已准备"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 9. Register Runner
|
||||
|
||||
**AI 执行**:注册 runner 到 Gitea 服务器。
|
||||
|
||||
```bash
|
||||
echo "注册 Runner 到 Gitea 服务器..."
|
||||
|
||||
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 注册失败"
|
||||
echo ""
|
||||
echo "请检查:"
|
||||
echo " 1. Token 是否有效"
|
||||
echo " 2. Gitea 服务器是否可访问"
|
||||
echo " 3. 配置文件是否正确"
|
||||
echo ""
|
||||
echo "查看详细错误,可以手动运行:"
|
||||
echo " act_runner register --config $runner_dir/config.yaml --instance $GITEA_URL --token <token> --name $runner_name --labels \"$labels\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify .runner file was created
|
||||
if [ ! -f "$runner_dir/.runner" ]; then
|
||||
echo "⚠️ 注册文件未创建,但注册可能成功"
|
||||
echo " 请检查: $runner_dir/.runner"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 10. Start Runner
|
||||
|
||||
**AI 执行**:后台启动 runner 并验证状态。
|
||||
|
||||
```bash
|
||||
echo "启动 Runner..."
|
||||
|
||||
# Start runner in background
|
||||
nohup act_runner daemon --config "$runner_dir/config.yaml" \
|
||||
> "$runner_dir/runner.log" 2>&1 &
|
||||
|
||||
runner_pid=$!
|
||||
|
||||
echo " 进程已启动 (PID: $runner_pid)"
|
||||
|
||||
# Wait for runner to initialize
|
||||
echo " 等待初始化..."
|
||||
sleep 3
|
||||
|
||||
# Check if process is still running
|
||||
if ps -p $runner_pid > /dev/null 2>&1; then
|
||||
echo "✓ Runner 运行中"
|
||||
else
|
||||
echo "❌ Runner 启动失败"
|
||||
echo ""
|
||||
echo "查看日志以诊断问题:"
|
||||
echo " tail -n 50 $runner_dir/runner.log"
|
||||
echo ""
|
||||
tail -n 20 "$runner_dir/runner.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 11. Display Summary
|
||||
|
||||
**AI 执行**:显示创建结果和管理命令。
|
||||
|
||||
```bash
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ Runner 创建完成!"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Runner 信息:"
|
||||
echo " 名称: $runner_name"
|
||||
echo " 级别: $runner_level"
|
||||
if [ "$runner_level" = "organization" ]; then
|
||||
echo " 组织: $org_name"
|
||||
fi
|
||||
echo " 模式: Host Mode (原生执行)"
|
||||
echo " 状态: 🟢 运行中"
|
||||
echo " PID: $runner_pid"
|
||||
echo ""
|
||||
echo "配置:"
|
||||
echo " 容量: $runner_capacity 并发任务"
|
||||
echo " 超时: $runner_timeout"
|
||||
echo " Labels: $labels"
|
||||
echo ""
|
||||
echo "目录:"
|
||||
echo " 配置文件: $runner_dir/config.yaml"
|
||||
echo " 注册信息: $runner_dir/.runner"
|
||||
echo " 工作目录: $runner_dir/workspace"
|
||||
echo " 缓存目录: $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"
|
||||
echo ""
|
||||
echo "使用 Runner:"
|
||||
echo " 在 workflow 中使用以下任一 runs-on 值:"
|
||||
echo " - runs-on: $combined"
|
||||
echo " - runs-on: $os_label"
|
||||
echo " - runs-on: [self-hosted, $os_label, $arch_label]"
|
||||
echo ""
|
||||
```
|
||||
|
||||
## Output Example
|
||||
|
||||
### Example 1: Successful Creation (Global Runner)
|
||||
|
||||
```
|
||||
检查 act_runner 安装状态...
|
||||
✓ act_runner 已安装: act_runner version 0.2.13
|
||||
|
||||
✓ 已加载 Gitea 配置
|
||||
URL: https://git.digitevents.com
|
||||
|
||||
生成 Runner 名称: runner-macbook-pro
|
||||
(基于主机名: macbook-pro)
|
||||
|
||||
检测系统环境...
|
||||
✓ 系统信息
|
||||
操作系统: Darwin (macOS)
|
||||
架构: arm64 (ARM64)
|
||||
组合标签: darwin-arm64
|
||||
|
||||
✓ Runner Labels (Host Mode)
|
||||
self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
|
||||
|
||||
创建 Runner 目录...
|
||||
✓ 目录创建成功
|
||||
路径: /Users/voson/.config/gitea/runners/runner-macbook-pro
|
||||
- cache/
|
||||
- workspace/
|
||||
|
||||
生成配置文件...
|
||||
✓ 配置文件已生成
|
||||
文件: /Users/voson/.config/gitea/runners/runner-macbook-pro/config.yaml
|
||||
模式: Host Mode (原生执行)
|
||||
容量: 2 并发任务
|
||||
超时: 3h
|
||||
|
||||
获取 Runner 注册 Token...
|
||||
|
||||
尝试创建全局 Runner(可用于所有组织和仓库)...
|
||||
✓ 使用全局 Runner
|
||||
✓ 注册 Token 已准备
|
||||
|
||||
注册 Runner 到 Gitea 服务器...
|
||||
✓ Runner 注册成功
|
||||
|
||||
启动 Runner...
|
||||
进程已启动 (PID: 12345)
|
||||
等待初始化...
|
||||
✓ Runner 运行中
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
✅ Runner 创建完成!
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Runner 信息:
|
||||
名称: runner-macbook-pro
|
||||
级别: global
|
||||
模式: Host Mode (原生执行)
|
||||
状态: 🟢 运行中
|
||||
PID: 12345
|
||||
|
||||
配置:
|
||||
容量: 2 并发任务
|
||||
超时: 3h
|
||||
Labels: self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
|
||||
|
||||
目录:
|
||||
配置文件: /Users/voson/.config/gitea/runners/runner-macbook-pro/config.yaml
|
||||
注册信息: /Users/voson/.config/gitea/runners/runner-macbook-pro/.runner
|
||||
工作目录: /Users/voson/.config/gitea/runners/runner-macbook-pro/workspace
|
||||
缓存目录: /Users/voson/.config/gitea/runners/runner-macbook-pro/cache
|
||||
日志文件: /Users/voson/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
|
||||
管理命令:
|
||||
查看日志: tail -f /Users/voson/.config/gitea/runners/runner-macbook-pro/runner.log
|
||||
停止 Runner: pkill -f 'act_runner daemon --config.*runner-macbook-pro'
|
||||
查看所有: /gitea-list-runners
|
||||
删除 Runner: /gitea-delete-runner
|
||||
|
||||
使用 Runner:
|
||||
在 workflow 中使用以下任一 runs-on 值:
|
||||
- runs-on: darwin-arm64
|
||||
- runs-on: macOS
|
||||
- runs-on: [self-hosted, macOS, ARM64]
|
||||
```
|
||||
|
||||
### Example 2: Auto-install act_runner
|
||||
|
||||
```
|
||||
检查 act_runner 安装状态...
|
||||
⚠️ act_runner 未安装
|
||||
正在使用 Homebrew 安装...
|
||||
==> Downloading act_runner...
|
||||
==> Installing act_runner...
|
||||
✓ act_runner 安装成功: act_runner version 0.2.13
|
||||
|
||||
[继续后续步骤...]
|
||||
```
|
||||
|
||||
### Example 3: Downgrade to Organization Runner
|
||||
|
||||
```
|
||||
获取 Runner 注册 Token...
|
||||
|
||||
尝试创建全局 Runner(可用于所有组织和仓库)...
|
||||
⚠️ 全局 Runner 权限不足 (HTTP 403)
|
||||
全局 Runner 需要管理员 Token
|
||||
|
||||
降级到组织 Runner...
|
||||
使用默认组织: ai
|
||||
✓ 组织 Runner Token 已获取
|
||||
✓ 注册 Token 已准备
|
||||
|
||||
[继续后续步骤...]
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
✅ Runner 创建完成!
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Runner 信息:
|
||||
名称: runner-macbook-pro
|
||||
级别: organization
|
||||
组织: ai
|
||||
模式: Host Mode (原生执行)
|
||||
[...]
|
||||
```
|
||||
|
||||
### Example 4: Configuration Not Found
|
||||
|
||||
```
|
||||
检查 act_runner 安装状态...
|
||||
✓ act_runner 已安装: act_runner version 0.2.13
|
||||
|
||||
❌ Gitea 配置不存在
|
||||
|
||||
请先初始化 Gitea 配置:
|
||||
/gitea-reset
|
||||
|
||||
或使用以下命令查看配置:
|
||||
/gitea-config
|
||||
```
|
||||
|
||||
### Example 5: Runner Already Exists
|
||||
|
||||
```
|
||||
[前置检查...]
|
||||
|
||||
生成 Runner 名称: runner-macbook-pro
|
||||
(基于主机名: macbook-pro)
|
||||
|
||||
❌ Runner 'runner-macbook-pro' 已存在
|
||||
路径: /Users/voson/.config/gitea/runners/runner-macbook-pro
|
||||
|
||||
选项:
|
||||
1. 使用其他名称: /gitea-create-runner <新名称>
|
||||
2. 删除现有 runner: /gitea-delete-runner
|
||||
3. 查看所有 runners: /gitea-list-runners
|
||||
```
|
||||
|
||||
## Technical Notes
|
||||
|
||||
- **默认模式**:Host Mode(支持 Android SDK、iOS 等原生工具)
|
||||
- **自动安装**:使用 Homebrew 安装 act_runner
|
||||
- **智能检测**:自动检测 OS 和架构,生成合适的 labels
|
||||
- **优雅降级**:全局 runner 权限不足时自动降级到组织 runner
|
||||
- **后台运行**:自动后台启动,日志记录到文件
|
||||
- **配置环境变量**:
|
||||
- `GITEA_RUNNER_CAPACITY`: 并发任务数(默认 2)
|
||||
- `GITEA_RUNNER_TIMEOUT`: 任务超时时间(默认 3h)
|
||||
- **目录权限**:自动创建,权限继承用户默认权限
|
||||
- **进程管理**:使用 nohup 后台运行,支持系统重启后手动重启
|
||||
|
||||
## Related Commands
|
||||
|
||||
- `/gitea-config`: 查看 Gitea 配置
|
||||
- `/gitea-reset`: 重置/初始化 Gitea 配置
|
||||
- `/gitea-list-runners`: 列出所有 runners
|
||||
- `/gitea-delete-runner`: 删除指定 runner
|
||||
- `/create-gitea-repo`: 创建 Gitea 仓库
|
||||
|
||||
## Safety Features
|
||||
|
||||
- **配置验证**:检查必需的配置项
|
||||
- **目录冲突检测**:避免覆盖现有 runner
|
||||
- **启动验证**:等待并验证进程启动成功
|
||||
- **错误提示**:清晰的错误信息和解决方案
|
||||
- **日志记录**:所有输出记录到日志文件
|
||||
|
||||
## Version
|
||||
|
||||
- **Command Version**: 1.0
|
||||
- **Last Updated**: 2026-01-12
|
||||
- **Compatible with**: act_runner 0.2.13+, macOS/Linux
|
||||
595
command/gitea-delete-runner.md
Normal file
595
command/gitea-delete-runner.md
Normal file
@@ -0,0 +1,595 @@
|
||||
---
|
||||
description: Delete a Gitea runner configuration (interactive)
|
||||
---
|
||||
|
||||
# gitea-delete-runner
|
||||
|
||||
删除 Gitea Runner 配置(交互式选择)。
|
||||
|
||||
## 命令说明
|
||||
|
||||
此命令用于从 Gitea 服务器删除 runner 配置。支持交互式选择单个或所有 runners。
|
||||
|
||||
**重要**:这是一个可执行命令,AI 应该按照以下步骤执行操作,并与用户进行交互。
|
||||
|
||||
## Features
|
||||
|
||||
- 显示 Gitea 服务器上的全局 runners
|
||||
- 交互式选择要删除的 runner
|
||||
- 支持删除单个或所有 runners
|
||||
- 删除 runner 配置目录(包括 cache 和 workspace)
|
||||
- 停止运行中的 runner 进程
|
||||
- 自动从 Gitea 服务器注销 runner
|
||||
- 安全确认机制(需要用户输入 'yes')
|
||||
|
||||
## User Input Format
|
||||
|
||||
无需参数,运行后交互式选择。
|
||||
|
||||
```bash
|
||||
/gitea-delete-runner
|
||||
```
|
||||
|
||||
## AI 执行指导
|
||||
|
||||
当用户调用此命令时,AI 应该:
|
||||
|
||||
1. **获取并展示 runner 列表**:调用 Gitea API 获取服务器上的全局 runners,并以清晰的格式展示给用户
|
||||
2. **等待用户选择**:让用户选择要删除的 runner(序号、'all' 或 'q')
|
||||
3. **确认操作**:在删除前要求用户输入 'yes' 确认
|
||||
4. **执行删除**:按照三步流程删除选中的 runners
|
||||
5. **显示结果**:展示删除操作的详细结果
|
||||
|
||||
**注意**:此命令需要与用户进行多次交互,不要一次性执行所有步骤。
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### 1. Load Configuration
|
||||
|
||||
```bash
|
||||
config_file_main="$HOME/.config/gitea/config.env"
|
||||
|
||||
if [ ! -f "$config_file_main" ]; then
|
||||
echo "❌ 未找到 Gitea 配置文件"
|
||||
echo " 路径: $config_file_main"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$config_file_main"
|
||||
|
||||
if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
|
||||
echo "❌ Gitea 配置不完整"
|
||||
echo " 需要 GITEA_URL 和 GITEA_TOKEN"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Fetch and Display Runners
|
||||
|
||||
**AI 执行**:运行以下命令获取并显示 runners 列表,然后等待用户选择。
|
||||
|
||||
```bash
|
||||
source "$HOME/.config/gitea/config.env"
|
||||
|
||||
echo "正在从 Gitea 服务器获取全局 runners..."
|
||||
echo ""
|
||||
|
||||
# Fetch global runners from Gitea API
|
||||
api_endpoint="${GITEA_URL}/api/v1/admin/actions/runners"
|
||||
response=$(curl -s -H "Authorization: token $GITEA_TOKEN" "$api_endpoint")
|
||||
|
||||
if [ $? -ne 0 ] || [ -z "$response" ]; then
|
||||
echo "❌ 无法连接到 Gitea 服务器"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse runners using jq
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "❌ 需要安装 jq 工具"
|
||||
echo " 安装: brew install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if response is valid JSON
|
||||
if ! echo "$response" | jq empty 2>/dev/null; then
|
||||
echo "❌ API 返回数据格式错误"
|
||||
echo " 请检查 Token 权限(需要 admin 权限)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract runner information (注意:API 返回格式是 {"runners": [...], "total_count": N})
|
||||
runner_count=$(echo "$response" | jq '.runners | length')
|
||||
|
||||
if [ "$runner_count" -eq 0 ]; then
|
||||
echo "⚠️ 服务器上没有全局 runners"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Gitea 全局 Runners (共 $runner_count 个)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Display runners with formatted output
|
||||
echo "$response" | jq -r '.runners[] | [.id, .name, .status] | @tsv' | \
|
||||
awk 'BEGIN{i=1} {
|
||||
printf "%2d. %-30s [ID: %-5s] %s\n",
|
||||
i++, $2, $1, ($3=="online"?"🟢 在线":"🔴 离线")
|
||||
}'
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "选择要删除的 Runner"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 输入序号: 删除单个 runner"
|
||||
echo " 输入 'all': 删除所有 runners"
|
||||
echo " 输入 'q' 或 'quit': 取消"
|
||||
echo ""
|
||||
|
||||
# Save runner data to temp file for later use
|
||||
echo "$response" | jq -r '.runners[] | "\(.id)|\(.name)"' > /tmp/gitea_runners.txt
|
||||
```
|
||||
|
||||
**AI 指导**:执行完上述命令后,等待用户输入选择(序号、'all' 或 'q')。
|
||||
|
||||
### 3. Process User Selection
|
||||
|
||||
**AI 指导**:根据用户的输入(从步骤 2 获取),执行相应的处理逻辑。
|
||||
|
||||
- 如果用户输入 'q' 或 'quit':取消操作,清理临时文件
|
||||
- 如果用户输入 'all':准备删除所有 runners,进入步骤 4 确认
|
||||
- 如果用户输入序号:验证并准备删除对应的 runner,进入步骤 4 确认
|
||||
|
||||
**选择处理脚本**(AI 根据用户输入执行相应部分):
|
||||
|
||||
```bash
|
||||
# 假设用户选择存储在变量 $USER_SELECTION 中
|
||||
|
||||
if [ "$USER_SELECTION" = "q" ] || [ "$USER_SELECTION" = "quit" ]; then
|
||||
echo "已取消"
|
||||
rm -f /tmp/gitea_runners.txt
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Read runner data from temp file
|
||||
mapfile -t runner_data < /tmp/gitea_runners.txt
|
||||
runner_count=${#runner_data[@]}
|
||||
|
||||
if [ "$USER_SELECTION" = "all" ]; then
|
||||
# Prepare to delete all runners
|
||||
echo ""
|
||||
echo "⚠️ 将删除所有 $runner_count 个 runners"
|
||||
echo ""
|
||||
# 继续到步骤 4 显示警告并确认
|
||||
else
|
||||
# Validate selection is a number
|
||||
if ! [[ "$USER_SELECTION" =~ ^[0-9]+$ ]]; then
|
||||
echo "❌ 无效的选择"
|
||||
rm -f /tmp/gitea_runners.txt
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate selection is in range
|
||||
if [ "$USER_SELECTION" -lt 1 ] || [ "$USER_SELECTION" -gt "$runner_count" ]; then
|
||||
echo "❌ 选择超出范围 (1-$runner_count)"
|
||||
rm -f /tmp/gitea_runners.txt
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get selected runner info
|
||||
selected_data="${runner_data[$((USER_SELECTION-1))]}"
|
||||
IFS='|' read -r id name <<< "$selected_data"
|
||||
|
||||
echo ""
|
||||
echo "已选择: $name (ID: $id)"
|
||||
echo ""
|
||||
# 继续到步骤 4 显示警告并确认
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. Display Warning and Get Confirmation
|
||||
|
||||
**AI 执行**:显示删除警告,列出将要删除的 runners,然后等待用户输入 'yes' 确认。
|
||||
|
||||
```bash
|
||||
echo "⚠️ 警告: 此操作将执行以下操作:"
|
||||
echo " - 从 Gitea 服务器注销 runner"
|
||||
echo " - 停止本地运行的 runner 进程"
|
||||
echo " - 删除 runner 配置文件"
|
||||
echo " - 删除 cache 和 workspace 目录"
|
||||
echo " - 删除所有相关数据"
|
||||
echo ""
|
||||
|
||||
# List runners to be deleted
|
||||
if [ "$USER_SELECTION" = "all" ]; then
|
||||
echo "将删除以下 runners:"
|
||||
cat /tmp/gitea_runners.txt | while IFS='|' read -r id name; do
|
||||
echo " - $name (ID: $id)"
|
||||
done
|
||||
else
|
||||
# Single runner already displayed in step 3
|
||||
:
|
||||
fi
|
||||
|
||||
echo ""
|
||||
```
|
||||
|
||||
**AI 指导**:显示完警告后,等待用户输入确认('yes' 继续,其他取消)。
|
||||
|
||||
### 5. Execute Deletion
|
||||
|
||||
**AI 执行**:如果用户确认(输入 'yes'),执行删除操作;否则取消。
|
||||
|
||||
```bash
|
||||
# 假设用户确认输入存储在 $USER_CONFIRM 中
|
||||
if [ "$USER_CONFIRM" != "yes" ]; then
|
||||
echo "已取消"
|
||||
rm -f /tmp/gitea_runners.txt
|
||||
exit 0
|
||||
fi
|
||||
|
||||
source "$HOME/.config/gitea/config.env"
|
||||
|
||||
echo "开始删除..."
|
||||
echo ""
|
||||
|
||||
success_count=0
|
||||
fail_count=0
|
||||
runners_dir="$HOME/.config/gitea/runners"
|
||||
|
||||
# Process all selected runners
|
||||
while IFS='|' read -r runner_id runner_name; do
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "删除: $runner_name (ID: $runner_id)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Find local runner directory by ID (处理 runners/* 不存在的情况)
|
||||
runner_dir=""
|
||||
if [ -d "$runners_dir" ]; then
|
||||
shopt -s nullglob # 避免 * 无匹配时报错
|
||||
for dir in "$runners_dir"/*; do
|
||||
if [ -f "$dir/.runner" ]; then
|
||||
local_id=$(jq -r '.id // ""' "$dir/.runner" 2>/dev/null)
|
||||
if [ "$local_id" = "$runner_id" ]; then
|
||||
runner_dir="$dir"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
# Step 1: Unregister from Gitea server
|
||||
echo "[1/3] 从 Gitea 服务器注销..."
|
||||
api_endpoint="${GITEA_URL}/api/v1/admin/actions/runners/${runner_id}"
|
||||
http_code=$(curl -s -w "%{http_code}" -o /dev/null \
|
||||
-X DELETE \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$api_endpoint")
|
||||
|
||||
if [ "$http_code" = "204" ]; then
|
||||
echo " ✓ 已从服务器注销"
|
||||
else
|
||||
echo " ⚠️ 注销失败 (HTTP $http_code)"
|
||||
fi
|
||||
|
||||
# Step 2: Stop local process if running
|
||||
echo "[2/3] 检查本地进程..."
|
||||
if [ -n "$runner_dir" ] && [ -f "$runner_dir/config.yaml" ]; then
|
||||
config_file="$runner_dir/config.yaml"
|
||||
|
||||
if pgrep -f "act_runner daemon --config $config_file" > /dev/null 2>&1; then
|
||||
pid=$(pgrep -f "act_runner daemon --config $config_file")
|
||||
|
||||
# Check if runner is busy (executing jobs)
|
||||
# 从服务器获取 runner 的 busy 状态
|
||||
runner_info=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/admin/actions/runners/${runner_id}")
|
||||
is_busy=$(echo "$runner_info" | jq -r '.busy // false')
|
||||
|
||||
if [ "$is_busy" = "true" ]; then
|
||||
echo " ⚠️ 警告: Runner 正在执行 job!"
|
||||
echo " 强制停止可能导致 job 中断和数据不一致"
|
||||
echo ""
|
||||
echo " 选项:"
|
||||
echo " 1. 等待 job 完成后再停止(推荐)"
|
||||
echo " 2. 强制立即停止"
|
||||
echo ""
|
||||
# AI 应在此处等待用户选择
|
||||
# 假设用户选择存储在 $STOP_CHOICE 中
|
||||
|
||||
if [ "$STOP_CHOICE" = "1" ]; then
|
||||
echo " 等待 job 完成..."
|
||||
# 轮询检查 runner 是否仍然 busy
|
||||
max_wait=300 # 最多等待 5 分钟
|
||||
waited=0
|
||||
while [ $waited -lt $max_wait ]; do
|
||||
sleep 10
|
||||
waited=$((waited + 10))
|
||||
runner_info=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/admin/actions/runners/${runner_id}")
|
||||
is_busy=$(echo "$runner_info" | jq -r '.busy // false')
|
||||
if [ "$is_busy" = "false" ]; then
|
||||
echo " ✓ Job 已完成"
|
||||
break
|
||||
fi
|
||||
echo " 仍在执行... (已等待 ${waited}s)"
|
||||
done
|
||||
|
||||
if [ $waited -ge $max_wait ]; then
|
||||
echo " ⚠️ 等待超时,将强制停止"
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ 用户选择强制停止"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 优雅停止 runner
|
||||
echo " 正在停止进程 (PID: $pid)..."
|
||||
kill "$pid" 2>/dev/null
|
||||
sleep 2
|
||||
|
||||
# 如果进程还在运行,强制杀死
|
||||
if pgrep -f "act_runner daemon --config $config_file" > /dev/null 2>&1; then
|
||||
echo " 进程未响应,强制终止..."
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# 验证进程已停止
|
||||
if pgrep -f "act_runner daemon --config $config_file" > /dev/null 2>&1; then
|
||||
echo " ❌ 无法停止进程"
|
||||
else
|
||||
echo " ✓ 进程已停止"
|
||||
fi
|
||||
else
|
||||
echo " ✓ 未运行"
|
||||
fi
|
||||
else
|
||||
echo " ⓘ 未找到本地配置"
|
||||
fi
|
||||
|
||||
# Step 3: Delete local directory
|
||||
echo "[3/3] 删除本地配置..."
|
||||
if [ -n "$runner_dir" ] && [ -d "$runner_dir" ]; then
|
||||
rm -rf "$runner_dir"
|
||||
|
||||
if [ ! -d "$runner_dir" ]; then
|
||||
echo " ✓ 本地配置已删除"
|
||||
((success_count++))
|
||||
else
|
||||
echo " ❌ 删除失败"
|
||||
((fail_count++))
|
||||
fi
|
||||
else
|
||||
# Server runner deleted, but no local config
|
||||
((success_count++))
|
||||
echo " ⓘ 无本地配置需要删除"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done < /tmp/gitea_runners.txt
|
||||
|
||||
# Cleanup temp file
|
||||
rm -f /tmp/gitea_runners.txt
|
||||
```
|
||||
|
||||
### 6. Display Summary
|
||||
|
||||
**AI 执行**:显示删除操作的最终结果。
|
||||
|
||||
```bash
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "删除完成"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "成功: $success_count 个"
|
||||
if [ $fail_count -gt 0 ]; then
|
||||
echo "失败: $fail_count 个"
|
||||
fi
|
||||
echo ""
|
||||
echo "管理命令:"
|
||||
echo " 查看剩余 runners: /gitea-list-runners"
|
||||
echo " 创建新 runner: /gitea-create-runner"
|
||||
echo ""
|
||||
```
|
||||
|
||||
**AI 指导**:删除完成后,可以选择性地验证服务器上的 runner 数量,确认删除成功。
|
||||
|
||||
## Output Example
|
||||
|
||||
### Example 1: Delete Single Runner
|
||||
|
||||
```
|
||||
正在从 Gitea 服务器获取全局 runners...
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Gitea 全局 Runners (共 3 个)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1. runner-mac-mini4 [ID: 42 ] 🟢 在线
|
||||
系统: darwin 架构: arm64 最后在线: 2026-01-12 10:30
|
||||
|
||||
2. runner-macbook-pro [ID: 43 ] 🔴 离线
|
||||
系统: darwin 架构: arm64 最后在线: 2026-01-10 18:45
|
||||
|
||||
3. runner-linux-server [ID: 44 ] 🟢 在线
|
||||
系统: linux 架构: amd64 最后在线: 2026-01-12 10:25
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
选择要删除的 Runner
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
输入序号: 删除单个 runner
|
||||
输入 'all': 删除所有 runners
|
||||
输入 'q' 或 'quit': 取消
|
||||
|
||||
请选择: 2
|
||||
|
||||
已选择: runner-macbook-pro (ID: 43)
|
||||
|
||||
⚠️ 警告: 此操作将执行以下操作:
|
||||
- 从 Gitea 服务器注销 runner
|
||||
- 停止本地运行的 runner 进程
|
||||
- 删除 runner 配置文件
|
||||
- 删除 cache 和 workspace 目录
|
||||
- 删除所有相关数据
|
||||
|
||||
确认删除? 输入 'yes' 继续: yes
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
删除: runner-macbook-pro (ID: 43)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
[1/3] 从 Gitea 服务器注销...
|
||||
✓ 已从服务器注销
|
||||
[2/3] 检查本地进程...
|
||||
✓ 未运行
|
||||
[3/3] 删除本地配置...
|
||||
✓ 本地配置已删除
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
删除完成
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
成功: 1 个
|
||||
|
||||
管理命令:
|
||||
查看剩余 runners: /gitea-list-runners
|
||||
创建新 runner: /gitea-create-runner
|
||||
```
|
||||
|
||||
### Example 2: Delete All Runners
|
||||
|
||||
```
|
||||
正在从 Gitea 服务器获取全局 runners...
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Gitea 全局 Runners (共 2 个)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1. runner-mac-mini4 [ID: 42 ] 🟢 在线
|
||||
系统: darwin 架构: arm64 最后在线: 2026-01-12 10:30
|
||||
|
||||
2. runner-linux-server [ID: 44 ] 🟢 在线
|
||||
系统: linux 架构: amd64 最后在线: 2026-01-12 10:25
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
选择要删除的 Runner
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
输入序号: 删除单个 runner
|
||||
输入 'all': 删除所有 runners
|
||||
输入 'q' 或 'quit': 取消
|
||||
|
||||
请选择: all
|
||||
|
||||
⚠️ 将删除所有 2 个 runners
|
||||
|
||||
⚠️ 警告: 此操作将执行以下操作:
|
||||
- 从 Gitea 服务器注销 runner
|
||||
- 停止本地运行的 runner 进程
|
||||
- 删除 runner 配置文件
|
||||
- 删除 cache 和 workspace 目录
|
||||
- 删除所有相关数据
|
||||
|
||||
将删除 2 个 runners:
|
||||
- runner-mac-mini4 (ID: 42)
|
||||
- runner-linux-server (ID: 44)
|
||||
|
||||
确认删除? 输入 'yes' 继续: yes
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
删除: runner-mac-mini4 (ID: 42)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
[1/3] 从 Gitea 服务器注销...
|
||||
✓ 已从服务器注销
|
||||
[2/3] 检查本地进程...
|
||||
正在停止进程 (PID: 12345)...
|
||||
✓ 进程已停止
|
||||
[3/3] 删除本地配置...
|
||||
✓ 本地配置已删除
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
删除: runner-linux-server (ID: 44)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
[1/3] 从 Gitea 服务器注销...
|
||||
✓ 已从服务器注销
|
||||
[2/3] 检查本地进程...
|
||||
ⓘ 未找到本地配置
|
||||
[3/3] 删除本地配置...
|
||||
ⓘ 无本地配置需要删除
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
删除完成
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
成功: 2 个
|
||||
|
||||
管理命令:
|
||||
查看剩余 runners: /gitea-list-runners
|
||||
创建新 runner: /gitea-create-runner
|
||||
```
|
||||
|
||||
## Safety Features
|
||||
|
||||
- **服务器数据优先**:直接从 Gitea 服务器获取 runner 列表,确保准确性
|
||||
- **交互式选择**:支持选择单个或所有 runners,避免误删
|
||||
- **双重确认**:需要输入 'yes' 进行最终确认(防止误删)
|
||||
- **Busy 状态检测**:检查 runner 是否正在执行 job
|
||||
- 如果 runner 正在执行 job,给用户选择:
|
||||
- 等待 job 完成后停止(推荐)
|
||||
- 强制立即停止(有风险)
|
||||
- **优雅停止**:先尝试 SIGTERM,2 秒后才使用 SIGKILL
|
||||
- **服务器注销**:自动从 Gitea 服务器注销 runner
|
||||
- **三步删除流程**:
|
||||
1. 从服务器注销
|
||||
2. 停止本地进程(检测 busy 状态)
|
||||
3. 删除本地配置
|
||||
- **清晰提示**:显示每个步骤的执行状态和警告信息
|
||||
- **批量删除支持**:可一次性删除所有 runners
|
||||
- **错误处理**:各步骤独立执行,部分失败不影响其他操作
|
||||
- **超时保护**:等待 job 完成最多 5 分钟,超时后强制停止
|
||||
|
||||
## Technical Notes
|
||||
|
||||
- **必需工具**:需要安装 `jq` 工具(`brew install jq`)
|
||||
- **权限要求**:需要 Gitea admin 权限(全局 runner 管理)
|
||||
- **配置文件**:读取 `~/.config/gitea/config.env` 获取 API 配置
|
||||
- **本地匹配**:通过 runner ID 匹配本地配置目录
|
||||
- **服务器同步**:从服务器注销后再删除本地配置
|
||||
- **无本地配置**:如果只存在服务器记录,仅注销服务器端
|
||||
- **取消操作**:输入 'q' 或 'quit' 可随时取消
|
||||
- **临时文件**:使用 `/tmp/gitea_runners.txt` 存储临时数据,操作完成后自动清理
|
||||
- **API 格式**:Gitea API 返回格式为 `{"runners": [...], "total_count": N}`,不是直接的数组
|
||||
- **Busy 检测**:通过 API 的 `busy` 字段判断 runner 是否正在执行 job
|
||||
- **停止信号**:
|
||||
- `kill $pid` (SIGTERM): 优雅停止,给进程清理资源的机会
|
||||
- `kill -9 $pid` (SIGKILL): 强制终止,无法被捕获或忽略
|
||||
- **等待策略**:如果 runner busy,最多等待 5 分钟(300 秒),每 10 秒检查一次状态
|
||||
|
||||
## AI 执行流程总结
|
||||
|
||||
当用户调用 `/gitea-delete-runner` 时,AI 应该按以下流程执行:
|
||||
|
||||
1. **步骤 1**:加载并验证 Gitea 配置
|
||||
2. **步骤 2**:获取并展示 runners 列表 → **等待用户选择**
|
||||
3. **步骤 3**:处理用户选择,验证输入
|
||||
4. **步骤 4**:显示删除警告和列表 → **等待用户确认**
|
||||
5. **步骤 5**:执行删除操作
|
||||
- 5.1: 从服务器注销
|
||||
- 5.2: 检查并停止本地进程
|
||||
- **如果 runner 正在执行 job(busy)** → **等待用户选择**(等待完成 or 强制停止)
|
||||
- 5.3: 删除本地配置
|
||||
6. **步骤 6**:显示操作结果摘要
|
||||
|
||||
**重要**:这是一个交互式命令,可能需要在以下位置等待用户输入:
|
||||
- 步骤 2: 选择要删除的 runner
|
||||
- 步骤 4: 确认删除操作
|
||||
- 步骤 5.2: 如果 runner 正在执行 job,选择等待或强制停止
|
||||
|
||||
不要一次性执行所有步骤。
|
||||
202
command/gitea-list-runners.md
Normal file
202
command/gitea-list-runners.md
Normal file
@@ -0,0 +1,202 @@
|
||||
---
|
||||
description: List all configured Gitea runners and their status
|
||||
---
|
||||
|
||||
# gitea-list-runners
|
||||
|
||||
列出所有已配置的 Gitea Runners 及其运行状态。
|
||||
|
||||
## Features
|
||||
|
||||
- 显示所有已配置的 runner
|
||||
- 检查 runner 运行状态(运行中/已停止)
|
||||
- 显示 runner 配置信息(labels、capacity 等)
|
||||
- 显示 runner ID 和名称
|
||||
- 提供启动命令
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Check Configuration
|
||||
|
||||
```bash
|
||||
config_dir="$HOME/.config/gitea"
|
||||
runners_dir="$config_dir/runners"
|
||||
|
||||
if [ ! -d "$runners_dir" ]; then
|
||||
echo "❌ 未找到 runner 目录"
|
||||
echo "请先创建 runner"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. List All Runners
|
||||
|
||||
```bash
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Gitea Runners"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
runners=$(ls -1 "$runners_dir" 2>/dev/null)
|
||||
|
||||
if [ -z "$runners" ]; then
|
||||
echo "未配置任何 runner"
|
||||
echo ""
|
||||
echo "创建 runner:"
|
||||
echo " /gitea-create-runner"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
runner_count=$(echo "$runners" | wc -l | tr -d ' ')
|
||||
echo "总计: $runner_count 个 runner"
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 3. Display Each Runner's Status
|
||||
|
||||
```bash
|
||||
for runner in $runners; do
|
||||
runner_dir="$runners_dir/$runner"
|
||||
config_file="$runner_dir/config.yaml"
|
||||
|
||||
echo "[$runner]"
|
||||
|
||||
# Check if config exists
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo " ⚠️ 配置文件缺失"
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if runner process is running
|
||||
if pgrep -f "act_runner daemon --config $config_file" > /dev/null; then
|
||||
status="🟢 运行中"
|
||||
pid=$(pgrep -f "act_runner daemon --config $config_file")
|
||||
else
|
||||
status="🔴 已停止"
|
||||
pid="-"
|
||||
fi
|
||||
|
||||
echo " 状态: $status"
|
||||
echo " PID: $pid"
|
||||
|
||||
# Display configuration info
|
||||
if command -v yq &> /dev/null; then
|
||||
# Use yq if available
|
||||
capacity=$(yq eval '.runner.capacity' "$config_file" 2>/dev/null)
|
||||
timeout=$(yq eval '.runner.timeout' "$config_file" 2>/dev/null)
|
||||
else
|
||||
# Fallback to grep
|
||||
capacity=$(grep "capacity:" "$config_file" | awk '{print $2}')
|
||||
timeout=$(grep "timeout:" "$config_file" | awk '{print $2}')
|
||||
fi
|
||||
|
||||
echo " 容量: ${capacity:-N/A}"
|
||||
echo " 超时: ${timeout:-N/A}"
|
||||
|
||||
# Display labels
|
||||
labels=$(grep -A 10 "labels:" "$config_file" | grep "^ -" | sed 's/^ - "//' | sed 's/"$//' | tr '\n' ',' | sed 's/,$//')
|
||||
if [ -n "$labels" ]; then
|
||||
echo " Labels: $labels"
|
||||
fi
|
||||
|
||||
# Display runner info from .runner file
|
||||
if [ -f "$runner_dir/.runner" ]; then
|
||||
if command -v jq &> /dev/null; then
|
||||
runner_id=$(jq -r '.id // "N/A"' "$runner_dir/.runner" 2>/dev/null)
|
||||
runner_name=$(jq -r '.name // "N/A"' "$runner_dir/.runner" 2>/dev/null)
|
||||
|
||||
echo " ID: $runner_id"
|
||||
echo " 名称: $runner_name"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " 路径: $runner_dir"
|
||||
|
||||
# Display start command
|
||||
echo ""
|
||||
echo " 启动命令:"
|
||||
echo " act_runner daemon --config $config_file"
|
||||
|
||||
# Display background start command
|
||||
if [ "$status" = "🔴 已停止" ]; then
|
||||
echo ""
|
||||
echo " 后台启动:"
|
||||
echo " nohup act_runner daemon --config $config_file > $runner_dir/runner.log 2>&1 &"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
```
|
||||
|
||||
### 4. Display Summary Commands
|
||||
|
||||
```bash
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "管理命令"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 查看配置: /gitea-config"
|
||||
echo " 创建 runner: /gitea-create-runner"
|
||||
echo " 删除 runner: /gitea-delete-runner"
|
||||
echo ""
|
||||
```
|
||||
|
||||
## Output Example
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Gitea Runners
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
总计: 2 个 runner
|
||||
|
||||
[runner-macbook-pro]
|
||||
状态: 🟢 运行中
|
||||
PID: 12345
|
||||
容量: 2
|
||||
超时: 3h
|
||||
Labels: self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
|
||||
ID: 42
|
||||
名称: runner-macbook-pro
|
||||
路径: /Users/voson/.config/gitea/runners/runner-macbook-pro
|
||||
|
||||
启动命令:
|
||||
act_runner daemon --config /Users/voson/.config/gitea/runners/runner-macbook-pro/config.yaml
|
||||
|
||||
[runner-mac-mini]
|
||||
状态: 🔴 已停止
|
||||
PID: -
|
||||
容量: 2
|
||||
超时: 3h
|
||||
Labels: self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host
|
||||
ID: 43
|
||||
名称: runner-mac-mini
|
||||
路径: /Users/voson/.config/gitea/runners/runner-mac-mini
|
||||
|
||||
启动命令:
|
||||
act_runner daemon --config /Users/voson/.config/gitea/runners/runner-mac-mini/config.yaml
|
||||
|
||||
后台启动:
|
||||
nohup act_runner daemon --config /Users/voson/.config/gitea/runners/runner-mac-mini/config.yaml > /Users/voson/.config/gitea/runners/runner-mac-mini/runner.log 2>&1 &
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
管理命令
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
查看配置: /gitea-config
|
||||
创建 runner: /gitea-create-runner
|
||||
删除 runner: /gitea-delete-runner
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- 使用 `pgrep` 检查进程状态
|
||||
- 优先使用 `yq` 解析 YAML,fallback 到 `grep`
|
||||
- 优先使用 `jq` 解析 JSON `.runner` 文件
|
||||
- Runner 状态图标:
|
||||
- 🟢 运行中
|
||||
- 🔴 已停止
|
||||
- ⚠️ 配置异常
|
||||
- 显示启动命令方便用户复制执行
|
||||
- 对已停止的 runner,额外显示后台启动命令
|
||||
314
command/gitea-reset.md
Normal file
314
command/gitea-reset.md
Normal file
@@ -0,0 +1,314 @@
|
||||
---
|
||||
description: Reset Gitea configuration with interactive setup wizard
|
||||
---
|
||||
|
||||
# gitea-reset
|
||||
|
||||
重置 Gitea 配置,启动交互式配置向导。
|
||||
|
||||
## Features
|
||||
|
||||
- 交互式引导配置
|
||||
- 验证 URL 和 Token
|
||||
- 检查 Token 权限
|
||||
- 自动保存配置到 `~/.config/gitea/config.env`
|
||||
- 创建必要的目录结构
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Create Configuration Directory
|
||||
|
||||
```bash
|
||||
config_dir="$HOME/.config/gitea"
|
||||
config_file="$config_dir/config.env"
|
||||
|
||||
# Create directories
|
||||
mkdir -p "$config_dir/runners"
|
||||
|
||||
echo "开始 Gitea 配置向导..."
|
||||
echo ""
|
||||
```
|
||||
|
||||
### 2. Input Gitea URL
|
||||
|
||||
```bash
|
||||
read -p "请输入 Gitea 实例地址 (例如: https://git.digitevents.com): " gitea_url
|
||||
|
||||
# Validate URL format
|
||||
if ! [[ "$gitea_url" =~ ^https?:// ]]; then
|
||||
echo "❌ URL 必须以 http:// 或 https:// 开头"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove trailing slash
|
||||
gitea_url="${gitea_url%/}"
|
||||
|
||||
echo "✓ URL: $gitea_url"
|
||||
```
|
||||
|
||||
### 3. Input Personal Access Token
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
read -sp "请输入 Personal Access Token: " gitea_token
|
||||
echo ""
|
||||
|
||||
if [ -z "$gitea_token" ]; then
|
||||
echo "❌ Token 不能为空"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ Token 已输入"
|
||||
```
|
||||
|
||||
**Token 获取提示**:
|
||||
|
||||
在用户输入 Token 前,可以显示帮助信息:
|
||||
|
||||
```
|
||||
提示:获取 Personal Access Token 的步骤:
|
||||
1. 登录 Gitea
|
||||
2. 右上角头像 → 设置 → 应用 → 访问令牌
|
||||
3. 点击 "生成新令牌"
|
||||
4. 设置令牌名称(如 opencode-cli)
|
||||
5. 选择权限:repo, admin:org, write:runner(推荐)
|
||||
6. 点击 "生成令牌"
|
||||
7. 复制生成的 Token
|
||||
```
|
||||
|
||||
### 4. Test Connection
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "正在测试连接..."
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $gitea_token" \
|
||||
"${gitea_url}/api/v1/user")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "❌ 连接失败 (HTTP $http_code)"
|
||||
echo "请检查:"
|
||||
echo " - URL 是否正确"
|
||||
echo " - Token 是否有效"
|
||||
echo " - 网络连接是否正常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
username=$(echo "$body" | jq -r '.login')
|
||||
echo "✓ 连接成功!"
|
||||
echo "✓ 登录用户: $username"
|
||||
```
|
||||
|
||||
### 5. Validate Token Permissions
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "正在检查 Token 权限..."
|
||||
|
||||
# Check repo permission
|
||||
if curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $gitea_token" \
|
||||
"${gitea_url}/api/v1/user/repos" | grep -q "200"; then
|
||||
echo " ✓ repo (仓库管理)"
|
||||
has_repo=true
|
||||
else
|
||||
echo " ✗ repo (仓库管理) - 缺少"
|
||||
has_repo=false
|
||||
fi
|
||||
|
||||
# Check org permission
|
||||
if curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $gitea_token" \
|
||||
"${gitea_url}/api/v1/user/orgs" | grep -q "200"; then
|
||||
echo " ✓ admin:org (组织管理)"
|
||||
has_org=true
|
||||
else
|
||||
echo " ⚠ admin:org (组织管理) - 缺少(创建组织 Runner 时需要)"
|
||||
has_org=false
|
||||
fi
|
||||
|
||||
# Check runner permission (try to get a registration token)
|
||||
if curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $gitea_token" \
|
||||
"${gitea_url}/api/v1/user/actions/runners/registration-token" 2>/dev/null | grep -q "200"; then
|
||||
echo " ✓ write:runner (Runner 管理)"
|
||||
has_runner=true
|
||||
else
|
||||
echo " ⚠ write:runner (Runner 管理) - 缺少(创建 Runner 时需要)"
|
||||
has_runner=false
|
||||
fi
|
||||
|
||||
# Warning if missing critical permissions
|
||||
if [ "$has_repo" = false ]; then
|
||||
echo ""
|
||||
echo "❌ 缺少必需的 repo 权限"
|
||||
read -p "是否继续? [y/N] " continue_anyway
|
||||
if [[ ! "$continue_anyway" =~ ^[Yy]$ ]]; then
|
||||
echo "已取消,请重新创建具有足够权限的 Token"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
### 6. Input Default Organization (Optional)
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "设置默认组织(可选):"
|
||||
echo " - 创建仓库时,如果不指定 owner,将使用默认组织"
|
||||
echo " - 创建组织级 Runner 时使用"
|
||||
echo ""
|
||||
read -p "请输入默认组织名称 (回车跳过): " default_org
|
||||
|
||||
if [ -n "$default_org" ]; then
|
||||
# Validate organization exists
|
||||
echo "正在验证组织..."
|
||||
org_response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $gitea_token" \
|
||||
"${gitea_url}/api/v1/orgs/${default_org}")
|
||||
|
||||
org_http_code=$(echo "$org_response" | tail -n1)
|
||||
|
||||
if [ "$org_http_code" = "200" ]; then
|
||||
echo "✓ 组织验证成功: $default_org"
|
||||
else
|
||||
echo "⚠️ 组织 '$default_org' 不存在或无权限访问"
|
||||
read -p "仍然设置为默认组织? [Y/n] " set_anyway
|
||||
if [[ "$set_anyway" =~ ^[Nn]$ ]]; then
|
||||
default_org=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
### 7. Save Configuration
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "正在保存配置..."
|
||||
|
||||
cat > "$config_file" << EOF
|
||||
# Gitea Configuration
|
||||
# Generated at $(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
GITEA_URL=$gitea_url
|
||||
GITEA_TOKEN=$gitea_token
|
||||
${default_org:+GITEA_DEFAULT_ORG=$default_org}
|
||||
|
||||
# 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
|
||||
EOF
|
||||
|
||||
# Set restrictive permissions
|
||||
chmod 600 "$config_file"
|
||||
|
||||
# Create .gitignore
|
||||
cat > "$config_dir/.gitignore" << EOF
|
||||
config.env
|
||||
runners/*/.runner
|
||||
runners/*/.env
|
||||
EOF
|
||||
|
||||
echo "✓ 配置已保存"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "配置完成"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 配置文件: $config_file"
|
||||
echo " Runner 目录: $config_dir/runners"
|
||||
echo ""
|
||||
echo "下一步:"
|
||||
echo " - 查看配置: /gitea-config"
|
||||
echo " - 创建 Runner: 告诉 AI '创建一个 runner'"
|
||||
echo " - 创建仓库: /create-gitea-repo <repo-name>"
|
||||
echo ""
|
||||
```
|
||||
|
||||
## Configuration File Format
|
||||
|
||||
生成的 `~/.config/gitea/config.env` 文件格式:
|
||||
|
||||
```bash
|
||||
# Gitea Configuration
|
||||
# Generated at 2026-01-12 22:00:00
|
||||
|
||||
GITEA_URL=https://git.digitevents.com
|
||||
GITEA_TOKEN=git_xxxxxxxxxxxxxxxxxxxx
|
||||
GITEA_DEFAULT_ORG=ai
|
||||
|
||||
# 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
|
||||
```
|
||||
|
||||
## Output Example
|
||||
|
||||
```
|
||||
开始 Gitea 配置向导...
|
||||
|
||||
请输入 Gitea 实例地址 (例如: https://git.digitevents.com): https://git.digitevents.com
|
||||
✓ URL: https://git.digitevents.com
|
||||
|
||||
请输入 Personal Access Token: ****************
|
||||
✓ Token 已输入
|
||||
|
||||
正在测试连接...
|
||||
✓ 连接成功!
|
||||
✓ 登录用户: your_username
|
||||
|
||||
正在检查 Token 权限...
|
||||
✓ repo (仓库管理)
|
||||
✓ admin:org (组织管理)
|
||||
✓ write:runner (Runner 管理)
|
||||
|
||||
设置默认组织(可选):
|
||||
- 创建仓库时,如果不指定 owner,将使用默认组织
|
||||
- 创建组织级 Runner 时使用
|
||||
|
||||
请输入默认组织名称 (回车跳过): ai
|
||||
正在验证组织...
|
||||
✓ 组织验证成功: ai
|
||||
|
||||
正在保存配置...
|
||||
✓ 配置已保存
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
配置完成
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
配置文件: /Users/voson/.config/gitea/config.env
|
||||
Runner 目录: /Users/voson/.config/gitea/runners
|
||||
|
||||
下一步:
|
||||
- 查看配置: /gitea-config
|
||||
- 创建 Runner: 告诉 AI '创建一个 runner'
|
||||
- 创建仓库: /create-gitea-repo <repo-name>
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- 配置文件权限设置为 `600`(仅所有者可读写)
|
||||
- Token 不会在日志中显示
|
||||
- 创建 `.gitignore` 文件排除敏感信息
|
||||
- 建议定期轮换 Token(每 3-6 个月)
|
||||
|
||||
## Notes
|
||||
|
||||
- **必需权限**: `repo` - 创建和管理仓库
|
||||
- **推荐权限**: `admin:org` - 创建组织级 Runner
|
||||
- **推荐权限**: `write:runner` - 管理 Runner
|
||||
- **可选权限**: `admin:repo_hook` - 配置 Webhooks
|
||||
- Token 只显示一次,请妥善保管
|
||||
- 重置配置不会影响已创建的 Runner,但 Runner 会继续使用旧的注册信息
|
||||
155
command/gitea-switch-org.md
Normal file
155
command/gitea-switch-org.md
Normal file
@@ -0,0 +1,155 @@
|
||||
---
|
||||
description: Switch default Gitea organization
|
||||
---
|
||||
|
||||
# gitea-switch-org
|
||||
|
||||
切换默认 Gitea 组织。
|
||||
|
||||
## Features
|
||||
|
||||
- 更新配置文件中的默认组织
|
||||
- 验证组织是否存在
|
||||
- 立即生效,无需重启
|
||||
|
||||
## User Input Format
|
||||
|
||||
```
|
||||
<organization_name>
|
||||
```
|
||||
|
||||
**Examples**:
|
||||
- `ai` - Switch to 'ai' organization
|
||||
- `my-team` - Switch to 'my-team' organization
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Check Configuration
|
||||
|
||||
```bash
|
||||
config_file="$HOME/.config/gitea/config.env"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Gitea 未配置"
|
||||
echo "请先运行 /gitea-reset 进行配置"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$config_file"
|
||||
```
|
||||
|
||||
### 2. Parse User Input
|
||||
|
||||
```bash
|
||||
new_org="$1"
|
||||
|
||||
if [ -z "$new_org" ]; then
|
||||
echo "用法: /gitea-switch-org <organization_name>"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " /gitea-switch-org ai"
|
||||
echo " /gitea-switch-org my-team"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Validate Organization Exists
|
||||
|
||||
```bash
|
||||
echo "正在验证组织 '$new_org'..."
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/orgs/${new_org}")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [ "$http_code" != "200" ]; then
|
||||
echo "❌ 组织 '$new_org' 不存在或无权限访问"
|
||||
|
||||
# Suggest available organizations
|
||||
echo ""
|
||||
echo "你可以访问的组织:"
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
"${GITEA_URL}/api/v1/user/orgs" | jq -r '.[].username' | sed 's/^/ - /'
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
org_name=$(echo "$body" | jq -r '.full_name // .username')
|
||||
echo "✓ 组织验证成功: $org_name"
|
||||
```
|
||||
|
||||
### 4. Update Configuration File
|
||||
|
||||
```bash
|
||||
echo "正在更新配置..."
|
||||
|
||||
# Check if GITEA_DEFAULT_ORG already exists in config
|
||||
if grep -q "^GITEA_DEFAULT_ORG=" "$config_file"; then
|
||||
# Update existing line (macOS compatible)
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' "s/^GITEA_DEFAULT_ORG=.*/GITEA_DEFAULT_ORG=$new_org/" "$config_file"
|
||||
else
|
||||
sed -i "s/^GITEA_DEFAULT_ORG=.*/GITEA_DEFAULT_ORG=$new_org/" "$config_file"
|
||||
fi
|
||||
else
|
||||
# Add new line after GITEA_TOKEN
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' "/^GITEA_TOKEN=/a\\
|
||||
GITEA_DEFAULT_ORG=$new_org
|
||||
" "$config_file"
|
||||
else
|
||||
sed -i "/^GITEA_TOKEN=/a GITEA_DEFAULT_ORG=$new_org" "$config_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✓ 默认组织已切换到: $new_org"
|
||||
```
|
||||
|
||||
### 5. Display Summary
|
||||
|
||||
```bash
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "切换完成"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo " 新的默认组织: $new_org"
|
||||
echo ""
|
||||
echo "现在可以:"
|
||||
echo " - 创建仓库: /create-gitea-repo my-project"
|
||||
echo " (将创建到 $new_org/my-project)"
|
||||
echo " - 查看配置: /gitea-config"
|
||||
echo ""
|
||||
```
|
||||
|
||||
## Output Example
|
||||
|
||||
```
|
||||
正在验证组织 'ai'...
|
||||
✓ 组织验证成功: AI Team
|
||||
|
||||
正在更新配置...
|
||||
✓ 默认组织已切换到: ai
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
切换完成
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
新的默认组织: ai
|
||||
|
||||
现在可以:
|
||||
- 创建仓库: /create-gitea-repo my-project
|
||||
(将创建到 ai/my-project)
|
||||
- 查看配置: /gitea-config
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- 切换组织不会影响已创建的仓库和 Runner
|
||||
- 仅影响后续创建仓库时的默认 owner
|
||||
- 可以随时切换到其他组织
|
||||
- 使用 `jq` 解析 JSON 响应
|
||||
- macOS 和 Linux 的 `sed` 命令略有不同,需兼容处理
|
||||
@@ -1,81 +0,0 @@
|
||||
---
|
||||
description: Pull latest OpenCode config changes from remote
|
||||
agent: build
|
||||
---
|
||||
|
||||
# sync-oc-pull
|
||||
|
||||
Pull latest changes for OpenCode configuration from remote repository.
|
||||
|
||||
## Use Cases
|
||||
|
||||
When you updated OpenCode configuration on another device, or team members shared new commands/configurations, use this command to sync to local.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Switch to OpenCode Config Directory
|
||||
|
||||
```bash
|
||||
cd ~/.config/opencode
|
||||
```
|
||||
|
||||
### 2. Check Local Status
|
||||
|
||||
Run `git status` to check if there are uncommitted local changes.
|
||||
|
||||
**If there are uncommitted changes**:
|
||||
- List changed files
|
||||
- Ask user how to handle:
|
||||
- **Stash**: `git stash` to save local changes, restore after pull
|
||||
- **Discard**: `git checkout -- .` to discard local changes
|
||||
- **Cancel**: Terminate operation, let user handle manually
|
||||
|
||||
### 3. Pull Remote Changes
|
||||
|
||||
```bash
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
### 4. Handle Conflicts (if any)
|
||||
|
||||
If conflicts occur during pull:
|
||||
|
||||
1. List conflicting files
|
||||
2. Open conflict files, analyze conflict content
|
||||
3. Ask user to choose:
|
||||
- **Keep local version**: Use `git checkout --ours <file>`
|
||||
- **Use remote version**: Use `git checkout --theirs <file>`
|
||||
- **Manual merge**: Prompt user to manually edit then execute `git add <file>`
|
||||
|
||||
4. After resolving all conflicts, complete merge:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "chore: resolve merge conflicts"
|
||||
```
|
||||
|
||||
### 5. Restore Stashed Changes (if any)
|
||||
|
||||
If `git stash` was used in step 2:
|
||||
|
||||
```bash
|
||||
git stash pop
|
||||
```
|
||||
|
||||
If conflicts occur during restore, handle according to step 4.
|
||||
|
||||
### 6. Show Update Summary
|
||||
|
||||
After pull completes, show update content:
|
||||
|
||||
```bash
|
||||
git log --oneline -5
|
||||
```
|
||||
|
||||
List newly added or modified command files to help user understand what new configurations are available.
|
||||
|
||||
## Notes
|
||||
|
||||
- **Backup important configs**: If there are local modifications before pull, suggest backing up or using `git stash` first.
|
||||
- **Conflict handling**: Config file conflicts usually prioritize keeping local version, unless explicitly needing remote's new config.
|
||||
- **Verify config**: After pull, suggest checking if `opencode.json` and other config files work correctly.
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
description: Commit and push OpenCode config changes to remote
|
||||
agent: build
|
||||
---
|
||||
|
||||
# sync-oc-push
|
||||
|
||||
Commit and push OpenCode configuration repository changes to remote repository.
|
||||
|
||||
## Use Cases
|
||||
|
||||
When you modified config files in `~/.config/opencode` directory (such as `command/`, `skill/`, `opencode.json`, etc.), use this command to sync changes to remote repository.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Switch to OpenCode Config Directory
|
||||
|
||||
```bash
|
||||
cd ~/.config/opencode
|
||||
```
|
||||
|
||||
### 2. Check Change Status
|
||||
|
||||
Run `git status` to view current changes.
|
||||
|
||||
**If there are no changes**:
|
||||
- Output prompt: "No changes to commit."
|
||||
- **Terminate command execution**
|
||||
|
||||
### 3. Collect Information (Execute in parallel)
|
||||
|
||||
- Run `git diff` to view unstaged changes
|
||||
- Run `git diff --cached` to view staged changes
|
||||
- Run `git log --oneline -5` to view recent commit history
|
||||
|
||||
### 4. Add Changes to Staging Area
|
||||
|
||||
Add all relevant config files to staging area:
|
||||
|
||||
```bash
|
||||
git add command/ skill/ opencode.json
|
||||
```
|
||||
|
||||
> Only add config files that need to be synced, ignore other local files.
|
||||
|
||||
### 5. Generate Commit Message and Commit
|
||||
|
||||
Generate concise commit message based on change content:
|
||||
|
||||
- Use [Conventional Commits](https://www.conventionalcommits.org/) specification
|
||||
- **Language selection**:
|
||||
- **Default (macOS/Linux)**: Use Chinese (中文) for commit messages
|
||||
- **Windows**: Use English due to encoding issues with Cursor Shell tool
|
||||
- Common types:
|
||||
- `feat`: New command or config
|
||||
- `fix`: Fix command or config issues
|
||||
- `docs`: Documentation update
|
||||
- `chore`: Miscellaneous adjustments
|
||||
|
||||
**Examples (macOS/Linux - Chinese)**:
|
||||
|
||||
```bash
|
||||
git commit -m "feat: 添加 Vue.js 开发命令"
|
||||
git commit -m "fix: 修正 MCP 服务器配置"
|
||||
git commit -m "docs: 更新 review 命令说明"
|
||||
```
|
||||
|
||||
**Examples (Windows - English)**:
|
||||
|
||||
```bash
|
||||
git commit -m "feat: add new developer command for Vue.js"
|
||||
git commit -m "fix: correct MCP server configuration"
|
||||
git commit -m "docs: update review command instructions"
|
||||
```
|
||||
|
||||
### 6. Push to Remote Repository
|
||||
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Only sync config files**: Only add `command/`, `skill/` and `opencode.json`, don't commit other local data.
|
||||
- **Sensitive info**: `opencode.json` may contain API keys, ensure remote repository access permissions are set correctly.
|
||||
- **Commit message language**: Default use Chinese (macOS/Linux); Windows must use English due to Cursor Shell tool encoding issues.
|
||||
565
skill/git/SKILL.md
Normal file
565
skill/git/SKILL.md
Normal file
@@ -0,0 +1,565 @@
|
||||
---
|
||||
name: git
|
||||
description: Git workflow best practices with commit conventions, tagging, and common operations for both polyrepo and monorepo
|
||||
---
|
||||
|
||||
# Git Workflow Best Practices
|
||||
|
||||
You are an expert in Git version control and repository management.
|
||||
|
||||
## Core Principles
|
||||
|
||||
1. **Default Main Branch**: Use `main` as the primary branch (not `master`)
|
||||
2. **Conventional Commits**: Follow [Conventional Commits](https://www.conventionalcommits.org/) specification
|
||||
3. **Semantic Versioning**: Use `major.minor.patch` format (e.g., `0.1.0`, `1.2.3`)
|
||||
4. **Repository Types**: Support both polyrepo and monorepo workflows
|
||||
5. **Clean History**: Maintain meaningful commit history and proper tagging
|
||||
|
||||
## Repository Types
|
||||
|
||||
### Polyrepo (Single Repository)
|
||||
|
||||
- Each project has its own repository
|
||||
- Tag format: `<version>` (e.g., `1.2.0`)
|
||||
- Version files at project root
|
||||
- Simpler workflow for independent projects
|
||||
|
||||
### Monorepo (Multiple Subprojects)
|
||||
|
||||
- Multiple projects in a single repository
|
||||
- Detect from `AGENTS.md` file or directory structure (e.g., `packages/`, `apps/`)
|
||||
- Tag format: `<subproject>-<version>` (e.g., `ios-1.2.0`, `android-0.3.1`)
|
||||
- Commit scope includes subproject name when changes affect single project
|
||||
- Each subproject maintains independent versioning
|
||||
|
||||
**Monorepo Detection Rules:**
|
||||
- Check if `AGENTS.md` explicitly indicates monorepo
|
||||
- Look for common monorepo directory structures:
|
||||
- `packages/`, `apps/`, `services/`, `modules/`, `projects/`
|
||||
- If uncertain, default to polyrepo
|
||||
|
||||
## Commit Message Convention
|
||||
|
||||
### Format
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
### Commit Types
|
||||
|
||||
| Type | Description | Version Impact | Examples |
|
||||
|------|-------------|----------------|----------|
|
||||
| `feat` | New feature | minor +1 | Add user authentication |
|
||||
| `fix` | Bug fix | patch +1 | Fix memory leak in cache |
|
||||
| `perf` | Performance improvement | patch +1 | Optimize database queries |
|
||||
| `BREAKING CHANGE` or `!` | Breaking change | major +1 | Remove deprecated API |
|
||||
| `docs` | Documentation only | None | Update README |
|
||||
| `style` | Code style/formatting | None | Fix indentation |
|
||||
| `refactor` | Code refactoring | None | Reorganize file structure |
|
||||
| `test` | Add/modify tests | None | Add unit tests for auth |
|
||||
| `chore` | Maintenance tasks | None | Update dependencies |
|
||||
| `ci` | CI/CD changes | None | Update workflow config |
|
||||
| `build` | Build system changes | None | Update webpack config |
|
||||
|
||||
### Commit Message Language
|
||||
|
||||
- **Default (macOS/Linux)**: Use Chinese (中文)
|
||||
- **Windows**: Use English (due to Cursor Shell tool encoding issues)
|
||||
- **Content**: Focus on "why" rather than "what"
|
||||
- **Length**: Subject line ≤ 50 characters, body line ≤ 72 characters
|
||||
|
||||
### Scope (for Monorepo)
|
||||
|
||||
When changes affect a single subproject, include scope:
|
||||
- Format: `<type>(<scope>): <subject>`
|
||||
- Example: `feat(ios): add OGG Opus upload support`
|
||||
- Example: `fix(electron): resolve clipboard injection issue`
|
||||
|
||||
When changes affect multiple subprojects or the entire repository, omit scope:
|
||||
- Example: `chore: update shared dependencies`
|
||||
|
||||
### Examples
|
||||
|
||||
**Polyrepo commits:**
|
||||
```bash
|
||||
feat: add user authentication with OAuth2
|
||||
fix: resolve bluetooth connection timeout
|
||||
docs: update API documentation
|
||||
chore: update project dependencies
|
||||
```
|
||||
|
||||
**Monorepo commits:**
|
||||
```bash
|
||||
feat(ios): add OGG Opus upload support
|
||||
fix(android): resolve memory leak in cache manager
|
||||
refactor(electron): reorganize main process code
|
||||
chore: update shared ESLint configuration
|
||||
```
|
||||
|
||||
## Version Management
|
||||
|
||||
### Semantic Versioning
|
||||
|
||||
Format: `major.minor.patch` (e.g., `0.1.0`, `1.2.3`, `2.0.0`)
|
||||
|
||||
- **Default starting version**: `0.1.0`
|
||||
- **Major** (X.0.0): Breaking changes, API incompatibility
|
||||
- **Minor** (0.X.0): New features, backward compatible
|
||||
- **Patch** (0.0.X): Bug fixes, backward compatible
|
||||
|
||||
### Version Increment Rules
|
||||
|
||||
| Change Type | Version Change | Example |
|
||||
|-------------|----------------|---------|
|
||||
| Breaking change | major +1, reset minor/patch | `1.2.3` → `2.0.0` |
|
||||
| New feature (`feat`) | minor +1, reset patch | `1.2.3` → `1.3.0` |
|
||||
| Bug fix (`fix`) | patch +1 | `1.2.3` → `1.2.4` |
|
||||
| Performance (`perf`) | patch +1 | `1.2.3` → `1.2.4` |
|
||||
|
||||
### When to Update Version
|
||||
|
||||
**Update version** (user-perceivable changes):
|
||||
- New features (`feat`)
|
||||
- Bug fixes that affect users (`fix`)
|
||||
- Performance improvements users can notice (`perf`)
|
||||
- Breaking changes (major version bump)
|
||||
|
||||
**Don't update version** (internal changes):
|
||||
- Documentation (`docs`)
|
||||
- Tests (`test`)
|
||||
- Refactoring without behavior change (`refactor`)
|
||||
- Code style (`style`)
|
||||
- Build configuration (`build`)
|
||||
- CI/CD changes (`ci`)
|
||||
- Maintenance tasks (`chore`)
|
||||
|
||||
**Decision criteria:**
|
||||
1. Will this be packaged into the final product?
|
||||
2. Will users notice this change?
|
||||
3. Does it affect the product that users download/use?
|
||||
|
||||
If answer is "yes" → update version. Otherwise → skip version update.
|
||||
|
||||
## Project Type Detection
|
||||
|
||||
### Common Project Types
|
||||
|
||||
| Project Type | Version File | Version Field |
|
||||
|--------------|--------------|---------------|
|
||||
| iOS | `*.xcodeproj/project.pbxproj` | `MARKETING_VERSION` |
|
||||
| npm/Node.js | `package.json` | `version` |
|
||||
| Android (Groovy) | `app/build.gradle` | `versionName` |
|
||||
| Android (Kotlin DSL) | `app/build.gradle.kts` | `versionName` |
|
||||
| Python (pyproject) | `pyproject.toml` | `[project] version` or `[tool.poetry] version` |
|
||||
| Python (setup) | `setup.py` | `version` |
|
||||
| Rust | `Cargo.toml` | `[package] version` |
|
||||
| Go | Git tag only | - |
|
||||
| Flutter | `pubspec.yaml` | `version` |
|
||||
| .NET | `*.csproj` | `<Version>` or `<PackageVersion>` |
|
||||
|
||||
### Detection Strategy
|
||||
|
||||
1. **Check AGENTS.md first**: If version rules are defined, use them
|
||||
2. **Auto-detect**: Scan for version files based on project structure
|
||||
3. **Fallback**: If no version file found, only create Git tag (like Go projects)
|
||||
|
||||
## Tag Management
|
||||
|
||||
### Tag Format
|
||||
|
||||
**Polyrepo:**
|
||||
```bash
|
||||
<version>
|
||||
Examples: 1.2.0, 0.3.1, 2.0.0
|
||||
```
|
||||
|
||||
**Monorepo:**
|
||||
```bash
|
||||
<subproject>-<version>
|
||||
Examples: ios-1.2.0, android-0.3.1, electron-2.0.0
|
||||
```
|
||||
|
||||
### Tag Annotation
|
||||
|
||||
- **Use same content as commit message** for tag annotation
|
||||
- Tag annotations are used as Release notes by CI/CD
|
||||
- Multi-line commits should have multi-line annotations
|
||||
|
||||
**Single-line example:**
|
||||
```bash
|
||||
git tag -a "1.2.0" -m "feat: add user authentication"
|
||||
```
|
||||
|
||||
**Multi-line example (recommended):**
|
||||
```bash
|
||||
git tag -a "1.2.1" \
|
||||
-m "fix: resolve bluetooth connection timeout" \
|
||||
-m "" \
|
||||
-m "- Increase connection timeout to 30s" \
|
||||
-m "- Add retry mechanism for failed connections" \
|
||||
-m "- Improve error messages"
|
||||
```
|
||||
|
||||
**Monorepo example:**
|
||||
```bash
|
||||
git tag -a "android-1.2.1" \
|
||||
-m "fix(android): resolve bluetooth connection timeout" \
|
||||
-m "" \
|
||||
-m "- Increase connection timeout to 30s" \
|
||||
-m "- Add retry mechanism for failed connections"
|
||||
```
|
||||
|
||||
### Tag Operations
|
||||
|
||||
**Create annotated tag:**
|
||||
```bash
|
||||
git tag -a "<tag-name>" -m "<message>"
|
||||
```
|
||||
|
||||
**Push single tag:**
|
||||
```bash
|
||||
git push origin <tag-name>
|
||||
```
|
||||
|
||||
**Push all tags:**
|
||||
```bash
|
||||
git push --tags
|
||||
# or
|
||||
git push origin --tags
|
||||
```
|
||||
|
||||
**List recent tags:**
|
||||
```bash
|
||||
git tag --list | sort -V | tail -5
|
||||
```
|
||||
|
||||
**Delete local tag:**
|
||||
```bash
|
||||
git tag -d <tag-name>
|
||||
```
|
||||
|
||||
**Delete remote tag:**
|
||||
```bash
|
||||
git push origin --delete <tag-name>
|
||||
# or
|
||||
git push origin :refs/tags/<tag-name>
|
||||
```
|
||||
|
||||
## Common Git Operations
|
||||
|
||||
### Check File Changes
|
||||
|
||||
**View changed files (working directory):**
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
|
||||
**View unstaged changes:**
|
||||
```bash
|
||||
git diff
|
||||
```
|
||||
|
||||
**View staged changes:**
|
||||
```bash
|
||||
git diff --cached
|
||||
# or
|
||||
git diff --staged
|
||||
```
|
||||
|
||||
**List changed files only:**
|
||||
```bash
|
||||
git diff --name-only
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
**View specific file changes:**
|
||||
```bash
|
||||
git diff <file-path>
|
||||
git diff --cached <file-path>
|
||||
```
|
||||
|
||||
### Staging and Committing
|
||||
|
||||
**Add files to staging area:**
|
||||
```bash
|
||||
git add <file>
|
||||
git add .
|
||||
git add -A
|
||||
```
|
||||
|
||||
**Check what's staged:**
|
||||
```bash
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
**Commit with message:**
|
||||
```bash
|
||||
# Single line
|
||||
git commit -m "feat: add new feature"
|
||||
|
||||
# Multi-line (macOS/Linux)
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat: add new feature
|
||||
|
||||
- Detail 1
|
||||
- Detail 2
|
||||
EOF
|
||||
)"
|
||||
|
||||
# Multi-line (Windows - use multiple -m flags)
|
||||
git commit -m "feat: add new feature" -m "- Detail 1" -m "- Detail 2"
|
||||
```
|
||||
|
||||
**Commit and tag in workflow:**
|
||||
```bash
|
||||
# 1. Check staging area
|
||||
git diff --cached --name-only
|
||||
|
||||
# 2. Commit changes
|
||||
git commit -m "feat: add user authentication"
|
||||
|
||||
# 3. Create tag
|
||||
git tag -a "1.2.0" -m "feat: add user authentication"
|
||||
|
||||
# 4. Push both commit and tag
|
||||
git push origin main
|
||||
git push origin 1.2.0
|
||||
```
|
||||
|
||||
### Pushing Changes
|
||||
|
||||
**Push current branch:**
|
||||
```bash
|
||||
git push origin $(git branch --show-current)
|
||||
# or
|
||||
git push origin main
|
||||
```
|
||||
|
||||
**Push with upstream tracking:**
|
||||
```bash
|
||||
git push -u origin <branch-name>
|
||||
```
|
||||
|
||||
**Push all tags:**
|
||||
```bash
|
||||
git push --tags
|
||||
# or
|
||||
git push origin --tags
|
||||
```
|
||||
|
||||
**Push specific tag:**
|
||||
```bash
|
||||
git push origin <tag-name>
|
||||
```
|
||||
|
||||
**Push commit and tag together:**
|
||||
```bash
|
||||
git push origin main && git push origin <tag-name>
|
||||
```
|
||||
|
||||
### Branch Operations
|
||||
|
||||
**View current branch:**
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
**List all branches:**
|
||||
```bash
|
||||
git branch -a
|
||||
```
|
||||
|
||||
**Create new branch:**
|
||||
```bash
|
||||
git branch <branch-name>
|
||||
git checkout -b <branch-name>
|
||||
# or (modern)
|
||||
git switch -c <branch-name>
|
||||
```
|
||||
|
||||
**Switch branch:**
|
||||
```bash
|
||||
git checkout <branch-name>
|
||||
# or (modern)
|
||||
git switch <branch-name>
|
||||
```
|
||||
|
||||
**Delete branch:**
|
||||
```bash
|
||||
git branch -d <branch-name>
|
||||
git branch -D <branch-name> # force delete
|
||||
```
|
||||
|
||||
### History and Logs
|
||||
|
||||
**View commit history:**
|
||||
```bash
|
||||
git log --oneline -10
|
||||
git log --graph --oneline --all
|
||||
```
|
||||
|
||||
**View recent tags:**
|
||||
```bash
|
||||
git tag --list | sort -V | tail -5
|
||||
```
|
||||
|
||||
**View commit details:**
|
||||
```bash
|
||||
git show <commit-hash>
|
||||
git show <tag-name>
|
||||
```
|
||||
|
||||
**Search commit history:**
|
||||
```bash
|
||||
git log --grep="<pattern>"
|
||||
git log --author="<name>"
|
||||
```
|
||||
|
||||
## Workflow Best Practices
|
||||
|
||||
### Standard Commit Workflow
|
||||
|
||||
1. **Check staging area:**
|
||||
```bash
|
||||
git diff --cached --name-only
|
||||
```
|
||||
- If empty, add files first: `git add .`
|
||||
|
||||
2. **Collect information (in parallel):**
|
||||
```bash
|
||||
git status
|
||||
git diff --cached
|
||||
git log --oneline -10
|
||||
git tag --list | sort -V | tail -5
|
||||
```
|
||||
|
||||
3. **Determine repository type:**
|
||||
- Check `AGENTS.md` for monorepo indicator
|
||||
- Analyze changed file paths for subproject scope
|
||||
|
||||
4. **Auto-detect project type:**
|
||||
- Read `AGENTS.md` for version rules
|
||||
- Scan for version files (package.json, build.gradle, etc.)
|
||||
- Determine if version update is needed
|
||||
|
||||
5. **Generate commit message:**
|
||||
- Analyze changes
|
||||
- Follow Conventional Commits format
|
||||
- Include scope for monorepo single-project changes
|
||||
|
||||
6. **Update version number (if needed):**
|
||||
- Calculate new version based on change type
|
||||
- Update version file
|
||||
- Add version file to staging: `git add <version-file>`
|
||||
- Verify: `git diff --cached --name-only`
|
||||
|
||||
7. **Commit changes:**
|
||||
```bash
|
||||
git commit -m "<message>"
|
||||
```
|
||||
|
||||
8. **Create tag (if version updated):**
|
||||
```bash
|
||||
# Polyrepo
|
||||
git tag -a "<version>" -m "<message>"
|
||||
|
||||
# Monorepo
|
||||
git tag -a "<subproject>-<version>" -m "<message>"
|
||||
```
|
||||
|
||||
9. **Push to remote:**
|
||||
```bash
|
||||
git push origin main
|
||||
git push origin <tag-name> # if tag created
|
||||
```
|
||||
|
||||
### Sync Configuration Workflow
|
||||
|
||||
**Pull latest config changes:**
|
||||
```bash
|
||||
cd ~/.config/opencode
|
||||
git status # check for local changes
|
||||
git pull origin main
|
||||
git log --oneline -5 # view updates
|
||||
```
|
||||
|
||||
**Push config changes:**
|
||||
```bash
|
||||
cd ~/.config/opencode
|
||||
git status # check changes
|
||||
git add command/ skill/ opencode.json
|
||||
git commit -m "feat: add new git skill"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Platform-Specific Considerations
|
||||
|
||||
### macOS/Linux
|
||||
|
||||
- **Commit language**: Use Chinese (中文)
|
||||
- **Multi-line commits**: Use heredoc with `cat <<'EOF'`
|
||||
- **Encoding**: UTF-8 without BOM (default)
|
||||
|
||||
### Windows
|
||||
|
||||
- **Commit language**: Use English only (Cursor Shell encoding issue)
|
||||
- **Multi-line commits**: Use multiple `-m` flags
|
||||
- **Prohibited methods**:
|
||||
- No Chinese commit messages
|
||||
- No `Out-File -Encoding utf8` (adds BOM)
|
||||
- No PowerShell here-strings `@"..."@`
|
||||
- No Write tool for temp files (encoding issues)
|
||||
|
||||
## Error Prevention
|
||||
|
||||
1. **Always check staging area first**: Don't commit empty staging area
|
||||
2. **Verify version file is staged**: After updating version, confirm with `git diff --cached --name-only`
|
||||
3. **No --amend after push**: Never amend commits that are already pushed
|
||||
4. **Tag naming conflicts**: Check existing tags before creating new ones
|
||||
5. **Branch protection**: Never force push to main/master without explicit user request
|
||||
6. **Sensitive data**: Never commit secrets, API keys, or credentials
|
||||
|
||||
## Integration with CI/CD
|
||||
|
||||
- **Tag annotations**: Used as Release notes
|
||||
- **Version consistency**: Git tag must match version file
|
||||
- **Automated releases**: Tags trigger CI/CD pipelines
|
||||
- **Semantic versioning**: CI/CD determines release type from version bump
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**Check status:**
|
||||
```bash
|
||||
git status
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
**Commit with tag:**
|
||||
```bash
|
||||
git commit -m "feat: add feature"
|
||||
git tag -a "1.2.0" -m "feat: add feature"
|
||||
git push origin main && git push origin 1.2.0
|
||||
```
|
||||
|
||||
**Push all tags:**
|
||||
```bash
|
||||
git push --tags
|
||||
```
|
||||
|
||||
**View recent history:**
|
||||
```bash
|
||||
git log --oneline -10
|
||||
git tag --list | sort -V | tail -5
|
||||
```
|
||||
|
||||
**View changes:**
|
||||
```bash
|
||||
git diff # unstaged changes
|
||||
git diff --cached # staged changes
|
||||
git diff main..feature # compare branches
|
||||
```
|
||||
663
skill/git/quick-reference.md
Normal file
663
skill/git/quick-reference.md
Normal file
@@ -0,0 +1,663 @@
|
||||
# Git Quick Reference
|
||||
|
||||
Quick reference guide for common Git operations.
|
||||
|
||||
## File Changes and Status
|
||||
|
||||
### View Changed Files
|
||||
|
||||
```bash
|
||||
# Show working directory status
|
||||
git status
|
||||
|
||||
# Show short status
|
||||
git status -s
|
||||
|
||||
# List changed files only (unstaged)
|
||||
git diff --name-only
|
||||
|
||||
# List changed files only (staged)
|
||||
git diff --cached --name-only
|
||||
# or
|
||||
git diff --staged --name-only
|
||||
|
||||
# Show file change statistics
|
||||
git diff --stat
|
||||
git diff --cached --stat
|
||||
```
|
||||
|
||||
### View Detailed Changes
|
||||
|
||||
```bash
|
||||
# View unstaged changes
|
||||
git diff
|
||||
|
||||
# View staged changes
|
||||
git diff --cached
|
||||
# or
|
||||
git diff --staged
|
||||
|
||||
# View specific file changes
|
||||
git diff <file-path>
|
||||
git diff --cached <file-path>
|
||||
|
||||
# View changes between commits
|
||||
git diff <commit1>..<commit2>
|
||||
git diff HEAD~1..HEAD
|
||||
|
||||
# View changes between branches
|
||||
git diff main..feature-branch
|
||||
```
|
||||
|
||||
## Staging and Committing
|
||||
|
||||
### Add Files to Staging
|
||||
|
||||
```bash
|
||||
# Add specific file
|
||||
git add <file-path>
|
||||
|
||||
# Add all files in directory
|
||||
git add .
|
||||
|
||||
# Add all files in repository
|
||||
git add -A
|
||||
|
||||
# Add files interactively
|
||||
git add -p
|
||||
|
||||
# Add only modified files (not new files)
|
||||
git add -u
|
||||
```
|
||||
|
||||
### Check Staging Area
|
||||
|
||||
```bash
|
||||
# List files in staging area
|
||||
git diff --cached --name-only
|
||||
|
||||
# Show detailed staged changes
|
||||
git diff --cached
|
||||
```
|
||||
|
||||
### Commit Changes
|
||||
|
||||
```bash
|
||||
# Simple commit
|
||||
git commit -m "feat: add user authentication"
|
||||
|
||||
# Multi-line commit (macOS/Linux)
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat: add user authentication
|
||||
|
||||
- Add OAuth2 support
|
||||
- Implement JWT tokens
|
||||
- Add login/logout endpoints
|
||||
EOF
|
||||
)"
|
||||
|
||||
# Multi-line commit (Windows)
|
||||
git commit -m "feat: add user authentication" \
|
||||
-m "" \
|
||||
-m "- Add OAuth2 support" \
|
||||
-m "- Implement JWT tokens" \
|
||||
-m "- Add login/logout endpoints"
|
||||
|
||||
# Commit with automatic staging
|
||||
git commit -am "fix: resolve issue"
|
||||
|
||||
# Amend last commit (before push only!)
|
||||
git commit --amend -m "new message"
|
||||
```
|
||||
|
||||
## Tag Management
|
||||
|
||||
### Create Tags
|
||||
|
||||
```bash
|
||||
# Create annotated tag
|
||||
git tag -a "1.2.0" -m "feat: add new feature"
|
||||
|
||||
# Create lightweight tag
|
||||
git tag "1.2.0"
|
||||
|
||||
# Create tag with multi-line message
|
||||
git tag -a "1.2.1" \
|
||||
-m "fix: resolve connection issue" \
|
||||
-m "" \
|
||||
-m "- Increase timeout to 30s" \
|
||||
-m "- Add retry mechanism"
|
||||
|
||||
# Create tag for specific commit
|
||||
git tag -a "1.2.0" <commit-hash> -m "message"
|
||||
|
||||
# Monorepo tag
|
||||
git tag -a "ios-1.2.0" -m "feat(ios): add feature"
|
||||
```
|
||||
|
||||
### List Tags
|
||||
|
||||
```bash
|
||||
# List all tags
|
||||
git tag
|
||||
|
||||
# List tags with pattern
|
||||
git tag -l "v1.*"
|
||||
|
||||
# List recent tags (sorted)
|
||||
git tag --list | sort -V | tail -5
|
||||
|
||||
# Show tag details
|
||||
git show <tag-name>
|
||||
```
|
||||
|
||||
### Push Tags
|
||||
|
||||
```bash
|
||||
# Push single tag
|
||||
git push origin <tag-name>
|
||||
|
||||
# Push all tags
|
||||
git push --tags
|
||||
# or
|
||||
git push origin --tags
|
||||
|
||||
# Push commit and tag together
|
||||
git push origin main && git push origin 1.2.0
|
||||
```
|
||||
|
||||
### Delete Tags
|
||||
|
||||
```bash
|
||||
# Delete local tag
|
||||
git tag -d <tag-name>
|
||||
|
||||
# Delete remote tag
|
||||
git push origin --delete <tag-name>
|
||||
# or
|
||||
git push origin :refs/tags/<tag-name>
|
||||
|
||||
# Delete multiple tags
|
||||
git tag -d tag1 tag2 tag3
|
||||
```
|
||||
|
||||
## Branch Operations
|
||||
|
||||
### View Branches
|
||||
|
||||
```bash
|
||||
# Show current branch
|
||||
git branch --show-current
|
||||
|
||||
# List local branches
|
||||
git branch
|
||||
|
||||
# List all branches (local + remote)
|
||||
git branch -a
|
||||
|
||||
# List remote branches only
|
||||
git branch -r
|
||||
|
||||
# Show branch with last commit
|
||||
git branch -v
|
||||
```
|
||||
|
||||
### Create and Switch Branches
|
||||
|
||||
```bash
|
||||
# Create new branch
|
||||
git branch <branch-name>
|
||||
|
||||
# Create and switch to new branch (old way)
|
||||
git checkout -b <branch-name>
|
||||
|
||||
# Create and switch to new branch (modern)
|
||||
git switch -c <branch-name>
|
||||
|
||||
# Switch to existing branch (old way)
|
||||
git checkout <branch-name>
|
||||
|
||||
# Switch to existing branch (modern)
|
||||
git switch <branch-name>
|
||||
|
||||
# Switch to previous branch
|
||||
git switch -
|
||||
```
|
||||
|
||||
### Delete Branches
|
||||
|
||||
```bash
|
||||
# Delete local branch (safe)
|
||||
git branch -d <branch-name>
|
||||
|
||||
# Delete local branch (force)
|
||||
git branch -D <branch-name>
|
||||
|
||||
# Delete remote branch
|
||||
git push origin --delete <branch-name>
|
||||
# or
|
||||
git push origin :<branch-name>
|
||||
```
|
||||
|
||||
## Pushing and Pulling
|
||||
|
||||
### Push Changes
|
||||
|
||||
```bash
|
||||
# Push current branch
|
||||
git push
|
||||
|
||||
# Push to specific remote and branch
|
||||
git push origin main
|
||||
|
||||
# Push current branch to remote
|
||||
git push origin $(git branch --show-current)
|
||||
|
||||
# Push with upstream tracking
|
||||
git push -u origin <branch-name>
|
||||
|
||||
# Push all branches
|
||||
git push --all
|
||||
|
||||
# Push all tags
|
||||
git push --tags
|
||||
|
||||
# Force push (dangerous!)
|
||||
git push --force
|
||||
# Better: force push with lease
|
||||
git push --force-with-lease
|
||||
```
|
||||
|
||||
### Pull Changes
|
||||
|
||||
```bash
|
||||
# Pull from tracked remote
|
||||
git pull
|
||||
|
||||
# Pull from specific remote and branch
|
||||
git pull origin main
|
||||
|
||||
# Pull with rebase
|
||||
git pull --rebase
|
||||
|
||||
# Pull and prune deleted remote branches
|
||||
git pull --prune
|
||||
```
|
||||
|
||||
### Fetch Changes
|
||||
|
||||
```bash
|
||||
# Fetch from all remotes
|
||||
git fetch
|
||||
|
||||
# Fetch from specific remote
|
||||
git fetch origin
|
||||
|
||||
# Fetch and prune deleted remote branches
|
||||
git fetch --prune
|
||||
|
||||
# Fetch all branches and tags
|
||||
git fetch --all --tags
|
||||
```
|
||||
|
||||
## History and Logs
|
||||
|
||||
### View Commit History
|
||||
|
||||
```bash
|
||||
# View recent commits
|
||||
git log
|
||||
|
||||
# View compact history
|
||||
git log --oneline
|
||||
|
||||
# View recent 10 commits
|
||||
git log --oneline -10
|
||||
|
||||
# View history with graph
|
||||
git log --graph --oneline --all
|
||||
|
||||
# View history with stats
|
||||
git log --stat
|
||||
|
||||
# View history with patches
|
||||
git log -p
|
||||
```
|
||||
|
||||
### Search History
|
||||
|
||||
```bash
|
||||
# Search commits by message
|
||||
git log --grep="feature"
|
||||
|
||||
# Search by author
|
||||
git log --author="John"
|
||||
|
||||
# Search by date
|
||||
git log --since="2024-01-01"
|
||||
git log --after="2 weeks ago"
|
||||
git log --before="yesterday"
|
||||
|
||||
# Search by file
|
||||
git log -- <file-path>
|
||||
|
||||
# Search code changes
|
||||
git log -S "function_name"
|
||||
```
|
||||
|
||||
### View Commit Details
|
||||
|
||||
```bash
|
||||
# Show specific commit
|
||||
git show <commit-hash>
|
||||
|
||||
# Show specific tag
|
||||
git show <tag-name>
|
||||
|
||||
# Show HEAD commit
|
||||
git show HEAD
|
||||
|
||||
# Show previous commit
|
||||
git show HEAD~1
|
||||
git show HEAD^
|
||||
```
|
||||
|
||||
## Undoing Changes
|
||||
|
||||
### Discard Changes
|
||||
|
||||
```bash
|
||||
# Discard unstaged changes in file
|
||||
git checkout -- <file-path>
|
||||
# or (modern)
|
||||
git restore <file-path>
|
||||
|
||||
# Discard all unstaged changes
|
||||
git checkout -- .
|
||||
# or (modern)
|
||||
git restore .
|
||||
|
||||
# Unstage file (keep changes)
|
||||
git reset HEAD <file-path>
|
||||
# or (modern)
|
||||
git restore --staged <file-path>
|
||||
|
||||
# Unstage all files
|
||||
git reset HEAD
|
||||
# or (modern)
|
||||
git restore --staged .
|
||||
```
|
||||
|
||||
### Reset Commits
|
||||
|
||||
```bash
|
||||
# Undo last commit, keep changes staged
|
||||
git reset --soft HEAD~1
|
||||
|
||||
# Undo last commit, keep changes unstaged
|
||||
git reset HEAD~1
|
||||
# or
|
||||
git reset --mixed HEAD~1
|
||||
|
||||
# Undo last commit, discard changes (dangerous!)
|
||||
git reset --hard HEAD~1
|
||||
|
||||
# Reset to specific commit
|
||||
git reset --hard <commit-hash>
|
||||
```
|
||||
|
||||
### Revert Commits
|
||||
|
||||
```bash
|
||||
# Create new commit that undoes a commit
|
||||
git revert <commit-hash>
|
||||
|
||||
# Revert without committing
|
||||
git revert -n <commit-hash>
|
||||
|
||||
# Revert multiple commits
|
||||
git revert <commit1>..<commit2>
|
||||
```
|
||||
|
||||
## Stash Operations
|
||||
|
||||
### Save Changes
|
||||
|
||||
```bash
|
||||
# Stash current changes
|
||||
git stash
|
||||
|
||||
# Stash with message
|
||||
git stash save "work in progress"
|
||||
|
||||
# Stash including untracked files
|
||||
git stash -u
|
||||
|
||||
# Stash including untracked and ignored files
|
||||
git stash -a
|
||||
```
|
||||
|
||||
### Apply Stash
|
||||
|
||||
```bash
|
||||
# Apply most recent stash
|
||||
git stash apply
|
||||
|
||||
# Apply and remove from stash list
|
||||
git stash pop
|
||||
|
||||
# Apply specific stash
|
||||
git stash apply stash@{2}
|
||||
```
|
||||
|
||||
### Manage Stash
|
||||
|
||||
```bash
|
||||
# List all stashes
|
||||
git stash list
|
||||
|
||||
# Show stash changes
|
||||
git stash show
|
||||
git stash show -p
|
||||
|
||||
# Drop specific stash
|
||||
git stash drop stash@{1}
|
||||
|
||||
# Clear all stashes
|
||||
git stash clear
|
||||
```
|
||||
|
||||
## Remote Operations
|
||||
|
||||
### View Remotes
|
||||
|
||||
```bash
|
||||
# List remotes
|
||||
git remote
|
||||
|
||||
# List remotes with URLs
|
||||
git remote -v
|
||||
|
||||
# Show remote details
|
||||
git remote show origin
|
||||
```
|
||||
|
||||
### Manage Remotes
|
||||
|
||||
```bash
|
||||
# Add remote
|
||||
git remote add <name> <url>
|
||||
|
||||
# Remove remote
|
||||
git remote remove <name>
|
||||
|
||||
# Rename remote
|
||||
git remote rename <old-name> <new-name>
|
||||
|
||||
# Change remote URL
|
||||
git remote set-url <name> <new-url>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### View Configuration
|
||||
|
||||
```bash
|
||||
# View all config
|
||||
git config --list
|
||||
|
||||
# View global config
|
||||
git config --global --list
|
||||
|
||||
# View local config
|
||||
git config --local --list
|
||||
|
||||
# View specific config
|
||||
git config user.name
|
||||
git config user.email
|
||||
```
|
||||
|
||||
### Set Configuration
|
||||
|
||||
```bash
|
||||
# Set user name
|
||||
git config --global user.name "Your Name"
|
||||
|
||||
# Set user email
|
||||
git config --global user.email "your.email@example.com"
|
||||
|
||||
# Set default branch name
|
||||
git config --global init.defaultBranch main
|
||||
|
||||
# Set default editor
|
||||
git config --global core.editor "code --wait"
|
||||
|
||||
# Set credential helper
|
||||
git config --global credential.helper store
|
||||
```
|
||||
|
||||
## Workflow Examples
|
||||
|
||||
### Standard Commit and Tag Workflow
|
||||
|
||||
```bash
|
||||
# 1. Check status
|
||||
git status
|
||||
git diff --cached --name-only
|
||||
|
||||
# 2. Stage changes
|
||||
git add .
|
||||
|
||||
# 3. Commit
|
||||
git commit -m "feat: add user authentication"
|
||||
|
||||
# 4. Create tag
|
||||
git tag -a "1.2.0" -m "feat: add user authentication"
|
||||
|
||||
# 5. Push commit and tag
|
||||
git push origin main
|
||||
git push origin 1.2.0
|
||||
```
|
||||
|
||||
### Complete Staging to Push Workflow
|
||||
|
||||
```bash
|
||||
# Check what files changed
|
||||
git status
|
||||
|
||||
# View changes
|
||||
git diff
|
||||
|
||||
# Stage specific files
|
||||
git add src/auth.js src/api.js
|
||||
|
||||
# Verify staging
|
||||
git diff --cached --name-only
|
||||
|
||||
# Commit with message
|
||||
git commit -m "feat: implement OAuth2 authentication"
|
||||
|
||||
# Push to remote
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Push All Tags Workflow
|
||||
|
||||
```bash
|
||||
# List local tags
|
||||
git tag
|
||||
|
||||
# View recent tags
|
||||
git tag --list | sort -V | tail -5
|
||||
|
||||
# Push all tags to remote
|
||||
git push --tags
|
||||
|
||||
# Verify tags on remote
|
||||
git ls-remote --tags origin
|
||||
```
|
||||
|
||||
### Quick Status Check
|
||||
|
||||
```bash
|
||||
# Full status
|
||||
git status
|
||||
|
||||
# Changed files only
|
||||
git diff --name-only
|
||||
git diff --cached --name-only
|
||||
|
||||
# Recent commits and tags
|
||||
git log --oneline -5
|
||||
git tag --list | sort -V | tail -5
|
||||
|
||||
# Current branch
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
## Tips and Tricks
|
||||
|
||||
### Aliases
|
||||
|
||||
Add to `~/.gitconfig`:
|
||||
|
||||
```ini
|
||||
[alias]
|
||||
st = status
|
||||
co = checkout
|
||||
br = branch
|
||||
ci = commit
|
||||
unstage = restore --staged
|
||||
last = log -1 HEAD
|
||||
lg = log --graph --oneline --all
|
||||
tags = tag -l --sort=-v:refname
|
||||
```
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
git st
|
||||
git co main
|
||||
git lg
|
||||
```
|
||||
|
||||
### Useful One-Liners
|
||||
|
||||
```bash
|
||||
# Delete all merged branches
|
||||
git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
|
||||
|
||||
# View file in specific commit
|
||||
git show <commit>:<file-path>
|
||||
|
||||
# Count commits by author
|
||||
git shortlog -sn
|
||||
|
||||
# Find when a line was changed
|
||||
git blame <file-path>
|
||||
|
||||
# Show what changed in each commit for a file
|
||||
git log -p <file-path>
|
||||
|
||||
# List files in a commit
|
||||
git diff-tree --no-commit-id --name-only -r <commit>
|
||||
```
|
||||
@@ -1,417 +0,0 @@
|
||||
---
|
||||
name: gitea-runner
|
||||
description: Gitea Act Runner configuration guide for macOS ARM64 with host mode, cache optimization, and multi-runner setup
|
||||
---
|
||||
|
||||
# Gitea Act Runner Configuration Skill
|
||||
|
||||
Complete guide for configuring and deploying Gitea Act Runner, optimized for macOS ARM64 (Apple Silicon) host mode.
|
||||
|
||||
## Overview
|
||||
|
||||
Gitea Act Runner is the CI/CD executor for Gitea Actions, compatible with GitHub Actions workflow syntax.
|
||||
|
||||
### Execution Modes
|
||||
|
||||
| Mode | Environment | Use Case | Android SDK |
|
||||
|------|-------------|----------|-------------|
|
||||
| **Host Mode** | Native macOS/Linux | Android/iOS builds, native toolchains | macOS ARM64 supported |
|
||||
| Docker Mode | Linux containers | Cross-platform builds | Linux ARM64 NOT supported |
|
||||
|
||||
**Recommendation**: Use **host mode** for macOS ARM64 runners to leverage native Android SDK support.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### 1. Install act_runner
|
||||
|
||||
```bash
|
||||
# Using Homebrew (recommended)
|
||||
brew install act_runner
|
||||
|
||||
# Or manual download
|
||||
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
|
||||
```
|
||||
|
||||
### 2. Install Development Tools
|
||||
|
||||
```bash
|
||||
# Go (for Go backend builds)
|
||||
brew install go
|
||||
|
||||
# Node.js (for frontend/miniprogram builds)
|
||||
brew install node@22
|
||||
|
||||
# pnpm (package manager)
|
||||
npm install -g pnpm
|
||||
|
||||
# JDK 17 (for Android builds)
|
||||
brew install openjdk@17
|
||||
|
||||
# Docker (for container builds)
|
||||
# Install Docker Desktop from https://docker.com
|
||||
```
|
||||
|
||||
### 3. Install Android SDK (for Android builds)
|
||||
|
||||
```bash
|
||||
# Using Homebrew
|
||||
brew install --cask android-commandlinetools
|
||||
|
||||
# Or manual installation
|
||||
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
|
||||
|
||||
# Accept licenses and install components
|
||||
yes | sdkmanager --licenses
|
||||
sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0"
|
||||
```
|
||||
|
||||
### 4. Configure Environment Variables
|
||||
|
||||
Add to `~/.zshrc` or `~/.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
|
||||
```
|
||||
|
||||
### 5. Verify Environment
|
||||
|
||||
```bash
|
||||
# Verify all tools
|
||||
go version # Go 1.23+
|
||||
node --version # v22.x
|
||||
pnpm --version # Latest
|
||||
java -version # 17+
|
||||
echo $ANDROID_HOME # SDK path
|
||||
docker --version # Latest
|
||||
act_runner --version
|
||||
```
|
||||
|
||||
## Runner Configuration
|
||||
|
||||
### Host Mode Configuration Template
|
||||
|
||||
Create `act_runner_host.yaml`:
|
||||
|
||||
```yaml
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: /path/to/work/dir/.runner
|
||||
capacity: 2 # Concurrent jobs
|
||||
timeout: 3h # Job timeout
|
||||
shutdown_timeout: 30s
|
||||
insecure: false
|
||||
fetch_timeout: 5s
|
||||
fetch_interval: 2s
|
||||
# Labels reflect actual system info for precise workflow matching
|
||||
labels:
|
||||
- "self-hosted:host" # Self-hosted runner
|
||||
- "macOS:host" # Operating system
|
||||
- "ARM64:host" # Architecture
|
||||
- "darwin-arm64:host" # Combined label (recommended for matching)
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "/path/to/work/dir/cache"
|
||||
host: "127.0.0.1" # Local only (use 0.0.0.0 for multi-runner)
|
||||
port: 9000
|
||||
|
||||
host:
|
||||
workdir_parent: "/path/to/work/dir/workspace"
|
||||
```
|
||||
|
||||
### Label Design Guidelines
|
||||
|
||||
| Label | Meaning | Usage |
|
||||
|-------|---------|-------|
|
||||
| `self-hosted` | Self-hosted runner | Distinguish from Gitea-hosted runners |
|
||||
| `macOS` | Operating system | Friendly name for Darwin |
|
||||
| `ARM64` | CPU architecture | Apple Silicon (M1/M2/M3/M4) |
|
||||
| `darwin-arm64` | Combined label | Most precise matching |
|
||||
|
||||
### Workflow Matching Examples
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
# Method 1: Combined label (recommended, most precise)
|
||||
runs-on: darwin-arm64
|
||||
|
||||
# Method 2: Label array (matches multiple conditions)
|
||||
# runs-on: [self-hosted, macOS, ARM64]
|
||||
|
||||
# Method 3: OS only
|
||||
# runs-on: macOS
|
||||
```
|
||||
|
||||
## Registration & Startup
|
||||
|
||||
### 1. Get Registration Token
|
||||
|
||||
```bash
|
||||
# Organization level (global runner, recommended)
|
||||
curl -H "Authorization: token YOUR_GITEA_TOKEN" \
|
||||
"https://your-gitea.com/api/v1/orgs/ORG_NAME/actions/runners/registration-token"
|
||||
|
||||
# Or repository level
|
||||
curl -H "Authorization: token YOUR_GITEA_TOKEN" \
|
||||
"https://your-gitea.com/api/v1/repos/OWNER/REPO/actions/runners/registration-token"
|
||||
```
|
||||
|
||||
### 2. Register Runner
|
||||
|
||||
```bash
|
||||
act_runner register \
|
||||
--config act_runner_host.yaml \
|
||||
--instance https://your-gitea.com/ \
|
||||
--token YOUR_REGISTRATION_TOKEN \
|
||||
--name "your-runner-name" \
|
||||
--labels "self-hosted:host,macOS:host,ARM64:host,darwin-arm64:host" \
|
||||
--no-interactive
|
||||
```
|
||||
|
||||
### 3. Start Runner
|
||||
|
||||
```bash
|
||||
# Foreground (for debugging)
|
||||
act_runner daemon --config act_runner_host.yaml
|
||||
|
||||
# Background
|
||||
nohup act_runner daemon --config act_runner_host.yaml > runner.log 2>&1 &
|
||||
|
||||
# Using brew services (recommended for persistence)
|
||||
brew services start act_runner
|
||||
```
|
||||
|
||||
## Multi-Runner Cache Sharing
|
||||
|
||||
### Option A: Master-Slave Mode (Recommended for 2-3 runners)
|
||||
|
||||
**Primary Runner (cache server)**:
|
||||
```yaml
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "/Users/voson/work/gitea/cache"
|
||||
host: "0.0.0.0" # Listen on all interfaces
|
||||
port: 9000
|
||||
```
|
||||
|
||||
**Secondary Runner (cache client)**:
|
||||
```yaml
|
||||
cache:
|
||||
enabled: true
|
||||
server: "http://192.168.0.103:9000" # Primary runner IP
|
||||
dir: "/Users/user/work/gitea/cache" # Local fallback
|
||||
host: "192.168.0.104" # This runner's IP
|
||||
port: 9000
|
||||
```
|
||||
|
||||
### Option B: NFS Shared Storage (Enterprise)
|
||||
|
||||
**1. Setup NFS server on primary runner:**
|
||||
```bash
|
||||
# /etc/exports
|
||||
/Users/voson/work/gitea/cache -alldirs -mapall=$(id -u):$(id -g) 192.168.0.0/24
|
||||
|
||||
sudo nfsd restart
|
||||
```
|
||||
|
||||
**2. Mount on secondary runner:**
|
||||
```bash
|
||||
sudo mkdir -p /mnt/runner-cache
|
||||
sudo mount -t nfs 192.168.0.103:/Users/voson/work/gitea/cache /mnt/runner-cache
|
||||
```
|
||||
|
||||
### Option C: Independent Cache (Default)
|
||||
|
||||
Each runner maintains its own cache. First build downloads dependencies, subsequent builds use local cache.
|
||||
|
||||
## Cache Management
|
||||
|
||||
### Host Mode Cache Locations
|
||||
|
||||
| Cache Type | Location | Behavior |
|
||||
|------------|----------|----------|
|
||||
| Runner cache service | `config.cache.dir` | Managed by act_runner |
|
||||
| Gradle | `~/.gradle/` | Persistent across builds |
|
||||
| npm/pnpm | `~/.npm/`, `~/.pnpm-store/` | Persistent across builds |
|
||||
| Go modules | `~/go/pkg/mod/` | Persistent across builds |
|
||||
|
||||
### Cache Cleanup Script
|
||||
|
||||
Create `cleanup-cache.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Cleaning up caches..."
|
||||
|
||||
# 1. Runner cache (older than 7 days)
|
||||
find /path/to/cache/cache -type f -mtime +7 -delete 2>/dev/null || true
|
||||
|
||||
# 2. Gradle cache (older than 30 days)
|
||||
find ~/.gradle/caches -type f -mtime +30 -delete 2>/dev/null || true
|
||||
find ~/.gradle/caches -type d -empty -delete 2>/dev/null || true
|
||||
|
||||
# 3. npm cache verification
|
||||
npm cache verify
|
||||
|
||||
# 4. Workspace cleanup
|
||||
find /path/to/workspace -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \; 2>/dev/null || true
|
||||
|
||||
echo "Cleanup complete!"
|
||||
echo "Runner cache: $(du -sh /path/to/cache/ | awk '{print $1}')"
|
||||
echo "Gradle cache: $(du -sh ~/.gradle/ | awk '{print $1}')"
|
||||
```
|
||||
|
||||
### Schedule Cleanup
|
||||
|
||||
```bash
|
||||
# Add to crontab for weekly cleanup
|
||||
crontab -e
|
||||
# Add: 0 3 * * 0 /path/to/cleanup-cache.sh >> /path/to/cleanup.log 2>&1
|
||||
```
|
||||
|
||||
## Management Commands
|
||||
|
||||
```bash
|
||||
# Check runner status
|
||||
ps aux | grep act_runner
|
||||
|
||||
# View logs
|
||||
tail -f /path/to/runner.log
|
||||
|
||||
# Stop runner
|
||||
pkill -f "act_runner daemon"
|
||||
|
||||
# Re-register (stop first, delete .runner file)
|
||||
rm /path/to/.runner
|
||||
act_runner register --config act_runner_host.yaml ...
|
||||
|
||||
# Check Gitea connection
|
||||
curl -s https://your-gitea.com/api/v1/version
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 1. Android SDK Not Found
|
||||
|
||||
```bash
|
||||
# Verify ANDROID_HOME
|
||||
echo $ANDROID_HOME
|
||||
ls $ANDROID_HOME
|
||||
|
||||
# Check if runner can access SDK
|
||||
# Ensure runner runs as the same user who installed SDK
|
||||
```
|
||||
|
||||
### 2. JDK Version Error
|
||||
|
||||
Android Gradle Plugin 8.x requires JDK 17+:
|
||||
```bash
|
||||
java -version
|
||||
# Should show: openjdk version "17.x.x"
|
||||
|
||||
# If wrong version, update JAVA_HOME
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@17
|
||||
```
|
||||
|
||||
### 3. Permission Issues
|
||||
|
||||
```bash
|
||||
# Ensure runner user owns work directories
|
||||
chown -R $(whoami) /path/to/work/dir
|
||||
chmod -R 755 /path/to/work/dir
|
||||
```
|
||||
|
||||
### 4. Label Mismatch
|
||||
|
||||
```bash
|
||||
# Check registered labels
|
||||
cat /path/to/.runner | jq '.labels'
|
||||
|
||||
# Ensure workflow runs-on matches
|
||||
# Workflow: runs-on: darwin-arm64
|
||||
# Runner: "darwin-arm64:host" label
|
||||
```
|
||||
|
||||
### 5. Cache Service Port Conflict
|
||||
|
||||
```bash
|
||||
# Check if port 9000 is in use
|
||||
lsof -i :9000
|
||||
|
||||
# Use different port if needed
|
||||
# In config: port: 9001
|
||||
```
|
||||
|
||||
## Docker Mode Configuration (Alternative)
|
||||
|
||||
For container-based builds:
|
||||
|
||||
```yaml
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: /path/to/.runner
|
||||
capacity: 2
|
||||
timeout: 3h
|
||||
labels:
|
||||
- "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"
|
||||
- "ubuntu-22.04:docker://catthehacker/ubuntu:act-latest"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: "/path/to/cache"
|
||||
host: "192.168.0.103" # Host IP (not 127.0.0.1 for containers)
|
||||
port: 9000
|
||||
|
||||
container:
|
||||
options: "--platform=linux/amd64" # For ARM64 host running x86 images
|
||||
network: "host"
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Task | Command |
|
||||
|------|---------|
|
||||
| Install runner | `brew install act_runner` |
|
||||
| Register | `act_runner register --config ... --instance ... --token ...` |
|
||||
| Start | `act_runner daemon --config act_runner_host.yaml` |
|
||||
| Stop | `pkill -f "act_runner daemon"` |
|
||||
| Check status | `ps aux \| grep act_runner` |
|
||||
| View logs | `tail -f runner.log` |
|
||||
| Re-register | `rm .runner && act_runner register ...` |
|
||||
|
||||
## Related Resources
|
||||
|
||||
- [Gitea Act Runner Documentation](https://docs.gitea.com/usage/actions/act-runner)
|
||||
- [Android SDK Command Line Tools](https://developer.android.com/studio/command-line)
|
||||
- [GitHub Actions Workflow Syntax](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions)
|
||||
|
||||
## Version
|
||||
|
||||
- **Skill Version**: 1.0
|
||||
- **Last Updated**: 2026-01-12
|
||||
- **Compatibility**: act_runner 0.2.13+, macOS ARM64
|
||||
@@ -1,383 +0,0 @@
|
||||
---
|
||||
name: gitea-workflow
|
||||
description: Gitea Actions Workflow foundation and templates for various project types with CI/CD best practices
|
||||
---
|
||||
|
||||
# Gitea Actions Workflow Skill
|
||||
|
||||
Gitea Actions workflow 基础知识和项目模板指南,兼容 GitHub Actions 语法。
|
||||
|
||||
## 概述
|
||||
|
||||
Gitea Actions workflows 定义在 `.gitea/workflows/*.yml` 文件中。本 skill 提供:
|
||||
- Workflow 基础结构和通用组件
|
||||
- 各项目类型的骨架模板(用户按需填充具体构建逻辑)
|
||||
|
||||
## 项目类型模板
|
||||
|
||||
| 类型 | 文档 | 适用场景 |
|
||||
|------|------|---------|
|
||||
| Go 后端 | [go-backend.md](./go-backend.md) | API 服务、微服务、CLI 工具 |
|
||||
| Node.js 前端 | [nodejs-frontend.md](./nodejs-frontend.md) | React/Vue/Vite/Next.js |
|
||||
| Android 应用 | [android-app.md](./android-app.md) | Kotlin/Java/Jetpack Compose |
|
||||
| 微信小程序 | [wechat-miniprogram.md](./wechat-miniprogram.md) | 微信小程序 CI/CD |
|
||||
|
||||
---
|
||||
|
||||
## Workflow 基础结构
|
||||
|
||||
### 文件位置
|
||||
|
||||
```
|
||||
project/
|
||||
├── .gitea/
|
||||
│ └── workflows/
|
||||
│ ├── backend.yml
|
||||
│ ├── frontend.yml
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Service Name - Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'service-dir/**' # 仅相关目录变更时触发
|
||||
- '.gitea/workflows/this-workflow.yml'
|
||||
tags:
|
||||
- 'service-prefix-*' # Tag 触发 Release
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true # 取消同分支旧的运行
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: service-name # 服务标识
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: darwin-arm64 # Runner 标签
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
version: ${{ steps.vars.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # 完整历史(用于 git describe)
|
||||
|
||||
# ... 构建步骤
|
||||
|
||||
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 点
|
||||
```
|
||||
|
||||
### 并发控制
|
||||
|
||||
```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` |
|
||||
|
||||
### 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/
|
||||
```
|
||||
|
||||
### 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 }}/${{ github.repository_owner }}/image:latest
|
||||
${{ env.registry }}/${{ github.repository_owner }}/image:${{ env.git_tag }}
|
||||
cache-from: type=registry,ref=image:buildcache
|
||||
cache-to: type=registry,ref=image:buildcache,mode=max
|
||||
```
|
||||
|
||||
### 通知 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 的项目 |
|
||||
|
||||
### 项目特定 Secrets
|
||||
|
||||
参考各项目类型子文档。
|
||||
|
||||
### 安全最佳实践
|
||||
|
||||
1. **不要在日志中打印 secrets**
|
||||
2. **使用 `vars.` 存储非敏感变量**(如用户名、URL)
|
||||
3. **secrets 仅用于敏感信息**(如密码、密钥)
|
||||
4. **定期轮换密钥**
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 路径过滤
|
||||
|
||||
仅相关文件变更时触发,避免无关构建:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/**'
|
||||
- '.gitea/workflows/backend.yml'
|
||||
```
|
||||
|
||||
### 2. Tag 命名规范
|
||||
|
||||
使用前缀区分不同服务:
|
||||
|
||||
```bash
|
||||
git tag server-1.0.0 && git push origin server-1.0.0
|
||||
git tag web-1.0.0 && git push origin web-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()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 快速参考
|
||||
|
||||
| 任务 | 命令/语法 |
|
||||
|------|----------|
|
||||
| 获取 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. **选择项目类型**:参考上方索引表,选择对应的子文档
|
||||
2. **复制骨架模板**:将模板复制到 `.gitea/workflows/`
|
||||
3. **填充构建逻辑**:根据项目需求填充 `# 用户自定义` 部分
|
||||
4. **配置 Secrets**:在 Gitea 中配置所需的 Secrets
|
||||
5. **推送触发**:推送代码或 Tag 触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本
|
||||
|
||||
- **Skill Version**: 2.0
|
||||
- **Last Updated**: 2026-01-12
|
||||
- **Structure**: 主文档 + 4 个项目类型子文档
|
||||
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 的所有模板
|
||||
Reference in New Issue
Block a user