Compare commits

...

3 Commits

Author SHA1 Message Date
Kevin Veen-Birkenbach
103f49c8f6 Release version 1.4.1
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled
2025-12-12 23:06:15 +01:00
Kevin Veen-Birkenbach
f5d428950e **Replace main.py with module-based entry point and unify CLI execution**
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled
* Remove legacy *main.py* and introduce *pkgmgr* module entry via *python -m pkgmgr*
* Add ***main**.py* as the canonical entry point delegating to the CLI
* Export *PYTHONPATH=src* in Makefile to ensure reliable imports in dev and CI
* Update setup scripts (venv & nix) to use module execution
* Refactor all E2E tests to execute the real module entry instead of file paths

This aligns pkgmgr with standard Python packaging practices and simplifies testing, setup, and execution across environments.

https://chatgpt.com/share/693c9056-716c-800f-b583-fc9245eab2b4
2025-12-12 22:59:46 +01:00
Kevin Veen-Birkenbach
b40787ffc5 ci: publish GHCR images after successful mark-stable workflow
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled
Trigger container publishing via workflow_run on "Mark stable commit", gate on success,
checkout the workflow_run head SHA, force-refresh tags, and derive version from the v* tag
pointing at the tested commit to correctly detect and publish stable images.

https://chatgpt.com/share/693c836b-0b00-800f-9536-9e273abd0fb5
2025-12-12 22:50:33 +01:00
24 changed files with 50 additions and 54 deletions

View File

@@ -1,12 +1,13 @@
name: Publish container images (GHCR)
on:
push:
tags:
- "v*"
workflow_run:
workflows: ["Mark stable commit"]
types: [completed]
jobs:
publish:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
permissions:
@@ -20,13 +21,22 @@ jobs:
fetch-depth: 0
fetch-tags: true
- name: Checkout workflow_run commit and refresh tags
run: |
set -euo pipefail
git checkout -f "${{ github.event.workflow_run.head_sha }}"
git fetch --tags --force
git tag --list 'stable' 'v*' --sort=version:refname | tail -n 20
- name: Compute version and stable flag
id: info
run: |
set -euo pipefail
SHA="$(git rev-parse HEAD)"
VERSION="${GITHUB_REF_NAME#v}"
V_TAG="$(git tag --points-at "${SHA}" --list 'v*' | sort -V | tail -n1)"
[[ -n "$V_TAG" ]] || { echo "No version tag found"; exit 1; }
VERSION="${V_TAG#v}"
STABLE_SHA="$(git rev-parse -q --verify refs/tags/stable^{commit} 2>/dev/null || true)"
IS_STABLE=false

View File

