diff --git a/packages/napcat-common/src/mirror.ts b/packages/napcat-common/src/mirror.ts index 17342a63..fde9f6ab 100644 --- a/packages/napcat-common/src/mirror.ts +++ b/packages/napcat-common/src/mirror.ts @@ -850,6 +850,8 @@ export interface ActionArtifact { created_at: string; expires_at: string; archive_download_url: string; + workflow_run_id?: number; + head_sha?: string; } /** @@ -860,13 +862,14 @@ export async function getLatestActionArtifacts ( owner: string, repo: string, workflow: string = 'build.yml', - branch: string = 'main' + branch: string = 'main', + maxRuns: number = 10 ): Promise { - const endpoint = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/runs?branch=${branch}&status=success&per_page=1`; + const endpoint = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/runs?branch=${branch}&status=success&per_page=${maxRuns}`; try { const runsResponse = await RequestUtil.HttpGetJson<{ - workflow_runs: Array<{ id: number; }>; + workflow_runs: Array<{ id: number; head_sha: string; created_at: string; }>; }>(endpoint, 'GET', undefined, { 'User-Agent': 'NapCat', 'Accept': 'application/vnd.github.v3+json', @@ -877,21 +880,33 @@ export async function getLatestActionArtifacts ( throw new Error('No successful workflow runs found'); } - const firstRun = workflowRuns[0]; - if (!firstRun) { - throw new Error('No workflow run found'); + // 获取所有 runs 的 artifacts + const allArtifacts: ActionArtifact[] = []; + + for (const run of workflowRuns) { + try { + const artifactsEndpoint = `https://api.github.com/repos/${owner}/${repo}/actions/runs/${run.id}/artifacts`; + const artifactsResponse = await RequestUtil.HttpGetJson<{ + artifacts: ActionArtifact[]; + }>(artifactsEndpoint, 'GET', undefined, { + 'User-Agent': 'NapCat', + 'Accept': 'application/vnd.github.v3+json', + }); + + if (artifactsResponse.artifacts) { + // 为每个 artifact 添加 run 信息 + for (const artifact of artifactsResponse.artifacts) { + artifact.workflow_run_id = run.id; + artifact.head_sha = run.head_sha; + allArtifacts.push(artifact); + } + } + } catch { + // 单个 run 获取失败,继续下一个 + } } - const runId = firstRun.id; - const artifactsEndpoint = `https://api.github.com/repos/${owner}/${repo}/actions/runs/${runId}/artifacts`; - const artifactsResponse = await RequestUtil.HttpGetJson<{ - artifacts: ActionArtifact[]; - }>(artifactsEndpoint, 'GET', undefined, { - 'User-Agent': 'NapCat', - 'Accept': 'application/vnd.github.v3+json', - }); - - return artifactsResponse.artifacts || []; + return allArtifacts; } catch { return []; } diff --git a/packages/napcat-webui-backend/src/api/BaseInfo.ts b/packages/napcat-webui-backend/src/api/BaseInfo.ts index 6b4f2282..2aae010e 100644 --- a/packages/napcat-webui-backend/src/api/BaseInfo.ts +++ b/packages/napcat-webui-backend/src/api/BaseInfo.ts @@ -5,6 +5,7 @@ import { sendSuccess } from '@/napcat-webui-backend/src/utils/response'; import { WebUiConfig } from '@/napcat-webui-backend/index'; import { getLatestTag, getAllTags, compareSemVer } from 'napcat-common/src/helper'; import { getLatestActionArtifacts } from '@/napcat-common/src/mirror'; +import { NapCatCoreWorkingEnv } from '@/napcat-webui-backend/src/types'; export const GetNapCatVersion: RequestHandler = (_, res) => { const data = WebUiDataRuntime.GetNapCatVersion(); @@ -32,6 +33,8 @@ export interface VersionInfo { createdAt?: string; expiresAt?: string; size?: number; + workflowRunId?: number; + headSha?: string; } /** @@ -75,8 +78,13 @@ export const getAllReleasesHandler: RequestHandler = async (req, res) => { if (includeActions) { try { const artifacts = await getLatestActionArtifacts('NapNeko', 'NapCatQQ', 'build.yml', 'main'); + + // 根据当前工作环境自动过滤对应的 artifact 类型 + const isFramework = WebUiDataRuntime.getWorkingEnv() === NapCatCoreWorkingEnv.Framework; + const targetArtifactName = isFramework ? 'NapCat.Framework' : 'NapCat.Shell'; + actionVersions = artifacts - .filter(a => a.name.includes('NapCat')) + .filter(a => a.name === targetArtifactName) .map(a => ({ tag: `action-${a.id}`, type: 'action' as const, @@ -85,6 +93,8 @@ export const getAllReleasesHandler: RequestHandler = async (req, res) => { createdAt: a.created_at, expiresAt: a.expires_at, size: a.size_in_bytes, + workflowRunId: a.workflow_run_id, + headSha: a.head_sha, })); } catch { // 忽略 action artifacts 获取失败 diff --git a/packages/napcat-webui-frontend/src/components/system_info.tsx b/packages/napcat-webui-frontend/src/components/system_info.tsx index a9aa2ee4..731a4184 100644 --- a/packages/napcat-webui-frontend/src/components/system_info.tsx +++ b/packages/napcat-webui-frontend/src/components/system_info.tsx @@ -267,6 +267,8 @@ interface VersionInfo { createdAt?: string; expiresAt?: string; size?: number; + workflowRunId?: number; + headSha?: string; } // 版本选择对话框内容 @@ -513,7 +515,7 @@ const VersionSelectDialogContent: React.FC = ({ setSelectedVersion(version || null); }} classNames={{ - trigger: 'h-10', + trigger: 'h-auto min-h-10', }} > {filteredVersions.map((version) => { @@ -524,19 +526,28 @@ const VersionSelectDialogContent: React.FC = ({ key={version.tag} textValue={version.tag} > -
- {version.tag} - {version.type === 'prerelease' && ( - 预发布 - )} +
+
+ {version.type === 'action' && version.artifactName ? version.artifactName : version.tag} + {version.type === 'prerelease' && ( + 预发布 + )} + {version.type === 'action' && ( + 临时 + )} + {isCurrent && ( + 当前 + )} + {downgrade && !isCurrent && version.type !== 'action' && ( + 降级 + )} +
{version.type === 'action' && ( - 临时 - )} - {isCurrent && ( - 当前 - )} - {downgrade && !isCurrent && version.type !== 'action' && ( - 降级 +
+ {version.headSha && {version.headSha.slice(0, 7)}} + {version.createdAt && {new Date(version.createdAt).toLocaleString()}} + {version.size && {(version.size / 1024 / 1024).toFixed(1)} MB} +
)}
diff --git a/packages/napcat-webui-frontend/src/controllers/webui_manager.ts b/packages/napcat-webui-frontend/src/controllers/webui_manager.ts index c9aa30b1..5bb344c5 100644 --- a/packages/napcat-webui-frontend/src/controllers/webui_manager.ts +++ b/packages/napcat-webui-frontend/src/controllers/webui_manager.ts @@ -83,6 +83,8 @@ export default class WebUIManager { createdAt?: string; expiresAt?: string; size?: number; + workflowRunId?: number; + headSha?: string; }>; pagination: { page: number;