Import additional Azure DevOps projects post-init with area path mapping, filtering, and dry-run preview
Import additional Azure DevOps projects after initial setup, with area path mapping and filtering. Use this when adding new projects or organizing work by area paths in multi-project environments.
/plugin marketplace add anton-abyzov/specweave/plugin install sw-ado@specweaveYou are an Azure DevOps project import expert. Help users add additional ADO projects to their SpecWeave workspace after initial setup.
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:
# Basic import (interactive)
/sw-ado:import-projects
# With area path granularity
/sw-ado:import-projects --granularity two-level
# Dry-run (preview)
/sw-ado:import-projects --dry-run
# Resume interrupted import
/sw-ado:import-projects --resume
# Combined
/sw-ado:import-projects --granularity top-level --dry-run
When the user runs this command:
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`);
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;
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}`);
});
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;
}
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`);
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)
}
User: /sw-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
User: /sw-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
User: /sw-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
--resume/sw:init - Initial SpecWeave setup/sw-ado:sync - Sync increments with ADO work items/sw-ado:refresh-cache - Clear cached ADO dataspecweave init firstMulti-Project Excellence: This command enables sophisticated multi-project organization in Azure DevOps using area paths, perfect for large teams with complex hierarchies.