906 lines
24 KiB
Markdown
906 lines
24 KiB
Markdown
---
|
||
name: ado-resource-validator
|
||
description: Validates Azure DevOps projects and resources exist, creates missing resources automatically. Smart enough to prompt user to select existing or create new projects. Supports multiple projects for project-per-team strategy, area paths for area-path-based strategy, and teams for team-based strategy. NEW - Per-project configuration support - AZURE_DEVOPS_AREA_PATHS_{ProjectName} and AZURE_DEVOPS_TEAMS_{ProjectName} for hierarchical organization. Activates for ado setup, ado validation, ado configuration, missing ado project, azure devops .env setup, per-project area paths, per-project teams.
|
||
allowed-tools: Read, Bash, Write, Edit
|
||
---
|
||
|
||
# Azure DevOps Resource Validator Skill
|
||
|
||
**Purpose**: Validate and auto-create Azure DevOps projects and resources, ensuring .env configuration is correct.
|
||
|
||
**Auto-Activation**: Triggers when Azure DevOps setup or validation is needed.
|
||
|
||
## What This Skill Does
|
||
|
||
This skill ensures your Azure DevOps configuration in `.env` is valid and all resources exist. It's **smart enough** to:
|
||
|
||
1. **Validate Azure DevOps projects** - Check if projects exist (multiple for project-per-team)
|
||
2. **Prompt for action** - Select existing project or create new one
|
||
3. **Validate area paths** - Check if area paths exist (for area-path-based strategy)
|
||
4. **Create missing area paths** - Auto-create area paths if missing
|
||
5. **Validate teams** - Check if teams exist (for team-based strategy)
|
||
6. **Update .env with correct values** - Ensure configuration is valid
|
||
|
||
## When This Skill Activates
|
||
|
||
✅ **Automatically activates when**:
|
||
- You set up Azure DevOps integration for the first time
|
||
- You run `/specweave-ado:sync` and resources are missing
|
||
- Your `.env` has invalid Azure DevOps configuration
|
||
- You mention "ado setup" or "azure devops validation"
|
||
|
||
## Azure DevOps Configuration Structure
|
||
|
||
### Required .env Variables
|
||
|
||
```bash
|
||
AZURE_DEVOPS_PAT=your_token_here
|
||
AZURE_DEVOPS_ORG=yourorganization
|
||
AZURE_DEVOPS_STRATEGY=project-per-team # or area-path-based, team-based
|
||
```
|
||
|
||
### Strategy-Specific Variables
|
||
|
||
**Strategy 1: Project-per-team** (Multiple Projects)
|
||
```bash
|
||
AZURE_DEVOPS_STRATEGY=project-per-team
|
||
AZURE_DEVOPS_PROJECTS=WebApp,MobileApp,Platform
|
||
```
|
||
→ Validates that WebApp, MobileApp, and Platform projects exist
|
||
|
||
**Strategy 2: Area-path-based** (One Project, Multiple Area Paths)
|
||
```bash
|
||
AZURE_DEVOPS_STRATEGY=area-path-based
|
||
AZURE_DEVOPS_PROJECT=MainProduct
|
||
AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile
|
||
```
|
||
→ Validates MainProduct project exists
|
||
→ Creates area paths if missing: MainProduct\Frontend, MainProduct\Backend, MainProduct\Mobile
|
||
|
||
**Strategy 3: Team-based** (One Project, Multiple Teams)
|
||
```bash
|
||
AZURE_DEVOPS_STRATEGY=team-based
|
||
AZURE_DEVOPS_PROJECT=MainProduct
|
||
AZURE_DEVOPS_TEAMS=Alpha Team,Beta Team,Gamma Team
|
||
```
|
||
→ Validates MainProduct project exists
|
||
→ Creates teams if missing: Alpha Team, Beta Team, Gamma Team
|
||
|
||
**NEW: Per-Project Configuration** (Advanced - Multiple Projects × Resources)
|
||
```bash
|
||
# Multiple projects with their own area paths and teams
|
||
AZURE_DEVOPS_STRATEGY=project-per-team
|
||
AZURE_DEVOPS_PROJECTS=Backend,Frontend,Mobile
|
||
|
||
# Per-project area paths (hierarchical naming)
|
||
AZURE_DEVOPS_AREA_PATHS_Backend=API,Database,Cache
|
||
AZURE_DEVOPS_AREA_PATHS_Frontend=Web,Admin,Public
|
||
AZURE_DEVOPS_AREA_PATHS_Mobile=iOS,Android,Shared
|
||
|
||
# Per-project teams (optional)
|
||
AZURE_DEVOPS_TEAMS_Backend=Alpha,Beta
|
||
AZURE_DEVOPS_TEAMS_Frontend=Gamma
|
||
```
|
||
→ Validates 3 projects exist: Backend, Frontend, Mobile
|
||
→ Creates area paths per project:
|
||
- Backend\API, Backend\Database, Backend\Cache
|
||
- Frontend\Web, Frontend\Admin, Frontend\Public
|
||
- Mobile\iOS, Mobile\Android, Mobile\Shared
|
||
→ Creates teams per project:
|
||
- Backend: Alpha, Beta
|
||
- Frontend: Gamma
|
||
|
||
**Naming Convention**: `{PROVIDER}_{RESOURCE_TYPE}_{PROJECT_NAME}`
|
||
|
||
## Validation Flow
|
||
|
||
### Step 1: Strategy Detection
|
||
|
||
**Read .env and detect strategy**:
|
||
```bash
|
||
AZURE_DEVOPS_STRATEGY=project-per-team
|
||
```
|
||
|
||
**Result**:
|
||
```
|
||
🔍 Detected strategy: Project-per-team
|
||
Projects to validate: WebApp, MobileApp, Platform
|
||
```
|
||
|
||
### Step 2: Project Validation (Project-per-team)
|
||
|
||
**Check if projects exist**:
|
||
```bash
|
||
# API calls to Azure DevOps
|
||
GET https://dev.azure.com/{org}/_apis/projects/WebApp
|
||
GET https://dev.azure.com/{org}/_apis/projects/MobileApp
|
||
GET https://dev.azure.com/{org}/_apis/projects/Platform
|
||
```
|
||
|
||
**If all projects exist**:
|
||
```
|
||
✅ All projects validated:
|
||
• WebApp (ID: abcd1234)
|
||
• MobileApp (ID: efgh5678)
|
||
• Platform (ID: ijkl9012)
|
||
```
|
||
|
||
**If some projects don't exist**:
|
||
```
|
||
⚠️ Projects not found:
|
||
✅ WebApp (exists)
|
||
❌ MobileApp (not found)
|
||
❌ Platform (not found)
|
||
|
||
What would you like to do?
|
||
1. Create missing projects
|
||
2. Select existing projects
|
||
3. Fix project names manually
|
||
4. Cancel
|
||
|
||
Your choice [1]:
|
||
```
|
||
|
||
**Option 1: Create Missing Projects**:
|
||
```
|
||
📦 Creating Azure DevOps projects...
|
||
|
||
Creating project: MobileApp...
|
||
✅ Project created: MobileApp (ID: mnop3456)
|
||
|
||
Creating project: Platform...
|
||
✅ Project created: Platform (ID: qrst7890)
|
||
|
||
✅ All projects now exist!
|
||
```
|
||
|
||
**Option 2: Select Existing Projects**:
|
||
```
|
||
Available projects in organization:
|
||
1. WebApp
|
||
2. ApiGateway
|
||
3. AuthService
|
||
4. NotificationService
|
||
5. DataPipeline
|
||
|
||
Select projects (comma-separated numbers) [2,3]:
|
||
|
||
✅ Updated .env: AZURE_DEVOPS_PROJECTS=WebApp,ApiGateway,AuthService
|
||
```
|
||
|
||
### Step 3: Area Path Validation (Area-path-based)
|
||
|
||
**Scenario**: One project with area paths
|
||
```bash
|
||
AZURE_DEVOPS_STRATEGY=area-path-based
|
||
AZURE_DEVOPS_PROJECT=MainProduct
|
||
AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile,QA
|
||
```
|
||
|
||
**Validation**:
|
||
```
|
||
Checking project: MainProduct...
|
||
✅ Project "MainProduct" exists
|
||
|
||
Checking area paths...
|
||
✅ MainProduct\Frontend (exists)
|
||
✅ MainProduct\Backend (exists)
|
||
⚠️ MainProduct\Mobile (not found)
|
||
⚠️ MainProduct\QA (not found)
|
||
|
||
📦 Creating missing area paths...
|
||
✅ Created: MainProduct\Mobile
|
||
✅ Created: MainProduct\QA
|
||
|
||
✅ All area paths validated/created successfully
|
||
```
|
||
|
||
### Step 4: Team Validation (Team-based)
|
||
|
||
**Scenario**: One project with multiple teams
|
||
```bash
|
||
AZURE_DEVOPS_STRATEGY=team-based
|
||
AZURE_DEVOPS_PROJECT=MainProduct
|
||
AZURE_DEVOPS_TEAMS=Alpha Team,Beta Team,Gamma Team
|
||
```
|
||
|
||
**Validation**:
|
||
```
|
||
Checking project: MainProduct...
|
||
✅ Project "MainProduct" exists
|
||
|
||
Checking teams...
|
||
✅ Alpha Team (exists)
|
||
⚠️ Beta Team (not found)
|
||
⚠️ Gamma Team (not found)
|
||
|
||
📦 Creating missing teams...
|
||
✅ Created: Beta Team
|
||
✅ Created: Gamma Team
|
||
|
||
✅ All teams validated/created successfully
|
||
```
|
||
|
||
## Usage Examples
|
||
|
||
### Example 1: Fresh Azure DevOps Setup (Project-per-team)
|
||
|
||
**Scenario**: New setup with multiple projects for different teams
|
||
|
||
**Action**: Run `/specweave-ado:sync`
|
||
|
||
**What Happens**:
|
||
```bash
|
||
🔍 Validating Azure DevOps configuration...
|
||
|
||
Strategy: Project-per-team
|
||
Checking projects: WebApp, MobileApp, Platform...
|
||
|
||
⚠️ Projects not found:
|
||
• WebApp
|
||
• MobileApp
|
||
• Platform
|
||
|
||
What would you like to do?
|
||
1. Create new projects
|
||
2. Select existing projects
|
||
3. Cancel
|
||
|
||
Your choice [1]: 1
|
||
|
||
📦 Creating Azure DevOps projects...
|
||
|
||
Creating project: WebApp
|
||
Description: Web application frontend
|
||
Process template: Agile
|
||
✅ Created: WebApp (ID: proj-001)
|
||
|
||
Creating project: MobileApp
|
||
Description: Mobile application
|
||
Process template: Agile
|
||
✅ Created: MobileApp (ID: proj-002)
|
||
|
||
Creating project: Platform
|
||
Description: Backend platform services
|
||
Process template: Agile
|
||
✅ Created: Platform (ID: proj-003)
|
||
|
||
🎉 Azure DevOps configuration complete! All resources ready.
|
||
```
|
||
|
||
### Example 2: Migrate from Single to Multi-Project
|
||
|
||
**Scenario**: Currently using single project, want to split into multiple
|
||
|
||
**Current .env**:
|
||
```bash
|
||
AZURE_DEVOPS_PROJECT=MainProduct
|
||
```
|
||
|
||
**New .env**:
|
||
```bash
|
||
AZURE_DEVOPS_STRATEGY=project-per-team
|
||
AZURE_DEVOPS_PROJECTS=MainProduct-Frontend,MainProduct-Backend,MainProduct-Mobile
|
||
```
|
||
|
||
**What Happens**:
|
||
```bash
|
||
🔍 Detected strategy change: team-based → project-per-team
|
||
|
||
Validating new projects...
|
||
✅ MainProduct-Frontend (exists from previous split)
|
||
⚠️ MainProduct-Backend (not found)
|
||
⚠️ MainProduct-Mobile (not found)
|
||
|
||
Would you like to:
|
||
1. Create missing projects
|
||
2. Keep single project with area paths instead
|
||
3. Cancel
|
||
|
||
Your choice [1]: 1
|
||
|
||
📦 Creating projects...
|
||
✅ Created: MainProduct-Backend
|
||
✅ Created: MainProduct-Mobile
|
||
|
||
💡 Tip: You can now organize specs by project:
|
||
.specweave/docs/internal/specs/MainProduct-Frontend/
|
||
.specweave/docs/internal/specs/MainProduct-Backend/
|
||
.specweave/docs/internal/specs/MainProduct-Mobile/
|
||
```
|
||
|
||
### Example 3: Area Path Setup
|
||
|
||
**Scenario**: Large monolithic project with area-based organization
|
||
|
||
**Action**: Setup area paths for team organization
|
||
|
||
**What Happens**:
|
||
```bash
|
||
🔍 Validating Azure DevOps configuration...
|
||
|
||
Strategy: Area-path-based
|
||
Project: EnterpriseApp
|
||
Area Paths: Core, UserManagement, Billing, Reports, Analytics
|
||
|
||
Checking project: EnterpriseApp...
|
||
✅ Project exists
|
||
|
||
Checking area paths...
|
||
✅ EnterpriseApp\Core
|
||
✅ EnterpriseApp\UserManagement
|
||
⚠️ EnterpriseApp\Billing (not found)
|
||
⚠️ EnterpriseApp\Reports (not found)
|
||
⚠️ EnterpriseApp\Analytics (not found)
|
||
|
||
📦 Creating area paths...
|
||
|
||
Creating: EnterpriseApp\Billing
|
||
✅ Area path created with default team
|
||
|
||
Creating: EnterpriseApp\Reports
|
||
✅ Area path created with default team
|
||
|
||
Creating: EnterpriseApp\Analytics
|
||
✅ Area path created with default team
|
||
|
||
✅ All area paths ready!
|
||
|
||
Work items will be organized by area:
|
||
• Billing features → EnterpriseApp\Billing
|
||
• Report features → EnterpriseApp\Reports
|
||
• Analytics features → EnterpriseApp\Analytics
|
||
```
|
||
|
||
## Implementation Details
|
||
|
||
**Location**: `src/utils/external-resource-validator.ts`
|
||
|
||
**Core Classes**:
|
||
```typescript
|
||
// Main validator class
|
||
export class AzureDevOpsResourceValidator {
|
||
private pat: string;
|
||
private organization: string;
|
||
private envPath: string;
|
||
|
||
constructor(envPath: string = '.env') {
|
||
this.envPath = envPath;
|
||
const env = this.loadEnv();
|
||
this.pat = env.AZURE_DEVOPS_PAT || '';
|
||
this.organization = env.AZURE_DEVOPS_ORG || '';
|
||
}
|
||
|
||
// Main validation entry point
|
||
async validate(): Promise<AzureDevOpsValidationResult> {
|
||
const env = this.loadEnv();
|
||
const strategy = env.AZURE_DEVOPS_STRATEGY || 'project-per-team';
|
||
|
||
// Validate based on strategy
|
||
if (strategy === 'project-per-team') {
|
||
return this.validateMultipleProjects(projectNames);
|
||
} else if (strategy === 'area-path-based') {
|
||
return this.validateAreaPaths(projectName, areaPaths);
|
||
} else if (strategy === 'team-based') {
|
||
return this.validateTeams(projectName, teams);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Public API function
|
||
export async function validateAzureDevOpsResources(
|
||
envPath: string = '.env'
|
||
): Promise<AzureDevOpsValidationResult> {
|
||
const validator = new AzureDevOpsResourceValidator(envPath);
|
||
return validator.validate();
|
||
}
|
||
```
|
||
|
||
**Key Implementation Features**:
|
||
|
||
1. **Async Project Creation** (ADO-specific):
|
||
```typescript
|
||
// ADO creates projects asynchronously - need to poll for completion
|
||
async createProject(name: string): Promise<AzureDevOpsProject> {
|
||
const result = await this.callAzureDevOpsApi('projects?api-version=7.0', 'POST', body);
|
||
|
||
// Wait for project to be fully created (ADO async behavior)
|
||
await this.waitForProjectCreation(result.id);
|
||
|
||
return { id: result.id, name, description };
|
||
}
|
||
|
||
// Poll until project is in 'wellFormed' state
|
||
private async waitForProjectCreation(projectId: string): Promise<void> {
|
||
const maxAttempts = 30; // 30 seconds max wait
|
||
for (let i = 0; i < maxAttempts; i++) {
|
||
const project = await this.getProject(projectId);
|
||
if (project.state === 'wellFormed') {
|
||
return; // Project is ready!
|
||
}
|
||
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second
|
||
}
|
||
throw new Error('Project creation timeout');
|
||
}
|
||
```
|
||
|
||
2. **Interactive Prompts** (when resources missing):
|
||
```typescript
|
||
const { action } = await inquirer.prompt([
|
||
{
|
||
type: 'select',
|
||
name: 'action',
|
||
message: `Project "${projectName}" not found. What would you like to do?`,
|
||
choices: [
|
||
{ name: 'Create new project', value: 'create' },
|
||
{ name: 'Select existing project', value: 'select' },
|
||
{ name: 'Skip this project', value: 'skip' },
|
||
{ name: 'Cancel', value: 'cancel' }
|
||
]
|
||
}
|
||
]);
|
||
```
|
||
|
||
3. **Automatic .env Updates**:
|
||
```typescript
|
||
// After creating projects, update .env
|
||
updateEnv(key: string, value: string): void {
|
||
const envContent = fs.readFileSync(this.envPath, 'utf-8');
|
||
const updated = envContent.replace(
|
||
new RegExp(`^${key}=.*$`, 'm'),
|
||
`${key}=${value}`
|
||
);
|
||
fs.writeFileSync(this.envPath, updated);
|
||
}
|
||
```
|
||
|
||
## CLI Command
|
||
|
||
**Automatic validation** (during setup):
|
||
```bash
|
||
# Runs automatically during specweave init
|
||
npx specweave init
|
||
|
||
# Also runs automatically before sync
|
||
/specweave-ado:sync 0014
|
||
```
|
||
|
||
**Manual validation**:
|
||
```bash
|
||
# Via skill activation
|
||
"Can you validate my Azure DevOps configuration?"
|
||
|
||
# Via TypeScript directly
|
||
npx tsx -e "import { validateAzureDevOpsResources } from './dist/utils/external-resource-validator.js'; await validateAzureDevOpsResources();"
|
||
|
||
# Via CLI (future command - planned)
|
||
specweave validate-ado
|
||
```
|
||
|
||
**Validation output**:
|
||
```typescript
|
||
interface AzureDevOpsValidationResult {
|
||
valid: boolean;
|
||
strategy: 'project-per-team' | 'area-path-based' | 'team-based';
|
||
projects: Array<{
|
||
name: string;
|
||
id: string;
|
||
exists: boolean;
|
||
}>;
|
||
created: string[]; // Names of newly created resources
|
||
envUpdated: boolean; // Whether .env was modified
|
||
}
|
||
|
||
// Example output:
|
||
{
|
||
valid: true,
|
||
strategy: 'project-per-team',
|
||
projects: [
|
||
{ name: 'WebApp', id: 'proj-001', exists: true },
|
||
{ name: 'MobileApp', id: 'proj-002', exists: true, created: true },
|
||
{ name: 'Platform', id: 'proj-003', exists: true, created: true }
|
||
],
|
||
created: ['MobileApp', 'Platform'],
|
||
envUpdated: false
|
||
}
|
||
```
|
||
|
||
## Smart Project Detection
|
||
|
||
### Auto-detect Based on Work Item Patterns
|
||
|
||
The skill can intelligently suggest project organization based on your existing work items:
|
||
|
||
```typescript
|
||
// Analyze existing work items
|
||
const workItems = await analyzeWorkItems(org, project);
|
||
|
||
// Detect patterns
|
||
const patterns = {
|
||
byArea: workItems.groupBy('areaPath'), // Area-based organization
|
||
byTeam: workItems.groupBy('assignedTeam'), // Team-based organization
|
||
byType: workItems.groupBy('workItemType') // Type-based organization
|
||
};
|
||
|
||
// Suggest strategy
|
||
if (patterns.byArea.length > 3) {
|
||
console.log('💡 Detected area-based organization');
|
||
console.log(' Suggested strategy: area-path-based');
|
||
} else if (patterns.byTeam.length > 2) {
|
||
console.log('💡 Detected team-based organization');
|
||
console.log(' Suggested strategy: team-based or project-per-team');
|
||
}
|
||
```
|
||
|
||
## Project Creation API
|
||
|
||
**Azure DevOps REST API** (v7.0):
|
||
|
||
### Create Project
|
||
```bash
|
||
POST https://dev.azure.com/{org}/_apis/projects?api-version=7.0
|
||
Content-Type: application/json
|
||
Authorization: Basic {base64(":PAT")}
|
||
|
||
{
|
||
"name": "MobileApp",
|
||
"description": "Mobile application project",
|
||
"capabilities": {
|
||
"versioncontrol": {
|
||
"sourceControlType": "Git"
|
||
},
|
||
"processTemplate": {
|
||
"templateTypeId": "adcc42ab-9882-485e-a3ed-7678f01f66bc" # Agile
|
||
}
|
||
}
|
||
}
|
||
|
||
Response:
|
||
{
|
||
"id": "proj-002",
|
||
"name": "MobileApp",
|
||
"state": "wellFormed"
|
||
}
|
||
```
|
||
|
||
### Create Area Path
|
||
```bash
|
||
POST https://dev.azure.com/{org}/{project}/_apis/wit/classificationnodes/areas?api-version=7.0
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "Frontend",
|
||
"attributes": {
|
||
"startDate": null,
|
||
"finishDate": null
|
||
}
|
||
}
|
||
|
||
Response:
|
||
{
|
||
"id": 123,
|
||
"name": "Frontend",
|
||
"path": "\\MainProduct\\Area\\Frontend"
|
||
}
|
||
```
|
||
|
||
### Create Team
|
||
```bash
|
||
POST https://dev.azure.com/{org}/_apis/projects/{projectId}/teams?api-version=7.0
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "Alpha Team",
|
||
"description": "Alpha development team"
|
||
}
|
||
|
||
Response:
|
||
{
|
||
"id": "team-001",
|
||
"name": "Alpha Team",
|
||
"projectName": "MainProduct"
|
||
}
|
||
```
|
||
|
||
## Configuration Examples
|
||
|
||
### Example 1: Microservices Architecture (Project-per-team)
|
||
|
||
**Before** (`.env`):
|
||
```bash
|
||
AZURE_DEVOPS_ORG=mycompany
|
||
AZURE_DEVOPS_PAT=xxx
|
||
```
|
||
|
||
**After validation**:
|
||
```bash
|
||
AZURE_DEVOPS_ORG=mycompany
|
||
AZURE_DEVOPS_PAT=xxx
|
||
AZURE_DEVOPS_STRATEGY=project-per-team
|
||
AZURE_DEVOPS_PROJECTS=AuthService,UserService,PaymentService,NotificationService
|
||
```
|
||
|
||
**Folder structure created**:
|
||
```
|
||
.specweave/docs/internal/specs/
|
||
├── AuthService/
|
||
│ └── spec-001-oauth-implementation.md
|
||
├── UserService/
|
||
│ └── spec-001-user-management.md
|
||
├── PaymentService/
|
||
│ └── spec-001-stripe-integration.md
|
||
└── NotificationService/
|
||
└── spec-001-email-notifications.md
|
||
```
|
||
|
||
### Example 2: Monolithic Application (Area-path-based)
|
||
|
||
**Before** (`.env`):
|
||
```bash
|
||
AZURE_DEVOPS_PROJECT=ERP
|
||
```
|
||
|
||
**After validation**:
|
||
```bash
|
||
AZURE_DEVOPS_ORG=enterprise
|
||
AZURE_DEVOPS_PAT=xxx
|
||
AZURE_DEVOPS_STRATEGY=area-path-based
|
||
AZURE_DEVOPS_PROJECT=ERP
|
||
AZURE_DEVOPS_AREA_PATHS=Finance,HR,Inventory,Sales,Reports
|
||
```
|
||
|
||
**Work item organization**:
|
||
```
|
||
ERP
|
||
├── Finance/ → Finance module features
|
||
├── HR/ → HR module features
|
||
├── Inventory/ → Inventory management
|
||
├── Sales/ → Sales module features
|
||
└── Reports/ → Reporting features
|
||
```
|
||
|
||
### Example 3: Platform Teams (Team-based)
|
||
|
||
**Before** (`.env`):
|
||
```bash
|
||
AZURE_DEVOPS_PROJECT=Platform
|
||
```
|
||
|
||
**After validation**:
|
||
```bash
|
||
AZURE_DEVOPS_ORG=techcorp
|
||
AZURE_DEVOPS_PAT=xxx
|
||
AZURE_DEVOPS_STRATEGY=team-based
|
||
AZURE_DEVOPS_PROJECT=Platform
|
||
AZURE_DEVOPS_TEAMS=Infrastructure,Security,Data,DevOps
|
||
```
|
||
|
||
**Team assignments**:
|
||
- Infrastructure Team → Cloud resources, networking
|
||
- Security Team → Auth, compliance, auditing
|
||
- Data Team → Databases, analytics, ML
|
||
- DevOps Team → CI/CD, monitoring, tooling
|
||
|
||
## Error Handling
|
||
|
||
### Error 1: Invalid Credentials
|
||
|
||
**Symptom**: API calls fail with 401 Unauthorized
|
||
|
||
**Solution**:
|
||
```
|
||
❌ Azure DevOps API authentication failed
|
||
|
||
Please check:
|
||
1. AZURE_DEVOPS_PAT is correct
|
||
2. Token has not expired
|
||
3. AZURE_DEVOPS_ORG is correct
|
||
|
||
Generate new token at:
|
||
https://dev.azure.com/{org}/_usersSettings/tokens
|
||
```
|
||
|
||
### Error 2: Insufficient Permissions
|
||
|
||
**Symptom**: Cannot create projects (403 Forbidden)
|
||
|
||
**Solution**:
|
||
```
|
||
❌ Insufficient permissions to create projects
|
||
|
||
You need:
|
||
- Project Collection Administrator role (for creating projects)
|
||
- Project Administrator role (for area paths and teams)
|
||
|
||
Contact your Azure DevOps administrator to request permissions.
|
||
```
|
||
|
||
### Error 3: Project Name Conflicts
|
||
|
||
**Symptom**: Project creation fails (name exists)
|
||
|
||
**Solution**:
|
||
```
|
||
❌ Project name "WebApp" already exists
|
||
|
||
Options:
|
||
1. Use a different project name
|
||
2. Select the existing project
|
||
3. Add a suffix (e.g., WebApp-v2)
|
||
|
||
Your choice [2]:
|
||
```
|
||
|
||
### Error 4: Organization Limits
|
||
|
||
**Symptom**: Cannot create more projects
|
||
|
||
**Solution**:
|
||
```
|
||
❌ Organization project limit reached (250 projects)
|
||
|
||
Consider:
|
||
1. Using area-path-based strategy (one project)
|
||
2. Archiving old projects
|
||
3. Upgrading organization plan
|
||
|
||
Contact Azure DevOps support for limit increases.
|
||
```
|
||
|
||
## Integration with SpecWeave Workflow
|
||
|
||
### Automatic Validation
|
||
|
||
When using `/specweave-ado:sync`, validation runs automatically:
|
||
|
||
```bash
|
||
/specweave-ado:sync 0014
|
||
|
||
# Internally calls:
|
||
1. validateAzureDevOpsResources()
|
||
2. Fix missing projects/area paths/teams
|
||
3. Create folder structure for specs
|
||
4. Proceed with sync
|
||
```
|
||
|
||
### Manual Validation
|
||
|
||
Run validation independently:
|
||
|
||
```bash
|
||
# Via skill
|
||
"Validate my Azure DevOps configuration"
|
||
|
||
# Via TypeScript
|
||
npx tsx src/utils/external-resource-validator.ts --provider=ado
|
||
|
||
# Via CLI (future)
|
||
specweave validate-ado
|
||
```
|
||
|
||
## Best Practices
|
||
|
||
✅ **Choose the right strategy**:
|
||
- **Project-per-team**: Best for autonomous teams, microservices
|
||
- **Area-path-based**: Best for monolithic apps, shared codebase
|
||
- **Team-based**: Best for small organizations, simple structure
|
||
|
||
✅ **Use descriptive names**:
|
||
```bash
|
||
# Good
|
||
AZURE_DEVOPS_PROJECTS=UserManagement,PaymentProcessing,NotificationEngine
|
||
|
||
# Bad
|
||
AZURE_DEVOPS_PROJECTS=Proj1,Proj2,Proj3
|
||
```
|
||
|
||
✅ **Document project mapping** (in README):
|
||
```markdown
|
||
## Azure DevOps Projects
|
||
|
||
- UserManagement: User authentication and profile management
|
||
- PaymentProcessing: Payment gateway integrations
|
||
- NotificationEngine: Email, SMS, and push notifications
|
||
```
|
||
|
||
✅ **Keep .env in version control** (gitignored tokens):
|
||
```bash
|
||
# Commit project structure
|
||
AZURE_DEVOPS_STRATEGY=project-per-team
|
||
AZURE_DEVOPS_PROJECTS=WebApp,MobileApp,Platform
|
||
|
||
# Don't commit sensitive data
|
||
AZURE_DEVOPS_PAT=<redacted>
|
||
```
|
||
|
||
## Folder Organization
|
||
|
||
Based on strategy, the skill creates appropriate folder structure:
|
||
|
||
### Project-per-team Structure
|
||
```
|
||
.specweave/docs/internal/specs/
|
||
├── WebApp/
|
||
│ ├── spec-001-user-interface.md
|
||
│ └── spec-002-responsive-design.md
|
||
├── MobileApp/
|
||
│ ├── spec-001-ios-features.md
|
||
│ └── spec-002-android-features.md
|
||
└── Platform/
|
||
├── spec-001-api-design.md
|
||
└── spec-002-database-schema.md
|
||
```
|
||
|
||
### Area-path-based Structure
|
||
```
|
||
.specweave/docs/internal/specs/MainProduct/
|
||
├── Frontend/
|
||
│ └── spec-001-ui-components.md
|
||
├── Backend/
|
||
│ └── spec-001-api-endpoints.md
|
||
└── Mobile/
|
||
└── spec-001-mobile-sync.md
|
||
```
|
||
|
||
### Team-based Structure
|
||
```
|
||
.specweave/docs/internal/specs/MainProduct/
|
||
├── AlphaTeam/
|
||
│ └── spec-001-feature-a.md
|
||
├── BetaTeam/
|
||
│ └── spec-001-feature-b.md
|
||
└── GammaTeam/
|
||
└── spec-001-feature-c.md
|
||
```
|
||
|
||
## Key Differences from JIRA
|
||
|
||
**Azure DevOps vs JIRA Resource Creation**:
|
||
|
||
| Aspect | Azure DevOps | JIRA |
|
||
|--------|-------------|------|
|
||
| **Project Creation** | Asynchronous (polling required) | Synchronous (immediate) |
|
||
| **Creation Time** | 5-30 seconds | <1 second |
|
||
| **Status Tracking** | Poll `state` field ('wellFormed') | No polling needed |
|
||
| **API Complexity** | Higher (async handling) | Lower (sync operations) |
|
||
| **Board Creation** | Auto-created with project | Requires separate API call |
|
||
| **Process Templates** | Required (Agile, Scrum, CMMI) | Not applicable |
|
||
|
||
**Why Async Matters**:
|
||
|
||
When you create an ADO project, the API returns immediately with `state: 'new'`, but the project isn't usable yet. The validator polls every 1 second (max 30 attempts) until `state: 'wellFormed'`:
|
||
|
||
```typescript
|
||
// Create project (returns immediately)
|
||
const project = await createProject('MobileApp'); // state: 'new'
|
||
|
||
// Poll until ready
|
||
await waitForProjectCreation(project.id); // Polls until state: 'wellFormed'
|
||
|
||
// Now safe to use!
|
||
console.log('✅ Project ready for work items');
|
||
```
|
||
|
||
**Impact on UX**:
|
||
- JIRA: "✅ Project created" (instant)
|
||
- ADO: "📦 Creating project... ⏳ Waiting for Azure DevOps to complete setup... ✅ Project ready!" (5-30s)
|
||
|
||
## Summary
|
||
|
||
This skill ensures your Azure DevOps configuration is **always valid** by:
|
||
|
||
1. ✅ **Validating projects** - Check if projects exist, prompt to select or create
|
||
2. ✅ **Supporting multiple strategies** - Project-per-team, area-path-based, team-based
|
||
3. ✅ **Auto-creating resources** - Projects, area paths, teams (with async handling)
|
||
4. ✅ **Organizing specs** - Create folder structure based on projects
|
||
5. ✅ **Clear error messages** - Actionable guidance for all failures
|
||
6. ✅ **Handles ADO async behavior** - Polls for project creation completion
|
||
|
||
**Result**: Zero manual Azure DevOps setup - system handles everything, including ADO's async project creation!
|
||
|
||
---
|
||
|
||
**Skill Version**: 1.1.0
|
||
**Introduced**: SpecWeave v0.17.0
|
||
**Last Updated**: 2025-11-11
|
||
**Key Changes v1.1.0**: Added implementation details, async project creation handling, JIRA comparison |