From d2a9e04a2b8e3454e83c06896601816d15770f24 Mon Sep 17 00:00:00 2001 From: kozyax Date: Mon, 8 Jun 2026 17:35:28 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20=E5=88=9D=E5=A7=8B=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=20-=202026/6/8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 75 ++++- src/extension.ts | 743 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 788 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 7e88f2e..9263823 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "auto-git-sync", "displayName": "Auto Git Sync - 自动Git同步", "description": "每行代码更改后自动提交并推送到你自己的Gitea服务器,按日期每天一个提交", - "version": "1.0.0", + "version": "2.0.0", "publisher": "kozyax", "engines": { "vscode": "^1.85.0" @@ -31,9 +31,80 @@ }, { "command": "autoGitSync.initRepo", - "title": "Auto Git: 初始化仓库并推送到Gitea" + "title": "Auto Git: 🏗️ 创建Git仓库并推送到Gitea" + }, + { + "command": "autoGitSync.viewLog", + "title": "Auto Git: 📋 查看版本日志" + }, + { + "command": "autoGitSync.restoreVersion", + "title": "Auto Git: ⏪ 恢复到指定版本" + }, + { + "command": "autoGitSync.createBranch", + "title": "Auto Git: 🌿 创建新分支" + }, + { + "command": "autoGitSync.switchBranch", + "title": "Auto Git: 🔀 切换分支" + }, + { + "command": "autoGitSync.pullLatest", + "title": "Auto Git: ⬇️ 拉取最新代码" } ], + "menus": { + "explorer/context": [ + { + "command": "autoGitSync.initRepo", + "when": "!explorerResourceIsFolder || explorerResourceIsFolder", + "group": "autoGitSync@1" + }, + { + "command": "autoGitSync.forceSync", + "group": "autoGitSync@2" + }, + { + "command": "autoGitSync.viewLog", + "group": "autoGitSync@3" + }, + { + "command": "autoGitSync.restoreVersion", + "group": "autoGitSync@4" + }, + { + "command": "autoGitSync.createBranch", + "group": "autoGitSync@5" + }, + { + "command": "autoGitSync.switchBranch", + "group": "autoGitSync@6" + }, + { + "command": "autoGitSync.pullLatest", + "group": "autoGitSync@7" + }, + { + "command": "autoGitSync.enable", + "group": "autoGitSync@8" + }, + { + "command": "autoGitSync.disable", + "group": "autoGitSync@9" + } + ], + "editor/title/context": [ + { + "command": "autoGitSync.forceSync", + "group": "autoGitSync@1" + }, + { + "command": "autoGitSync.viewLog", + "group": "autoGitSync@2" + } + ] + }, "configuration": { "title": "Auto Git Sync 配置", "properties": { diff --git a/src/extension.ts b/src/extension.ts index 09568c1..cbdbb73 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,7 +1,9 @@ import * as vscode from 'vscode'; -import { exec, execSync } from 'child_process'; +import { execSync } from 'child_process'; import * as path from 'path'; import * as fs from 'fs'; +import * as https from 'https'; +import * as http from 'http'; let debounceTimer: ReturnType | undefined; let statusBarItem: vscode.StatusBarItem; @@ -49,10 +51,45 @@ export function activate(context: vscode.ExtensionContext) { }) ); - // 初始化仓库并推送到Gitea + // 🏗️ 创建Git仓库并推送到Gitea context.subscriptions.push( - vscode.commands.registerCommand('autoGitSync.initRepo', async () => { - await initRepoAndPushToGitea(); + vscode.commands.registerCommand('autoGitSync.initRepo', async (clickedUri?: vscode.Uri) => { + await initRepoAndPushToGitea(clickedUri); + }) + ); + + // 📋 查看版本日志 + context.subscriptions.push( + vscode.commands.registerCommand('autoGitSync.viewLog', async (clickedUri?: vscode.Uri) => { + await viewVersionLog(clickedUri); + }) + ); + + // ⏪ 恢复到指定版本 + context.subscriptions.push( + vscode.commands.registerCommand('autoGitSync.restoreVersion', async (clickedUri?: vscode.Uri) => { + await restoreToVersion(clickedUri); + }) + ); + + // 🌿 创建新分支 + context.subscriptions.push( + vscode.commands.registerCommand('autoGitSync.createBranch', async (clickedUri?: vscode.Uri) => { + await createNewBranch(clickedUri); + }) + ); + + // 🔀 切换分支 + context.subscriptions.push( + vscode.commands.registerCommand('autoGitSync.switchBranch', async (clickedUri?: vscode.Uri) => { + await switchBranch(clickedUri); + }) + ); + + // ⬇️ 拉取最新代码 + context.subscriptions.push( + vscode.commands.registerCommand('autoGitSync.pullLatest', async (clickedUri?: vscode.Uri) => { + await pullLatest(clickedUri); }) ); @@ -270,16 +307,630 @@ function runGit(cwd: string, command: string): string { } /** - * 初始化仓库并推送到Gitea + * 获取工作区根目录(优先使用右键点击的目录) */ -async function initRepoAndPushToGitea() { +function getWorkspaceRoot(clickedUri?: vscode.Uri): string | undefined { + // 优先使用右键点击的目录/文件所在目录 + if (clickedUri) { + const clickedPath = clickedUri.fsPath; + // 如果点击的是目录,直接使用 + if (fs.existsSync(clickedPath) && fs.statSync(clickedPath).isDirectory()) { + return clickedPath; + } + // 如果点击的是文件,使用其所在目录 + return path.dirname(clickedPath); + } + + // 没有右键点击时,使用当前工作区 const workspaceFolders = vscode.workspace.workspaceFolders; if (!workspaceFolders || workspaceFolders.length === 0) { - vscode.window.showErrorMessage('请先打开一个项目文件夹!'); + vscode.window.showErrorMessage('❌ 请先打开一个项目文件夹!'); + return undefined; + } + return workspaceFolders[0].uri.fsPath; +} + +// ========== 📋 查看版本日志 ========== + +interface GitCommit { + hash: string; + shortHash: string; + author: string; + date: string; + message: string; +} + +async function viewVersionLog(clickedUri?: vscode.Uri) { + const workspaceRoot = getWorkspaceRoot(clickedUri); + if (!workspaceRoot) { return; } + + if (!fs.existsSync(path.join(workspaceRoot, '.git'))) { + vscode.window.showErrorMessage('❌ 当前项目不是Git仓库!请先使用"创建Git仓库"命令。'); return; } - const workspaceRoot = workspaceFolders[0].uri.fsPath; + try { + // 获取最近30条提交记录 + const logOutput = runGit(workspaceRoot, 'log --max-count=30 --pretty=format:"%H|%h|%an|%ai|%s"'); + + if (!logOutput.trim()) { + vscode.window.showInformationMessage('📋 暂无提交记录'); + return; + } + + const commits: GitCommit[] = logOutput.trim().split('\n').map(line => { + const parts = line.split('|'); + return { + hash: parts[0] || '', + shortHash: parts[1] || '', + author: parts[2] || '', + date: parts[3] || '', + message: parts.slice(4).join('|') || '' + }; + }); + + // 创建Webview面板显示日志 + const panel = vscode.window.createWebviewPanel( + 'gitVersionLog', + '📋 Git版本日志', + vscode.ViewColumn.One, + { enableScripts: true } + ); + + panel.webview.html = getLogWebviewHtml(commits); + + // 监听webview消息 + panel.webview.onDidReceiveMessage( + async (msg) => { + if (msg.command === 'restore') { + panel.dispose(); + await restoreToCommit(msg.hash, msg.message); + } else if (msg.command === 'viewDiff') { + await viewDiff(msg.hash); + } + }, + undefined, + [] + ); + + } catch (error: any) { + vscode.window.showErrorMessage(`❌ 获取版本日志失败: ${error.message}`); + } +} + +function getLogWebviewHtml(commits: GitCommit[]): string { + const commitRows = commits.map((c, index) => { + const isFirst = index === 0; + const tag = isFirst ? '最新' : ''; + + return ` +
+
+ ${c.shortHash} + ${tag} + ${c.date} +
+
${c.message}
+
👤 ${c.author}
+
+ + ${!isFirst ? `` : ''} +
+
`; + }).join(''); + + return ` + + + + + Git版本日志 + + + +

