🎉 初始提交 - Auto Git Sync VS Code扩展
这个提交包含在:
当前提交
c05e688a04
5
.gitignore
vendored
普通文件
5
.gitignore
vendored
普通文件
@ -0,0 +1,5 @@
|
|||||||
|
node_modules/
|
||||||
|
out/
|
||||||
|
*.vsix
|
||||||
|
*.js.map
|
||||||
|
.vscode/
|
||||||
9
.vscodeignore
普通文件
9
.vscodeignore
普通文件
@ -0,0 +1,9 @@
|
|||||||
|
.vscode/**
|
||||||
|
.vscode-test/**
|
||||||
|
src/**
|
||||||
|
.gitignore
|
||||||
|
**/tsconfig.json
|
||||||
|
**/.eslintrc.json
|
||||||
|
**/*.map
|
||||||
|
**/*.ts
|
||||||
|
node_modules/**
|
||||||
21
LICENSE
普通文件
21
LICENSE
普通文件
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 kozyax
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
58
package-lock.json
自动生成的
普通文件
58
package-lock.json
自动生成的
普通文件
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"name": "auto-git-sync",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "auto-git-sync",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "18.x",
|
||||||
|
"@types/vscode": "^1.85.0",
|
||||||
|
"typescript": "^5.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.85.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "18.19.130",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.19.130.tgz",
|
||||||
|
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/vscode": {
|
||||||
|
"version": "1.120.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/vscode/-/vscode-1.120.0.tgz",
|
||||||
|
"integrity": "sha512-feaT4Rst+FkTch5zz/ZbNCxoIvo55YU80Be2kiL7OJcod4+CUYf2lUBPdIJzozNnSEMq1VRTGrWEcCGFB3fBmA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.9.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
|
||||||
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
85
package.json
普通文件
85
package.json
普通文件
@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"name": "auto-git-sync",
|
||||||
|
"displayName": "Auto Git Sync - 自动Git同步",
|
||||||
|
"description": "每行代码更改后自动提交并推送到你自己的Gitea服务器,按日期每天一个提交",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"publisher": "kozyax",
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.85.0"
|
||||||
|
},
|
||||||
|
"categories": [
|
||||||
|
"Other",
|
||||||
|
"SCM"
|
||||||
|
],
|
||||||
|
"activationEvents": [
|
||||||
|
"onStartupFinished"
|
||||||
|
],
|
||||||
|
"main": "./out/extension.js",
|
||||||
|
"contributes": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"command": "autoGitSync.enable",
|
||||||
|
"title": "Auto Git: 启用自动同步"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "autoGitSync.disable",
|
||||||
|
"title": "Auto Git: 停用自动同步"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "autoGitSync.forceSync",
|
||||||
|
"title": "Auto Git: 立即同步"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "autoGitSync.initRepo",
|
||||||
|
"title": "Auto Git: 初始化仓库并推送到Gitea"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration": {
|
||||||
|
"title": "Auto Git Sync 配置",
|
||||||
|
"properties": {
|
||||||
|
"autoGitSync.giteaUrl": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "http://localhost:3000",
|
||||||
|
"description": "Gitea 服务器地址"
|
||||||
|
},
|
||||||
|
"autoGitSync.giteaToken": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Gitea 访问令牌 (在Gitea设置 -> 应用 -> 生成令牌)"
|
||||||
|
},
|
||||||
|
"autoGitSync.autoPush": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "提交后是否自动推送到远程"
|
||||||
|
},
|
||||||
|
"autoGitSync.debounceSeconds": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 5,
|
||||||
|
"description": "保存后等待几秒再提交(防抖)"
|
||||||
|
},
|
||||||
|
"autoGitSync.dailyCommit": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "按日期每天一个提交(追加到当天提交)"
|
||||||
|
},
|
||||||
|
"autoGitSync.enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "是否启用自动同步"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"vscode:prepublish": "npm run compile",
|
||||||
|
"compile": "tsc -p ./",
|
||||||
|
"watch": "tsc -watch -p ./",
|
||||||
|
"pretest": "npm run compile && npm run lint",
|
||||||
|
"lint": "eslint src --ext ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/vscode": "^1.85.0",
|
||||||
|
"@types/node": "18.x",
|
||||||
|
"typescript": "^5.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
414
src/extension.ts
普通文件
414
src/extension.ts
普通文件
@ -0,0 +1,414 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { exec, execSync } from 'child_process';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
let debounceTimer: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
let statusBarItem: vscode.StatusBarItem;
|
||||||
|
let isEnabled = true;
|
||||||
|
|
||||||
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
|
console.log('Auto Git Sync 插件已激活!');
|
||||||
|
|
||||||
|
// 读取配置
|
||||||
|
const config = vscode.workspace.getConfiguration('autoGitSync');
|
||||||
|
isEnabled = config.get<boolean>('enabled', true);
|
||||||
|
|
||||||
|
// 创建状态栏
|
||||||
|
statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
|
||||||
|
updateStatusBar();
|
||||||
|
statusBarItem.show();
|
||||||
|
context.subscriptions.push(statusBarItem);
|
||||||
|
|
||||||
|
// ========== 命令注册 ==========
|
||||||
|
|
||||||
|
// 启用自动同步
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.commands.registerCommand('autoGitSync.enable', () => {
|
||||||
|
isEnabled = true;
|
||||||
|
config.update('enabled', true, true);
|
||||||
|
updateStatusBar();
|
||||||
|
vscode.window.showInformationMessage('✅ Auto Git Sync 已启用!');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// 停用自动同步
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.commands.registerCommand('autoGitSync.disable', () => {
|
||||||
|
isEnabled = false;
|
||||||
|
config.update('enabled', false, true);
|
||||||
|
updateStatusBar();
|
||||||
|
vscode.window.showInformationMessage('⏸️ Auto Git Sync 已停用!');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// 立即同步
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.commands.registerCommand('autoGitSync.forceSync', async () => {
|
||||||
|
await autoCommitAndPush('手动同步');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// 初始化仓库并推送到Gitea
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.commands.registerCommand('autoGitSync.initRepo', async () => {
|
||||||
|
await initRepoAndPushToGitea();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// ========== 监听文件保存 ==========
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.workspace.onDidSaveTextDocument((doc) => {
|
||||||
|
if (!isEnabled) { return; }
|
||||||
|
|
||||||
|
// 只处理文件类型的文档
|
||||||
|
if (doc.uri.scheme !== 'file') { return; }
|
||||||
|
|
||||||
|
// 忽略.git目录下的文件
|
||||||
|
const filePath = doc.uri.fsPath;
|
||||||
|
if (filePath.includes('.git') || filePath.includes('node_modules')) { return; }
|
||||||
|
|
||||||
|
const debounceSeconds = config.get<number>('debounceSeconds', 5);
|
||||||
|
|
||||||
|
// 防抖:保存后等待几秒再提交
|
||||||
|
if (debounceTimer) {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
statusBarItem.text = '$(sync~spin) Auto Git: 等待提交...';
|
||||||
|
statusBarItem.tooltip = `代码已保存,${debounceSeconds}秒后自动提交`;
|
||||||
|
|
||||||
|
debounceTimer = setTimeout(async () => {
|
||||||
|
await autoCommitAndPush();
|
||||||
|
}, debounceSeconds * 1000);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// ========== 监听文件创建/删除 ==========
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.workspace.onDidCreateFiles(() => {
|
||||||
|
if (!isEnabled) { return; }
|
||||||
|
scheduleAutoSync();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
context.subscriptions.push(
|
||||||
|
vscode.workspace.onDidDeleteFiles(() => {
|
||||||
|
if (!isEnabled) { return; }
|
||||||
|
scheduleAutoSync();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 核心功能 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防抖调度自动同步
|
||||||
|
*/
|
||||||
|
function scheduleAutoSync() {
|
||||||
|
const config = vscode.workspace.getConfiguration('autoGitSync');
|
||||||
|
const debounceSeconds = config.get<number>('debounceSeconds', 5);
|
||||||
|
|
||||||
|
if (debounceTimer) {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
statusBarItem.text = '$(sync~spin) Auto Git: 等待提交...';
|
||||||
|
|
||||||
|
debounceTimer = setTimeout(async () => {
|
||||||
|
await autoCommitAndPush();
|
||||||
|
}, debounceSeconds * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动提交并推送
|
||||||
|
*/
|
||||||
|
async function autoCommitAndPush(manualReason?: string) {
|
||||||
|
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||||
|
if (!workspaceFolders || workspaceFolders.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceRoot = workspaceFolders[0].uri.fsPath;
|
||||||
|
const config = vscode.workspace.getConfiguration('autoGitSync');
|
||||||
|
|
||||||
|
// 检查是否是Git仓库
|
||||||
|
if (!fs.existsSync(path.join(workspaceRoot, '.git'))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查是否有更改
|
||||||
|
const hasChanges = checkHasChanges(workspaceRoot);
|
||||||
|
if (!hasChanges) {
|
||||||
|
updateStatusBar();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
statusBarItem.text = '$(sync~spin) Auto Git: 正在提交...';
|
||||||
|
|
||||||
|
// git add all
|
||||||
|
runGit(workspaceRoot, 'add -A');
|
||||||
|
|
||||||
|
// 生成提交信息
|
||||||
|
const commitMsg = generateCommitMessage(manualReason);
|
||||||
|
|
||||||
|
// git commit
|
||||||
|
const dailyCommit = config.get<boolean>('dailyCommit', true);
|
||||||
|
|
||||||
|
if (dailyCommit) {
|
||||||
|
// 按日期每天一个提交:先尝试amend到今天的提交
|
||||||
|
const todayCommitExists = checkTodayCommitExists(workspaceRoot);
|
||||||
|
if (todayCommitExists) {
|
||||||
|
runGit(workspaceRoot, `commit --amend --no-edit --allow-empty`);
|
||||||
|
} else {
|
||||||
|
runGit(workspaceRoot, `commit -m "${commitMsg}" --allow-empty`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
runGit(workspaceRoot, `commit -m "${commitMsg}" --allow-empty`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动推送
|
||||||
|
const autoPush = config.get<boolean>('autoPush', true);
|
||||||
|
if (autoPush) {
|
||||||
|
statusBarItem.text = '$(sync~spin) Auto Git: 正在推送...';
|
||||||
|
runGit(workspaceRoot, 'push --force-with-lease');
|
||||||
|
statusBarItem.text = '$(check) Auto Git: 已同步';
|
||||||
|
vscode.window.setStatusBarMessage('✅ Auto Git: 已同步到服务器', 3000);
|
||||||
|
} else {
|
||||||
|
statusBarItem.text = '$(check) Auto Git: 已提交';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatusBar();
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Auto Git Sync 错误:', error);
|
||||||
|
statusBarItem.text = '$(error) Auto Git: 错误';
|
||||||
|
statusBarItem.tooltip = `错误: ${error.message}`;
|
||||||
|
setTimeout(updateStatusBar, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成提交信息
|
||||||
|
*/
|
||||||
|
function generateCommitMessage(manualReason?: string): string {
|
||||||
|
const now = new Date();
|
||||||
|
const dateStr = now.toLocaleDateString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit'
|
||||||
|
});
|
||||||
|
const timeStr = now.toLocaleTimeString('zh-CN', {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (manualReason) {
|
||||||
|
return `📝 ${manualReason} - ${dateStr} ${timeStr}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `📋 自动同步 - ${dateStr} ${timeStr}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查今天是否已有提交
|
||||||
|
*/
|
||||||
|
function checkTodayCommitExists(workspaceRoot: string): boolean {
|
||||||
|
try {
|
||||||
|
const now = new Date();
|
||||||
|
const todayStr = now.toLocaleDateString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取最近一次提交的信息
|
||||||
|
const lastMsg = runGit(workspaceRoot, 'log -1 --pretty=%s').trim();
|
||||||
|
|
||||||
|
// 如果今天已有提交(包含今天的日期),则amend
|
||||||
|
if (lastMsg.includes(todayStr) || lastMsg.includes('自动同步')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否有更改
|
||||||
|
*/
|
||||||
|
function checkHasChanges(workspaceRoot: string): boolean {
|
||||||
|
try {
|
||||||
|
const status = runGit(workspaceRoot, 'status --porcelain');
|
||||||
|
return status.trim().length > 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行Git命令
|
||||||
|
*/
|
||||||
|
function runGit(cwd: string, command: string): string {
|
||||||
|
try {
|
||||||
|
return execSync(`git ${command}`, {
|
||||||
|
cwd,
|
||||||
|
encoding: 'utf-8',
|
||||||
|
timeout: 30000,
|
||||||
|
stdio: ['pipe', 'pipe', 'pipe']
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
// git commit 无更改时不报错
|
||||||
|
if (command.startsWith('commit') && error.stderr?.includes('nothing to commit')) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
throw new Error(`Git命令失败: git ${command}\n${error.stderr || error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化仓库并推送到Gitea
|
||||||
|
*/
|
||||||
|
async function initRepoAndPushToGitea() {
|
||||||
|
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||||
|
if (!workspaceFolders || workspaceFolders.length === 0) {
|
||||||
|
vscode.window.showErrorMessage('请先打开一个项目文件夹!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceRoot = workspaceFolders[0].uri.fsPath;
|
||||||
|
const config = vscode.workspace.getConfiguration('autoGitSync');
|
||||||
|
const giteaUrl = config.get<string>('giteaUrl', 'http://localhost:3000');
|
||||||
|
const giteaToken = config.get<string>('giteaToken', '');
|
||||||
|
|
||||||
|
// 输入Gitea用户名
|
||||||
|
const username = await vscode.window.showInputBox({
|
||||||
|
prompt: '请输入Gitea用户名',
|
||||||
|
placeHolder: '例如: kozyax',
|
||||||
|
value: 'kozyax'
|
||||||
|
});
|
||||||
|
if (!username) { return; }
|
||||||
|
|
||||||
|
// 输入仓库名
|
||||||
|
const projectName = await vscode.window.showInputBox({
|
||||||
|
prompt: '请输入仓库名称',
|
||||||
|
placeHolder: '例如: my-project',
|
||||||
|
value: path.basename(workspaceRoot)
|
||||||
|
});
|
||||||
|
if (!projectName) { return; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 如果不是Git仓库,先初始化
|
||||||
|
if (!fs.existsSync(path.join(workspaceRoot, '.git'))) {
|
||||||
|
runGit(workspaceRoot, 'init');
|
||||||
|
vscode.window.showInformationMessage('✅ Git仓库已初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建远程仓库(通过Gitea API)
|
||||||
|
if (giteaToken) {
|
||||||
|
await createGiteaRepo(giteaUrl, giteaToken, username, projectName);
|
||||||
|
vscode.window.showInformationMessage('✅ Gitea远程仓库已创建');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置远程地址
|
||||||
|
const remoteUrl = `${giteaUrl}/${username}/${projectName}.git`;
|
||||||
|
try {
|
||||||
|
runGit(workspaceRoot, 'remote remove origin');
|
||||||
|
} catch { /* remote可能不存在 */ }
|
||||||
|
runGit(workspaceRoot, `remote add origin ${remoteUrl}`);
|
||||||
|
|
||||||
|
// 添加所有文件并提交
|
||||||
|
runGit(workspaceRoot, 'add -A');
|
||||||
|
try {
|
||||||
|
runGit(workspaceRoot, `commit -m "🎉 初始提交 - ${new Date().toLocaleDateString('zh-CN')}"`);
|
||||||
|
} catch { /* 可能没有文件 */ }
|
||||||
|
|
||||||
|
// 推送
|
||||||
|
runGit(workspaceRoot, 'branch -M main');
|
||||||
|
runGit(workspaceRoot, 'push -u origin main');
|
||||||
|
|
||||||
|
vscode.window.showInformationMessage(`🎉 仓库已推送到 ${remoteUrl}`);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
vscode.window.showErrorMessage(`初始化失败: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过Gitea API创建仓库
|
||||||
|
*/
|
||||||
|
async function createGiteaRepo(giteaUrl: string, token: string, username: string, repoName: string): Promise<void> {
|
||||||
|
const axios = await import('https');
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
hostname: parsedUrl.hostname,
|
||||||
|
port: parsedUrl.port,
|
||||||
|
path: parsedUrl.pathname,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `token ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Content-Length': Buffer.byteLength(data)
|
||||||
|
},
|
||||||
|
rejectUnauthorized: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = axios.request(options, (res) => {
|
||||||
|
let body = '';
|
||||||
|
res.on('data', (chunk: string) => { body += chunk; });
|
||||||
|
res.on('end', () => {
|
||||||
|
if (res.statusCode === 201) {
|
||||||
|
resolve();
|
||||||
|
} else if (res.statusCode === 409) {
|
||||||
|
// 仓库已存在
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(new Error(`创建仓库失败: ${res.statusCode} ${body}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (e: Error) => reject(e));
|
||||||
|
req.write(data);
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新状态栏
|
||||||
|
*/
|
||||||
|
function updateStatusBar() {
|
||||||
|
if (isEnabled) {
|
||||||
|
statusBarItem.text = '$(git-commit) Auto Git: 已启用';
|
||||||
|
statusBarItem.tooltip = 'Auto Git Sync 已启用 - 保存文件时自动提交推送';
|
||||||
|
statusBarItem.command = 'autoGitSync.disable';
|
||||||
|
statusBarItem.backgroundColor = undefined;
|
||||||
|
} else {
|
||||||
|
statusBarItem.text = '$(git-commit) Auto Git: 已停用';
|
||||||
|
statusBarItem.tooltip = 'Auto Git Sync 已停用 - 点击启用';
|
||||||
|
statusBarItem.command = 'autoGitSync.enable';
|
||||||
|
statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deactivate() {
|
||||||
|
if (debounceTimer) {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
}
|
||||||
|
if (statusBarItem) {
|
||||||
|
statusBarItem.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
tsconfig.json
普通文件
15
tsconfig.json
普通文件
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "ES2020",
|
||||||
|
"outDir": "out",
|
||||||
|
"lib": ["ES2020"],
|
||||||
|
"sourceMap": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", ".vscode-test"]
|
||||||
|
}
|
||||||
正在加载...
在新工单中引用
屏蔽一个用户