Skip to content

Commit ae55f80

Browse files
unisol1020mrzachnugent
authored andcommitted
add git status check and validation for project directory in init command
1 parent dcb7363 commit ae55f80

File tree

1 file changed

+62
-22
lines changed

1 file changed

+62
-22
lines changed

apps/cli/src/commands/init.ts

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import chalk from 'chalk';
1212
import prompts from 'prompts';
1313
import glob from 'fast-glob';
1414
import { createRequire } from 'module';
15+
import { execSync } from 'child_process';
1516

1617
const filePath = fileURLToPath(import.meta.url);
1718
const fileDir = path.dirname(filePath);
@@ -177,6 +178,64 @@ async function updateImportPaths(cwd: string, spinner: Ora) {
177178
}
178179
}
179180

181+
async function shouldPromptGitWarning(cwd: string): Promise<boolean> {
182+
try {
183+
execSync('git rev-parse --is-inside-work-tree', { cwd });
184+
const status = execSync('git status --porcelain', { cwd }).toString();
185+
return !!status;
186+
} catch (error) {
187+
return false;
188+
}
189+
}
190+
191+
async function validateProjectDirectory(cwd: string) {
192+
if (!existsSync(cwd)) {
193+
logger.error(`The path ${cwd} does not exist. Please try again.`);
194+
process.exit(1);
195+
}
196+
197+
if (!existsSync(path.join(cwd, 'package.json'))) {
198+
logger.error('No package.json found. Please run this command in a React Native project directory.');
199+
process.exit(1);
200+
}
201+
}
202+
203+
async function checkGitStatus(cwd: string) {
204+
if (await shouldPromptGitWarning(cwd)) {
205+
const { proceed } = await prompts({
206+
type: 'confirm',
207+
name: 'proceed',
208+
message: 'The Git repository is dirty (uncommitted changes). It is recommended to commit your changes before proceeding. Do you want to continue?',
209+
initial: false,
210+
});
211+
212+
if (!proceed) {
213+
logger.info('Installation cancelled.');
214+
process.exit(0);
215+
}
216+
}
217+
}
218+
219+
async function initializeProject(cwd: string, overwrite: boolean) {
220+
const spinner = ora(`Initializing project...`).start();
221+
const templatesDir = path.dirname(
222+
createRequire(import.meta.url).resolve('@rnr/starter-base')
223+
);
224+
225+
await installDependencies(cwd, spinner);
226+
await updateTsConfig(cwd, spinner);
227+
228+
spinner.text = 'Copying template files...';
229+
for (const file of TEMPLATE_FILES) {
230+
await copyTemplateFile(file, templatesDir, cwd, spinner, overwrite);
231+
}
232+
233+
await updateImportPaths(cwd, spinner);
234+
await updateLayoutFile(cwd, spinner);
235+
236+
spinner.succeed('Initialization completed successfully!');
237+
}
238+
180239
export const init = new Command()
181240
.name('init')
182241
.description('Initialize the React Native project with required configuration')
@@ -191,28 +250,9 @@ export const init = new Command()
191250
const options = initOptionsSchema.parse(opts);
192251
const cwd = path.resolve(options.cwd);
193252

194-
if (!existsSync(cwd)) {
195-
logger.error(`The path ${cwd} does not exist. Please try again.`);
196-
process.exit(1);
197-
}
198-
199-
const spinner = ora(`Initializing project...`).start();
200-
const templatesDir = path.dirname(
201-
createRequire(import.meta.url).resolve('@rnr/starter-base')
202-
);
203-
204-
await installDependencies(cwd, spinner);
205-
await updateTsConfig(cwd, spinner);
206-
207-
spinner.text = 'Copying template files...';
208-
for (const file of TEMPLATE_FILES) {
209-
await copyTemplateFile(file, templatesDir, cwd, spinner, options.overwrite);
210-
}
211-
212-
await updateImportPaths(cwd, spinner);
213-
await updateLayoutFile(cwd, spinner);
214-
215-
spinner.succeed('Initialization completed successfully!');
253+
await validateProjectDirectory(cwd);
254+
await checkGitStatus(cwd);
255+
await initializeProject(cwd, options.overwrite);
216256
} catch (error) {
217257
handleError(error);
218258
}

0 commit comments

Comments
 (0)