confkit 2.2.0__tar.gz → 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. confkit-3.0.0/.github/actions/setup/action.yml +34 -0
  2. confkit-3.0.0/.github/ci-filters.yml +51 -0
  3. confkit-3.0.0/.github/workflows/bump-version-by-labels.yml +32 -0
  4. confkit-3.0.0/.github/workflows/ci.yml +147 -0
  5. confkit-3.0.0/.github/workflows/coverage.yml +55 -0
  6. confkit-3.0.0/.github/workflows/docs-publish.yml +81 -0
  7. confkit-3.0.0/.github/workflows/docs.yml +42 -0
  8. {confkit-2.2.0 → confkit-3.0.0}/.github/workflows/gitleaks.yml +4 -8
  9. confkit-3.0.0/.github/workflows/lint.yml +52 -0
  10. {confkit-2.2.0 → confkit-3.0.0}/.github/workflows/pypi.yml +1 -1
  11. {confkit-2.2.0 → confkit-3.0.0}/.github/workflows/release.yml +5 -10
  12. {confkit-2.2.0 → confkit-3.0.0}/.github/workflows/test.yml +12 -22
  13. {confkit-2.2.0 → confkit-3.0.0}/.pre-commit-config.yaml +4 -1
  14. {confkit-2.2.0 → confkit-3.0.0}/PKG-INFO +1 -1
  15. confkit-3.0.0/docs/ci.md +107 -0
  16. {confkit-2.2.0 → confkit-3.0.0}/docs/usage.md +2 -0
  17. {confkit-2.2.0 → confkit-3.0.0}/pyproject.toml +10 -1
  18. {confkit-2.2.0 → confkit-3.0.0}/ruff.toml +1 -1
  19. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/exceptions.py +4 -0
  20. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/parsers.py +7 -0
  21. {confkit-2.2.0 → confkit-3.0.0}/tests/test_config_decorators.py +18 -4
  22. confkit-3.0.0/uv.lock +1924 -0
  23. {confkit-2.2.0 → confkit-3.0.0}/zensical.toml +4 -1
  24. confkit-2.2.0/.github/workflows/bump-version-by-labels.yml +0 -34
  25. confkit-2.2.0/.github/workflows/coverage.yml +0 -46
  26. confkit-2.2.0/.github/workflows/docs.yml +0 -30
  27. confkit-2.2.0/.github/workflows/lint-public.yml +0 -70
  28. confkit-2.2.0/.github/workflows/lint.yml +0 -66
  29. confkit-2.2.0/uv.lock +0 -1293
  30. {confkit-2.2.0 → confkit-3.0.0}/.bumpversion.toml +0 -0
  31. {confkit-2.2.0 → confkit-3.0.0}/.github/FUNDING.yml +0 -0
  32. {confkit-2.2.0 → confkit-3.0.0}/.github/copilot-instructions.md +0 -0
  33. {confkit-2.2.0 → confkit-3.0.0}/.github/dependabot.yml +0 -0
  34. {confkit-2.2.0 → confkit-3.0.0}/.gitignore +0 -0
  35. {confkit-2.2.0 → confkit-3.0.0}/.python-version +0 -0
  36. {confkit-2.2.0 → confkit-3.0.0}/.vscode/settings.json +0 -0
  37. {confkit-2.2.0 → confkit-3.0.0}/LICENSE +0 -0
  38. {confkit-2.2.0 → confkit-3.0.0}/README.md +0 -0
  39. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/argparse.md +0 -0
  40. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/basic.md +0 -0
  41. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/custom_data_type.md +0 -0
  42. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/data_types.md +0 -0
  43. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/decorators.md +0 -0
  44. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/delegate.md +0 -0
  45. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/enums.md +0 -0
  46. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/index.md +0 -0
  47. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/list_types.md +0 -0
  48. {confkit-2.2.0 → confkit-3.0.0}/docs/examples/optional_values.md +0 -0
  49. {confkit-2.2.0 → confkit-3.0.0}/docs/index.md +0 -0
  50. {confkit-2.2.0 → confkit-3.0.0}/docs/markdown.md +0 -0
  51. {confkit-2.2.0 → confkit-3.0.0}/docs/reference/config.md +0 -0
  52. {confkit-2.2.0 → confkit-3.0.0}/docs/reference/data_types.md +0 -0
  53. {confkit-2.2.0 → confkit-3.0.0}/docs/reference/exceptions.md +0 -0
  54. {confkit-2.2.0 → confkit-3.0.0}/docs/reference/notes_two_instances.md +0 -0
  55. {confkit-2.2.0 → confkit-3.0.0}/examples/api.ini +0 -0
  56. {confkit-2.2.0 → confkit-3.0.0}/examples/argparse_example.py +0 -0
  57. {confkit-2.2.0 → confkit-3.0.0}/examples/args.ini +0 -0
  58. {confkit-2.2.0 → confkit-3.0.0}/examples/basic.py +0 -0
  59. {confkit-2.2.0 → confkit-3.0.0}/examples/config.ini +0 -0
  60. {confkit-2.2.0 → confkit-3.0.0}/examples/custom_data_type.py +0 -0
  61. {confkit-2.2.0 → confkit-3.0.0}/examples/data_types.py +0 -0
  62. {confkit-2.2.0 → confkit-3.0.0}/examples/database.ini +0 -0
  63. {confkit-2.2.0 → confkit-3.0.0}/examples/decorators.py +0 -0
  64. {confkit-2.2.0 → confkit-3.0.0}/examples/delegate.py +0 -0
  65. {confkit-2.2.0 → confkit-3.0.0}/examples/enums.py +0 -0
  66. {confkit-2.2.0 → confkit-3.0.0}/examples/example.json +0 -0
  67. {confkit-2.2.0 → confkit-3.0.0}/examples/example.toml +0 -0
  68. {confkit-2.2.0 → confkit-3.0.0}/examples/example.yaml +0 -0
  69. {confkit-2.2.0 → confkit-3.0.0}/examples/file_change_event.py +0 -0
  70. {confkit-2.2.0 → confkit-3.0.0}/examples/list_types.py +0 -0
  71. {confkit-2.2.0 → confkit-3.0.0}/examples/multiple_configs.py +0 -0
  72. {confkit-2.2.0 → confkit-3.0.0}/examples/nested_config.py +0 -0
  73. {confkit-2.2.0 → confkit-3.0.0}/examples/nested_example.ini +0 -0
  74. {confkit-2.2.0 → confkit-3.0.0}/examples/nested_example.json +0 -0
  75. {confkit-2.2.0 → confkit-3.0.0}/examples/nested_example.toml +0 -0
  76. {confkit-2.2.0 → confkit-3.0.0}/examples/nested_example.yaml +0 -0
  77. {confkit-2.2.0 → confkit-3.0.0}/examples/optional_values.py +0 -0
  78. {confkit-2.2.0 → confkit-3.0.0}/examples/other_file_types.py +0 -0
  79. {confkit-2.2.0 → confkit-3.0.0}/examples/pydantic_example.py +0 -0
  80. {confkit-2.2.0 → confkit-3.0.0}/examples/references.py +0 -0
  81. {confkit-2.2.0 → confkit-3.0.0}/examples/url_example.py +0 -0
  82. {confkit-2.2.0 → confkit-3.0.0}/mkdocs.yml +0 -0
  83. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/__init__.py +0 -0
  84. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/config.py +0 -0
  85. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/data_types.py +0 -0
  86. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/ext/__init__.py +0 -0
  87. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/ext/delegate.py +0 -0
  88. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/ext/parsers.py +0 -0
  89. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/ext/pydantic.py +0 -0
  90. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/ext/reference.py +0 -0
  91. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/py.typed +0 -0
  92. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/sentinels.py +0 -0
  93. {confkit-2.2.0 → confkit-3.0.0}/src/confkit/watcher.py +0 -0
  94. {confkit-2.2.0 → confkit-3.0.0}/tests/__init__.py +0 -0
  95. {confkit-2.2.0 → confkit-3.0.0}/tests/conftest.py +0 -0
  96. {confkit-2.2.0 → confkit-3.0.0}/tests/test_config.py +0 -0
  97. {confkit-2.2.0 → confkit-3.0.0}/tests/test_config_classvars.py +0 -0
  98. {confkit-2.2.0 → confkit-3.0.0}/tests/test_config_detect_parser.py +0 -0
  99. {confkit-2.2.0 → confkit-3.0.0}/tests/test_data_types.py +0 -0
  100. {confkit-2.2.0 → confkit-3.0.0}/tests/test_delegate.py +0 -0
  101. {confkit-2.2.0 → confkit-3.0.0}/tests/test_enum_allowed_values.py +0 -0
  102. {confkit-2.2.0 → confkit-3.0.0}/tests/test_enum_auto_conversion.py +0 -0
  103. {confkit-2.2.0 → confkit-3.0.0}/tests/test_env_parser.py +0 -0
  104. {confkit-2.2.0 → confkit-3.0.0}/tests/test_examples_run.py +0 -0
  105. {confkit-2.2.0 → confkit-3.0.0}/tests/test_list_type.py +0 -0
  106. {confkit-2.2.0 → confkit-3.0.0}/tests/test_metaclass.py +0 -0
  107. {confkit-2.2.0 → confkit-3.0.0}/tests/test_msgspec.py +0 -0
  108. {confkit-2.2.0 → confkit-3.0.0}/tests/test_msgspecparser_branches.py +0 -0
  109. {confkit-2.2.0 → confkit-3.0.0}/tests/test_msgspecparser_no_msgspec.py +0 -0
  110. {confkit-2.2.0 → confkit-3.0.0}/tests/test_msgspecparser_read.py +0 -0
  111. {confkit-2.2.0 → confkit-3.0.0}/tests/test_msgspecparser_sections.py +0 -0
  112. {confkit-2.2.0 → confkit-3.0.0}/tests/test_multiple_configurations.py +0 -0
  113. {confkit-2.2.0 → confkit-3.0.0}/tests/test_nested_config.py +0 -0
  114. {confkit-2.2.0 → confkit-3.0.0}/tests/test_on_file_change.py +0 -0
  115. {confkit-2.2.0 → confkit-3.0.0}/tests/test_pydantic_models.py +0 -0
  116. {confkit-2.2.0 → confkit-3.0.0}/tests/test_sentinel.py +0 -0
  117. {confkit-2.2.0 → confkit-3.0.0}/tests/test_two_instances.py +0 -0
  118. {confkit-2.2.0 → confkit-3.0.0}/tests/test_unreachable_paths.py +0 -0
