diff --git a/.gitea/workflows/dependency-audit.yml b/.gitea/workflows/dependency-audit.yml index 89e4a56..ceb7f45 100644 --- a/.gitea/workflows/dependency-audit.yml +++ b/.gitea/workflows/dependency-audit.yml @@ -41,19 +41,6 @@ jobs: .venv/bin/python -m pip install 'pip-audit>=2.9,<3' - name: Install WebUI release dependencies working-directory: webui - run: | - node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync('package.json')); const rel=JSON.parse(fs.readFileSync('package.release.json')); for (const key of ['dependencies','devDependencies','peerDependencies','optionalDependencies','overrides']) if (rel[key]) pkg[key]=rel[key]; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');" - rm -f package-lock.json - npm cache clean --force - for attempt in 1 2 3; do - if npm install --prefer-online; then - break - fi - if [ "$attempt" = 3 ]; then - exit 1 - fi - sleep $((attempt * 10)) - npm cache clean --force - done + run: bash ../scripts/install-webui-release-dependencies.sh . - name: Run dependency audits run: bash scripts/check-dependency-audits.sh diff --git a/.gitea/workflows/module-matrix.yml b/.gitea/workflows/module-matrix.yml index 511b451..32e9636 100644 --- a/.gitea/workflows/module-matrix.yml +++ b/.gitea/workflows/module-matrix.yml @@ -39,19 +39,6 @@ jobs: .venv/bin/python -m pip install '.[dev]' - name: Install WebUI release dependencies with test scripts working-directory: webui - run: | - node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync('package.json')); const rel=JSON.parse(fs.readFileSync('package.release.json')); for (const key of ['dependencies','devDependencies','peerDependencies','optionalDependencies','overrides']) if (rel[key]) pkg[key]=rel[key]; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');" - rm -f package-lock.json - npm cache clean --force - for attempt in 1 2 3; do - if npm install --prefer-online; then - break - fi - if [ "$attempt" = 3 ]; then - exit 1 - fi - sleep $((attempt * 10)) - npm cache clean --force - done + run: bash ../scripts/install-webui-release-dependencies.sh . - name: Run module matrix and contract tests run: bash scripts/check-module-matrix.sh diff --git a/.gitea/workflows/release-integration.yml b/.gitea/workflows/release-integration.yml index 04afd05..adc251c 100644 --- a/.gitea/workflows/release-integration.yml +++ b/.gitea/workflows/release-integration.yml @@ -39,19 +39,6 @@ jobs: .venv/bin/python -m pip install '.[dev]' - name: Install WebUI release dependencies working-directory: webui - run: | - node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync('package.json')); const rel=JSON.parse(fs.readFileSync('package.release.json')); for (const key of ['dependencies','devDependencies','peerDependencies','optionalDependencies','overrides']) if (rel[key]) pkg[key]=rel[key]; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');" - rm -f package-lock.json - npm cache clean --force - for attempt in 1 2 3; do - if npm install --prefer-online; then - break - fi - if [ "$attempt" = 3 ]; then - exit 1 - fi - sleep $((attempt * 10)) - npm cache clean --force - done + run: bash ../scripts/install-webui-release-dependencies.sh . - name: Run release integration checks run: bash scripts/check-release-integration.sh diff --git a/scripts/install-webui-release-dependencies.sh b/scripts/install-webui-release-dependencies.sh new file mode 100644 index 0000000..307adbd --- /dev/null +++ b/scripts/install-webui-release-dependencies.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +WEBUI_DIR="${1:-$ROOT/webui}" +WORK_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/govoplan-webui-release-deps.XXXXXXXX")" +GOVOPLAN_DEPS="$WORK_ROOT/govoplan-webui-deps.tsv" +export GOVOPLAN_DEPS + +trap 'rm -rf "$WORK_ROOT"' EXIT + +retry() { + local attempt status + for attempt in 1 2 3; do + if "$@"; then + return 0 + fi + status=$? + if [[ "$attempt" == 3 ]]; then + return "$status" + fi + sleep $((attempt * 10)) + done +} + +cd "$WEBUI_DIR" + +node <<'JS' +const fs = require("fs"); + +const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); +const rel = JSON.parse(fs.readFileSync("package.release.json", "utf8")); +const govoplanDeps = []; +const dependencies = {...(rel.dependencies || {})}; + +for (const [name, spec] of Object.entries(dependencies)) { + if (name.startsWith("@govoplan/")) { + govoplanDeps.push([name, spec]); + delete dependencies[name]; + } +} + +for (const key of ["devDependencies", "peerDependencies", "optionalDependencies", "overrides"]) { + if (rel[key]) pkg[key] = rel[key]; +} +pkg.dependencies = dependencies; + +fs.writeFileSync("package.json", JSON.stringify(pkg, null, 2) + "\n"); +fs.writeFileSync(process.env.GOVOPLAN_DEPS, govoplanDeps.map((item) => item.join("\t")).join("\n") + "\n"); +JS + +rm -f package-lock.json +npm cache clean --force +retry npm install --prefer-online + +module_paths=() +while IFS=$'\t' read -r package_name spec; do + [[ -n "${package_name:-}" ]] || continue + git_url="${spec%%#*}" + git_ref="${spec#*#}" + if [[ "$git_url" == "$spec" || -z "$git_ref" ]]; then + echo "Unsupported GovOPlaN WebUI git spec for $package_name: $spec" >&2 + exit 1 + fi + clone_url="${git_url#git+}" + clone_dir="$WORK_ROOT/${package_name#@govoplan/}" + echo "Installing $package_name from $clone_url#$git_ref" + retry git clone --depth 1 --branch "$git_ref" "$clone_url" "$clone_dir" + module_paths+=("file:$clone_dir") +done < "$GOVOPLAN_DEPS" + +if [[ "${#module_paths[@]}" -gt 0 ]]; then + retry npm install --prefer-online --no-save "${module_paths[@]}" +fi