|
1 | 1 | import { execa } from "execa"; |
| 2 | +import semver, { Range } from 'semver'; |
2 | 3 | import ncp from "ncp"; |
3 | 4 | import path from "path"; |
4 | 5 | import fs from "fs"; |
5 | 6 | import { createFirstGitCommit } from "../tasks/create-first-git-commit"; |
6 | 7 | import { fetchChallenges } from "../modules/api"; |
7 | | -import { loadChallenges } from "../utils/stateManager"; |
| 8 | +import { loadChallenges } from "../utils/state-manager"; |
8 | 9 | import { IChallenge } from "../types"; |
9 | 10 | import { BASE_REPO, BASE_BRANCH, BASE_COMMIT } from "../config"; |
10 | 11 | import { DefaultRenderer, Listr, ListrTaskWrapper, SimpleRenderer } from "listr2"; |
11 | 12 | import chalk from "chalk"; |
12 | 13 |
|
| 14 | +type RequiredDependency = "node" | "git" | "yarn" | "foundryup"; |
| 15 | + |
13 | 16 | // Sidestep for ncp issue https://github.com/AvianFlu/ncp/issues/127 |
14 | 17 | const copy = (source: string, destination: string, options?: ncp.Options) => new Promise((resolve, reject) => { |
15 | 18 | ncp(source, destination, options || {}, (err) => { |
@@ -57,6 +60,10 @@ export const setupChallenge = async (name: string, installLocation: string) => { |
57 | 60 | } |
58 | 61 |
|
59 | 62 | const tasks = new Listr([ |
| 63 | + { |
| 64 | + title: 'Checking for required dependencies', |
| 65 | + task: () => checkUserDependencies() |
| 66 | + }, |
60 | 67 | { |
61 | 68 | title: 'Setting up base repository', |
62 | 69 | task: () => setupBaseRepo(targetDir) |
@@ -84,11 +91,39 @@ export const setupChallenge = async (name: string, installLocation: string) => { |
84 | 91 | console.log(chalk.green("Challenge setup completed successfully.")); |
85 | 92 | console.log(""); |
86 | 93 | console.log(chalk.cyan(`Now open this repository in your favorite code editor and look at the readme for instructions: ${targetDir}`)); |
87 | | - } catch (error) { |
88 | | - console.error(chalk.red("An error occurred during challenge setup:"), error); |
| 94 | + } catch (error: any) { |
| 95 | + console.error(chalk.red("An error occurred during challenge setup:"), error.message); |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +const checkDependencyInstalled = async (name: RequiredDependency) => { |
| 100 | + try { |
| 101 | + await execa(name, ["--help"]); |
| 102 | + } catch(_) { |
| 103 | + throw new Error(`${name} is required. Please install to continue.`); |
89 | 104 | } |
90 | 105 | } |
91 | 106 |
|
| 107 | +const checkDependencyVersion = async (name: RequiredDependency, requiredVersion: string | Range) => { |
| 108 | + try { |
| 109 | + const userVersion = (await execa(name, ["--version"])).stdout; |
| 110 | + if (!semver.satisfies(userVersion, requiredVersion)) { |
| 111 | + throw new Error(`${name} version requirement of ${requiredVersion} not met. Please update to continue.`); |
| 112 | + } |
| 113 | + } catch(_) { |
| 114 | + throw new Error(`${name} ${requiredVersion} is required. Please install to continue.`); |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +export const checkUserDependencies = async () => { |
| 119 | + await Promise.all([ |
| 120 | + checkDependencyVersion("node", ">=18.17.0"), |
| 121 | + checkDependencyInstalled("git"), |
| 122 | + checkDependencyInstalled("yarn"), |
| 123 | + checkDependencyInstalled("foundryup"), |
| 124 | + ]) |
| 125 | +} |
| 126 | + |
92 | 127 | const setupBaseRepo = async (targetDir: string): Promise<void> => { |
93 | 128 | await execa("git", ["clone", "--branch", BASE_BRANCH, "--single-branch", BASE_REPO, targetDir]); |
94 | 129 | await execa("git", ["checkout", BASE_COMMIT], { cwd: targetDir }); |
|
0 commit comments