1 Commits

Author SHA1 Message Date
Ivan Fontosh e923de350d fix(ci): merge origin/updates before push to avoid fetch-first rejection
Release / release (push) Failing after 6m2s
Shallow clone depth 40 (DND_UPDATES_CLONE_DEPTH); fetch+merge before each push attempt.
Release 1.0.9.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 11:15:33 +08:00
4 changed files with 33 additions and 6 deletions
+6
View File
@@ -378,6 +378,12 @@ git push origin v1.0.1
--- ---
## Если push отклонён: `(fetch first)` / `rejected`
Пока job собирает артефакты, в **`updates`** мог успеть попасть **другой** коммит (второй релиз, ручная выкладка). Скрипт `sync-update-feed.mjs` перед push делает **`git fetch` + `git merge origin/updates`** (и после клона — то же в начале), плюс shallow **глубина по умолчанию 40** (`DND_UPDATES_CLONE_DEPTH`). Не запускайте **два релиза одного и того же репо одновременно** по двум тегам — возможны конфликты merge.
---
## Поведение приложения ## Поведение приложения
- Проверка только в **собранной** установке (`app.isPackaged`). - Проверка только в **собранной** установке (`app.isPackaged`).
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "DndGamePlayer", "name": "DndGamePlayer",
"version": "1.0.8", "version": "1.0.9",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "DndGamePlayer", "name": "DndGamePlayer",
"version": "1.0.8", "version": "1.0.9",
"hasInstallScript": true, "hasInstallScript": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "DndGamePlayer", "name": "DndGamePlayer",
"version": "1.0.8", "version": "1.0.9",
"description": "DNDGamePlayer — редактор и проигрыватель игр", "description": "DNDGamePlayer — редактор и проигрыватель игр",
"main": "dist/main/index.cjs", "main": "dist/main/index.cjs",
"scripts": { "scripts": {
+24 -3
View File
@@ -14,6 +14,7 @@
* ARTIFACT_LINUX — каталог с файлами Linux (AppImage и т.д.) * ARTIFACT_LINUX — каталог с файлами Linux (AppImage и т.д.)
* GIT_COMMIT_TAG — опционально, для сообщения коммита * GIT_COMMIT_TAG — опционально, для сообщения коммита
* DND_GIT_PUSH_RETRIES — опционально, число попыток git push (1–5, по умолчанию 3) * DND_GIT_PUSH_RETRIES — опционально, число попыток git push (1–5, по умолчанию 3)
* DND_UPDATES_CLONE_DEPTH — опционально, глубина shallow clone (2200, по умолчанию 40), чтобы merge с remote был надёжнее
*/ */
import { execFileSync } from 'node:child_process'; import { execFileSync } from 'node:child_process';
import fs from 'node:fs'; import fs from 'node:fs';
@@ -76,16 +77,23 @@ function sleepSyncSeconds(seconds) {
} }
} }
function mergeOriginUpdates(work) {
runGit(['fetch', 'origin', 'updates'], work);
runGit(['merge', '--no-edit', 'origin/updates'], work);
}
function pushUpdatesBranch(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 = Math.max(1, Math.min(5, Number.parseInt(process.env.DND_GIT_PUSH_RETRIES || '3', 10) || 3));
let lastError; let lastError;
for (let attempt = 1; attempt <= retries; attempt += 1) { for (let attempt = 1; attempt <= retries; attempt += 1) {
try { try {
console.log(`[sync-update-feed] merge origin/updates before push (attempt ${attempt}/${retries})`);
mergeOriginUpdates(work);
runGit(['push', '-u', 'origin', 'updates'], work); runGit(['push', '-u', 'origin', 'updates'], work);
return; return;
} catch (err) { } catch (err) {
lastError = err; lastError = err;
console.warn(`[sync-update-feed] git push failed (attempt ${attempt}/${retries})`); console.warn(`[sync-update-feed] merge/push failed (attempt ${attempt}/${retries})`);
if (attempt < retries) { if (attempt < retries) {
sleepSyncSeconds(20); sleepSyncSeconds(20);
} }
@@ -109,10 +117,17 @@ function main() {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'dnd-feed-')); const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'dnd-feed-'));
const work = path.join(tmp, 'repo'); const work = path.join(tmp, 'repo');
const cloneDepth = Math.max(
2,
Math.min(200, Number.parseInt(process.env.DND_UPDATES_CLONE_DEPTH || '40', 10) || 40),
);
try { try {
execFileSync('git', ['clone', '--depth', '1', '-b', 'updates', cloneUrl, work], { stdio: 'inherit' }); execFileSync('git', ['clone', `--depth=${String(cloneDepth)}`, '-b', 'updates', cloneUrl, work], {
stdio: 'inherit',
});
} catch { } catch {
execFileSync('git', ['clone', '--depth', '1', cloneUrl, work], { stdio: 'inherit' }); execFileSync('git', ['clone', `--depth=${String(cloneDepth)}`, cloneUrl, work], { stdio: 'inherit' });
runGit(['checkout', '-B', 'updates'], work); runGit(['checkout', '-B', 'updates'], work);
} }
@@ -120,6 +135,12 @@ function main() {
runGit(['config', 'user.name', 'gitea-actions'], work); runGit(['config', 'user.name', 'gitea-actions'], work);
configureGitHttpForLargePush(work); configureGitHttpForLargePush(work);
try {
mergeOriginUpdates(work);
} catch {
console.warn('[sync-update-feed] initial merge skipped (новая ветка или пустой remote)');
}
const copied = const copied =
copyFlatReleaseFiles(winDir, work) + copyFlatReleaseFiles(winDir, work) +
copyFlatReleaseFiles(macDir, work) + copyFlatReleaseFiles(macDir, work) +