create-gitee
Version:
快速初始化Git仓库并推送到Gitee的工具
293 lines (250 loc) • 9.81 kB
text/typescript
import * as fs from 'fs';
import * as readline from 'readline';
import { execSync } from 'child_process';
// 创建命令行交互接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 问题询问函数
const askQuestion = (question: string, defaultValue?: string): Promise<string> => {
const fullQuestion = defaultValue ? `${question} (默认: ${defaultValue}): ` : `${question}: `;
return new Promise((resolve) => {
rl.question(fullQuestion, (answer) => {
resolve(answer.trim() || defaultValue || '');
});
});
};
// 执行命令并处理错误
const executeCommand = (command: string, successMessage: string, errorMessage: string = '') => {
try {
execSync(command, { stdio: 'inherit' });
console.log(`\x1b[32m${successMessage}\x1b[0m`);
return true; // 返回 true 表示命令成功
} catch (error) {
console.error(`\x1b[31m${errorMessage || `执行命令失败: ${command}`}\x1b[0m`);
console.error(error);
return false; // 返回 false 表示命令失败
}
};
// 创建.gitignore文件
const createGitignore = () => {
const defaultGitignore = `# 依赖
node_modules/
.pnp/
.pnp.js
# 测试
coverage/
# 生产环境
build/
dist/
# 环境变量
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# 日志
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# 编辑器配置
.idea/
.vscode/
*.swp
*.swo
`;
try {
if (!fs.existsSync('.gitignore')) {
fs.writeFileSync('.gitignore', defaultGitignore, { encoding: 'utf-8' });
console.log('\x1b[32m已创建.gitignore文件\x1b[0m');
} else {
console.log('\x1b[33m.gitignore文件已存在,跳过创建\x1b[0m');
}
} catch (error) {
console.error('\x1b[31m创建.gitignore文件失败,请检查目录权限\x1b[0m');
console.error(error);
process.exit(1);
}
};
// 添加 Git 命令到 package.json
const addGitCommandToPackageJson = async (branch:string='main') => {
const packageJsonPath = './package.json'; // package.json 文件路径
try {
// 读取 package.json 文件内容
const packageJsonData = fs.readFileSync(packageJsonPath, { encoding: 'utf-8' });
const packageJson = JSON.parse(packageJsonData);
// 确保 scripts 字段存在
if (!packageJson.scripts) {
packageJson.scripts = {};
}
// 根据操作系统生成 Git 命令
const isWindows = process.platform === 'win32';
const gitCommand = isWindows
? 'powershell -Command "$msg = Read-Host \'Enter commit message\'; git add .; git commit -m \\\"$msg\\\"; git push"'
: `read -p \'Enter commit message: \' msg && git add . && git commit -m "$msg" && git push`;
// 更新 scripts 字段
packageJson.scripts['git'] = gitCommand;
// 写回 package.json 文件
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), { encoding: 'utf-8' });
console.log(`\x1b[32m已成功添加 Git 命令: "git": "${gitCommand}"\x1b[0m`);
} catch (error) {
console.error('\x1b[31m更新 package.json 失败\x1b[0m');
console.error(error);
}
};
// 检查并更新 package.json 中的 repository 字段
const checkAndUpdateRepository = async (): Promise<string> => {
const packageJsonPath = './package.json';
let repoUrl = '';
try {
// 读取 package.json 文件内容
if (fs.existsSync(packageJsonPath)) {
const packageJsonData = fs.readFileSync(packageJsonPath, { encoding: 'utf-8' });
const packageJson = JSON.parse(packageJsonData);
// 检查是否存在 repository 字段
if (packageJson.repository) {
let existingRepoUrl = '';
if (typeof packageJson.repository === 'string') {
existingRepoUrl = packageJson.repository;
} else if (packageJson.repository.url) {
existingRepoUrl = packageJson.repository.url;
}
if (existingRepoUrl) {
console.log(`\x1b[33m在 package.json 中检测到已设置的仓库地址: ${existingRepoUrl}\x1b[0m`);
const updateAnswer = await askQuestion('是否更新仓库地址?', 'n');
if (updateAnswer.toLowerCase() === 'y' || updateAnswer.toLowerCase() === 'yes') {
repoUrl = await askQuestion('请输入新的Git仓库地址');
} else {
repoUrl = existingRepoUrl;
}
} else {
repoUrl = await askQuestion('请输入Git仓库地址');
}
} else {
repoUrl = await askQuestion('请输入Git仓库地址');
}
} else {
repoUrl = await askQuestion('请输入Git仓库地址');
}
} catch (error) {
console.error('\x1b[31m读取 package.json 失败\x1b[0m');
console.error(error);
repoUrl = await askQuestion('请输入Git仓库地址');
}
// 确保用户输入了仓库地址
while (!repoUrl) {
console.log('\x1b[31m未输入仓库地址,无法继续\x1b[0m');
repoUrl = await askQuestion('请重新输入Git仓库地址');
}
return repoUrl;
};
// 更新 package.json 中的 repository 字段
const updateRepositoryInPackageJson = async (repoUrl: string) => {
const packageJsonPath = './package.json';
try {
if (fs.existsSync(packageJsonPath)) {
const packageJsonData = fs.readFileSync(packageJsonPath, { encoding: 'utf-8' });
const packageJson = JSON.parse(packageJsonData);
// 设置 repository 字段
packageJson.repository = {
type: 'git',
url: repoUrl
};
// 写回 package.json 文件
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), { encoding: 'utf-8' });
console.log(`\x1b[32m已成功设置 repository 字段为: ${repoUrl}\x1b[0m`);
} else {
console.log('\x1b[33m未找到 package.json 文件,跳过设置 repository 字段\x1b[0m');
}
} catch (error) {
console.error('\x1b[31m更新 package.json 中的 repository 字段失败\x1b[0m');
console.error(error);
}
};
// 设置或更新 Git remote origin
const setGitRemoteOrigin = (repoUrl: string) => {
try {
// 检查是否已经存在 origin
execSync('git remote get-url origin', { stdio: 'ignore' });
// 如果没有报错,说明 origin 存在,需要更新
executeCommand(`git remote set-url origin ${repoUrl}`, 'git remote origin 已更新', '更新 git remote origin 失败');
} catch (error) {
// 如果报错,说明 origin 不存在,需要添加
executeCommand(`git remote add origin ${repoUrl}`, 'git remote 添加成功', 'git remote add 失败');
}
};
// 主函数
const main = async () => {
console.log('\x1b[34m欢迎使用create-gitee - 快速初始化Git仓库并推送到Gitee\x1b[0m\n');
// 1. 创建.gitignore文件
createGitignore();
// 2. 初始化 Git 仓库
const initAnswer = await askQuestion('是否执行git init?', 'y');
if (initAnswer.toLowerCase() === 'y' || initAnswer.toLowerCase() === 'yes') {
executeCommand('git init', 'git init 执行成功', 'git init 执行失败');
} else {
console.log('跳过git init');
}
// 3. 添加文件到暂存区
const addAnswer = await askQuestion('是否执行git add .?', 'y');
if (addAnswer.toLowerCase() === 'y' || addAnswer.toLowerCase() === 'yes') {
executeCommand('git add .', 'git add . 执行成功', 'git add . 执行失败');
} else {
console.log('跳过git add .');
}
// 4. 获取commit信息并执行commit
const commitMessage = await askQuestion('请输入commit备注信息', 'Initial commit');
if (commitMessage) {
const commitSuccess = executeCommand(`git commit -m "${commitMessage}"`, 'git commit 执行成功', 'git commit 执行失败');
if (!commitSuccess && /nothing to commit/.test(execSync('git status').toString())) {
console.log('\x1b[33m没有需要提交的更改,跳过git commit\x1b[0m');
} else if (!commitSuccess) {
console.log('\x1b[31mgit commit 失败,程序终止\x1b[0m');
process.exit(1);
}
} else {
console.log('\x1b[31m未输入commit信息,跳过git commit\x1b[0m');
}
// 5. 获取仓库地址(已更新逻辑)
let repoUrl = await checkAndUpdateRepository();
// 6. 设置 repository 字段到 package.json
await updateRepositoryInPackageJson(repoUrl);
// 7. 获取分支名称
let branchName = await askQuestion('请输入分支名称', 'main');
let branch = branchName || 'main';
// 8. 设置或更新远程仓库 (修复了 remote origin already exists 的问题)
setGitRemoteOrigin(repoUrl);
// 9. 推送到远程仓库
let pushSuccess = false;
while (!pushSuccess) {
const pushAnswer = await askQuestion(`是否执行git push到${branch}分支?`, 'y');
if (pushAnswer.toLowerCase() === 'y' || pushAnswer.toLowerCase() === 'yes') {
pushSuccess = executeCommand(`git push -u origin ${branch}`, `git push 到${branch}分支成功`, `git push 到${branch}分支失败`);
if (!pushSuccess) {
console.log('\x1b[31mgit push 失败,请检查分支名称或网络连接\x1b[0m');
branch = await askQuestion('请重新输入分支名称', 'main');
}
} else {
console.log('跳过git push');
break;
}
}
// 提示用户是否添加 Git 提交命令
const gitCommandAnswer = await askQuestion('是否在 package.json 中添加 Git 提交命令?', 'y');
if (gitCommandAnswer.toLowerCase() === 'y' || gitCommandAnswer.toLowerCase() === 'yes') {
await addGitCommandToPackageJson(branchName);
} else {
console.log('跳过添加 Git 提交命令');
}
console.log('\n\x1b[32m操作完成!\x1b[0m');
rl.close();
};
// 启动程序
main().catch((error) => {
console.error('\x1b[31m程序出错\x1b[0m');
console.error(error);
rl.close();
process.exit(1);
});