Bis jetzt stand nirgends, welcher Stand laeuft. Beim Aktualisieren auf einem Server ist das die erste Frage. CHANGELOG.md nach Keep a Changelog, Versionsnummern nach SemVer. Der Changelog sagt, was sich beim Arbeiten aendert - nicht, welche Datei angefasst wurde. Dazu eine Tabelle, was Major, Minor und Patch fuer den Betreiber praktisch bedeuten, und der Hinweis, dass sich eine Datenbank-Migration nicht zurueckrollen laesst. Die Version steht bewusst an zwei Stellen: package.json und src/lib/version.ts. Ein Import der package.json waere im Standalone-Build eine andere Datei als die des Projekts - die Zahl haenge dann an der Laufzeit. Ein Test haelt beide zusammen, und "npm run version" setzt sie gemeinsam samt Changelog-Abschnitt. Committet und getaggt wird nicht automatisch. Ein Changelog-Eintrag, den niemand gegengelesen hat, ist keinen Deut besser als keiner. Sichtbar wird die Version unten in der Seitenleiste und unter /api/gesundheit - dort mit Git-Stand, den der Docker-Build hineinreicht. Auf der Anmeldeseite steht sie nicht: wer nicht angemeldet ist, muss nicht wissen, welche Fassung hier laeuft. Etappe: 8 Phase: Haertung
138 lines
4.1 KiB
JavaScript
138 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Version anheben.
|
||
*
|
||
* npm run version -- patch 1.0.0 -> 1.0.1
|
||
* npm run version -- minor 1.0.0 -> 1.1.0
|
||
* npm run version -- major 1.0.0 -> 2.0.0
|
||
* npm run version -- 1.2.3 genau diese Version
|
||
*
|
||
* Was passiert:
|
||
* 1. package.json und src/lib/version.ts werden gesetzt - beide, damit
|
||
* sie nicht auseinanderlaufen.
|
||
* 2. Im CHANGELOG wird aus "## [Unveroeffentlicht]" ein Abschnitt mit
|
||
* Versionsnummer und heutigem Datum, darueber ein neuer leerer
|
||
* Abschnitt.
|
||
* 3. Der Vergleichslink am Dateiende wird nachgezogen.
|
||
*
|
||
* Was NICHT passiert: committen und taggen. Das machst du selbst, nachdem
|
||
* du den Changelog-Eintrag gegengelesen hast. Ein automatisch erzeugter
|
||
* Changelog, den niemand liest, ist keinen Deut besser als keiner.
|
||
*
|
||
* Danach:
|
||
* git add -A && git commit -m "chore: Version 1.0.1"
|
||
* git tag -a v1.0.1 -m "..." && git push --follow-tags
|
||
*/
|
||
import { readFileSync, writeFileSync } from 'node:fs'
|
||
|
||
const WURZEL = new URL('..', import.meta.url)
|
||
const pfad = (name) => new URL(name, WURZEL)
|
||
|
||
function lesen(name) {
|
||
return readFileSync(pfad(name), 'utf8')
|
||
}
|
||
|
||
function schreiben(name, inhalt) {
|
||
writeFileSync(pfad(name), inhalt, 'utf8')
|
||
console.log(` ${name}`)
|
||
}
|
||
|
||
// --- Ziel bestimmen ---------------------------------------------------------
|
||
|
||
const argument = process.argv[2]
|
||
if (!argument) {
|
||
console.error('Aufruf: npm run version -- <patch|minor|major|x.y.z>')
|
||
process.exit(1)
|
||
}
|
||
|
||
const paket = JSON.parse(lesen('package.json'))
|
||
const alt = paket.version
|
||
|
||
function naechste(aktuell, art) {
|
||
const treffer = aktuell.match(/^(\d+)\.(\d+)\.(\d+)$/)
|
||
if (!treffer) throw new Error(`Version "${aktuell}" ist kein x.y.z`)
|
||
const [haupt, neben, fehler] = treffer.slice(1).map(Number)
|
||
|
||
switch (art) {
|
||
case 'major':
|
||
return `${haupt + 1}.0.0`
|
||
case 'minor':
|
||
return `${haupt}.${neben + 1}.0`
|
||
case 'patch':
|
||
return `${haupt}.${neben}.${fehler + 1}`
|
||
default:
|
||
if (!/^\d+\.\d+\.\d+$/.test(art)) {
|
||
throw new Error(`"${art}" ist weder patch/minor/major noch x.y.z`)
|
||
}
|
||
return art
|
||
}
|
||
}
|
||
|
||
const neu = naechste(alt, argument)
|
||
if (neu === alt) {
|
||
console.error(`Version ist bereits ${alt}.`)
|
||
process.exit(1)
|
||
}
|
||
|
||
console.log(`\n${alt} -> ${neu}\n`)
|
||
console.log('Geaendert:')
|
||
|
||
// --- 1. package.json --------------------------------------------------------
|
||
|
||
paket.version = neu
|
||
schreiben('package.json', `${JSON.stringify(paket, null, 2)}\n`)
|
||
|
||
// --- 2. src/lib/version.ts --------------------------------------------------
|
||
|
||
const versionsdatei = lesen('src/lib/version.ts')
|
||
const ersetzt = versionsdatei.replace(
|
||
/export const VERSION = '[^']+'/,
|
||
`export const VERSION = '${neu}'`,
|
||
)
|
||
if (ersetzt === versionsdatei) {
|
||
console.error('FEHLER: VERSION in src/lib/version.ts nicht gefunden.')
|
||
process.exit(1)
|
||
}
|
||
schreiben('src/lib/version.ts', ersetzt)
|
||
|
||
// --- 3. CHANGELOG.md --------------------------------------------------------
|
||
|
||
const heute = new Date().toISOString().slice(0, 10)
|
||
let changelog = lesen('CHANGELOG.md')
|
||
|
||
const UNVEROEFFENTLICHT = '## [Unveröffentlicht]'
|
||
if (!changelog.includes(UNVEROEFFENTLICHT)) {
|
||
console.error(`FEHLER: "${UNVEROEFFENTLICHT}" steht nicht im CHANGELOG.`)
|
||
process.exit(1)
|
||
}
|
||
|
||
const leererAbschnitt = [
|
||
UNVEROEFFENTLICHT,
|
||
'',
|
||
'_Noch nichts._',
|
||
'',
|
||
`## [${neu}] – ${heute}`,
|
||
].join('\n')
|
||
|
||
changelog = changelog.replace(UNVEROEFFENTLICHT, leererAbschnitt)
|
||
|
||
// Vergleichslinks am Dateiende nachziehen.
|
||
const basis = 'https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare'
|
||
changelog = changelog.replace(
|
||
/^\[Unveröffentlicht\]:.*$/m,
|
||
`[Unveröffentlicht]: ${basis}/v${neu}...HEAD\n[${neu}]: ${basis}/v${alt}...v${neu}`,
|
||
)
|
||
|
||
schreiben('CHANGELOG.md', changelog)
|
||
|
||
// --- Hinweis ----------------------------------------------------------------
|
||
|
||
console.log(`
|
||
Jetzt:
|
||
1. CHANGELOG.md gegenlesen - steht dort, was sich fuer den Nutzer
|
||
tatsaechlich aendert? Nicht, welche Datei angefasst wurde.
|
||
2. git add -A && git commit -m "chore: Version ${neu}"
|
||
3. git tag -a v${neu} -m "Version ${neu}"
|
||
4. git push --follow-tags
|
||
`)
|