From 6f954d05a59b4bfc0cff60693da09180709ca840 Mon Sep 17 00:00:00 2001 From: Fernanda Toledo Date: Mon, 7 Sep 2026 15:40:24 -0300 Subject: [PATCH 1/2] feat(cli): create develop, qa and main branches on project creation --- cli/setup-project.js | 22 ++++++++++++++++++++-- cli/utils.js | 4 ++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/cli/setup-project.js b/cli/setup-project.js index cbde3776b..1e0d70622 100755 --- a/cli/setup-project.js +++ b/cli/setup-project.js @@ -13,8 +13,25 @@ const ProjectFilesManager = require('./project-files-manager.js'); */ let projectFilesManager; +const DEFAULT_BRANCH = 'develop'; +const ADDITIONAL_BRANCHES = ['qa', 'main']; + +// 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) => { - await execShellCommand(`cd ${projectName} && git init && cd ..`); + const options = { cwd: projectName }; + + await execShellCommand('git init', options); + await execShellCommand('git add -A', options); + await execShellCommand( + 'git 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) => { @@ -211,12 +228,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 7bbcb5e1d..b549ff8bb 100755 --- a/cli/utils.js +++ b/cli/utils.js @@ -5,9 +5,9 @@ const { consola } = require('consola'); const UPSTREAM_REPOSITORY = "obytes/react-native-template-obytes"; const TEMPLATE_REPOSITORY = "rootstrap/react-native-template"; -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); From b445779781c42dda29c3af9b30eb199ee392ca94 Mon Sep 17 00:00:00 2001 From: Fernanda Toledo Date: Tue, 8 Sep 2026 15:15:26 -0300 Subject: [PATCH 2/2] fix(cli): address review feedback on repository initialization - fall back to a template git identity when user.name/user.email are not configured - drop async from synchronous setup helpers so errors reach the try/catch - return after reject in execShellCommand --- cli/setup-project.js | 16 +++++++++++++--- cli/utils.js | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cli/setup-project.js b/cli/setup-project.js index 1e0d70622..71c59bcd4 100755 --- a/cli/setup-project.js +++ b/cli/setup-project.js @@ -16,6 +16,12 @@ 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) => { @@ -23,8 +29,12 @@ const initializeProjectRepository = async (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 commit -m "chore: initial commit from Rootstrap React Native template"', + `git ${identityFlags} commit -m "chore: initial commit from Rootstrap React Native template"`, options, ); await execShellCommand(`git branch -M ${DEFAULT_BRANCH}`, options); @@ -55,7 +65,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'); @@ -76,7 +86,7 @@ const updatePackageJson = async (projectName) => { fs.writeJsonSync(packageJsonPath, packageJson, { spaces: 2 }); }; -const updateProjectConfig = async (projectName) => { +const updateProjectConfig = (projectName) => { projectFilesManager.replaceFilesContent([ { fileName: 'env.js', diff --git a/cli/utils.js b/cli/utils.js index b549ff8bb..95badc227 100755 --- a/cli/utils.js +++ b/cli/utils.js @@ -10,7 +10,7 @@ const execShellCommand = (cmd, options) => { exec(cmd, options, (error, stdout, stderr) => { if (error) { console.warn(error); - reject(error); + return reject(error); } resolve(stdout || stderr); });