#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" BACKEND_DIR="$ROOT_DIR/oa-backend" FRONTEND_DIR="$ROOT_DIR/ofbiz-framework/plugins/modern-ui/app" DIST_DIR="${ERP_RELEASE_DIST_DIR:-$ROOT_DIR/dist}" VERSION="${1:-${ERP_RELEASE_VERSION:-}}" PRIVATE_KEY="${ERP_RELEASE_PRIVATE_KEY_FILE:-}" REQUIRE_SIGNATURE="${ERP_REQUIRE_RELEASE_SIGNATURE:-1}" if [[ "$VERSION" == v* ]]; then VERSION="${VERSION#v}"; fi if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]]; then printf 'usage: %s \n' "$0" >&2 exit 2 fi for command in java jar npm tar openssl cmp; do command -v "$command" >/dev/null 2>&1 || { printf 'missing command: %s\n' "$command" >&2; exit 1; } done JAVA_MAJOR="$(java -version 2>&1 | awk -F'[".]' '/version/ {print $2; exit}')" [[ "$JAVA_MAJOR" =~ ^[0-9]+$ && "$JAVA_MAJOR" -ge 17 ]] \ || { printf 'Java 17 or newer is required\n' >&2; exit 1; } OPENSSL_VERSION="$(openssl version 2>/dev/null || true)" [[ "$OPENSSL_VERSION" =~ ^OpenSSL[[:space:]]3\. ]] \ || { printf 'OpenSSL 3 with Ed25519 support is required\n' >&2; exit 1; } OPENSSL_ALGORITHMS="$(openssl list -public-key-algorithms 2>/dev/null || true)" grep -qi ED25519 <<< "$OPENSSL_ALGORITHMS" \ || { printf 'OpenSSL 3 with Ed25519 support is required\n' >&2; exit 1; } if [[ "${ERP_SKIP_FRONTEND_BUILD:-0}" != "1" ]]; then ( cd "$FRONTEND_DIR" npm ci NODE_OPTIONS="${NODE_OPTIONS:---max-old-space-size=8192}" npm run build ) fi ( cd "$BACKEND_DIR" ./gradlew clean bootJar installerBootJar -PreleaseVersion="$VERSION" -PproductionBuild=true ) JAR="$BACKEND_DIR/build/libs/oa-backend-${VERSION}.jar" INSTALLER_JAR="$BACKEND_DIR/build/libs/kaidi-erp-installer-${VERSION}.jar" [[ -r "$JAR" ]] || { printf 'bootJar not found: %s\n' "$JAR" >&2; exit 1; } [[ -r "$INSTALLER_JAR" ]] || { printf 'installerBootJar not found: %s\n' "$INSTALLER_JAR" >&2; exit 1; } JAR_ENTRIES="$(jar tf "$JAR")" grep -Eq '^BOOT-INF/lib/postgresql-[^/]+\.jar$' <<< "$JAR_ENTRIES" \ || { printf 'production JAR is missing the PostgreSQL driver\n' >&2; exit 1; } if grep -Eq '^BOOT-INF/lib/(sqlite-jdbc|hibernate-community-dialects)-[^/]+\.jar$' <<< "$JAR_ENTRIES"; then printf 'production JAR must not contain SQLite runtime libraries\n' >&2 exit 1 fi INSTALLER_ENTRIES="$(jar tf "$INSTALLER_JAR")" grep -Eq '^BOOT-INF/lib/postgresql-[^/]+\.jar$' <<< "$INSTALLER_ENTRIES" \ || { printf 'installer JAR is missing the PostgreSQL driver\n' >&2; exit 1; } grep -q '^BOOT-INF/classes/static/index.html$' <<< "$INSTALLER_ENTRIES" \ || { printf 'installer JAR is missing the web setup page\n' >&2; exit 1; } if grep -Eq '^BOOT-INF/lib/(sqlite-jdbc|hibernate-community-dialects)-[^/]+\.jar$' <<< "$INSTALLER_ENTRIES"; then printf 'installer JAR must not contain SQLite runtime libraries\n' >&2 exit 1 fi mkdir -p "$DIST_DIR" STAGE="$(mktemp -d "${TMPDIR:-/tmp}/kaidi-erp-package.XXXXXX")" trap 'rm -rf "$STAGE"' EXIT PACKAGE_ROOT="$STAGE/kaidi-erp-${VERSION}" mkdir -p "$PACKAGE_ROOT/app" "$PACKAGE_ROOT/bin" "$PACKAGE_ROOT/config" cp "$JAR" "$PACKAGE_ROOT/app/kaidi-erp.jar" cp "$ROOT_DIR/distribution/bin/erp-run" "$PACKAGE_ROOT/bin/erp-run" cp "$ROOT_DIR/distribution/bin/erp-update" "$PACKAGE_ROOT/bin/erp-update" cp "$ROOT_DIR/distribution/release-public-key.pem" "$PACKAGE_ROOT/config/release-public-key.pem" chmod 755 "$PACKAGE_ROOT/bin/erp-run" "$PACKAGE_ROOT/bin/erp-update" printf '%s\n' "$VERSION" > "$PACKAGE_ROOT/VERSION" printf '{"version":"%s","database":"postgresql","minimumPostgres":15,"rollbackCompatible":true}\n' \ "$VERSION" > "$PACKAGE_ROOT/manifest.json" ARCHIVE="kaidi-erp-${VERSION}.tar.gz" INSTALLER_ASSET="kaidi-erp-installer-${VERSION}.jar" tar -czf "$DIST_DIR/$ARCHIVE" -C "$STAGE" "kaidi-erp-${VERSION}" cp "$INSTALLER_JAR" "$DIST_DIR/$INSTALLER_ASSET" if command -v sha256sum >/dev/null 2>&1; then (cd "$DIST_DIR" && sha256sum "$ARCHIVE" "$INSTALLER_ASSET" > SHA256SUMS) else (cd "$DIST_DIR" && shasum -a 256 "$ARCHIVE" "$INSTALLER_ASSET" > SHA256SUMS) fi if [[ -n "$PRIVATE_KEY" && -r "$PRIVATE_KEY" ]]; then GENERATED_PUBLIC_KEY="$STAGE/release-public-key.pem" openssl pkey -in "$PRIVATE_KEY" -pubout -out "$GENERATED_PUBLIC_KEY" >/dev/null 2>&1 cmp -s "$GENERATED_PUBLIC_KEY" "$ROOT_DIR/distribution/release-public-key.pem" \ || { printf 'release signing key does not match distribution/release-public-key.pem\n' >&2; exit 1; } openssl pkeyutl -sign -rawin -inkey "$PRIVATE_KEY" \ -in "$DIST_DIR/SHA256SUMS" -out "$DIST_DIR/SHA256SUMS.sig" elif [[ "$REQUIRE_SIGNATURE" == "1" ]]; then printf 'ERP_RELEASE_PRIVATE_KEY_FILE is required for signed releases\n' >&2 exit 1 else : > "$DIST_DIR/SHA256SUMS.sig" fi printf 'release assets:\n %s\n %s\n %s\n %s\n' \ "$DIST_DIR/$ARCHIVE" "$DIST_DIR/$INSTALLER_ASSET" \ "$DIST_DIR/SHA256SUMS" "$DIST_DIR/SHA256SUMS.sig"