fix: fix release
This commit is contained in:
+75
-41
@@ -1,18 +1,18 @@
|
||||
#!/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.
|
||||
* Publie les artefacts du launcher sur deux releases Gitea :
|
||||
*
|
||||
* Pré-requis :
|
||||
* - `npm run build:win` a produit dist/ (latest.yml + installeur + .blockmap)
|
||||
* - variable d'env GITEA_TOKEN (scope write:repository)
|
||||
* 1. Release à tag fixe "latest" — electron-updater (provider generic) lit
|
||||
* latest.yml à cette URL pour proposer les mises à jour automatiques.
|
||||
*
|
||||
* Config par variables d'env (avec valeurs par défaut) :
|
||||
* 2. Release versionnée "vX.Y.Z" — archive permanente consultable dans l'UI
|
||||
* Gitea, utile pour le suivi des versions et les téléchargements manuels.
|
||||
*
|
||||
* Config par variables d'env :
|
||||
* 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)
|
||||
* GITEA_TOKEN token write:repository (obligatoire)
|
||||
*/
|
||||
import { readdir, readFile } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
@@ -20,7 +20,6 @@ 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')
|
||||
@@ -31,12 +30,16 @@ if (!TOKEN) {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
/** Lit la version courante depuis package.json. */
|
||||
async function readVersion() {
|
||||
const pkg = JSON.parse(await readFile(join(process.cwd(), 'package.json'), 'utf8'))
|
||||
return pkg.version // ex. "3.1.0"
|
||||
}
|
||||
|
||||
/**
|
||||
* Fichiers de dist/ à publier pour l'auto-update.
|
||||
* - Windows : latest.yml + l'installeur NSIS (+ .blockmap)
|
||||
* - Linux : latest-linux.yml + l'AppImage (+ .blockmap) ; le .deb est publié
|
||||
* pour téléchargement manuel (electron-updater ne l'utilise pas).
|
||||
* electron-updater choisit le bon latest*.yml selon la plateforme.
|
||||
* Fichiers de dist/ à publier.
|
||||
* - Windows : latest.yml + installeur NSIS (+ .blockmap)
|
||||
* - Linux : latest-linux.yml + AppImage (+ .blockmap) + .deb
|
||||
*/
|
||||
function isUpdateArtifact(name) {
|
||||
return (
|
||||
@@ -61,65 +64,96 @@ async function api(path, init = {}) {
|
||||
})
|
||||
if (!res.ok) {
|
||||
const body = await res.text().catch(() => '')
|
||||
throw new Error(`Gitea ${init.method ?? 'GET'} ${path} -> ${res.status} ${body}`)
|
||||
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}`, {
|
||||
/** Récupère la release par tag, ou la crée avec les options données. */
|
||||
async function getOrCreateRelease(tag, createBody) {
|
||||
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()}`)
|
||||
throw new Error(`Gitea GET release/${tag} → ${res.status} ${await res.text()}`)
|
||||
}
|
||||
console.log(`Création de la release "${TAG}"…`)
|
||||
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 d’auto-update du launcher (écrasés à chaque publication).'
|
||||
})
|
||||
body: JSON.stringify(createBody)
|
||||
})
|
||||
}
|
||||
|
||||
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}…`)
|
||||
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 uploadAssets(releaseId, files) {
|
||||
for (const name of files) {
|
||||
const buf = await readFile(join(DIST, name))
|
||||
const form = new FormData()
|
||||
form.append('attachment', new Blob([buf]), name)
|
||||
console.log(` Upload "${name}" (${(buf.length / 1e6).toFixed(1)} Mo)…`)
|
||||
await api(
|
||||
`/repos/${OWNER}/${REPO}/releases/${releaseId}/assets?name=${encodeURIComponent(name)}`,
|
||||
{ method: 'POST', body: form }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function publishRelease(tag, createBody, files) {
|
||||
console.log(`\n── Release "${tag}" ──`)
|
||||
const release = await getOrCreateRelease(tag, createBody)
|
||||
await deleteExistingAssets(release.id)
|
||||
await uploadAssets(release.id, files)
|
||||
console.log(` ✓ Release "${tag}" publiée.`)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const version = await readVersion()
|
||||
const versionTag = `v${version}`
|
||||
|
||||
const files = (await readdir(DIST)).filter(isUpdateArtifact)
|
||||
if (!files.some((f) => f === 'latest.yml')) {
|
||||
throw new Error('dist/latest.yml introuvable — lance d’abord `npm run build:win`.')
|
||||
throw new Error('dist/latest.yml introuvable — lance d'abord `npm run build:win`.')
|
||||
}
|
||||
console.log(`Publication sur ${OWNER}/${REPO} (tag ${TAG}) : ${files.join(', ')}`)
|
||||
console.log(`Version : ${versionTag}`)
|
||||
console.log(`Artefacts : ${files.join(', ')}`)
|
||||
console.log(`Dépôt : ${OWNER}/${REPO}`)
|
||||
|
||||
const release = await getOrCreateRelease()
|
||||
await deleteExistingAssets(release.id)
|
||||
for (const name of files) await uploadAsset(release.id, name)
|
||||
// 1. Release fixe "latest" — point d'ancrage de l'auto-update.
|
||||
await publishRelease(
|
||||
'latest',
|
||||
{
|
||||
tag_name: 'latest',
|
||||
name: 'Auto-update (dernière version)',
|
||||
body: 'Artefacts d'auto-update écrasés à chaque publication. Version courante : ' + versionTag,
|
||||
prerelease: false
|
||||
},
|
||||
files
|
||||
)
|
||||
|
||||
console.log('✓ Publication terminée.')
|
||||
// 2. Release versionnée — archive permanente par version.
|
||||
await publishRelease(
|
||||
versionTag,
|
||||
{
|
||||
tag_name: versionTag,
|
||||
name: `OFLauncher ${versionTag}`,
|
||||
body: '',
|
||||
prerelease: false
|
||||
},
|
||||
files
|
||||
)
|
||||
|
||||
console.log('\n✓ Publication terminée.')
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
|
||||
Reference in New Issue
Block a user