AIRA-64: Branch Protection Rules & Core Development Automation #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Validation & Auto-linking | ||
| on: | ||
| pull_request: | ||
| types: [opened, edited, synchronize, ready_for_review] | ||
| pull_request_review: | ||
| types: [submitted] | ||
| jobs: | ||
| validate-pr: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Check PR links to issue | ||
| uses: actions/github-script@v6 | ||
| with: | ||
| script: | | ||
| const prBody = context.payload.pull_request.body || ''; | ||
| const prTitle = context.payload.pull_request.title || ''; | ||
| const prNumber = context.payload.pull_request.number; | ||
| // Check for issue references | ||
| const issuePattern = /(?:closes|fixes|resolves|implements)\s+#?(\d+)|AIRA-(\d+)/gi; | ||
| const hasIssueRef = issuePattern.test(prBody + ' ' + prTitle); | ||
| if (!hasIssueRef) { | ||
| core.setFailed('PR must reference an issue using keywords like "Closes #12" or "AIRA-12"'); | ||
| return; | ||
| } | ||
| // Validate PR title format | ||
| const titlePattern = /^(feat|fix|docs|style|refactor|test|chore|hotfix):\s.+\s\(AIRA-\d+\)$/; | ||
| if (!titlePattern.test(prTitle)) { | ||
| core.setFailed('PR title must follow format: "type: description (AIRA-X)"'); | ||
| return; | ||
| } | ||
| console.log('✅ PR validation passed'); | ||
| - name: Validate branch name | ||
| run: | | ||
| BRANCH_NAME="${{ github.head_ref }}" | ||
| if [[ ! $BRANCH_NAME =~ ^AIRA-[0-9]+$ ]] && \ | ||
| [[ ! $BRANCH_NAME =~ ^(hotfix|docs|experiment)/AIRA-[0-9]+$ ]] && \ | ||
| [[ ! $BRANCH_NAME =~ ^release/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||
| echo "❌ Branch name must follow convention:" | ||
| echo " - AIRA-X (feature branches)" | ||
| echo " - hotfix/AIRA-X (hotfixes)" | ||
| echo " - docs/AIRA-X (documentation)" | ||
| echo " - release/vX.Y.Z (releases)" | ||
| exit 1 | ||
| fi | ||
| echo "✅ Branch name follows convention: $BRANCH_NAME" | ||
| - name: Check PR size | ||
| uses: actions/github-script@v6 | ||
| with: | ||
| script: | | ||
| const pr = context.payload.pull_request; | ||
| const additions = pr.additions; | ||
| const deletions = pr.deletions; | ||
| const changedFiles = pr.changed_files; | ||
| if (additions + deletions > 1000) { | ||
| github.rest.issues.createComment({ | ||
| issue_number: pr.number, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: `⚠️ **Large PR Warning** | ||
| This PR modifies ${additions + deletions} lines across ${changedFiles} files. | ||
| Consider breaking it into smaller, focused PRs for easier review. | ||
| **PR Stats:** | ||
| - **Additions:** ${additions} | ||
| - **Deletions:** ${deletions} | ||
| - **Files Changed:** ${changedFiles}` | ||
| }); | ||
| } | ||
| - name: Auto-assign reviewers | ||
| uses: actions/github-script@v6 | ||
| with: | ||
| script: | | ||
| const prAuthor = context.payload.pull_request.user.login; | ||
| const isExternal = context.payload.pull_request.head.repo.fork; | ||
| let reviewers = []; | ||
| let teamReviewers = []; | ||
| if (isExternal) { | ||
| // External contributors need core team review | ||
| teamReviewers = ['aira-core']; | ||
| reviewers = ['maintainer1', 'maintainer2']; | ||
| } else { | ||
| // Internal PRs need peer review | ||
| const coreTeam = ['dev1', 'dev2', 'dev3', 'dev4']; | ||
| reviewers = coreTeam.filter(dev => dev !== prAuthor).slice(0, 1); | ||
| } | ||
| if (reviewers.length > 0) { | ||
| await github.rest.pulls.requestReviewers({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: context.payload.pull_request.number, | ||
| reviewers: reviewers, | ||
| team_reviewers: teamReviewers | ||
| }); | ||
| } | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| python-version: [3.9, 3.10, 3.11] | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Set up Python ${{ matrix.python-version }} | ||
| uses: actions/setup-python@v4 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| - name: Cache dependencies | ||
| uses: actions/cache@v3 | ||
| with: | ||
| path: ~/.cache/pip | ||
| key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-pip- | ||
| - name: Install dependencies | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install -r requirements.txt | ||
| pip install -r requirements-dev.txt | ||
| - name: Run linting | ||
| run: | | ||
| flake8 aira/ tests/ --max-line-length=88 --extend-ignore=E203,W503 | ||
| black --check aira/ tests/ | ||
| isort --check-only aira/ tests/ | ||
| - name: Run type checking | ||
| run: mypy aira/ | ||
| - name: Run security scan | ||
| run: | | ||
| bandit -r aira/ -f json -o bandit-report.json | ||
| safety check --json --output safety-report.json | ||
| - name: Run tests with coverage | ||
| run: | | ||
| pytest tests/ \ | ||
| --cov=aira \ | ||
| --cov-report=xml \ | ||
| --cov-report=html \ | ||
| --cov-fail-under=85 \ | ||
| --junitxml=pytest-report.xml | ||
| - name: Upload coverage reports | ||
| uses: codecov/codecov-action@v3 | ||
| with: | ||
| file: ./coverage.xml | ||
| flags: unittests | ||
| name: codecov-umbrella | ||
| - name: Upload test results | ||
| uses: actions/upload-artifact@v3 | ||
| if: always() | ||
| with: | ||
| name: test-results-${{ matrix.python-version }} | ||
| path: | | ||
| pytest-report.xml | ||
| htmlcov/ | ||
| bandit-report.json | ||
| safety-report.json | ||
| security-check: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - 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 scan results | ||
| uses: github/codeql-action/upload-sarif@v2 | ||
| with: | ||
| sarif_file: 'trivy-results.sarif' | ||
| quality-gate: | ||
| runs-on: ubuntu-latest | ||
| needs: [test, security-check] | ||
| steps: | ||
| - name: Quality Gate Check | ||
| run: | | ||
| echo "✅ All quality checks passed" | ||
| echo "- Tests: Passed" | ||
| echo "- Security: Passed" | ||
| echo "- Coverage: >85%" | ||
| echo "- Linting: Passed" | ||