Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e4a9ca3e1 | ||
|
|
51f876efd3 | ||
|
|
00893fa6be | ||
|
|
b5a068d3d8 | ||
|
|
dbdb3ecfc3 | ||
|
|
2a4edee192 | ||
|
|
fdb9771916 |
+2
-1
@@ -6,7 +6,8 @@ frontend/dist/
|
|||||||
|
|
||||||
# Omgevingsvariabelen (gebruik .env.example als sjabloon)
|
# Omgevingsvariabelen (gebruik .env.example als sjabloon)
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# Logs en rommel
|
# Logs en rommel
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -95,6 +95,42 @@ $env:GITEA_TOKEN = "<token>"
|
|||||||
Het script bouwt één image voor `linux/amd64` en `linux/arm64`, zodat dezelfde
|
Het script bouwt één image voor `linux/amd64` en `linux/arm64`, zodat dezelfde
|
||||||
tag op een Raspberry Pi en op een x86-server werkt.
|
tag op een Raspberry Pi en op een x86-server werkt.
|
||||||
|
|
||||||
|
### Tokens niet elke sessie opnieuw zetten
|
||||||
|
|
||||||
|
Staat er een `.env.release` naast `release.ps1`, dan leest het script die in
|
||||||
|
voordat er iets gebeurt. Handig voor stap 3, die anders elke nieuwe shell
|
||||||
|
opnieuw met de hand moet:
|
||||||
|
|
||||||
|
```
|
||||||
|
# .env.release — staat in .gitignore, hoort alleen op de release-machine
|
||||||
|
GITEA_TOKEN=<token met write:repository>
|
||||||
|
REGISTRY_USER=<gitea-gebruiker>
|
||||||
|
REGISTRY_TOKEN=<token met write:package>
|
||||||
|
```
|
||||||
|
|
||||||
|
Een variabele die al in je shell staat wint, zodat je per run kunt afwijken
|
||||||
|
zonder het bestand aan te passen. Het script logt alleen welke namen het heeft
|
||||||
|
geladen, nooit de waarden.
|
||||||
|
|
||||||
|
Twee **verschillende** tokens is hier de bedoeling: de registry heeft
|
||||||
|
`write:package` nodig en het aanmaken van een release `write:repository`. Eén
|
||||||
|
breed token voor beide werkt ook, maar dan gaat een repo-schrijfrecht mee bij
|
||||||
|
elke `docker push`.
|
||||||
|
|
||||||
|
> Een **404** in stap 5 betekent bijna altijd dat de token de repo niet mag
|
||||||
|
> zien: Gitea geeft op repo-endpoints 404 in plaats van 403, om niet te
|
||||||
|
> verklappen dat iets bestaat. Controleer dan eerst wie de token is en wat hij
|
||||||
|
> ziet:
|
||||||
|
>
|
||||||
|
> ```powershell
|
||||||
|
> $h = @{ Authorization = "token $env:GITEA_TOKEN" }
|
||||||
|
> (Invoke-RestMethod https://vibehoogie.duckdns.org/api/v1/user -Headers $h).login
|
||||||
|
> (Invoke-RestMethod https://vibehoogie.duckdns.org/api/v1/user/repos -Headers $h).full_name
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Staat de repo niet in die lijst, dan mist de token de repository-scope of
|
||||||
|
> hoort hij bij een account zonder toegang.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
@@ -107,6 +143,9 @@ docker compose pull && docker compose up -d
|
|||||||
docker compose down -v && docker compose up -d
|
docker compose down -v && docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Pullen vereist een registry-login op die host — zie
|
||||||
|
[Pullen op een deploy-machine](#pullen-op-een-deploy-machine).
|
||||||
|
|
||||||
### PostgreSQL versie-upgrade
|
### PostgreSQL versie-upgrade
|
||||||
|
|
||||||
Bij een upgrade van PostgreSQL (bijv. 16 → 18) is de bestaande data niet compatibel. Stappen:
|
Bij een upgrade van PostgreSQL (bijv. 16 → 18) is de bestaande data niet compatibel. Stappen:
|
||||||
@@ -302,6 +341,29 @@ Controleren wat er is opgeslagen:
|
|||||||
docker-credential-desktop list
|
docker-credential-desktop list
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Pullen op een deploy-machine
|
||||||
|
|
||||||
|
Het package is privé, dus ook een **pull** vereist een login — anoniem geeft
|
||||||
|
`401 Unauthorized` (`docker compose pull` meldt dan "no basic auth credentials"
|
||||||
|
of "pull access denied"). Eenmalig op de Docker-host:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker login vibehoogie.duckdns.org
|
||||||
|
# gebruikersnaam: je Gitea-account
|
||||||
|
# wachtwoord: access token met scope read:package
|
||||||
|
```
|
||||||
|
|
||||||
|
Daarna werkt `docker compose pull && docker compose up -d`. De login komt in
|
||||||
|
`~/.docker/config.json` van de gebruiker die het commando uitvoert — doe het dus
|
||||||
|
als dezelfde gebruiker (bij `sudo docker` is dat root). Log in op
|
||||||
|
`vibehoogie.duckdns.org` **zonder** `:3000`.
|
||||||
|
|
||||||
|
Controleren zonder te pullen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker manifest inspect vibehoogie.duckdns.org/vibe/vibefinance-app:latest
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Update-notificaties
|
## Update-notificaties
|
||||||
|
|||||||
@@ -1,5 +1,46 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [Niet vrijgegeven]
|
||||||
|
|
||||||
|
### Gewijzigd
|
||||||
|
- `release.ps1` leest een `.env.release` naast het script in (niet in git), zodat
|
||||||
|
`GITEA_TOKEN` en de registry-credentials niet elke shell opnieuw gezet hoeven
|
||||||
|
te worden; een variabele die al in de omgeving staat wint, en alleen de namen
|
||||||
|
worden gelogd
|
||||||
|
- `.gitignore` negeert nu alle `.env.*` op `.env.example` na — `.env.release`
|
||||||
|
zou anders door een `git add .` in git belanden
|
||||||
|
- `BEHEER.md` beschrijft welke token-scopes waarvoor nodig zijn
|
||||||
|
(`write:package` voor de registry, `write:repository` voor een release) en
|
||||||
|
hoe je een 404 in stap 5 nakijkt
|
||||||
|
- De draaiende versie komt uit de build in plaats van uit een bestand: de
|
||||||
|
frontend leest `__APP_VERSION__` via het nieuwe `src/version.js`, niet meer
|
||||||
|
rechtstreeks uit `frontend/package.json`. `vite.config.js` definieerde die
|
||||||
|
constante al, maar niets gebruikte hem — een productie-image gebouwd terwijl
|
||||||
|
er een `-dev` in `package.json` stond, sloeg de update-check stil helemaal
|
||||||
|
over
|
||||||
|
|
||||||
|
## [0.1.8] - 2026-09-09
|
||||||
|
|
||||||
|
### Gewijzigd
|
||||||
|
- `BEHEER.md` beschrijft de registry-login die een deploy-machine nodig heeft om
|
||||||
|
te kunnen pullen: het package is privé, dus ook `docker compose pull` vraagt
|
||||||
|
een token (`read:package`) — anoniem geeft de registry `401 Unauthorized`
|
||||||
|
- Testsuite dekt nu het serveren van de favicon, de cache-headers daarop en de
|
||||||
|
404 op ontbrekende bestanden
|
||||||
|
- `release.ps1 -DryRun` schrijft de frontend-versie niet meer echt weg: een
|
||||||
|
droogloop meldde de sync wél en voerde hem óók uit, waardoor er na een
|
||||||
|
`-DryRun` een gewijzigde `frontend/package.json` bleef liggen
|
||||||
|
|
||||||
|
### Opgelost
|
||||||
|
- De favicon bleef weg in de browser: `favicon.svg` en `icons/*` hebben geen
|
||||||
|
hash in hun naam, maar kregen wel een jaar `immutable` mee — een eenmaal
|
||||||
|
verkeerd gecacht antwoord revalideerde daardoor nooit meer. Alleen de
|
||||||
|
gehashte bundels in `/assets` houden die cache; de rest revalideert
|
||||||
|
- `/favicon.ico` en `/apple-touch-icon.png` gaven via de SPA-fallback
|
||||||
|
`index.html` terug met status 200 en `text/html` — de browser kreeg HTML waar
|
||||||
|
hij een icoon verwachtte en toonde stil niets, zonder zichtbare fout. Paden
|
||||||
|
met een bestandsextensie geven nu een echte 404
|
||||||
|
|
||||||
## [0.1.7] - 2026-09-08
|
## [0.1.7] - 2026-09-08
|
||||||
|
|
||||||
### Gewijzigd
|
### Gewijzigd
|
||||||
|
|||||||
+20
-7
@@ -5,7 +5,7 @@ import rateLimit from "express-rate-limit";
|
|||||||
import cookieParser from "cookie-parser";
|
import cookieParser from "cookie-parser";
|
||||||
import pinoHttp from "pino-http";
|
import pinoHttp from "pino-http";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
import { join } from "path";
|
import { extname, join, relative, sep } from "path";
|
||||||
import { config } from "./config/index.js";
|
import { config } from "./config/index.js";
|
||||||
import { logger } from "./logger.js";
|
import { logger } from "./logger.js";
|
||||||
import { initDb } from "./db.js";
|
import { initDb } from "./db.js";
|
||||||
@@ -73,21 +73,34 @@ const indexHtml = join(config.STATIC_DIR, "index.html");
|
|||||||
export const servesFrontend = existsSync(indexHtml);
|
export const servesFrontend = existsSync(indexHtml);
|
||||||
|
|
||||||
if (servesFrontend) {
|
if (servesFrontend) {
|
||||||
// Assets hebben een hash in de naam en mogen lang gecached worden;
|
// Alleen de bundels in /assets krijgen bij elke build een nieuwe, gehashte
|
||||||
// index.html juist nooit, anders blijft een oude build hangen.
|
// naam — die mogen een jaar blijven staan. Bestanden met een vaste naam
|
||||||
|
// (favicon.svg, icons/*) moeten revalideren: met "immutable" blijft een
|
||||||
|
// eenmaal verkeerd gecacht antwoord een jaar hangen, ook na een reload.
|
||||||
app.use(express.static(config.STATIC_DIR, {
|
app.use(express.static(config.STATIC_DIR, {
|
||||||
index: false,
|
index: false,
|
||||||
setHeaders(res, path) {
|
setHeaders(res, bestandspad) {
|
||||||
res.setHeader("Cache-Control", path.endsWith(".html")
|
const relatief = relative(config.STATIC_DIR, bestandspad).split(sep).join("/");
|
||||||
? "no-store, no-cache, must-revalidate"
|
if (bestandspad.endsWith(".html")) {
|
||||||
: "public, max-age=31536000, immutable");
|
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||||
|
} else if (relatief.startsWith("assets/")) {
|
||||||
|
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
||||||
|
} else {
|
||||||
|
res.setHeader("Cache-Control", "public, max-age=0, must-revalidate");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// SPA-fallback: alle overige GET-routes naar index.html. Pathloze middleware
|
// SPA-fallback: alle overige GET-routes naar index.html. Pathloze middleware
|
||||||
// in plaats van app.get("*") — dat patroon is in Express 5 ongeldig.
|
// in plaats van app.get("*") — dat patroon is in Express 5 ongeldig.
|
||||||
|
//
|
||||||
|
// Paden met een extensie vragen om een bestand (/favicon.ico, /robots.txt)
|
||||||
|
// en krijgen een echte 404. Anders levert zo'n verzoek index.html op met
|
||||||
|
// status 200 en content-type text/html: de browser krijgt HTML waar hij een
|
||||||
|
// icoon verwacht en toont dan niets, zonder zichtbare fout.
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
if (req.method !== "GET" && req.method !== "HEAD") return next();
|
if (req.method !== "GET" && req.method !== "HEAD") return next();
|
||||||
|
if (extname(req.path)) return next();
|
||||||
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||||
res.sendFile(indexHtml);
|
res.sendFile(indexHtml);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { join } from "node:path";
|
|||||||
|
|
||||||
const INDEX_MARKER = "<div id=\"root\"></div>";
|
const INDEX_MARKER = "<div id=\"root\"></div>";
|
||||||
const ASSET_BODY = "console.log('vibefinance');";
|
const ASSET_BODY = "console.log('vibefinance');";
|
||||||
|
const FAVICON_BODY = "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>";
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
let basis;
|
let basis;
|
||||||
@@ -23,6 +24,7 @@ before(async () => {
|
|||||||
mkdirSync(join(staticDir, "assets"));
|
mkdirSync(join(staticDir, "assets"));
|
||||||
writeFileSync(join(staticDir, "index.html"), `<!DOCTYPE html><html><body>${INDEX_MARKER}</body></html>`);
|
writeFileSync(join(staticDir, "index.html"), `<!DOCTYPE html><html><body>${INDEX_MARKER}</body></html>`);
|
||||||
writeFileSync(join(staticDir, "assets", "index-abc12345.js"), ASSET_BODY);
|
writeFileSync(join(staticDir, "assets", "index-abc12345.js"), ASSET_BODY);
|
||||||
|
writeFileSync(join(staticDir, "favicon.svg"), FAVICON_BODY);
|
||||||
|
|
||||||
process.env.NODE_ENV = "test";
|
process.env.NODE_ENV = "test";
|
||||||
process.env.STATIC_DIR = staticDir;
|
process.env.STATIC_DIR = staticDir;
|
||||||
@@ -93,6 +95,32 @@ describe("Frontend serveren", () => {
|
|||||||
assert.equal(await res.text(), ASSET_BODY);
|
assert.equal(await res.text(), ASSET_BODY);
|
||||||
assert.match(res.headers.get("cache-control") ?? "", /immutable/);
|
assert.match(res.headers.get("cache-control") ?? "", /immutable/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("favicon wordt geserveerd als svg", async () => {
|
||||||
|
const res = await fetch(`${basis}/favicon.svg`);
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.match(res.headers.get("content-type") ?? "", /image\/svg\+xml/);
|
||||||
|
assert.equal(await res.text(), FAVICON_BODY);
|
||||||
|
});
|
||||||
|
|
||||||
|
// De naam bevat geen hash, dus een jaar "immutable" zou een oude of
|
||||||
|
// verkeerde versie onhoudbaar lang in de browsercache vastzetten.
|
||||||
|
it("favicon wordt niet immutable gecached", async () => {
|
||||||
|
const res = await fetch(`${basis}/favicon.svg`);
|
||||||
|
const cache = res.headers.get("cache-control") ?? "";
|
||||||
|
assert.doesNotMatch(cache, /immutable/);
|
||||||
|
assert.match(cache, /must-revalidate/);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Anders krijgt de browser index.html met status 200 en content-type
|
||||||
|
// text/html waar hij een icoon verwacht, en toont hij stil niets.
|
||||||
|
it("ontbrekend bestand geeft 404 in plaats van index.html", async () => {
|
||||||
|
for (const pad of ["/favicon.ico", "/apple-touch-icon.png"]) {
|
||||||
|
const res = await fetch(`${basis}${pad}`);
|
||||||
|
assert.equal(res.status, 404, pad);
|
||||||
|
assert.doesNotMatch(await res.text(), new RegExp(INDEX_MARKER), pad);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Security headers", () => {
|
describe("Security headers", () => {
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ export default [
|
|||||||
languageOptions: {
|
languageOptions: {
|
||||||
ecmaVersion: "latest",
|
ecmaVersion: "latest",
|
||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
globals: { ...globals.browser },
|
// Door Vite ingebakken tijdens de build (define in vite.config.js)
|
||||||
|
globals: { ...globals.browser, __APP_VERSION__: "readonly" },
|
||||||
parserOptions: { ecmaFeatures: { jsx: true } },
|
parserOptions: { ecmaFeatures: { jsx: true } },
|
||||||
},
|
},
|
||||||
settings: { react: { version: "detect" } },
|
settings: { react: { version: "detect" } },
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vibefinance-frontend",
|
"name": "vibefinance-frontend",
|
||||||
"version": "0.1.6",
|
"version": "0.1.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import SchuldTab from "./pages/SchuldTab.jsx";
|
|||||||
import VoortgangTab from "./pages/VoortgangTab.jsx";
|
import VoortgangTab from "./pages/VoortgangTab.jsx";
|
||||||
import { RED, PURPLE_LIGHT } from "./constants/index.js";
|
import { RED, PURPLE_LIGHT } from "./constants/index.js";
|
||||||
import { fmt } from "./utils/format.js";
|
import { fmt } from "./utils/format.js";
|
||||||
import { version } from "../package.json";
|
import { version } from "./version.js";
|
||||||
import { useUpdateCheck } from "./hooks/useUpdateCheck.js";
|
import { useUpdateCheck } from "./hooks/useUpdateCheck.js";
|
||||||
import ProfielPopup from "./components/ProfielPopup.jsx";
|
import ProfielPopup from "./components/ProfielPopup.jsx";
|
||||||
import InstellingenModal from "./components/InstellingenModal.jsx";
|
import InstellingenModal from "./components/InstellingenModal.jsx";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { TABS } from "../constants/index.js";
|
import { TABS } from "../constants/index.js";
|
||||||
import { version } from "../../package.json";
|
import { version } from "../version.js";
|
||||||
import { useUpdateCheck } from "../hooks/useUpdateCheck.js";
|
import { useUpdateCheck } from "../hooks/useUpdateCheck.js";
|
||||||
import { useApp } from "../context/AppContext.jsx";
|
import { useApp } from "../context/AppContext.jsx";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { version } from "../../package.json";
|
import { version } from "../version.js";
|
||||||
|
|
||||||
// De check loopt via de eigen backend (/api/update-check): de Gitea API stuurt
|
// De check loopt via de eigen backend (/api/update-check): de Gitea API stuurt
|
||||||
// geen CORS-headers, dus de browser mag die niet direct bevragen.
|
// geen CORS-headers, dus de browser mag die niet direct bevragen.
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// Draaiende versie, tijdens de build ingebakken door Vite (`define` in
|
||||||
|
// vite.config.js). Die leest VITE_APP_VERSION uit de omgeving — de build-arg
|
||||||
|
// die de Dockerfile en release.ps1 doorgeven — en valt terug op de versie uit
|
||||||
|
// package.json wanneer die niet gezet is (dev-server, `npm run build` los).
|
||||||
|
//
|
||||||
|
// Niet rechtstreeks uit package.json importeren: dan hangt de versie aan een
|
||||||
|
// bestand in plaats van aan de build, en checkt een image dat gebouwd is met
|
||||||
|
// een `-dev` in package.json stil nooit meer op updates.
|
||||||
|
export const version = __APP_VERSION__;
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vibefinance",
|
"name": "vibefinance",
|
||||||
"version": "0.1.7",
|
"version": "0.1.9",
|
||||||
"description": "VibeFinance — persoonlijk vermogensbeheer",
|
"description": "VibeFinance — persoonlijk vermogensbeheer",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "https://vibehoogie.duckdns.org/vibe/VibeFinance",
|
"repository": "https://vibehoogie.duckdns.org/vibe/VibeFinance",
|
||||||
|
|||||||
+32
-3
@@ -28,6 +28,29 @@ param(
|
|||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# ── Geheimen uit .env.release ──────────────────────────────────────────────
|
||||||
|
# Staat niet in git (.gitignore) en bestaat alleen op de release-machine, zodat
|
||||||
|
# GITEA_TOKEN niet elke sessie met de hand gezet hoeft te worden. Een variabele
|
||||||
|
# die al in de omgeving staat wint, zodat je per run kunt afwijken.
|
||||||
|
$envFile = Join-Path $PSScriptRoot ".env.release"
|
||||||
|
if (Test-Path $envFile) {
|
||||||
|
$geladen = @()
|
||||||
|
foreach ($regel in Get-Content $envFile) {
|
||||||
|
if ($regel -notmatch '^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$') { continue }
|
||||||
|
$naam = $Matches[1]
|
||||||
|
$waarde = $Matches[2].Trim().Trim('"').Trim("'")
|
||||||
|
if (-not $waarde) { continue }
|
||||||
|
# Al gezet in de shell? Dan die laten staan.
|
||||||
|
if ([Environment]::GetEnvironmentVariable($naam)) { continue }
|
||||||
|
[Environment]::SetEnvironmentVariable($naam, $waarde)
|
||||||
|
$geladen += $naam
|
||||||
|
}
|
||||||
|
# Alleen de namen loggen, nooit de waarden.
|
||||||
|
if ($geladen) {
|
||||||
|
Write-Host "Geheimen geladen uit .env.release: $($geladen -join ', ')" -ForegroundColor DarkGray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
# ── PROJECTCONFIGURATIE — pas alleen dit blok aan voor een nieuw project ──
|
# ── PROJECTCONFIGURATIE — pas alleen dit blok aan voor een nieuw project ──
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
@@ -53,12 +76,18 @@ if ($appVersion -match "-dev$") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ── Versie synchroniseren naar frontend/package.json ──────────────────────
|
# ── Versie synchroniseren naar frontend/package.json ──────────────────────
|
||||||
|
# Een droogloop schrijft hier niet: anders laat -DryRun een gewijzigd bestand
|
||||||
|
# achter, en tagt de echte release daarna een vervuilde working tree.
|
||||||
$frontendPkgPath = Join-Path $PSScriptRoot "frontend/package.json"
|
$frontendPkgPath = Join-Path $PSScriptRoot "frontend/package.json"
|
||||||
$frontendPkg = Get-Content $frontendPkgPath -Raw | ConvertFrom-Json
|
$frontendPkg = Get-Content $frontendPkgPath -Raw | ConvertFrom-Json
|
||||||
if ($frontendPkg.version -ne $appVersion) {
|
if ($frontendPkg.version -ne $appVersion) {
|
||||||
$frontendPkg.version = $appVersion
|
if ($DryRun) {
|
||||||
[System.IO.File]::WriteAllText($frontendPkgPath, ($frontendPkg | ConvertTo-Json -Depth 10))
|
Write-Host "[DRY-RUN] Versie naar frontend synchroniseren: $($frontendPkg.version) -> $appVersion" -ForegroundColor Yellow
|
||||||
Write-Host "Versie gesynchroniseerd naar frontend: $appVersion" -ForegroundColor Green
|
} else {
|
||||||
|
$frontendPkg.version = $appVersion
|
||||||
|
[System.IO.File]::WriteAllText($frontendPkgPath, ($frontendPkg | ConvertTo-Json -Depth 10))
|
||||||
|
Write-Host "Versie gesynchroniseerd naar frontend: $appVersion" -ForegroundColor Green
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$gitTag = "$appVersion"
|
$gitTag = "$appVersion"
|
||||||
|
|||||||
Reference in New Issue
Block a user