diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d437d4a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +version: 2 +updates: +- package-ecosystem: uv + directory: / + schedule: + interval: cron + cronjob: 12 5 * * * + 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..c01ad10 --- /dev/null +++ b/.github/workflows/internal-dependency-freshness.yml @@ -0,0 +1,36 @@ +name: Internal dependency freshness + +on: + schedule: + - cron: "21 6 * * *" + 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..78c199a --- /dev/null +++ b/.github/workflows/test-locked.yml @@ -0,0 +1,49 @@ +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 + with: + fetch-depth: 0 + - uses: actions/setup-python@v7 + with: + python-version: ${{ matrix.python-version }} + - name: Check out immutable documentation standard + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: wellmanifest/docs + ref: ebe7501063ef4f3e63ded610c2d3183010ca636e # v0.1.1 + path: .docs-standard + token: ${{ secrets.ORG_SYNC_PAT }} + persist-credentials: false + - name: Validate documentation placement + shell: bash + env: + DOCS_BASE: ${{ github.event.pull_request.base.sha }} + run: | + set -euo pipefail + args=(--root . --standard-revision ebe7501063ef4f3e63ded610c2d3183010ca636e) + if [[ -n "$DOCS_BASE" ]]; then args+=(--base "$DOCS_BASE"); fi + python .docs-standard/docs/standard/check.py "${args[@]}" + - run: python -m pip install uv + - name: Install locked test dependencies + run: uv sync --locked --extra dev --extra performance --python "${{ matrix.python-version }}" + - name: Test supported Python versions + run: uv run --no-sync python -m pytest -q diff --git a/.governance/docs.json b/.governance/docs.json new file mode 100644 index 0000000..fef752a --- /dev/null +++ b/.governance/docs.json @@ -0,0 +1,7 @@ +{ + "schema": "wellmanifest.docs/adoption/v1", + "repository": "semcod/prefact", + "standard": "wellmanifest/docs", + "source_revision": "ebe7501063ef4f3e63ded610c2d3183010ca636e", + "policy_sha256": "f6ba9c011ea1d9260e7fac3a1638a767d5ebc9f7d9b32ed51cc3aea22fe95d8c" +} diff --git a/docs/README.md b/docs/README.md index fcc693a..cf07c3d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -564,4 +564,6 @@ pip install -e ".[dev]" | `examples/` | Usage examples | [Browse](./examples) | | `mkdocs.yml` | MkDocs configuration | — | - \ No newline at end of file + + +- [Aktualizacja zależności wewnętrznych](information/internal-dependencies.md) — lockfile, testy i codzienny audyt. diff --git a/docs/information/internal-dependencies.md b/docs/information/internal-dependencies.md new file mode 100644 index 0000000..98a1233 --- /dev/null +++ b/docs/information/internal-dependencies.md @@ -0,0 +1,81 @@ +--- +{ + "schema": "wellmanifest.docs/document/v1", + "id": "internal-dependencies", + "kind": "information", + "version": 1, + "title": "Aktualizacja i kontrola zależności wewnętrznych", + "status": "implemented", + "owner": "semcod/prefact", + "created": "2026-09-06", + "updated": "2026-09-06", + "review_after": "2026-09-13", + "source_revision": "21e1252020e4e24e46f1f21138178320f895ba0b", + "affected_repositories": [ + "semcod/prefact" + ], + "evidence": [ + "https://github.com/semcod/prefact/blob/21e1252020e4e24e46f1f21138178320f895ba0b/pyproject.toml", + "https://pypi.org/project/goal/2.2.0/", + "https://docs.astral.sh/uv/concepts/projects/dependencies/", + "https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference" + ] +} +--- + +# Aktualizacja i kontrola zależności wewnętrznych + + +## Cel + +Utrzymywać aktualne, przetestowane zależności projektu `semcod/prefact` przy zachowaniu Pythona 3.10 jako minimalnej wersji aplikacji. + + +## Zakres + +Właścicielem lockfile i CI jest `semcod/prefact`. Katalog [.github/internal-dependencies.json](../../.github/internal-dependencies.json) obejmuje pięć jawnie wskazanych dystrybucji PyPI: costs, goal, pfix, clickmd i code2llm. Audyt sprawdza te z nich, które występują w uv.lock. Nie obejmuje dowolnego pakietu tylko na podstawie nazwy organizacji. + + +## Dowody + +Przed zmianą wersja źródłowa wskazana w metadanych miała starsze zależności i nie miała workflow testów lockfile ani audytu aktualności. W odczycie PyPI z 2026-09-06 aktualnymi stabilnymi wersjami były costs 0.2.0, goal 2.2.0, pfix 0.1.79 i clickmd 1.1.15; te wersje zapisano w uv.lock. + +Lokalne testy zatwierdzanego lockfile: 109 testów przeszło, jeden pominięto na Pythonie 3.10 oraz 3.13. Po instalacji dodatku performance oba testy modułu cache przeszły na obu wersjach; CI uruchamia pełny zestaw z tym dodatkiem. Wyniki publikacji i kolejnych kontroli są dostępne w [GitHub Actions](https://github.com/semcod/prefact/actions). + + +## Obsługa + +Goal jest narzędziem automatyzacji, bez importów w kodzie aplikacji. Grupa `automation` wymaga Pythona >=3.12 i nie jest domyślnie instalowana z aplikacją ani dodatkiem `dev`. Zastosowano [oddzielny zakres Pythona grupy uv](https://docs.astral.sh/uv/concepts/projects/dependencies/#group-requires-python). + +```bash +uv sync --locked --extra dev --extra performance --python 3.10 +uv run --no-sync python -m pytest -q +``` + +Dependabot codziennie proponuje aktualizację wewnętrznych pakietów w jednym PR. Testy uruchamiają zatwierdzony lockfile na Pythonie 3.10 i 3.13. Osobny workflow codziennie oraz po zmianie zależności w PR porównuje lockfile z najwyższymi stabilnymi wydaniami w katalogu; zachowuje raport jako artefakt. Obie automatyzacje można uruchomić ręcznie. + +Ręczny audyt używa grupy narzędziowej: + +```bash +uv run --locked --group automation --python 3.12 goal dependencies --catalog .github/internal-dependencies.json --check +``` + +Aktualizacja wybranych pakietów: + +```bash +uv lock --upgrade-package costs --upgrade-package goal --upgrade-package pfix --upgrade-package clickmd --upgrade-package code2llm +``` + +Po aktualizacji uruchom testy, opublikuj PR, a po jego sprawdzeniu i scaleniu zsynchronizuj środowisko. CI kontroluje też położenie i metadane dokumentacji według wellmanifest/docs 0.1.1, przypiętego do `ebe7501063ef4f3e63ded610c2d3183010ca636e` w `.governance/docs.json`. + + +## Ograniczenia + +Ograniczenie `>=` dopuszcza nowszą wersję, lecz nie zmienia istniejącego środowiska. `uv sync --locked` odtwarza wersje z lockfile. Codzienny PR nie jest automatycznie scalany ani wdrażany. Opóźnienie zależy od harmonogramu, testów i procesu publikacji. + +Checker w CI jest przypięty do Goal 2.2.0. Jego aktualizację trzeba wykonać jawnie. Audyt tej wersji porównuje stabilne wersje x.y.z i nie jest pełnym resolverem wszystkich formatów wersji ani kontrolą pochodzenia każdego pakietu. Dokładne przypięcie standardu dokumentacji podlega osobnej, sprawdzanej aktualizacji. + + +## Utrzymanie + +Sprawdzaj nieudane harmonogramy i zaległe PR-y. Nową dystrybucję dodaj do katalogu dopiero po potwierdzeniu jej właściciela i sposobu wersjonowania. Wyniki przekrojowe rozwijaj w [kanonicznym raporcie subactor/docs](https://github.com/subactor/docs/blob/main/architecture/analysis/internal-dependencies.md). Zwiększ wersję tego dokumentu po zmianie mechanizmu. diff --git a/pyproject.toml b/pyproject.toml index 50c10bb..bb90cb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,6 @@ dependencies = [ "pyyaml>=6.0", "rich>=12.0.0", "tomli>=2.0.0; python_version<'3.11'", - "goal>=2.1.218", "costs>=0.1.20", "pfix>=0.1.60", "planfile>=0.1.117", @@ -76,7 +75,6 @@ dev = [ "mypy>=1.0.0", "ruff>=0.5.0", "pre-commit>=3.0.0", - "goal>=2.1.218", "costs>=0.1.20", "pfix>=0.1.60", ] @@ -152,7 +150,6 @@ exclude = [ [tool.hatch.envs.default] dependencies = [ "prefact[dev]", - "goal>=2.1.218", "costs>=0.1.20", "pfix>=0.1.60", ] @@ -160,7 +157,6 @@ dependencies = [ [tool.hatch.envs.test] dependencies = [ "prefact[dev]", - "goal>=2.1.218", "costs>=0.1.20", "pfix>=0.1.60", "pytest-xdist>=3.0.0", @@ -171,7 +167,6 @@ python = ["3.10", "3.11", "3.12", "3.13"] [tool.hatch.envs.docs] dependencies = [ "prefact[docs]", - "goal>=2.1.218", "costs>=0.1.20", "pfix>=0.1.60", ] @@ -181,7 +176,6 @@ dependencies = [ "build>=0.10.0", "twine>=4.0.0", "wheel>=0.40.0", - "goal>=2.1.218", "costs>=0.1.20", "pfix>=0.1.60", ] @@ -335,3 +329,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 } + +[dependency-groups] +automation = ["goal>=2.2.0"] + +[tool.uv.dependency-groups.automation] +requires-python = ">=3.12" diff --git a/uv.lock b/uv.lock index acdf7cd..f2b5884 100644 --- a/uv.lock +++ b/uv.lock @@ -666,7 +666,7 @@ wheels = [ [[package]] name = "costs" -version = "0.1.53" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anthropic" }, @@ -678,11 +678,12 @@ dependencies = [ { name = "pandas", version = "3.0.5", 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/64/02/126b813e063a47c7e7efef481ac144747f94fd05ae39ee9d5c3c6253a09f/costs-0.1.53.tar.gz", hash = "sha256:9f9f76a9e523e899b72a658c574e33145f0f25b97554c15f70dc714206d3d8ca", size = 30980, upload-time = "2026-07-02T14:11:25.407Z" } +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/bd/0e/a6c82f642985c19f6b42a86e5aaf54086fab4ab3771d54e932ec78a7d577/costs-0.1.53-py3-none-any.whl", hash = "sha256:2795668c83a5974c66b1fb6d7831248a481e1bb009f68c4b345d74d357205b88", size = 35990, upload-time = "2026-07-02T14:11:24.146Z" }, + { 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]] @@ -919,7 +920,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 = [ @@ -1184,7 +1185,7 @@ wheels = [ [[package]] name = "goal" -version = "2.1.284" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1194,9 +1195,9 @@ dependencies = [ { name = "tomlkit" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/ed/3ef5beaa56627e95a66269adcfce7c219fff1948b93fc6f2f209fb0cea66/goal-2.1.284.tar.gz", hash = "sha256:61d47e6b68ba499fefad17b3df4bc4b6647da9db80a5dbc0918165c81d3f8ab1", size = 334328, upload-time = "2026-07-23T19:42:09.372Z" } +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/09/30/8155e85057ef3a8871f04db2a14b10d2216c0af68957f36f0417c2b44821/goal-2.1.284-py3-none-any.whl", hash = "sha256:d00dab399a774d07da902e1ef42ad5282e513e65410bace0c3185b555f365777", size = 309816, upload-time = "2026-07-23T19:42:07.494Z" }, + { 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]] @@ -2665,10 +2666,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 = [ @@ -2743,10 +2744,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.1", 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/be/4f/5f3422a2afec5ffc46308b79e53291365a93748b498ac2e58bead0197916/pandas-3.0.5.tar.gz", hash = "sha256:dca3734d6ab7c906e6730f0788b0a1dbb9f2467731f9711f77995c8e9d62d712", size = 4658219, upload-time = "2026-07-22T22:19:28.819Z" } wheels = [ @@ -2825,7 +2826,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 = [ @@ -2934,7 +2935,6 @@ dependencies = [ { name = "ast-decompiler" }, { name = "click" }, { name = "costs" }, - { name = "goal" }, { name = "libcst" }, { name = "pfix" }, { name = "planfile" }, @@ -2962,7 +2962,6 @@ autoflake = [ dev = [ { name = "black" }, { name = "costs" }, - { name = "goal" }, { name = "isort" }, { name = "mypy" }, { name = "pfix" }, @@ -3005,6 +3004,11 @@ unimport = [ { name = "unimport" }, ] +[package.dev-dependencies] +automation = [ + { name = "goal", marker = "python_full_version >= '3.12'" }, +] + [package.metadata] requires-dist = [ { name = "ast-decompiler", specifier = ">=0.7.0" }, @@ -3016,8 +3020,6 @@ requires-dist = [ { name = "costs", marker = "extra == 'dev'", specifier = ">=0.1.20" }, { name = "diskcache", marker = "extra == 'all'", specifier = ">=5.4.0" }, { name = "diskcache", marker = "extra == 'performance'", specifier = ">=5.4.0" }, - { name = "goal", specifier = ">=2.1.218" }, - { name = "goal", marker = "extra == 'dev'", specifier = ">=2.1.218" }, { name = "import-linter", marker = "extra == 'all'", specifier = ">=2.0.0" }, { name = "import-linter", marker = "extra == 'import-linter'", specifier = ">=2.0.0" }, { name = "importchecker", marker = "extra == 'all'", specifier = ">=0.1.0" }, @@ -3054,6 +3056,9 @@ requires-dist = [ ] provides-extras = ["all", "autoflake", "dev", "docs", "import-linter", "importchecker", "isort", "monitoring", "mypy", "performance", "pylint", "ruff", "unimport"] +[package.metadata.requires-dev] +automation = [{ name = "goal", marker = "python_full_version >= '3.12'", specifier = ">=2.2.0" }] + [[package]] name = "prometheus-client" version = "0.26.0"