fix(ci): more git push retries for feed; document HTTP 500 and temp branch

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-05-13 23:48:39 +08:00
parent 2dc7015f53
commit 26f8a81631
3 changed files with 27 additions and 10 deletions
+22 -7
View File
@@ -13,12 +13,13 @@
* ARTIFACT_MAC — каталог с файлами macOS
* ARTIFACT_LINUX — каталог с файлами Linux (AppImage и т.д.)
* GIT_COMMIT_TAG — опционально, для сообщения коммита
* DND_GIT_PUSH_RETRIES — опционально, число попыток git push (15, по умолчанию 3)
* DND_GIT_PUSH_RETRIES — число попыток git push (110, по умолчанию 5); при squash — для каждого push во временную ветку и финального push в updates
* DND_GIT_PUSH_RETRY_SLEEP_SEC — пауза между попытками push (5–120 с, по умолчанию 30)
* DND_UPDATES_CLONE_DEPTH — опционально, глубина shallow clone (2200, по умолчанию 40), чтобы merge с remote был надёжнее
* DND_FEED_TMP_ROOT — каталог для временного клона feed (по умолчанию GITHUB_WORKSPACE / TMPDIR / os.tmpdir); не используйте узкий /tmp на раннере
* DND_GIT_FETCH_RETRIES — число попыток git fetch (1–6, по умолчанию 6); между попытками — git gc --prune=now (освобождение после обрыва TLS/unpack)
* DND_FEED_SKIP_DISK_CHECK — если "1", не проверять свободное место на томе DND_FEED_TMP_ROOT перед clone
* DND_UPDATES_SQUASH_HISTORY — если "1", после каждого релиза ветка updates в UPDATES_REPO переписывается на историю только текущего релиза (orphan + временная ветка + force-with-lease)
* DND_UPDATES_SQUASH_HISTORY — если "1", после каждого релиза ветка updates в UPDATES_REPO переписывается на историю только текущего релиза. Загрузка идёт во временную ветку updates-upload-* (маленькие pack'и), затем публикуется updates; временная ветка удаляется — пользователям feed по-прежнему нужна только ветка updates.
* DND_FEED_LARGE_FILE_BYTES — порог "большого" файла для дробления push в squash-режиме (по умолчанию 64 MiB)
*/
import { execFileSync, spawnSync } from 'node:child_process';
@@ -200,8 +201,20 @@ function sanitizeRefPart(s) {
.slice(0, 80);
}
function gitPushRetryCount() {
return Math.max(1, Math.min(10, Number.parseInt(process.env.DND_GIT_PUSH_RETRIES || '5', 10) || 5));
}
function gitPushRetrySleepSec() {
return Math.max(
5,
Math.min(120, Number.parseInt(process.env.DND_GIT_PUSH_RETRY_SLEEP_SEC || '30', 10) || 30),
);
}
function pushWithRetries(work, args, label) {
const retries = Math.max(1, Math.min(5, Number.parseInt(process.env.DND_GIT_PUSH_RETRIES || '3', 10) || 3));
const retries = gitPushRetryCount();
const sleepSec = gitPushRetrySleepSec();
let lastError;
for (let attempt = 1; attempt <= retries; attempt += 1) {
try {
@@ -212,7 +225,7 @@ function pushWithRetries(work, args, label) {
lastError = err;
console.warn(`[sync-update-feed] ${label} failed (attempt ${attempt}/${retries})`);
if (attempt < retries) {
sleepSyncSeconds(20);
sleepSyncSeconds(sleepSec);
}
}
}
@@ -269,7 +282,8 @@ function publishSquashedUpdatesBranchStreamed(work, message, tag) {
console.warn(
`[sync-update-feed] DND_UPDATES_SQUASH_HISTORY=1: переписываем только UPDATES_REPO/updates; ` +
`push дробится через временную ветку ${tempBranch} (${smallFiles.length} small, ${largeFiles.length} large)`,
`push дробится через временную ветку ${tempBranch} (${smallFiles.length} small, ${largeFiles.length} large). ` +
`Ветка updates-upload-* служебная: после успеха на remote остаётся только updates; клиенты по-прежнему читают raw/.../updates/.`,
);
runGit(['checkout', '--orphan', 'dnd-feed-upload-tmp'], work);
@@ -354,7 +368,8 @@ function mergeOriginUpdates(work) {
}
function pushUpdatesBranch(work) {
const retries = Math.max(1, Math.min(5, Number.parseInt(process.env.DND_GIT_PUSH_RETRIES || '3', 10) || 3));
const retries = gitPushRetryCount();
const sleepSec = gitPushRetrySleepSec();
let lastError;
for (let attempt = 1; attempt <= retries; attempt += 1) {
try {
@@ -366,7 +381,7 @@ function pushUpdatesBranch(work) {
lastError = err;
console.warn(`[sync-update-feed] merge/push failed (attempt ${attempt}/${retries})`);
if (attempt < retries) {
sleepSyncSeconds(20);
sleepSyncSeconds(sleepSec);
}
}
}