@@ -1,3 +1,8 @@
## [1.4.1] - 2025-12-12
* Fixed (#1) stable release container publishing
## [1.4.0] - 2025-12-12
* **Docker Container Building**

View File

@@ -30,6 +30,7 @@ export BASE_IMAGE_CENTOS
# PYthon Unittest Pattern
TEST_PATTERN := test_*.py
export TEST_PATTERN
export PYTHONPATH := src
# ------------------------------------------------------------
# System install
@@ -45,7 +46,7 @@ install:
# Default: keep current auto-detection behavior
setup: setup-nix setup-venv
# Explicit: developer setup (Python venv + shell RC + main.py install)
# Explicit: developer setup (Python venv + shell RC + install)
setup-venv: setup-nix
@bash scripts/setup/venv.sh

View File

@@ -36,7 +36,7 @@
rec {
pkgmgr = pyPkgs.buildPythonApplication {
pname = "package-manager";
version = "1.4.0";
version = "1.4.1";
# Use the git repo as source
src = ./.;

14
main.py
View File

@@ -1,14 +0,0 @@
#!/usr/bin/env python3
import sys
from pathlib import Path
# Ensure local src/ overrides installed package
ROOT = Path(__file__).resolve().parent
SRC = ROOT / "src"
if SRC.is_dir():
sys.path.insert(0, str(SRC))
from pkgmgr.cli import main
if __name__ == "__main__":
main()

View File

@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "package-manager"
version = "1.4.0"
version = "1.4.1"
description = "Kevin's package-manager tool (pkgmgr)"
readme = "README.md"
requires-python = ">=3.9"

View File

@@ -1,9 +1,9 @@
# ------------------------------------------------------------
# Nix shell mode: do not touch venv, only run main.py install
# Nix shell mode: do not touch venv, only run install
# ------------------------------------------------------------
echo "[setup] Nix mode enabled (NIX_ENABLED=1)."
echo "[setup] Skipping virtualenv creation and dependency installation."
echo "[setup] Running main.py install via system python3..."
python3 main.py install
echo "[setup] Running install via system python3..."
python3 -m pkgmgr install
echo "[setup] Setup finished (Nix mode)."

View File

@@ -15,9 +15,6 @@ RC_LINE='if [ -d "${HOME}/.venvs/pkgmgr" ]; then . "${HOME}/.venvs/pkgmgr/bin/ac
echo "[setup] Running in normal user mode (developer setup)."
echo "[setup] Ensuring main.py is executable..."
chmod +x main.py || true
echo "[setup] Ensuring global virtualenv root: ${HOME}/.venvs"
mkdir -p "${HOME}/.venvs"
@@ -90,8 +87,8 @@ for rc in "${HOME}/.bashrc" "${HOME}/.zshrc"; do
fi
done
echo "[setup] Running main.py install via venv Python..."
"${VENV_DIR}/bin/python" main.py install
echo "[setup] Running install via venv Python..."
"${VENV_DIR}/bin/python" -m pkgmgr install
echo
echo "[setup] Developer setup complete."

5
src/pkgmgr/__main__.py Executable file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env python3
from pkgmgr.cli import main
if __name__ == "__main__":
main()

View File

@@ -27,7 +27,7 @@ class TestIntegrationBranchCommands(unittest.TestCase):
try:
# argv[0] is the program name; the rest are CLI arguments.
sys.argv = ["pkgmgr"] + list(extra_args)
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
finally:
sys.argv = original_argv

View File

@@ -24,7 +24,7 @@ def _run_pkgmgr_help(argv_tail: list[str]) -> str:
try:
with redirect_stdout(buffer), redirect_stderr(buffer):
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else None
if code not in (0, None):

View File

@@ -53,7 +53,7 @@ class TestIntegrationChangelogCommands(unittest.TestCase):
sys.argv = ["pkgmgr", "changelog"] + list(extra_args)
try:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else str(exc.code)
if code != 0:

View File

@@ -47,7 +47,7 @@ class TestIntegrationCloneAllHttps(unittest.TestCase):
try:
# Execute main.py as if it was called from CLI.
# This will run the full clone pipeline inside the container.
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
# Determine the exit code (int or string)
exit_code = exc.code

View File

@@ -34,7 +34,7 @@ def _run_pkgmgr_config(extra_args: list[str]) -> None:
sys.argv = ["pkgmgr"] + extra_args
try:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else str(exc.code)
if code != 0:

View File

@@ -139,7 +139,7 @@ class TestIntegrationInstalPKGMGRShallow(unittest.TestCase):
]
# Execute installation via main.py
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
# Debug: interactive shell test
pkgmgr_help_debug()

View File

@@ -27,7 +27,7 @@ class TestIntegrationListCommands(unittest.TestCase):
sys.argv = ["pkgmgr"] + args
try:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else str(exc.code)
if code != 0:

View File

@@ -44,7 +44,7 @@ class TestIntegrationMakeCommands(unittest.TestCase):
sys.argv = ["pkgmgr"] + extra_args
try:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else str(exc.code)
if code != 0:

View File

@@ -50,7 +50,7 @@ class TestIntegrationMirrorCommands(unittest.TestCase):
try:
with redirect_stdout(buffer), redirect_stderr(buffer):
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else None
if code not in (0, None):

View File

@@ -50,7 +50,7 @@ class TestPathCommandsE2E(unittest.TestCase):
try:
# Capture stdout while running the CLI entry point.
with redirect_stdout(buffer):
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
# Determine the exit code (int or string)
exit_code = exc.code

View File

@@ -27,7 +27,7 @@ class TestIntegrationProxyCommands(unittest.TestCase):
sys.argv = ["pkgmgr"] + args
try:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else str(exc.code)
if code != 0:

View File

@@ -44,7 +44,7 @@ class TestIntegrationReleaseCommand(unittest.TestCase):
try:
# argv[0] is the program name; the rest are CLI arguments.
sys.argv = ["pkgmgr"] + list(extra_args)
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
finally:
sys.argv = original_argv
@@ -152,7 +152,7 @@ class TestIntegrationReleaseCommand(unittest.TestCase):
# argparse will call sys.exit(), so we expect a SystemExit here.
with contextlib.redirect_stdout(buf), contextlib.redirect_stderr(buf):
with self.assertRaises(SystemExit) as cm:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
finally:
sys.argv = original_argv

View File

@@ -55,7 +55,7 @@ class TestIntegrationToolsCommands(unittest.TestCase):
sys.argv = ["pkgmgr"] + extra_args
try:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else str(exc.code)
if code != 0:

View File

@@ -18,14 +18,6 @@ import sys
import unittest
from typing import List
# Resolve project root (the repo where main.py lives, e.g. /src)
PROJECT_ROOT = os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "..")
)
MAIN_PATH = os.path.join(PROJECT_ROOT, "main.py")
def _run_main(argv: List[str]) -> None:
"""
Helper to run main.py with the given argv.
@@ -40,7 +32,7 @@ def _run_main(argv: List[str]) -> None:
try:
sys.argv = ["pkgmgr"] + argv
try:
runpy.run_path(MAIN_PATH, run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc: # argparse uses this for --help
# SystemExit.code can be int, str or None; for our purposes:
code = exc.code

View File

@@ -130,7 +130,7 @@ class TestIntegrationVersionCommands(unittest.TestCase):
sys.argv = ["pkgmgr", "version"] + extra_args
try:
runpy.run_module("main", run_name="__main__")
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else str(exc.code)
if code != 0: