Skip to content

Commit

Permalink
Merge pull request #754 from githru/feat/635
Browse files Browse the repository at this point in the history
AI 요약 기능 도입을 위한 사이드바뷰 도입 및 엔진 호출방식 변경
  • Loading branch information
mdgarden authored Oct 6, 2024
2 parents a8316c6 + be6bd99 commit d44b5aa
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 98 deletions.
119 changes: 119 additions & 0 deletions packages/analysis-engine/src/engine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import "reflect-metadata";

import { container } from "tsyringe";

import { buildCommitDict } from "./commit.util";
import { buildCSMDict } from "./csm";
import getCommitRaws from "./parser";
import { PluginOctokit } from "./pluginOctokit";
import { buildStemDict } from "./stem";
import { getSummary } from "./summary";
import type { CommitNode } from "./types";

export type AnalysisEngineArgs = {
isDebugMode?: boolean;
gitLog: string;
owner: string;
repo: string;
baseBranchName: string;
auth?: string;
};

export class AnalysisEngine {
private static instance: AnalysisEngine | null = null;
private gitLog!: string;
private isDebugMode?: boolean;
private octokit!: PluginOctokit;
private baseBranchName!: string;
private nodes?: CommitNode[];
private isInitialized: boolean = false;

private constructor() {}

public static getInstance(): AnalysisEngine {
if (!AnalysisEngine.instance) {
AnalysisEngine.instance = new AnalysisEngine();
}
return AnalysisEngine.instance;
}

public initialize(args: AnalysisEngineArgs): void {
const { isDebugMode, gitLog, owner, repo, auth, baseBranchName } = args;
this.gitLog = gitLog;
this.baseBranchName = baseBranchName;
this.isDebugMode = isDebugMode;
container.register("OctokitOptions", {
useValue: {
owner,
repo,
options: {
auth,
},
},
});
this.octokit = container.resolve(PluginOctokit);
this.isInitialized = true;
}

private checkInitialization() {
if (!this.isInitialized) {
throw new Error("AnalysisEngine is not initialized. Call initialize() first.");
}
}

public async analyzeGit() {
this.checkInitialization();

if (!this.gitLog) {
throw new Error("AnalysisEngine is not initialized. Call initialize() first.");
}

let isPRSuccess = true;
if (this.isDebugMode) console.log("baseBranchName: ", this.baseBranchName);

const commitRaws = getCommitRaws(this.gitLog);
if (this.isDebugMode) console.log("commitRaws: ", commitRaws);

const commitDict = buildCommitDict(commitRaws);
if (this.isDebugMode) console.log("commitDict: ", commitDict);

const pullRequests = await this.octokit
.getPullRequests()
.catch((err) => {
console.error(err);
isPRSuccess = false;
return [];
})
.then((pullRequests) => {
console.log("success, pr = ", pullRequests);
return pullRequests;
});
if (this.isDebugMode) console.log("pullRequests: ", pullRequests);

const stemDict = buildStemDict(commitDict, this.baseBranchName);
if (this.isDebugMode) console.log("stemDict: ", stemDict);
const csmDict = buildCSMDict(commitDict, stemDict, this.baseBranchName, pullRequests);
if (this.isDebugMode) console.log("csmDict: ", csmDict);
this.nodes = stemDict.get(this.baseBranchName)?.nodes;

return {
isPRSuccess,
csmDict,
};
}

public updateArgs(args: AnalysisEngineArgs) {
if (container.isRegistered("OctokitOptions")) container.clearInstances();
this.initialize(args);
}

public async geminiCommitSummary() {
this.checkInitialization();
if (!this.nodes) {
throw new Error("No commits available. Run analyzeGit() first.");
}
return await getSummary(this.nodes.slice(-10).map(({ commit }) => commit));
}
}

export default AnalysisEngine;
98 changes: 2 additions & 96 deletions packages/analysis-engine/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,96 +1,2 @@
import "reflect-metadata";

import { container } from "tsyringe";

import { buildCommitDict } from "./commit.util";
import { buildCSMDict } from "./csm";
import getCommitRaws from "./parser";
import { PluginOctokit } from "./pluginOctokit";
import { buildStemDict } from "./stem";
import { getCurrentUserCommitSummary, getLatestCommitSummary } from "./summary";

type AnalysisEngineArgs = {
isDebugMode?: boolean;
gitLog: string;
owner: string;
repo: string;
baseBranchName: string;
auth?: string;
};

