|
| 1 | +import inquirer from 'inquirer' |
| 2 | + |
| 3 | +import { normalizeRepoUrl } from '../../utils/normalize-repo-url.js' |
| 4 | +import { chalk, logAndThrowError, log } from '../../utils/command-helpers.js' |
| 5 | +import { runGit } from '../../utils/run-git.js' |
| 6 | +import type BaseCommand from '../base-command.js' |
| 7 | +import { link } from '../link/link.js' |
| 8 | +import type { CloneOptionValues } from './option_values.js' |
| 9 | +import { startSpinner } from '../../lib/spinner.js' |
| 10 | + |
| 11 | +const getTargetDir = async (defaultDir: string): Promise<string> => { |
| 12 | + const { selectedDir } = await inquirer.prompt<{ selectedDir: string }>([ |
| 13 | + { |
| 14 | + type: 'input', |
| 15 | + name: 'selectedDir', |
| 16 | + message: 'Where should we clone the repository?', |
| 17 | + default: defaultDir, |
| 18 | + }, |
| 19 | + ]) |
| 20 | + |
| 21 | + return selectedDir |
| 22 | +} |
| 23 | + |
| 24 | +const cloneRepo = async (repoUrl: string, targetDir: string, debug: boolean): Promise<void> => { |
| 25 | + try { |
| 26 | + await runGit(['clone', repoUrl, targetDir], !debug) |
| 27 | + } catch (error) { |
| 28 | + throw new Error(`Failed to clone repository: ${error instanceof Error ? error.message : error?.toString() ?? ''}`) |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +export const clone = async ( |
| 33 | + options: CloneOptionValues, |
| 34 | + command: BaseCommand, |
| 35 | + args: { repo: string; targetDir?: string }, |
| 36 | +) => { |
| 37 | + await command.authenticate() |
| 38 | + |
| 39 | + const { repoUrl, httpsUrl, repoName } = normalizeRepoUrl(args.repo) |
| 40 | + |
| 41 | + const targetDir = args.targetDir ?? (await getTargetDir(`./${repoName}`)) |
| 42 | + |
| 43 | + const cloneSpinner = startSpinner({ text: `Cloning repository to ${chalk.cyan(targetDir)}` }) |
| 44 | + try { |
| 45 | + await cloneRepo(repoUrl, targetDir, options.debug ?? false) |
| 46 | + } catch (error) { |
| 47 | + return logAndThrowError(error) |
| 48 | + } |
| 49 | + cloneSpinner.success(`Cloned repository to ${chalk.cyan(targetDir)}`) |
| 50 | + |
| 51 | + command.workingDir = targetDir |
| 52 | + // TODO(serhalp): This shouldn't be necessary but `getPathInProject` does not take |
| 53 | + // `command.workingDir` into account. Carefully fix this and remove this line. |
| 54 | + process.chdir(targetDir) |
| 55 | + |
| 56 | + const { id, name, ...globalOptions } = options |
| 57 | + const linkOptions = { |
| 58 | + ...globalOptions, |
| 59 | + id, |
| 60 | + name, |
| 61 | + // Use the normalized HTTPS URL as the canonical git URL for linking to ensure |
| 62 | + // we have a consistent URL format for looking up sites. |
| 63 | + gitRemoteUrl: httpsUrl, |
| 64 | + } |
| 65 | + await link(linkOptions, command) |
| 66 | + |
| 67 | + log() |
| 68 | + log(chalk.green('✔ Your project is ready to go!')) |
| 69 | + log(`→ Next, enter your project directory using ${chalk.cyanBright(`cd ${targetDir}`)}`) |
| 70 | + log() |
| 71 | + log(`→ You can now run other ${chalk.cyanBright('netlify')} CLI commands in this directory`) |
| 72 | + log(`→ To build and deploy your site: ${chalk.cyanBright('netlify deploy')}`) |
| 73 | + if (command.netlify.config.dev?.command) { |
| 74 | + log(`→ To run your dev server: ${chalk.cyanBright(command.netlify.config.dev.command)}`) |
| 75 | + } |
| 76 | + log(`→ To see all available commands: ${chalk.cyanBright('netlify help')}`) |
| 77 | + log() |
| 78 | +} |
0 commit comments