@morodomi/ait3
Version:
AIT³ Development Platform - AI + Ticket + Test + Tool driven development methodology
181 lines (180 loc) • 6.9 kB
JavaScript
import { TicketMigrationService } from '../../services/implementations/TicketMigrationService.js';
import { GitHubTicketService } from '../../services/implementations/GitHubTicketService.js';
import { STYLES } from '../../common/styles.js';
/**
* Get tickets to migrate based on filter
*/
async function getTicketsToMigrate(fromService, ticketFilter) {
if (ticketFilter && ticketFilter.length > 0) {
// Get filtered tickets
const tickets = [];
for (const ticketId of ticketFilter) {
const ticket = await fromService.getTicket(ticketId);
if (ticket) {
tickets.push({ title: ticket.title });
}
}
return tickets;
}
else {
// Get all tickets
const allTickets = await fromService.listTickets();
return allTickets.map(t => ({ title: t.title }));
}
}
export async function migrateCommand(args, services) {
// Validate required arguments
if (!args.from || !args.to) {
return {
success: false,
message: STYLES.danger('ERROR: --from and --to flags are required')
};
}
// Validate supported migration directions
if (args.from === args.to) {
return {
success: false,
message: STYLES.danger('ERROR: Source and target backends cannot be the same')
};
}
if (args.to !== 'github' && args.to !== 'local') {
return {
success: false,
message: STYLES.danger('ERROR: Unsupported migration direction. Only "local" and "github" are supported')
};
}
// Validate GitHub configuration
if (args.to === 'github' && (!args.owner || !args.repo)) {
return {
success: false,
message: STYLES.danger('ERROR: GitHub owner and repo are required for GitHub migration')
};
}
// Validate GitHub owner format
if (args.owner && !/^[a-zA-Z0-9-]+$/.test(args.owner)) {
return {
success: false,
message: STYLES.danger('ERROR: Invalid GitHub owner format. Use alphanumeric characters and hyphens only')
};
}
try {
// Create migration service
const migrationService = new TicketMigrationService();
// Create services based on migration direction
const fromService = createServiceFromType(args.from, services, args);
const toService = createServiceFromType(args.to, services, args);
// Parse ticket filter if provided
let ticketFilter;
if (args.tickets) {
try {
ticketFilter = migrationService.parseTicketFilter(args.tickets);
}
catch (error) {
return {
success: false,
message: STYLES.danger(`Invalid ticket filter format: ${error instanceof Error ? error.message : String(error)}`)
};
}
}
// Handle validation mode
if (args.validate) {
const validation = await migrationService.validateMigration(fromService, toService);
if (!validation.success) {
const messageParts = [
STYLES.danger('Validation failed'),
'',
...validation.conflicts.map(c => STYLES.danger(` • ${c}`)),
...validation.errors.map(e => STYLES.danger(` • ${e}`))
];
return {
success: false,
message: messageParts.join('\n')
};
}
const messageParts = [
STYLES.success('Validation completed'),
'',
...validation.warnings.map(w => STYLES.warning(` • ${w}`))
];
return {
success: true,
message: messageParts.join('\n')
};
}
// Handle dry run mode
if (args.dryRun) {
const validation = await migrationService.validateMigration(fromService, toService);
const ticketsToShow = await getTicketsToMigrate(fromService, ticketFilter);
const messageParts = [
STYLES.success('Dry run completed'),
'',
STYLES.info(`${ticketsToShow.length} tickets will be migrated`),
'',
...ticketsToShow.map(ticket => ` • ${ticket.title}`),
'',
...validation.warnings.map(w => STYLES.warning(` • ${w}`))
];
return {
success: true,
message: messageParts.join('\n')
};
}
// Perform actual migration
if (args.from === 'local' && args.to === 'github') {
const result = await migrationService.migrateLocalToGitHub(fromService, toService, ticketFilter);
if (result.success) {
return {
success: true,
message: STYLES.success(`Migration completed successfully. ${result.migratedCount} tickets migrated.`)
};
}
else {
const messageParts = [
result.migratedCount > 0
? STYLES.warning(`Migration completed with errors. ${result.migratedCount} tickets migrated, ${result.failedCount} tickets failed.`)
: STYLES.danger('Migration failed'),
'',
...result.errors.map(e => STYLES.danger(` • ${e}`))
];
return {
success: false,
message: messageParts.join('\n')
};
}
}
return {
success: false,
message: STYLES.danger('ERROR: Migration direction not implemented yet')
};
}
catch (error) {
if (error instanceof Error && error.message.includes('GitHub service creation failed')) {
return {
success: false,
message: STYLES.danger('ERROR: Failed to create GitHub service. Check your configuration.')
};
}
return {
success: false,
message: STYLES.danger(`Migration failed: ${error instanceof Error ? error.message : String(error)}`)
};
}
}
/**
* Create appropriate service based on type
*/
function createServiceFromType(type, services, args) {
if (type === 'local') {
return services.ticketService; // Use existing local service
}
if (type === 'github') {
if (!args.owner || !args.repo) {
throw new Error('GitHub owner and repo are required');
}
return new GitHubTicketService({
owner: args.owner,
repo: args.repo
});
}
throw new Error(`Unsupported service type: ${type}`);
}