Skip to content

Commit abfc2b9

Browse files
authored
feat(sync): 优化GitHub同步逻辑并增强错误处理 (#16)
* ci: 重构 GitHub Actions 工作流 - 新增 pnpm-cache.yml 工作流,用于设置 pnpm 缓存 - 更新 CI、nightly、pr-check 等工作流,使用新的 pnpm 缓存设置 - 优化工作流中的步骤,减少重复代码 - 更新 release-please 配置,移除不必要的设置 - 新增 .release-please-config.json 文件,详细配置 release-please * ci: 重构 GitHub Actions 工作流 - 新增 build-test.yml、code-quality.yml 和 setup.yml 工作流文件 - 重构 ci.yml、nightly.yml 和 pr-check.yml,使用新的工作流文件 - 移除 env.yml 和 pnpm-cache.yml 工作流文件 - 更新工作流调用,使用新的输入参数和输出值 * ci: 重构 GitHub Actions 工作流 - 移除各工作流中的重复 setup 步骤 - 新增单独的 setup 工作流,统一处理环境配置 - 更新工作流之间的依赖关系,确保按顺序执行 - 为发布到 Marketplace 添加新的工作流 * ci: 重构 GitHub Actions 工作流 - 在 build-test.yml 和 code-quality.yml 中添加 setup 作业 - 使用 workflow_call 方式调用 setup.yml - 优化工作流结构,提高可维护性 * ci: 重构 GitHub Actions 工作流 - 新增 Setup Node.js and pnpm 复合操作,用于统一配置 Node.js 和 pnpm - 更新所有工作流文件,使用新的 Setup Node.js and pnpm 复合操作 - 移除单独的 setup 任务,直接在每个工作流中配置环境 - 优化工作流结构,提高可维护性和可读性 * feat(sync): 优化GitHub同步逻辑并增强错误处理 - 将认证头抽离为统一方法以减少重复代码 - 添加对Gist创建响应信息的详细日志输出 - 提取获取文件SHA逻辑为独立方法,提升可读性和复用性 - 增强GitHub API错误处理的健壮性 - 在.vscode配置中添加Node.js路径以支持特定开发环境 - 修复esbuild任务匹配器为tsc-watch以支持TS错误识别 - 添加packageManager字段以确保pnpm一致性 * fix: 修复 pnpm 版本并优化 Gist 导出日志 * fix: 移除 pnpm 版本设置 移除了 setup-node-pnpm action 中的 pnpm 版本设置,以简化配置并使用默认版本。
1 parent e4e97f1 commit abfc2b9

File tree

6 files changed

+113
-96
lines changed

6 files changed

+113
-96
lines changed

.github/actions/setup-node-pnpm/action.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ inputs:
99
pnpm_version:
1010
description: 'pnpm version'
1111
required: false
12-
default: '9.15.0'
12+
default: '9.4.0'
1313

1414
outputs:
1515
store_path:
@@ -26,8 +26,6 @@ runs:
2626

2727
- name: Setup pnpm
2828
uses: pnpm/action-setup@v4
29-
with:
30-
version: ${{ inputs.pnpm_version }}
3129

3230
- name: Get pnpm store directory
3331
id: get-store-path

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.vscode
12
out
23
dist
34
node_modules

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@
1010
},
1111
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
1212
"typescript.tsc.autoDetect": "off",
13+
"terminal.integrated.env.linux": {
14+
"PATH": "/config/.asdf/installs/nodejs/22.13.0/bin:${env:PATH}"
15+
},
1316
"github-actions.remote-name": "upstream"
1417
}

.vscode/tasks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"type": "npm",
2222
"script": "watch:esbuild",
2323
"group": "build",
24-
"problemMatcher": "$esbuild-watch",
24+
"problemMatcher": "$tsc-watch",
2525
"isBackground": true,
2626
"label": "npm: watch:esbuild",
2727
"presentation": {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,5 +167,6 @@
167167
"npm-run-all": "^4.1.5",
168168
"prettier": "3.6.2",
169169
"typescript": "^5.8.3"
170-
}
170+
},
171+
"packageManager": "[email protected]+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a"
171172
}

src/githubService.ts

