11import { execa } from "execa" ;
2+ import semver , { Range } from 'semver' ;
23import ncp from "ncp" ;
34import path from "path" ;
45import fs from "fs" ;
@@ -10,6 +11,8 @@ import { BASE_REPO, BASE_BRANCH, BASE_COMMIT } from "../config";
1011import { DefaultRenderer , Listr , ListrTaskWrapper , SimpleRenderer } from "listr2" ;
1112import chalk from "chalk" ;
1213
14+ type RequiredDependency = "node" | "git" | "yarn" | "foundryup" ;
15+
1316// Sidestep for ncp issue https://github.com/AvianFlu/ncp/issues/127
1417const copy = ( source : string , destination : string , options ?: ncp . Options ) => new Promise ( ( resolve , reject ) => {
1518 ncp ( source , destination , options || { } , ( err ) => {
@@ -57,6 +60,10 @@ export const setupChallenge = async (name: string, installLocation: string) => {
5760 }
5861
5962 const tasks = new Listr ( [
63+ {
64+ title : 'Checking for required dependencies' ,
65+ task : ( ) => checkUserDependencies ( )
66+ } ,
6067 {
6168 title : 'Setting up base repository' ,
6269 task : ( ) => setupBaseRepo ( targetDir )
@@ -84,11 +91,39 @@ export const setupChallenge = async (name: string, installLocation: string) => {
8491 console . log ( chalk . green ( "Challenge setup completed successfully." ) ) ;
8592 console . log ( "" ) ;
8693 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.` ) ;
89104 }
90105}
91106
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+
92127const setupBaseRepo = async ( targetDir : string ) : Promise < void > => {
93128 await execa ( "git" , [ "clone" , "--branch" , BASE_BRANCH , "--single-branch" , BASE_REPO , targetDir ] ) ;
94129 await execa ( "git" , [ "checkout" , BASE_COMMIT ] , { cwd : targetDir } ) ;
0 commit comments