All files / services sendTaskAgent.ts

100% Statements 41/41
87.5% Branches 21/24
100% Functions 5/5
100% Lines 39/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 1452x   2x 2x 2x                                                                     2x                 5x 5x 1x       4x                   4x 4x 4x 4x 1x     3x 3x 3x 3x 2x 2x 1x 1x 1x   3x   3x   3x   3x     3x   3x       3x                 3x 3x 1x     2x       2x       1x                                     1x 1x 1x          
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<SendTaskAgentResult> {
  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>', 'ID (IID) de l’issue GitLab')
      .option('--targetBranch <branch>', 'Branche cible (défaut: main)')
      .option('--repoPath <path>', 'Chemin du dépôt (défaut: cwd)')
      .option('--gitlabToken <token>', 'Jeton GitLab (défaut: GITLAB_TOKEN env)')
      .option(
        '--gitlabUrl <url>',
        'URL GitLab (défaut: https://gitlab.teleport.ftprod.fr/)'
      )
      .option(
        '--workDir <path>',
        "Répertoire TLS pour teleportBot (défaut: ~/.ftprod-ai/tbot)"
      )
      .option(
        '--teleportToken <token>',
        'Join token du Teleport application bot (pour générer TLS via TeleportBot)'
      ),
  handler: async (id: string, opts: Omit<SendTaskAgentOptions, 'id'>) => {
    // 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}`
    );
  },
};