export class AnalysisEngine {
private gitLog!: string;

private isDebugMode?: boolean;

private octokit!: PluginOctokit;

private baseBranchName!: string;

constructor(args: AnalysisEngineArgs) {
this.insertArgs(args);
}

private insertArgs = (args: AnalysisEngineArgs) => {
const { isDebugMode, gitLog, owner, repo, auth, baseBranchName } = args;
this.gitLog = gitLog;
this.baseBranchName = baseBranchName;
this.isDebugMode = isDebugMode;
container.register("OctokitOptions", {
useValue: {
owner,
repo,
options: {
auth,
},
},
});
this.octokit = container.resolve(PluginOctokit);
};

public analyzeGit = async () => {
let isPRSuccess = true;
if (this.isDebugMode) console.log("baseBranchName: ", this.baseBranchName);

const commitRaws = getCommitRaws(this.gitLog);
if (this.isDebugMode) console.log("commitRaws: ", commitRaws);

const commitDict = buildCommitDict(commitRaws);
if (this.isDebugMode) console.log("commitDict: ", commitDict);

const pullRequests = await this.octokit
.getPullRequests()
.catch((err) => {
console.error(err);
isPRSuccess = false;
return [];
})
.then((pullRequests) => {
console.log("success, pr = ", pullRequests);
return pullRequests;
});
if (this.isDebugMode) console.log("pullRequests: ", pullRequests);

const stemDict = buildStemDict(commitDict, this.baseBranchName);
if (this.isDebugMode) console.log("stemDict: ", stemDict);
const csmDict = buildCSMDict(commitDict, stemDict, this.baseBranchName, pullRequests);
if (this.isDebugMode) console.log("csmDict: ", csmDict);
const latestCommitSummary = await getLatestCommitSummary(stemDict, this.baseBranchName);
if (this.isDebugMode) console.log("latestCommitSummary: ", latestCommitSummary);

const currentUserCommitSummary = await getCurrentUserCommitSummary(stemDict, this.baseBranchName, this.octokit);
if (this.isDebugMode) console.log("currentUserCommitSummary: ", currentUserCommitSummary);

return {
isPRSuccess,
csmDict,
};
};

public updateArgs = (args: AnalysisEngineArgs) => {
if (container.isRegistered("OctokitOptions")) container.clearInstances();
this.insertArgs(args);
};
}

export default AnalysisEngine;
export type { AnalysisEngineArgs } from "./engine";
export { AnalysisEngine } from "./engine";
21 changes: 20 additions & 1 deletion packages/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"visual analytics"
],
"activationEvents": [
"*"
"*",
"onView:githruSidebar"
],
"main": "./dist/extension.js",
"contributes": {
Expand Down Expand Up @@ -68,6 +69,24 @@
"description": "Insert your primary color."
}
}
},
"viewsContainers": {
"activitybar": [
{
"id": "githruSidebarView",
"title": "Githru Sidebar",
"icon": "images/logo.png"
}
]
},
"views": {
"githruSidebarView": [
{
"type": "webview",
"id": "githruSidebar",
"name": "Githru Sidebar"
}
]
}
},
"scripts": {
Expand Down
8 changes: 7 additions & 1 deletion packages/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { COMMAND_LAUNCH, COMMAND_LOGIN_WITH_GITHUB, COMMAND_RESET_GITHUB_AUTH }
import { Credentials } from "./credentials";
import { GithubTokenUndefinedError, WorkspacePathUndefinedError } from "./errors/ExtensionError";
import { deleteGithubToken, getGithubToken, setGithubToken } from "./setting-repository";
import { SidebarProvider } from "./sidebar";
import { mapClusterNodesFrom } from "./utils/csm.mapper";
import {
findGit,
Expand All @@ -25,6 +26,10 @@ function normalizeFsPath(fsPath: string) {
}

export async function activate(context: vscode.ExtensionContext) {
const provider = new SidebarProvider(context.extensionUri);

context.subscriptions.push(vscode.window.registerWebviewViewProvider("githruSidebar", provider));

const { subscriptions, extensionPath, secrets } = context;
const credentials = new Credentials();
let currentPanel: vscode.WebviewPanel | undefined = undefined;
Expand Down Expand Up @@ -82,7 +87,8 @@ export async function activate(context: vscode.ExtensionContext) {
const { owner, repo: initialRepo } = getRepo(gitConfig);
webLoader.setGlobalOwnerAndRepo(owner, initialRepo);
const repo = initialRepo[0];
const engine = new AnalysisEngine({
const engine = AnalysisEngine.getInstance();
engine.initialize({
isDebugMode: true,
gitLog,
owner,
Expand Down
66 changes: 66 additions & 0 deletions packages/vscode/src/sidebar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { AnalysisEngine } from "@githru-vscode-ext/analysis-engine";
import type * as vscode from "vscode";

export class SidebarProvider implements vscode.WebviewViewProvider {
constructor(private readonly _extensionUri: vscode.Uri) {}

resolveWebviewView(webviewView: vscode.WebviewView) {
webviewView.webview.options = {
enableScripts: true,
};

webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);

webviewView.webview.onDidReceiveMessage(async (data) => {
const result = await this.callApi(data.apiNumber);
webviewView.webview.postMessage({ type: "apiResult", result });
});
}

private async callApi(apiNumber: number): Promise<string> {
const engine = AnalysisEngine.getInstance();
try {
const summary = await engine.geminiCommitSummary();
console.log("Commit summary:", summary);
} catch (error) {
console.error("Error getting commit summary:", error);
}
return `API ${apiNumber} 호출 결과`;
}

private _getHtmlForWebview(webview: vscode.Webview) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API Caller</title>
</head>
<body>
<button onclick="callApi(1)">Call AI Analyze 1</button>
<button onclick="callApi(2)">Call AI Analyze 2</button>
<button onclick="callApi(3)">Call AI Analyze 3</button>
<div id="result"></div>
<script>
const vscode = acquireVsCodeApi();
function callApi(apiNumber) {
vscode.postMessage({ type: 'apiCall', apiNumber });
}
window.addEventListener('message', event => {
const message = event.data;
switch (message.type) {
case 'apiResult':
document.getElementById('result').innerText = message.result;
break;
}
});
</script>
</body>
</html>
`;
}
}

0 comments on commit d44b5aa

Please sign in to comment.