Skip to content

Commit 286a431

Browse files
author
winjo
committed
feat: 增加分支和标签接口
1 parent 294edd6 commit 286a431

31 files changed

Lines changed: 1569 additions & 451 deletions

packages/alex/src/integration/startup/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const platformConfig = {
5858
platform: 'gitlab',
5959
owner: 'kaitian',
6060
name: 'ide-framework',
61-
origin: 'https://code.alipay.com',
61+
origin: 'http://gitlab.alibaba-inc.com',
6262
},
6363
};
6464

@@ -74,8 +74,8 @@ delete query.platform;
7474
delete query.project;
7575
Object.assign(config, query);
7676

77-
if (platform === 'github') {
78-
layoutConfig[SlotLocation.left].modules.push('github');
77+
if (platform === 'github' || platform === 'gitlab') {
78+
layoutConfig[SlotLocation.left].modules.push(platform);
7979
}
8080

8181
ReactDOM.render(

packages/code-api/src/antcode/antcode.service.ts

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Injectable, Autowired } from '@ali/common-di';
2-
import { localize, IReporterService, formatLocalize } from '@ali/ide-core-common';
2+
import { localize, IReporterService } from '@ali/ide-core-common';
33
import { REPORT_NAME } from '@alipay/alex-core';
4-
import { CodeModelService, ICodeAPIService, EntryParam } from '@alipay/alex-code-service';
4+
import { CodeModelService, ICodeAPIService } from '@alipay/alex-code-service';
5+
import type { EntryParam, RefsParam } from '@alipay/alex-code-service';
56
import { IMessageService } from '@ali/ide-overlay';
6-
import { request, RequestOptions } from '@alipay/alex-shared';
7-
import { createUrl } from '../common/utils';
7+
import { request, RequestOptions, isResponseError } from '@alipay/alex-shared';
88
import { API } from './types';
99

1010
@Injectable()
@@ -28,37 +28,39 @@ export class AntCodeService implements ICodeAPIService {
2828
}
2929

3030
private async request<T>(path: string, options?: RequestOptions): Promise<T> {
31-
const url = createUrl(this.codeModel.endpoint, path);
32-
3331
try {
34-
const data = await request(url, {
32+
const data = await request(path, {
33+
baseURL: this.codeModel.endpoint,
3534
credentials: 'include',
3635
responseType: 'json',
3736
...options,
3837
});
3938
return data;
40-
} catch (err: any) {
41-
const status = err.response?.status;
42-
this.reporter.point(REPORT_NAME.CODE_SERVICE_REQUEST_ERROR, err.message, {
43-
url,
44-
status,
45-
platform: this.codeModel.platform,
46-
});
47-
if (status === 401) {
48-
const goto = localize('api.login.goto');
49-
this.messageService
50-
.error(localize('api.response.no-login-antcode'), [goto])
51-
.then((value) => {
52-
if (value === goto) {
53-
window.open(this.codeModel.origin);
54-
}
55-
});
56-
} else if (status === 403) {
57-
this.messageService.error(localize('api.response.project-no-access'));
58-
} else if (status === 404) {
59-
this.messageService.error(
60-
formatLocalize('api.response.project-not-found', this.codeModel.project)
61-
);
39+
} catch (err: unknown) {
40+
if (isResponseError(err)) {
41+
const { status } = err.response;
42+
this.reporter.point(REPORT_NAME.CODE_SERVICE_REQUEST_ERROR, err.message, {
43+
path,
44+
status,
45+
platform: this.codeModel.platform,
46+
});
47+
if (status === 401) {
48+
const goto = localize('api.login.goto');
49+
this.messageService
50+
.error(localize('api.response.no-login-antcode'), [goto])
51+
.then((value) => {
52+
if (value === goto) {
53+
window.open(this.codeModel.origin);
54+
}
55+
});
56+
} else if (status === 403) {
57+
this.messageService.error(localize('api.response.project-no-access'));
58+
} else if (status === 404) {
59+
// TODO 更精细化的错误提示
60+
this.messageService.error(localize('error.resource-not-found'));
61+
} else {
62+
this.messageService.error(`${status} - ${localize('error.request')}`);
63+
}
6264
} else {
6365
this.messageService.error(localize('api.response.unknown-error'));
6466
}
@@ -75,7 +77,7 @@ export class AntCodeService implements ICodeAPIService {
7577
}
7678

7779
async getTree(path: string) {
78-
await this.codeModel.isInitialized;
80+
await this.codeModel.headInitialized;
7981
return this.request<API.ResponseGetTree>(
8082
`/api/v3/projects/${this.codeModel.projectId}/repository/tree`,
8183
{
@@ -88,7 +90,7 @@ export class AntCodeService implements ICodeAPIService {
8890
}
8991

9092
async getBlob(entry: EntryParam) {
91-
await this.codeModel.isInitialized;
93+
await this.codeModel.headInitialized;
9294
const buf = await this.request<ArrayBuffer>(
9395
`/api/v3/projects/${this.codeModel.projectId}/repository/blobs/${this.codeModel.HEAD}`,
9496
{
@@ -102,7 +104,7 @@ export class AntCodeService implements ICodeAPIService {
102104
}
103105

104106
async getEntryInfo(entry: EntryParam) {
105-
await this.codeModel.isInitialized;
107+
await this.codeModel.headInitialized;
106108
const data = await this.request<API.ResponseGetEntry>(
107109
`/api/v3/projects/${this.codeModel.projectId}/repository/tree_entry`,
108110
{
@@ -117,4 +119,19 @@ export class AntCodeService implements ICodeAPIService {
117119
fileType: data.render === 'download' ? 'binary' : data.render,
118120
} as const;
119121
}
122+
123+
async getRefs(): Promise<RefsParam> {
124+
const [branches, tags] = await Promise.all([
125+
this.request<API.ResponseGetRefs>(
126+
`/api/v3/projects/${this.codeModel.projectId}/repository/branches`
127+
),
128+
this.request<API.ResponseGetRefs>(
129+
`/api/v3/projects/${this.codeModel.projectId}/repository/tags`
130+
),
131+
]);
132+
return {
133+
branches,
134+
tags,
135+
};
136+
}
120137
}

packages/code-api/src/antcode/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,11 @@ export namespace API {
1717
size: number;
1818
render: 'download' | 'image' | 'text';
1919
}
20+
21+
export type ResponseGetRefs = Array<{
22+
name: string;
23+
commit: {
24+
id: string;
25+
};
26+
}>;
2027
}
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
export const CODE_SERVICE_CONTAINER_ID = 'code-service';
1+
export const GITHUB_CONTAINER_ID = 'github';
2+
3+
export const GITLAB_CONTAINER_ID = 'gitlab';
4+
5+
export const GITHUB_OAUTH_TOKEN = 'github-oauth-token';
6+
7+
export const GITLAB_PRIVATE_TOKEN = 'gitlab-private-token';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './constant';
2+
export * from './service';
3+
export * from './utils';
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Injectable, Autowired } from '@ali/common-di';
2+
import {
3+
StorageProvider,
4+
IStorage,
5+
STORAGE_SCHEMA,
6+
URI,
7+
Deferred,
8+
CommandService,
9+
} from '@ali/ide-core-common';
10+
import { GITHUB_OAUTH_TOKEN, GITLAB_PRIVATE_TOKEN } from './constant';
11+
12+
/**
13+
* 使用 localStorage 存储 token 够用了
14+
* TODO: 需要简单加密下 token
15+
*/
16+
17+
@Injectable()
18+
export class HelperService {
19+
@Autowired(StorageProvider)
20+
private provideStorage: StorageProvider;
21+
22+
@Autowired(CommandService)
23+
private readonly commandService: CommandService;
24+
25+
private _storageDeferred: Deferred<IStorage>;
26+
27+
async getStorage() {
28+
if (!this._storageDeferred) {
29+
this._storageDeferred = new Deferred();
30+
const storage = await this.provideStorage(
31+
new URI('code-api').withScheme(STORAGE_SCHEMA.SCOPE)
32+
);
33+
this._storageDeferred.resolve(storage);
34+
}
35+
return this._storageDeferred.promise;
36+
}
37+
38+
get(key: string) {
39+
return localStorage.getItem(key);
40+
}
41+
42+
set(key: string, value: string) {
43+
localStorage.setItem(key, value);
44+
}
45+
46+
delete(key: string) {
47+
localStorage.removeItem(key);
48+
}
49+
50+
get GITHUB_TOKEN() {
51+
return this.get(GITHUB_OAUTH_TOKEN);
52+
}
53+
54+
set GITHUB_TOKEN(value: string | null) {
55+
if (value === null) {
56+
this.delete(GITHUB_OAUTH_TOKEN);
57+
} else {
58+
this.set(GITHUB_OAUTH_TOKEN, value);
59+
}
60+
}
61+
62+
get GITLAB_TOKEN() {
63+
return this.get(GITLAB_PRIVATE_TOKEN);
64+
}
65+
66+
set GITLAB_TOKEN(value: string | null) {
67+
if (value === null) {
68+
this.delete(GITLAB_PRIVATE_TOKEN);
69+
} else {
70+
this.set(GITLAB_PRIVATE_TOKEN, value);
71+
}
72+
}
73+
74+
revealView(id: string) {
75+
this.commandService.executeCommand(`workbench.view.${id}`);
76+
}
77+
}
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1-
export const stripLeadingSlash = (path: string) => (path.charAt(0) === '/' ? path.substr(1) : path);
1+
export class RetryError extends Error {}
22

3-
export const stripTrailingSlash = (path: string) =>
4-
path.charAt(path.length - 1) === '/' ? path.slice(0, -1) : path;
3+
export const retry = (target: any, key: string, descriptor: any) => {
4+
const fn = descriptor.value;
5+
descriptor.value = async function (...args: any[]) {
6+
try {
7+
return await fn.call(this, ...args);
8+
} catch (err) {
9+
if (err instanceof RetryError) {
10+
return fn.call(this, ...args);
11+
}
12+
throw err;
13+
}
14+
};
15+
};
516

6-
export const createUrl = (origin: string, path: string) =>
7-
`${stripTrailingSlash(origin)}/${stripLeadingSlash(path)}`;
17+
/**
18+
* 解析代码托管平台 url,获取相关数据信息
19+
*/
20+
export const parseCodeHostURL = (href: string) => {
21+
if (!href) return null;
22+
};
Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,32 @@
1-
import { Injectable } from '@ali/common-di';
2-
import { ComponentContribution, ComponentRegistry, getIcon } from '@ali/ide-core-browser';
3-
import { Domain } from '@ali/ide-core-common';
4-
import { CODE_SERVICE_CONTAINER_ID } from '../common/constant';
1+
import { Autowired } from '@ali/common-di';
2+
import {
3+
ComponentContribution,
4+
ComponentRegistry,
5+
getIcon,
6+
CommandRegistry,
7+
SlotLocation,
8+
ClientAppContribution,
9+
} from '@ali/ide-core-browser';
10+
import { CommandContribution, Domain } from '@ali/ide-core-common';
11+
import { ICodeAPIService } from '@alipay/alex-code-service';
12+
import { IMainLayoutService } from '@ali/ide-main-layout';
13+
import { GITHUB_CONTAINER_ID } from '../common/constant';
514
import { GitHubView } from './github.view';
15+
import { GitHubService } from './github.service';
16+
import { HelperService } from '../common/service';
17+
18+
@Domain(ComponentContribution, CommandContribution, ClientAppContribution)
19+
export class GithubContribution
20+
implements ComponentContribution, CommandContribution, ClientAppContribution {
21+
@Autowired(ICodeAPIService)
22+
codeAPI: GitHubService;
23+
24+
@Autowired()
25+
helper: HelperService;
26+
27+
@Autowired(IMainLayoutService)
28+
layoutService: IMainLayoutService;
629

7-
@Domain(ComponentContribution)
8-
export class GithubContribution implements ComponentContribution {
930
registerComponent(registry: ComponentRegistry) {
1031
registry.register(
1132
'github',
@@ -15,10 +36,30 @@ export class GithubContribution implements ComponentContribution {
1536
name: 'GitHub',
1637
},
1738
{
18-
containerId: CODE_SERVICE_CONTAINER_ID,
39+
containerId: GITHUB_CONTAINER_ID,
1940
iconClass: getIcon('github-fill'),
2041
title: 'GitHub',
2142
}
2243
);
2344
}
45+
46+
registerCommands(registry: CommandRegistry) {
47+
registry.afterExecuteCommand(`workbench.view.${GITHUB_CONTAINER_ID}`, () => {
48+
this.codeAPI.getRateLimit();
49+
});
50+
}
51+
52+
onDidStart() {
53+
if (this.codeAPI.shouldShowView) {
54+
this.helper.revealView(GITHUB_CONTAINER_ID);
55+
}
56+
57+
this.layoutService
58+
.getTabbarService(SlotLocation.left)
59+
.onCurrentChange(({ currentId, previousId }) => {
60+
if (previousId !== currentId && currentId === GITHUB_CONTAINER_ID) {
61+
this.codeAPI.refresh();
62+
}
63+
});
64+
}
2465
}

packages/code-api/src/github/github.module.less

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,38 @@
11
.container {
22
padding: 8px;
3+
padding-top: 0;
34
}
45

56
.title {
6-
font-size: 14px;
7+
font-size: 15px;
78
font-weight: 500;
89
}
910

1011
.rateList {
1112
padding-left: 0;
13+
margin-bottom: 0;;
1214

1315
.rateData {
1416
font-weight: 600;
1517
}
1618
}
1719

20+
.resource {
21+
margin-bottom: 4px;
22+
}
23+
24+
.resourceTitle {
25+
color: var(--descriptionForeground);
26+
padding: 4px 0;
27+
}
28+
29+
.rateItem {
30+
display: flex;
31+
> span {
32+
width: 100px;
33+
}
34+
}
35+
1836
.authTip {
1937
color: var(--descriptionForeground)
2038
}

0 commit comments

Comments
 (0)