fix(ci): reduce disk use for update feed sync (rename, tmp root, fetch retries)
Release / release (push) Failing after 8m46s
Release / release (push) Failing after 8m46s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
* GIT_COMMIT_TAG — опционально, для сообщения коммита
|
||||
* DND_GIT_PUSH_RETRIES — опционально, число попыток git push (1–5, по умолчанию 3)
|
||||
* DND_UPDATES_CLONE_DEPTH — опционально, глубина shallow clone (2–200, по умолчанию 40), чтобы merge с remote был надёжнее
|
||||
* DND_FEED_TMP_ROOT — каталог для временного клона feed (по умолчанию GITHUB_WORKSPACE / TMPDIR / os.tmpdir); не используйте узкий /tmp на раннере
|
||||
*/
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
@@ -37,7 +38,34 @@ function optionalDir(name) {
|
||||
return v && v.length > 0 ? v : '';
|
||||
}
|
||||
|
||||
function copyFlatReleaseFiles(fromDir, toDir) {
|
||||
/** Куда класть временный клон: workspace раннера предпочтительнее, чем /tmp (место под AppImage). */
|
||||
function feedTempRoot() {
|
||||
const a =
|
||||
process.env.DND_FEED_TMP_ROOT?.trim() ||
|
||||
process.env.GITHUB_WORKSPACE?.trim() ||
|
||||
process.env.GITEA_WORKSPACE?.trim() ||
|
||||
process.env.TMPDIR?.trim() ||
|
||||
os.tmpdir();
|
||||
return a;
|
||||
}
|
||||
|
||||
/** Перенос (rename) без дублирования байтов на одном томе; иначе copy + unlink исходника (освобождение места). */
|
||||
function moveOrCopyArtifactFile(src, dest) {
|
||||
if (fs.existsSync(dest)) {
|
||||
fs.unlinkSync(dest);
|
||||
}
|
||||
try {
|
||||
fs.renameSync(src, dest);
|
||||
return;
|
||||
} catch (e) {
|
||||
const code = /** @type {NodeJS.ErrnoException} */ (e).code;
|
||||
if (code !== 'EXDEV' && code !== 'EINVAL') throw e;
|
||||
}
|
||||
fs.copyFileSync(src, dest);
|
||||
fs.unlinkSync(src);
|
||||
}
|
||||
|
||||
function moveOrCopyFlatReleaseFiles(fromDir, toDir) {
|
||||
if (!fromDir || !fs.existsSync(fromDir)) {
|
||||
console.warn(`[sync-update-feed] skip missing dir: ${fromDir || '(empty)'}`);
|
||||
return 0;
|
||||
@@ -48,7 +76,7 @@ function copyFlatReleaseFiles(fromDir, toDir) {
|
||||
if (!fs.statSync(src).isFile()) continue;
|
||||
const ext = path.extname(name).toLowerCase();
|
||||
if (!ALLOWED_EXT.has(ext)) continue;
|
||||
fs.copyFileSync(src, path.join(toDir, name));
|
||||
moveOrCopyArtifactFile(src, path.join(toDir, name));
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
@@ -78,7 +106,28 @@ function sleepSyncSeconds(seconds) {
|
||||
}
|
||||
|
||||
function mergeOriginUpdates(work) {
|
||||
runGit(['fetch', 'origin', 'updates'], work);
|
||||
const fetchRetries = Math.max(
|
||||
1,
|
||||
Math.min(6, Number.parseInt(process.env.DND_GIT_FETCH_RETRIES || '4', 10) || 4),
|
||||
);
|
||||
let fetchOk = false;
|
||||
let lastFetchErr;
|
||||
for (let i = 0; i < fetchRetries; i += 1) {
|
||||
try {
|
||||
runGit(['fetch', 'origin', 'updates'], work);
|
||||
fetchOk = true;
|
||||
break;
|
||||
} catch (err) {
|
||||
lastFetchErr = err;
|
||||
console.warn(`[sync-update-feed] git fetch failed (attempt ${i + 1}/${fetchRetries})`);
|
||||
if (i < fetchRetries - 1) {
|
||||
sleepSyncSeconds(15);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fetchOk) {
|
||||
throw lastFetchErr ?? new Error('git fetch origin updates failed');
|
||||
}
|
||||
runGit(['merge', '--no-edit', 'origin/updates'], work);
|
||||
}
|
||||
|
||||
@@ -114,7 +163,9 @@ function main() {
|
||||
const host = u.host;
|
||||
const cloneUrl = `https://oauth2:${encodeURIComponent(token)}@${host}/${updatesRepo}.git`;
|
||||
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'dnd-feed-'));
|
||||
const tmpRoot = feedTempRoot();
|
||||
fs.mkdirSync(tmpRoot, { recursive: true });
|
||||
const tmp = fs.mkdtempSync(path.join(tmpRoot, 'dnd-feed-'));
|
||||
const work = path.join(tmp, 'repo');
|
||||
|
||||
const cloneDepth = Math.max(
|
||||
@@ -138,13 +189,14 @@ function main() {
|
||||
try {
|
||||
mergeOriginUpdates(work);
|
||||
} catch {
|
||||
console.warn('[sync-update-feed] initial merge skipped (новая ветка или пустой remote)');
|
||||
console.warn('[sync-update-feed] initial merge skipped (новая ветка или сеть/TLS — продолжаем)');
|
||||
}
|
||||
|
||||
const copied =
|
||||
copyFlatReleaseFiles(winDir, work) +
|
||||
copyFlatReleaseFiles(macDir, work) +
|
||||
copyFlatReleaseFiles(linuxDir, work);
|
||||
const artifactDirs = [...new Set([winDir, macDir, linuxDir].filter(Boolean))];
|
||||
let copied = 0;
|
||||
for (const d of artifactDirs) {
|
||||
copied += moveOrCopyFlatReleaseFiles(d, work);
|
||||
}
|
||||
if (copied === 0) {
|
||||
throw new Error(
|
||||
'[sync-update-feed] no release files copied (check ARTIFACT_WIN / ARTIFACT_MAC / ARTIFACT_LINUX)',
|
||||
@@ -162,7 +214,7 @@ function main() {
|
||||
}
|
||||
|
||||
fs.rmSync(tmp, { recursive: true, force: true });
|
||||
console.log(`[sync-update-feed] done (${String(copied)} file(s) copied)`);
|
||||
console.log(`[sync-update-feed] done (${String(copied)} file(s) into feed repo)`);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
Reference in New Issue
Block a user