// // Copyright 2021 DXOS.org // import chalk from 'chalk'; import fs from 'fs'; import path from 'path'; import { asyncExec } from './util'; export type Branch = { name: string current: boolean modified?: boolean status?: string } export type Repo = { dir: string name: string origin: string branches?: Branch[] } export const parseOrigin = (origin: string) => { const [, repo] = origin.match(/:(.*)\./) as any; return (repo.indexOf('/') === -1 ? repo : `@${repo}`); } /** * Get root path of current repo or undefined if not in a repo directory. */ export const getRepo = async () => { try { return await asyncExec('git rev-parse --show-toplevel'); } catch { return undefined; } } /** * Get list of repos. * @param root Optional root directory. */ export const getRepos = async (root?: string): Promise => { // Memo current dir. const cwd = process.cwd(); if (!root) { root = cwd; } const dirs = fs.readdirSync(root || cwd, { withFileTypes: true }).filter(f => f.isDirectory()).map(f => f.name); // Synchronously visit each directory. const repos = []; for (const f of dirs) { const dir = path.join(root!, f); process.chdir(dir); if (!fs.existsSync('.git')) { continue; } try { const origin = await asyncExec('git remote get-url origin'); // Status of current branch. const status = await asyncExec(`git status -s -b`); const lines = status.split('\n'); const [, match] = lines[0].match(/(\[.+\])/) ?? []; const modified = lines.length > 1; // https://stackoverflow.com/questions/2016901/viewing-unpushed-git-commits/30720302#30720302 // git for-each-ref --format="%(HEAD)" refs/heads // git status --porcelain const result = await asyncExec('git branch --format "%(refname:short) %(HEAD)"'); const branches = await Promise.all(result.split('\n').map(async line => { const [name, head] = line.split(' '); return { name, current: !!head, modified: !!head ? modified : false, status: !!head ? match : undefined }; })); repos.push({ dir, origin, name: parseRepo(origin), branches }); } catch { console.log(chalk.red('Invalid directory:', f)); } } // Change back. process.chdir(cwd); return (repos as Repo[]).filter(Boolean); }; export const parseRepo = (repo: string) => { const match = repo.match(/.+:(.+)\./); return match && match.length > 1 ? match[1] : undefined; };