From fd2530cea33299cfdd6138da9ca8e1d8d59bc1c0 Mon Sep 17 00:00:00 2001 From: matt Date: Fri, 22 Aug 2025 16:46:44 -0700 Subject: [PATCH] Release v1.1.1: headless README flags + DockerHub notes auto from template --- .github/workflows/dockerhub-publish.yml | 21 +++++++++++++++++++++ README.md | Bin 8304 -> 13564 bytes RELEASE_NOTES.md | 2 ++ code/headless_runner.py | 12 +++++++----- config/deck.json | 6 +++--- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.github/workflows/dockerhub-publish.yml b/.github/workflows/dockerhub-publish.yml index 7f3e323..1f63324 100644 --- a/.github/workflows/dockerhub-publish.yml +++ b/.github/workflows/dockerhub-publish.yml @@ -16,6 +16,23 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Prepare release notes from template + id: notes + shell: bash + run: | + VERSION_REF="${GITHUB_REF##*/}" # e.g. v1.2.3 + TEMPLATE="RELEASE_NOTES_TEMPLATE.md" + if [ -f "$TEMPLATE" ]; then + sed "s/\${VERSION}/${VERSION_REF}/g" "$TEMPLATE" > RELEASE_NOTES.md + else + echo "# MTG Python Deckbuilder ${VERSION_REF}" > RELEASE_NOTES.md + echo >> RELEASE_NOTES.md + echo "Automated release." >> RELEASE_NOTES.md + fi + # Escape newlines for label usage + DESC=$(awk 'BEGIN{ORS="\\n"} {print}' RELEASE_NOTES.md) + echo "desc=$DESC" >> $GITHUB_OUTPUT + - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -38,6 +55,10 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=raw,value=latest + labels: | + org.opencontainers.image.title=MTG Python Deckbuilder + org.opencontainers.image.version=${{ github.ref_name }} + org.opencontainers.image.description=${{ steps.notes.outputs.desc }} - name: Build and push uses: docker/build-push-action@v6 diff --git a/README.md b/README.md index fd4fa28989eb0d5d0627d08cff90e6af6de566f4..a8ce92fc4d7440d7c3aac3c866257be3085a97b0 100644 GIT binary patch literal 13564 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 S97#jIIa!ihi_}K9+`j-b2$|^s delta 17 Ycmey9`N3g>obcv2wE&*Yzl@m}0ZI=B?EnA( diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e0ee89a..3eeb0e8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,7 @@ # MTG Python Deckbuilder v1.1.0 Release Notes +Note: Future releases will generate this file from `RELEASE_NOTES_TEMPLATE.md` automatically in CI. + ## Highlights - Headless mode via submenu in the main menu (auto-runs single config; lists multiple as "Commander - Theme1, Theme2, Theme3"; `deck.json` shows as "Default") - Config precedence: CLI > env > JSON > defaults; honors `ideal_counts` in JSON diff --git a/code/headless_runner.py b/code/headless_runner.py index 4130409..66cec5d 100644 --- a/code/headless_runner.py +++ b/code/headless_runner.py @@ -6,7 +6,7 @@ import os from typing import Any, Dict, List, Optional from pathlib import Path -from code.deck_builder.builder import DeckBuilder +from deck_builder.builder import DeckBuilder """Headless (non-interactive) runner. @@ -159,10 +159,12 @@ def run( if csv_path: base = os.path.splitext(os.path.basename(csv_path))[0] builder.export_decklist_text(filename=base + '.txt') - if hasattr(builder, 'export_run_config_json'): + # Headless policy: do NOT export JSON by default. Opt-in with HEADLESS_EXPORT_JSON=1 + allow_json = (os.getenv('HEADLESS_EXPORT_JSON', '').strip().lower() in {'1','true','yes','on'}) + if allow_json and hasattr(builder, 'export_run_config_json'): try: cfg_path_env = os.getenv('DECK_CONFIG') - if cfg_path_env: + if cfg_path_env and os.path.isdir(os.path.dirname(cfg_path_env) or '.'): cfg_dir = os.path.dirname(cfg_path_env) or '.' elif os.path.isdir('/app/config'): cfg_dir = '/app/config' @@ -170,8 +172,8 @@ def run( cfg_dir = 'config' os.makedirs(cfg_dir, exist_ok=True) builder.export_run_config_json(directory=cfg_dir, filename=base + '.json') - # If an explicit DECK_CONFIG path is given, also write to exactly that path - if cfg_path_env: + # If an explicit DECK_CONFIG path is given to a file, write exactly there as well + if cfg_path_env and os.path.splitext(cfg_path_env)[1].lower() == '.json': cfg_dir2 = os.path.dirname(cfg_path_env) or '.' cfg_name2 = os.path.basename(cfg_path_env) os.makedirs(cfg_dir2, exist_ok=True) diff --git a/config/deck.json b/config/deck.json index 57f247d..3faeb45 100644 --- a/config/deck.json +++ b/config/deck.json @@ -1,8 +1,8 @@ { "commander": "Aang, Airbending Master", - "primary_tag": "Experience Counters", - "secondary_tag": "Token Creation", - "tertiary_tag": null, + "primary_tag": "Exile Matters", + "secondary_tag": "Airbending", + "tertiary_tag": "Token Creation", "bracket_level": 4, "use_multi_theme": true, "add_lands": true,