From 8d0db9beba29b8774a09fa45170bab35c7685aaa Mon Sep 17 00:00:00 2001 From: TDPI Date: Mon, 13 Jul 2026 13:31:51 +0200 Subject: [PATCH] feat: first release --- .dockerignore | 4 +++ .env.example | 10 ++++-- .gitea/workflows/build-docker.yml | 33 +++++++++++-------- .gitea/workflows/create-release-pr.yml | 2 +- .gitea/workflows/create-release.yml | 4 +-- .release-please-manifest.json | 3 ++ README.md | 23 ++++++++------ docker-compose.yml | 35 ++++++++++++++++++++ docker/docker-compose.example.yml | 44 -------------------------- 9 files changed, 85 insertions(+), 73 deletions(-) create mode 100644 .release-please-manifest.json create mode 100644 docker-compose.yml delete mode 100644 docker/docker-compose.example.yml diff --git a/.dockerignore b/.dockerignore index a5b3f86..5fecb63 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,6 +8,10 @@ __pycache__/ .env .env.example docker/ +docker-compose.yml +.gitea/ +.release-please-manifest.json +CHANGELOG.md README.md # Local dev runtime dirs data/ diff --git a/.env.example b/.env.example index ec38827..0bea4d5 100644 --- a/.env.example +++ b/.env.example @@ -22,9 +22,15 @@ DOCKHAND_VERIFY_TLS=true # --- Timezone (display, filenames, cron) --- TZ=Europe/Berlin -# --- Paths (usually only set inside Docker) --- +# --- Prod deployment (docker-compose.yml reads these for HOST paths) --- +# Where the .tar files land / where config.json is persisted on the host: +BACKUP_DIR=/mnt/user/backups/stacks +CONFIG_DIR=/mnt/user/appdata/dockhand-backup +# Host root that gets mounted read-only (source of the bind paths to back up): +BIND_ROOT=/mnt/user + +# --- Container-internal paths (rarely changed) --- # BACKUP_ROOT=/backup -# DATA_DIR=/data # --- Authentik OIDC for THIS tool's web UI (optional) --- # Leave empty to keep the UI open (e.g. behind a reverse proxy). diff --git a/.gitea/workflows/build-docker.yml b/.gitea/workflows/build-docker.yml index d13bdb3..72c11c5 100644 --- a/.gitea/workflows/build-docker.yml +++ b/.gitea/workflows/build-docker.yml @@ -6,46 +6,51 @@ on: permissions: contents: write +env: + REGISTRY: git.tdpi.dev + IMAGE: git.tdpi.dev/tdpi/Dockhand_Backup + REPO_SLUG: TDPI/Dockhand_Backup + jobs: deploy: name: Build + Push to Packages + Deploy to Prod runs-on: ubuntu-latest - + steps: - name: Checkout Repo uses: actions/checkout@v4 with: fetch-depth: 0 - + - name: Set image tag id: vars run: | - # Extrahiert den Tag-Namen direkt aus dem Release-Event (z.B. v1.17.8) + # Tag-Name direkt aus dem Release-Event (z.B. v1.2.3) TAG="${{ gitea.event.release.tag_name }}" - # Der Tag-Name enthält bereits das 'v' echo "TAG=$TAG" >> "$GITHUB_ENV" - + - name: Login to Gitea Packages run: | - echo "${{ secrets.GT_TOKEN }}" | docker login git.tdpi.dev -u ${{ gitea.actor }} --password-stdin - + echo "${{ secrets.GT_TOKEN }}" | docker login ${REGISTRY} -u ${{ gitea.actor }} --password-stdin + - name: Build Image run: | - docker build -t git.tdpi.dev/tdpi/shopify-helper:${TAG} . - docker tag git.tdpi.dev/tdpi/shopify-helper:${TAG} git.tdpi.dev/tdpi/shopify-helper:latest + # Dockerfile liegt in docker/, Build-Context ist das Repo-Root. + docker build -f docker/Dockerfile -t ${IMAGE}:${TAG} . + docker tag ${IMAGE}:${TAG} ${IMAGE}:latest - name: Update docker-compose.yml tag env: GIT_TOKEN: ${{ secrets.GT_TOKEN }} run: | - sed -i "s|image: git.tdpi.dev/tdpi/shopify-helper:.*|image: git.tdpi.dev/tdpi/shopify-helper:${TAG}|" docker-compose.yml + sed -i "s|image: ${IMAGE}:.*|image: ${IMAGE}:${TAG}|" docker-compose.yml git config user.name "Gitea Actions" git config user.email "actions@git.tdpi.dev" git add docker-compose.yml - git commit -m "chore: update docker-compose tag to ${TAG}" - git push https://x-access-token:${GIT_TOKEN}@git.tdpi.dev/TDPI/Shopify-Helper.git HEAD:main + git commit -m "chore: update docker-compose tag to ${TAG}" || echo "no changes to commit" + git push https://x-access-token:${GIT_TOKEN}@${REGISTRY}/${REPO_SLUG}.git HEAD:main - name: Push Image run: | - docker push git.tdpi.dev/tdpi/shopify-helper:${TAG} - docker push git.tdpi.dev/tdpi/shopify-helper:latest \ No newline at end of file + docker push ${IMAGE}:${TAG} + docker push ${IMAGE}:latest diff --git a/.gitea/workflows/create-release-pr.yml b/.gitea/workflows/create-release-pr.yml index 83b32f5..5c7e310 100644 --- a/.gitea/workflows/create-release-pr.yml +++ b/.gitea/workflows/create-release-pr.yml @@ -32,7 +32,7 @@ jobs: - name: Create Release PR env: GIT_TOKEN: ${{ secrets.GT_TOKEN }} - REPO: "TDPI/Shopify-Helper" + REPO: "TDPI/Dockhand_Backup" run: | python3 << 'EOF' import re diff --git a/.gitea/workflows/create-release.yml b/.gitea/workflows/create-release.yml index 1efd0a6..983ff09 100644 --- a/.gitea/workflows/create-release.yml +++ b/.gitea/workflows/create-release.yml @@ -33,7 +33,7 @@ jobs: git config user.name "Gitea Actions" git config user.email "actions@git.tdpi.dev" git tag -a "v${{ steps.version.outputs.version }}" -m "Release v${{ steps.version.outputs.version }}" - git push https://x-access-token:${GIT_TOKEN}@git.tdpi.dev/TDPI/Shopify-Helper.git "v${{ steps.version.outputs.version }}" + git push https://x-access-token:${GIT_TOKEN}@git.tdpi.dev/TDPI/Dockhand_Backup.git "v${{ steps.version.outputs.version }}" - name: Create Release env: @@ -51,7 +51,7 @@ jobs: '{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}') # Führt den Curl-Befehl mit der sicheren Payload aus - curl -X POST "https://git.tdpi.dev/api/v1/repos/TDPI/Shopify-Helper/releases" \ + curl -X POST "https://git.tdpi.dev/api/v1/repos/TDPI/Dockhand_Backup/releases" \ -H "Authorization: token $GIT_TOKEN" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..e18ee07 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.0.0" +} diff --git a/README.md b/README.md index d661c98..8c30505 100644 --- a/README.md +++ b/README.md @@ -63,17 +63,18 @@ sichern), setze `DOCKHAND_URL`/`DOCKHAND_USER`/`DOCKHAND_PASS`. ## Deployment (Docker / Unraid) +Die Prod-Compose (`docker-compose.yml`) zieht das fertige Image aus der Gitea-Registry und +liest **alle** Werte aus einer `.env` daneben (nichts Sensibles im Repo). Kein Port-Mapping — +der Container hängt im externen Netzwerk `nginx` hinter dem Reverse-Proxy. + ```bash -cp docker/docker-compose.example.yml docker-compose.yml -# Pfade, Secrets und OIDC anpassen -docker compose up -d --build +cp .env.example .env # Secrets/Pfade eintragen (DOCKHAND_*, FLASK_SECRET_KEY, BACKUP_DIR, ...) +docker compose up -d ``` -Die UI läuft auf Port `8080`. Wichtige Env-Vars: `DOCKHAND_URL`, `DOCKHAND_USER`, -`DOCKHAND_PASS`, `DOCKHAND_ENV_ID`, `FLASK_SECRET_KEY`, optional `OIDC_*`. - -Der Build kompiliert Tailwind mit der Standalone-CLI in `app/static/app.css` — zur Laufzeit -wird **kein CDN** benötigt. +Voraussetzung: das externe Docker-Netzwerk `nginx` existiert und das Image wurde per CI +gebaut/gepusht (siehe `.gitea/workflows/`). Das Image kompiliert Tailwind mit der +Standalone-CLI in `app/static/app.css` — zur Laufzeit wird **kein CDN** benötigt. ## Projektstruktur @@ -88,8 +89,10 @@ app/ # Python-Package routes.py # Flask-Routes templates/ # Jinja + Tailwind static/ # src.css, app.css (build), vendor/sortable.min.js -docker/ # Dockerfile + compose-Beispiel (NICHT im Image) -wsgi.py # Entrypoint +docker/Dockerfile # Multi-stage build (NICHT im Image) +docker-compose.yml # Prod-Compose (Registry-Image, .env-gesteuert) +.gitea/workflows/ # CI: build+push Image, Release-Automation +wsgi.py # Entrypoint ``` ## Hinweis diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5c0302f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,35 @@ +# Production compose — pulls the pre-built image from the Gitea registry. +# The "Deploy on Release" workflow bumps the image tag on this file. +# ALL config comes from a .env next to this file (NOT committed). No secrets here. +services: + dockhand-backup: + image: git.tdpi.dev/tdpi/Dockhand_Backup:latest + container_name: dockhand-backup + restart: unless-stopped + environment: + DOCKHAND_URL: "${DOCKHAND_URL}" + DOCKHAND_USER: "${DOCKHAND_USER}" + DOCKHAND_PASS: "${DOCKHAND_PASS}" + DOCKHAND_PROVIDER: "${DOCKHAND_PROVIDER:-local}" + DOCKHAND_ENV_ID: "${DOCKHAND_ENV_ID}" + DOCKHAND_VERIFY_TLS: "${DOCKHAND_VERIFY_TLS:-true}" + FLASK_SECRET_KEY: "${FLASK_SECRET_KEY}" + OIDC_ISSUER: "${OIDC_ISSUER:-}" + OIDC_CLIENT_ID: "${OIDC_CLIENT_ID:-}" + OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET:-}" + OIDC_REDIRECT_URI: "${OIDC_REDIRECT_URI:-}" + TZ: "${TZ:-Europe/Berlin}" + volumes: + - /mnt/user/backup/docker:/backup + - /mnt/cache/appdata/backupdocker:/data + # Mount ONLY the host paths you want backed up, identically mapped. + # Anything not mounted (or switched off per bind in the UI) is skipped. + - /mnt/cache/appdata:/mnt/cache/appdata + - /mnt/docker/appdata:/mnt/docker/appdata + - /mnt/user/appdata:/mnt/user/appdata + networks: + - nginx + +networks: + nginx: + external: true diff --git a/docker/docker-compose.example.yml b/docker/docker-compose.example.yml deleted file mode 100644 index 495f75e..0000000 --- a/docker/docker-compose.example.yml +++ /dev/null @@ -1,44 +0,0 @@ -# Example deployment for Unraid / Docker. -# Copy to docker-compose.yml, adjust paths & secrets, then: docker compose up -d --build -services: - dockhand-backup: - build: - context: .. - dockerfile: docker/Dockerfile - image: dockhand-backup:latest - container_name: dockhand-backup - restart: unless-stopped - ports: - - "8080:8080" - environment: - # --- Dockhand connection (daemon logs in with these) --- - DOCKHAND_URL: "http://192.168.1.10:3000" - DOCKHAND_USER: "backup-service" - DOCKHAND_PASS: "change-me" - DOCKHAND_PROVIDER: "local" # local user/password login in Dockhand - DOCKHAND_ENV_ID: "1" - DOCKHAND_VERIFY_TLS: "true" - - # --- Flask --- - FLASK_SECRET_KEY: "generate-a-long-random-string" - - # --- Authentik OIDC for THIS tool's web UI (optional) --- - # Leave unset to run the UI open (e.g. behind a reverse proxy). - OIDC_ISSUER: "" # e.g. https://auth.example.com/application/o/dockhand-backup/ - OIDC_CLIENT_ID: "" - OIDC_CLIENT_SECRET: "" - OIDC_REDIRECT_URI: "" # e.g. https://backup.example.com/callback - - TZ: "Europe/Berlin" - # DEV_MODE auto-off inside Docker; force with DEV_MODE: "false" if needed. - volumes: - # Backup output — pick where the .tar files land on the host: - - /mnt/user/backups/stacks:/backup - - # JSON "DB" / config persistence: - - /mnt/user/appdata/dockhand-backup:/data - - # IMPORTANT: bind-mount host paths must exist INSIDE the container at the - # SAME absolute path Dockhand reports. Mount ONLY what you want backed up — - # anything not mounted (or switched off per bind in the UI) is skipped. - - /mnt/user:/mnt/user:ro