📋 Git版本日志

+
💡 点击"恢复到此版本"可将项目回退到该版本的状态。点击"查看差异"可查看该版本的改动内容。
+ ${commitRows} + + + +`; +} + +// ========== ⏪ 恢复到指定版本 ========== + +async function restoreToVersion(clickedUri?: vscode.Uri) { + const workspaceRoot = getWorkspaceRoot(clickedUri); + if (!workspaceRoot) { return; } + + if (!fs.existsSync(path.join(workspaceRoot, '.git'))) { + vscode.window.showErrorMessage('❌ 当前项目不是Git仓库!'); + return; + } + + try { + // 获取提交列表 + const logOutput = runGit(workspaceRoot, 'log --max-count=20 --pretty=format:"%H|%h|%s"'); + if (!logOutput.trim()) { + vscode.window.showInformationMessage('📋 暂无提交记录'); + return; + } + + const commits = logOutput.trim().split('\n').map(line => { + const parts = line.split('|'); + return { + hash: parts[0], + shortHash: parts[1], + message: parts.slice(2).join('|') + }; + }); + + const items = commits.map(c => ({ + label: `$(git-commit) ${c.shortHash}`, + description: c.message, + detail: c.hash + })); + + const selected = await vscode.window.showQuickPick(items, { + placeHolder: '选择要恢复到的版本', + title: '⏪ 恢复到指定版本' + }); + + if (selected) { + await restoreToCommit(selected.detail, selected.description); + } + + } catch (error: any) { + vscode.window.showErrorMessage(`❌ 获取版本列表失败: ${error.message}`); + } +} + +async function restoreToCommit(hash: string, message: string) { + const workspaceRoot = getWorkspaceRoot(); + if (!workspaceRoot) { return; } + + // 选择恢复方式 + const restoreType = await vscode.window.showQuickPick([ + { + label: '$(copy) 软恢复(保留更改在工作区)', + description: 'git reset --soft', + detail: '回退提交,但保留文件更改在工作区,可以重新编辑' + }, + { + label: '$(file) 混合恢复(保留更改在暂存区)', + description: 'git reset --mixed', + detail: '回退提交,文件更改放回暂存区' + }, + { + label: '$(trash) 硬恢复(丢弃所有更改)⚠️', + description: 'git reset --hard', + detail: '完全回退到该版本,丢弃之后的所有更改!不可恢复!' + }, + { + label: '$(branch) 创建新分支保留', + description: '从该版本创建新分支', + detail: '在该版本上创建新分支,当前分支不受影响' + } + ], { + placeHolder: '选择恢复方式', + title: `⏪ 恢复到: ${message}` + }); + + if (!restoreType) { return; } + + try { + if (restoreType.description === 'git reset --soft') { + runGit(workspaceRoot, `reset --soft ${hash}`); + vscode.window.showInformationMessage(`✅ 已软恢复到版本 ${hash.substring(0, 7)},更改保留在工作区`); + } else if (restoreType.description === 'git reset --mixed') { + runGit(workspaceRoot, `reset --mixed ${hash}`); + vscode.window.showInformationMessage(`✅ 已混合恢复到版本 ${hash.substring(0, 7)},更改在暂存区`); + } else if (restoreType.description === 'git reset --hard') { + // 硬恢复需要确认 + const confirm = await vscode.window.showWarningMessage( + `⚠️ 确定要硬恢复吗?这将丢弃版本 ${hash.substring(0, 7)} 之后的所有更改,不可恢复!`, + { modal: true }, + '确认恢复' + ); + if (confirm === '确认恢复') { + runGit(workspaceRoot, `reset --hard ${hash}`); + vscode.window.showInformationMessage(`✅ 已硬恢复到版本 ${hash.substring(0, 7)}`); + } else { + return; + } + } else if (restoreType.description === '从该版本创建新分支') { + const branchName = await vscode.window.showInputBox({ + prompt: '请输入新分支名称', + placeHolder: '例如: feature/restore-version' + }); + if (branchName) { + runGit(workspaceRoot, `checkout -b ${branchName} ${hash}`); + vscode.window.showInformationMessage(`✅ 已从版本 ${hash.substring(0, 7)} 创建并切换到新分支 ${branchName}`); + } + } + + // 推送到远程 + const autoPush = vscode.workspace.getConfiguration('autoGitSync').get('autoPush', true); + if (autoPush && restoreType.description !== '从该版本创建新分支') { + try { + runGit(workspaceRoot, 'push --force-with-lease'); + vscode.window.showInformationMessage('✅ 已强制推送到远程'); + } catch (e: any) { + vscode.window.showWarningMessage(`⚠️ 推送失败: ${e.message}`); + } + } + + } catch (error: any) { + vscode.window.showErrorMessage(`❌ 恢复失败: ${error.message}`); + } +} + +// ========== 📊 查看差异 ========== + +async function viewDiff(hash: string) { + const workspaceRoot = getWorkspaceRoot(); + if (!workspaceRoot) { return; } + + try { + const diffOutput = runGit(workspaceRoot, `show --stat ${hash}`); + const fullDiff = runGit(workspaceRoot, `show ${hash}`); + + const panel = vscode.window.createWebviewPanel( + 'gitDiff', + `📊 版本差异 - ${hash.substring(0, 7)}`, + vscode.ViewColumn.One, + { enableScripts: true } + ); + + panel.webview.html = getDiffWebviewHtml(hash, diffOutput, fullDiff); + + } catch (error: any) { + vscode.window.showErrorMessage(`❌ 查看差异失败: ${error.message}`); + } +} + +function getDiffWebviewHtml(hash: string, stat: string, diff: string): string { + // 转义HTML特殊字符 + const escapeHtml = (str: string) => str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + + const diffLines = escapeHtml(diff).split('\n').map(line => { + if (line.startsWith('+++') || line.startsWith('---')) { + return `
${line}
`; + } else if (line.startsWith('@@')) { + return `
${line}
`; + } else if (line.startsWith('+')) { + return `
${line}
`; + } else if (line.startsWith('-')) { + return `
${line}
`; + } else { + return `
${line}
`; + } + }).join(''); + + return ` + + + + 版本差异 + + + +

