From d4df0f076cf73fae1261fe9d5a54247492d7d6b6 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Sat, 5 Sep 2026 22:48:51 +0200 Subject: [PATCH] chore(deps): track stable internal releases and test Python compatibility --- .github/dependabot.yml | 31 ++++++++++++ .github/internal-dependencies.json | 35 +++++++++++++ .../internal-dependency-freshness.yml | 36 ++++++++++++++ .github/workflows/test-locked.yml | 30 ++++++++++++ README.md | 4 ++ docs/dependencies.md | 27 ++++++++++ pyproject.toml | 8 ++- uv.lock | 49 ++++++++++--------- 8 files changed, 196 insertions(+), 24 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/internal-dependencies.json create mode 100644 .github/workflows/internal-dependency-freshness.yml create mode 100644 .github/workflows/test-locked.yml create mode 100644 docs/dependencies.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..19c46ff --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +version: 2 +updates: +- package-ecosystem: uv + directory: / + schedule: + interval: cron + cronjob: 33 4 * * * + timezone: Europe/Warsaw + open-pull-requests-limit: 1 + versioning-strategy: increase-if-necessary + allow: + - dependency-name: costs + dependency-type: all + - dependency-name: goal + dependency-type: all + - dependency-name: pfix + dependency-type: all + - dependency-name: clickmd + dependency-type: all + - dependency-name: code2llm + dependency-type: all + groups: + internal-packages: + patterns: + - costs + - goal + - pfix + - clickmd + - code2llm + commit-message: + prefix: "chore(deps)" diff --git a/.github/internal-dependencies.json b/.github/internal-dependencies.json new file mode 100644 index 0000000..ce582b0 --- /dev/null +++ b/.github/internal-dependencies.json @@ -0,0 +1,35 @@ +{ + "schema": "goal.internal-dependencies/v1", + "packages": [ + { + "name": "costs", + "repository": "semcod/costs", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "goal", + "repository": "semcod/goal", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "pfix", + "repository": "semcod/pfix", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "clickmd", + "repository": "semcod/clickmd", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "code2llm", + "repository": "semcod/code2llm", + "registry": "pypi", + "versioning": "semver" + } + ] +} diff --git a/.github/workflows/internal-dependency-freshness.yml b/.github/workflows/internal-dependency-freshness.yml new file mode 100644 index 0000000..d64bfc8 --- /dev/null +++ b/.github/workflows/internal-dependency-freshness.yml @@ -0,0 +1,36 @@ +name: Internal dependency freshness + +on: + schedule: + - cron: "47 5 * * *" + workflow_dispatch: + pull_request: + paths: + - pyproject.toml + - uv.lock + - .github/internal-dependencies.json + - .github/workflows/internal-dependency-freshness.yml + +permissions: + contents: read + +jobs: + freshness: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.12" + - name: Install released checker + run: python -m pip install "goal==2.2.0" + - name: Verify published stable targets + run: goal dependencies --catalog .github/internal-dependencies.json --check > dependency-freshness.json + - name: Retain freshness evidence + if: always() + uses: actions/upload-artifact@v4 + with: + name: dependency-freshness + path: dependency-freshness.json + if-no-files-found: ignore diff --git a/.github/workflows/test-locked.yml b/.github/workflows/test-locked.yml new file mode 100644 index 0000000..c42bf24 --- /dev/null +++ b/.github/workflows/test-locked.yml @@ -0,0 +1,30 @@ +name: Locked tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.13"] + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: ${{ matrix.python-version }} + - run: python -m pip install uv + - name: Install locked test dependencies + run: uv sync --locked --extra dev --python "${{ matrix.python-version }}" + - name: Test supported Python versions + run: uv run --no-sync python -m pytest -q diff --git a/README.md b/README.md index d1f82d2..edbde8b 100644 --- a/README.md +++ b/README.md @@ -108,3 +108,7 @@ Licensed under Apache-2.0. ## Author Tom Sapletta + +## Dependency maintenance + +See [internal dependency updates](docs/dependencies.md) for daily updates, locked tests and Python support. diff --git a/docs/dependencies.md b/docs/dependencies.md new file mode 100644 index 0000000..7d132f5 --- /dev/null +++ b/docs/dependencies.md @@ -0,0 +1,27 @@ +# Internal dependency updates + +This repository owns its dependency configuration and this guide, following the repository ownership principle in [wellmanifest/docs](https://github.com/wellmanifest/docs/blob/f64de5806577769672ebc1730d2e144b4c7671ec/README.md). The checker belongs to [semcod/goal](https://github.com/semcod/goal/blob/84f18540d14c24cc8ff5b7f202d2874344779ecc/docs/internal-dependencies.md). + +## Python and installation + +Application support remains Python >=3.10. Source inspection found no Goal imports or executable invocation in application Python code. Goal's old declarations moved to an `automation` dependency group requiring Python >=3.12, so updating release tooling does not remove Python 3.10 application support. + +```sh +uv sync --locked --extra dev --python 3.10 +uv run --no-sync python -m pytest -q +UV_PROJECT_ENVIRONMENT=.venv-automation uv sync --locked --group automation --python 3.12 +``` + +The automation command uses a separate environment. Synchronize the application environment again after merging tested dependency updates. + +## Daily checks + +[Dependabot](../.github/dependabot.yml) checks the explicit costs, Goal, pfix, clickmd and code2llm catalog daily, including weekends, and groups updates into one PR. It includes transitive packages and may widen constraints when necessary. This is a bounded catalog, not discovery of every internal package. Local/Git sources and other packages need separate review. + +[Freshness CI](../.github/workflows/internal-dependency-freshness.yml) uses released Goal 2.2.0 to compare uv.lock with the highest published stable three-part versions of the catalog packages actually used here. It has read-only repository permissions, runs daily/manually/on dependency PRs, and retains JSON evidence. Registry and resolution errors remain visible. An audit does not prove a deployed environment has installed the new versions. + +[Locked tests](../.github/workflows/test-locked.yml) install the dev extra from uv.lock and run the full project suite on Python 3.10 and 3.13. A permissive version declaration alone does not refresh the lockfile; update creation, testing, merge and installation are separate steps. + +## Delivery + +The registry targets observed on 2026-09-05 are costs 0.2.0, Goal 2.2.0, pfix 0.1.79, clickmd 1.1.15 and code2llm 0.5.176. PR and Actions checks hold the test results; the [ecosystem rollout history](https://github.com/semcod/costs/tree/main/docs/dependencies) belongs to costs. Reports and instructions are versioned in repository docs, rather than temporary machine directories. diff --git a/pyproject.toml b/pyproject.toml index 7e432f7..95fcba6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,14 +17,12 @@ classifiers = [ ] # Zero external dependencies — stdlib only dependencies = [ - "goal>=2.1.0", "costs>=0.1.20", "pfix>=0.1.60", ] [project.optional-dependencies] dev = ["pytest", "pytest-cov", "ruff", - "goal>=2.1.0", "costs>=0.1.20", "pfix>=0.1.60", ] @@ -77,3 +75,9 @@ max_commits = 500 # Cost thresholds for badge colors (USD) badge_color_thresholds = { low = 1.0, medium = 5.0, high = 10.0, critical = 50.0 } + +[tool.uv.dependency-groups.automation] +requires-python = ">=3.12" + +[dependency-groups] +automation = ["goal>=2.2.0"] diff --git a/uv.lock b/uv.lock index d577fbb..2fd3cfb 100644 --- a/uv.lock +++ b/uv.lock @@ -602,7 +602,7 @@ wheels = [ [[package]] name = "costs" -version = "0.1.52" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anthropic" }, @@ -614,11 +614,12 @@ dependencies = [ { name = "pandas", version = "3.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "python-dotenv" }, { name = "tiktoken" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c5/34/d88a86a72b19b6d399a67cdc7723b76a6e4dd36ed64c82021fc9c26d2125/costs-0.1.52.tar.gz", hash = "sha256:46feda45975cf5a66d8ddeae615b13bd66547bc9ad91fc56b7f58979218ba05b", size = 30688, upload-time = "2026-06-28T22:44:37.492Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/6f/7f3c72d6d4b5264bd5a3447e18a3b5184bffee143f72c8d023bb759afd1a/costs-0.2.0.tar.gz", hash = "sha256:3782bae859725dae30f697b5f3e5aa5d84e06feadebc5782ae706e21d46437af", size = 44606, upload-time = "2026-09-05T15:49:55.524Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/91/cb3ffe3638a2ff28b420cad95cc8bbbfc89f844b87162e57d98477e90e51/costs-0.1.52-py3-none-any.whl", hash = "sha256:d3944767c5e12a01a831c6a3250f4702694a7ade199bbd7c70ee0c2c140b6a6c", size = 35676, upload-time = "2026-06-28T22:44:36.264Z" }, + { url = "https://files.pythonhosted.org/packages/1d/7e/fc91d9fdc7a1ceb9116daffab27124a54f6e8887c9d59d906df43dcbfa6a/costs-0.2.0-py3-none-any.whl", hash = "sha256:4798b8535cbbcbb354e440ebce91365f17c910414bf5831a0610998ae6e679af", size = 48625, upload-time = "2026-09-05T15:49:54.054Z" }, ] [[package]] @@ -828,7 +829,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -931,14 +932,12 @@ version = "0.1.18" source = { editable = "." } dependencies = [ { name = "costs" }, - { name = "goal" }, { name = "pfix" }, ] [package.optional-dependencies] dev = [ { name = "costs" }, - { name = "goal" }, { name = "pfix" }, { name = "pytest" }, { name = "pytest-cov" }, @@ -948,12 +947,15 @@ ssh = [ { name = "paramiko" }, ] +[package.dev-dependencies] +automation = [ + { name = "goal", marker = "python_full_version >= '3.12'" }, +] + [package.metadata] requires-dist = [ { name = "costs", specifier = ">=0.1.20" }, { name = "costs", marker = "extra == 'dev'", specifier = ">=0.1.20" }, - { name = "goal", specifier = ">=2.1.0" }, - { name = "goal", marker = "extra == 'dev'", specifier = ">=2.1.0" }, { name = "paramiko", marker = "extra == 'ssh'" }, { name = "pfix", specifier = ">=0.1.60" }, { name = "pfix", marker = "extra == 'dev'", specifier = ">=0.1.60" }, @@ -963,6 +965,9 @@ requires-dist = [ ] provides-extras = ["dev", "ssh"] +[package.metadata.requires-dev] +automation = [{ name = "goal", marker = "python_full_version >= '3.12'", specifier = ">=2.2.0" }] + [[package]] name = "frozenlist" version = "1.8.0" @@ -1119,7 +1124,7 @@ wheels = [ [[package]] name = "goal" -version = "2.1.262" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1129,9 +1134,9 @@ dependencies = [ { name = "tomlkit" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/a4/39210297a1561695939789bd2b92397e2e833e8716d4efcf505a8d21d3d0/goal-2.1.262.tar.gz", hash = "sha256:6283b26a2e8405ace61e539232e69698574981d6aa129a00e7b42be51e5f4bab", size = 302063, upload-time = "2026-06-28T22:47:08.142Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/9c/135e3f67a7324c3c49ef4246f5518b59ad90226e62c3d30ae20cba005c1d/goal-2.2.0.tar.gz", hash = "sha256:e9e2c1ac9493dae3b887b16d503f7c1f83d02ddcbdd3c5cf58d44a458bb2662f", size = 399786, upload-time = "2026-09-05T19:41:55.329Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/e8/46823636d6d51e6b8d87c4fd67ec86ed9000d311f84c917b5629327ba3a5/goal-2.1.262-py3-none-any.whl", hash = "sha256:8698aefa60d983ac261e3d4aa5b21e116be801fc63d77de988479d9877744c84", size = 289987, upload-time = "2026-06-28T22:47:06.285Z" }, + { url = "https://files.pythonhosted.org/packages/24/69/8a4cf5710683bb777f1f6e4cd44dd3907befe97b94c6ea6e97d4305b4e44/goal-2.2.0-py3-none-any.whl", hash = "sha256:0d8f93aa317ac92a66b64b797e210a5d66044ce8db2cb05b012b03d42aced95e", size = 349709, upload-time = "2026-09-05T19:41:53.615Z" }, ] [[package]] @@ -2069,10 +2074,10 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "python-dateutil", marker = "python_full_version < '3.11'" }, - { name = "pytz", marker = "python_full_version < '3.11'" }, - { name = "tzdata", marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ @@ -2141,10 +2146,10 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "numpy", version = "2.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, - { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/fd/e0194474c71dbfba82e744f66945c274f15b667acd5f8c117b12555fb91e/pandas-3.0.4.tar.gz", hash = "sha256:62f6062586d159663825f06e70ef49cd1572d45824cb63a9559f3ffd1d0d2a20", size = 4658146, upload-time = "2026-06-28T15:31:51.3Z" } wheels = [ @@ -2238,7 +2243,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess", marker = "python_full_version < '3.11' or sys_platform != 'win32'" }, + { name = "ptyprocess" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ @@ -2247,7 +2252,7 @@ wheels = [ [[package]] name = "pfix" -version = "0.1.74" +version = "0.1.79" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "litellm" }, @@ -2256,9 +2261,9 @@ dependencies = [ { name = "python-dotenv" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/51/51/fdbc91a818bc5d30fd1f73d4a1a5c1683d3eb74959119772944c6d12b385/pfix-0.1.74.tar.gz", hash = "sha256:eaae020c3899dfde5117b0d89c3c96bb57487dde404a019fac23497d62585cac", size = 2839963, upload-time = "2026-06-29T07:38:19.223Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/7e/252be5e1d55321b947013010f45b02d781de87e25b9a524c0ee72c1ad3c0/pfix-0.1.79.tar.gz", hash = "sha256:6bc4c572e22e0f0d952bc5e2df78f52f8f999cab64e22138b097b2eab4d83092", size = 2845663, upload-time = "2026-07-05T17:00:57.331Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/83/56a88a9c26ce19b6212a56f0f0b33a2b788d28402a2d8cd8faa50302fb1a/pfix-0.1.74-py3-none-any.whl", hash = "sha256:e9d1ccc9dc3e06e8438c6c2f03a63c2d869e484b3692cad5ee70cc433d05e210", size = 149279, upload-time = "2026-06-29T07:38:14.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/bf/548982294e795d79003680b2214c7f5dd00ca4b0ea856064bf9cb6869ba7/pfix-0.1.79-py3-none-any.whl", hash = "sha256:bb7ab83b99c0bfbaae5e6e95cb801a27d4fd68749485600fdfe49dad00607461", size = 151754, upload-time = "2026-07-05T17:00:52.816Z" }, ] [[package]]