diff --git a/api-sample/database/docker-compose.apple-silicon.yml b/api-sample/database/docker-compose.apple-silicon.yml index 21ebbcd2..cdfd2310 100644 --- a/api-sample/database/docker-compose.apple-silicon.yml +++ b/api-sample/database/docker-compose.apple-silicon.yml @@ -1,4 +1,3 @@ -version: "3.3" services: {{PROJECT_NAME_KEBAPCASE}}-db: container_name: {{PROJECT_NAME_KEBAPCASE}}-mysql-db diff --git a/api-sample/database/docker-compose.yml b/api-sample/database/docker-compose.yml index 742c9374..37972397 100644 --- a/api-sample/database/docker-compose.yml +++ b/api-sample/database/docker-compose.yml @@ -1,8 +1,7 @@ -version: "3.3" services: {{PROJECT_NAME_KEBAPCASE}}-db: container_name: {{PROJECT_NAME_KEBAPCASE}}-mysql-db - image: mysql:5.7 + image: mysql:latest restart: always command: --sql_mode="NO_ENGINE_SUBSTITUTION" environment: diff --git a/cli/commands/run/index.js b/cli/commands/run/index.js index 7bcfa952..a5d314d8 100644 --- a/cli/commands/run/index.js +++ b/cli/commands/run/index.js @@ -15,7 +15,7 @@ const run = async () => { const projectDetails = findProjectRoot(); if (!projectDetails) { console.log( - chalk.red`You are not within a Xest project directory. Please check your current path directory.` + chalk.red`You are not within a Xest project directory. Please check your current path directory.`, ); return; } @@ -34,7 +34,7 @@ const run = async () => { const checkDatabaseSchemaAppliedQuery = `select count(*) as count from migrations where name = '/20211107064304-database-schema';`; const mySQLConnectionString = `mysql -h localhost -u root -ppassword ${snakeCase( - projectName + projectName, )}_db`; const checkDatabaseSchema = `printf "${checkDatabaseSchemaAppliedQuery}" | docker exec -i ${mySQLContainerId} ${mySQLConnectionString}`; // insert database schema @@ -73,7 +73,7 @@ const run = async () => { }); const checkMigrationsQuery = `select count(*) as count from migrations where name='/${latestMigrationFile.replace( ".js", - "" + "", )}';`; const checkMigrations = `printf "${checkMigrationsQuery}" | docker exec -i ${mySQLContainerId} ${mySQLConnectionString}`; ({ error, output } = await runSqlQueryWithinContainer(checkMigrations)); @@ -101,7 +101,7 @@ const run = async () => { if (error && error.includes("ERROR")) { console.log( - chalk.red`Failed to populate database with seed data. This might happen if you have recently updated your migrations, please modify your seed data to match new schema changes.` + chalk.red`Failed to populate database with seed data. This might happen if you have recently updated your migrations, please modify your seed data to match new schema changes.`, ); console.log(chalk.red`Error: ${error.split("ERROR")[1]}`); @@ -112,12 +112,22 @@ const run = async () => { process.stdin.resume(); let isExiting = false; - let dockerComposeCommand = `docker-compose --project-name ${projectName} down`; const usingAppleSiliconChipset = isAppleSilicon(); - if (usingAppleSiliconChipset) { - dockerComposeCommand = `docker-compose --project-name ${projectName} -f docker-compose.apple-silicon.yml down`; + const composeFileName = usingAppleSiliconChipset + ? "docker-compose.apple-silicon.yml" + : "docker-compose.yml"; + + let dockerComposePrefixByVersion = "docker compose"; + + try { + execSync("docker compose version"); + } catch (err) { + // Fallback to legacy docker-compose command if docker compose fails + dockerComposePrefixByVersion = "docker-compose"; } + let dockerComposeCommand = `${dockerComposePrefixByVersion} --project-name ${projectName} -f ${composeFileName} down`; + // shutdown procedure [ `exit`, @@ -141,7 +151,7 @@ const run = async () => { { cwd: path.join(rootPath, "database") }, () => { process.exit(0); - } + }, ); } }); diff --git a/cli/utils/runMySQLContainer.js b/cli/utils/runMySQLContainer.js index 04f4d544..80e67cc3 100644 --- a/cli/utils/runMySQLContainer.js +++ b/cli/utils/runMySQLContainer.js @@ -16,7 +16,7 @@ const runMySQLContainer = async (rootPath, projectName) => { } catch (err) { if (err.toString().includes("Error")) { console.log( - chalk.red`Docker is currently not running. Please start Docker and repeat ${chalk.green`xx run`} again.` + chalk.red`Docker is currently not running. Please start Docker and repeat ${chalk.green`xx run`} again.`, ); return false; } @@ -26,7 +26,7 @@ const runMySQLContainer = async (rootPath, projectName) => { `docker ps --format "table {{.ID}}\t{{.Names}}" | grep ${projectName}-mysql-db | cut -d ' ' -f 1`, { cwd: path.join(rootPath, "database"), - } + }, ).toString(); let ready = false; @@ -36,12 +36,13 @@ const runMySQLContainer = async (rootPath, projectName) => { // read from docker-compose file the PORT number const usingAppleSiliconChipset = isAppleSilicon(); + const composeFileName = usingAppleSiliconChipset + ? "docker-compose.apple-silicon.yml" + : "docker-compose.yml"; const dockerComposeFilePath = path.join( rootPath, "database", - usingAppleSiliconChipset - ? "docker-compose.apple-silicon.yml" - : "docker-compose.yml" + composeFileName, ); const dockerComposeFile = fs.readFileSync(dockerComposeFilePath, "utf8"); @@ -52,7 +53,7 @@ const runMySQLContainer = async (rootPath, projectName) => { // Regex pattern to extract the host port const pattern = new RegExp( `${serviceName}:\\s*\\n(?:\\s*\\w+:.*\\n)*\\s*ports:\\s*\\n(?:\\s*-\\s*"?(\\d+):\\d+"?\\n)*`, - "gm" + "gm", ); const match = pattern.exec(dockerComposeFile); let mysqlHostPort = 3306; @@ -64,13 +65,17 @@ const runMySQLContainer = async (rootPath, projectName) => { let mySQLContainerId = isDockerMySQLContainerRunning.trim(); if (!Boolean(isDockerMySQLContainerRunning)) { // check if mysql port is available for use - await resolvePortConflict(mysqlHostPort, "MySQL Docker Container", false, ); - - let dockerComposeCommand = `docker-compose --project-name ${projectName} up -d`; - - if (usingAppleSiliconChipset) { - dockerComposeCommand = `docker-compose --project-name ${projectName} -f docker-compose.apple-silicon.yml up -d`; + await resolvePortConflict(mysqlHostPort, "MySQL Docker Container", false); + + // Since Docker Compose V2, docker compose is preferred over docker-compose + let dockerComposePrefixByVersion = "docker compose"; + try { + execSync("docker compose version"); + } catch (err) { + // Fallback to legacy docker-compose command if docker compose fails + dockerComposePrefixByVersion = "docker-compose"; } + let dockerComposeCommand = `${dockerComposePrefixByVersion} --project-name ${projectName} -f ${composeFileName} up -d`; const runMySQLContainer = execSync(dockerComposeCommand, { cwd: path.join(rootPath, "database"), @@ -81,21 +86,21 @@ const runMySQLContainer = async (rootPath, projectName) => { `docker ps --format "table {{.ID}}\t{{.Names}}" | grep ${projectName}-mysql-db | cut -d ' ' -f 1`, { cwd: path.join(rootPath, "database"), - } + }, ).toString(); mySQLContainerId = isDockerMySQLContainerRunningAgain.trim(); // check whether mysql is ready console.log( - chalk.yellow`Waiting for MySQL Container to become ready. This should only take a few seconds.` + chalk.yellow`Waiting for MySQL Container to become ready. This should only take a few seconds.`, ); while (!ready && retryCount < 60) { const query = `SELECT COUNT(*) as tbl_count FROM information_schema.tables WHERE table_schema = '${snakeCase( - projectName + projectName, )}_db';`; const mySQLConnectionString = `mysql -h localhost -u root -ppassword ${snakeCase( - projectName + projectName, )}_db`; const checkDatabaseSchema = `printf "${query}" | docker exec -i ${mySQLContainerId} ${mySQLConnectionString}`; ({ error, output } = await runSqlQueryWithinContainer(checkDatabaseSchema)); @@ -113,7 +118,7 @@ const runMySQLContainer = async (rootPath, projectName) => { } if (!ready) { console.log( - chalk.red`MySQL instance is not ready yet. Try running ${chalk.green`xx run`} again.` + chalk.red`MySQL instance is not ready yet. Try running ${chalk.green`xx run`} again.`, ); return false; }