diff --git a/Docker/push.sh b/Docker/push.sh index 72d5f15..9c7c173 100644 --- a/Docker/push.sh +++ b/Docker/push.sh @@ -1,15 +1,19 @@ #!/usr/bin/env bash -# filepath: /home/lukas/Volume/repo/Aniworld/Docker/push.sh # -# Build and push Aniworld container images to the Gitea registry. +# Build and push AniWorld container images to the Gitea registry. # # Usage: -# ./push.sh # builds & pushes with tag "latest" -# ./push.sh v1.2.3 # builds & pushes with tag "v1.2.3" -# ./push.sh v1.2.3 --no-build # pushes existing images only +# ./push.sh # builds & pushes app with tag "latest" +# ./push.sh app # builds & pushes app image +# ./push.sh vpn # builds & pushes vpn image +# ./push.sh all # builds & pushes both images +# ./push.sh app v1.2.3 # builds & pushes app with tag "v1.2.3" +# ./push.sh vpn v1.2.3 # builds & pushes vpn with tag "v1.2.3" +# ./push.sh all v1.2.3 # builds & pushes both images +# ./push.sh app v1.2.3 --no-build # pushes existing image only # # Prerequisites: -# podman login git.lpl-mind.de +# podman login git.lpl-mind.de (or: docker login git.lpl-mind.de) set -euo pipefail @@ -23,12 +27,20 @@ PROJECT="aniworld" APP_IMAGE="${REGISTRY}/${NAMESPACE}/${PROJECT}/app" VPN_IMAGE="${REGISTRY}/${NAMESPACE}/${PROJECT}/vpn" -TAG="${1:-latest}" +# Parse arguments +TARGET="${1:-app}" +TAG="${2:-latest}" SKIP_BUILD=false -if [[ "${2:-}" == "--no-build" ]]; then +if [[ "${3:-}" == "--no-build" ]]; then SKIP_BUILD=true fi +# Validate target +if [[ "${TARGET}" != "app" && "${TARGET}" != "vpn" && "${TARGET}" != "all" ]]; then + echo "ERROR: Invalid target '${TARGET}'. Must be one of: app, vpn, all" >&2 + exit 1 +fi + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" @@ -36,62 +48,93 @@ PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" # Helpers # --------------------------------------------------------------------------- log() { echo -e "\n>>> $*"; } -err() { echo -e "\n❌ ERROR: $*" >&2; exit 1; } +err() { echo -e "\nERROR: $*" >&2; exit 1; } + +# Detect container engine (podman preferred, docker fallback) +if command -v podman &>/dev/null; then + ENGINE="podman" +elif command -v docker &>/dev/null; then + ENGINE="docker" +else + err "Neither podman nor docker is installed." +fi # --------------------------------------------------------------------------- # Pre-flight checks # --------------------------------------------------------------------------- echo "============================================" -echo " Aniworld — Build & Push" +echo " AniWorld — Build & Push" +echo " Engine : ${ENGINE}" echo " Registry : ${REGISTRY}" +echo " Target : ${TARGET}" echo " Tag : ${TAG}" echo "============================================" -command -v podman &>/dev/null || err "podman is not installed." - -if ! podman login --get-login "${REGISTRY}" &>/dev/null; then - err "Not logged in. Run:\n podman login ${REGISTRY}" -fi +log "Logging in to ${REGISTRY}" +"${ENGINE}" login "${REGISTRY}" # --------------------------------------------------------------------------- # Build # --------------------------------------------------------------------------- -if [[ "${SKIP_BUILD}" == false ]]; then +build_app() { log "Building app image → ${APP_IMAGE}:${TAG}" - podman build \ + "${ENGINE}" build \ -t "${APP_IMAGE}:${TAG}" \ -f "${SCRIPT_DIR}/Dockerfile.app" \ "${PROJECT_ROOT}" +} - log "Building VPN image → ${VPN_IMAGE}:${TAG}" - podman build \ +build_vpn() { + log "Building vpn image → ${VPN_IMAGE}:${TAG}" + "${ENGINE}" build \ -t "${VPN_IMAGE}:${TAG}" \ -f "${SCRIPT_DIR}/Containerfile" \ "${SCRIPT_DIR}" +} + +if [[ "${SKIP_BUILD}" == false ]]; then + case "${TARGET}" in + app) build_app ;; + vpn) build_vpn ;; + all) build_app; build_vpn ;; + esac fi # --------------------------------------------------------------------------- # Push # --------------------------------------------------------------------------- -log "Pushing ${APP_IMAGE}:${TAG}" -podman push "${APP_IMAGE}:${TAG}" +push_app() { + log "Pushing ${APP_IMAGE}:${TAG}" + "${ENGINE}" push "${APP_IMAGE}:${TAG}" +} -log "Pushing ${VPN_IMAGE}:${TAG}" -podman push "${VPN_IMAGE}:${TAG}" +push_vpn() { + log "Pushing ${VPN_IMAGE}:${TAG}" + "${ENGINE}" push "${VPN_IMAGE}:${TAG}" +} + +case "${TARGET}" in + app) push_app ;; + vpn) push_vpn ;; + all) push_app; push_vpn ;; +esac # --------------------------------------------------------------------------- # Summary # --------------------------------------------------------------------------- echo "" echo "============================================" -echo " ✅ Push complete!" +echo " Push complete!" echo "" echo " Images:" -echo " ${APP_IMAGE}:${TAG}" -echo " ${VPN_IMAGE}:${TAG}" +case "${TARGET}" in + app) echo " ${APP_IMAGE}:${TAG}" ;; + vpn) echo " ${VPN_IMAGE}:${TAG}" ;; + all) echo " ${APP_IMAGE}:${TAG}"; echo " ${VPN_IMAGE}:${TAG}" ;; +esac echo "" echo " Deploy on server:" -echo " podman login ${REGISTRY}" -echo " podman-compose -f podman-compose.prod.yml pull" -echo " podman-compose -f podman-compose.prod.yml up -d" +echo " ${ENGINE} login ${REGISTRY}" +echo " ${ENGINE} compose -f Docker/podman-compose.prod.yml pull" +echo " ${ENGINE} compose -f Docker/podman-compose.prod.yml up -d" echo "============================================" \ No newline at end of file diff --git a/Docker/release.sh b/Docker/release.sh new file mode 100644 index 0000000..8226160 --- /dev/null +++ b/Docker/release.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash +# +# Bump the project version and push images to the registry. +# +# Usage: +# ./release.sh +# +# The current version is stored in VERSION (next to this script). +# You will be asked whether to bump major, minor, or patch. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VERSION_FILE="${SCRIPT_DIR}/VERSION" + +# --------------------------------------------------------------------------- +# Read current version +# --------------------------------------------------------------------------- +if [[ ! -f "${VERSION_FILE}" ]]; then + echo "0.0.0" > "${VERSION_FILE}" +fi + +CURRENT="$(cat "${VERSION_FILE}")" +# Strip leading 'v' for arithmetic +VERSION="${CURRENT#v}" + +IFS='.' read -r MAJOR MINOR PATCH <<< "${VERSION}" + +echo "============================================" +echo " AniWorld — Release" +echo " Current version: v${MAJOR}.${MINOR}.${PATCH}" +echo "============================================" +echo "" +echo "Which image(s) would you like to release?" +echo " 1) app (Dockerfile.app)" +echo " 2) vpn (Containerfile)" +echo " 3) all (both images)" +echo "" +read -rp "Enter choice [1/2/3]: " TARGET_CHOICE + +case "${TARGET_CHOICE}" in + 1) TARGET="app" ;; + 2) TARGET="vpn" ;; + 3) TARGET="all" ;; + *) + echo "Invalid choice. Aborting." >&2 + exit 1 + ;; +esac + +echo "" +echo "How would you like to bump the version?" +echo " 1) patch (v${MAJOR}.${MINOR}.${PATCH} → v${MAJOR}.${MINOR}.$((PATCH + 1)))" +echo " 2) minor (v${MAJOR}.${MINOR}.${PATCH} → v${MAJOR}.$((MINOR + 1)).0)" +echo " 3) major (v${MAJOR}.${MINOR}.${PATCH} → v$((MAJOR + 1)).0.0)" +echo "" +read -rp "Enter choice [1/2/3]: " CHOICE + +case "${CHOICE}" in + 1) NEW_TAG="v${MAJOR}.${MINOR}.$((PATCH + 1))" ;; + 2) NEW_TAG="v${MAJOR}.$((MINOR + 1)).0" ;; + 3) NEW_TAG="v$((MAJOR + 1)).0.0" ;; + *) + echo "Invalid choice. Aborting." >&2 + exit 1 + ;; +esac + +echo "" +echo "New version: ${NEW_TAG}" +echo "Target: ${TARGET}" +read -rp "Confirm? [y/N]: " CONFIRM +if [[ ! "${CONFIRM}" =~ ^[yY]$ ]]; then + echo "Aborted." + exit 0 +fi + +# --------------------------------------------------------------------------- +# Write new version +# --------------------------------------------------------------------------- +echo "${NEW_TAG}" > "${VERSION_FILE}" +echo "Version file updated → ${VERSION_FILE}" + +# Keep root package.json in sync. +FRONT_VERSION="${NEW_TAG#v}" +FRONT_PKG="${SCRIPT_DIR}/../package.json" +if [[ -f "${FRONT_PKG}" ]]; then + sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"${FRONT_VERSION}\"/" "${FRONT_PKG}" + echo "package.json version updated → ${FRONT_VERSION}" +else + echo "Warning: package.json not found, skipping package.json version sync" >&2 +fi + +# Keep root pyproject.toml in sync. +BACKEND_PYPROJECT="${SCRIPT_DIR}/../pyproject.toml" +if [[ -f "${BACKEND_PYPROJECT}" ]]; then + # Update version under [project] section if present + if grep -q '^\[project\]' "${BACKEND_PYPROJECT}"; then + sed -i "/^\[project\]/,/^\[/ s/^version = \".*\"/version = \"${FRONT_VERSION}\"/" "${BACKEND_PYPROJECT}" + else + sed -i "s/^version = \".*\"/version = \"${FRONT_VERSION}\"/" "${BACKEND_PYPROJECT}" + fi + echo "pyproject.toml version updated → ${FRONT_VERSION}" +else + echo "Warning: pyproject.toml not found, skipping pyproject.toml version sync" >&2 +fi + +# --------------------------------------------------------------------------- +# Push containers +# --------------------------------------------------------------------------- +bash "${SCRIPT_DIR}/push.sh" "${TARGET}" "${NEW_TAG}" +bash "${SCRIPT_DIR}/push.sh" "${TARGET}" + + +# --------------------------------------------------------------------------- +# Git tag (local only; push after container build) +# --------------------------------------------------------------------------- +cd "${SCRIPT_DIR}/.." +git add Docker/VERSION package.json pyproject.toml +git commit -m "chore: release ${NEW_TAG}" +git tag -a "${NEW_TAG}" -m "Release ${NEW_TAG}" +echo "Local git commit + tag ${NEW_TAG} created." + +# --------------------------------------------------------------------------- +# Push git commits & tag +# --------------------------------------------------------------------------- +git push origin HEAD +git push origin "${NEW_TAG}" +echo "Git commit and tag ${NEW_TAG} pushed."