diff --git a/.gitignore b/.gitignore index c471eaa12..45e0e8ab2 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ cli/README.md # PR description scratchpad (agents) PR_DESCRIPTION.md + +# PR review triage scratchpad (agents) +PR_REVIEW_TRIAGE.md diff --git a/cli/setup-project.js b/cli/setup-project.js index e4b6f42ab..440914b96 100755 --- a/cli/setup-project.js +++ b/cli/setup-project.js @@ -12,9 +12,35 @@ const ProjectFilesManager = require('./project-files-manager.js'); */ let projectFilesManager; +const DEFAULT_BRANCH = 'develop'; +const ADDITIONAL_BRANCHES = ['qa', 'main']; + +const hasGitIdentity = async (options) => { + const name = await execShellCommand('git config user.name || true', options); + const email = await execShellCommand('git config user.email || true', options); + return Boolean(name.trim() && email.trim()); +}; + +// Branches can only be created once a commit exists, so the initial commit +// happens before renaming the current branch and branching off it. const initializeProjectRepository = async (projectName) => { - const escapedProjectName = escapeShellArg(projectName); - await execShellCommand(`cd ${escapedProjectName} && git init && cd ..`); + const options = { cwd: projectName }; + + await execShellCommand('git init', options); + await execShellCommand('git add -A', options); + + const identityFlags = (await hasGitIdentity(options)) + ? '' + : '-c user.name="Rootstrap Template" -c user.email="template@rootstrap.com"'; + await execShellCommand( + `git ${identityFlags} commit -m "chore: initial commit from Rootstrap React Native template"`, + options, + ); + await execShellCommand(`git branch -M ${DEFAULT_BRANCH}`, options); + + for (const branch of ADDITIONAL_BRANCHES) { + await execShellCommand(`git branch ${branch}`, options); + } }; const installDependencies = async (projectName) => { @@ -54,7 +80,7 @@ const removeUnrelatedFiles = () => { }; // Update package.json infos, name and set version to 0.0.1 + add initial version to rsMetadata -const updatePackageJson = async (projectName) => { +const updatePackageJson = (projectName) => { const packageJsonPath = projectFilesManager.getAbsoluteFilePath('package.json'); @@ -75,7 +101,7 @@ const updatePackageJson = async (projectName) => { fs.writeJsonSync(packageJsonPath, packageJson, { spaces: 2 }); }; -const updateProjectConfig = async (projectName) => { +const updateProjectConfig = (projectName) => { projectFilesManager.replaceFilesContent([ { fileName: 'env.js', @@ -227,12 +253,13 @@ const setupProject = async (projectName) => { try { removeUnrelatedFiles(); - await initializeProjectRepository(projectName); updatePackageJson(projectName); updateProjectConfig(projectName); updateGitHubWorkflows(projectName); updateProjectReadme(projectName); updateAgentDocs(projectName); + // Runs last so the initial commit contains the fully set up project + await initializeProjectRepository(projectName); consola.success(`Clean up and setup your project 🧹`); } catch (error) { consola.error(`Failed to clean up project folder`, error); diff --git a/cli/utils.js b/cli/utils.js index d72704b4a..6930c8f9b 100755 --- a/cli/utils.js +++ b/cli/utils.js @@ -6,17 +6,18 @@ const UPSTREAM_REPOSITORY = "obytes/react-native-template-obytes"; const TEMPLATE_REPOSITORY = "rootstrap/react-native-template"; const escapeShellArg = (value) => { - return `'${String(value).replaceAll(/'/g, "'\\''")}'`; + return `'${String(value).replaceAll("'", "'\\''")}'`; }; -const execShellCommand = (cmd) => { +const execShellCommand = (cmd, options) => { return new Promise((resolve, reject) => { - exec(cmd, (error, stdout, stderr) => { + exec(cmd, options, (error, stdout, stderr) => { if (error) { console.warn(error); reject(error); + } else { + resolve(stdout || stderr); } - resolve(stdout || stderr); }); }); };