Skip to content

Commit

Permalink
📝 docs(scm): 添加源代码管理模块详细注释和类型定义
Browse files Browse the repository at this point in the history
- 【代码完善】为所有SCM相关类添加完整的JSDoc文档注释
- 【类型增强】完善接口定义与类型声明
- 【结构优化】规范化错误处理和异常提示
- 【文档补充】补充各个类的职责说明和使用说明
- 【代码规范】统一异步方法的错误处理风格
- 【可维护性】增加关键流程的详细注释说明
  • Loading branch information
littleCareless committed Jan 22, 2025
1 parent 2e70f09 commit 79801c4
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 11 deletions.
29 changes: 28 additions & 1 deletion src/scm/AuthorService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,50 @@ import { LocalizationManager } from "../utils/LocalizationManager";

const execAsync = promisify(exec);

/**
* 作者服务类
* 用于获取Git或SVN仓库的作者信息
*/
export class AuthorService {
/**
* 构造函数
* @param workspacePath 工作区路径
*/
constructor(private readonly workspacePath: string) {}

/**
* 获取仓库作者信息
* @param type 仓库类型:'git'或'svn'
* @returns 作者名称
*/
async getAuthor(type: "git" | "svn"): Promise<string> {
if (type === "git") {
return this.getGitAuthor();
}
return this.getSvnAuthor();
}

/**
* 获取Git仓库的作者信息
* @returns Git配置中的用户名
*/
private async getGitAuthor(): Promise<string> {
const { stdout } = await execAsync("git config user.name");
return stdout.trim();
}

/**
* 获取SVN仓库的作者信息
* 优先从SVN身份验证信息获取,如果失败则提示用户手动输入
* @returns SVN作者名称
* @throws 如果无法获取作者信息则抛出错误
*/
private async getSvnAuthor(): Promise<string> {
// await SvnUtils.getSvnAuthorFromInfo(this.workspacePath) ||
console.log(
"getSvnAuthorFromAuth",
await SvnUtils.getSvnAuthorFromAuth(this.workspacePath)
);
// 尝试从SVN认证信息获取作者,如果失败则提示手动输入
const author =
(await SvnUtils.getSvnAuthorFromAuth(this.workspacePath)) ||
(await this.promptForAuthor());
Expand All @@ -40,6 +63,10 @@ export class AuthorService {
return author;
}

/**
* 提示用户手动输入作者信息
* @returns 用户输入的作者名称,如果用户取消则返回undefined
*/
private async promptForAuthor(): Promise<string | undefined> {
const locManager = LocalizationManager.getInstance();
return vscode.window.showInputBox({
Expand Down
47 changes: 45 additions & 2 deletions src/scm/CommitLogStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,52 @@ import { DateUtils } from "../utils/DateUtils";

const execAsync = promisify(exec);

/**
* 表示一个时间段的接口
*/
interface Period {
/** 开始日期 */
startDate: string;
/** 结束日期 */
endDate: string;
}

/**
* 提交日志策略接口
* 定义了获取代码提交记录的统一接口
*/
export interface CommitLogStrategy {
/**
* 获取指定时间段内指定作者的提交记录
* @param workspacePath 工作区路径
* @param period 时间段
* @param author 作者名
* @returns 提交记录数组
*/
getCommits(
workspacePath: string,
period: Period,
author: string
): Promise<string[]>;
}

/**
* Git提交记录策略实现类
*/
export class GitCommitStrategy implements CommitLogStrategy {
/**
* 获取Git仓库的提交记录
* @param workspacePath Git仓库路径
* @param period 查询的时间段
* @param author 提交作者
* @returns 格式化后的提交记录数组
*/
async getCommits(
workspacePath: string,
period: Period,
author: string
): Promise<string[]> {
// 构建git log命令,格式化输出提交信息
const command = `git log --since="${period.startDate}" --until="${period.endDate}" --pretty=format:"%h - %an, %ar : %s" --author="${author}"`;

console.log("command", command);
Expand All @@ -31,14 +58,23 @@ export class GitCommitStrategy implements CommitLogStrategy {
}
}

/**
* SVN提交记录策略实现类
*/
export class SvnCommitStrategy implements CommitLogStrategy {
/**
* 获取SVN仓库的提交记录
* @param workspacePath SVN仓库路径
* @param period 查询的时间段
* @param author 提交作者
* @returns 解析后的提交记录数组
*/
async getCommits(
workspacePath: string,
period: Period,
author: string
): Promise<string[]> {
// const { startDate, endDate } = DateUtils.getDateRangeFromPeriod(period);

// 构建svn log命令,使用XML格式输出
const command = `svn log -r "{${period.startDate}}:{${period.endDate}}" --search="${author}" --xml`;

console.log("command", command);
Expand All @@ -47,12 +83,19 @@ export class SvnCommitStrategy implements CommitLogStrategy {
return this.parseXmlLogs(stdout);
}

/**
* 解析SVN的XML格式日志输出
* @param xmlOutput XML格式的SVN日志输出
* @returns 提取的提交消息数组
*/
private parseXmlLogs(xmlOutput: string): string[] {
const commits: string[] = [];
// 匹配<logentry>标签内的<msg>内容
const logEntriesRegex =
/<logentry[^>]*>[\s\S]*?<msg>([\s\S]*?)<\/msg>[\s\S]*?<\/logentry>/g;
let match;

// 循环提取所有匹配的提交消息
while ((match = logEntriesRegex.exec(xmlOutput)) !== null) {
if (match[1]?.trim()) {
commits.push(match[1].trim());
Expand Down
76 changes: 71 additions & 5 deletions src/scm/GitProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,59 @@ import { LocalizationManager } from "../utils/LocalizationManager";

const exec = promisify(childProcess.exec);

/**
* Git API接口定义
*/
interface GitAPI {
/** Git仓库集合 */
repositories: GitRepository[];

/**
* 获取指定版本的Git API
* @param version - API版本号
*/
getAPI(version: number): GitAPI;
}

/**
* Git仓库接口定义
*/
interface GitRepository {
/** 提交信息输入框 */
inputBox: {
value: string;
};

/**
* 执行提交操作
* @param message - 提交信息
* @param options - 提交选项
*/
commit(
message: string,
options: { all: boolean; files?: string[] }
): Promise<void>;
}

/**
* Git源代码管理提供者实现
* @implements {ISCMProvider}
*/
export class GitProvider implements ISCMProvider {
/** SCM类型标识符 */
type = "git" as const;

/** 工作区根目录路径 */
private workspaceRoot: string;

/** Git API实例 */
private readonly api: GitAPI;

/**
* 创建Git提供者实例
* @param gitExtension - VS Code Git扩展实例
* @throws {Error} 当未找到工作区时抛出错误
*/
constructor(private readonly gitExtension: any) {
this.api = gitExtension.getAPI(1);
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
Expand All @@ -38,13 +71,22 @@ export class GitProvider implements ISCMProvider {
this.workspaceRoot = workspaceRoot;
}

/**
* 检查Git是否可用
* @returns {Promise<boolean>} 如果Git可用返回true,否则返回false
*/
async isAvailable(): Promise<boolean> {
const api = this.gitExtension.getAPI(1);
const repositories = api.repositories;
return repositories.length > 0;
}

// 优化 getFileStatus 方法
/**
* 获取文件状态
* @param {string} file - 文件路径
* @returns {Promise<string>} 返回文件状态描述
* @private
*/
private async getFileStatus(file: string): Promise<string> {
try {
const { stdout: status } = await exec(
Expand Down Expand Up @@ -74,27 +116,35 @@ export class GitProvider implements ISCMProvider {
}
}

/**
* 获取文件差异信息
* @param {string[]} [files] - 可选的文件路径数组
* @returns {Promise<string | undefined>} 返回差异文本
* @throws {Error} 当执行diff命令失败时抛出错误
*/
async getDiff(files?: string[]): Promise<string | undefined> {
try {
let diffOutput = "";

if (files && files.length > 0) {
// 处理多个文件的情况
// 处理指定文件的差异
for (const file of files) {
const fileStatus = await this.getFileStatus(file);
const escapedFile = file.replace(/"/g, '\\"');
const escapedFile = file.replace(/"/g, '\\"'); // 转义文件路径中的双引号

// 执行单个文件的diff命令
const { stdout } = await exec(`git diff HEAD -- "${escapedFile}"`, {
cwd: this.workspaceRoot,
maxBuffer: 1024 * 1024 * 10,
maxBuffer: 1024 * 1024 * 10, // 设置更大的缓冲区以处理大型差异
});

// 添加文件状态和差异信息
if (stdout.trim()) {
diffOutput += `\n=== ${fileStatus}: ${file} ===\n${stdout}`;
}
}
} else {
// 处理所有改动文件的情况
// 获取所有更改的差异
const { stdout } = await exec("git diff HEAD", {
cwd: this.workspaceRoot,
maxBuffer: 1024 * 1024 * 10,
Expand Down Expand Up @@ -148,6 +198,12 @@ export class GitProvider implements ISCMProvider {
}
}

/**
* 提交更改
* @param {string} message - 提交信息
* @param {string[]} [files] - 要提交的文件路径数组
* @throws {Error} 当提交失败或未找到仓库时抛出错误
*/
async commit(message: string, files?: string[]): Promise<void> {
const api = this.gitExtension.getAPI(1);
const repository = api.repositories[0];
Expand All @@ -161,6 +217,11 @@ export class GitProvider implements ISCMProvider {
await repository.commit(message, { all: files ? false : true, files });
}

/**
* 设置提交输入框的内容
* @param {string} message - 要设置的提交信息
* @throws {Error} 当未找到仓库时抛出错误
*/
async setCommitInput(message: string): Promise<void> {
const api = this.gitExtension.getAPI(1);
const repository = api.repositories[0];
Expand All @@ -174,6 +235,11 @@ export class GitProvider implements ISCMProvider {
repository.inputBox.value = message;
}

/**
* 获取提交输入框的当前内容
* @returns {Promise<string>} 返回当前的提交信息
* @throws {Error} 当未找到仓库时抛出错误
*/
async getCommitInput(): Promise<string> {
const api = this.gitExtension.getAPI(1);
const repository = api.repositories[0];
Expand Down
28 changes: 28 additions & 0 deletions src/scm/SCMProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,42 @@ import { GitProvider } from "./GitProvider";
import { SvnProvider } from "./SvnProvider";
import { LocalizationManager } from "../utils/LocalizationManager";

/**
* 源代码管理提供者接口
* 定义了通用的SCM操作方法
*/
export interface ISCMProvider {
/** SCM类型:"git" 或 "svn" */
type: "git" | "svn";

/** 检查SCM系统是否可用 */
isAvailable(): Promise<boolean>;

/** 获取文件差异 */
getDiff(files?: string[]): Promise<string | undefined>;

/** 提交更改 */
commit(message: string, files?: string[]): Promise<void>;

/** 设置提交信息 */
setCommitInput(message: string): Promise<void>;

/** 获取当前提交信息 */
getCommitInput(): Promise<string>;
}

/**
* SCM工厂类
* 用于创建和管理源代码管理提供者实例
*/
export class SCMFactory {
/** 当前激活的SCM提供者实例 */
private static currentProvider: ISCMProvider | undefined;

/**
* 检测并创建可用的SCM提供者
* @returns {Promise<ISCMProvider | undefined>} 返回可用的SCM提供者实例,如果没有可用的提供者则返回undefined
*/
static async detectSCM(): Promise<ISCMProvider | undefined> {
try {
if (this.currentProvider) {
Expand Down Expand Up @@ -58,6 +82,10 @@ export class SCMFactory {
}
}

/**
* 获取当前使用的SCM类型
* @returns {"git" | "svn" | undefined} 返回当前SCM类型,如果未设置则返回undefined
*/
static getCurrentSCMType(): "git" | "svn" | undefined {
return this.currentProvider?.type;
}
Expand Down
Loading

0 comments on commit 79801c4

Please sign in to comment.