mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-09-21 20:40:47 +02:00
release: default to Web UI in Docker image, add HEALTHCHECK and APP_VERSION; CI smoke test; compose docs and dockerhub compose file
This commit is contained in:
parent
9357a04541
commit
be672ac5d2
6 changed files with 96 additions and 4 deletions
24
.github/workflows/dockerhub-publish.yml
vendored
24
.github/workflows/dockerhub-publish.yml
vendored
|
@ -32,6 +32,7 @@ jobs:
|
||||||
# Escape newlines for label usage
|
# Escape newlines for label usage
|
||||||
DESC=$(awk 'BEGIN{ORS="\\n"} {print}' RELEASE_NOTES.md)
|
DESC=$(awk 'BEGIN{ORS="\\n"} {print}' RELEASE_NOTES.md)
|
||||||
echo "desc=$DESC" >> $GITHUB_OUTPUT
|
echo "desc=$DESC" >> $GITHUB_OUTPUT
|
||||||
|
echo "version=$VERSION_REF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
@ -39,6 +40,26 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Smoke test image boots Web UI by default (amd64)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Build a local test image (amd64) and load into docker
|
||||||
|
docker buildx build --platform linux/amd64 --load -t mtg-deckbuilder:test --build-arg APP_VERSION=${{ steps.notes.outputs.version }} .
|
||||||
|
# Run container and wait for it to serve on 8080
|
||||||
|
docker rm -f mtg-smoke 2>/dev/null || true
|
||||||
|
docker run -d --name mtg-smoke -p 8080:8080 mtg-deckbuilder:test
|
||||||
|
echo "Waiting for Web UI..."
|
||||||
|
for i in {1..30}; do
|
||||||
|
if curl -fsS http://localhost:8080/ >/dev/null; then echo "Up"; break; fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
# Final assert; print logs on failure
|
||||||
|
if ! curl -fsS http://localhost:8080/ >/dev/null; then
|
||||||
|
echo "Web UI did not start in time. Container logs:" && docker logs mtg-smoke || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
docker rm -f mtg-smoke >/dev/null 2>&1 || true
|
||||||
|
|
||||||
- name: Docker Hub login
|
- name: Docker Hub login
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
|
@ -58,6 +79,7 @@ jobs:
|
||||||
org.opencontainers.image.title=MTG Python Deckbuilder
|
org.opencontainers.image.title=MTG Python Deckbuilder
|
||||||
org.opencontainers.image.version=${{ github.ref_name }}
|
org.opencontainers.image.version=${{ github.ref_name }}
|
||||||
org.opencontainers.image.description=${{ steps.notes.outputs.desc }}
|
org.opencontainers.image.description=${{ steps.notes.outputs.desc }}
|
||||||
|
org.opencontainers.image.revision=${{ github.sha }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
|
@ -68,4 +90,6 @@ jobs:
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
APP_VERSION=${{ steps.notes.outputs.version }}
|
||||||
|
|
||||||
|
|
21
Dockerfile
21
Dockerfile
|
@ -7,6 +7,8 @@ WORKDIR /app
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
ARG APP_VERSION=dev
|
||||||
|
ENV APP_VERSION=${APP_VERSION}
|
||||||
|
|
||||||
# Install system dependencies if needed
|
# Install system dependencies if needed
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
|
@ -46,12 +48,25 @@ RUN cd /app/code && ls -la deck_files logs csv_files config owned_cards
|
||||||
# Set the working directory to code for proper imports
|
# Set the working directory to code for proper imports
|
||||||
WORKDIR /app/code
|
WORKDIR /app/code
|
||||||
|
|
||||||
# Run the application
|
# Add a tiny entrypoint to select Web UI (default) or CLI
|
||||||
CMD ["python", "main.py"]
|
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
|
|
||||||
# Expose web port for the optional Web UI
|
# Expose web port for the optional Web UI
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Container health check: verify Web UI health endpoint (skip if APP_MODE=cli)
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||||
|
CMD python -c "import os,sys,json,urllib.request;\
|
||||||
|
m=os.getenv('APP_MODE','web');\
|
||||||
|
\
|
||||||
|
\
|
||||||
|
\
|
||||||
|
sys.exit(0) if m=='cli' else None;\
|
||||||
|
d=urllib.request.urlopen('http://127.0.0.1:8080/healthz', timeout=3).read();\
|
||||||
|
sys.exit(0 if json.loads(d.decode()).get('status')=='ok' else 1)"
|
||||||
|
|
||||||
# Note: For the Web UI, start uvicorn in your orchestrator (compose/run) like:
|
# Note: For the Web UI, start uvicorn in your orchestrator (compose/run) like:
|
||||||
# uvicorn code.web.app:app --host 0.0.0.0 --port 8080
|
# (now default) container starts Web UI automatically; to run CLI set APP_MODE=cli
|
||||||
# Phase 9: enable web list virtualization with env WEB_VIRTUALIZE=1
|
# Phase 9: enable web list virtualization with env WEB_VIRTUALIZE=1
|
||||||
|
|
BIN
README.md
BIN
README.md
Binary file not shown.
|
@ -53,5 +53,4 @@ services:
|
||||||
- ${PWD}/config:/app/config
|
- ${PWD}/config:/app/config
|
||||||
- ${PWD}/owned_cards:/app/owned_cards
|
- ${PWD}/owned_cards:/app/owned_cards
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
command: ["bash", "-lc", "cd /app && uvicorn code.web.app:app --host 0.0.0.0 --port 8080"]
|
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
|
34
dockerhub-docker-compose.yml
Normal file
34
dockerhub-docker-compose.yml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: mwisnowski/mtg-python-deckbuilder:latest
|
||||||
|
# Tip: pin to a specific tag when available, e.g. :2.0.2 (defaults to Web UI)
|
||||||
|
container_name: mtg-deckbuilder-web
|
||||||
|
ports:
|
||||||
|
- "8080:8080" # Host:Container — open http://localhost:8080
|
||||||
|
environment:
|
||||||
|
# UI features/flags (all optional)
|
||||||
|
- SHOW_LOGS=1 # 1=enable /logs page; 0=hide (default off if unset)
|
||||||
|
- SHOW_DIAGNOSTICS=1 # 1=enable /diagnostics & /diagnostics/perf; 0=hide (default off)
|
||||||
|
- ENABLE_PWA=0 # 1=serve manifest/service worker (experimental); 0=disabled
|
||||||
|
- WEB_VIRTUALIZE=1 # 1=enable list virtualization/lazy tweaks in Web UI; 0=off
|
||||||
|
- WEB_TAG_PARALLEL=1 # 1=parallelize heavy tagging steps in Web UI; 0=serial
|
||||||
|
- WEB_TAG_WORKERS=4 # Worker count for parallel tagging (only used if WEB_TAG_PARALLEL=1)
|
||||||
|
|
||||||
|
# Theming (optional)
|
||||||
|
- THEME=system # Default theme for first-time visitors: system|light|dark
|
||||||
|
# 'light' maps to the consolidated Light (Blend) palette
|
||||||
|
- ENABLE_THEMES=1 # 1=show theme selector in header; 0=hide selector
|
||||||
|
# Note: THEME still applies as the default even if selector is hidden
|
||||||
|
|
||||||
|
# Version label (optional; shown in footer/diagnostics)
|
||||||
|
# - APP_VERSION=v2.0.2
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Persist app data locally; ensure these directories exist next to this compose file
|
||||||
|
- ${PWD}/deck_files:/app/deck_files
|
||||||
|
- ${PWD}/logs:/app/logs
|
||||||
|
- ${PWD}/csv_files:/app/csv_files
|
||||||
|
- ${PWD}/config:/app/config
|
||||||
|
- ${PWD}/owned_cards:/app/owned_cards
|
||||||
|
|
||||||
|
restart: unless-stopped
|
20
entrypoint.sh
Normal file
20
entrypoint.sh
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Always operate from the code directory for imports to work
|
||||||
|
cd /app/code || exit 1
|
||||||
|
|
||||||
|
# Select mode: default to Web UI
|
||||||
|
MODE="${APP_MODE:-web}"
|
||||||
|
|
||||||
|
if [ "$MODE" = "cli" ]; then
|
||||||
|
# Run the CLI (interactive menu; use DECK_MODE=headless for non-interactive)
|
||||||
|
exec python main.py
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Web UI (FastAPI via uvicorn)
|
||||||
|
HOST="${HOST:-0.0.0.0}"
|
||||||
|
PORT="${PORT:-8080}"
|
||||||
|
WORKERS="${WORKERS:-1}"
|
||||||
|
|
||||||
|
exec uvicorn web.app:app --host "$HOST" --port "$PORT" --workers "$WORKERS"
|
Loading…
Add table
Add a link
Reference in a new issue