import os from 'os'; import { Command } from 'commander'; import { simpleGit } from 'simple-git'; import { GitlabClient } from './gitlabClient'; import { startTaskAgent } from './startTaskAgent'; /** * Options for pushing a task branch and creating a merge request based on a GitLab issue */ export interface SendTaskAgentOptions { /** IID de l’issue GitLab */ id: string; /** Brache cible pour la MR (défaut: main) */ targetBranch?: string; /** Chemin du dépôt (défaut: cwd) */ repoPath?: string; /** Jeton GitLab (défaut: GITLAB_TOKEN env) */ gitlabToken?: string; /** URL GitLab (défaut: https://gitlab.teleport.ftprod.fr/) */ gitlabUrl?: string; /** Répertoire TLS pour TeleportBot (défaut: ~/.ftprod-ai/tbot) */ workDir?: string; /** Join token du Teleport application bot (pour générer TLS via TeleportBot) */ teleportToken?: string; } /** * Résultat de l’opération sendTaskAgent */ export interface SendTaskAgentResult { mrIid: number; branch: string; commitSha: string; webUrl: string; } /** * Push d’une branche générée pour l’issue et création d’une MR GitLab. */ export async function sendTaskAgent({ id, targetBranch = 'main', repoPath = process.cwd(), gitlabToken, gitlabUrl = 'https://gitlab.teleport.ftprod.fr/', workDir = os.homedir() + '/.ftprod-ai/tbot', teleportToken, }: SendTaskAgentOptions): Promise { const token = gitlabToken || process.env.GITLAB_TOKEN; if (!token) { throw new Error('Le jeton GitLab est requis (passer --gitlabToken ou définir GITLAB_TOKEN).'); } // Exécute startTaskAgent pour créer / checkout / push la branche issue-based const { branch, commitSha } = await startTaskAgent({ id, repoPath, gitlabToken: token, gitlabUrl, workDir, teleportToken }); // Prépare GitLab API client const git = simpleGit({ baseDir: repoPath }); const remotes = await git.getRemotes(true); const origin = remotes.find((r) => r.name === 'origin' && (r.refs.fetch || r.refs.push)); if (!origin) { throw new Error('Remote origin introuvable dans le dépôt.'); } // Extrait project path pour GitLab API const remoteUrl = origin.refs.fetch || origin.refs.push!; const parseProject = (u: string): string => { let p = u.endsWith('.git') ? u.slice(0, -4) : u; if (p.startsWith('git@')) { const i = p.indexOf(':'); if (i !== -1) p = p.slice(i + 1); } else if (p.startsWith('http')) { const parts = p.split('/'); p = parts.slice(3).join('/'); } return p; }; const projectPath = encodeURIComponent(parseProject(remoteUrl)); const client = new GitlabClient({ token, url: gitlabUrl, workDir }); // Récupère l’issue pour titre/description const issueRes = await client.instance.get<{ title: string; description?: string }>( `/projects/${projectPath}/issues/${id}` ); const { title, description } = issueRes.data; // Génère la description de MR en liant l’issue (Closes #id) const mrDescription = description ? `${description}\n\nCloses #${id}` : `Closes #${id}`; // Crée la merge request const mrRes = await client.instance.post( `/projects/${projectPath}/merge_requests`, { source_branch: branch, target_branch: targetBranch, title, description: mrDescription, } ); const { iid, web_url } = mrRes.data as { iid: number; web_url: string }; if (typeof iid !== 'number' || typeof web_url !== 'string') { throw new Error(`Échec création MR: ${JSON.stringify(mrRes.data)}`); } return { mrIid: iid, branch, commitSha, webUrl: web_url }; } /** CLI metadata for sendTaskAgent */ export const cli = { command: 'send-task', description: 'Crée et push une branche issue-based et ouvre une MR GitLab', builder: (cmd: Command) => cmd .argument('', 'ID (IID) de l’issue GitLab') .option('--targetBranch ', 'Branche cible (défaut: main)') .option('--repoPath ', 'Chemin du dépôt (défaut: cwd)') .option('--gitlabToken ', 'Jeton GitLab (défaut: GITLAB_TOKEN env)') .option( '--gitlabUrl ', 'URL GitLab (défaut: https://gitlab.teleport.ftprod.fr/)' ) .option( '--workDir ', "Répertoire TLS pour teleportBot (défaut: ~/.ftprod-ai/tbot)" ) .option( '--teleportToken ', 'Join token du Teleport application bot (pour générer TLS via TeleportBot)' ), handler: async (id: string, opts: Omit) => { // eslint-disable-next-line @typescript-eslint/no-var-requires const { sendTaskAgent: run } = require('./sendTaskAgent'); const res = await run({ id, ...opts }); console.log( `MR créée: !${res.mrIid} (${res.webUrl}), branche ${res.branch} à ${res.commitSha}` ); }, };