Skip to content

Commit fb5929d

Browse files
committed
feat: create mr.
1 parent 79bb94e commit fb5929d

File tree

6 files changed

+253
-44
lines changed

6 files changed

+253
-44
lines changed

package.json

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@
3737
"title": "Logout coding.net",
3838
"category": "Coding plugin"
3939
},
40+
{
41+
"command": "codingPlugin.newMrDesc",
42+
"title": "New Merge Request",
43+
"category": "Coding plugin",
44+
"icon": "$(add)"
45+
},
46+
{
47+
"command": "codingPlugin.createMr",
48+
"title": "Create Merge Request from current document",
49+
"category": "Coding plugin"
50+
},
4051
{
4152
"command": "codingPlugin.refresh",
4253
"title": "Refresh",
@@ -51,6 +62,11 @@
5162
],
5263
"menus": {
5364
"view/title": [
65+
{
66+
"command": "codingPlugin.newMrDesc",
67+
"when": "view == mrTreeView",
68+
"group": "navigation"
69+
},
5470
{
5571
"command": "codingPlugin.refresh",
5672
"when": "view == mrTreeView",
@@ -133,7 +149,7 @@
133149
"babel-plugin-styled-components": "^1.12.0",
134150
"css-loader": "^5.0.0",
135151
"eslint": "^7.1.0",
136-
"husky": "^5.0.4",
152+
"husky": "^4.3.0",
137153
"lint-staged": "^10.5.2",
138154
"npm-run-all": "^4.1.5",
139155
"prettier": "^2.2.1",
@@ -149,7 +165,7 @@
149165
}
150166
},
151167
"lint-staged": {
152-
"**/*.{js,json,css,scss,md}": [
168+
"**/*.{js,json,css,scss,md,ts,tsx}": [
153169
"prettier --write"
154170
]
155171
},

src/codingServer.ts

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import {
99
IRepoListResponse,
1010
IMRDiffResponse,
1111
IMRDetailResponse,
12+
ICreateMRBody,
13+
ICreateMRResp,
14+
IBranchListResp,
1215
} from 'src/typings/respResult';
1316
import { PromiseAdapter, promiseFromEvent, parseQuery, parseCloneUrl } from 'src/common/utils';
1417
import { GitService } from 'src/common/gitService';
@@ -231,9 +234,8 @@ export class CodingServer {
231234

232235
public static async getRepoParams() {
233236
const urls = await GitService.getRemoteURLs();
234-
// TODO: multiple working repos
235-
const url = urls?.[0];
236-
return parseCloneUrl(url || ``);
237+
const result = urls?.map((i) => parseCloneUrl(i || ``));
238+
return result?.[0];
237239
}
238240

239241
public async getMRList(repo?: string, status?: string): Promise<CodingResponse> {
@@ -329,7 +331,7 @@ export class CodingServer {
329331
throw new Error(`team not exist`);
330332
}
331333

332-
const diff: IMRDetailResponse = await got
334+
const resp: IMRDetailResponse = await got
333335
.get(
334336
`https://${repoInfo.team}.coding.net/api/user/${this._session?.user?.team}/project/${repoInfo.project}/depot/${repoInfo.repo}/git/merge/${iid}/detail`,
335337
{
@@ -340,11 +342,11 @@ export class CodingServer {
340342
)
341343
.json();
342344

343-
if (diff.code) {
344-
return Promise.reject(diff);
345+
if (resp.code) {
346+
return Promise.reject(resp);
345347
}
346348

347-
return diff;
349+
return resp;
348350
} catch (err) {
349351
return Promise.reject(err);
350352
}
@@ -358,18 +360,68 @@ export class CodingServer {
358360
}
359361

360362
const url = `https://${repoInfo.team}.coding.net/p/${repoInfo.project}/d/${repoInfo.repo}/git/raw/${path}`;
361-
const { body } = await got.get(
362-
url,
363+
const { body } = await got.get(url, {
364+
searchParams: {
365+
access_token: this._session?.accessToken,
366+
},
367+
});
368+
369+
return body;
370+
} catch (err) {
371+
return ``;
372+
}
373+
}
374+
375+
public async createMR(data: ICreateMRBody) {
376+
try {
377+
const repoInfo = this._context.workspaceState.get(`repoInfo`) as IRepoInfo;
378+
if (!repoInfo?.team) {
379+
throw new Error(`team not exist`);
380+
}
381+
382+
const resp: ICreateMRResp = await got.post(
383+
`https://${repoInfo.team}.coding.net/api/user/${this._session?.user?.team}/project/${repoInfo.project}/depot/${repoInfo.repo}/git/merge`,
363384
{
385+
resolveBodyOnly: true,
386+
responseType: `json`,
364387
searchParams: {
365388
access_token: this._session?.accessToken,
366389
},
390+
form: data,
367391
},
368392
);
393+
if (resp.code) {
394+
return Promise.reject(resp);
395+
}
396+
return resp;
397+
} catch (err) {
398+
return Promise.reject(err);
399+
}
400+
}
369401

370-
return body;
402+
public async getBranchList() {
403+
try {
404+
const repoInfo = this._context.workspaceState.get(`repoInfo`) as IRepoInfo;
405+
if (!repoInfo?.team) {
406+
throw new Error(`team not exist`);
407+
}
408+
409+
const resp: IBranchListResp = await got
410+
.get(
411+
`https://${repoInfo.team}.coding.net/api/user/${this._session?.user?.team}/project/${repoInfo.project}/depot/${repoInfo.repo}/git/list_branches`,
412+
{
413+
searchParams: {
414+
access_token: this._session?.accessToken,
415+
},
416+
},
417+
)
418+
.json();
419+
if (resp.code) {
420+
return Promise.reject(resp);
421+
}
422+
return resp;
371423
} catch (err) {
372-
return ``;
424+
return Promise.reject(err);
373425
}
374426
}
375427

src/common/gitService.ts

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,49 @@
11
import * as vscode from 'vscode';
22
import * as cp from 'child_process';
3-
import { promisify } from 'util';
43

5-
import { GitExtension } from 'src/typings/git';
6-
7-
const exec = promisify(cp.exec);
4+
import { Git, GitExtension } from 'src/typings/git';
85

96
export class GitService {
7+
static git: Git;
8+
9+
static async init() {
10+
const extension = vscode.extensions.getExtension(
11+
`vscode.git`,
12+
) as vscode.Extension<GitExtension>;
13+
if (extension !== undefined) {
14+
const gitExtension = extension.isActive ? extension.exports : await extension.activate();
15+
const model = gitExtension.getAPI(1);
16+
GitService.git = model.git;
17+
}
18+
}
19+
1020
static async getRemoteURLs(): Promise<string[] | null> {
1121
try {
12-
const extension = vscode.extensions.getExtension(
13-
`vscode.git`,
14-
) as vscode.Extension<GitExtension>;
15-
if (extension !== undefined) {
16-
const gitExtension = extension.isActive ? extension.exports : await extension.activate();
17-
const model = gitExtension.getAPI(1);
18-
19-
if (vscode.workspace.workspaceFolders?.length) {
20-
const tasks = vscode.workspace.workspaceFolders.map((f) =>
21-
exec(`${model.git.path} config --get remote.origin.url`, {
22-
cwd: f.uri.path,
23-
}),
24-
);
25-
const result = await Promise.all(tasks);
26-
const urls = result.map(({ stdout, stderr }) => {
27-
return stdout.trim();
28-
});
29-
30-
return urls;
31-
}
22+
if (!GitService.git || !vscode.workspace.workspaceFolders?.length) {
23+
return null;
3224
}
25+
26+
const tasks = vscode.workspace.workspaceFolders.map(
27+
(f) =>
28+
new Promise((resolve) => {
29+
cp.exec(
30+
`${GitService.git.path} -C "${f.uri.path}" config --get remote.origin.url`,
31+
{
32+
cwd: f.uri.path,
33+
},
34+
(err, stdout, stderr) => {
35+
resolve({ stdout, stderr });
36+
},
37+
);
38+
}),
39+
);
40+
41+
const result = await Promise.all(tasks);
42+
const urls = result.map((o) => {
43+
return (o as { stdout: string; stderr: string }).stdout?.trim();
44+
});
45+
46+
return urls;
3347
} catch (err) {
3448
console.error(err);
3549
}

src/extension.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import { Panel } from 'src/panel';
66
import { IFileNode, MRTreeDataProvider } from 'src/tree/mrTree';
77
import { ReleaseTreeDataProvider } from 'src/tree/releaseTree';
88
import { IRepoInfo, IMRWebViewDetail } from 'src/typings/commonTypes';
9+
import { GitService } from 'src/common/gitService';
910

1011
export async function activate(context: vscode.ExtensionContext) {
12+
await GitService.init();
1113
const repoInfo = await CodingServer.getRepoParams();
1214

1315
if (!repoInfo?.team) {
@@ -32,7 +34,7 @@ export async function activate(context: vscode.ExtensionContext) {
3234

3335
const mrDataProvider = new MRTreeDataProvider(context, codingSrv);
3436
const releaseDataProvider = new ReleaseTreeDataProvider(context);
35-
vscode.window.createTreeView(`mrTreeView`, {
37+
const mrTree = vscode.window.createTreeView(`mrTreeView`, {
3638
treeDataProvider: mrDataProvider,
3739
showCollapseAll: true,
3840
});
@@ -79,6 +81,58 @@ export async function activate(context: vscode.ExtensionContext) {
7981
mrDataProvider.refresh();
8082
}),
8183
);
84+
context.subscriptions.push(
85+
vscode.commands.registerCommand('codingPlugin.newMrDesc', async () => {
86+
const doc = await vscode.workspace.openTextDocument({
87+
language: `markdown`,
88+
});
89+
await vscode.window.showTextDocument(doc);
90+
}),
91+
);
92+
context.subscriptions.push(
93+
vscode.commands.registerCommand('codingPlugin.createMr', async () => {
94+
const editor = vscode.window.activeTextEditor;
95+
if (!editor) {
96+
return;
97+
}
98+
99+
const content = editor.document.getText();
100+
if (!content) {
101+
return;
102+
}
103+
104+
const { data } = await codingSrv.getBranchList();
105+
const list = data.map((i) => ({
106+
label: i.name,
107+
description: ``,
108+
}));
109+
const src = await vscode.window.showQuickPick(list, {
110+
placeHolder: `Please choose source branch`,
111+
});
112+
if (!src) return;
113+
const des = await vscode.window.showQuickPick(list, {
114+
placeHolder: `Please choose target branch`,
115+
});
116+
if (!des) return;
117+
const title = await vscode.window.showInputBox({ placeHolder: `Please input title` });
118+
if (!title) {
119+
return;
120+
}
121+
122+
try {
123+
const newMr = await codingSrv.createMR({
124+
content,
125+
title,
126+
srcBranch: src.label,
127+
desBranch: des.label,
128+
});
129+
vscode.window.showInformationMessage(
130+
`Merge request ${newMr.data.merge_request.title} was created successfully.`,
131+
);
132+
mrDataProvider.refresh();
133+
} catch (err) {}
134+
}),
135+
);
82136
context.subscriptions.push(
83137
vscode.commands.registerCommand('codingPlugin.switchRepo', async () => {
84138
try {
@@ -131,5 +185,4 @@ export async function activate(context: vscode.ExtensionContext) {
131185
}
132186
}
133187

134-
export function deactivate() {
135-
}
188+
export function deactivate() {}

src/typings/respResult.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,34 @@ export interface IMRDetailResponse extends CodingResponse {
127127
can_merge: boolean;
128128
};
129129
}
130+
131+
export interface ICreateMRBody {
132+
srcBranch: string;
133+
desBranch: string;
134+
title: string;
135+
content: string;
136+
reviewers?: string;
137+
labels?: string;
138+
watchers?: string;
139+
}
140+
141+
export interface ICreateMRResp extends CodingResponse {
142+
can_edit: boolean;
143+
can_edit_src_branch: boolean;
144+
merge_request: IMRDetail;
145+
}
146+
147+
export interface IBranchItem {
148+
commitTime: number;
149+
deny_force_push: boolean;
150+
force_squash: boolean;
151+
is_default_branch: boolean;
152+
is_protected: boolean;
153+
name: string;
154+
sha: string;
155+
status_check: boolean;
156+
}
157+
158+
export interface IBranchListResp extends CodingResponse {
159+
data: IBranchItem[];
160+
}

0 commit comments

Comments
 (0)