📊 版本差异 - ${hash.substring(0, 7)}

+
${escapeHtml(stat)}
+
${diffLines}
+ +`; +} + +// ========== 🌿 创建新分支 ========== + +async function createNewBranch(clickedUri?: vscode.Uri) { + const workspaceRoot = getWorkspaceRoot(clickedUri); + if (!workspaceRoot) { return; } + + if (!fs.existsSync(path.join(workspaceRoot, '.git'))) { + vscode.window.showErrorMessage('❌ 当前项目不是Git仓库!'); + return; + } + + const branchName = await vscode.window.showInputBox({ + prompt: '请输入新分支名称', + placeHolder: '例如: feature/new-feature', + title: '🌿 创建新分支' + }); + + if (!branchName) { return; } + + try { + // 先提交当前更改 + if (checkHasChanges(workspaceRoot)) { + const shouldCommit = await vscode.window.showQuickPick([ + { label: '$(check) 提交更改后创建分支', description: '先提交当前更改' }, + { label: '$(x) 暂存更改后创建分支', description: 'git stash 保存更改' }, + { label: '$(warning) 直接创建分支', description: '更改将带到新分支' } + ], { placeHolder: '当前有未提交的更改,如何处理?' }); + + if (!shouldCommit) { return; } + + if (shouldCommit.description === '先提交当前更改') { + runGit(workspaceRoot, 'add -A'); + const commitMsg = generateCommitMessage('创建分支前提交'); + runGit(workspaceRoot, `commit -m "${commitMsg}" --allow-empty`); + } else if (shouldCommit.description === 'git stash 保存更改') { + runGit(workspaceRoot, 'stash'); + } + } + + runGit(workspaceRoot, `checkout -b ${branchName}`); + vscode.window.showInformationMessage(`✅ 已创建并切换到新分支: ${branchName}`); + + // 推送新分支到远程 + try { + runGit(workspaceRoot, `push -u origin ${branchName}`); + vscode.window.showInformationMessage(`✅ 新分支已推送到远程`); + } catch (e: any) { + vscode.window.showWarningMessage(`⚠️ 推送新分支失败: ${e.message}`); + } + + } catch (error: any) { + vscode.window.showErrorMessage(`❌ 创建分支失败: ${error.message}`); + } +} + +// ========== 🔀 切换分支 ========== + +async function switchBranch(clickedUri?: vscode.Uri) { + const workspaceRoot = getWorkspaceRoot(clickedUri); + if (!workspaceRoot) { return; } + + if (!fs.existsSync(path.join(workspaceRoot, '.git'))) { + vscode.window.showErrorMessage('❌ 当前项目不是Git仓库!'); + return; + } + + try { + // 获取所有分支 + const branchOutput = runGit(workspaceRoot, 'branch -a'); + const branches = branchOutput.trim().split('\n') + .map(b => b.replace('*', '').trim()) + .filter(b => b && !b.includes('HEAD')); + + if (branches.length === 0) { + vscode.window.showInformationMessage('📋 暂无其他分支'); + return; + } + + const currentBranch = runGit(workspaceRoot, 'branch --show-current').trim(); + + const items = branches.map(b => { + const isCurrent = b === currentBranch; + const isRemote = b.includes('remotes/'); + const displayName = isRemote ? `$(cloud) ${b.replace('remotes/', '')}` : `$(git-branch) ${b}`; + return { + label: displayName, + description: isCurrent ? '(当前)' : '', + detail: b, + picked: isCurrent + }; + }); + + const selected = await vscode.window.showQuickPick(items, { + placeHolder: `当前分支: ${currentBranch} — 选择要切换到的分支`, + title: '🔀 切换分支' + }); + + if (selected && selected.detail !== currentBranch) { + let branchName = selected.detail; + + // 处理未提交的更改 + if (checkHasChanges(workspaceRoot)) { + const shouldStash = await vscode.window.showQuickPick([ + { label: '$(check) 提交更改后切换', description: '先提交当前更改' }, + { label: '$(archive) 暂存更改后切换', description: 'git stash' }, + { label: '$(warning) 强制切换', description: '可能丢失更改' } + ], { placeHolder: '当前有未提交的更改,如何处理?' }); + + if (!shouldStash) { return; } + + if (shouldStash.description === '先提交当前更改') { + runGit(workspaceRoot, 'add -A'); + const commitMsg = generateCommitMessage('切换分支前提交'); + runGit(workspaceRoot, `commit -m "${commitMsg}" --allow-empty`); + } else if (shouldStash.description === 'git stash') { + runGit(workspaceRoot, 'stash'); + } + } + + // 如果是远程分支,需要创建本地分支 + if (branchName.includes('remotes/origin/')) { + const localName = branchName.replace('remotes/origin/', ''); + runGit(workspaceRoot, `checkout -b ${localName} ${branchName}`); + } else { + runGit(workspaceRoot, `checkout ${branchName}`); + } + + vscode.window.showInformationMessage(`✅ 已切换到分支: ${selected.detail}`); + } + + } catch (error: any) { + vscode.window.showErrorMessage(`❌ 切换分支失败: ${error.message}`); + } +} + +// ========== ⬇️ 拉取最新代码 ========== + +async function pullLatest(clickedUri?: vscode.Uri) { + const workspaceRoot = getWorkspaceRoot(clickedUri); + if (!workspaceRoot) { return; } + + if (!fs.existsSync(path.join(workspaceRoot, '.git'))) { + vscode.window.showErrorMessage('❌ 当前项目不是Git仓库!'); + return; + } + + try { + statusBarItem.text = '$(sync~spin) Auto Git: 正在拉取...'; + + // 先提交本地更改 + if (checkHasChanges(workspaceRoot)) { + runGit(workspaceRoot, 'add -A'); + const commitMsg = generateCommitMessage('拉取前自动提交'); + runGit(workspaceRoot, `commit -m "${commitMsg}" --allow-empty`); + } + + runGit(workspaceRoot, 'pull --rebase'); + statusBarItem.text = '$(check) Auto Git: 已拉取'; + vscode.window.showInformationMessage('✅ 已拉取最新代码'); + + updateStatusBar(); + + } catch (error: any) { + statusBarItem.text = '$(error) Auto Git: 拉取失败'; + // 尝试中止rebase + try { + runGit(workspaceRoot, 'rebase --abort'); + } catch { /* ignore */ } + + vscode.window.showErrorMessage(`❌ 拉取失败: ${error.message}`); + setTimeout(updateStatusBar, 5000); + } +} + +// ========== 🏗️ 初始化仓库并推送到Gitea ========== + +async function initRepoAndPushToGitea(clickedUri?: vscode.Uri) { + const workspaceRoot = getWorkspaceRoot(clickedUri); + if (!workspaceRoot) { return; } const config = vscode.workspace.getConfiguration('autoGitSync'); const giteaUrl = config.get('giteaUrl', 'http://localhost:3000'); const giteaToken = config.get('giteaToken', ''); @@ -292,29 +943,58 @@ async function initRepoAndPushToGitea() { }); if (!username) { return; } - // 输入仓库名 + // 输入仓库名 - 自动清理不合法字符 + const rawName = path.basename(workspaceRoot); + const defaultName = rawName.replace(/[^a-zA-Z0-9_\-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, ''); const projectName = await vscode.window.showInputBox({ - prompt: '请输入仓库名称', + prompt: '请输入仓库名称(仅支持字母、数字、中横线、下划线)', placeHolder: '例如: my-project', - value: path.basename(workspaceRoot) + value: defaultName, + validateInput: (value) => { + if (!/^[a-zA-Z0-9_\-]+$/.test(value)) { + return '仓库名称只能包含字母、数字、中横线(-)和下划线(_)'; + } + return null; + } }); if (!projectName) { return; } + // 选择仓库可见性 + const visibility = await vscode.window.showQuickPick([ + { label: '$(lock) 私有仓库', description: 'private', detail: '仅自己可见' }, + { label: '$(globe) 公开仓库', description: 'public', detail: '所有人可见' } + ], { placeHolder: '选择仓库可见性' }); + + const isPrivate = visibility?.description !== 'public'; + try { + statusBarItem.text = '$(sync~spin) Auto Git: 正在创建仓库...'; + // 如果不是Git仓库,先初始化 if (!fs.existsSync(path.join(workspaceRoot, '.git'))) { runGit(workspaceRoot, 'init'); vscode.window.showInformationMessage('✅ Git仓库已初始化'); } + // 设置用户信息 + try { runGit(workspaceRoot, `config user.name "${username}"`); } catch { /* ignore */ } + try { runGit(workspaceRoot, 'config user.email "user@gitea.local"'); } catch { /* ignore */ } + // 创建远程仓库(通过Gitea API) if (giteaToken) { - await createGiteaRepo(giteaUrl, giteaToken, username, projectName); - vscode.window.showInformationMessage('✅ Gitea远程仓库已创建'); + try { + await createGiteaRepo(giteaUrl, giteaToken, username, projectName, isPrivate); + vscode.window.showInformationMessage('✅ Gitea远程仓库已创建'); + } catch (e: any) { + vscode.window.showWarningMessage(`⚠️ 创建远程仓库失败: ${e.message},请手动创建`); + } + } else { + vscode.window.showWarningMessage('⚠️ 未设置Gitea令牌,请手动在Gitea上创建仓库'); } // 设置远程地址 - const remoteUrl = `${giteaUrl}/${username}/${projectName}.git`; + const cleanUrl = giteaUrl.replace(/\/$/, ''); + const remoteUrl = `${cleanUrl}/${username}/${projectName}.git`; try { runGit(workspaceRoot, 'remote remove origin'); } catch { /* remote可能不存在 */ } @@ -330,32 +1010,39 @@ async function initRepoAndPushToGitea() { runGit(workspaceRoot, 'branch -M main'); runGit(workspaceRoot, 'push -u origin main'); + statusBarItem.text = '$(check) Auto Git: 已推送'; vscode.window.showInformationMessage(`🎉 仓库已推送到 ${remoteUrl}`); + updateStatusBar(); + } catch (error: any) { - vscode.window.showErrorMessage(`初始化失败: ${error.message}`); + statusBarItem.text = '$(error) Auto Git: 创建失败'; + vscode.window.showErrorMessage(`❌ 初始化失败: ${error.message}`); + setTimeout(updateStatusBar, 5000); } } /** * 通过Gitea API创建仓库 */ -async function createGiteaRepo(giteaUrl: string, token: string, username: string, repoName: string): Promise { - const axios = await import('https'); +async function createGiteaRepo(giteaUrl: string, token: string, username: string, repoName: string, isPrivate: boolean): Promise { + const cleanUrl = giteaUrl.replace(/\/$/, ''); + const url = `${cleanUrl}/api/v1/user/repos`; + const data = JSON.stringify({ + name: repoName, + private: isPrivate, + auto_init: false, + description: `自动创建的仓库 - ${new Date().toLocaleDateString('zh-CN')}` + }); return new Promise((resolve, reject) => { - const url = `${giteaUrl}/api/v1/user/repos`; - const data = JSON.stringify({ - name: repoName, - private: true, - auto_init: false, - description: `自动创建的仓库 - ${new Date().toLocaleDateString('zh-CN')}` - }); - const parsedUrl = new URL(url); - const options = { + const isHttps = parsedUrl.protocol === 'https:'; + const requestModule = isHttps ? https : http; + + const options: any = { hostname: parsedUrl.hostname, - port: parsedUrl.port, + port: parsedUrl.port || (isHttps ? 443 : 80), path: parsedUrl.pathname, method: 'POST', headers: { @@ -366,7 +1053,7 @@ async function createGiteaRepo(giteaUrl: string, token: string, username: string rejectUnauthorized: false }; - const req = axios.request(options, (res) => { + const req = requestModule.request(options, (res) => { let body = ''; res.on('data', (chunk: string) => { body += chunk; }); res.on('end', () => {