fix(ci): prune old DNDGamePlayer artifacts from updates feed before copy
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -388,6 +388,8 @@ git push origin v1.0.1
|
||||
|
||||
Не запускайте **два релиза**, которые одновременно пушат feed, — возможна гонка и отказ **`--force-with-lease`**.
|
||||
|
||||
Перед подкладкой артефактов скрипт **удаляет** из корня ветки файлы вида **`DNDGamePlayer-<чужая версия>-*`** / **`DNDGamePlayer-Setup-<чужая версия>.exe`** (и связанные `.blockmap`), чтобы после `merge` не копились старые установщики (1.0.6 рядом с 1.0.14). Версия текущего релиза берётся из **`GIT_COMMIT_TAG`** (`v1.0.14` → `1.0.14`). Файлы **`latest*.yml`** перезаписываются копированием. Если в **`ARTIFACT_MAC`** нет ни одного файла сборки, **`.dmg` / `.pkg`** не удаляются — сохраняется вручную залитый mac в feed. Отключить очистку: **`DND_FEED_PRUNE_OLD_VERSIONS=0`**.
|
||||
|
||||
---
|
||||
|
||||
## Если push отклонён: `(fetch first)` / `rejected`
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
* ветка `updates`, чтобы generic URL …/raw/branch/updates/ указывал на актуальные latest*.yml и установщики.
|
||||
*
|
||||
* Копирование **merge**: существующие файлы в ветке (другие ОС) не удаляются — обновляются только
|
||||
* те имена, которые пришли из переданных каталогов артефактов.
|
||||
* те имена, которые пришли из переданных каталогов артефактов. Перед копированием удаляются **устаревшие**
|
||||
* установщики другой semver в имени (`DNDGamePlayer-1.0.6-…` при релизе `v1.0.14`), чтобы в feed не копились старые версии.
|
||||
*
|
||||
* Переменные окружения:
|
||||
* DND_UPDATES_SERVER — https://git.example.com (без слэша в конце)
|
||||
@@ -21,6 +22,7 @@
|
||||
* DND_FEED_SKIP_DISK_CHECK — если "1", не проверять свободное место на томе DND_FEED_TMP_ROOT перед clone
|
||||
* DND_UPDATES_SQUASH_HISTORY — если "1", после каждого релиза ветка updates в UPDATES_REPO переписывается на историю только текущего релиза. Загрузка идёт во временную ветку updates-upload-* (маленькие pack'и), затем публикуется updates; временная ветка удаляется — пользователям feed по-прежнему нужна только ветка updates.
|
||||
* DND_FEED_LARGE_FILE_BYTES — порог "большого" файла для дробления push в squash-режиме (по умолчанию 64 MiB)
|
||||
* DND_FEED_PRUNE_OLD_VERSIONS — если "0"/"false"/"no", не удалять старые DNDGamePlayer-* другой версии перед копированием
|
||||
*/
|
||||
import { execFileSync, spawnSync } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
@@ -99,6 +101,80 @@ function tryGitGcPrune(work) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Тег релиза `v1.0.14` → `1.0.14` (с опциональным prerelease). */
|
||||
function parseReleaseSemverFromGitTag() {
|
||||
const t = (process.env.GIT_COMMIT_TAG || '').trim();
|
||||
const m = /^v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.+]+)?)$/.exec(t);
|
||||
return m ? m[1] : null;
|
||||
}
|
||||
|
||||
function macArtifactLooksLike(fileName) {
|
||||
const lo = fileName.toLowerCase();
|
||||
if (lo.endsWith('.dmg') || lo.endsWith('.pkg')) return true;
|
||||
if (lo.endsWith('.zip') && /(?:^|-)mac(?:-|$)|darwin/i.test(fileName)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Версия из имени артефакта electron-builder (DNDGamePlayer + semver в имени).
|
||||
* `latest*.yml` и прочее без semver — null.
|
||||
*/
|
||||
function extractVersionedDndArtifactSemver(fileName) {
|
||||
const n = fileName;
|
||||
let m = /^DNDGamePlayer-Setup-(\d+\.\d+\.\d+(?:-[0-9A-Za-z.+]+)?)\.exe(?:\.blockmap)?$/i.exec(n);
|
||||
if (m) return m[1];
|
||||
m = /^DNDGamePlayer-(\d+\.\d+\.\d+(?:-[0-9A-Za-z.+]+)?)-/i.exec(n);
|
||||
if (m) return m[1];
|
||||
m = /^DNDGamePlayer-(\d+\.\d+\.\d+(?:-[0-9A-Za-z.+]+)?)\.(dmg|pkg)$/i.exec(n);
|
||||
if (m) return m[1];
|
||||
return null;
|
||||
}
|
||||
|
||||
function artifactDirHasIncomingFiles(dir) {
|
||||
if (!dir || !fs.existsSync(dir)) return false;
|
||||
for (const name of fs.readdirSync(dir)) {
|
||||
const p = path.join(dir, name);
|
||||
if (!fs.statSync(p).isFile()) continue;
|
||||
const ext = path.extname(name).toLowerCase();
|
||||
if (ALLOWED_EXT.has(ext)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет из корня клона старые установщики с другим semver (после merge они иначе остаются навсегда).
|
||||
* Если в ARTIFACT_MAC нет файлов — .dmg/.pkg не трогаем (ручная заливка mac в feed).
|
||||
*/
|
||||
function pruneObsoleteDndReleaseArtifacts(work, currentSemver, macDir) {
|
||||
const off = process.env.DND_FEED_PRUNE_OLD_VERSIONS?.trim().toLowerCase();
|
||||
if (off === '0' || off === 'false' || off === 'no') return 0;
|
||||
if (!currentSemver) {
|
||||
console.warn('[sync-update-feed] prune: пропуск — GIT_COMMIT_TAG не похож на v1.2.3');
|
||||
return 0;
|
||||
}
|
||||
const pruneMac = artifactDirHasIncomingFiles(macDir);
|
||||
let removed = 0;
|
||||
for (const name of fs.readdirSync(work)) {
|
||||
if (name === '.git') continue;
|
||||
const p = path.join(work, name);
|
||||
if (!fs.statSync(p).isFile()) continue;
|
||||
const ext = path.extname(name).toLowerCase();
|
||||
if (!ALLOWED_EXT.has(ext)) continue;
|
||||
const fileVer = extractVersionedDndArtifactSemver(name);
|
||||
if (!fileVer) continue;
|
||||
if (fileVer === currentSemver) continue;
|
||||
if (!pruneMac && macArtifactLooksLike(name)) continue;
|
||||
fs.unlinkSync(p);
|
||||
removed += 1;
|
||||
}
|
||||
if (removed > 0) {
|
||||
console.warn(
|
||||
`[sync-update-feed] prune: удалено устаревших артефактов (другая версия в имени): ${String(removed)}`,
|
||||
);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
function mustEnv(name) {
|
||||
const v = process.env[name]?.trim();
|
||||
if (!v) throw new Error(`Missing env ${name}`);
|
||||
@@ -429,6 +505,9 @@ function main() {
|
||||
|
||||
mergeOriginUpdates(work);
|
||||
|
||||
const currentSemver = parseReleaseSemverFromGitTag();
|
||||
pruneObsoleteDndReleaseArtifacts(work, currentSemver, macDir);
|
||||
|
||||
const artifactDirs = [...new Set([winDir, macDir, linuxDir].filter(Boolean))];
|
||||
let copied = 0;
|
||||
for (const d of artifactDirs) {
|
||||
|
||||
Reference in New Issue
Block a user