tech-hub-skills 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +250 -0
- package/bin/cli.js +241 -0
- package/bin/copilot.js +182 -0
- package/bin/postinstall.js +42 -0
- package/package.json +46 -0
- package/tech_hub_skills/roles/ai-engineer/skills/01-prompt-engineering/README.md +252 -0
- package/tech_hub_skills/roles/ai-engineer/skills/02-rag-pipeline/README.md +448 -0
- package/tech_hub_skills/roles/ai-engineer/skills/03-agent-orchestration/README.md +599 -0
- package/tech_hub_skills/roles/ai-engineer/skills/04-llm-guardrails/README.md +735 -0
- package/tech_hub_skills/roles/ai-engineer/skills/05-vector-embeddings/README.md +711 -0
- package/tech_hub_skills/roles/ai-engineer/skills/06-llm-evaluation/README.md +777 -0
- package/tech_hub_skills/roles/azure/skills/01-infrastructure-fundamentals/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/02-data-factory/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/03-synapse-analytics/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/04-databricks/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/05-functions/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/06-kubernetes-service/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/07-openai-service/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/08-machine-learning/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/09-storage-adls/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/10-networking/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/11-sql-cosmos/README.md +264 -0
- package/tech_hub_skills/roles/azure/skills/12-event-hubs/README.md +264 -0
- package/tech_hub_skills/roles/code-review/skills/01-automated-code-review/README.md +394 -0
- package/tech_hub_skills/roles/code-review/skills/02-pr-review-workflow/README.md +427 -0
- package/tech_hub_skills/roles/code-review/skills/03-code-quality-gates/README.md +518 -0
- package/tech_hub_skills/roles/code-review/skills/04-reviewer-assignment/README.md +504 -0
- package/tech_hub_skills/roles/code-review/skills/05-review-analytics/README.md +540 -0
- package/tech_hub_skills/roles/data-engineer/skills/01-lakehouse-architecture/README.md +550 -0
- package/tech_hub_skills/roles/data-engineer/skills/02-etl-pipeline/README.md +580 -0
- package/tech_hub_skills/roles/data-engineer/skills/03-data-quality/README.md +579 -0
- package/tech_hub_skills/roles/data-engineer/skills/04-streaming-pipelines/README.md +608 -0
- package/tech_hub_skills/roles/data-engineer/skills/05-performance-optimization/README.md +547 -0
- package/tech_hub_skills/roles/data-governance/skills/01-data-catalog/README.md +112 -0
- package/tech_hub_skills/roles/data-governance/skills/02-data-lineage/README.md +129 -0
- package/tech_hub_skills/roles/data-governance/skills/03-data-quality-framework/README.md +182 -0
- package/tech_hub_skills/roles/data-governance/skills/04-access-control/README.md +39 -0
- package/tech_hub_skills/roles/data-governance/skills/05-master-data-management/README.md +40 -0
- package/tech_hub_skills/roles/data-governance/skills/06-compliance-privacy/README.md +46 -0
- package/tech_hub_skills/roles/data-scientist/skills/01-eda-automation/README.md +230 -0
- package/tech_hub_skills/roles/data-scientist/skills/02-statistical-modeling/README.md +264 -0
- package/tech_hub_skills/roles/data-scientist/skills/03-feature-engineering/README.md +264 -0
- package/tech_hub_skills/roles/data-scientist/skills/04-predictive-modeling/README.md +264 -0
- package/tech_hub_skills/roles/data-scientist/skills/05-customer-analytics/README.md +264 -0
- package/tech_hub_skills/roles/data-scientist/skills/06-campaign-analysis/README.md +264 -0
- package/tech_hub_skills/roles/data-scientist/skills/07-experimentation/README.md +264 -0
- package/tech_hub_skills/roles/data-scientist/skills/08-data-visualization/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/01-cicd-pipeline/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/02-container-orchestration/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/03-infrastructure-as-code/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/04-gitops/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/05-environment-management/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/06-automated-testing/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/07-release-management/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/08-monitoring-alerting/README.md +264 -0
- package/tech_hub_skills/roles/devops/skills/09-devsecops/README.md +265 -0
- package/tech_hub_skills/roles/finops/skills/01-cost-visibility/README.md +264 -0
- package/tech_hub_skills/roles/finops/skills/02-resource-tagging/README.md +264 -0
- package/tech_hub_skills/roles/finops/skills/03-budget-management/README.md +264 -0
- package/tech_hub_skills/roles/finops/skills/04-reserved-instances/README.md +264 -0
- package/tech_hub_skills/roles/finops/skills/05-spot-optimization/README.md +264 -0
- package/tech_hub_skills/roles/finops/skills/06-storage-tiering/README.md +264 -0
- package/tech_hub_skills/roles/finops/skills/07-compute-rightsizing/README.md +264 -0
- package/tech_hub_skills/roles/finops/skills/08-chargeback/README.md +264 -0
- package/tech_hub_skills/roles/ml-engineer/skills/01-mlops-pipeline/README.md +566 -0
- package/tech_hub_skills/roles/ml-engineer/skills/02-feature-engineering/README.md +655 -0
- package/tech_hub_skills/roles/ml-engineer/skills/03-model-training/README.md +704 -0
- package/tech_hub_skills/roles/ml-engineer/skills/04-model-serving/README.md +845 -0
- package/tech_hub_skills/roles/ml-engineer/skills/05-model-monitoring/README.md +874 -0
- package/tech_hub_skills/roles/mlops/skills/01-ml-pipeline-orchestration/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/02-experiment-tracking/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/03-model-registry/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/04-feature-store/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/05-model-deployment/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/06-model-observability/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/07-data-versioning/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/08-ab-testing/README.md +264 -0
- package/tech_hub_skills/roles/mlops/skills/09-automated-retraining/README.md +264 -0
- package/tech_hub_skills/roles/platform-engineer/skills/01-internal-developer-platform/README.md +153 -0
- package/tech_hub_skills/roles/platform-engineer/skills/02-self-service-infrastructure/README.md +57 -0
- package/tech_hub_skills/roles/platform-engineer/skills/03-slo-sli-management/README.md +59 -0
- package/tech_hub_skills/roles/platform-engineer/skills/04-developer-experience/README.md +57 -0
- package/tech_hub_skills/roles/platform-engineer/skills/05-incident-management/README.md +73 -0
- package/tech_hub_skills/roles/platform-engineer/skills/06-capacity-management/README.md +59 -0
- package/tech_hub_skills/roles/product-designer/skills/01-requirements-discovery/README.md +407 -0
- package/tech_hub_skills/roles/product-designer/skills/02-user-research/README.md +382 -0
- package/tech_hub_skills/roles/product-designer/skills/03-brainstorming-ideation/README.md +437 -0
- package/tech_hub_skills/roles/product-designer/skills/04-ux-design/README.md +496 -0
- package/tech_hub_skills/roles/product-designer/skills/05-product-market-fit/README.md +376 -0
- package/tech_hub_skills/roles/product-designer/skills/06-stakeholder-management/README.md +412 -0
- package/tech_hub_skills/roles/security-architect/skills/01-pii-detection/README.md +319 -0
- package/tech_hub_skills/roles/security-architect/skills/02-threat-modeling/README.md +264 -0
- package/tech_hub_skills/roles/security-architect/skills/03-infrastructure-security/README.md +264 -0
- package/tech_hub_skills/roles/security-architect/skills/04-iam/README.md +264 -0
- package/tech_hub_skills/roles/security-architect/skills/05-application-security/README.md +264 -0
- package/tech_hub_skills/roles/security-architect/skills/06-secrets-management/README.md +264 -0
- package/tech_hub_skills/roles/security-architect/skills/07-security-monitoring/README.md +264 -0
- package/tech_hub_skills/roles/system-design/skills/01-architecture-patterns/README.md +337 -0
- package/tech_hub_skills/roles/system-design/skills/02-requirements-engineering/README.md +264 -0
- package/tech_hub_skills/roles/system-design/skills/03-scalability/README.md +264 -0
- package/tech_hub_skills/roles/system-design/skills/04-high-availability/README.md +264 -0
- package/tech_hub_skills/roles/system-design/skills/05-cost-optimization-design/README.md +264 -0
- package/tech_hub_skills/roles/system-design/skills/06-api-design/README.md +264 -0
- package/tech_hub_skills/roles/system-design/skills/07-observability-architecture/README.md +264 -0
- package/tech_hub_skills/roles/system-design/skills/08-process-automation/PROCESS_TEMPLATE.md +336 -0
- package/tech_hub_skills/roles/system-design/skills/08-process-automation/README.md +521 -0
- package/tech_hub_skills/skills/README.md +336 -0
- package/tech_hub_skills/skills/ai-engineer.md +104 -0
- package/tech_hub_skills/skills/azure.md +149 -0
- package/tech_hub_skills/skills/code-review.md +399 -0
- package/tech_hub_skills/skills/compliance-automation.md +747 -0
- package/tech_hub_skills/skills/data-engineer.md +113 -0
- package/tech_hub_skills/skills/data-governance.md +102 -0
- package/tech_hub_skills/skills/data-scientist.md +123 -0
- package/tech_hub_skills/skills/devops.md +160 -0
- package/tech_hub_skills/skills/docker.md +160 -0
- package/tech_hub_skills/skills/enterprise-dashboard.md +613 -0
- package/tech_hub_skills/skills/finops.md +184 -0
- package/tech_hub_skills/skills/ml-engineer.md +115 -0
- package/tech_hub_skills/skills/mlops.md +187 -0
- package/tech_hub_skills/skills/optimization-advisor.md +329 -0
- package/tech_hub_skills/skills/orchestrator.md +497 -0
- package/tech_hub_skills/skills/platform-engineer.md +102 -0
- package/tech_hub_skills/skills/process-automation.md +226 -0
- package/tech_hub_skills/skills/process-changelog.md +184 -0
- package/tech_hub_skills/skills/process-documentation.md +484 -0
- package/tech_hub_skills/skills/process-kanban.md +324 -0
- package/tech_hub_skills/skills/process-versioning.md +214 -0
- package/tech_hub_skills/skills/product-designer.md +104 -0
- package/tech_hub_skills/skills/project-starter.md +443 -0
- package/tech_hub_skills/skills/security-architect.md +135 -0
- package/tech_hub_skills/skills/system-design.md +126 -0
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
# cr-04: Reviewer Assignment
|
|
2
|
+
|
|
3
|
+
Intelligent reviewer selection with CODEOWNERS, load balancing, and expertise matching.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Effective reviewer assignment ensures the right people review the right code. This skill provides automated assignment based on code ownership, expertise, availability, and workload balancing.
|
|
8
|
+
|
|
9
|
+
## Capabilities
|
|
10
|
+
|
|
11
|
+
### CODEOWNERS Management
|
|
12
|
+
- File and directory ownership rules
|
|
13
|
+
- Team-based ownership
|
|
14
|
+
- Fallback reviewers
|
|
15
|
+
- Wildcard patterns
|
|
16
|
+
|
|
17
|
+
### Intelligent Assignment
|
|
18
|
+
- Expertise matching based on history
|
|
19
|
+
- Workload balancing across team
|
|
20
|
+
- Availability awareness
|
|
21
|
+
- Timezone considerations
|
|
22
|
+
|
|
23
|
+
### Assignment Rules
|
|
24
|
+
- Required vs optional reviewers
|
|
25
|
+
- Minimum review count
|
|
26
|
+
- Escalation paths
|
|
27
|
+
- Conflict of interest detection
|
|
28
|
+
|
|
29
|
+
## Implementation
|
|
30
|
+
|
|
31
|
+
### CODEOWNERS File
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
# CODEOWNERS - GitHub/GitLab code ownership
|
|
35
|
+
# Syntax: pattern @user-or-team
|
|
36
|
+
|
|
37
|
+
# Default: core team reviews everything not otherwise specified
|
|
38
|
+
* @org/core-team
|
|
39
|
+
|
|
40
|
+
# ============================================
|
|
41
|
+
# FRONTEND
|
|
42
|
+
# ============================================
|
|
43
|
+
/src/components/** @org/frontend-team
|
|
44
|
+
/src/pages/** @org/frontend-team
|
|
45
|
+
/src/hooks/** @org/frontend-team
|
|
46
|
+
*.tsx @org/frontend-team
|
|
47
|
+
*.css @org/frontend-team
|
|
48
|
+
*.scss @org/frontend-team
|
|
49
|
+
/public/** @org/frontend-team
|
|
50
|
+
|
|
51
|
+
# ============================================
|
|
52
|
+
# BACKEND
|
|
53
|
+
# ============================================
|
|
54
|
+
/src/api/** @org/backend-team
|
|
55
|
+
/src/services/** @org/backend-team
|
|
56
|
+
/src/models/** @org/backend-team
|
|
57
|
+
*.py @org/python-team
|
|
58
|
+
/src/server/** @org/backend-team
|
|
59
|
+
|
|
60
|
+
# ============================================
|
|
61
|
+
# DATA
|
|
62
|
+
# ============================================
|
|
63
|
+
/src/data/** @org/data-team
|
|
64
|
+
/pipelines/** @org/data-team
|
|
65
|
+
*.sql @org/data-team
|
|
66
|
+
/dbt/** @org/data-team
|
|
67
|
+
|
|
68
|
+
# ============================================
|
|
69
|
+
# INFRASTRUCTURE & DEVOPS
|
|
70
|
+
# ============================================
|
|
71
|
+
/terraform/** @org/platform-team @org/security-team
|
|
72
|
+
/kubernetes/** @org/platform-team
|
|
73
|
+
/.github/workflows/** @org/platform-team
|
|
74
|
+
/docker/** @org/platform-team
|
|
75
|
+
Dockerfile* @org/platform-team
|
|
76
|
+
docker-compose*.yml @org/platform-team
|
|
77
|
+
|
|
78
|
+
# ============================================
|
|
79
|
+
# SECURITY-SENSITIVE FILES (Require security review)
|
|
80
|
+
# ============================================
|
|
81
|
+
**/auth/** @org/security-team
|
|
82
|
+
**/security/** @org/security-team
|
|
83
|
+
**/crypto/** @org/security-team
|
|
84
|
+
**/*secret* @org/security-team
|
|
85
|
+
**/*password* @org/security-team
|
|
86
|
+
**/*token* @org/security-team
|
|
87
|
+
.env* @org/security-team
|
|
88
|
+
**/iam/** @org/security-team
|
|
89
|
+
|
|
90
|
+
# ============================================
|
|
91
|
+
# DATABASE MIGRATIONS (Require DBA review)
|
|
92
|
+
# ============================================
|
|
93
|
+
**/migrations/** @org/dba-team @org/backend-team
|
|
94
|
+
*.migration.* @org/dba-team
|
|
95
|
+
|
|
96
|
+
# ============================================
|
|
97
|
+
# API CONTRACTS
|
|
98
|
+
# ============================================
|
|
99
|
+
**/openapi/** @org/api-governance
|
|
100
|
+
*.openapi.yaml @org/api-governance
|
|
101
|
+
**/graphql/schema/** @org/api-governance
|
|
102
|
+
|
|
103
|
+
# ============================================
|
|
104
|
+
# DOCUMENTATION
|
|
105
|
+
# ============================================
|
|
106
|
+
*.md @org/docs-team
|
|
107
|
+
/docs/** @org/docs-team
|
|
108
|
+
README* @org/docs-team
|
|
109
|
+
|
|
110
|
+
# ============================================
|
|
111
|
+
# DEPENDENCIES & CONFIGURATION
|
|
112
|
+
# ============================================
|
|
113
|
+
package.json @org/core-team @org/security-team
|
|
114
|
+
package-lock.json @org/core-team
|
|
115
|
+
requirements.txt @org/core-team @org/security-team
|
|
116
|
+
pyproject.toml @org/core-team
|
|
117
|
+
|
|
118
|
+
# ============================================
|
|
119
|
+
# CRITICAL FILES (Require lead approval)
|
|
120
|
+
# ============================================
|
|
121
|
+
/.github/CODEOWNERS @org/engineering-leads
|
|
122
|
+
/src/core/** @org/engineering-leads
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Auto-Assignment Configuration
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
# .github/auto-assign.yml
|
|
129
|
+
# GitHub Auto-Assign Action configuration
|
|
130
|
+
|
|
131
|
+
# Add reviewers to pull requests
|
|
132
|
+
addReviewers: true
|
|
133
|
+
|
|
134
|
+
# Add assignees to pull requests
|
|
135
|
+
addAssignees: true
|
|
136
|
+
|
|
137
|
+
# Strategy: round-robin, random, or load-balance
|
|
138
|
+
reviewersStrategy: load-balance
|
|
139
|
+
|
|
140
|
+
# Number of reviewers to assign
|
|
141
|
+
numberOfReviewers: 2
|
|
142
|
+
|
|
143
|
+
# Review groups - assign from specific teams
|
|
144
|
+
reviewGroups:
|
|
145
|
+
frontend:
|
|
146
|
+
- frontend-dev-1
|
|
147
|
+
- frontend-dev-2
|
|
148
|
+
- frontend-dev-3
|
|
149
|
+
|
|
150
|
+
backend:
|
|
151
|
+
- backend-dev-1
|
|
152
|
+
- backend-dev-2
|
|
153
|
+
- backend-dev-3
|
|
154
|
+
|
|
155
|
+
fullstack:
|
|
156
|
+
- fullstack-1
|
|
157
|
+
- fullstack-2
|
|
158
|
+
|
|
159
|
+
# Assign from groups based on file patterns
|
|
160
|
+
useReviewGroups: true
|
|
161
|
+
|
|
162
|
+
# File pattern to group mapping
|
|
163
|
+
filterLabels:
|
|
164
|
+
frontend:
|
|
165
|
+
- "*.tsx"
|
|
166
|
+
- "*.css"
|
|
167
|
+
- "src/components/**"
|
|
168
|
+
backend:
|
|
169
|
+
- "*.py"
|
|
170
|
+
- "src/api/**"
|
|
171
|
+
- "src/services/**"
|
|
172
|
+
|
|
173
|
+
# Skip if author is the only team member
|
|
174
|
+
skipIfAlreadyReviewing: true
|
|
175
|
+
|
|
176
|
+
# Don't assign author as reviewer
|
|
177
|
+
skipAssigneesForAuthor: true
|
|
178
|
+
|
|
179
|
+
# Skip if PR is draft
|
|
180
|
+
skipDraft: true
|
|
181
|
+
|
|
182
|
+
# Max reviews per person (load balancing)
|
|
183
|
+
maxReviewsPerPerson: 5
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Intelligent Assignment System
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
#!/usr/bin/env python3
|
|
190
|
+
"""Intelligent reviewer assignment system."""
|
|
191
|
+
|
|
192
|
+
from dataclasses import dataclass, field
|
|
193
|
+
from typing import List, Dict, Set, Optional
|
|
194
|
+
from datetime import datetime, timedelta
|
|
195
|
+
from collections import defaultdict
|
|
196
|
+
import random
|
|
197
|
+
|
|
198
|
+
@dataclass
|
|
199
|
+
class Developer:
|
|
200
|
+
"""Represents a developer for review assignment."""
|
|
201
|
+
username: str
|
|
202
|
+
teams: List[str]
|
|
203
|
+
expertise: List[str] # File patterns they're expert in
|
|
204
|
+
timezone: str
|
|
205
|
+
active_reviews: int = 0
|
|
206
|
+
max_reviews: int = 5
|
|
207
|
+
on_vacation: bool = False
|
|
208
|
+
last_assigned: Optional[datetime] = None
|
|
209
|
+
|
|
210
|
+
@dataclass
|
|
211
|
+
class PullRequest:
|
|
212
|
+
"""Represents a PR needing reviewers."""
|
|
213
|
+
number: int
|
|
214
|
+
author: str
|
|
215
|
+
files_changed: List[str]
|
|
216
|
+
labels: List[str] = field(default_factory=list)
|
|
217
|
+
is_security_sensitive: bool = False
|
|
218
|
+
is_database_change: bool = False
|
|
219
|
+
|
|
220
|
+
class ReviewerAssigner:
|
|
221
|
+
"""Assigns reviewers based on multiple factors."""
|
|
222
|
+
|
|
223
|
+
def __init__(self, developers: List[Developer], codeowners: Dict[str, List[str]]):
|
|
224
|
+
self.developers = {d.username: d for d in developers}
|
|
225
|
+
self.codeowners = codeowners
|
|
226
|
+
self.assignment_history: Dict[str, List[datetime]] = defaultdict(list)
|
|
227
|
+
|
|
228
|
+
def assign_reviewers(
|
|
229
|
+
self,
|
|
230
|
+
pr: PullRequest,
|
|
231
|
+
min_reviewers: int = 2,
|
|
232
|
+
require_codeowner: bool = True
|
|
233
|
+
) -> List[str]:
|
|
234
|
+
"""Assign reviewers to a PR."""
|
|
235
|
+
candidates = self._get_candidates(pr)
|
|
236
|
+
assigned = []
|
|
237
|
+
|
|
238
|
+
# 1. Must include CODEOWNER if required
|
|
239
|
+
if require_codeowner:
|
|
240
|
+
codeowner = self._select_codeowner(pr, candidates)
|
|
241
|
+
if codeowner:
|
|
242
|
+
assigned.append(codeowner)
|
|
243
|
+
candidates.remove(codeowner)
|
|
244
|
+
|
|
245
|
+
# 2. Add security reviewer if needed
|
|
246
|
+
if pr.is_security_sensitive:
|
|
247
|
+
security_reviewer = self._select_from_team("security-team", candidates, pr)
|
|
248
|
+
if security_reviewer:
|
|
249
|
+
assigned.append(security_reviewer)
|
|
250
|
+
candidates.discard(security_reviewer)
|
|
251
|
+
|
|
252
|
+
# 3. Add DBA if database change
|
|
253
|
+
if pr.is_database_change:
|
|
254
|
+
dba = self._select_from_team("dba-team", candidates, pr)
|
|
255
|
+
if dba:
|
|
256
|
+
assigned.append(dba)
|
|
257
|
+
candidates.discard(dba)
|
|
258
|
+
|
|
259
|
+
# 4. Fill remaining slots with load-balanced selection
|
|
260
|
+
while len(assigned) < min_reviewers and candidates:
|
|
261
|
+
reviewer = self._select_load_balanced(candidates, pr)
|
|
262
|
+
if reviewer:
|
|
263
|
+
assigned.append(reviewer)
|
|
264
|
+
candidates.discard(reviewer)
|
|
265
|
+
else:
|
|
266
|
+
break
|
|
267
|
+
|
|
268
|
+
# Update assignment tracking
|
|
269
|
+
for reviewer in assigned:
|
|
270
|
+
self.developers[reviewer].active_reviews += 1
|
|
271
|
+
self.developers[reviewer].last_assigned = datetime.now()
|
|
272
|
+
self.assignment_history[reviewer].append(datetime.now())
|
|
273
|
+
|
|
274
|
+
return assigned
|
|
275
|
+
|
|
276
|
+
def _get_candidates(self, pr: PullRequest) -> Set[str]:
|
|
277
|
+
"""Get all eligible candidates for review."""
|
|
278
|
+
candidates = set()
|
|
279
|
+
|
|
280
|
+
for dev in self.developers.values():
|
|
281
|
+
# Exclude author
|
|
282
|
+
if dev.username == pr.author:
|
|
283
|
+
continue
|
|
284
|
+
|
|
285
|
+
# Exclude unavailable
|
|
286
|
+
if dev.on_vacation:
|
|
287
|
+
continue
|
|
288
|
+
|
|
289
|
+
# Exclude overloaded
|
|
290
|
+
if dev.active_reviews >= dev.max_reviews:
|
|
291
|
+
continue
|
|
292
|
+
|
|
293
|
+
candidates.add(dev.username)
|
|
294
|
+
|
|
295
|
+
return candidates
|
|
296
|
+
|
|
297
|
+
def _select_codeowner(self, pr: PullRequest, candidates: Set[str]) -> Optional[str]:
|
|
298
|
+
"""Select a CODEOWNER for the changed files."""
|
|
299
|
+
owners = set()
|
|
300
|
+
|
|
301
|
+
for file in pr.files_changed:
|
|
302
|
+
for pattern, owner_list in self.codeowners.items():
|
|
303
|
+
if self._matches_pattern(file, pattern):
|
|
304
|
+
owners.update(owner_list)
|
|
305
|
+
|
|
306
|
+
# Filter to available candidates
|
|
307
|
+
available_owners = owners & candidates
|
|
308
|
+
|
|
309
|
+
if not available_owners:
|
|
310
|
+
return None
|
|
311
|
+
|
|
312
|
+
# Select least loaded owner
|
|
313
|
+
return self._select_load_balanced(available_owners, pr)
|
|
314
|
+
|
|
315
|
+
def _select_from_team(
|
|
316
|
+
self,
|
|
317
|
+
team: str,
|
|
318
|
+
candidates: Set[str],
|
|
319
|
+
pr: PullRequest
|
|
320
|
+
) -> Optional[str]:
|
|
321
|
+
"""Select a reviewer from a specific team."""
|
|
322
|
+
team_members = {
|
|
323
|
+
username for username, dev in self.developers.items()
|
|
324
|
+
if team in dev.teams and username in candidates
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if not team_members:
|
|
328
|
+
return None
|
|
329
|
+
|
|
330
|
+
return self._select_load_balanced(team_members, pr)
|
|
331
|
+
|
|
332
|
+
def _select_load_balanced(
|
|
333
|
+
self,
|
|
334
|
+
candidates: Set[str],
|
|
335
|
+
pr: PullRequest
|
|
336
|
+
) -> Optional[str]:
|
|
337
|
+
"""Select reviewer with lowest load, with expertise tiebreaker."""
|
|
338
|
+
if not candidates:
|
|
339
|
+
return None
|
|
340
|
+
|
|
341
|
+
scored = []
|
|
342
|
+
for username in candidates:
|
|
343
|
+
dev = self.developers[username]
|
|
344
|
+
score = self._calculate_score(dev, pr)
|
|
345
|
+
scored.append((username, score))
|
|
346
|
+
|
|
347
|
+
# Sort by score (lower is better), with randomization for ties
|
|
348
|
+
scored.sort(key=lambda x: (x[1], random.random()))
|
|
349
|
+
|
|
350
|
+
return scored[0][0] if scored else None
|
|
351
|
+
|
|
352
|
+
def _calculate_score(self, dev: Developer, pr: PullRequest) -> float:
|
|
353
|
+
"""Calculate assignment score (lower is better)."""
|
|
354
|
+
score = 0.0
|
|
355
|
+
|
|
356
|
+
# Active review load (major factor)
|
|
357
|
+
score += dev.active_reviews * 10
|
|
358
|
+
|
|
359
|
+
# Recent assignments (avoid assigning same person repeatedly)
|
|
360
|
+
recent = sum(
|
|
361
|
+
1 for dt in self.assignment_history.get(dev.username, [])
|
|
362
|
+
if dt > datetime.now() - timedelta(days=7)
|
|
363
|
+
)
|
|
364
|
+
score += recent * 5
|
|
365
|
+
|
|
366
|
+
# Expertise match (negative = good)
|
|
367
|
+
for pattern in dev.expertise:
|
|
368
|
+
for file in pr.files_changed:
|
|
369
|
+
if self._matches_pattern(file, pattern):
|
|
370
|
+
score -= 3
|
|
371
|
+
|
|
372
|
+
return score
|
|
373
|
+
|
|
374
|
+
def _matches_pattern(self, file: str, pattern: str) -> bool:
|
|
375
|
+
"""Check if file matches CODEOWNERS pattern."""
|
|
376
|
+
import fnmatch
|
|
377
|
+
# Handle directory patterns
|
|
378
|
+
if pattern.endswith("/**"):
|
|
379
|
+
dir_pattern = pattern[:-3]
|
|
380
|
+
return file.startswith(dir_pattern.lstrip("/"))
|
|
381
|
+
return fnmatch.fnmatch(file, pattern.lstrip("/"))
|
|
382
|
+
|
|
383
|
+
def get_reviewer_load(self) -> Dict[str, Dict]:
|
|
384
|
+
"""Get current reviewer load statistics."""
|
|
385
|
+
return {
|
|
386
|
+
username: {
|
|
387
|
+
"active_reviews": dev.active_reviews,
|
|
388
|
+
"max_reviews": dev.max_reviews,
|
|
389
|
+
"utilization": f"{(dev.active_reviews / dev.max_reviews) * 100:.0f}%",
|
|
390
|
+
"recent_assignments": len([
|
|
391
|
+
dt for dt in self.assignment_history.get(username, [])
|
|
392
|
+
if dt > datetime.now() - timedelta(days=7)
|
|
393
|
+
])
|
|
394
|
+
}
|
|
395
|
+
for username, dev in self.developers.items()
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
# GitHub Action for auto-assignment
|
|
400
|
+
GITHUB_ACTION = """
|
|
401
|
+
name: Auto Assign Reviewers
|
|
402
|
+
on:
|
|
403
|
+
pull_request:
|
|
404
|
+
types: [opened, ready_for_review]
|
|
405
|
+
|
|
406
|
+
jobs:
|
|
407
|
+
assign:
|
|
408
|
+
runs-on: ubuntu-latest
|
|
409
|
+
steps:
|
|
410
|
+
- uses: actions/checkout@v4
|
|
411
|
+
|
|
412
|
+
- name: Get changed files
|
|
413
|
+
id: files
|
|
414
|
+
uses: tj-actions/changed-files@v41
|
|
415
|
+
|
|
416
|
+
- name: Assign reviewers
|
|
417
|
+
uses: actions/github-script@v7
|
|
418
|
+
with:
|
|
419
|
+
script: |
|
|
420
|
+
const changedFiles = '${{ steps.files.outputs.all_changed_files }}'.split(' ');
|
|
421
|
+
|
|
422
|
+
// Determine required reviewers based on files
|
|
423
|
+
const reviewers = new Set();
|
|
424
|
+
const teams = new Set();
|
|
425
|
+
|
|
426
|
+
for (const file of changedFiles) {
|
|
427
|
+
if (file.includes('/auth/') || file.includes('/security/')) {
|
|
428
|
+
teams.add('security-team');
|
|
429
|
+
}
|
|
430
|
+
if (file.includes('/migrations/') || file.endsWith('.sql')) {
|
|
431
|
+
teams.add('dba-team');
|
|
432
|
+
}
|
|
433
|
+
if (file.startsWith('terraform/') || file.startsWith('kubernetes/')) {
|
|
434
|
+
teams.add('platform-team');
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Request team reviews
|
|
439
|
+
if (teams.size > 0) {
|
|
440
|
+
await github.rest.pulls.requestReviewers({
|
|
441
|
+
owner: context.repo.owner,
|
|
442
|
+
repo: context.repo.repo,
|
|
443
|
+
pull_number: context.issue.number,
|
|
444
|
+
team_reviewers: Array.from(teams)
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
"""
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Escalation Configuration
|
|
451
|
+
|
|
452
|
+
```yaml
|
|
453
|
+
# .github/review-escalation.yml
|
|
454
|
+
escalation:
|
|
455
|
+
# Escalate if no review after X hours
|
|
456
|
+
no_review_timeout: 24
|
|
457
|
+
escalation_chain:
|
|
458
|
+
- level: 1
|
|
459
|
+
after_hours: 24
|
|
460
|
+
action: remind_reviewers
|
|
461
|
+
message: "Reminder: PR #{pr_number} needs review"
|
|
462
|
+
|
|
463
|
+
- level: 2
|
|
464
|
+
after_hours: 48
|
|
465
|
+
action: add_team_lead
|
|
466
|
+
teams: ["engineering-leads"]
|
|
467
|
+
message: "Escalation: PR #{pr_number} unreviewed for 48 hours"
|
|
468
|
+
|
|
469
|
+
- level: 3
|
|
470
|
+
after_hours: 72
|
|
471
|
+
action: notify_manager
|
|
472
|
+
slack_channel: "#engineering-escalations"
|
|
473
|
+
message: "Critical: PR #{pr_number} blocked for 72 hours"
|
|
474
|
+
|
|
475
|
+
# Conflict of interest rules
|
|
476
|
+
conflict_rules:
|
|
477
|
+
- author_reports_to_reviewer: warn
|
|
478
|
+
- same_team_only: require_external
|
|
479
|
+
- self_approval: block
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Metrics
|
|
483
|
+
|
|
484
|
+
| Metric | Target | Description |
|
|
485
|
+
|--------|--------|-------------|
|
|
486
|
+
| Assignment accuracy | > 90% | Right expertise assigned |
|
|
487
|
+
| Load balance variance | < 20% | Even distribution |
|
|
488
|
+
| Escalation rate | < 5% | Reviews happening on time |
|
|
489
|
+
| CODEOWNER coverage | 100% | All files have owners |
|
|
490
|
+
|
|
491
|
+
## Connections
|
|
492
|
+
|
|
493
|
+
- **Inputs from**: PR creation event
|
|
494
|
+
- **Outputs to**: Review workflow (cr-02), analytics (cr-05)
|
|
495
|
+
- **Integrates with**: Team management, PTO calendars
|
|
496
|
+
|
|
497
|
+
## Best Practices
|
|
498
|
+
|
|
499
|
+
1. Keep CODEOWNERS up to date as team changes
|
|
500
|
+
2. Set reasonable max review limits (5-7)
|
|
501
|
+
3. Account for timezone differences
|
|
502
|
+
4. Automate vacation/OOO detection
|
|
503
|
+
5. Review assignment patterns quarterly
|
|
504
|
+
6. Balance between expertise and load
|