Merge pull request #224 from Xoconoch/dev

Guard docker-compose file image
This commit is contained in:
Xoconoch
2025-08-09 14:05:55 -06:00
committed by GitHub
4 changed files with 165 additions and 14 deletions

109
.github/scripts/ensure_compose_image.py vendored Executable file
View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python3
import sys
import subprocess
from pathlib import Path
from typing import Tuple
try:
import yaml
except Exception:
sys.stderr.write("PyYAML is required to run this check.\n")
sys.exit(2)
EXPECTED_IMAGE = "cooldockerizer93/spotizerr"
def load_compose(path: Path):
with path.open("r", encoding="utf-8") as f:
return yaml.safe_load(f) or {}
def save_compose(path: Path, data) -> None:
with path.open("w", encoding="utf-8") as f:
yaml.safe_dump(data, f, sort_keys=False)
def ensure_image_unversioned(data) -> Tuple[bool, str, str]:
"""
Returns (changed, old_image, new_image)
"""
services = (data or {}).get("services", {})
svc = services.get("spotizerr", {})
image = svc.get("image")
if image == EXPECTED_IMAGE:
return False, image, image
# Normalize to expected image if it has a tag/digest or is different
svc["image"] = EXPECTED_IMAGE
services["spotizerr"] = svc
data["services"] = services
return True, image, EXPECTED_IMAGE
def git(*args: str) -> subprocess.CompletedProcess:
return subprocess.run(["git", *args], check=False, text=True, capture_output=True)
def autocommit(file_path: str) -> None:
# Configure git identity if missing
git("config", "user.name").stdout
if git("config", "user.name").stdout.strip() == "":
git("config", "user.name", "github-actions[bot]")
if git("config", "user.email").stdout.strip() == "":
git("config", "user.email", "github-actions[bot]@users.noreply.github.com")
# Stage and commit
git("add", file_path)
status = git("status", "--porcelain").stdout.strip()
if status:
msg = "chore: normalize docker-compose image to cooldockerizer93/spotizerr"
commit_res = git("commit", "-m", msg)
if commit_res.returncode != 0:
sys.stderr.write(f"Git commit failed: {commit_res.stderr}\n")
sys.exit(1)
push_res = git("push")
if push_res.returncode != 0:
sys.stderr.write(f"Git push failed: {push_res.stderr}\n")
sys.exit(1)
print("Pushed normalization commit")
else:
print("No changes to commit")
def main(argv: list[str]) -> int:
# Usage: ensure_compose_image.py [docker-compose.yaml] [--autocommit]
compose_path = (
Path(argv[1])
if len(argv) > 1 and not argv[1].startswith("-")
else Path("docker-compose.yaml")
)
do_autocommit = any(arg == "--autocommit" for arg in argv[1:])
if not compose_path.exists():
sys.stderr.write(f"File not found: {compose_path}\n")
return 1
try:
data = load_compose(compose_path)
except Exception as e:
sys.stderr.write(f"Failed to parse YAML from {compose_path}: {e}\n")
return 1
changed, old_image, new_image = ensure_image_unversioned(data)
if changed:
save_compose(compose_path, data)
sys.stderr.write(
f"Normalized services.spotizerr.image from '{old_image}' to '{new_image}'\n"
)
# For pre-commit: exit non-zero to force user to re-stage
if do_autocommit:
autocommit(str(compose_path))
return 0
return 1
print(f"OK: docker-compose image is '{EXPECTED_IMAGE}'")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))

View File

@@ -0,0 +1,46 @@
name: Compose Image Guard
on:
push:
branches: [ dev, main, master ]
paths:
- 'docker-compose.yaml'
- '.github/workflows/compose-image-guard.yml'
- '.github/scripts/ensure_compose_image.py'
pull_request:
branches: [ dev, main, master ]
paths:
- 'docker-compose.yaml'
- '.github/workflows/compose-image-guard.yml'
- '.github/scripts/ensure_compose_image.py'
permissions:
contents: write
pull-requests: write
jobs:
validate-compose-image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyyaml
# On pushes to this repo: normalize and push
- name: Validate and normalize (auto-commit on push)
if: github.event_name == 'push' && github.repository == 'Xoconoch/spotizerr'
run: python .github/scripts/ensure_compose_image.py docker-compose.yaml --autocommit
# On PRs (including forks): validate only, no push
- name: Validate (no auto-commit on PR)
if: github.event_name != 'push' || github.repository != 'Xoconoch/spotizerr'
run: python .github/scripts/ensure_compose_image.py docker-compose.yaml

View File

@@ -52,4 +52,4 @@ repos:
args: [--no-strict-optional, --ignore-missing-imports] args: [--no-strict-optional, --ignore-missing-imports]
exclude: ^spotizerr-ui/ exclude: ^spotizerr-ui/
# NOTE: you might need to add some deps here: # NOTE: you might need to add some deps here:
additional_dependencies: [waitress==3.0.2, types-waitress, types-requests] additional_dependencies: [waitress==3.0.2, types-waitress, types-requests, types-PyYAML]

View File

@@ -1,22 +1,19 @@
name: spotizerr name: spotizerr
services: services:
spotizerr: spotizerr:
image: cooldockerizer93/spotizerr:beta image: cooldockerizer93/spotizerr
volumes: volumes:
- ./data:/app/data - ./data:/app/data
- ./downloads:/app/downloads # <-- Change this for your music library dir - ./downloads:/app/downloads
- ./logs:/app/logs # <-- Volume for persistent logs - ./logs:/app/logs
ports: ports:
- 7171:7171 - 7171:7171
container_name: spotizerr-app container_name: spotizerr-app
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- .env - .env
depends_on: depends_on:
- redis - redis
redis: redis:
image: redis:alpine image: redis:alpine
container_name: spotizerr-redis container_name: spotizerr-redis
@@ -26,7 +23,6 @@ services:
volumes: volumes:
- redis-data:/data - redis-data:/data
command: sh -c 'redis-server --requirepass "$REDIS_PASSWORD" --appendonly yes' command: sh -c 'redis-server --requirepass "$REDIS_PASSWORD" --appendonly yes'
volumes: volumes:
redis-data: redis-data:
driver: local driver: local