mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-04 03:21:04 +08:00
feat: pr validation
This commit is contained in:
127
.github/labeler.yml
vendored
Normal file
127
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
# Auto-labeler configuration
|
||||
# Automatically adds labels based on changed files
|
||||
|
||||
# Area: Frontend
|
||||
'area: frontend':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'web/**/*'
|
||||
- '*.tsx'
|
||||
- '*.ts'
|
||||
- '*.jsx'
|
||||
- '*.js'
|
||||
- '*.css'
|
||||
|
||||
# Area: Backend
|
||||
'area: backend':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/*.go'
|
||||
- 'go.mod'
|
||||
- 'go.sum'
|
||||
- 'cmd/**/*'
|
||||
- 'internal/**/*'
|
||||
- 'pkg/**/*'
|
||||
|
||||
# Area: Exchange
|
||||
'area: exchange':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/exchange/**/*'
|
||||
- 'pkg/exchange/**/*'
|
||||
- '**/binance*.go'
|
||||
- '**/hyperliquid*.go'
|
||||
- '**/aster*.go'
|
||||
- '**/okx*.go'
|
||||
- '**/bybit*.go'
|
||||
|
||||
# Area: AI
|
||||
'area: ai':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/ai/**/*'
|
||||
- 'pkg/ai/**/*'
|
||||
- '**/deepseek*.go'
|
||||
- '**/qwen*.go'
|
||||
- '**/openai*.go'
|
||||
- '**/claude*.go'
|
||||
|
||||
# Area: API
|
||||
'area: api':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/api/**/*'
|
||||
- 'pkg/api/**/*'
|
||||
- '**/handler*.go'
|
||||
- '**/router*.go'
|
||||
|
||||
# Area: Security
|
||||
'area: security':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/auth*.go'
|
||||
- '**/jwt*.go'
|
||||
- '**/encryption*.go'
|
||||
- '**/crypto*.go'
|
||||
- 'SECURITY.md'
|
||||
|
||||
# Area: Database
|
||||
'area: database':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/database/**/*'
|
||||
- 'internal/db/**/*'
|
||||
- '**/migration*.go'
|
||||
- '**/*.sql'
|
||||
- '**/schema*.go'
|
||||
|
||||
# Area: UI/UX
|
||||
'area: ui/ux':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'web/src/components/**/*'
|
||||
- 'web/src/pages/**/*'
|
||||
- '**/*.css'
|
||||
- '**/style*.ts'
|
||||
|
||||
# Area: Deployment
|
||||
'area: deployment':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'Dockerfile'
|
||||
- 'docker-compose*.yml'
|
||||
- '.github/workflows/**/*'
|
||||
- 'start.sh'
|
||||
- '**/*deploy*.md'
|
||||
|
||||
# Type: Documentation
|
||||
'type: documentation':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'docs/**/*'
|
||||
- '*.md'
|
||||
- 'README*'
|
||||
- 'CHANGELOG*'
|
||||
- 'CONTRIBUTING.md'
|
||||
- 'CODE_OF_CONDUCT.md'
|
||||
|
||||
# Type: Test
|
||||
'type: test':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/*_test.go'
|
||||
- 'test/**/*'
|
||||
- '**/*.test.ts'
|
||||
- '**/*.test.tsx'
|
||||
- '**/*.spec.ts'
|
||||
|
||||
# Dependencies
|
||||
'dependencies':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'go.mod'
|
||||
- 'go.sum'
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'web/package.json'
|
||||
- 'web/package-lock.json'
|
||||
180
.github/labels.yml
vendored
Normal file
180
.github/labels.yml
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
# GitHub Labels Configuration
|
||||
# Use https://github.com/crazy-max/ghaction-github-labeler to sync labels
|
||||
|
||||
# Priority Labels
|
||||
- name: "priority: critical"
|
||||
color: "d73a4a"
|
||||
description: "Critical priority - requires immediate attention"
|
||||
|
||||
- name: "priority: high"
|
||||
color: "ff6b6b"
|
||||
description: "High priority - should be addressed soon"
|
||||
|
||||
- name: "priority: medium"
|
||||
color: "fbca04"
|
||||
description: "Medium priority - normal queue"
|
||||
|
||||
- name: "priority: low"
|
||||
color: "0e8a16"
|
||||
description: "Low priority - nice to have"
|
||||
|
||||
# Type Labels
|
||||
- name: "type: bug"
|
||||
color: "d73a4a"
|
||||
description: "Something isn't working"
|
||||
|
||||
- name: "type: feature"
|
||||
color: "a2eeef"
|
||||
description: "New feature or request"
|
||||
|
||||
- name: "type: enhancement"
|
||||
color: "84b6eb"
|
||||
description: "Improvement to existing feature"
|
||||
|
||||
- name: "type: documentation"
|
||||
color: "0075ca"
|
||||
description: "Documentation improvements"
|
||||
|
||||
- name: "type: security"
|
||||
color: "ee0701"
|
||||
description: "Security-related changes"
|
||||
|
||||
- name: "type: performance"
|
||||
color: "f9d0c4"
|
||||
description: "Performance improvements"
|
||||
|
||||
- name: "type: refactor"
|
||||
color: "fbca04"
|
||||
description: "Code refactoring"
|
||||
|
||||
- name: "type: test"
|
||||
color: "c5def5"
|
||||
description: "Test-related changes"
|
||||
|
||||
# Status Labels
|
||||
- name: "status: needs review"
|
||||
color: "fbca04"
|
||||
description: "PR is ready for review"
|
||||
|
||||
- name: "status: needs changes"
|
||||
color: "d93f0b"
|
||||
description: "PR needs changes based on review"
|
||||
|
||||
- name: "status: on hold"
|
||||
color: "fef2c0"
|
||||
description: "PR/issue is on hold"
|
||||
|
||||
- name: "status: in progress"
|
||||
color: "0e8a16"
|
||||
description: "Currently being worked on"
|
||||
|
||||
- name: "status: blocked"
|
||||
color: "d93f0b"
|
||||
description: "Blocked by another issue/PR"
|
||||
|
||||
# Area Labels (aligned with roadmap)
|
||||
- name: "area: security"
|
||||
color: "ee0701"
|
||||
description: "Security enhancements (Phase 1.1)"
|
||||
|
||||
- name: "area: ai"
|
||||
color: "7057ff"
|
||||
description: "AI capabilities and models (Phase 1.2)"
|
||||
|
||||
- name: "area: exchange"
|
||||
color: "0075ca"
|
||||
description: "Exchange integrations (Phase 1.3)"
|
||||
|
||||
- name: "area: architecture"
|
||||
color: "d4c5f9"
|
||||
description: "Project structure refactoring (Phase 1.4)"
|
||||
|
||||
- name: "area: ui/ux"
|
||||
color: "c2e0c6"
|
||||
description: "User experience improvements (Phase 1.5)"
|
||||
|
||||
- name: "area: frontend"
|
||||
color: "bfdadc"
|
||||
description: "Frontend (React/TypeScript)"
|
||||
|
||||
- name: "area: backend"
|
||||
color: "c5def5"
|
||||
description: "Backend (Go)"
|
||||
|
||||
- name: "area: api"
|
||||
color: "0e8a16"
|
||||
description: "API endpoints"
|
||||
|
||||
- name: "area: database"
|
||||
color: "f9d0c4"
|
||||
description: "Database changes"
|
||||
|
||||
- name: "area: deployment"
|
||||
color: "fbca04"
|
||||
description: "Deployment and CI/CD"
|
||||
|
||||
# Special Labels
|
||||
- name: "good first issue"
|
||||
color: "7057ff"
|
||||
description: "Good for newcomers"
|
||||
|
||||
- name: "help wanted"
|
||||
color: "008672"
|
||||
description: "Extra attention is needed"
|
||||
|
||||
- name: "bounty"
|
||||
color: "1d76db"
|
||||
description: "Bounty available for this issue"
|
||||
|
||||
- name: "bounty: claimed"
|
||||
color: "5319e7"
|
||||
description: "Bounty has been claimed"
|
||||
|
||||
- name: "bounty: paid"
|
||||
color: "0e8a16"
|
||||
description: "Bounty has been paid"
|
||||
|
||||
- name: "RFC"
|
||||
color: "d4c5f9"
|
||||
description: "Request for Comments - needs discussion"
|
||||
|
||||
- name: "breaking change"
|
||||
color: "d73a4a"
|
||||
description: "Includes breaking changes"
|
||||
|
||||
- name: "duplicate"
|
||||
color: "cfd3d7"
|
||||
description: "This issue or pull request already exists"
|
||||
|
||||
- name: "invalid"
|
||||
color: "e4e669"
|
||||
description: "This doesn't seem right"
|
||||
|
||||
- name: "wontfix"
|
||||
color: "ffffff"
|
||||
description: "This will not be worked on"
|
||||
|
||||
- name: "dependencies"
|
||||
color: "0366d6"
|
||||
description: "Dependency updates"
|
||||
|
||||
# Roadmap Phases
|
||||
- name: "roadmap: phase-1"
|
||||
color: "0e8a16"
|
||||
description: "Core Infrastructure Enhancement"
|
||||
|
||||
- name: "roadmap: phase-2"
|
||||
color: "fbca04"
|
||||
description: "Testing & Stability"
|
||||
|
||||
- name: "roadmap: phase-3"
|
||||
color: "0075ca"
|
||||
description: "Universal Market Expansion"
|
||||
|
||||
- name: "roadmap: phase-4"
|
||||
color: "7057ff"
|
||||
description: "Advanced AI & Automation"
|
||||
|
||||
- name: "roadmap: phase-5"
|
||||
color: "d73a4a"
|
||||
description: "Enterprise & Scaling"
|
||||
331
.github/workflows/pr-checks-advisory.yml
vendored
Normal file
331
.github/workflows/pr-checks-advisory.yml
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
name: PR Checks (Advisory)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches: [main, dev]
|
||||
|
||||
# These checks are advisory only - they won't block PR merging
|
||||
# Results will be posted as comments to help contributors improve their PRs
|
||||
|
||||
jobs:
|
||||
pr-info:
|
||||
name: PR Information
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Check PR title format
|
||||
id: check-title
|
||||
run: |
|
||||
PR_TITLE="${{ github.event.pull_request.title }}"
|
||||
|
||||
# Check if title follows conventional commits
|
||||
if echo "$PR_TITLE" | grep -qE "^(feat|fix|docs|style|refactor|perf|test|chore|ci|security)(\(.+\))?: .+"; then
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "message=PR title follows Conventional Commits format" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Suggestion" >> $GITHUB_OUTPUT
|
||||
echo "message=Consider using Conventional Commits format: type(scope): description" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Calculate PR size
|
||||
id: pr-size
|
||||
run: |
|
||||
ADDITIONS=${{ github.event.pull_request.additions }}
|
||||
DELETIONS=${{ github.event.pull_request.deletions }}
|
||||
TOTAL=$((ADDITIONS + DELETIONS))
|
||||
|
||||
if [ $TOTAL -lt 100 ]; then
|
||||
echo "size=🟢 Small" >> $GITHUB_OUTPUT
|
||||
echo "label=size: small" >> $GITHUB_OUTPUT
|
||||
elif [ $TOTAL -lt 500 ]; then
|
||||
echo "size=🟡 Medium" >> $GITHUB_OUTPUT
|
||||
echo "label=size: medium" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "size=🔴 Large" >> $GITHUB_OUTPUT
|
||||
echo "label=size: large" >> $GITHUB_OUTPUT
|
||||
echo "suggestion=Consider breaking this into smaller PRs for easier review" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "lines=$TOTAL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Post advisory comment
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const titleStatus = '${{ steps.check-title.outputs.status }}';
|
||||
const titleMessage = '${{ steps.check-title.outputs.message }}';
|
||||
const prSize = '${{ steps.pr-size.outputs.size }}';
|
||||
const prLines = '${{ steps.pr-size.outputs.lines }}';
|
||||
const sizeSuggestion = '${{ steps.pr-size.outputs.suggestion }}' || '';
|
||||
|
||||
let comment = '## 🤖 PR Advisory Feedback\n\n';
|
||||
comment += 'Thank you for your contribution! Here\'s some automated feedback to help improve your PR:\n\n';
|
||||
comment += '### PR Title\n';
|
||||
comment += titleStatus + ' ' + titleMessage + '\n\n';
|
||||
comment += '### PR Size\n';
|
||||
comment += prSize + ' (' + prLines + ' lines changed)\n';
|
||||
if (sizeSuggestion) {
|
||||
comment += '\n💡 **Suggestion:** ' + sizeSuggestion + '\n';
|
||||
}
|
||||
comment += '\n---\n\n';
|
||||
comment += '### 📖 New PR Management System\n\n';
|
||||
comment += 'We\'re introducing a new PR management system! These checks are **advisory only** and won\'t block your PR.\n\n';
|
||||
comment += '**Want to check your PR against new standards?**\n';
|
||||
comment += '```bash\n';
|
||||
comment += '# Run the PR health check tool\n';
|
||||
comment += './scripts/pr-check.sh\n';
|
||||
comment += '```\n\n';
|
||||
comment += 'This tool will:\n';
|
||||
comment += '- 🔍 Analyze your PR (doesn\'t modify anything)\n';
|
||||
comment += '- ✅ Show what\'s already good\n';
|
||||
comment += '- ⚠️ Point out issues\n';
|
||||
comment += '- 💡 Give specific suggestions on how to fix\n\n';
|
||||
comment += '**Learn more:**\n';
|
||||
comment += '- [Migration Guide](https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md)\n';
|
||||
comment += '- [Contributing Guidelines](https://github.com/tinkle-community/nofx/blob/dev/CONTRIBUTING.md)\n\n';
|
||||
comment += '**Questions?** Just ask in the comments! We\'re here to help. 🙏\n\n';
|
||||
comment += '---\n\n';
|
||||
comment += '*This is an automated message. It won\'t affect your PR being merged.*';
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
|
||||
backend-checks:
|
||||
name: Backend Checks (Advisory)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
continue-on-error: true
|
||||
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 "files<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$UNFORMATTED" | head -10 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "files=" >> $GITHUB_OUTPUT
|
||||
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
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat vet-output.txt | head -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
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
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Failed" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat test-output.txt | tail -30 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Post backend feedback
|
||||
if: always()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fmtStatus = '${{ steps.go-fmt.outputs.status }}' || '⚠️ Skipped';
|
||||
const vetStatus = '${{ steps.go-vet.outputs.status }}' || '⚠️ Skipped';
|
||||
const testStatus = '${{ steps.go-test.outputs.status }}' || '⚠️ Skipped';
|
||||
const fmtFiles = `${{ steps.go-fmt.outputs.files }}`;
|
||||
const vetOutput = `${{ steps.go-vet.outputs.output }}`;
|
||||
const testOutput = `${{ steps.go-test.outputs.output }}`;
|
||||
|
||||
let comment = '## 🔧 Backend Checks (Advisory)\n\n';
|
||||
comment += '### Go Formatting\n';
|
||||
comment += fmtStatus + '\n';
|
||||
if (fmtFiles) {
|
||||
comment += '\nFiles needing formatting:\n```\n' + fmtFiles + '\n```\n';
|
||||
}
|
||||
comment += '\n### Go Vet\n';
|
||||
comment += vetStatus + '\n';
|
||||
if (vetOutput) {
|
||||
comment += '\n```\n' + vetOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n### Tests\n';
|
||||
comment += testStatus + '\n';
|
||||
if (testOutput) {
|
||||
comment += '\n```\n' + testOutput.substring(0, 1000) + '\n```\n';
|
||||
}
|
||||
comment += '\n---\n\n';
|
||||
comment += '💡 **To fix locally:**\n';
|
||||
comment += '```bash\n';
|
||||
comment += '# Format code\n';
|
||||
comment += 'go fmt ./...\n\n';
|
||||
comment += '# Check for issues\n';
|
||||
comment += 'go vet ./...\n\n';
|
||||
comment += '# Run tests\n';
|
||||
comment += 'go test ./...\n';
|
||||
comment += '```\n\n';
|
||||
comment += '*These checks are advisory and won\'t block merging. Need help? Just ask!*';
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
|
||||
frontend-checks:
|
||||
name: Frontend Checks (Advisory)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
continue-on-error: true
|
||||
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: Run linter
|
||||
if: steps.check-web.outputs.exists == 'true'
|
||||
id: lint
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if npm run lint 2>&1 | tee lint-output.txt; then
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat lint-output.txt | head -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Type check
|
||||
if: steps.check-web.outputs.exists == 'true'
|
||||
id: typecheck
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if npm run type-check 2>&1 | tee typecheck-output.txt; then
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat typecheck-output.txt | head -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
if: steps.check-web.outputs.exists == 'true'
|
||||
id: build
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if npm run build 2>&1 | tee build-output.txt; then
|
||||
echo "status=✅ Success" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Failed" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat build-output.txt | tail -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Post frontend feedback
|
||||
if: always() && steps.check-web.outputs.exists == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const lintStatus = '${{ steps.lint.outputs.status }}' || '⚠️ Skipped';
|
||||
const typecheckStatus = '${{ steps.typecheck.outputs.status }}' || '⚠️ Skipped';
|
||||
const buildStatus = '${{ steps.build.outputs.status }}' || '⚠️ Skipped';
|
||||
const lintOutput = `${{ steps.lint.outputs.output }}`;
|
||||
const typecheckOutput = `${{ steps.typecheck.outputs.output }}`;
|
||||
const buildOutput = `${{ steps.build.outputs.output }}`;
|
||||
|
||||
let comment = '## ⚛️ Frontend Checks (Advisory)\n\n';
|
||||
comment += '### Linting\n';
|
||||
comment += lintStatus + '\n';
|
||||
if (lintOutput) {
|
||||
comment += '\n```\n' + lintOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n### Type Checking\n';
|
||||
comment += typecheckStatus + '\n';
|
||||
if (typecheckOutput) {
|
||||
comment += '\n```\n' + typecheckOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n### Build\n';
|
||||
comment += buildStatus + '\n';
|
||||
if (buildOutput) {
|
||||
comment += '\n```\n' + buildOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n---\n\n';
|
||||
comment += '💡 **To fix locally:**\n';
|
||||
comment += '```bash\n';
|
||||
comment += 'cd web\n\n';
|
||||
comment += '# Fix linting issues\n';
|
||||
comment += 'npm run lint -- --fix\n\n';
|
||||
comment += '# Check types\n';
|
||||
comment += 'npm run type-check\n\n';
|
||||
comment += '# Test build\n';
|
||||
comment += 'npm run build\n';
|
||||
comment += '```\n\n';
|
||||
comment += '*These checks are advisory and won\'t block merging. Need help? Just ask!*';
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
237
.github/workflows/pr-checks.yml
vendored
Normal file
237
.github/workflows/pr-checks.yml
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
name: PR Checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
branches:
|
||||
- dev
|
||||
- main
|
||||
|
||||
jobs:
|
||||
# Validate PR title and description
|
||||
validate-pr:
|
||||
name: Validate PR Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR title format
|
||||
uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
chore
|
||||
ci
|
||||
security
|
||||
scopes: |
|
||||
exchange
|
||||
trader
|
||||
ai
|
||||
api
|
||||
ui
|
||||
frontend
|
||||
backend
|
||||
security
|
||||
deps
|
||||
requireScope: false
|
||||
|
||||
- name: Check PR size
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const additions = pr.additions;
|
||||
const deletions = pr.deletions;
|
||||
const total = additions + deletions;
|
||||
|
||||
let label = '';
|
||||
let comment = '';
|
||||
|
||||
if (total < 300) {
|
||||
label = 'size: small';
|
||||
comment = '✅ This PR is **small** and easy to review!';
|
||||
} else if (total < 1000) {
|
||||
label = 'size: medium';
|
||||
comment = '⚠️ This PR is **medium** sized. Consider breaking it into smaller PRs if possible.';
|
||||
} else {
|
||||
label = 'size: large';
|
||||
comment = '🚨 This PR is **large** (>' + total + ' lines changed). Please consider breaking it into smaller, focused PRs for easier review.';
|
||||
}
|
||||
|
||||
// Add size label
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
labels: [label]
|
||||
});
|
||||
|
||||
// Add comment for large PRs
|
||||
if (total >= 1000) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: comment
|
||||
});
|
||||
}
|
||||
|
||||
# Backend tests
|
||||
backend-tests:
|
||||
name: Backend Tests (Go)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
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
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Run go fmt
|
||||
run: |
|
||||
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
|
||||
echo "Please run 'go fmt' on your code"
|
||||
gofmt -s -l .
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run go vet
|
||||
run: go vet ./...
|
||||
|
||||
- name: Run tests
|
||||
run: go test -v -race -coverprofile=coverage.out ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -v -o nofx
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./coverage.out
|
||||
flags: backend
|
||||
|
||||
# Frontend tests
|
||||
frontend-tests:
|
||||
name: Frontend Tests (React/TypeScript)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Cache Node modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: web/node_modules
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('web/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ./web
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
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
|
||||
run: npm run build
|
||||
|
||||
# Auto-label based on files changed
|
||||
auto-label:
|
||||
name: Auto Label PR
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: .github/labeler.yml
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Check for security issues
|
||||
security-check:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
scan-ref: '.'
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy results
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
# Check for secrets in code
|
||||
secrets-check:
|
||||
name: Check for Secrets
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run Gitleaks
|
||||
uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# All checks passed
|
||||
all-checks:
|
||||
name: All Checks Passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [validate-pr, backend-tests, frontend-tests, security-check, secrets-check]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check all jobs
|
||||
run: |
|
||||
if [ "${{ contains(needs.*.result, 'failure') }}" == "true" ]; then
|
||||
echo "Some checks failed"
|
||||
exit 1
|
||||
else
|
||||
echo "All checks passed!"
|
||||
fi
|
||||
Reference in New Issue
Block a user