ci: 添加构建结果评论中的下载链接和获取 artifacts 列表功能

This commit is contained in:
时瑾 2025-12-29 03:14:17 +08:00
parent 05b38825c0
commit 3365211507
No known key found for this signature in database
GPG Key ID: 023F70A1B8F8C196
3 changed files with 59 additions and 12 deletions

View File

@ -10,6 +10,7 @@ export interface BuildTarget {
name: string; name: string;
status: BuildStatus; status: BuildStatus;
error?: string; error?: string;
downloadUrl?: string; // Artifact 直接下载链接
} }
// ============== 辅助函数 ============== // ============== 辅助函数 ==============
@ -70,8 +71,8 @@ export function generateResultComment (
runId: string, runId: string,
repository: string repository: string
): string { ): string {
const artifactUrl = `https://github.com/${repository}/actions/runs/${runId}/artifacts`; // 链接到 run 详情页,页面底部有 Artifacts 下载区域
const logUrl = `https://github.com/${repository}/actions/runs/${runId}`; const runUrl = `https://github.com/${repository}/actions/runs/${runId}`;
const allSuccess = targets.every(t => t.status === 'success'); const allSuccess = targets.every(t => t.status === 'success');
const anyCancelled = targets.some(t => t.status === 'cancelled'); const anyCancelled = targets.some(t => t.status === 'cancelled');
@ -82,8 +83,14 @@ export function generateResultComment (
? '⚪ 构建已取消' ? '⚪ 构建已取消'
: '❌ 构建失败'; : '❌ 构建失败';
const downloadLink = (status: BuildStatus) => const downloadLink = (target: BuildTarget) => {
status === 'success' ? `[📦 下载](${artifactUrl})` : '—'; if (target.status !== 'success') return '—';
if (target.downloadUrl) {
return `[📦 下载](${target.downloadUrl})`;
}
// 回退到 run 详情页
return `[📦 下载](${runUrl}#artifacts)`;
};
const lines: string[] = [ const lines: string[] = [
COMMENT_MARKER, COMMENT_MARKER,
@ -91,12 +98,12 @@ export function generateResultComment (
'', '',
'| 构建目标 | 状态 | 下载 |', '| 构建目标 | 状态 | 下载 |',
'| :--- | :--- | :--- |', '| :--- | :--- | :--- |',
...targets.map(t => `| ${t.name} | ${getStatusIcon(t.status)} | ${downloadLink(t.status)} |`), ...targets.map(t => `| ${t.name} | ${getStatusIcon(t.status)} | ${downloadLink(t)} |`),
'', '',
'---', '---',
'', '',
`📝 **提交**: \`${formatSha(prSha)}\``, `📝 **提交**: \`${formatSha(prSha)}\``,
`🔗 **构建日志**: [查看详情](${logUrl})`, `🔗 **构建日志**: [查看详情](${runUrl})`,
]; ];
// 添加错误详情 // 添加错误详情

View File

@ -24,7 +24,14 @@ export interface Repository {
}; };
} }
// ============== GitHub API Client ============== export interface Artifact {
id: number;
name: string;
size_in_bytes: number;
archive_download_url: string;
}
// ============== GitHub API Client ==========================
export class GitHubAPI { export class GitHubAPI {
private token: string; private token: string;
@ -76,6 +83,13 @@ export class GitHubAPI {
} }
} }
async getRunArtifacts (owner: string, repo: string, runId: string): Promise<Artifact[]> {
const data = await this.request<{ artifacts: Artifact[]; }>(
`/repos/${owner}/${repo}/actions/runs/${runId}/artifacts`
);
return data.artifacts;
}
async createComment (owner: string, repo: string, issueNumber: number, body: string): Promise<void> { async createComment (owner: string, repo: string, issueNumber: number, body: string): Promise<void> {
await this.request(`/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { await this.request(`/repos/${owner}/${repo}/issues/${issueNumber}/comments`, {
method: 'POST', method: 'POST',

View File

@ -43,13 +43,39 @@ async function main (): Promise<void> {
console.log(`Framework: ${frameworkStatus}${frameworkError ? ` (${frameworkError})` : ''}`); console.log(`Framework: ${frameworkStatus}${frameworkError ? ` (${frameworkError})` : ''}`);
console.log(`Shell: ${shellStatus}${shellError ? ` (${shellError})` : ''}\n`); console.log(`Shell: ${shellStatus}${shellError ? ` (${shellError})` : ''}\n`);
const targets: BuildTarget[] = [
{ name: 'NapCat.Framework', status: frameworkStatus, error: frameworkError },
{ name: 'NapCat.Shell', status: shellStatus, error: shellError },
];
const github = new GitHubAPI(token); const github = new GitHubAPI(token);
const repository = `${owner}/${repo}`; const repository = `${owner}/${repo}`;
// 获取 artifacts 列表,生成直接下载链接
const artifactMap: Record<string, string> = {};
try {
const artifacts = await github.getRunArtifacts(owner, repo, runId);
console.log(`Found ${artifacts.length} artifacts`);
for (const artifact of artifacts) {
// 生成直接下载链接https://github.com/{owner}/{repo}/actions/runs/{run_id}/artifacts/{artifact_id}
const downloadUrl = `https://github.com/${repository}/actions/runs/${runId}/artifacts/${artifact.id}`;
artifactMap[artifact.name] = downloadUrl;
console.log(` - ${artifact.name}: ${downloadUrl}`);
}
} catch (e) {
console.log(`Warning: Failed to get artifacts: ${(e as Error).message}`);
}
const targets: BuildTarget[] = [
{
name: 'NapCat.Framework',
status: frameworkStatus,
error: frameworkError,
downloadUrl: artifactMap['NapCat.Framework'],
},
{
name: 'NapCat.Shell',
status: shellStatus,
error: shellError,
downloadUrl: artifactMap['NapCat.Shell'],
},
];
const comment = generateResultComment(targets, prSha, runId, repository); const comment = generateResultComment(targets, prSha, runId, repository);
await github.createOrUpdateComment(owner, repo, prNumber, comment, COMMENT_MARKER); await github.createOrUpdateComment(owner, repo, prNumber, comment, COMMENT_MARKER);