1import spawnAsync from '@expo/spawn-async'; 2import chalk from 'chalk'; 3import fs from 'fs-extra'; 4 5import { Task } from './Task'; 6 7type CloneSettings = 8 | { 9 branch: string; 10 } 11 | { 12 tag: string; 13 } 14 | { 15 commit: string; 16 } 17 | object; 18 19export type CloneRepoSettings = { 20 url: string; 21 destination?: string; 22} & CloneSettings; 23 24/** 25 * A task which will clone repository into the provided destination or into the working directory. 26 */ 27export class Clone extends Task { 28 private readonly url: string; 29 private readonly options: CloneSettings; 30 private destination?: string; 31 32 constructor({ url, destination, ...options }: CloneRepoSettings) { 33 super(); 34 this.url = url; 35 this.destination = destination; 36 this.options = options; 37 } 38 39 protected overrideWorkingDirectory(): string { 40 return this.destination || '<workingDirectory>'; 41 } 42 43 async execute() { 44 const workDirectory = this.getWorkingDirectory(); 45 46 this.logSubStep(` remove ${chalk.yellow(this.overrideWorkingDirectory())}`); 47 await fs.remove(workDirectory); 48 49 this.logSubStep( 50 ` clone repo ${chalk.green(this.url)} into ${chalk.yellow(this.overrideWorkingDirectory())}` 51 ); 52 53 const cloneArguments = this.cloneArguments(); 54 this.logDebugInfo(`run git clone ${cloneArguments.join(' ')}`); 55 await spawnAsync('git', ['clone', ...cloneArguments, this.url, workDirectory]); 56 57 if ('commit' in this.options) { 58 this.logDebugInfo(`run git checkout ${this.options.commit}`); 59 await spawnAsync('git', ['checkout', this.options.commit], { cwd: workDirectory }); 60 } 61 } 62 63 cloneArguments(): string[] { 64 // if a branch or tag was provided, we don't need to clone the whole repo. 65 const args = ['--depth', '1']; 66 if ('branch' in this.options) { 67 args.push('--branch', this.options.branch); 68 } else if ('tag' in this.options) { 69 args.push('--branch', this.options.tag); 70 } else if ('commit' in this.options) { 71 return []; 72 } 73 return args; 74 } 75} 76