mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-07 13:00:59 +08:00
Merge pull request #292 from hzb1115/dev
aaafix(workflow): fix github workflow
This commit is contained in:
322
.github/PR_TITLE_GUIDE.md
vendored
Normal file
322
.github/PR_TITLE_GUIDE.md
vendored
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
# PR 标题指南
|
||||||
|
|
||||||
|
## 📋 概述
|
||||||
|
|
||||||
|
我们使用 **Conventional Commits** 格式来保持 PR 标题的一致性,但这是**建议性的**,不会阻止你的 PR 被合并。
|
||||||
|
|
||||||
|
## ✅ 推荐格式
|
||||||
|
|
||||||
|
```
|
||||||
|
type(scope): description
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(trader): add new trading strategy
|
||||||
|
fix(api): resolve authentication issue
|
||||||
|
docs: update README
|
||||||
|
chore(deps): update dependencies
|
||||||
|
ci(workflow): improve GitHub Actions
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 详细说明
|
||||||
|
|
||||||
|
### Type(类型)- 必需
|
||||||
|
|
||||||
|
描述这次变更的类型:
|
||||||
|
|
||||||
|
| Type | 说明 | 示例 |
|
||||||
|
|------|------|------|
|
||||||
|
| `feat` | 新功能 | `feat(trader): add stop-loss feature` |
|
||||||
|
| `fix` | Bug 修复 | `fix(api): handle null response` |
|
||||||
|
| `docs` | 文档变更 | `docs: update installation guide` |
|
||||||
|
| `style` | 代码格式(不影响代码运行) | `style: format code with prettier` |
|
||||||
|
| `refactor` | 重构(既不是新功能也不是修复) | `refactor(exchange): simplify connection logic` |
|
||||||
|
| `perf` | 性能优化 | `perf(ai): optimize prompt processing` |
|
||||||
|
| `test` | 添加或修改测试 | `test(trader): add unit tests` |
|
||||||
|
| `chore` | 构建过程或辅助工具的变动 | `chore: update dependencies` |
|
||||||
|
| `ci` | CI/CD 相关变更 | `ci: add test coverage report` |
|
||||||
|
| `security` | 安全相关修复 | `security: update vulnerable dependencies` |
|
||||||
|
| `build` | 构建系统或外部依赖项变更 | `build: upgrade webpack to v5` |
|
||||||
|
|
||||||
|
### Scope(范围)- 可选
|
||||||
|
|
||||||
|
描述这次变更影响的范围:
|
||||||
|
|
||||||
|
| Scope | 说明 |
|
||||||
|
|-------|------|
|
||||||
|
| `exchange` | 交易所相关 |
|
||||||
|
| `trader` | 交易员/交易策略 |
|
||||||
|
| `ai` | AI 模型相关 |
|
||||||
|
| `api` | API 接口 |
|
||||||
|
| `ui` | 用户界面 |
|
||||||
|
| `frontend` | 前端代码 |
|
||||||
|
| `backend` | 后端代码 |
|
||||||
|
| `security` | 安全相关 |
|
||||||
|
| `deps` | 依赖项 |
|
||||||
|
| `workflow` | GitHub Actions workflows |
|
||||||
|
| `github` | GitHub 配置 |
|
||||||
|
| `actions` | GitHub Actions |
|
||||||
|
| `config` | 配置文件 |
|
||||||
|
| `docker` | Docker 相关 |
|
||||||
|
| `build` | 构建相关 |
|
||||||
|
| `release` | 发布相关 |
|
||||||
|
|
||||||
|
**注意:** 如果变更影响多个范围,可以省略 scope 或选择最主要的。
|
||||||
|
|
||||||
|
### Description(描述)- 必需
|
||||||
|
|
||||||
|
- 使用现在时态("add" 而不是 "added")
|
||||||
|
- 首字母小写
|
||||||
|
- 结尾不加句号
|
||||||
|
- 简洁明了地描述变更内容
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 完整示例
|
||||||
|
|
||||||
|
### ✅ 好的 PR 标题
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(trader): add risk management system
|
||||||
|
fix(exchange): resolve connection timeout issue
|
||||||
|
docs: add API documentation for trading endpoints
|
||||||
|
style: apply consistent code formatting
|
||||||
|
refactor(ai): simplify prompt processing logic
|
||||||
|
perf(backend): optimize database queries
|
||||||
|
test(api): add integration tests for auth
|
||||||
|
chore(deps): update TypeScript to 5.0
|
||||||
|
ci(workflow): add automated security scanning
|
||||||
|
security(api): fix SQL injection vulnerability
|
||||||
|
build(docker): optimize Docker image size
|
||||||
|
```
|
||||||
|
|
||||||
|
### ⚠️ 需要改进的标题
|
||||||
|
|
||||||
|
| 不好的标题 | 问题 | 改进后 |
|
||||||
|
|-----------|------|--------|
|
||||||
|
| `update code` | 太模糊 | `refactor(trader): simplify order execution logic` |
|
||||||
|
| `Fixed bug` | 首字母大写,不够具体 | `fix(api): handle edge case in login` |
|
||||||
|
| `Add new feature.` | 有句号,不够具体 | `feat(ui): add dark mode toggle` |
|
||||||
|
| `changes` | 完全不符合格式 | `chore: update dependencies` |
|
||||||
|
| `feat: Added new trading algo` | 时态错误 | `feat(trader): add new trading algorithm` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤖 自动检查行为
|
||||||
|
|
||||||
|
### 当 PR 标题不符合格式时
|
||||||
|
|
||||||
|
1. **不会阻止合并** ✅
|
||||||
|
- 检查会标记为"建议"
|
||||||
|
- PR 仍然可以被审查和合并
|
||||||
|
|
||||||
|
2. **会收到友好提示** 💬
|
||||||
|
- 机器人会在 PR 中留言
|
||||||
|
- 提供格式说明和示例
|
||||||
|
- 建议如何改进标题
|
||||||
|
|
||||||
|
3. **可以随时更新** 🔄
|
||||||
|
- 更新 PR 标题后会重新检查
|
||||||
|
- 无需关闭和重新打开 PR
|
||||||
|
|
||||||
|
### 示例评论
|
||||||
|
|
||||||
|
如果你的 PR 标题是 `update workflow`,你会收到这样的评论:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## ⚠️ PR Title Format Suggestion
|
||||||
|
|
||||||
|
Your PR title doesn't follow the Conventional Commits format,
|
||||||
|
but this won't block your PR from being merged.
|
||||||
|
|
||||||
|
**Current title:** `update workflow`
|
||||||
|
|
||||||
|
**Recommended format:** `type(scope): description`
|
||||||
|
|
||||||
|
### Valid types:
|
||||||
|
feat, fix, docs, style, refactor, perf, test, chore, ci, security, build
|
||||||
|
|
||||||
|
### Common scopes (optional):
|
||||||
|
exchange, trader, ai, api, ui, frontend, backend, security, deps,
|
||||||
|
workflow, github, actions, config, docker, build, release
|
||||||
|
|
||||||
|
### Examples:
|
||||||
|
- feat(trader): add new trading strategy
|
||||||
|
- fix(api): resolve authentication issue
|
||||||
|
- docs: update README
|
||||||
|
- chore(deps): update dependencies
|
||||||
|
- ci(workflow): improve GitHub Actions
|
||||||
|
|
||||||
|
**Note:** This is a suggestion to improve consistency.
|
||||||
|
Your PR can still be reviewed and merged.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 配置详情
|
||||||
|
|
||||||
|
### 支持的 Types
|
||||||
|
|
||||||
|
在 `.github/workflows/pr-checks.yml` 中配置:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
types: |
|
||||||
|
feat
|
||||||
|
fix
|
||||||
|
docs
|
||||||
|
style
|
||||||
|
refactor
|
||||||
|
perf
|
||||||
|
test
|
||||||
|
chore
|
||||||
|
ci
|
||||||
|
security
|
||||||
|
build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 支持的 Scopes
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
scopes: |
|
||||||
|
exchange
|
||||||
|
trader
|
||||||
|
ai
|
||||||
|
api
|
||||||
|
ui
|
||||||
|
frontend
|
||||||
|
backend
|
||||||
|
security
|
||||||
|
deps
|
||||||
|
workflow
|
||||||
|
github
|
||||||
|
actions
|
||||||
|
config
|
||||||
|
docker
|
||||||
|
build
|
||||||
|
release
|
||||||
|
```
|
||||||
|
|
||||||
|
### 添加新的 Scope
|
||||||
|
|
||||||
|
如果你需要添加新的 scope,请:
|
||||||
|
|
||||||
|
1. 在 `.github/workflows/pr-checks.yml` 的 `scopes` 部分添加
|
||||||
|
2. 在 `.github/workflows/pr-checks-run.yml` 更新正则表达式(可选)
|
||||||
|
3. 更新本文档
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 为什么使用 Conventional Commits?
|
||||||
|
|
||||||
|
### 优点
|
||||||
|
|
||||||
|
1. **自动化 Changelog** 📝
|
||||||
|
- 可以自动生成版本更新日志
|
||||||
|
- 清晰地分类各种变更
|
||||||
|
|
||||||
|
2. **语义化版本** 🔢
|
||||||
|
- `feat` → MINOR 版本(1.1.0)
|
||||||
|
- `fix` → PATCH 版本(1.0.1)
|
||||||
|
- `BREAKING CHANGE` → MAJOR 版本(2.0.0)
|
||||||
|
|
||||||
|
3. **更好的可读性** 👀
|
||||||
|
- 一眼看出 PR 的目的
|
||||||
|
- 更容易浏览 Git 历史
|
||||||
|
|
||||||
|
4. **团队协作** 🤝
|
||||||
|
- 统一的提交风格
|
||||||
|
- 降低沟通成本
|
||||||
|
|
||||||
|
### 示例:自动生成的 Changelog
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## v1.2.0 (2025-11-02)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- **trader**: add risk management system (#123)
|
||||||
|
- **ui**: add dark mode toggle (#125)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
- **api**: resolve authentication issue (#124)
|
||||||
|
- **exchange**: fix connection timeout (#126)
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- update API documentation (#127)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎓 学习资源
|
||||||
|
|
||||||
|
- **Conventional Commits 官网:** https://www.conventionalcommits.org/
|
||||||
|
- **Angular Commit Guidelines:** https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit
|
||||||
|
- **Semantic Versioning:** https://semver.org/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❓ FAQ
|
||||||
|
|
||||||
|
### Q: 我必须遵循这个格式吗?
|
||||||
|
|
||||||
|
**A:** 不必须。这是建议性的,不会阻止你的 PR 被合并。但遵循格式可以提高项目的可维护性。
|
||||||
|
|
||||||
|
### Q: 如果我忘记了怎么办?
|
||||||
|
|
||||||
|
**A:** 机器人会在 PR 中提醒你,你可以随时更新标题。
|
||||||
|
|
||||||
|
### Q: 我可以在一个 PR 中做多种类型的变更吗?
|
||||||
|
|
||||||
|
**A:** 可以,但建议:
|
||||||
|
- 选择最主要的类型
|
||||||
|
- 或者考虑拆分成多个 PR(更易于审查)
|
||||||
|
|
||||||
|
### Q: Scope 可以省略吗?
|
||||||
|
|
||||||
|
**A:** 可以。`requireScope: false` 表示 scope 是可选的。
|
||||||
|
|
||||||
|
示例:`docs: update README` (没有 scope 也可以)
|
||||||
|
|
||||||
|
### Q: 我想添加新的 type 或 scope,怎么做?
|
||||||
|
|
||||||
|
**A:** 提一个 PR 修改 `.github/workflows/pr-checks.yml`,并在本文档中说明新增项的用途。
|
||||||
|
|
||||||
|
### Q: Breaking Changes 怎么表示?
|
||||||
|
|
||||||
|
**A:** 在描述中添加 `BREAKING CHANGE:` 或在 type 后加 `!`:
|
||||||
|
|
||||||
|
```
|
||||||
|
feat!: remove deprecated API
|
||||||
|
feat(api)!: change authentication method
|
||||||
|
|
||||||
|
BREAKING CHANGE: The old /auth endpoint is removed
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 统计
|
||||||
|
|
||||||
|
想看项目的 commit 类型分布?运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --oneline --no-merges | \
|
||||||
|
grep -oE '^[a-f0-9]+ (feat|fix|docs|style|refactor|perf|test|chore|ci|security|build)' | \
|
||||||
|
cut -d' ' -f2 | sort | uniq -c | sort -rn
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 快速检查清单
|
||||||
|
|
||||||
|
在提交 PR 前,检查你的标题是否:
|
||||||
|
|
||||||
|
- [ ] 包含有效的 type(feat, fix, docs 等)
|
||||||
|
- [ ] 使用小写字母开头
|
||||||
|
- [ ] 使用现在时态("add" 而不是 "added")
|
||||||
|
- [ ] 简洁明了(最好在 50 字符内)
|
||||||
|
- [ ] 准确描述了变更内容
|
||||||
|
|
||||||
|
**记住:** 这些都是建议,不是强制要求!
|
||||||
279
.github/PULL_REQUEST_TEMPLATE.md
vendored
279
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,153 +1,288 @@
|
|||||||
# Pull Request
|
# Pull Request | PR 提交
|
||||||
|
|
||||||
## 📝 Description
|
> **💡 提示 Tip:** 推荐 PR 标题格式 Recommended PR title format: `type(scope): description`
|
||||||
|
> 例如 Examples: `feat(trader): add new strategy` | `fix(api): resolve auth issue`
|
||||||
|
> 详情 Details: [PR Title Guide](./PR_TITLE_GUIDE.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Description | 描述
|
||||||
|
|
||||||
<!-- Provide a brief summary of your changes -->
|
<!-- Provide a brief summary of your changes -->
|
||||||
|
<!-- 简要描述你的变更 -->
|
||||||
|
|
||||||
## 🎯 Type of Change
|
**English:**
|
||||||
|
|
||||||
|
**中文:**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Type of Change | 变更类型
|
||||||
|
|
||||||
<!-- Mark the relevant option with an "x" -->
|
<!-- Mark the relevant option with an "x" -->
|
||||||
|
<!-- 在相关选项上打"x" -->
|
||||||
|
|
||||||
- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
|
- [ ] 🐛 Bug fix | 修复 Bug(不影响现有功能的修复)
|
||||||
- [ ] ✨ New feature (non-breaking change which adds functionality)
|
- [ ] ✨ New feature | 新功能(不影响现有功能的新增)
|
||||||
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
- [ ] 💥 Breaking change | 破坏性变更(会导致现有功能无法正常工作的修复或功能)
|
||||||
- [ ] 📝 Documentation update
|
- [ ] 📝 Documentation update | 文档更新
|
||||||
- [ ] 🎨 Code style update (formatting, renaming)
|
- [ ] 🎨 Code style update | 代码样式更新(格式化、重命名等)
|
||||||
- [ ] ♻️ Refactoring (no functional changes)
|
- [ ] ♻️ Refactoring | 重构(无功能变更)
|
||||||
- [ ] ⚡ Performance improvement
|
- [ ] ⚡ Performance improvement | 性能优化
|
||||||
- [ ] ✅ Test update
|
- [ ] ✅ Test update | 测试更新
|
||||||
- [ ] 🔧 Build/config change
|
- [ ] 🔧 Build/config change | 构建/配置变更
|
||||||
|
- [ ] 🔒 Security fix | 安全修复
|
||||||
|
|
||||||
## 🔗 Related Issues
|
---
|
||||||
|
|
||||||
|
## 🔗 Related Issues | 相关 Issue
|
||||||
|
|
||||||
<!-- Link related issues below. Use "Closes #123" to auto-close issues when PR is merged -->
|
<!-- Link related issues below. Use "Closes #123" to auto-close issues when PR is merged -->
|
||||||
|
<!-- 在下方关联相关 issue。使用 "Closes #123" 可以在 PR 合并时自动关闭 issue -->
|
||||||
|
|
||||||
- Closes #
|
- Closes # | 关闭 #
|
||||||
- Related to #
|
- Related to # | 相关 #
|
||||||
|
|
||||||
## 📋 Changes Made
|
---
|
||||||
|
|
||||||
|
## 📋 Changes Made | 具体变更
|
||||||
|
|
||||||
<!-- List the specific changes you made -->
|
<!-- List the specific changes you made -->
|
||||||
|
<!-- 列出你做的具体变更 -->
|
||||||
|
|
||||||
|
**English:**
|
||||||
- Change 1
|
- Change 1
|
||||||
- Change 2
|
- Change 2
|
||||||
- Change 3
|
- Change 3
|
||||||
|
|
||||||
## 🧪 Testing
|
**中文:**
|
||||||
|
- 变更 1
|
||||||
|
- 变更 2
|
||||||
|
- 变更 3
|
||||||
|
|
||||||
### Manual Testing
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing | 测试
|
||||||
|
|
||||||
|
### Manual Testing | 手动测试
|
||||||
|
|
||||||
<!-- Describe how you tested your changes -->
|
<!-- Describe how you tested your changes -->
|
||||||
|
<!-- 描述你如何测试你的变更 -->
|
||||||
|
|
||||||
- [ ] Tested locally (manual verification)
|
- [ ] Tested locally | 本地测试通过
|
||||||
- [ ] Tested on testnet (for exchange integrations)
|
- [ ] Tested on testnet | 测试网测试通过(交易所集成相关)
|
||||||
- [ ] Tested with different configurations
|
- [ ] Tested with different configurations | 测试了不同配置
|
||||||
- [ ] Verified no existing functionality broke
|
- [ ] Verified no existing functionality broke | 确认没有破坏现有功能
|
||||||
|
|
||||||
### Test Environment
|
### Test Environment | 测试环境
|
||||||
|
|
||||||
- **OS:** [e.g. macOS, Ubuntu]
|
- **OS | 操作系统:** [e.g. macOS, Ubuntu, Windows]
|
||||||
- **Go Version:** [e.g. 1.21.5]
|
- **Go Version | Go 版本:** [e.g. 1.21.5]
|
||||||
- **Exchange:** [if applicable]
|
- **Node Version | Node 版本:** [e.g. 18.x] (if applicable | 如适用)
|
||||||
|
- **Exchange | 交易所:** [if applicable | 如适用]
|
||||||
|
|
||||||
### Test Results
|
### Test Results | 测试结果
|
||||||
|
|
||||||
<!-- Paste relevant test output or describe results -->
|
<!-- Paste relevant test output or describe results -->
|
||||||
|
<!-- 粘贴相关测试输出或描述结果 -->
|
||||||
|
|
||||||
```
|
```
|
||||||
Test output here
|
Test output here | 测试输出
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📸 Screenshots / Demo
|
---
|
||||||
|
|
||||||
|
## 📸 Screenshots / Demo | 截图/演示
|
||||||
|
|
||||||
<!-- If applicable, add screenshots or video demo -->
|
<!-- If applicable, add screenshots or video demo -->
|
||||||
|
<!-- 如适用,添加截图或视频演示 -->
|
||||||
|
|
||||||
<!-- For UI changes, include before/after screenshots -->
|
<!-- For UI changes, include before/after screenshots -->
|
||||||
|
<!-- 对于 UI 变更,包含变更前后的截图 -->
|
||||||
|
|
||||||
**Before:**
|
**Before | 变更前:**
|
||||||
|
|
||||||
|
|
||||||
**After:**
|
**After | 变更后:**
|
||||||
|
|
||||||
|
|
||||||
## ✅ Checklist
|
---
|
||||||
|
|
||||||
|
## ✅ Checklist | 检查清单
|
||||||
|
|
||||||
<!-- Mark completed items with an "x" -->
|
<!-- Mark completed items with an "x" -->
|
||||||
|
<!-- 在已完成的项目上打"x" -->
|
||||||
|
|
||||||
### Code Quality
|
### Code Quality | 代码质量
|
||||||
|
|
||||||
- [ ] My code follows the project's code style ([Contributing Guide](../CONTRIBUTING.md))
|
- [ ] My code follows the project's code style | 我的代码遵循项目代码风格 ([Contributing Guide](../CONTRIBUTING.md))
|
||||||
- [ ] I have performed a self-review of my code
|
- [ ] I have performed a self-review of my code | 我已进行代码自查
|
||||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
- [ ] I have commented my code, particularly in hard-to-understand areas | 我已添加代码注释,特别是难以理解的部分
|
||||||
- [ ] My changes generate no new warnings or errors
|
- [ ] My changes generate no new warnings or errors | 我的变更没有产生新的警告或错误
|
||||||
- [ ] Code compiles successfully (`go build` / `npm run build`)
|
- [ ] Code compiles successfully | 代码编译成功 (`go build` / `npm run build`)
|
||||||
- [ ] I have run `go fmt` (for Go code)
|
- [ ] I have run `go fmt` (for Go code) | 我已运行 `go fmt`(Go 代码)
|
||||||
|
- [ ] I have run `npm run lint` (for frontend code) | 我已运行 `npm run lint`(前端代码)
|
||||||
|
|
||||||
### Testing
|
### Testing | 测试
|
||||||
|
|
||||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
- [ ] I have added tests that prove my fix is effective or that my feature works | 我已添加证明修复有效或功能正常的测试
|
||||||
- [ ] New and existing unit tests pass locally
|
- [ ] New and existing unit tests pass locally | 新旧单元测试在本地通过
|
||||||
- [ ] I have tested on testnet (for trading/exchange changes)
|
- [ ] I have tested on testnet (for trading/exchange changes) | 我已在测试网测试(交易/交易所变更)
|
||||||
|
- [ ] Integration tests pass | 集成测试通过
|
||||||
|
|
||||||
### Documentation
|
### Documentation | 文档
|
||||||
|
|
||||||
- [ ] I have updated the documentation accordingly
|
- [ ] I have updated the documentation accordingly | 我已相应更新文档
|
||||||
- [ ] I have updated the README if needed
|
- [ ] I have updated the README if needed | 我已更新 README(如需要)
|
||||||
- [ ] I have added inline code comments where necessary
|
- [ ] I have added inline code comments where necessary | 我已在必要处添加代码注释
|
||||||
- [ ] I have updated type definitions (for TypeScript changes)
|
- [ ] I have updated type definitions (for TypeScript changes) | 我已更新类型定义(TypeScript 变更)
|
||||||
|
- [ ] I have updated API documentation (if applicable) | 我已更新 API 文档(如适用)
|
||||||
|
|
||||||
### Git
|
### Git
|
||||||
|
|
||||||
- [ ] My commits follow the conventional commits format (`feat:`, `fix:`, etc.)
|
- [ ] My commits follow the conventional commits format | 我的提交遵循 Conventional Commits 格式 (`feat:`, `fix:`, etc.)
|
||||||
- [ ] I have rebased my branch on the latest `dev` branch
|
- [ ] I have rebased my branch on the latest `dev` branch | 我已将分支 rebase 到最新的 `dev` 分支
|
||||||
- [ ] There are no merge conflicts
|
- [ ] There are no merge conflicts | 没有合并冲突
|
||||||
|
- [ ] Commit messages are clear and descriptive | 提交信息清晰明确
|
||||||
|
|
||||||
## 🔒 Security Considerations
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Considerations | 安全考虑
|
||||||
|
|
||||||
<!-- Answer these questions for security-sensitive changes -->
|
<!-- Answer these questions for security-sensitive changes -->
|
||||||
|
<!-- 对于安全敏感的变更,请回答以下问题 -->
|
||||||
|
|
||||||
- [ ] No API keys or secrets are hardcoded
|
- [ ] No API keys or secrets are hardcoded | 没有硬编码 API 密钥或密钥
|
||||||
- [ ] User inputs are properly validated
|
- [ ] User inputs are properly validated | 用户输入已正确验证
|
||||||
- [ ] No SQL injection vulnerabilities introduced
|
- [ ] No SQL injection vulnerabilities introduced | 未引入 SQL 注入漏洞
|
||||||
- [ ] Authentication/authorization properly handled
|
- [ ] No XSS vulnerabilities introduced | 未引入 XSS 漏洞
|
||||||
- [ ] N/A (not security-related)
|
- [ ] Authentication/authorization properly handled | 认证/授权已正确处理
|
||||||
|
- [ ] Sensitive data is encrypted | 敏感数据已加密
|
||||||
|
- [ ] N/A (not security-related) | 不适用(非安全相关)
|
||||||
|
|
||||||
## ⚡ Performance Impact
|
---
|
||||||
|
|
||||||
|
## ⚡ Performance Impact | 性能影响
|
||||||
|
|
||||||
<!-- Describe any performance implications -->
|
<!-- Describe any performance implications -->
|
||||||
|
<!-- 描述任何性能影响 -->
|
||||||
|
|
||||||
- [ ] No significant performance impact
|
- [ ] No significant performance impact | 无显著性能影响
|
||||||
- [ ] Performance improved
|
- [ ] Performance improved | 性能提升
|
||||||
- [ ] Performance may be impacted (explain below)
|
- [ ] Performance may be impacted (explain below) | 性能可能受影响(请在下方说明)
|
||||||
|
|
||||||
<!-- If performance impacted, explain: -->
|
<!-- If performance impacted, explain: -->
|
||||||
|
<!-- 如果性能受影响,请说明: -->
|
||||||
|
|
||||||
## 📚 Additional Notes
|
**English:**
|
||||||
|
|
||||||
|
**中文:**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Internationalization | 国际化
|
||||||
|
|
||||||
|
<!-- For UI/documentation changes -->
|
||||||
|
<!-- 对于 UI/文档变更 -->
|
||||||
|
|
||||||
|
- [ ] All user-facing text supports i18n | 所有面向用户的文本支持国际化
|
||||||
|
- [ ] Both English and Chinese versions provided | 提供了中英文版本
|
||||||
|
- [ ] N/A | 不适用
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Additional Notes | 补充说明
|
||||||
|
|
||||||
<!-- Any additional information for reviewers -->
|
<!-- Any additional information for reviewers -->
|
||||||
|
<!-- 给审查者的任何补充信息 -->
|
||||||
|
|
||||||
|
**English:**
|
||||||
|
|
||||||
|
**中文:**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## For Bounty Claims
|
## 💰 For Bounty Claims | 赏金申请
|
||||||
|
|
||||||
<!-- Fill this section only if claiming a bounty -->
|
<!-- Fill this section only if claiming a bounty -->
|
||||||
|
<!-- 仅在申请赏金时填写此部分 -->
|
||||||
|
|
||||||
- [ ] This PR is for bounty issue #
|
- [ ] This PR is for bounty issue # | 此 PR 用于赏金 issue #
|
||||||
- [ ] All acceptance criteria from the bounty issue are met
|
- [ ] All acceptance criteria from the bounty issue are met | 满足赏金 issue 的所有验收标准
|
||||||
- [ ] I have included a demo video/screenshots
|
- [ ] I have included a demo video/screenshots | 我已包含演示视频/截图
|
||||||
- [ ] I am ready for payment upon merge
|
- [ ] I am ready for payment upon merge | 我准备好在合并后接收付款
|
||||||
|
|
||||||
**Payment Details:** <!-- Discuss privately with maintainers -->
|
**Payment Details | 付款详情:** <!-- Discuss privately with maintainers | 与维护者私下讨论 -->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🙏 Reviewer Notes
|
## 🙏 Reviewer Notes | 审查者注意事项
|
||||||
|
|
||||||
<!-- Optional: anything specific you want reviewers to focus on? -->
|
<!-- Optional: anything specific you want reviewers to focus on? -->
|
||||||
|
<!-- 可选:你希望审查者关注的特定内容? -->
|
||||||
|
|
||||||
|
**English:**
|
||||||
|
|
||||||
|
**中文:**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 PR Size Estimate | PR 大小估计
|
||||||
|
|
||||||
|
<!-- This helps reviewers plan their time -->
|
||||||
|
<!-- 这有助于审查者安排时间 -->
|
||||||
|
|
||||||
|
- [ ] 🟢 Small (< 100 lines) | 小(< 100 行)
|
||||||
|
- [ ] 🟡 Medium (100-500 lines) | 中(100-500 行)
|
||||||
|
- [ ] 🔴 Large (> 500 lines) | 大(> 500 行)
|
||||||
|
|
||||||
|
<!-- For large PRs, consider: -->
|
||||||
|
<!-- 对于大型 PR,考虑: -->
|
||||||
|
<!-- - Breaking into smaller, focused PRs | 拆分为更小、更专注的 PR -->
|
||||||
|
<!-- - Providing a detailed explanation | 提供详细说明 -->
|
||||||
|
<!-- - Highlighting the most important changes | 突出最重要的变更 -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Review Focus Areas | 审查重点
|
||||||
|
|
||||||
|
<!-- Help reviewers know where to focus their attention -->
|
||||||
|
<!-- 帮助审查者了解重点关注的地方 -->
|
||||||
|
|
||||||
|
Please pay special attention to:
|
||||||
|
请特别注意:
|
||||||
|
|
||||||
|
- [ ] Logic changes | 逻辑变更
|
||||||
|
- [ ] Security implications | 安全影响
|
||||||
|
- [ ] Performance optimization | 性能优化
|
||||||
|
- [ ] API changes | API 变更
|
||||||
|
- [ ] Database schema changes | 数据库架构变更
|
||||||
|
- [ ] UI/UX changes | UI/UX 变更
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**By submitting this PR, I confirm that:**
|
**By submitting this PR, I confirm that:**
|
||||||
- [ ] I have read the [Contributing Guidelines](../CONTRIBUTING.md)
|
**提交此 PR,我确认:**
|
||||||
- [ ] I agree to the [Code of Conduct](../CODE_OF_CONDUCT.md)
|
|
||||||
- [ ] My contribution is licensed under the MIT License
|
- [ ] I have read the [Contributing Guidelines](../CONTRIBUTING.md) | 我已阅读[贡献指南](../CONTRIBUTING.md)
|
||||||
|
- [ ] I agree to the [Code of Conduct](../CODE_OF_CONDUCT.md) | 我同意[行为准则](../CODE_OF_CONDUCT.md)
|
||||||
|
- [ ] My contribution is licensed under the MIT License | 我的贡献遵循 MIT 许可证
|
||||||
|
- [ ] I understand this is a voluntary contribution | 我理解这是自愿贡献
|
||||||
|
- [ ] I have the right to submit this code | 我有权提交此代码
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
🌟 感谢你的贡献!Thank you for your contribution!
|
||||||
|
|
||||||
|
贡献者来自世界各地,我们重视每一份贡献。
|
||||||
|
Contributors come from all around the world, and we value every contribution.
|
||||||
|
|
||||||
|
如果你是首次贡献,欢迎加入我们的社区!
|
||||||
|
If this is your first contribution, welcome to our community!
|
||||||
|
|
||||||
|
💬 需要帮助?Feel free to ask questions in:
|
||||||
|
- GitHub Discussions
|
||||||
|
- Discord: [链接 Link]
|
||||||
|
- Telegram: [链接 Link]
|
||||||
|
-->
|
||||||
|
|||||||
176
.github/workflows/README.md
vendored
Normal file
176
.github/workflows/README.md
vendored
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# GitHub Actions Workflows
|
||||||
|
|
||||||
|
This directory contains the GitHub Actions workflows for the NOFX project.
|
||||||
|
|
||||||
|
## 📚 Documentation Index
|
||||||
|
|
||||||
|
- **[README.md](./README.md)** - This file, overview of all workflows
|
||||||
|
- **[PERMISSIONS.md](./PERMISSIONS.md)** - Detailed permission analysis and security model
|
||||||
|
- **[TRIGGERS.md](./TRIGGERS.md)** - Comparison of event triggers (pull_request vs pull_request_target vs workflow_run)
|
||||||
|
- **[FORK_PR_FLOW.md](./FORK_PR_FLOW.md)** - Complete analysis of what happens when a fork PR is submitted
|
||||||
|
- **[FLOW_DIAGRAM.md](./FLOW_DIAGRAM.md)** - Visual flow diagrams and quick reference
|
||||||
|
- **[SECRETS_SCANNING.md](./SECRETS_SCANNING.md)** - Secrets scanning solutions and TruffleHog setup
|
||||||
|
|
||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
**Want to understand how fork PRs work?** → Read [FLOW_DIAGRAM.md](./FLOW_DIAGRAM.md)
|
||||||
|
|
||||||
|
**Need security details?** → Read [PERMISSIONS.md](./PERMISSIONS.md)
|
||||||
|
|
||||||
|
**Confused about triggers?** → Read [TRIGGERS.md](./TRIGGERS.md)
|
||||||
|
|
||||||
|
## PR Check Workflows
|
||||||
|
|
||||||
|
We use a **two-workflow pattern** to safely handle PR checks from both internal and fork PRs:
|
||||||
|
|
||||||
|
### 1. `pr-checks-run.yml` - Execute Checks
|
||||||
|
|
||||||
|
**Trigger:** On pull request (opened, synchronize, reopened)
|
||||||
|
|
||||||
|
**Permissions:** Read-only
|
||||||
|
|
||||||
|
**Purpose:** Executes all PR checks with read-only permissions, making it safe for fork PRs.
|
||||||
|
|
||||||
|
**What it does:**
|
||||||
|
- ✅ Checks PR title format (Conventional Commits)
|
||||||
|
- ✅ Calculates PR size
|
||||||
|
- ✅ Runs backend checks (Go formatting, vet, tests)
|
||||||
|
- ✅ Runs frontend checks (linting, type checking, build)
|
||||||
|
- ✅ Saves all results as artifacts
|
||||||
|
|
||||||
|
**Security:** Safe for fork PRs because it only has read permissions and cannot access secrets or modify the repository.
|
||||||
|
|
||||||
|
### 2. `pr-checks-comment.yml` - Post Results
|
||||||
|
|
||||||
|
**Trigger:** When `pr-checks-run.yml` completes (workflow_run)
|
||||||
|
|
||||||
|
**Permissions:** Write (pull-requests, issues)
|
||||||
|
|
||||||
|
**Purpose:** Posts check results as PR comments, running in the main repository context.
|
||||||
|
|
||||||
|
**What it does:**
|
||||||
|
- ✅ Downloads artifacts from `pr-checks-run.yml`
|
||||||
|
- ✅ Reads check results
|
||||||
|
- ✅ Posts a comprehensive comment to the PR
|
||||||
|
|
||||||
|
**Security:** Safe because:
|
||||||
|
- Runs in the main repository context (not fork context)
|
||||||
|
- Has write permissions but doesn't execute untrusted code
|
||||||
|
- Only reads pre-generated results from artifacts
|
||||||
|
|
||||||
|
### 3. `pr-checks.yml` - Strict Checks
|
||||||
|
|
||||||
|
**Trigger:** On pull request
|
||||||
|
|
||||||
|
**Permissions:** Read + conditional write
|
||||||
|
|
||||||
|
**Purpose:** Runs mandatory checks that must pass before PR can be merged.
|
||||||
|
|
||||||
|
**What it does:**
|
||||||
|
- ✅ Validates PR title (blocks merge if invalid)
|
||||||
|
- ✅ Auto-labels PR based on size and files changed (non-fork only)
|
||||||
|
- ✅ Runs backend tests (Go)
|
||||||
|
- ✅ Runs frontend tests (React/TypeScript)
|
||||||
|
- ✅ Security scanning (Trivy, Gitleaks)
|
||||||
|
|
||||||
|
**Security:**
|
||||||
|
- Fork PRs: Only runs read-only operations (tests, security scans)
|
||||||
|
- Non-fork PRs: Can add labels and comments
|
||||||
|
- Uses `continue-on-error` for operations that may fail on forks
|
||||||
|
|
||||||
|
## Why Two Workflows for PR Checks?
|
||||||
|
|
||||||
|
### The Problem
|
||||||
|
|
||||||
|
When a PR comes from a forked repository:
|
||||||
|
- GitHub restricts `GITHUB_TOKEN` permissions for security
|
||||||
|
- Fork PRs cannot write comments, add labels, or access secrets
|
||||||
|
- This prevents malicious contributors from:
|
||||||
|
- Stealing repository secrets
|
||||||
|
- Modifying workflow files to execute malicious code
|
||||||
|
- Spamming issues/PRs with automated comments
|
||||||
|
|
||||||
|
### The Solution
|
||||||
|
|
||||||
|
**Two-Workflow Pattern:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Fork PR Submitted
|
||||||
|
↓
|
||||||
|
[pr-checks-run.yml]
|
||||||
|
- Runs with read-only permissions
|
||||||
|
- Executes all checks safely
|
||||||
|
- Saves results to artifacts
|
||||||
|
↓
|
||||||
|
[pr-checks-comment.yml]
|
||||||
|
- Triggered by workflow_run
|
||||||
|
- Runs in main repo context (has write permissions)
|
||||||
|
- Downloads artifacts
|
||||||
|
- Posts comment with results
|
||||||
|
```
|
||||||
|
|
||||||
|
This approach:
|
||||||
|
- ✅ Allows fork PRs to run checks
|
||||||
|
- ✅ Safely posts results as comments
|
||||||
|
- ✅ Prevents security vulnerabilities
|
||||||
|
- ✅ Follows GitHub's best practices
|
||||||
|
|
||||||
|
### Can workflow_run Comment on Fork PRs?
|
||||||
|
|
||||||
|
**Yes! ✅ The permissions are sufficient.**
|
||||||
|
|
||||||
|
**Key Understanding:**
|
||||||
|
- `workflow_run` executes in the **base repository** context
|
||||||
|
- Fork PRs exist in the **base repository** (not in the fork)
|
||||||
|
- The base repository's `GITHUB_TOKEN` has write permissions
|
||||||
|
- Therefore, `workflow_run` can comment on fork PRs
|
||||||
|
|
||||||
|
**Security:**
|
||||||
|
- Fork PR code runs in isolated environment (read-only)
|
||||||
|
- Comment workflow doesn't execute fork code
|
||||||
|
- Only reads pre-generated artifact data
|
||||||
|
|
||||||
|
**For detailed permission analysis, see:** [PERMISSIONS.md](./PERMISSIONS.md)
|
||||||
|
|
||||||
|
## Workflow Comparison
|
||||||
|
|
||||||
|
| Workflow | Fork PRs | Write Access | Blocks Merge | Purpose |
|
||||||
|
|----------|----------|--------------|--------------|---------|
|
||||||
|
| `pr-checks-run.yml` | ✅ Yes | ❌ No | ❌ No | Advisory checks |
|
||||||
|
| `pr-checks-comment.yml` | ✅ Yes | ✅ Yes* | ❌ No | Post results |
|
||||||
|
| `pr-checks.yml` | ✅ Yes | ⚠️ Partial | ✅ Yes | Mandatory checks |
|
||||||
|
|
||||||
|
\* Write access only in main repo context, not available to fork PR code
|
||||||
|
|
||||||
|
## File History
|
||||||
|
|
||||||
|
- `pr-checks-advisory.yml.old` - Old advisory workflow that failed on fork PRs (deprecated)
|
||||||
|
- Now replaced by the two-workflow pattern (`pr-checks-run.yml` + `pr-checks-comment.yml`)
|
||||||
|
|
||||||
|
## Testing the Workflows
|
||||||
|
|
||||||
|
### Test with a Fork PR
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Make changes in your fork
|
||||||
|
3. Create a PR to the main repository
|
||||||
|
4. Observe:
|
||||||
|
- `pr-checks-run.yml` runs successfully with read-only access
|
||||||
|
- `pr-checks-comment.yml` posts results as a comment
|
||||||
|
- `pr-checks.yml` runs tests but skips labeling
|
||||||
|
|
||||||
|
### Test with a Branch PR
|
||||||
|
|
||||||
|
1. Create a branch in the main repository
|
||||||
|
2. Make changes
|
||||||
|
3. Create a PR
|
||||||
|
4. Observe:
|
||||||
|
- All workflows run with full permissions
|
||||||
|
- Labels are added automatically
|
||||||
|
- Comments are posted
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [GitHub Actions: Keeping your GitHub Actions and workflows secure Part 1](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)
|
||||||
|
- [Safely posting comments from untrusted workflows](https://securitylab.github.com/research/github-actions-building-blocks/)
|
||||||
|
- [GitHub Actions: workflow_run trigger](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run)
|
||||||
248
.github/workflows/pr-checks-comment.yml
vendored
Normal file
248
.github/workflows/pr-checks-comment.yml
vendored
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
name: PR Checks - Comment
|
||||||
|
|
||||||
|
# This workflow posts ADVISORY check results as comments
|
||||||
|
# Runs in the main repo context with write permissions (SAFE)
|
||||||
|
# Triggered after pr-checks-run.yml completes
|
||||||
|
#
|
||||||
|
# NOTE: PR title and size checks are handled by pr-checks.yml (no duplication)
|
||||||
|
# This workflow only posts backend/frontend advisory check results
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["PR Checks - Run"]
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
# Write permissions - SAFE because runs in main repo context
|
||||||
|
# This token has write access to the base repository
|
||||||
|
# Fork PRs exist in the base repo, so we can comment on them
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
actions: read # Needed to download artifacts
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
comment:
|
||||||
|
name: Post Advisory Check Results
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Only run if the workflow was triggered by a pull_request event
|
||||||
|
if: github.event.workflow_run.event == 'pull_request'
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
id: download-artifacts
|
||||||
|
continue-on-error: true
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run-id: ${{ github.event.workflow_run.id }}
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
- name: Debug workflow run info
|
||||||
|
run: |
|
||||||
|
echo "=== Workflow Run Debug Info ==="
|
||||||
|
echo "Workflow Run ID: ${{ github.event.workflow_run.id }}"
|
||||||
|
echo "Workflow Run Event: ${{ github.event.workflow_run.event }}"
|
||||||
|
echo "Workflow Run Conclusion: ${{ github.event.workflow_run.conclusion }}"
|
||||||
|
echo "Workflow Run Head SHA: ${{ github.event.workflow_run.head_sha }}"
|
||||||
|
|
||||||
|
- name: List downloaded artifacts
|
||||||
|
run: |
|
||||||
|
echo "=== Checking downloaded artifacts ==="
|
||||||
|
ls -la artifacts/ || echo "⚠️ No artifacts directory found"
|
||||||
|
find artifacts/ -type f || echo "⚠️ No files found in artifacts"
|
||||||
|
echo ""
|
||||||
|
echo "Artifact download result: ${{ steps.download-artifacts.outcome }}"
|
||||||
|
|
||||||
|
- name: Read backend results
|
||||||
|
id: backend
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
if [ -f artifacts/backend-results/backend-results.json ]; then
|
||||||
|
echo "=== Backend Results JSON ==="
|
||||||
|
cat artifacts/backend-results/backend-results.json
|
||||||
|
echo "pr_number=$(jq -r '.pr_number' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT
|
||||||
|
echo "fmt_status=$(jq -r '.fmt_status' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT
|
||||||
|
echo "vet_status=$(jq -r '.vet_status' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT
|
||||||
|
echo "test_status=$(jq -r '.test_status' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Read output files
|
||||||
|
if [ -f artifacts/backend-results/fmt-files.txt ]; then
|
||||||
|
echo "fmt_files<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
cat artifacts/backend-results/fmt-files.txt >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
if [ -f artifacts/backend-results/vet-output-short.txt ]; then
|
||||||
|
echo "vet_output<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
cat artifacts/backend-results/vet-output-short.txt >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
if [ -f artifacts/backend-results/test-output-short.txt ]; then
|
||||||
|
echo "test_output<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
cat artifacts/backend-results/test-output-short.txt >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "pr_number=0" >> $GITHUB_OUTPUT
|
||||||
|
echo "⚠️ Backend results artifact not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Read frontend results
|
||||||
|
id: frontend
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
if [ -f artifacts/frontend-results/frontend-results.json ]; then
|
||||||
|
echo "=== Frontend Results JSON ==="
|
||||||
|
cat artifacts/frontend-results/frontend-results.json
|
||||||
|
echo "build_status=$(jq -r '.build_status' artifacts/frontend-results/frontend-results.json)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Read output files
|
||||||
|
if [ -f artifacts/frontend-results/build-output-short.txt ]; then
|
||||||
|
echo "build_output<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
cat artifacts/frontend-results/build-output-short.txt >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⚠️ Frontend results artifact not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Post advisory results comment
|
||||||
|
if: steps.backend.outputs.pr_number != '0'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const prNumber = ${{ steps.backend.outputs.pr_number }};
|
||||||
|
|
||||||
|
let comment = '## 🤖 Advisory Check Results\n\n';
|
||||||
|
comment += 'These are **advisory** checks to help improve code quality. They won\'t block your PR from being merged.\n\n';
|
||||||
|
comment += '> **Note:** PR title and size checks are handled by the main workflow and may appear in a separate comment.\n\n';
|
||||||
|
|
||||||
|
// Backend checks
|
||||||
|
const fmtStatus = '${{ steps.backend.outputs.fmt_status }}';
|
||||||
|
const vetStatus = '${{ steps.backend.outputs.vet_status }}';
|
||||||
|
const testStatus = '${{ steps.backend.outputs.test_status }}';
|
||||||
|
|
||||||
|
if (fmtStatus || vetStatus || testStatus) {
|
||||||
|
comment += '\n### 🔧 Backend Checks\n\n';
|
||||||
|
|
||||||
|
if (fmtStatus) {
|
||||||
|
comment += '**Go Formatting:** ' + fmtStatus + '\n';
|
||||||
|
const fmtFiles = `${{ steps.backend.outputs.fmt_files }}`;
|
||||||
|
if (fmtFiles && fmtFiles.trim()) {
|
||||||
|
comment += '<details><summary>Files needing formatting</summary>\n\n```\n' + fmtFiles + '\n```\n</details>\n\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vetStatus) {
|
||||||
|
comment += '**Go Vet:** ' + vetStatus + '\n';
|
||||||
|
const vetOutput = `${{ steps.backend.outputs.vet_output }}`;
|
||||||
|
if (vetOutput && vetOutput.trim()) {
|
||||||
|
comment += '<details><summary>Issues found</summary>\n\n```\n' + vetOutput.substring(0, 1000) + '\n```\n</details>\n\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testStatus) {
|
||||||
|
comment += '**Tests:** ' + testStatus + '\n';
|
||||||
|
const testOutput = `${{ steps.backend.outputs.test_output }}`;
|
||||||
|
if (testOutput && testOutput.trim()) {
|
||||||
|
comment += '<details><summary>Test output</summary>\n\n```\n' + testOutput.substring(0, 1000) + '\n```\n</details>\n\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comment += '\n**Fix locally:**\n';
|
||||||
|
comment += '```bash\n';
|
||||||
|
comment += 'go fmt ./... # Format code\n';
|
||||||
|
comment += 'go vet ./... # Check for issues\n';
|
||||||
|
comment += 'go test ./... # Run tests\n';
|
||||||
|
comment += '```\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frontend checks
|
||||||
|
const buildStatus = '${{ steps.frontend.outputs.build_status }}';
|
||||||
|
|
||||||
|
if (buildStatus) {
|
||||||
|
comment += '\n### ⚛️ Frontend Checks\n\n';
|
||||||
|
|
||||||
|
comment += '**Build & Type Check:** ' + buildStatus + '\n';
|
||||||
|
const buildOutput = `${{ steps.frontend.outputs.build_output }}`;
|
||||||
|
if (buildOutput && buildOutput.trim()) {
|
||||||
|
comment += '<details><summary>Build output</summary>\n\n```\n' + buildOutput.substring(0, 1000) + '\n```\n</details>\n\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
comment += '\n**Fix locally:**\n';
|
||||||
|
comment += '```bash\n';
|
||||||
|
comment += 'cd web\n';
|
||||||
|
comment += 'npm run build # Test build (includes type checking)\n';
|
||||||
|
comment += '```\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
comment += '\n---\n\n';
|
||||||
|
comment += '### 📖 Resources\n\n';
|
||||||
|
comment += '- [Contributing Guidelines](https://github.com/tinkle-community/nofx/blob/dev/CONTRIBUTING.md)\n';
|
||||||
|
comment += '- [Migration Guide](https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md)\n\n';
|
||||||
|
comment += '**Questions?** Feel free to ask in the comments! 🙏\n\n';
|
||||||
|
comment += '---\n\n';
|
||||||
|
comment += '*These checks are advisory and won\'t block your PR from being merged. This comment is automatically generated from [pr-checks-run.yml](https://github.com/tinkle-community/nofx/blob/dev/.github/workflows/pr-checks-run.yml).*';
|
||||||
|
|
||||||
|
// Post comment
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
issue_number: prNumber,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: comment
|
||||||
|
});
|
||||||
|
|
||||||
|
- name: Post fallback comment if no results
|
||||||
|
if: steps.backend.outputs.pr_number == '0'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
// Try to get PR number from the workflow_run event
|
||||||
|
const pulls = await github.rest.pulls.list({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'open',
|
||||||
|
head: `${context.repo.owner}:${{ github.event.workflow_run.head_branch }}`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pulls.data.length === 0) {
|
||||||
|
console.log('⚠️ Could not find PR for this workflow run');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prNumber = pulls.data[0].number;
|
||||||
|
|
||||||
|
const comment = [
|
||||||
|
'## ⚠️ Advisory Checks - Results Unavailable',
|
||||||
|
'',
|
||||||
|
'The advisory checks workflow completed, but results could not be retrieved.',
|
||||||
|
'',
|
||||||
|
'### Possible reasons:',
|
||||||
|
'- Artifacts were not uploaded successfully',
|
||||||
|
'- Artifacts expired (retention: 1 day)',
|
||||||
|
'- Permission issues',
|
||||||
|
'',
|
||||||
|
'### What to do:',
|
||||||
|
'1. Check the [PR Checks - Run workflow](${{ github.event.workflow_run.html_url }}) logs',
|
||||||
|
'2. Ensure your code passes local checks:',
|
||||||
|
'```bash',
|
||||||
|
'# Backend',
|
||||||
|
'go fmt ./...',
|
||||||
|
'go vet ./...',
|
||||||
|
'go build',
|
||||||
|
'go test ./...',
|
||||||
|
'',
|
||||||
|
'# Frontend (if applicable)',
|
||||||
|
'cd web',
|
||||||
|
'npm run build',
|
||||||
|
'```',
|
||||||
|
'',
|
||||||
|
'---',
|
||||||
|
'',
|
||||||
|
'*This is an automated fallback message. The advisory checks ran but results are not available.*'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
issue_number: prNumber,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: comment
|
||||||
|
});
|
||||||
160
.github/workflows/pr-checks-run.yml
vendored
Normal file
160
.github/workflows/pr-checks-run.yml
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
name: PR Checks - Run
|
||||||
|
|
||||||
|
# This workflow runs advisory PR checks with read-only permissions
|
||||||
|
# Safe for fork PRs - results are saved as artifacts
|
||||||
|
# Companion workflow (pr-checks-comment.yml) will post comments
|
||||||
|
#
|
||||||
|
# NOTE: This workflow provides ADVISORY checks (non-blocking)
|
||||||
|
# Main blocking checks are in pr-checks.yml
|
||||||
|
# PR title and size checks are handled by pr-checks.yml (no duplication)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
branches: [main, dev]
|
||||||
|
|
||||||
|
# Read-only permissions - safe for fork PRs
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Backend advisory checks
|
||||||
|
# Different from pr-checks.yml: these use continue-on-error and generate reports
|
||||||
|
backend-checks:
|
||||||
|
name: Backend Checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.21'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libta-lib-dev || true
|
||||||
|
go mod download || true
|
||||||
|
|
||||||
|
- name: Check Go formatting
|
||||||
|
id: go-fmt
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
UNFORMATTED=$(gofmt -l . 2>/dev/null || echo "")
|
||||||
|
if [ -n "$UNFORMATTED" ]; then
|
||||||
|
echo "status=⚠️ Needs formatting" >> $GITHUB_OUTPUT
|
||||||
|
echo "$UNFORMATTED" | head -10 > fmt-files.txt
|
||||||
|
else
|
||||||
|
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||||
|
echo "" > fmt-files.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run go vet
|
||||||
|
id: go-vet
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
if go vet ./... 2>&1 | tee vet-output.txt; then
|
||||||
|
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT
|
||||||
|
cat vet-output.txt | head -20 > vet-output-short.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
id: go-test
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
if go test ./... -v 2>&1 | tee test-output.txt; then
|
||||||
|
echo "status=✅ Passed" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "status=⚠️ Failed" >> $GITHUB_OUTPUT
|
||||||
|
cat test-output.txt | tail -30 > test-output-short.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Save backend results
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
cat > backend-results.json <<EOF
|
||||||
|
{
|
||||||
|
"pr_number": ${{ github.event.pull_request.number }},
|
||||||
|
"fmt_status": "${{ steps.go-fmt.outputs.status }}",
|
||||||
|
"vet_status": "${{ steps.go-vet.outputs.status }}",
|
||||||
|
"test_status": "${{ steps.go-test.outputs.status }}"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Upload backend results
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: backend-results
|
||||||
|
path: |
|
||||||
|
backend-results.json
|
||||||
|
fmt-files.txt
|
||||||
|
vet-output-short.txt
|
||||||
|
test-output-short.txt
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
# Frontend advisory checks
|
||||||
|
# Different from pr-checks.yml: these use continue-on-error and generate reports
|
||||||
|
frontend-checks:
|
||||||
|
name: Frontend Checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
|
||||||
|
- name: Check if web directory exists
|
||||||
|
id: check-web
|
||||||
|
run: |
|
||||||
|
if [ -d "web" ]; then
|
||||||
|
echo "exists=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
if: steps.check-web.outputs.exists == 'true'
|
||||||
|
working-directory: ./web
|
||||||
|
continue-on-error: true
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Build and Type Check
|
||||||
|
if: steps.check-web.outputs.exists == 'true'
|
||||||
|
id: build
|
||||||
|
working-directory: ./web
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
# build script includes: tsc && vite build
|
||||||
|
if npm run build 2>&1 | tee build-output.txt; then
|
||||||
|
echo "status=✅ Success" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "status=⚠️ Failed" >> $GITHUB_OUTPUT
|
||||||
|
cat build-output.txt | tail -30 > build-output-short.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Save frontend results
|
||||||
|
if: always() && steps.check-web.outputs.exists == 'true'
|
||||||
|
working-directory: ./web
|
||||||
|
run: |
|
||||||
|
cat > frontend-results.json <<EOF
|
||||||
|
{
|
||||||
|
"pr_number": ${{ github.event.pull_request.number }},
|
||||||
|
"build_status": "${{ steps.build.outputs.status }}"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Upload frontend results
|
||||||
|
if: always() && steps.check-web.outputs.exists == 'true'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: frontend-results
|
||||||
|
path: |
|
||||||
|
web/frontend-results.json
|
||||||
|
web/build-output-short.txt
|
||||||
|
retention-days: 1
|
||||||
189
.github/workflows/pr-checks.yml
vendored
189
.github/workflows/pr-checks.yml
vendored
@@ -7,11 +7,13 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
- main
|
- main
|
||||||
|
|
||||||
# Default permissions for all jobs (can be overridden per job)
|
# Default permissions for all jobs
|
||||||
|
# Note: Fork PRs won't have write access for security
|
||||||
|
# Advisory checks use separate workflow (pr-checks-run.yml + pr-checks-comment.yml)
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # Read repository contents
|
contents: read # Read repository contents
|
||||||
pull-requests: write # Manage PRs (labels, comments)
|
pull-requests: write # Manage PRs (labels, comments) - only works for non-fork PRs
|
||||||
issues: write # Manage issues (PRs are issues)
|
issues: write # Manage issues (PRs are issues) - only works for non-fork PRs
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Validate PR title and description
|
# Validate PR title and description
|
||||||
@@ -21,6 +23,8 @@ jobs:
|
|||||||
# Inherits workflow-level permissions (contents: read, pull-requests: write, issues: write)
|
# Inherits workflow-level permissions (contents: read, pull-requests: write, issues: write)
|
||||||
steps:
|
steps:
|
||||||
- name: Check PR title format
|
- name: Check PR title format
|
||||||
|
id: semantic-pr
|
||||||
|
continue-on-error: true # Don't block PR if title format is invalid
|
||||||
uses: amannn/action-semantic-pull-request@v5
|
uses: amannn/action-semantic-pull-request@v5
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -36,6 +40,7 @@ jobs:
|
|||||||
chore
|
chore
|
||||||
ci
|
ci
|
||||||
security
|
security
|
||||||
|
build
|
||||||
scopes: |
|
scopes: |
|
||||||
exchange
|
exchange
|
||||||
trader
|
trader
|
||||||
@@ -46,10 +51,70 @@ jobs:
|
|||||||
backend
|
backend
|
||||||
security
|
security
|
||||||
deps
|
deps
|
||||||
|
workflow
|
||||||
|
github
|
||||||
|
actions
|
||||||
|
config
|
||||||
|
docker
|
||||||
|
build
|
||||||
|
release
|
||||||
requireScope: false
|
requireScope: false
|
||||||
|
|
||||||
|
- name: Comment on invalid PR title
|
||||||
|
if: steps.semantic-pr.outcome == 'failure'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
continue-on-error: true # Don't fail for fork PRs
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const prTitle = context.payload.pull_request.title;
|
||||||
|
const isFork = context.payload.pull_request.head.repo.full_name !== context.payload.pull_request.base.repo.full_name;
|
||||||
|
|
||||||
|
const comment = [
|
||||||
|
'## ⚠️ PR Title Format Suggestion',
|
||||||
|
'',
|
||||||
|
"Your PR title doesn't follow the Conventional Commits format, but **this won't block your PR from being merged**.",
|
||||||
|
'',
|
||||||
|
`**Current title:** \`${prTitle}\``,
|
||||||
|
'',
|
||||||
|
'**Recommended format:** `type(scope): description`',
|
||||||
|
'',
|
||||||
|
'### Valid types:',
|
||||||
|
'`feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `security`, `build`',
|
||||||
|
'',
|
||||||
|
'### Common scopes (optional):',
|
||||||
|
'`exchange`, `trader`, `ai`, `api`, `ui`, `frontend`, `backend`, `security`, `deps`, `workflow`, `github`, `actions`, `config`, `docker`, `build`, `release`',
|
||||||
|
'',
|
||||||
|
'### Examples:',
|
||||||
|
'- `feat(trader): add new trading strategy`',
|
||||||
|
'- `fix(api): resolve authentication issue`',
|
||||||
|
'- `docs: update README`',
|
||||||
|
'- `chore(deps): update dependencies`',
|
||||||
|
'- `ci(workflow): improve GitHub Actions`',
|
||||||
|
'',
|
||||||
|
'**Note:** This is a suggestion to improve consistency. Your PR can still be reviewed and merged.',
|
||||||
|
'',
|
||||||
|
'---',
|
||||||
|
'*This is an automated comment. You can update the PR title anytime.*'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
if (!isFork) {
|
||||||
|
try {
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.payload.pull_request.number,
|
||||||
|
body: comment
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Could not post comment (expected for fork PRs):', error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Fork PR - comment will be posted by pr-checks-comment.yml');
|
||||||
|
}
|
||||||
|
|
||||||
- name: Check PR size
|
- name: Check PR size
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
|
continue-on-error: true # Don't fail for fork PRs
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const pr = context.payload.pull_request;
|
const pr = context.payload.pull_request;
|
||||||
@@ -57,6 +122,9 @@ jobs:
|
|||||||
const deletions = pr.deletions;
|
const deletions = pr.deletions;
|
||||||
const total = additions + deletions;
|
const total = additions + deletions;
|
||||||
|
|
||||||
|
// Check if this is a fork PR
|
||||||
|
const isFork = pr.head.repo.full_name !== pr.base.repo.full_name;
|
||||||
|
|
||||||
let label = '';
|
let label = '';
|
||||||
let comment = '';
|
let comment = '';
|
||||||
|
|
||||||
@@ -71,27 +139,36 @@ jobs:
|
|||||||
comment = '🚨 This PR is **large** (>' + total + ' lines changed). Please consider breaking it into smaller, focused PRs for easier review.';
|
comment = '🚨 This PR is **large** (>' + total + ' lines changed). Please consider breaking it into smaller, focused PRs for easier review.';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add size label
|
// Only add labels/comments for non-fork PRs (fork PRs don't have write permission)
|
||||||
await github.rest.issues.addLabels({
|
if (!isFork) {
|
||||||
owner: context.repo.owner,
|
try {
|
||||||
repo: context.repo.repo,
|
// Add size label
|
||||||
issue_number: pr.number,
|
await github.rest.issues.addLabels({
|
||||||
labels: [label]
|
owner: context.repo.owner,
|
||||||
});
|
repo: context.repo.repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
labels: [label]
|
||||||
|
});
|
||||||
|
|
||||||
// Add comment for large PRs
|
// Add comment for large PRs
|
||||||
if (total >= 1000) {
|
if (total >= 1000) {
|
||||||
await github.rest.issues.createComment({
|
await github.rest.issues.createComment({
|
||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
issue_number: pr.number,
|
issue_number: pr.number,
|
||||||
body: comment
|
body: comment
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Failed to add label/comment (expected for fork PRs):', error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Fork PR detected - skipping label/comment (will be handled by pr-checks-comment.yml)');
|
||||||
}
|
}
|
||||||
|
|
||||||
# Backend tests
|
# Backend checks (simplified - no TA-Lib required)
|
||||||
backend-tests:
|
backend-checks:
|
||||||
name: Backend Tests (Go)
|
name: Backend Code Quality (Go)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # Only need read access for testing
|
contents: read # Only need read access for testing
|
||||||
@@ -104,11 +181,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.21'
|
||||||
|
|
||||||
- name: Install TA-Lib
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libta-lib-dev
|
|
||||||
|
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -121,28 +193,26 @@ jobs:
|
|||||||
run: go mod download
|
run: go mod download
|
||||||
|
|
||||||
- name: Run go fmt
|
- name: Run go fmt
|
||||||
|
continue-on-error: true # Don't block PR if formatting issues found
|
||||||
run: |
|
run: |
|
||||||
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
|
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
|
||||||
echo "Please run 'go fmt' on your code"
|
echo "⚠️ Code formatting issues found. Please run 'go fmt ./...' locally."
|
||||||
|
echo ""
|
||||||
|
echo "Files needing formatting:"
|
||||||
gofmt -s -l .
|
gofmt -s -l .
|
||||||
|
echo ""
|
||||||
|
echo "This is a warning and won't block your PR from being merged."
|
||||||
exit 1
|
exit 1
|
||||||
|
else
|
||||||
|
echo "✅ All Go files are properly formatted"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Run go vet
|
- name: Run go vet
|
||||||
run: go vet ./...
|
run: go vet ./...
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: go test -v -race -coverprofile=coverage.out ./...
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: go build -v -o nofx
|
run: go build -v -o nofx
|
||||||
|
|
||||||
- name: Upload coverage
|
|
||||||
uses: codecov/codecov-action@v4
|
|
||||||
with:
|
|
||||||
file: ./coverage.out
|
|
||||||
flags: backend
|
|
||||||
|
|
||||||
# Frontend tests
|
# Frontend tests
|
||||||
frontend-tests:
|
frontend-tests:
|
||||||
name: Frontend Tests (React/TypeScript)
|
name: Frontend Tests (React/TypeScript)
|
||||||
@@ -170,22 +240,17 @@ jobs:
|
|||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
- name: Run linter
|
- name: Build and Type Check
|
||||||
working-directory: ./web
|
|
||||||
run: npm run lint
|
|
||||||
|
|
||||||
- name: Run type check
|
|
||||||
working-directory: ./web
|
|
||||||
run: npm run type-check || true # Don't fail on type errors for now
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
# Note: build script runs "tsc && vite build" which includes type checking
|
||||||
|
|
||||||
# Auto-label based on files changed
|
# Auto-label based on files changed
|
||||||
auto-label:
|
auto-label:
|
||||||
name: Auto Label PR
|
name: Auto Label PR
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# Only run for non-fork PRs (fork PRs don't have write permission)
|
||||||
|
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
@@ -233,25 +298,43 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Run Gitleaks
|
- name: Run TruffleHog OSS
|
||||||
uses: gitleaks/gitleaks-action@v2
|
uses: trufflesecurity/trufflehog@main
|
||||||
env:
|
with:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
path: ./
|
||||||
|
base: ${{ github.event.pull_request.base.sha }}
|
||||||
|
head: ${{ github.event.pull_request.head.sha }}
|
||||||
|
extra_args: --debug --only-verified
|
||||||
|
|
||||||
# All checks passed
|
# All checks passed
|
||||||
all-checks:
|
all-checks:
|
||||||
name: All Checks Passed
|
name: All Checks Passed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [validate-pr, backend-tests, frontend-tests, security-check, secrets-check]
|
needs: [validate-pr, backend-checks, frontend-tests, security-check, secrets-check]
|
||||||
if: always()
|
if: always()
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # Only need read access for status checking
|
contents: read # Only need read access for status checking
|
||||||
steps:
|
steps:
|
||||||
- name: Check all jobs
|
- name: Check all jobs
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ contains(needs.*.result, 'failure') }}" == "true" ]; then
|
# Note: validate-pr uses continue-on-error, so it won't block even if title format is invalid
|
||||||
echo "Some checks failed"
|
# We only care about actual test failures
|
||||||
|
echo "validate-pr: ${{ needs.validate-pr.result }}"
|
||||||
|
echo "backend-checks: ${{ needs.backend-checks.result }}"
|
||||||
|
echo "frontend-tests: ${{ needs.frontend-tests.result }}"
|
||||||
|
echo "security-check: ${{ needs.security-check.result }}"
|
||||||
|
echo "secrets-check: ${{ needs.secrets-check.result }}"
|
||||||
|
|
||||||
|
# Check if any critical checks failed (excluding validate-pr which is advisory)
|
||||||
|
if [[ "${{ needs.backend-checks.result }}" == "failure" ]] || \
|
||||||
|
[[ "${{ needs.frontend-tests.result }}" == "failure" ]] || \
|
||||||
|
[[ "${{ needs.security-check.result }}" == "failure" ]] || \
|
||||||
|
[[ "${{ needs.secrets-check.result }}" == "failure" ]]; then
|
||||||
|
echo "❌ Critical checks failed"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
echo "All checks passed!"
|
echo "✅ All critical checks passed!"
|
||||||
|
if [[ "${{ needs.validate-pr.result }}" != "success" ]]; then
|
||||||
|
echo "ℹ️ Note: PR title format check is advisory only and doesn't block merging"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user