Skip to main content

Check your Docker Compose stack for image updates without pulling

Project description

compose-outdated

Check your Docker Compose stack for image updates without pulling any images. Shows current vs latest versions and fetches changelogs from GitHub.

Features

  • Parses docker-compose.yml / compose.yaml with full include: recursion
  • Queries Docker Hub, GHCR, and lscr.io for available tags
  • Compares versions within the same tag channel (e.g. -alpine tags stay in their lane)
  • Fetches release notes from GitHub for each available update
  • Supports environment variable interpolation (${VAR:-default})
  • Concurrent registry checks for fast results
  • No images are pulled -- registry APIs only

Setup

Requires Python 3.12+ and uv.

# Clone and install
git clone <repo-url> && cd compose-outdated
uv sync

# Or install directly with uv/pipx
uv tool install .

This installs two equivalent commands: compose-outdated and cod.

Usage

# Check compose file in the current directory
cod

# Check a specific directory or file
cod /path/to/my-stack
cod /path/to/docker-compose.yml

# Skip changelog fetching (faster, table-only output)
cod --no-changelog

# Only check specific services
cod -s traefik -s redis

# Set a GitHub token for higher API rate limits (also reads GITHUB_TOKEN env var)
cod --github-token ghp_xxxxx

# Control concurrent registry requests (default: 5)
cod -n 10

# Show more changelog context per release (default: 8 lines, 0 = unlimited)
cod -l 20
cod -l 0

# Save the full report to a file (always untruncated)
cod -o report.txt

# Compact terminal output but full detail in the file
cod -l 3 -o report.txt

Options

Flag Short Description
--changelog / --no-changelog -c / -C Enable/disable GitHub changelog fetching (default: on)
--github-token TEXT GitHub API token for higher rate limits
--service TEXT -s Only check named service(s), can be repeated
--concurrency INT -n Max concurrent registry checks (default: 5)
--body-lines INT -l Max lines per changelog body in terminal (0 = unlimited, default: 8)
--output PATH -o Write full report to file (changelogs are never truncated in the file)

Exit codes

Code Meaning
0 All images are up to date
1 Error (compose file not found, parse failure, etc.)
2 Updates are available

This makes it easy to use in scripts or CI:

cod --no-changelog /path/to/stack || echo "Updates available!"

Supported registries

  • Docker Hub (docker.io) -- uses the Hub REST API, no auth required for public images
  • GitHub Container Registry (ghcr.io) -- uses OCI Distribution API with anonymous tokens
  • LinuxServer (lscr.io) -- proxied through GHCR
  • Any OCI-compliant registry should work via the Distribution spec fallback

How changelogs are resolved

The tool tries several strategies to find the GitHub source repo for each image:

  1. Built-in known mappings for popular images (traefik, postgres, redis, cloudflared, etc.)
  2. GHCR / lscr.io path inference (image path usually matches the GitHub repo)
  3. docker-library/official-images manifest lookup (for official library/ images)
  4. Docker Hub repository metadata (parses README for GitHub links)
  5. GitHub search as a last resort

Once a repo is found, GitHub Releases are fetched and filtered to versions between your current tag and the latest.

Compose file support

The tool handles real-world compose setups:

  • compose.yaml, compose.yml, docker-compose.yaml, docker-compose.yml
  • Recursive include: directives (nested includes are followed)
  • Environment variable interpolation: $VAR, ${VAR}, ${VAR:-default}
  • Digest-pinned images (image:tag@sha256:...) -- the tag is extracted for comparison
  • Images without explicit tags default to latest

Version comparison

Tags are compared within "channels" to avoid false positives:

  • 1.25.3-alpine is only compared against other *-alpine tags
  • v-prefixed and non-prefixed duplicates are deduplicated (v3.6.10 and 3.6.10 count as one)
  • Non-semver tags like latest, stable, or commit SHAs are skipped

Development

uv sync                                    # install deps
uv run pytest                              # run tests
uv run pytest --cov=compose_outdated       # run tests with coverage
uv run ruff check .                        # lint
uv run ruff format .                       # format

This project uses Conventional Commits. Prefix your commit messages with feat:, fix:, chore:, docs:, test:, ci:, refactor:, etc.

Releasing a new version

  1. Ensure you're on master with a clean working tree and CI passing.
  2. Run the version bump:
    uv run cz bump
    
    This will:
    • Determine the next version from commit messages since the last tag
    • Update version in pyproject.toml
    • Update CHANGELOG.md
    • Create a commit and git tag (e.g. v0.4.0)
  3. Review the changes:
    git log -1 --stat
    git diff HEAD~1 CHANGELOG.md
    
  4. Push the commit and tag:
    git push origin master --follow-tags
    
  5. The CI publish job triggers on the tag, builds the package, and publishes to PyPI via OIDC trusted publisher.

PyPI trusted publisher setup (one-time)

On pypi.org, under the project's "Publishing" settings, add a new "GitLab" trusted publisher:

  • GitLab instance URL: gitlab.com
  • Project path: <your-namespace>/compose-outdated
  • Environment: pypi
  • Top-level pipeline or workflow name: .gitlab-ci.yml

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

compose_outdated-0.4.1.tar.gz (61.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

compose_outdated-0.4.1-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file compose_outdated-0.4.1.tar.gz.

File metadata

  • Download URL: compose_outdated-0.4.1.tar.gz
  • Upload date:
  • Size: 61.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for compose_outdated-0.4.1.tar.gz
Algorithm Hash digest
SHA256 de25e6ac1c1bb182085d298f87be7a8c0c8dedc9e0c5e83a042d0257fe463b89
MD5 e6b948feddc7452751146198ad1aaca9
BLAKE2b-256 34cc17d9ab8c2c6177dbd9ced3c930aac1ecfc8f36a4b718dbffc3bca27c14e5

See more details on using hashes here.

File details

Details for the file compose_outdated-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: compose_outdated-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 17.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for compose_outdated-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 da0ea34f9ff1c70abeb52836feb4b020f0cfed8d4e0e5878df6bfbc899d7b394
MD5 d47bc19e29008ea426d2039501538c33
BLAKE2b-256 7725b0644b459a35eb3b33c16618033eef626e58c06b634f56a351621e9b82ce

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page