Initial commit
This commit is contained in:
331
commands/specweave-ado-import-projects.md
Normal file
331
commands/specweave-ado-import-projects.md
Normal file
@@ -0,0 +1,331 @@
|
||||
---
|
||||
name: specweave-ado:import-projects
|
||||
description: Import additional Azure DevOps projects post-init with area path mapping, filtering, and dry-run preview
|
||||
---
|
||||
|
||||
# Import Azure DevOps Projects Command
|
||||
|
||||
You are an Azure DevOps project import expert. Help users add additional ADO projects to their SpecWeave workspace after initial setup.
|
||||
|
||||
## Purpose
|
||||
|
||||
This command allows users to import additional Azure DevOps projects **after** initial SpecWeave setup (`specweave init`), with area path mapping, filtering, and dry-run preview.
|
||||
|
||||
**Use Cases**:
|
||||
- Adding new ADO projects to existing workspace
|
||||
- Importing projects from different organizations
|
||||
- Selective import with area path granularity
|
||||
- Multi-project organization (Backend, Frontend, Mobile, Infrastructure)
|
||||
|
||||
## Command Syntax
|
||||
|
||||
```bash
|
||||
# Basic import (interactive)
|
||||
/specweave-ado:import-projects
|
||||
|
||||
# With area path granularity
|
||||
/specweave-ado:import-projects --granularity two-level
|
||||
|
||||
# Dry-run (preview)
|
||||
/specweave-ado:import-projects --dry-run
|
||||
|
||||
# Resume interrupted import
|
||||
/specweave-ado:import-projects --resume
|
||||
|
||||
# Combined
|
||||
/specweave-ado:import-projects --granularity top-level --dry-run
|
||||
```
|
||||
|
||||
## Your Task
|
||||
|
||||
When the user runs this command:
|
||||
|
||||
### Step 1: Validate Prerequisites
|
||||
```typescript
|
||||
import { readEnvFile, parseEnvFile } from '../../../src/utils/env-file.js';
|
||||
|
||||
// 1. Check if ADO credentials exist
|
||||
const envContent = readEnvFile(process.cwd());
|
||||
const parsed = parseEnvFile(envContent);
|
||||
|
||||
if (!parsed.AZURE_DEVOPS_PAT || !parsed.AZURE_DEVOPS_ORG) {
|
||||
console.log('❌ Missing Azure DevOps credentials. Run `specweave init` first.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Get existing configuration
|
||||
const org = parsed.AZURE_DEVOPS_ORG;
|
||||
const existingProject = parsed.AZURE_DEVOPS_PROJECT;
|
||||
|
||||
console.log(`\n📋 Organization: ${org}`);
|
||||
console.log(` Current project: ${existingProject || 'None'}\n`);
|
||||
```
|
||||
|
||||
### Step 2: Fetch Available Projects
|
||||
```typescript
|
||||
import { getProjectCount } from '../../../src/cli/helpers/project-count-fetcher.js';
|
||||
import { AsyncProjectLoader } from '../../../src/cli/helpers/async-project-loader.js';
|
||||
|
||||
// Count check (< 1 second)
|
||||
const countResult = await getProjectCount({
|
||||
provider: 'ado',
|
||||
credentials: {
|
||||
organization: org,
|
||||
pat: parsed.AZURE_DEVOPS_PAT
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`✓ Found ${countResult.accessible} accessible project(s)`);
|
||||
|
||||
// Fetch all projects (with smart pagination)
|
||||
const loader = new AsyncProjectLoader(
|
||||
{
|
||||
organization: org,
|
||||
pat: parsed.AZURE_DEVOPS_PAT
|
||||
},
|
||||
'ado',
|
||||
{
|
||||
batchSize: 50,
|
||||
updateFrequency: 5,
|
||||
showEta: true
|
||||
}
|
||||
);
|
||||
|
||||
const result = await loader.fetchAllProjects(countResult.accessible);
|
||||
const allProjects = result.projects;
|
||||
```
|
||||
|
||||
### Step 3: Area Path Mapping (Multi-Project Organization)
|
||||
```typescript
|
||||
import { AreaPathMapper } from '../../../src/integrations/ado/area-path-mapper.js';
|
||||
|
||||
const { selectedProject } = await inquirer.prompt([{
|
||||
type: 'select',
|
||||
name: 'selectedProject',
|
||||
message: 'Select ADO project to import area paths from:',
|
||||
choices: allProjects.map(p => ({ name: p.name, value: p.name }))
|
||||
}]);
|
||||
|
||||
const mapper = new AreaPathMapper({
|
||||
credentials: { organization: org, pat: parsed.AZURE_DEVOPS_PAT },
|
||||
project: selectedProject
|
||||
});
|
||||
|
||||
// Fetch area path tree
|
||||
const areaPathTree = await mapper.fetchAreaPaths();
|
||||
|
||||
// Get granularity suggestion
|
||||
const suggestion = mapper.suggestGranularity(areaPathTree);
|
||||
console.log(`\n💡 Suggestion: ${suggestion.suggested}`);
|
||||
console.log(` ${suggestion.reasoning}\n`);
|
||||
|
||||
// Prompt for granularity (if not provided via CLI)
|
||||
const granularity = args.granularity || await mapper.promptAreaPathGranularity(areaPathTree);
|
||||
|
||||
// Flatten area paths with selected granularity
|
||||
const areaPaths = mapper.flattenAreaPaths(areaPathTree, granularity);
|
||||
|
||||
console.log(`\n📊 ${areaPaths.length} project(s) will be created from area paths:\n`);
|
||||
areaPaths.forEach(ap => {
|
||||
const projectId = mapper.mapToProjectId(ap.path);
|
||||
console.log(` ✨ ${ap.path} → ${projectId}`);
|
||||
});
|
||||
```
|
||||
|
||||
### Step 4: Dry-Run or Execute
|
||||
```typescript
|
||||
if (args.dryRun) {
|
||||
console.log('\n🔎 DRY RUN: No changes will be made.\n');
|
||||
console.log('The following projects would be configured:');
|
||||
areaPaths.forEach(ap => {
|
||||
const projectId = mapper.mapToProjectId(ap.path);
|
||||
console.log(` ✨ ${projectId} (${ap.path})`);
|
||||
});
|
||||
console.log(`\nTotal: ${areaPaths.length} projects would be configured\n`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Confirm import
|
||||
const { confirmed } = await inquirer.prompt([{
|
||||
type: 'confirm',
|
||||
name: 'confirmed',
|
||||
message: `Configure ${areaPaths.length} project(s) from area paths?`,
|
||||
default: true
|
||||
}]);
|
||||
|
||||
if (!confirmed) {
|
||||
console.log('⏭️ Import cancelled.');
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Update Configuration
|
||||
```typescript
|
||||
import { getConfigManager } from '../../../src/core/config/index.js';
|
||||
|
||||
const configManager = getConfigManager(process.cwd());
|
||||
|
||||
// Build area path configuration
|
||||
const areaPathConfig: Record<string, string[]> = {};
|
||||
|
||||
for (const ap of areaPaths) {
|
||||
const projectId = mapper.mapToProjectId(ap.path);
|
||||
areaPathConfig[projectId] = [ap.path];
|
||||
}
|
||||
|
||||
// Update configuration
|
||||
await configManager.update({
|
||||
issueTracker: {
|
||||
provider: 'ado',
|
||||
ado: {
|
||||
organization: org,
|
||||
project: selectedProject,
|
||||
areaPathMapping: areaPathConfig,
|
||||
granularity
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update .env file
|
||||
import { updateEnvFile } from '../../../src/utils/env-manager.js';
|
||||
|
||||
await updateEnvFile('AZURE_DEVOPS_PROJECT', selectedProject);
|
||||
|
||||
// Write area paths to .env (comma-separated)
|
||||
const areaPathList = areaPaths.map(ap => ap.path).join(',');
|
||||
await updateEnvFile('AZURE_DEVOPS_AREA_PATHS', areaPathList);
|
||||
|
||||
console.log('\n✅ Projects configured successfully!\n');
|
||||
console.log(`Organization: ${org}`);
|
||||
console.log(`Project: ${selectedProject}`);
|
||||
console.log(`Granularity: ${granularity}`);
|
||||
console.log(`\nArea paths configured:\n ${areaPathList.split(',').join('\n ')}\n`);
|
||||
```
|
||||
|
||||
### Step 6: Resume Support
|
||||
```typescript
|
||||
if (args.resume) {
|
||||
const { CacheManager } = await import('../../../src/core/cache/cache-manager.js');
|
||||
const cacheManager = new CacheManager(process.cwd());
|
||||
|
||||
const importState = await cacheManager.get('ado-import-state');
|
||||
|
||||
if (!importState) {
|
||||
console.log('⚠️ No import state found. Use without --resume to start fresh.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`\n📂 Resuming from: ${importState.lastAreaPath} (${importState.completed}/${importState.total})`);
|
||||
|
||||
// Skip already-processed area paths
|
||||
const remainingPaths = areaPaths.filter(ap => !importState.processed.includes(ap.path));
|
||||
|
||||
// Continue import with remaining paths
|
||||
// (use same logic as Step 5)
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Import with Area Paths
|
||||
**User**: `/specweave-ado:import-projects`
|
||||
|
||||
**Output**:
|
||||
```
|
||||
📋 Organization: mycompany
|
||||
Current project: Platform
|
||||
|
||||
✓ Found 5 accessible project(s)
|
||||
|
||||
Select ADO project to import area paths from:
|
||||
> Platform
|
||||
|
||||
💡 Suggestion: two-level
|
||||
Balanced hierarchy (8 two-level areas). Recommended granularity.
|
||||
|
||||
Select area path granularity for project organization:
|
||||
> Two-level (8 projects) - e.g., Backend-API, Backend-Database
|
||||
|
||||
📊 8 project(s) will be created from area paths:
|
||||
|
||||
✨ Platform/Backend/API → backend-api
|
||||
✨ Platform/Backend/Database → backend-database
|
||||
✨ Platform/Frontend/Web → frontend-web
|
||||
✨ Platform/Frontend/Admin → frontend-admin
|
||||
✨ Platform/Mobile/iOS → mobile-ios
|
||||
✨ Platform/Mobile/Android → mobile-android
|
||||
✨ Platform/Infrastructure/Cloud → infrastructure-cloud
|
||||
✨ Platform/Infrastructure/Network → infrastructure-network
|
||||
|
||||
Configure 8 project(s) from area paths? (Y/n)
|
||||
|
||||
✅ Projects configured successfully!
|
||||
|
||||
Organization: mycompany
|
||||
Project: Platform
|
||||
Granularity: two-level
|
||||
|
||||
Area paths configured:
|
||||
Platform/Backend/API
|
||||
Platform/Backend/Database
|
||||
Platform/Frontend/Web
|
||||
Platform/Frontend/Admin
|
||||
Platform/Mobile/iOS
|
||||
Platform/Mobile/Android
|
||||
Platform/Infrastructure/Cloud
|
||||
Platform/Infrastructure/Network
|
||||
```
|
||||
|
||||
### Example 2: Top-Level Only
|
||||
**User**: `/specweave-ado:import-projects --granularity top-level`
|
||||
|
||||
**Output**:
|
||||
```
|
||||
Select area path granularity: top-level (forced via CLI)
|
||||
|
||||
📊 3 project(s) will be created from area paths:
|
||||
|
||||
✨ Platform/Backend → backend
|
||||
✨ Platform/Frontend → frontend
|
||||
✨ Platform/Mobile → mobile
|
||||
```
|
||||
|
||||
### Example 3: Dry-Run
|
||||
**User**: `/specweave-ado:import-projects --dry-run`
|
||||
|
||||
**Output**:
|
||||
```
|
||||
🔎 DRY RUN: No changes will be made.
|
||||
|
||||
The following projects would be configured:
|
||||
✨ backend-api (Platform/Backend/API)
|
||||
✨ backend-database (Platform/Backend/Database)
|
||||
✨ frontend-web (Platform/Frontend/Web)
|
||||
|
||||
Total: 8 projects would be configured
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Multi-Project Organization**: Uses area paths to create logical project separation
|
||||
- **Granularity Control**: Top-level, two-level, or full-tree based on hierarchy complexity
|
||||
- **Atomic Updates**: Uses temp file + rename to prevent corruption
|
||||
- **Progress Tracking**: Shows progress bar for large hierarchies (> 50 area paths)
|
||||
- **Resume Support**: Interrupted imports can be resumed with `--resume`
|
||||
|
||||
## Related Commands
|
||||
|
||||
- `/specweave:init` - Initial SpecWeave setup
|
||||
- `/specweave-ado:sync` - Sync increments with ADO work items
|
||||
- `/specweave-ado:refresh-cache` - Clear cached ADO data
|
||||
|
||||
## Error Handling
|
||||
|
||||
- **Missing Credentials**: Prompt user to run `specweave init` first
|
||||
- **API Errors**: Show clear error message with suggestion
|
||||
- **No Area Paths**: Fallback to single-project mode
|
||||
- **Permission Errors**: Check ADO PAT scopes
|
||||
|
||||
---
|
||||
|
||||
**Multi-Project Excellence**: This command enables sophisticated multi-project organization in Azure DevOps using area paths, perfect for large teams with complex hierarchies.
|
||||
Reference in New Issue
Block a user