Merge pull request #97 from router-for-me/dev

Dev
This commit is contained in:
lzt404 authored and GitHub committed 2026-08-05 18:44:46 +08:00
commit 44e3f36fd6
5 files changed
+80 -12

No files matched your search

+2 -1
View File
@@ -33,7 +33,7 @@ jobs:
|| github.event.workflow_run.conclusion == 'success'
)
runs-on: ubuntu-24.04
timeout-minutes: 60
timeout-minutes: 35
steps:
- uses: actions/checkout@v7
- name: Resolve release tag
@@ -75,6 +75,7 @@ jobs:
run: gh release download "${{ steps.release.outputs.tag }}" --dir artifacts
- name: Publish GitCode mirror
if: steps.release.outputs.should_mirror == 'true'
timeout-minutes: 30
env:
ARTIFACT_DIRECTORY: artifacts
GITCODE_ACCESS_TOKEN: ${{ secrets.GITCODE_ACCESS_TOKEN }}
+15 -1
View File
@@ -1,6 +1,8 @@
[CmdletBinding()]
param(
[int]$BuildJobs
[int]$BuildJobs,
[string]$GitCodeRepository = 'lzt404/EasyCLIProxyAPI'
)
Set-StrictMode -Version Latest
@@ -25,12 +27,16 @@ if (-not $PSBoundParameters.ContainsKey('BuildJobs')) {
if ($BuildJobs -lt 1 -or $BuildJobs -gt 256) {
throw 'BuildJobs must be between 1 and 256.'
}
if ($GitCodeRepository -notmatch '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$') {
throw 'GitCodeRepository must use the owner/repository format.'
}
if (-not (Get-Command bun -ErrorAction SilentlyContinue)) {
throw 'bun is not installed or not in PATH.'
}
Write-Host "Cargo build jobs: $BuildJobs"
Write-Host "GitCode fallback repository: $GitCodeRepository"
& bun install
if ($LASTEXITCODE -ne 0) {
@@ -38,8 +44,10 @@ if ($LASTEXITCODE -ne 0) {
}
$PreviousBuildJobs = $env:CARGO_BUILD_JOBS
$PreviousGitCodeRepository = $env:GITCODE_REPOSITORY
try {
$env:CARGO_BUILD_JOBS = [string]$BuildJobs
$env:GITCODE_REPOSITORY = $GitCodeRepository
& bun tauri build --no-bundle
if ($LASTEXITCODE -ne 0) {
throw "Tauri build failed with exit code $LASTEXITCODE."
@@ -52,6 +60,12 @@ finally {
else {
$env:CARGO_BUILD_JOBS = $PreviousBuildJobs
}
if ($null -eq $PreviousGitCodeRepository) {
Remove-Item Env:GITCODE_REPOSITORY -ErrorAction SilentlyContinue
}
else {
$env:GITCODE_REPOSITORY = $PreviousGitCodeRepository
}
}
if (-not (Test-Path -LiteralPath $AppBin -PathType Leaf)) {
+3 -1
View File
@@ -5,6 +5,7 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT_DIR"
BUILD_JOBS="${CARGO_BUILD_JOBS:-20}"
GITCODE_REPOSITORY="${GITCODE_REPOSITORY:-lzt404/EasyCLIProxyAPI}"
APP_BIN="$ROOT_DIR/src-tauri/target/release/cpa-gui"
BIN_DIR="$ROOT_DIR/bin-work"
BIN_OUT="$BIN_DIR/EasyCLIProxyAPI"
@@ -15,8 +16,9 @@ if ! command -v bun >/dev/null 2>&1; then
fi
echo "Cargo build jobs: $BUILD_JOBS"
echo "GitCode fallback repository: $GITCODE_REPOSITORY"
bun install
CARGO_BUILD_JOBS="$BUILD_JOBS" bun tauri build --no-bundle
CARGO_BUILD_JOBS="$BUILD_JOBS" GITCODE_REPOSITORY="$GITCODE_REPOSITORY" bun tauri build --no-bundle
if [ ! -x "$APP_BIN" ]; then
echo "Build finished, but executable not found: $APP_BIN"
+22 -9
View File
@@ -4,6 +4,8 @@ import { basename, join, resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
const API_BASE = 'https://api.gitcode.com/api/v5';
const API_TIMEOUT_MS = 30_000;
const UPLOAD_TIMEOUT_SECONDS = 180;
function parseRepository(value) {
const repository = String(value ?? '').trim();
@@ -36,6 +38,7 @@ async function apiRequest(path, {
method,
headers: body ? { 'Content-Type': 'application/json' } : undefined,
body: body ? JSON.stringify(body) : undefined,
signal: AbortSignal.timeout(API_TIMEOUT_MS),
});
} catch (error) {
throw new Error(`GitCode API request failed for ${path}: ${error instanceof Error ? error.message : error}`);
@@ -53,11 +56,10 @@ export function uploadFileWithCurl({ url, headers, path }) {
'--silent',
'--show-error',
'--location',
'--retry', '3',
'--retry-delay', '5',
'--retry-all-errors',
'--connect-timeout', '30',
'--max-time', '1800',
'--speed-limit', '1',
'--speed-time', '30',
'--max-time', String(UPLOAD_TIMEOUT_SECONDS),
'--request', 'PUT',
'--upload-file', path,
'--output', process.platform === 'win32' ? 'NUL' : '/dev/null',
@@ -147,11 +149,22 @@ export async function publishGitcodeRelease({
const headers = Array.isArray(rawHeaders)
? Object.fromEntries(rawHeaders.map(({ key, name, value }) => [key ?? name, value]))
: rawHeaders && typeof rawHeaders === 'object' ? rawHeaders : {};
await uploadImpl({
url: uploadUrl,
headers,
path: join(directory, entry.name),
});
console.log(`Uploading GitCode asset: ${entry.name}`);
try {
await uploadImpl({
url: uploadUrl,
headers,
path: join(directory, entry.name),
});
} catch (error) {
console.warn(`GitCode upload command did not finish cleanly; verifying asset: ${entry.name}`);
const refreshedRelease = await apiRequest(releaseByTagPath, { token, fetchImpl });
const uploadedDespiteError = (refreshedRelease.assets ?? [])
.some((asset) => asset.name === entry.name);
if (!uploadedDespiteError) throw error;
console.log(`GitCode asset exists despite upload error: ${entry.name}`);
}
existingAssets.add(entry.name);
console.log(`Uploaded GitCode asset: ${entry.name}`);
}
}
+38
View File
@@ -53,4 +53,42 @@ describe('GitCode release mirror', () => {
await rm(directory, { recursive: true, force: true });
}
});
test('continues when GitCode stores an asset but the upload response times out', async () => {
const directory = await mkdtemp(join(tmpdir(), 'easycli-gitcode-release-'));
const artifactName = 'EasyCLIProxyAPI-v1.2.3-Windows-amd64.zip';
let releaseRequests = 0;
try {
await writeFile(join(directory, artifactName), 'artifact');
const fetchImpl = async (input: URL | RequestInfo) => {
const url = String(input);
if (url.includes('/releases/tags/')) {
releaseRequests += 1;
return Response.json({
tag_name: 'v1.2.3',
assets: releaseRequests === 1 ? [] : [{ name: artifactName }],
});
}
if (url.includes('/upload_url?')) {
return Response.json({ upload_url: 'https://file-cdn.gitcode.com/presigned-upload' });
}
return new Response('', { status: 500 });
};
await expect(publishGitcodeRelease({
directory,
repository: 'mirror-owner/EasyCLIProxyAPI',
token: 'secret-token',
tag: 'v1.2.3',
fetchImpl,
uploadImpl: async () => {
throw new Error('upload response timed out');
},
})).resolves.toBeUndefined();
expect(releaseRequests).toBe(2);
} finally {
await rm(directory, { recursive: true, force: true });
}
});
});