import { memoize } from 'lodash-es' import { execFileNoThrow } from './execFileNoThrow' export const getIsGit = memoize(async (): Promise => { const { code } = await execFileNoThrow('git', [ 'rev-parse', '--is-inside-work-tree', ]) return code === 0 }) export const getHead = async (): Promise => { const { stdout } = await execFileNoThrow('git', ['rev-parse', 'HEAD']) return stdout.trim() } export const getBranch = async (): Promise => { const { stdout } = await execFileNoThrow( 'git', ['rev-parse', '--abbrev-ref', 'HEAD'], undefined, undefined, false, ) return stdout.trim() } export const getRemoteUrl = async (): Promise => { // This might fail if there is no remote called origin const { stdout, code } = await execFileNoThrow( 'git', ['remote', 'get-url', 'origin'], undefined, undefined, false, ) return code === 0 ? stdout.trim() : null } export const getIsHeadOnRemote = async (): Promise => { const { code } = await execFileNoThrow( 'git', ['rev-parse', '@{u}'], undefined, undefined, false, ) return code === 0 } export const getIsClean = async (): Promise => { const { stdout } = await execFileNoThrow( 'git', ['status', '--porcelain'], undefined, undefined, false, ) return stdout.trim().length === 0 } export interface GitRepoState { commitHash: string branchName: string remoteUrl: string | null isHeadOnRemote: boolean isClean: boolean } export async function getGitState(): Promise { try { const [commitHash, branchName, remoteUrl, isHeadOnRemote, isClean] = await Promise.all([ getHead(), getBranch(), getRemoteUrl(), getIsHeadOnRemote(), getIsClean(), ]) return { commitHash, branchName, remoteUrl, isHeadOnRemote, isClean, } } catch (_) { // Fail silently - git state is best effort return null } }