Mark the release :latest serves as the repository's latest release
Sync upstream and build images / sync-and-build (push) Successful in 32s

Gitea shows a repository's "latest release" on the home page and at
/releases/latest, and defines it as the newest non-pre-release. Upstream
flags every RC and alpha pre-release, and mirroring that left the home page
with no release listed although ten exist. The release for the version
:latest serves is now the one full release; every other version keeps
upstream's flag, and the flag is part of the up-to-date check so it flips
when :latest moves.
This commit is contained in:
Ward committed 2026-09-11 14:30:48 -04:00
1 parent 0070b82414
commit f7fbe495ab
2 files changed
+26 -9

No files matched your search

+23 -8
View File
@@ -213,7 +213,17 @@ function existingHistory(body) {
// --- main -----------------------------------------------------------------
async function publish(ver) {
// The digest `:latest` currently serves. The release for that version is the
// repository's one full release; every other version keeps upstream's
// pre-release flag. Gitea defines a repository's "latest release" as its
// newest non-pre-release, and only that is shown on the repository home page
// and served at /releases/latest — with every RC flagged pre-release the way
// upstream flags them, the home page listed no release at all.
async function latestDigest() {
try { return (await imageFacts('latest')).digest; } catch { return ''; }
}
async function publish(ver, current) {
const tag = `dsh-v${ver}`;
const tagLookup = await gitea('GET', `/repos/${REPO}/tags/${tag}`);
if (tagLookup.status !== 200) {
@@ -223,24 +233,27 @@ async function publish(ver) {
const facts = await imageFacts(ver);
const up = await upstreamRelease(ver);
const title = up?.name ?? `v${ver}`;
const prerelease = up ? up.prerelease : true;
const isCurrent = current !== '' && facts.digest === current;
const prerelease = isCurrent ? false : (up ? up.prerelease : true);
const existing = await gitea('GET', `/repos/${REPO}/releases/tags/${tag}`);
if (existing.status === 200) {
const prev = existingDigest(existing.json.body);
const history = [prev, ...existingHistory(existing.json.body)].filter((d) => d && d !== facts.digest).slice(0, HISTORY_MAX);
const body = renderBody(ver, facts, up, history);
// Same image, same title, same rendered text -> nothing to do. Comparing
// the text (not just the digest) lets a changed container note or edited
// upstream notes reach existing releases on the next run.
// Same image, same title, same flag, same rendered text -> nothing to do.
// Comparing the text (not just the digest) lets a changed container note
// or edited upstream notes reach existing releases on the next run.
const norm = (s) => (s || '').replace(/\r\n/g, '\n').trim();
const sameImage = prev === facts.digest;
if (sameImage && existing.json.name === title && norm(existing.json.body) === norm(body)) { console.log(`${tag}: up to date`); return; }
const unchanged = sameImage && existing.json.name === title && existing.json.prerelease === prerelease
&& norm(existing.json.body) === norm(body);
if (unchanged) { console.log(`${tag}: up to date`); return; }
if (DRY_RUN) { console.log(`\n===== DRY RUN update ${tag} =====\n${title}\n\n${body}\n`); return; }
const r = await gitea('PATCH', `/repos/${REPO}/releases/${existing.json.id}`, { name: title, body, prerelease, draft: false });
if (r.status !== 200) throw new Error(`${tag}: update HTTP ${r.status} ${r.text.slice(0, 200)}`);
console.log(sameImage
? `${tag}: updated (notes)`
? `${tag}: updated (${existing.json.prerelease === prerelease ? 'notes' : isCurrent ? 'now the latest release' : 'back to pre-release'})`
: `${tag}: updated (image rebuilt: ${prev.slice(0, 19)} -> ${facts.digest.slice(0, 19)})`);
return;
}
@@ -258,6 +271,8 @@ async function publish(ver) {
(async () => {
const versions = await registryVersions();
console.log(`image versions: ${versions.join(', ') || '(none)'}`);
const current = await latestDigest();
console.log(`:latest digest: ${current || '(none — every release keeps its upstream flag)'}`);
// Oldest first, so the Releases page (newest created on top) reads in version order.
for (const v of versions) await publish(v);
for (const v of versions) await publish(v, current);
})().catch((err) => { console.error(`::error::${err.message}`); process.exit(1); });
+3 -1
View File
@@ -266,7 +266,9 @@ The [Releases](../../releases) page mirrors upstream's: one entry per version, o
`dsh-v<version>` tag, titled the same way, with upstream's own notes followed by a short
container footer (digest, pnpm, base image, build). Version tags are rebuilt in place when
*our* recipe changes — the dsh inside never does — and the release footer keeps the
previous digests.
previous digests. One deliberate difference: the release for the version `:latest` serves
is the repository's **Latest** release (Gitea lists only a non-pre-release on the home page
and at `/releases/latest`); every other version carries upstream's pre-release flag.
Changing the **dsh version** is the deliberate part, and with `:latest` in the template
that happens whenever you accept an update Unraid offers. Before you do: