Skip to content

Commit 2dbe447

Browse files
committed
refactor: Split CLI into sub parsers
Misc refactoring
1 parent 9d4f069 commit 2dbe447

File tree

7 files changed

+74
-55
lines changed

7 files changed

+74
-55
lines changed

.github/workflows/build.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: Generate build matrix
2424
run: |
2525
FORCE=$(if git log --pretty=format:"%s" HEAD^..HEAD | grep -q '\[force\]'; then echo "--force"; else echo ""; fi)
26-
uv run dpn --ci-matrix $FORCE --ci-event ${{ github.event_name }}
26+
uv run dpn $FORCE build-matrix --event ${{ github.event_name }}
2727
id: set-matrix
2828

2929
deploy:
@@ -39,7 +39,7 @@ jobs:
3939
with:
4040
enable-cache: true
4141
- name: Generate Dockerfile from config
42-
run: uv run dpn --dockerfile-with-context '${{ toJSON(matrix) }}'
42+
run: uv run dpn dockerfile --context '${{ toJSON(matrix) }}'
4343
- name: Set up QEMU
4444
uses: docker/setup-qemu-action@v3
4545
- name: Set up Docker Buildx
@@ -79,7 +79,7 @@ jobs:
7979
enable-cache: true
8080
- name: Update versions.json and README.md, then commit and push changes (if any)
8181
run: |
82-
uv run dpn --verbose --release
82+
uv run dpn --verbose release
8383
clean_checkout=$(git status --porcelain)
8484
if [[ -n "${clean_checkout}" ]]; then
8585
git config --global user.name "Nikolai Kristiansen" > /dev/null 2>&1

.gitignore

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
debug-*.Dockerfile
22
.idea/
33
dockerfiles/
4-
.circleci/config_generated.yml
5-
version_config.json
64
__pycache__
75
.coverage
86
coverage.xml
97
.vscode/
108
htmlcov/
9+
tmp/

pyproject.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ ignore = [
4444
"FBT001", # Allow boolean function args
4545
"FIX001" # Allow fixme's
4646
]
47-
target-version = "py311"
47+
target-version = "py312"
4848

4949
[tool.ruff.per-file-ignores]
5050
"**/test*.py" = ["S101"]
@@ -54,6 +54,5 @@ strict = true
5454
disallow_any_unimported = true
5555
no_implicit_optional = true
5656

57-
5857
[tool.pytest.ini_options]
5958
addopts = "--disable-socket"

src/docker_python_nodejs/ci_matrix.py src/docker_python_nodejs/build_matrix.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
import logging
44
import os
5+
import sys
56
from pathlib import Path
67
from typing import TYPE_CHECKING
78

@@ -19,11 +20,15 @@ def _github_action_set_output(key: str, value: str) -> None:
1920
"""Write
2021
https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter
2122
"""
23+
if not GITHUB_OUTPUT:
24+
print("GITHUB_OUTPUT not set", file=sys.stderr)
25+
sys.exit(1)
26+
2227
with Path(GITHUB_OUTPUT).open("a") as fp:
2328
fp.write(f"{key}={value}")
2429

2530

26-
def generate_matrix(new_or_updated: "list[BuildVersion]", ci_event: str) -> None:
31+
def build_matrix(new_or_updated: "list[BuildVersion]", ci_event: str) -> None:
2732
if not new_or_updated and ci_event == CI_EVENT_SCHEDULED:
2833
logger.info("\n# Scheduled run with no new or updated versions. Doing nothing.")
2934
return

src/docker_python_nodejs/cli.py

+47-37
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import argparse
22
import logging
3-
from typing import cast
3+
from typing import Literal, cast
44

5-
from .ci_matrix import generate_matrix
5+
from .build_matrix import build_matrix
66
from .dockerfiles import render_dockerfile_with_context
7-
from .readme import format_supported_versions, update_dynamic_readme
7+
from .readme import update_dynamic_readme
88
from .settings import DISTROS
99
from .versions import (
1010
decide_version_combinations,
11-
fetch_supported_nodejs_versions,
1211
find_new_or_updated,
13-
load_versions,
1412
persist_versions,
15-
scrape_supported_python_versions,
13+
supported_versions,
1614
)
1715

1816
logger = logging.getLogger("dpn")
@@ -21,41 +19,48 @@
2119
class CLIArgs(argparse.Namespace):
2220
dry_run: bool
2321
distros: list[str]
24-
ci_matrix: bool
25-
dockerfile_with_context: str
26-
ci_event: str
27-
release: bool
28-
force: bool
2922
verbose: bool
23+
command: Literal["dockerfile", "build-matrix", "release"]
24+
force: bool # build-matrix and release command arg
3025

26+
context: str # dockerfile command arg
27+
event: str # build-matrix command arg
3128

32-
def main(args: CLIArgs) -> None:
33-
if args.dry_run:
34-
logger.debug("Dry run, outputing only.")
3529

36-
if args.dockerfile_with_context:
37-
render_dockerfile_with_context(args.dockerfile_with_context, args.dry_run)
38-
return
30+
def run_dockerfile(args: CLIArgs) -> None:
31+
render_dockerfile_with_context(args.context, args.dry_run)
3932

40-
current_versions = load_versions()
41-
suported_python_versions = scrape_supported_python_versions()
42-
suported_nodejs_versions = fetch_supported_nodejs_versions()
43-
supported_versions = format_supported_versions(suported_python_versions, suported_nodejs_versions)
44-
logger.debug(f"Found the following supported versions:\n{supported_versions}")
4533

34+
def run_build_matrix(args: CLIArgs) -> None:
35+
suported_python_versions, suported_nodejs_versions = supported_versions()
4636
versions = decide_version_combinations(args.distros, suported_python_versions, suported_nodejs_versions)
47-
new_or_updated = find_new_or_updated(current_versions, versions, args.force)
37+
new_or_updated = find_new_or_updated(versions, args.force)
38+
build_matrix(new_or_updated, args.event)
39+
4840

49-
if args.ci_matrix:
50-
generate_matrix(new_or_updated, args.ci_event)
41+
def run_release(args: CLIArgs) -> None:
42+
suported_python_versions, suported_nodejs_versions = supported_versions()
43+
versions = decide_version_combinations(args.distros, suported_python_versions, suported_nodejs_versions)
44+
new_or_updated = find_new_or_updated(versions, args.force)
5145

52-
if not new_or_updated and not args.ci_matrix:
46+
if not new_or_updated:
5347
logger.info("No new or updated versions")
5448
return
5549

56-
if args.release:
57-
persist_versions(versions, args.dry_run)
58-
update_dynamic_readme(versions, suported_python_versions, suported_nodejs_versions, args.dry_run)
50+
persist_versions(versions, args.dry_run)
51+
update_dynamic_readme(versions, suported_python_versions, suported_nodejs_versions, args.dry_run)
52+
53+
54+
def main(args: CLIArgs) -> None:
55+
if args.dry_run:
56+
logger.debug("Dry run, outputing only.")
57+
58+
if args.command == "dockerfile":
59+
run_dockerfile(args)
60+
elif args.command == "build-matrix":
61+
run_build_matrix(args)
62+
elif args.command == "release":
63+
run_release(args)
5964

6065