@@ -0,0 +1,34 @@
1
+ name: Set up uv and the project
2
+ description: Install uv and a Python version, then sync the locked dependency groups.
3
+
4
+ inputs:
5
+ python-version:
6
+ description: Python version to install.
7
+ default: "3.13"
8
+ sync-args:
9
+ description: Extra arguments for `uv sync`, such as `--group dev`.
10
+ default: ""
11
+
12
+ runs:
13
+ using: composite
14
+ steps:
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v7
17
+ with:
18
+ enable-cache: true
19
+
20
+ - name: Set up Python ${{ inputs.python-version }}
21
+ shell: bash
22
+ run: uv python install ${{ inputs.python-version }}
23
+
24
+ - name: Install dependencies
25
+ shell: bash
26
+ run: uv sync --locked --python ${{ inputs.python-version }} ${{ inputs.sync-args }}
27
+
28
+ # Without these, a later `uv run` follows .python-version back to 3.11
29
+ # and re-syncs only the default groups, dropping the ones synced above.
30
+ - name: Keep later uv commands on this environment
31
+ shell: bash
32
+ run: |
33
+ echo "UV_PYTHON=${{ inputs.python-version }}" >> "$GITHUB_ENV"
34
+ echo "UV_NO_SYNC=1" >> "$GITHUB_ENV"
@@ -0,0 +1,51 @@
1
+ # Inputs for each check that ci.yml runs. A check only runs when one of its
2
+ # inputs changed. Editing CI itself reruns every check.
3
+ ci: &ci
4
+ - .github/workflows/ci.yml
5
+ - .github/ci-filters.yml
6
+ - .github/actions/setup/**
7
+ deps: &deps
8
+ - pyproject.toml
9
+ - uv.lock
10
+
11
+ test:
12
+ - *ci
13
+ - *deps
14
+ - .github/workflows/test.yml
15
+ - src/**
16
+ - tests/**
17
+
18
+ lint:
19
+ - *ci
20
+ - *deps
21
+ - .github/workflows/lint.yml
22
+ - ruff.toml
23
+ - src/**
24
+ - tests/**
25
+ - examples/**
26
+
27
+ lint-public:
28
+ - *ci
29
+ - *deps
30
+ - .github/workflows/lint.yml
31
+ - ruff.toml
32
+ - src/**
33
+ - examples/**
34
+
35
+ coverage:
36
+ - *ci
37
+ - *deps
38
+ - .github/workflows/coverage.yml
39
+ - src/**
40
+ - tests/**
41
+ - examples/**
42
+
43
+ docs:
44
+ - *ci
45
+ - *deps
46
+ - .github/workflows/docs.yml
47
+ - .github/workflows/docs-publish.yml
48
+ - zensical.toml
49
+ - mkdocs.yml
50
+ - src/**
51
+ - docs/**
@@ -0,0 +1,32 @@
1
+ name: Bump Version By Labels
2
+
3
+ # Called from ci.yml once all-checks passes on a push to master. The action
4
+ # looks up the merged PR for the pushed commit and opens a bump PR from its
5
+ # Major, Minor or Patch label. Merging the bump PR runs CI again, and that
6
+ # run's release job publishes the new version.
7
+ on:
8
+ workflow_call:
9
+
10
+ jobs:
11
+ bump-version:
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ contents: write
15
+ pull-requests: write
16
+
17
+ steps:
18
+ - uses: actions/checkout@v7
19
+ with:
20
+ fetch-depth: 0
21
+
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v7
24
+
25
+ # v4.1.0 is the first release that reads labels on push events.
26
+ - name: Bump by labels
27
+ uses: HEROgold/bump-by-label@v4.1.0
28
+ with:
29
+ github_token: ${{ secrets.GITHUB_TOKEN }}
30
+ command: "uv version --bump"
31
+ validate: "uv version"
32
+ base_branch: master
@@ -0,0 +1,147 @@
1
+ name: CI
2
+
3
+ # One entry point for every check. The changes job compares the push or PR
4
+ # against .github/ci-filters.yml, and each check only runs when its inputs
5
+ # changed. On pushes to master the chain continues once all-checks passes.
6
+ # Bump opens a version bump PR, then release tags and publishes any version
7
+ # that has no tag yet. Coverage stays outside the chain.
8
+ #
9
+ # The master ruleset requires none of these checks. To require them, require
10
+ # the all-checks job only. A called workflow's check names change with whether
11
+ # it ran ("test / test (3.13)") or was skipped ("test"), so neither name works
12
+ # as a required check on its own.
13
+ on:
14
+ push:
15
+ branches: [master]
16
+ pull_request:
17
+ branches: [master]
18
+ # closed only removes the docs preview.
19
+ types: [opened, synchronize, reopened, closed]
20
+ workflow_dispatch:
21
+
22
+ # A newer push to a PR cancels its older run. Pushes to master each get their
23
+ # own group, because GitHub keeps only one pending run per group and would
24
+ # drop a merge's run, along with its version bump.
25
+ concurrency:
26
+ group: ${{ github.event_name == 'push' && github.run_id || format('ci-{0}', github.ref) }}
27
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
28
+
29
+ permissions:
30
+ contents: read
31
+
32
+ jobs:
33
+ changes:
34
+ if: github.event.action != 'closed'
35
+ runs-on: ubuntu-latest
36
+ permissions:
37
+ contents: read
38
+ pull-requests: read
39
+ outputs:
40
+ # A manual run checks everything.
41
+ test: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.test == 'true' }}
42
+ lint: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.lint == 'true' }}
43
+ lint-public: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.lint-public == 'true' }}
44
+ coverage: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.coverage == 'true' }}
45
+ docs: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.docs == 'true' }}
46
+ steps:
47
+ - uses: actions/checkout@v7
48
+
49
+ - uses: dorny/paths-filter@v3
50
+ id: filter
51
+ if: github.event_name != 'workflow_dispatch'
52
+ with:
53
+ filters: .github/ci-filters.yml
54
+
55
+ test:
56
+ needs: changes
57
+ if: needs.changes.outputs.test == 'true'
58
+ uses: ./.github/workflows/test.yml
59
+
60
+ lint:
61
+ needs: changes
62
+ if: needs.changes.outputs.lint == 'true'
63
+ uses: ./.github/workflows/lint.yml
64
+ with:
65
+ cache-prefix: lint
66
+ tools: >-
67
+ [
68
+ {"tool": "ruff", "args": "check ."},
69
+ {"tool": "ty", "args": "check . --ignore no-matching-overload"},
70
+ {"tool": "undersort", "args": ". --check"}
71
+ ]
72
+
73
+ lint-public:
74
+ needs: changes
75
+ if: needs.changes.outputs.lint-public == 'true'
76
+ uses: ./.github/workflows/lint.yml
77
+ with:
78
+ cache-prefix: lint-public
79
+ tools: >-
80
+ [
81
+ {"tool": "ruff", "args": "check ./examples"},
82
+ {"tool": "ty", "args": "check ./examples --ignore no-matching-overload"},
83
+ {"tool": "pyrefly", "args": "check ./examples"},
84
+ {"tool": "zuban", "args": "check ./examples"},
85
+ {"tool": "mypy", "args": "./examples"},
86
+ {"tool": "pyright", "args": "./examples"}
87
+ ]
88
+
89
+ gitleaks:
90
+ if: github.event.action != 'closed'
91
+ uses: ./.github/workflows/gitleaks.yml
92
+
93
+ docs:
94
+ needs: changes
95
+ if: needs.changes.outputs.docs == 'true'
96
+ uses: ./.github/workflows/docs.yml
97
+
98
+ # Not a check, so all-checks doesn't wait on it. Each PR and master get their
99
+ # own group. A newer run waiting in the group replaces an older waiting one,
100
+ # so the newest docs always win.
101
+ docs-publish:
102
+ needs: docs
103
+ # Always runs on closed, so the preview gets removed even when no docs input changed.
104
+ if: always() && (github.event.action == 'closed' || needs.docs.result == 'success')
105
+ concurrency:
106
+ group: gh-pages-${{ github.event.pull_request.number || 'master' }}
107
+ uses: ./.github/workflows/docs-publish.yml
108
+ permissions:
109
+ contents: write
110
+ pull-requests: write
111
+
112
+ coverage:
113
+ needs: changes
114
+ if: github.event_name == 'push' && needs.changes.outputs.coverage == 'true'
115
+ uses: ./.github/workflows/coverage.yml
116
+ secrets:
117
+ COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
118
+
119
+ # Passes when every check passed or was skipped because its inputs didn't
120
+ # change. Coverage is informational, so it isn't listed.
121
+ all-checks:
122
+ if: always() && github.event.action != 'closed'
123
+ needs: [changes, test, lint, lint-public, gitleaks, docs]
124
+ runs-on: ubuntu-latest
125
+ steps:
126
+ - name: Fail if a check failed or was cancelled
127
+ if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
128
+ run: exit 1
129
+
130
+ # always() is needed even though all-checks passed. Without it, GitHub's
131
+ # implicit success() also looks at the checks all-checks needs, and skips
132
+ # this job whenever one of them was skipped.
133
+ bump:
134
+ needs: all-checks
135
+ if: always() && github.event_name == 'push' && needs.all-checks.result == 'success'
136
+ uses: ./.github/workflows/bump-version-by-labels.yml
137
+ permissions:
138
+ contents: write
139
+ pull-requests: write
140
+
141
+ release:
142
+ needs: bump
143
+ if: always() && needs.bump.result == 'success'
144
+ uses: ./.github/workflows/release.yml
145
+ permissions:
146
+ contents: write
147
+ secrets: inherit
@@ -0,0 +1,55 @@
1
+ name: Coverage
2
+
3
+ # Called from ci.yml on pushes to master. Informational, so nothing waits on it.
4
+ on:
5
+ workflow_call:
6
+ secrets:
7
+ COVERALLS_REPO_TOKEN:
8
+ required: false
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ coveralls-upload:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+
19
+ # A hit means coverage for these exact inputs is already on Coveralls.
20
+ - name: Cache coverage result
21
+ id: cache-coverage
22
+ uses: actions/cache@v4
23
+ with:
24
+ path: .coverage_cache
25
+ key: ${{ runner.os }}-coverage-${{ hashFiles('src/**', 'tests/**', 'examples/**', 'pyproject.toml', 'uv.lock', '.github/workflows/coverage.yml', '.github/actions/setup/**') }}
26
+
27
+ - name: Set up the project
28
+ if: steps.cache-coverage.outputs.cache-hit != 'true'
29
+ uses: ./.github/actions/setup
30
+ with:
31
+ sync-args: --group dev
32
+
33
+ - name: Run tests with coverage
34
+ if: steps.cache-coverage.outputs.cache-hit != 'true'
35
+ run: uv run coverage run --source=. -m pytest tests/
36
+
37
+ - name: Upload coverage data to coveralls.io
38
+ if: steps.cache-coverage.outputs.cache-hit != 'true'
39
+ env:
40
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41
+ COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
42
+ COVERALLS_SERVICE_NAME: github-actions
43
+ COVERALLS_PARALLEL: true
44
+ run: uvx coveralls --service=github
45
+
46
+ - name: Coveralls Finished
47
+ if: steps.cache-coverage.outputs.cache-hit != 'true'
48
+ env:
49
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50
+ COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
51
+ run: uvx coveralls --finish
52
+
53
+ - name: Record the upload
54
+ if: steps.cache-coverage.outputs.cache-hit != 'true'
55
+ run: mkdir -p .coverage_cache && touch .coverage_cache/done
@@ -0,0 +1,81 @@
1
+ name: Publish documentation
2
+
3
+ # Called from ci.yml after the docs build. Pages serves the gh-pages branch.
4
+ # Master publishes to its root, and each PR from this repo gets a preview under
5
+ # pr-previews/pr-<n>/. Fork PRs get no preview, because their token can't push
6
+ # to gh-pages. Both actions fetch and rebase when another run pushed first.
7
+ on:
8
+ workflow_call:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ preview:
15
+ if: >-
16
+ github.event_name == 'pull_request'
17
+ && github.event.action != 'closed'
18
+ && github.event.pull_request.head.repo.full_name == github.repository
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ contents: write
22
+ pull-requests: write
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+
26
+ - uses: actions/download-artifact@v4
27
+ with:
28
+ name: site
29
+ path: site
30
+
31
+ - name: Deploy the PR preview
32
+ uses: rossjrw/pr-preview-action@v1
33
+ with:
34
+ source-dir: site
35
+ preview-branch: gh-pages
36
+ umbrella-dir: pr-previews
37
+ action: deploy
38
+
39
+ remove-preview:
40
+ if: >-
41
+ github.event_name == 'pull_request'
42
+ && github.event.action == 'closed'
43
+ && github.event.pull_request.head.repo.full_name == github.repository
44
+ runs-on: ubuntu-latest
45
+ permissions:
46
+ contents: write
47
+ pull-requests: write
48
+ steps:
49
+ - uses: actions/checkout@v7
50
+
51
+ - name: Remove the PR preview
52
+ uses: rossjrw/pr-preview-action@v1
53
+ with:
54
+ preview-branch: gh-pages
55
+ umbrella-dir: pr-previews
56
+ action: remove
57
+
58
+ deploy:
59
+ if: github.event_name == 'push' && github.ref == 'refs/heads/master'
60
+ runs-on: ubuntu-latest
61
+ permissions:
62
+ contents: write
63
+ steps:
64
+ - uses: actions/checkout@v7
65
+
66
+ - uses: actions/download-artifact@v4
67
+ with:
68
+ name: site
69
+ path: site
70
+
71
+ # Only the root needs .nojekyll. In a preview it would outlive the
72
+ # preview's removal, which skips hidden files.
73
+ - name: Keep Pages from running Jekyll
74
+ run: touch site/.nojekyll
75
+
76
+ - name: Publish to the gh-pages root
77
+ uses: JamesIves/github-pages-deploy-action@v4
78
+ with:
79
+ folder: site
80
+ branch: gh-pages
81
+ clean-exclude: pr-previews
@@ -0,0 +1,42 @@
1
+ name: Documentation
2
+
3
+ # Called from ci.yml. Builds the site and uploads it as the "site" artifact.
4
+ # docs-publish.yml publishes it, so a cancelled publish never fails this check.
5
+ on:
6
+ workflow_call:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v7
17
+
18
+ # A hit means the site for these exact inputs is already built.
19
+ - name: Cache the built site
20
+ id: cache-site
21
+ uses: actions/cache@v4
22
+ with:
23
+ path: site
24
+ key: ${{ runner.os }}-site-${{ hashFiles('src/**', 'docs/**', 'zensical.toml', 'mkdocs.yml', 'pyproject.toml', 'uv.lock', '.github/workflows/docs.yml', '.github/actions/setup/**') }}
25
+
26
+ - name: Set up the project
27
+ if: steps.cache-site.outputs.cache-hit != 'true'
28
+ uses: ./.github/actions/setup
29
+ with:
30
+ sync-args: --group docs
31
+
32
+ - name: Build the site
33
+ if: steps.cache-site.outputs.cache-hit != 'true'
34
+ run: |
35
+ uv run pdoc confkit -o docs/api
36
+ uv run zensical build --clean
37
+
38
+ - uses: actions/upload-artifact@v4
39
+ with:
40
+ name: site
41
+ path: site
42
+
@@ -1,14 +1,10 @@
1
1
  name: Gitleaks
2
2
 
3
+ # Called from ci.yml on every push and PR, with no path filter, because a
4
+ # leaked secret can land in any file.
3
5
  on:
4
- push:
5
- branches: [master]
6
- pull_request:
7
- branches: [master]
8
- workflow_dispatch:
9
6
  workflow_call:
10
-
11
- concurrency: gitleaks-${{ github.ref }}
7
+ workflow_dispatch:
12
8
 
13
9
  permissions:
14
10
  contents: read
@@ -18,7 +14,7 @@ jobs:
18
14
  runs-on: ubuntu-latest
19
15
  steps:
20
16
  - name: Checkout code
21
- uses: actions/checkout@v4
17
+ uses: actions/checkout@v7
22
18
  with:
23
19
  fetch-depth: 0
24
20
 
@@ -0,0 +1,52 @@
1
+ name: Lint
2
+
3
+ # Called from ci.yml twice: once for the package and once for the public API
4
+ # as the examples use it.
5
+ on:
6
+ workflow_call:
7
+ inputs:
8
+ cache-prefix:
9
+ description: Cache key prefix that keeps the two callers apart.
10
+ required: true
11
+ type: string
12
+ tools:
13
+ description: JSON list of {"tool", "args"} objects, one matrix entry each.
14
+ required: true
15
+ type: string
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ lint:
22
+ runs-on: ubuntu-latest
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ include: ${{ fromJSON(inputs.tools) }}
27
+
28
+ steps:
29
+ - uses: actions/checkout@v7
30
+
31
+ # The lint group in uv.lock pins every tool, so a tool upgrade changes
32
+ # the key. A hit means this tool already passed on these exact inputs.
33
+ - name: Cache lint result
34
+ id: cache-lint
35
+ uses: actions/cache@v4
36
+ with:
37
+ path: .lint_cache
38
+ key: ${{ runner.os }}-${{ inputs.cache-prefix }}-${{ matrix.tool }}-${{ hashFiles('src/**', 'tests/**', 'examples/**', 'pyproject.toml', 'uv.lock', 'ruff.toml', '.github/workflows/ci.yml', '.github/workflows/lint.yml', '.github/actions/setup/**') }}
39
+
40
+ - name: Set up the project
41
+ if: steps.cache-lint.outputs.cache-hit != 'true'
42
+ uses: ./.github/actions/setup
43
+ with:
44
+ sync-args: --group dev --group lint
45
+
46
+ - name: Run ${{ matrix.tool }}
47
+ if: steps.cache-lint.outputs.cache-hit != 'true'
48
+ run: uv run ${{ matrix.tool }} ${{ matrix.args }}
49
+
50
+ - name: Record the pass
51
+ if: steps.cache-lint.outputs.cache-hit != 'true'
52
+ run: mkdir -p .lint_cache && touch ".lint_cache/${{ matrix.tool }}"
@@ -21,7 +21,7 @@ jobs:
21
21
 
22
22
  steps:
23
23
  - name: Checkout
24
- uses: actions/checkout@v4
24
+ uses: actions/checkout@v7
25
25
  with:
26
26
  persist-credentials: false
27
27
 
@@ -1,11 +1,9 @@
1
1
  name: Auto-release
2
2
 
3
+ # Called from ci.yml after the version bump, on pushes to master. A push
4
+ # that merged a bump PR has an untagged version, so this run releases it.
3
5
  on:
4
- workflow_run:
5
- workflows: ["Test"]
6
- branches: [master]
7
- types:
8
- - completed
6
+ workflow_call:
9
7
  workflow_dispatch:
10
8
 
11
9
  jobs:
@@ -13,12 +11,11 @@ jobs:
13
11
  runs-on: ubuntu-latest
14
12
  permissions:
15
13
  contents: write
16
- if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
17
14
  outputs:
18
15
  version_changed: ${{ steps.version-check.outputs.version_changed }}
19
16
 
20
17
  steps:
21
- - uses: actions/checkout@v4
18
+ - uses: actions/checkout@v7
22
19
  with:
23
20
  fetch-depth: 0 # Needed to get all tags for version comparison
24
21
 
@@ -28,9 +25,7 @@ jobs:
28
25
  python-version: "3.*"
29
26
 
30
27
  - name: Install uv
31
- uses: astral-sh/setup-uv@v4
32
- with:
33
- version: "latest"
28
+ uses: astral-sh/setup-uv@v7
34
29
 
35
30
  - name: Check if version changed
36
31
  id: version-check
@@ -1,14 +1,9 @@
1
1
  name: Test
2
2
 
3
+ # Called from ci.yml, which decides whether the inputs below changed.
3
4
  on:
4
- push:
5
- branches: [master]
6
- pull_request:
7
- branches: [master]
8
- workflow_dispatch:
9
5
  workflow_call:
10
-
11
- concurrency: test-${{ github.sha }}
6
+ workflow_dispatch:
12
7
 
13
8
  permissions:
14
9
  contents: read
@@ -18,32 +13,27 @@ jobs:
18
13
  runs-on: ubuntu-latest
19
14
  strategy:
20
15
  matrix:
21
- python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
16
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
22
17
  fail-fast: false
23
18
 
24
19
  steps:
25
- - uses: actions/checkout@v4
20
+ - uses: actions/checkout@v7
26
21
 
22
+ # A hit means these exact inputs already passed on this Python version.
23
+ # The cache only saves when the job succeeds, so a failure never hits.
27
24
  - name: Cache pytest results
28
25
  id: cache-pytest
29
26
  uses: actions/cache@v4
30
27
  with:
31
28
  path: .pytest_cache
32
- key: ${{ runner.os }}-pytest-${{ matrix.python-version }}-${{ hashFiles('**/tests/**/*.py', 'src/**') }}
29
+ key: ${{ runner.os }}-pytest-${{ matrix.python-version }}-${{ hashFiles('src/**', 'tests/**', 'pyproject.toml', 'uv.lock', '.github/workflows/test.yml', '.github/actions/setup/**') }}
33
30
 
34
- - name: Install uv
31
+ - name: Set up the project
35
32
  if: steps.cache-pytest.outputs.cache-hit != 'true'
36
- uses: astral-sh/setup-uv@v7
33
+ uses: ./.github/actions/setup
37
34
  with:
38
- enable-cache: true
39
-
40
- - name: Set up Python ${{ matrix.python-version }}
41
- if: steps.cache-pytest.outputs.cache-hit != 'true'
42
- run: uv python install ${{ matrix.python-version }}
43
-
44
- - name: Install dependencies
45
- if: steps.cache-pytest.outputs.cache-hit != 'true'
46
- run: uv sync --group dev
35
+ python-version: ${{ matrix.python-version }}
36
+ sync-args: --group dev
47
37
 
48
38
  - name: Run tests
49
39
  if: steps.cache-pytest.outputs.cache-hit != 'true'
@@ -55,7 +45,7 @@ jobs:
55
45
  clean-install:
56
46
  runs-on: ubuntu-latest
57
47
  steps:
58
- - uses: actions/checkout@v4
48
+ - uses: actions/checkout@v7
59
49
 
60
50
  - name: Install uv
61
51
  uses: astral-sh/setup-uv@v7
@@ -1,3 +1,6 @@
1
+ ci:
2
+ skip: [ty-check]
3
+
1
4
  default_install_hook_types:
2
5
  - pre-commit
3
6
  - post-checkout
@@ -76,7 +79,7 @@ repos:
76
79
  - id: ty-check
77
80
  name: ty check
78
81
  language: system
79
- entry: uvx ty check
82
+ entry: uvx ty check --ignore no-matching-overload
80
83
  pass_filenames: false
81
84
  files: ^src/.*\.py$
82
85
  stages: [pre-push, pre-commit]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: confkit
3
- Version: 2.2.0
3
+ Version: 3.0.0
4
4
  Summary: Lightweight and Easy to use configuration manager for Python projects
5
5
  Author: HEROgold
6
6
  License-File: LICENSE