Lines changed: 105 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import * as vscode from 'vscode';
22
import { API_BASE_URL } from './constants';
33

4+
// ===== 常量定义 =====
5+
const GITHUB_ACCEPT_HEADER = 'application/vnd.github.v3+json';
6+
const CONTENT_TYPE_JSON = 'application/json';
7+
const DEFAULT_GIST_DESCRIPTION = 'VSCode 配置同步';
8+
const DEFAULT_COMMIT_MESSAGE = '自动同步配置';
9+
10+
// ===== 接口定义 =====
411
interface GistResponse {
512
id: string;
613
html_url: string;
@@ -20,6 +27,10 @@ interface GistBody {
2027
public?: boolean;
2128
}
2229

30+
interface FileDataResponse {
31+
sha?: string;
32+
}
33+
2334
export class GitHubService {
2435
private readonly baseUrl = API_BASE_URL;
2536

@@ -33,129 +44,132 @@ export class GitHubService {
3344
const method = gistId ? 'PATCH' : 'POST';
3445

3546
const body: GistBody = {
36-
description: `VSCode 配置同步 - ${new Date().toLocaleString()}`,
47+
description: `${DEFAULT_GIST_DESCRIPTION} - ${new Date().toLocaleString()}`,
3748
files: {
3849
[fileName]: {
39-
content: content,
50+
content,
4051
},
4152
},
53+
public: false,
4254
};
4355

44-
if (!gistId) {
45-
body.public = false;
46-
}
56+
const headers = this.getAuthHeaders(token, CONTENT_TYPE_JSON);
4757

48-
const response = await fetch(url, {
49-
method: method,
50-
headers: {
51-
Authorization: `token ${token}`,
52-
Accept: 'application/vnd.github.v3+json',
53-
'Content-Type': 'application/json',
54-
},
55-
body: JSON.stringify(body),
56-
});
58+
try {
59+
const response = await fetch(url, {
60+
method,
61+
headers,
62+
body: JSON.stringify(body),
63+
});
5764

58-
if (!response.ok) {
59-
const error = await response.text();
60-
throw new Error(`GitHub API 错误: ${response.status} - ${error}`);
61-
}
65+
// 获取响应头信息
66+
const responseHeaders: Record<string, string> = {};
67+
response.headers.forEach((value, key) => {
68+
responseHeaders[key] = value;
69+
});
70+
71+
await this.handleGitHubError(response);
6272

63-
const result = (await response.json()) as GistResponse;
73+
const result = (await response.json()) as GistResponse;
6474

65-
// 如果是新创建的Gist,保存ID
66-
if (!gistId && result.id) {
67-
const config = vscode.workspace.getConfiguration('vscode-syncing');
68-
await config.update('gistId', result.id, vscode.ConfigurationTarget.Global);
69-
vscode.window.showInformationMessage(`新的Gist已创建,ID: ${result.id}`);
75+
if (!gistId && result.id) {
76+
await this.saveGistIdToConfig(result.id);
77+
}
78+
79+
return result;
80+
} catch (error) {
81+
throw error;
7082
}
71-
return result;
7283
}
7384

85+
// 更新仓库文件
7486
async updateRepository(
7587
token: string,
7688
repoName: string,
7789
branch: string,
7890
fileName: string,
7991
content: string,
80-
commitMessage: string,
92+
commitMessage: string = DEFAULT_COMMIT_MESSAGE,
8193
): Promise<void> {
82-
try {
83-
// 获取文件的当前SHA(如果存在)
84-
const fileUrl = `${this.baseUrl}/repos/${repoName}/contents/${fileName}?ref=${branch}`;
85-
let sha: string | undefined;
86-
87-
try {
88-
const fileResponse = await fetch(fileUrl, {
89-
headers: {
90-
Authorization: `token ${token}`,
91-
Accept: 'application/vnd.github.v3+json',
92-
},
93-
});
94-
95-
if (fileResponse.ok) {
96-
const fileData = await fileResponse.json();
97-
if (
98-
typeof fileData === 'object' &&
99-
fileData !== null &&
100-
'sha' in fileData &&
101-
typeof fileData.sha === 'string'
102-
) {
103-
sha = fileData.sha;
104-
}
105-
}
106-
} catch (error) {
107-
// 文件不存在,这是正常的
108-
}
109-
110-
// 更新或创建文件
111-
interface RepoUpdateBody {
112-
message: string;
113-
content: string;
114-
branch: string;
115-
sha?: string;
116-
}
117-
const updateUrl = `${this.baseUrl}/repos/${repoName}/contents/${fileName}`;
118-
const body: RepoUpdateBody = {
119-
message: commitMessage,
120-
content: Buffer.from(content).toString('base64'),
121-
branch: branch,
122-
};
123-
124-
if (sha) {
125-
body.sha = sha;
126-
}
94+
const fileUrl = `${this.baseUrl}/repos/${repoName}/contents/${fileName}?ref=${branch}`;
95+
const sha = await this.getFileSha(token, fileUrl);
96+
97+
const updateUrl = `${this.baseUrl}/repos/${repoName}/contents/${fileName}`;
98+
const body = {
99+
message: commitMessage,
100+
content: Buffer.from(content).toString('base64'),
101+
branch,
102+
...(sha && { sha }),
103+
};
127104

128-
const response = await fetch(updateUrl, {
129-
method: 'PUT',
130-
headers: {
131-
Authorization: `token ${token}`,
132-
Accept: 'application/vnd.github.v3+json',
133-
'Content-Type': 'application/json',
134-
},
135-
body: JSON.stringify(body),
136-
});
105+
const response = await fetch(updateUrl, {
106+
method: 'PUT',
107+
headers: this.getAuthHeaders(token, CONTENT_TYPE_JSON),
108+
body: JSON.stringify(body),
109+
});
137110

138-
if (!response.ok) {
139-
const error = await response.text();
140-
throw new Error(`GitHub API 错误: ${response.status} - ${error}`);
141-
}
142-
} catch (error) {
143-
throw new Error(`更新仓库失败: ${error}`);
144-
}
111+
await this.handleGitHubError(response);
145112
}
146113

114+
// 测试连接
147115
async testConnection(token: string): Promise<boolean> {
148116
try {
149117
const response = await fetch(`${this.baseUrl}/user`, {
150-
headers: {
151-
Authorization: `token ${token}`,
152-
Accept: 'application/vnd.github.v3+json',
153-
},
118+
headers: this.getAuthHeaders(token),
154119
});
155120

156121
return response.ok;
157122
} catch (error) {
158123
return false;
159124
}
160125
}
126+
127+
// ===== 私有辅助方法 =====
128+
129+
private getAuthHeaders(token: string, contentType?: string): Record<string, string> {
130+
const headers: Record<string, string> = {
131+
Authorization: `token ${token}`,
132+
Accept: GITHUB_ACCEPT_HEADER,
133+
};
134+
135+
if (contentType) {
136+
headers['Content-Type'] = contentType;
137+
}
138+
139+
return headers;
140+
}
141+
142+
private async getFileSha(token: string, fileUrl: string): Promise<string | undefined> {
143+
try {
144+
const response = await fetch(fileUrl, {
145+
headers: this.getAuthHeaders(token),
146+
});
147+
148+
if (!response.ok) {
149+
return undefined;
150+
}
151+
152+
const fileData = (await response.json()) as FileDataResponse;
153+
154+
return typeof fileData === 'object' && fileData !== null && 'sha' in fileData
155+
? (fileData.sha as string)
156+
: undefined;
157+
} catch (error) {
158+
console.warn('获取文件 SHA 时出错:', error);
159+
return undefined;
160+
}
161+
}
162+
163+
private async handleGitHubError(response: Response): Promise<void> {
164+
if (!response.ok) {
165+
const errorText = await response.text();
166+
throw new Error(`GitHub API 错误: ${response.status} - ${errorText}`);
167+
}
168+
}
169+
170+
private async saveGistIdToConfig(gistId: string): Promise<void> {
171+
const config = vscode.workspace.getConfiguration('vscode-syncing');
172+
await config.update('gistId', gistId, vscode.ConfigurationTarget.Global);
173+
vscode.window.showInformationMessage(`新的 Gist 已创建,ID: ${gistId}`);
174+
}
161175
}

0 commit comments

Comments
 (0)