6166
def parse_args() -> CLIArgs:
@@ -75,16 +80,21 @@ def parse_args() -> CLIArgs:
7580
dest="dry_run",
7681
help="Skip persisting, README update, and pushing of builds",
7782
)
78-
parser.add_argument("--ci-matrix", action="store_true", help="Generate CI build matrix")
79-
parser.add_argument(
80-
"--ci-event",
83+
parser.add_argument("--force", action="store_true", help="Force build all versions (even old)")
84+
parser.add_argument("--verbose", action="store_true", help="Enable debug logging")
85+
86+
subparsers = parser.add_subparsers(dest="command", help="Sub-commands")
87+
# Dockerfile command
88+
parser_dockerfile = subparsers.add_parser("dockerfile", help="Render a dockerfile based on version config")
89+
parser_dockerfile.add_argument("context", default="", help="Dockerfile version config")
90+
# Build matrix command
91+
parser_build_matrix = subparsers.add_parser("build-matrix", help="Generate CI build matrix")
92+
parser_build_matrix.add_argument(
93+
"--event",
8194
default="webhook",
8295
# https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
8396
help="GitHub Action event name (github.event_name)",
8497
)
85-
parser.add_argument("--release", action="store_true", help="Persist versions and make a release")
86-
parser.add_argument("--dockerfile-with-context", default="", help="Render a dockerfile based on version config")
87-
parser.add_argument("--force", action="store_true", help="Force build all versions (even old)")
88-
parser.add_argument("--verbose", action="store_true", help="Enable debug logging")
89-
98+
# Release command
99+
subparsers.add_parser("release", help="Persist versions and make a release")
90100
return cast(CLIArgs, parser.parse_args())

src/docker_python_nodejs/readme.py

+5-9
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,10 @@ def format_supported_versions(
6767
python_versions: "list[SupportedVersion]",
6868
node_versions: "list[SupportedVersion]",
6969
) -> str:
70-
headings = ["Python version", "Start", "End"]
71-
rows = [[ver.version, ver.start, ver.end] for ver in sorted(python_versions, key=lambda x: x.start, reverse=True)]
72-
python_table = _format_md_table(headings, rows)
73-
74-
headings_node = ["Node.js version", "Start", "End"]
75-
rows_node = [
76-
[ver.version, ver.start, ver.end] for ver in sorted(node_versions, key=lambda x: x.start, reverse=True)
77-
]
78-
node_table = _format_md_table(headings_node, rows_node)
70+
def _as_rows(versions: "list[SupportedVersion]") -> list[list[str]]:
71+
return [[ver.version, ver.start, ver.end] for ver in sorted(versions, key=lambda x: x.start, reverse=True)]
72+
73+
python_table = _format_md_table(["Python version", "Start", "End"], _as_rows(python_versions))
74+
node_table = _format_md_table(["Node.js version", "Start", "End"], _as_rows(node_versions))
7975

8076
return f"{python_table}\n{node_table}"

src/docker_python_nodejs/versions.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from bs4 import BeautifulSoup
1010
from semver.version import Version
1111

12+
from docker_python_nodejs.readme import format_supported_versions
13+
1214
from .docker_hub import DockerImageDict, DockerTagDict, fetch_tags
1315
from .nodejs_versions import (
1416
fetch_node_releases,
@@ -162,6 +164,14 @@ def fetch_supported_nodejs_versions() -> list[SupportedVersion]:
162164
return versions
163165

164166

167+
def supported_versions() -> tuple[list[SupportedVersion], list[SupportedVersion]]:
168+
suported_python_versions = scrape_supported_python_versions()
169+
suported_nodejs_versions = fetch_supported_nodejs_versions()
170+
supported_versions = format_supported_versions(suported_python_versions, suported_nodejs_versions)
171+
logger.debug(f"Found the following supported versions:\n{supported_versions}")
172+
return suported_python_versions, suported_nodejs_versions
173+
174+
165175
def _has_arch_files(files: list[str], distro: str) -> bool:
166176
if distro == "alpine":
167177
return {"linux-x64-musl"}.issubset(files)
@@ -257,13 +267,13 @@ def load_versions() -> list[BuildVersion]:
257267

258268

259269
def find_new_or_updated(
260-
current_versions: list[BuildVersion],
261270
versions: list[BuildVersion],
262271
force: bool = False,
263272
) -> list[BuildVersion]:
264273
if force:
265274
logger.warning("Generating full build matrix because --force is set")
266275

276+
current_versions = load_versions()
267277
current_versions_dict = {ver.key: ver for ver in current_versions}
268278
versions_dict = {ver.key: ver for ver in versions}
269279
new_or_updated: list[BuildVersion] = []

0 commit comments

Comments
 (0)