Files
OFLauncher/scripts/publish-gitea.mjs
T
2026-06-14 12:32:29 +02:00

119 lines
3.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Publie les artefacts d'auto-update du launcher sur une release Gitea à tag
* fixe ("latest"). electron-updater (provider generic) lit ensuite latest.yml
* à l'URL configurée dans electron-builder.yml.
*
* Pré-requis :
* - `npm run build:win` a produit dist/ (latest.yml + installeur + .blockmap)
* - variable d'env GITEA_TOKEN (scope write:repository)
*
* Config par variables d'env (avec valeurs par défaut) :
* GITEA_URL base de l'instance (def. https://gitea.ldpt.fr)
* GITEA_OWNER propriétaire du repo (def. zertus)
* GITEA_REPO nom du repo launcher (def. OFLauncher)
* GITEA_TAG tag fixe de la release (def. latest)
*/
import { readdir, readFile } from 'node:fs/promises'
import { join } from 'node:path'
const BASE = process.env.GITEA_URL ?? 'https://gitea.ldpt.fr'
const OWNER = process.env.GITEA_OWNER ?? 'zertus'
const REPO = process.env.GITEA_REPO ?? 'OFLauncher'
const TAG = process.env.GITEA_TAG ?? 'latest'
const TOKEN = process.env.GITEA_TOKEN
const DIST = join(process.cwd(), 'dist')
const API = `${BASE}/api/v1`
if (!TOKEN) {
console.error('GITEA_TOKEN manquant (scope write:repository).')
process.exit(1)
}
/** Fichiers de dist/ à publier pour l'auto-update Windows. */
function isUpdateArtifact(name) {
return (
name === 'latest.yml' ||
name.endsWith('-setup.exe') ||
name.endsWith('-setup.exe.blockmap')
)
}
async function api(path, init = {}) {
const res = await fetch(`${API}${path}`, {
...init,
headers: {
Authorization: `token ${TOKEN}`,
Accept: 'application/json',
...(init.headers ?? {})
}
})
if (!res.ok) {
const body = await res.text().catch(() => '')
throw new Error(`Gitea ${init.method ?? 'GET'} ${path} -> ${res.status} ${body}`)
}
return res.status === 204 ? null : res.json()
}
/** Récupère la release au tag fixe, ou la crée si absente. */
async function getOrCreateRelease() {
const res = await fetch(`${API}/repos/${OWNER}/${REPO}/releases/tags/${TAG}`, {
headers: { Authorization: `token ${TOKEN}`, Accept: 'application/json' }
})
if (res.ok) return res.json()
if (res.status !== 404) {
throw new Error(`Gitea GET release -> ${res.status} ${await res.text()}`)
}
console.log(`Création de la release "${TAG}"…`)
return api(`/repos/${OWNER}/${REPO}/releases`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tag_name: TAG,
name: 'Dernière version',
body: 'Artefacts dauto-update du launcher (écrasés à chaque publication).'
})
})
}
async function deleteExistingAssets(releaseId) {
const assets = await api(`/repos/${OWNER}/${REPO}/releases/${releaseId}/assets`)
for (const a of assets) {
console.log(`Suppression de l'ancien asset ${a.name}`)
await api(`/repos/${OWNER}/${REPO}/releases/${releaseId}/assets/${a.id}`, {
method: 'DELETE'
})
}
}
async function uploadAsset(releaseId, name) {
const buf = await readFile(join(DIST, name))
const form = new FormData()
form.append('attachment', new Blob([buf]), name)
console.log(`Upload de ${name} (${(buf.length / 1e6).toFixed(1)} Mo)…`)
await api(
`/repos/${OWNER}/${REPO}/releases/${releaseId}/assets?name=${encodeURIComponent(name)}`,
{ method: 'POST', body: form }
)
}
async function main() {
const files = (await readdir(DIST)).filter(isUpdateArtifact)
if (!files.some((f) => f === 'latest.yml')) {
throw new Error('dist/latest.yml introuvable — lance dabord `npm run build:win`.')
}
console.log(`Publication sur ${OWNER}/${REPO} (tag ${TAG}) : ${files.join(', ')}`)
const release = await getOrCreateRelease()
await deleteExistingAssets(release.id)
for (const name of files) await uploadAsset(release.id, name)
console.log('✓ Publication terminée.')
}
main().catch((e) => {
console.error(e.message)
process.exit(1)
})