lib-cli-exit-tools 2.2.3__tar.gz → 2.2.4__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.
- lib_cli_exit_tools-2.2.4/.github/workflows/default_cicd_public.yml +303 -0
- lib_cli_exit_tools-2.2.4/.github/workflows/default_release_public.yml +69 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/CHANGELOG.md +6 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/PKG-INFO +10 -10
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/README.md +1 -1
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/pyproject.toml +21 -10
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/__init__conf__.py +1 -1
- lib_cli_exit_tools-2.2.3/tests/test_scripts.py +0 -233
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.codacy/cli-config.yaml +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.codacy/cli.sh +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.codacy/codacy.yaml +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.codacy/tools-configs/lizard.yaml +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.codacy/tools-configs/trivy.yaml +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.devcontainer/devcontainer.json +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.devcontainer/settings.json +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.env.example +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.github/dependabot.yml +0 -0
- /lib_cli_exit_tools-2.2.3/.github/workflows/ci.yml → /lib_cli_exit_tools-2.2.4/.github/workflows/ci.yml_backup +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.github/workflows/codeql.yml +0 -0
- /lib_cli_exit_tools-2.2.3/.github/workflows/release.yml → /lib_cli_exit_tools-2.2.4/.github/workflows/release.yml_backup +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.gitignore +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.qlty/qlty.toml +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/.snyk +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/CLAUDE.md +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/CONTRIBUTING.md +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/DEVELOPMENT.md +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/INSTALL.md +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/LICENSE +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/Makefile +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/codecov.yml +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/docs/system-design/module_reference.md +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/notebooks/Quickstart.ipynb +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/__init__.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/__main__.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/_utils.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/build.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/bump.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/bump_major.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/bump_minor.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/bump_patch.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/bump_version.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/clean.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/cli.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/dependencies.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/dev.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/help.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/install.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/menu.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/push.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/release.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/run_cli.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/target_metadata.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/test.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/toml_config.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/scripts/version_current.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/__init__.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/__main__.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/adapters/__init__.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/adapters/signals.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/application/__init__.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/application/runner.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/cli.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/core/__init__.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/core/configuration.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/core/exit_codes.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/lib_cli_exit_tools.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/py.typed +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/conftest.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_adapters_signals.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_application_runner.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_behaviors.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_cli.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_core_configuration.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_core_exit_codes.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_metadata.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_module_entry.py +0 -0
- {lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/tests/test_signals_integration.py +0 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main, master ]
|
|
8
|
+
schedule:
|
|
9
|
+
# Run daily at 3:17 AM UTC (off-peak hours, odd minute to avoid congestion)
|
|
10
|
+
- cron: '17 3 * * *'
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Tests (Python ${{ matrix.python }}, ${{ matrix.os }})
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
20
|
+
# Test against all supported Python versions (3.10+)
|
|
21
|
+
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
22
|
+
env:
|
|
23
|
+
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: "1"
|
|
24
|
+
PYTHONIOENCODING: "utf-8"
|
|
25
|
+
UV_LINK_MODE: "copy"
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
|
+
- uses: actions/setup-python@v6
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python }}
|
|
31
|
+
- name: Install uv
|
|
32
|
+
uses: astral-sh/setup-uv@v7
|
|
33
|
+
with:
|
|
34
|
+
enable-cache: true
|
|
35
|
+
prune-cache: false
|
|
36
|
+
|
|
37
|
+
- name: Install tomli (Python < 3.11)
|
|
38
|
+
shell: bash
|
|
39
|
+
run: python -c "import tomllib" 2>/dev/null || uv pip install tomli --system
|
|
40
|
+
|
|
41
|
+
- name: Extract project metadata
|
|
42
|
+
shell: python
|
|
43
|
+
run: |
|
|
44
|
+
import os
|
|
45
|
+
try:
|
|
46
|
+
import tomllib
|
|
47
|
+
except ModuleNotFoundError:
|
|
48
|
+
import tomli as tomllib
|
|
49
|
+
|
|
50
|
+
with open('pyproject.toml', 'rb') as f:
|
|
51
|
+
data = tomllib.load(f)
|
|
52
|
+
project = data['project']['name']
|
|
53
|
+
module = project.replace('-', '_')
|
|
54
|
+
dash = project.replace('_', '-')
|
|
55
|
+
scripts = list(data['project'].get('scripts', {}).keys())
|
|
56
|
+
cli_bin = scripts[0] if scripts else dash
|
|
57
|
+
|
|
58
|
+
with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
|
|
59
|
+
env.write(f"PROJECT_NAME={project}\n")
|
|
60
|
+
env.write(f"PACKAGE_MODULE={module}\n")
|
|
61
|
+
env.write(f"CLI_BIN={cli_bin}\n")
|
|
62
|
+
|
|
63
|
+
- name: Install journald prerequisites
|
|
64
|
+
if: runner.os == 'Linux'
|
|
65
|
+
shell: bash
|
|
66
|
+
run: |
|
|
67
|
+
sudo apt-get update
|
|
68
|
+
sudo apt-get install -y python3-systemd
|
|
69
|
+
|
|
70
|
+
- name: Install dev deps
|
|
71
|
+
shell: bash
|
|
72
|
+
run: |
|
|
73
|
+
uv pip install -e .[dev] --system
|
|
74
|
+
|
|
75
|
+
- name: Install Windows Event Log prerequisites
|
|
76
|
+
if: runner.os == 'Windows'
|
|
77
|
+
shell: bash
|
|
78
|
+
run: |
|
|
79
|
+
uv pip install pywin32 --system
|
|
80
|
+
|
|
81
|
+
- name: Restore ruff cache
|
|
82
|
+
id: ruff-cache
|
|
83
|
+
uses: actions/cache/restore@v5
|
|
84
|
+
with:
|
|
85
|
+
path: .ruff_cache
|
|
86
|
+
key: ruff-${{ runner.os }}-py${{ matrix.python }}-${{ github.sha }}
|
|
87
|
+
restore-keys: |
|
|
88
|
+
ruff-${{ runner.os }}-py${{ matrix.python }}-
|
|
89
|
+
ruff-${{ runner.os }}-
|
|
90
|
+
|
|
91
|
+
- name: Run ruff (lint + format)
|
|
92
|
+
id: ruff
|
|
93
|
+
continue-on-error: true
|
|
94
|
+
shell: bash
|
|
95
|
+
run: |
|
|
96
|
+
ruff check src tests notebooks
|
|
97
|
+
ruff format --check src tests notebooks
|
|
98
|
+
|
|
99
|
+
- name: Run pyright (type check)
|
|
100
|
+
id: pyright
|
|
101
|
+
continue-on-error: true
|
|
102
|
+
shell: bash
|
|
103
|
+
run: pyright
|
|
104
|
+
|
|
105
|
+
- name: Run pytest (tests + coverage)
|
|
106
|
+
id: pytest
|
|
107
|
+
continue-on-error: true
|
|
108
|
+
shell: bash
|
|
109
|
+
env:
|
|
110
|
+
TEST_VERBOSE: "1"
|
|
111
|
+
run: pytest --cov=src --cov-report=term-missing --cov-report=xml
|
|
112
|
+
|
|
113
|
+
- name: Run import-linter (architecture)
|
|
114
|
+
id: importlinter
|
|
115
|
+
continue-on-error: true
|
|
116
|
+
shell: bash
|
|
117
|
+
run: lint-imports
|
|
118
|
+
|
|
119
|
+
- name: Run bandit (security scan)
|
|
120
|
+
id: bandit
|
|
121
|
+
continue-on-error: true
|
|
122
|
+
shell: bash
|
|
123
|
+
run: bandit -q -r src/${{ env.PACKAGE_MODULE }}
|
|
124
|
+
|
|
125
|
+
- name: Run pip-audit (vulnerability scan)
|
|
126
|
+
id: pipaudit
|
|
127
|
+
continue-on-error: true
|
|
128
|
+
shell: python
|
|
129
|
+
run: |
|
|
130
|
+
import subprocess, sys
|
|
131
|
+
try:
|
|
132
|
+
import tomllib
|
|
133
|
+
except ModuleNotFoundError:
|
|
134
|
+
import tomli as tomllib
|
|
135
|
+
with open("pyproject.toml", "rb") as f:
|
|
136
|
+
data = tomllib.load(f)
|
|
137
|
+
vulns = data.get("tool", {}).get("pip-audit", {}).get("ignore-vulns", [])
|
|
138
|
+
cmd = ["pip-audit", "--skip-editable"]
|
|
139
|
+
for v in vulns:
|
|
140
|
+
cmd.extend(["--ignore-vuln", v])
|
|
141
|
+
sys.exit(subprocess.call(cmd))
|
|
142
|
+
|
|
143
|
+
- name: Check all steps passed
|
|
144
|
+
shell: bash
|
|
145
|
+
run: |
|
|
146
|
+
if [[ "${{ steps.ruff.outcome }}" != "success" ]]; then
|
|
147
|
+
echo "::error::Ruff check failed"
|
|
148
|
+
exit 1
|
|
149
|
+
fi
|
|
150
|
+
if [[ "${{ steps.pyright.outcome }}" != "success" ]]; then
|
|
151
|
+
echo "::error::Pyright check failed"
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
if [[ "${{ steps.pytest.outcome }}" != "success" ]]; then
|
|
155
|
+
echo "::error::Pytest failed"
|
|
156
|
+
exit 1
|
|
157
|
+
fi
|
|
158
|
+
if [[ "${{ steps.importlinter.outcome }}" != "success" ]]; then
|
|
159
|
+
echo "::error::Import-linter check failed"
|
|
160
|
+
exit 1
|
|
161
|
+
fi
|
|
162
|
+
if [[ "${{ steps.bandit.outcome }}" != "success" ]]; then
|
|
163
|
+
echo "::error::Bandit security scan failed"
|
|
164
|
+
exit 1
|
|
165
|
+
fi
|
|
166
|
+
if [[ "${{ steps.pipaudit.outcome }}" != "success" ]]; then
|
|
167
|
+
echo "::error::pip-audit vulnerability scan failed"
|
|
168
|
+
exit 1
|
|
169
|
+
fi
|
|
170
|
+
echo "All checks passed!"
|
|
171
|
+
|
|
172
|
+
- name: Build wheel/sdist
|
|
173
|
+
shell: bash
|
|
174
|
+
run: uv build
|
|
175
|
+
|
|
176
|
+
- name: Verify wheel install in clean env
|
|
177
|
+
shell: bash
|
|
178
|
+
run: |
|
|
179
|
+
uv venv .venv_wheel
|
|
180
|
+
. .venv_wheel/bin/activate 2>/dev/null || . .venv_wheel/Scripts/activate 2>/dev/null
|
|
181
|
+
uv pip install dist/*.whl
|
|
182
|
+
"$CLI_BIN" --version 2>/dev/null || python -m "$PACKAGE_MODULE" --version
|
|
183
|
+
|
|
184
|
+
- name: Prune uv cache
|
|
185
|
+
continue-on-error: true
|
|
186
|
+
shell: bash
|
|
187
|
+
run: uv cache prune --ci
|
|
188
|
+
|
|
189
|
+
- name: Save ruff cache
|
|
190
|
+
if: always() && steps.ruff-cache.outputs.cache-hit != 'true'
|
|
191
|
+
uses: actions/cache/save@v5
|
|
192
|
+
with:
|
|
193
|
+
path: .ruff_cache
|
|
194
|
+
key: ruff-${{ runner.os }}-py${{ matrix.python }}-${{ github.sha }}
|
|
195
|
+
|
|
196
|
+
pipx-uv:
|
|
197
|
+
name: pipx/uv verification (ubuntu)
|
|
198
|
+
runs-on: ubuntu-latest
|
|
199
|
+
steps:
|
|
200
|
+
- uses: actions/checkout@v6
|
|
201
|
+
- uses: actions/setup-python@v6
|
|
202
|
+
with:
|
|
203
|
+
python-version: "3.14"
|
|
204
|
+
|
|
205
|
+
- name: Install uv
|
|
206
|
+
uses: astral-sh/setup-uv@v7
|
|
207
|
+
with:
|
|
208
|
+
enable-cache: true
|
|
209
|
+
prune-cache: false
|
|
210
|
+
|
|
211
|
+
- name: Install tomli (Python < 3.11)
|
|
212
|
+
shell: bash
|
|
213
|
+
run: python -c "import tomllib" 2>/dev/null || uv pip install tomli --system
|
|
214
|
+
|
|
215
|
+
- name: Extract project metadata
|
|
216
|
+
shell: python
|
|
217
|
+
run: |
|
|
218
|
+
import os
|
|
219
|
+
try:
|
|
220
|
+
import tomllib
|
|
221
|
+
except ModuleNotFoundError:
|
|
222
|
+
import tomli as tomllib
|
|
223
|
+
|
|
224
|
+
with open('pyproject.toml', 'rb') as f:
|
|
225
|
+
data = tomllib.load(f)
|
|
226
|
+
project = data['project']['name']
|
|
227
|
+
module = project.replace('-', '_')
|
|
228
|
+
dash = project.replace('_', '-')
|
|
229
|
+
scripts = list(data['project'].get('scripts', {}).keys())
|
|
230
|
+
cli_bin = scripts[0] if scripts else dash
|
|
231
|
+
|
|
232
|
+
with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
|
|
233
|
+
env.write(f"PROJECT_NAME={project}\n")
|
|
234
|
+
env.write(f"PACKAGE_MODULE={module}\n")
|
|
235
|
+
env.write(f"CLI_BIN={cli_bin}\n")
|
|
236
|
+
|
|
237
|
+
- name: Build wheel
|
|
238
|
+
run: uv build
|
|
239
|
+
- name: pipx install from wheel
|
|
240
|
+
run: |
|
|
241
|
+
uv pip install --system pipx
|
|
242
|
+
pipx ensurepath
|
|
243
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
244
|
+
pipx install dist/*.whl
|
|
245
|
+
"$CLI_BIN" --version
|
|
246
|
+
|
|
247
|
+
- name: uv tool install
|
|
248
|
+
run: |
|
|
249
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
250
|
+
uv tool install --force .
|
|
251
|
+
"$CLI_BIN" --version
|
|
252
|
+
|
|
253
|
+
- name: Prune uv cache
|
|
254
|
+
continue-on-error: true
|
|
255
|
+
run: uv cache prune --ci
|
|
256
|
+
|
|
257
|
+
notebooks:
|
|
258
|
+
name: Execute notebooks (ubuntu, Python 3.14)
|
|
259
|
+
runs-on: ubuntu-latest
|
|
260
|
+
steps:
|
|
261
|
+
- uses: actions/checkout@v6
|
|
262
|
+
- uses: actions/setup-python@v6
|
|
263
|
+
with:
|
|
264
|
+
python-version: "3.14"
|
|
265
|
+
|
|
266
|
+
- name: Install uv
|
|
267
|
+
uses: astral-sh/setup-uv@v7
|
|
268
|
+
with:
|
|
269
|
+
enable-cache: true
|
|
270
|
+
prune-cache: false
|
|
271
|
+
|
|
272
|
+
- name: Install notebook runner deps
|
|
273
|
+
run: |
|
|
274
|
+
uv pip install --system nbclient nbformat ipykernel jupyter_client
|
|
275
|
+
python -m ipykernel install --user --name python3 --display-name "Python 3"
|
|
276
|
+
- name: Execute Quickstart notebook
|
|
277
|
+
env:
|
|
278
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
|
279
|
+
PIP_NO_INPUT: "1"
|
|
280
|
+
run: |
|
|
281
|
+
python - << 'PY'
|
|
282
|
+
from pathlib import Path
|
|
283
|
+
|
|
284
|
+
import nbformat
|
|
285
|
+
from nbclient import NotebookClient
|
|
286
|
+
|
|
287
|
+
nb_path = Path('notebooks/Quickstart.ipynb')
|
|
288
|
+
if not nb_path.exists():
|
|
289
|
+
raise SystemExit(f"Notebook not found: {nb_path}")
|
|
290
|
+
|
|
291
|
+
notebook = nbformat.read(nb_path, as_version=4)
|
|
292
|
+
client = NotebookClient(
|
|
293
|
+
notebook,
|
|
294
|
+
timeout=900,
|
|
295
|
+
kernel_name='python3',
|
|
296
|
+
allow_errors=False,
|
|
297
|
+
)
|
|
298
|
+
client.execute()
|
|
299
|
+
|
|
300
|
+
out_path = Path('notebooks/Quickstart-executed.ipynb')
|
|
301
|
+
nbformat.write(notebook, out_path)
|
|
302
|
+
print(f"Executed notebook written to: {out_path}")
|
|
303
|
+
PY
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- 'v*'
|
|
9
|
+
workflow_dispatch: {}
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
env:
|
|
17
|
+
UV_LINK_MODE: "copy"
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
|
+
- uses: actions/setup-python@v6
|
|
21
|
+
with:
|
|
22
|
+
python-version: '3.14'
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v7
|
|
26
|
+
with:
|
|
27
|
+
enable-cache: true
|
|
28
|
+
prune-cache: false
|
|
29
|
+
|
|
30
|
+
- name: Build artifacts
|
|
31
|
+
run: uv build
|
|
32
|
+
|
|
33
|
+
- name: Upload artifacts
|
|
34
|
+
uses: actions/upload-artifact@v6
|
|
35
|
+
with:
|
|
36
|
+
name: dist
|
|
37
|
+
path: dist/*
|
|
38
|
+
|
|
39
|
+
- name: Prune uv cache
|
|
40
|
+
continue-on-error: true
|
|
41
|
+
run: uv cache prune --ci
|
|
42
|
+
|
|
43
|
+
publish:
|
|
44
|
+
needs: build
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
environment: pypi
|
|
47
|
+
permissions:
|
|
48
|
+
contents: read
|
|
49
|
+
steps:
|
|
50
|
+
- name: Verify PyPI token is set
|
|
51
|
+
run: |
|
|
52
|
+
if [ -z "${{ secrets.PYPI_API_TOKEN }}" ]; then
|
|
53
|
+
echo "::error title=Missing PyPI token::Set the PYPI_API_TOKEN secret in GitHub repository settings to enable PyPI publishing on releases."
|
|
54
|
+
echo "See: https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions"
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
- name: Download artifacts
|
|
59
|
+
uses: actions/download-artifact@v6
|
|
60
|
+
with:
|
|
61
|
+
name: dist
|
|
62
|
+
path: dist/
|
|
63
|
+
|
|
64
|
+
- name: Publish to PyPI
|
|
65
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
66
|
+
with:
|
|
67
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
68
|
+
attestations: false
|
|
69
|
+
skip-existing: true
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
## [2.2.4] - 2026-01-26
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- Updated dependencies.
|
|
10
|
+
- Excluded `scripts/` from pyright, pytest, and CI/CD test collection.
|
|
11
|
+
|
|
6
12
|
## [2.2.3] - 2025-12-17
|
|
7
13
|
|
|
8
14
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lib_cli_exit_tools
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.4
|
|
4
4
|
Summary: CLI exit handling helpers: clean signals, exit codes, and error printing
|
|
5
5
|
Project-URL: Homepage, https://github.com/bitranox/lib_cli_exit_tools
|
|
6
6
|
Project-URL: Repository, https://github.com/bitranox/lib_cli_exit_tools.git
|
|
@@ -16,29 +16,29 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
17
|
Classifier: Typing :: Typed
|
|
18
18
|
Requires-Python: >=3.10
|
|
19
|
-
Requires-Dist: rich-click>=1.9.
|
|
19
|
+
Requires-Dist: rich-click>=1.9.6
|
|
20
20
|
Provides-Extra: dev
|
|
21
|
-
Requires-Dist: bandit>=1.9.
|
|
22
|
-
Requires-Dist: build>=1.
|
|
21
|
+
Requires-Dist: bandit>=1.9.3; extra == 'dev'
|
|
22
|
+
Requires-Dist: build>=1.4.0; extra == 'dev'
|
|
23
23
|
Requires-Dist: codecov-cli>=11.2.6; extra == 'dev'
|
|
24
|
-
Requires-Dist: coverage[toml]>=7.13.
|
|
25
|
-
Requires-Dist: hypothesis>=6.
|
|
24
|
+
Requires-Dist: coverage[toml]>=7.13.2; extra == 'dev'
|
|
25
|
+
Requires-Dist: hypothesis>=6.151.2; extra == 'dev'
|
|
26
26
|
Requires-Dist: import-linter>=2.9; extra == 'dev'
|
|
27
27
|
Requires-Dist: pip-audit>=2.10.0; extra == 'dev'
|
|
28
|
-
Requires-Dist: pyright>=1.1.
|
|
28
|
+
Requires-Dist: pyright[nodejs]>=1.1.408; extra == 'dev'
|
|
29
29
|
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
|
|
30
30
|
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
31
31
|
Requires-Dist: pytest>=9.0.2; extra == 'dev'
|
|
32
32
|
Requires-Dist: rtoml>=0.13.0; extra == 'dev'
|
|
33
|
-
Requires-Dist: ruff>=0.14.
|
|
34
|
-
Requires-Dist: textual>=
|
|
33
|
+
Requires-Dist: ruff>=0.14.14; extra == 'dev'
|
|
34
|
+
Requires-Dist: textual>=7.4.0; extra == 'dev'
|
|
35
35
|
Requires-Dist: twine>=6.2.0; extra == 'dev'
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
38
38
|
# lib_cli_exit_tools
|
|
39
39
|
|
|
40
40
|
<!-- Badges -->
|
|
41
|
-
[](https://github.com/bitranox/lib_cli_exit_tools/actions/workflows/default_cicd_public.yml)
|
|
42
42
|
[](https://github.com/bitranox/lib_cli_exit_tools/actions/workflows/codeql.yml)
|
|
43
43
|
[](LICENSE)
|
|
44
44
|
[](https://codespaces.new/bitranox/lib_cli_exit_tools?quickstart=1)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# lib_cli_exit_tools
|
|
2
2
|
|
|
3
3
|
<!-- Badges -->
|
|
4
|
-
[](https://github.com/bitranox/lib_cli_exit_tools/actions/workflows/default_cicd_public.yml)
|
|
5
5
|
[](https://github.com/bitranox/lib_cli_exit_tools/actions/workflows/codeql.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://codespaces.new/bitranox/lib_cli_exit_tools?quickstart=1)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "lib_cli_exit_tools"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.4"
|
|
4
4
|
description = "CLI exit handling helpers: clean signals, exit codes, and error printing"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
7
|
-
dependencies = ["rich-click>=1.9.
|
|
7
|
+
dependencies = ["rich-click>=1.9.6"]
|
|
8
8
|
license = { text = "MIT" }
|
|
9
9
|
authors = [{ name = "bitranox", email = "bitranox@gmail.com" }]
|
|
10
10
|
keywords = ["cli", "exit", "signals", "errors", "click"]
|
|
@@ -24,19 +24,19 @@ Issues = "https://github.com/bitranox/lib_cli_exit_tools/issues"
|
|
|
24
24
|
|
|
25
25
|
[project.optional-dependencies]
|
|
26
26
|
dev = [
|
|
27
|
-
"build>=1.
|
|
27
|
+
"build>=1.4.0",
|
|
28
28
|
"codecov-cli>=11.2.6",
|
|
29
|
-
"coverage[toml]>=7.13.
|
|
30
|
-
"hypothesis>=6.
|
|
29
|
+
"coverage[toml]>=7.13.2",
|
|
30
|
+
"hypothesis>=6.151.2",
|
|
31
31
|
"import-linter>=2.9",
|
|
32
|
-
"bandit>=1.9.
|
|
32
|
+
"bandit>=1.9.3",
|
|
33
33
|
"pip-audit>=2.10.0",
|
|
34
|
-
"pyright>=1.1.
|
|
34
|
+
"pyright[nodejs]>=1.1.408",
|
|
35
35
|
"pytest>=9.0.2",
|
|
36
36
|
"pytest-asyncio>=1.3.0",
|
|
37
37
|
"pytest-cov>=7.0.0",
|
|
38
|
-
"ruff>=0.14.
|
|
39
|
-
"textual>=
|
|
38
|
+
"ruff>=0.14.14",
|
|
39
|
+
"textual>=7.4.0",
|
|
40
40
|
"rtoml>=0.13.0",
|
|
41
41
|
"twine>=6.2.0"
|
|
42
42
|
]
|
|
@@ -66,12 +66,13 @@ target-version = "py310"
|
|
|
66
66
|
[tool.pyright]
|
|
67
67
|
typeCheckingMode = "strict"
|
|
68
68
|
exclude = [
|
|
69
|
-
"scripts/
|
|
69
|
+
"scripts/",
|
|
70
70
|
]
|
|
71
71
|
|
|
72
72
|
[tool.pytest.ini_options]
|
|
73
73
|
addopts = ["--doctest-modules"]
|
|
74
74
|
pythonpath = ["src"]
|
|
75
|
+
testpaths = ["src", "tests"]
|
|
75
76
|
doctest_optionflags = ["ELLIPSIS", "NORMALIZE_WHITESPACE"]
|
|
76
77
|
markers = [
|
|
77
78
|
"os_agnostic: test exercises behavior that is the same on every operating system",
|
|
@@ -161,6 +162,11 @@ forbidden_modules = [
|
|
|
161
162
|
# setuptools version is managed by the CI environment/pip itself.
|
|
162
163
|
# CVE-2025-68146: filelock <3.20.1 vulnerability, transitive dev dependency
|
|
163
164
|
# Will be resolved when upstream packages update their dependencies.
|
|
165
|
+
# CVE-2026-23949: jaraco-context <6.1.0, transitive dev dependency
|
|
166
|
+
# CVE-2025-69277: pynacl <1.6.2, transitive dev dependency
|
|
167
|
+
# CVE-2026-21441: urllib3 <2.6.3, transitive dev dependency
|
|
168
|
+
# CVE-2026-22702: virtualenv <20.36.1, transitive dev dependency
|
|
169
|
+
# CVE-2026-24049: wheel <0.46.2, build-time dependency
|
|
164
170
|
ignore-vulns = [
|
|
165
171
|
"GHSA-4xh5-x5gv-qwph",
|
|
166
172
|
"PYSEC-2022-42969",
|
|
@@ -168,4 +174,9 @@ ignore-vulns = [
|
|
|
168
174
|
"CVE-2024-6345",
|
|
169
175
|
"PYSEC-2025-49",
|
|
170
176
|
"CVE-2025-68146",
|
|
177
|
+
"CVE-2026-23949",
|
|
178
|
+
"CVE-2025-69277",
|
|
179
|
+
"CVE-2026-21441",
|
|
180
|
+
"CVE-2026-22702",
|
|
181
|
+
"CVE-2026-24049",
|
|
171
182
|
]
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/__init__conf__.py
RENAMED
|
@@ -24,7 +24,7 @@ name = "lib_cli_exit_tools"
|
|
|
24
24
|
#: Human-readable summary shown in CLI help output.
|
|
25
25
|
title = "CLI exit handling helpers: clean signals, exit codes, and error printing"
|
|
26
26
|
#: Current release version pulled from ``pyproject.toml`` by automation.
|
|
27
|
-
version = "2.2.
|
|
27
|
+
version = "2.2.4"
|
|
28
28
|
#: Repository homepage presented to users.
|
|
29
29
|
homepage = "https://github.com/bitranox/lib_cli_exit_tools"
|
|
30
30
|
#: Author attribution surfaced in CLI output.
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from click.testing import CliRunner
|
|
4
|
-
from collections.abc import Mapping, Sequence
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
import sys
|
|
7
|
-
from types import ModuleType, SimpleNamespace
|
|
8
|
-
from typing import Protocol, TypedDict
|
|
9
|
-
|
|
10
|
-
from pytest import MonkeyPatch
|
|
11
|
-
|
|
12
|
-
import scripts.build as build
|
|
13
|
-
import scripts.cli as cli
|
|
14
|
-
import scripts.dev as dev
|
|
15
|
-
import scripts.install as install
|
|
16
|
-
import scripts.run_cli as run_cli
|
|
17
|
-
import scripts.test as test_script
|
|
18
|
-
from scripts._utils import RunResult
|
|
19
|
-
from scripts import _utils
|
|
20
|
-
from scripts import target_metadata
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
RunCommand = Sequence[str] | str
|
|
24
|
-
ModuleLike = ModuleType | SimpleNamespace
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class RecordedOptions(TypedDict):
|
|
28
|
-
check: bool
|
|
29
|
-
capture: bool
|
|
30
|
-
cwd: str | None
|
|
31
|
-
env: Mapping[str, str] | None
|
|
32
|
-
dry_run: bool
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
RunRecord = tuple[RunCommand, RecordedOptions]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class RunStub(Protocol):
|
|
39
|
-
def __call__(
|
|
40
|
-
self,
|
|
41
|
-
cmd: RunCommand,
|
|
42
|
-
*,
|
|
43
|
-
check: bool = True,
|
|
44
|
-
capture: bool = True,
|
|
45
|
-
cwd: str | None = None,
|
|
46
|
-
env: Mapping[str, str] | None = None,
|
|
47
|
-
dry_run: bool = False,
|
|
48
|
-
) -> RunResult: ...
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def _make_run_recorder(record: list[RunRecord]) -> RunStub:
|
|
52
|
-
def _run(
|
|
53
|
-
cmd: RunCommand,
|
|
54
|
-
*,
|
|
55
|
-
check: bool = True,
|
|
56
|
-
capture: bool = True,
|
|
57
|
-
cwd: str | None = None,
|
|
58
|
-
env: Mapping[str, str] | None = None,
|
|
59
|
-
dry_run: bool = False,
|
|
60
|
-
) -> RunResult:
|
|
61
|
-
record.append(
|
|
62
|
-
(
|
|
63
|
-
cmd,
|
|
64
|
-
{
|
|
65
|
-
"check": check,
|
|
66
|
-
"capture": capture,
|
|
67
|
-
"cwd": cwd,
|
|
68
|
-
"env": env,
|
|
69
|
-
"dry_run": dry_run,
|
|
70
|
-
},
|
|
71
|
-
),
|
|
72
|
-
)
|
|
73
|
-
return RunResult(0, "", "")
|
|
74
|
-
|
|
75
|
-
return _run
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def test_get_project_metadata_fields():
|
|
79
|
-
meta = _utils.get_project_metadata()
|
|
80
|
-
assert meta.name == "lib_cli_exit_tools"
|
|
81
|
-
assert meta.slug == "lib-cli-exit-tools"
|
|
82
|
-
assert meta.import_package == "lib_cli_exit_tools"
|
|
83
|
-
assert meta.coverage_source == "src/lib_cli_exit_tools"
|
|
84
|
-
assert meta.github_tarball_url("1.2.3").endswith("/bitranox/lib_cli_exit_tools/archive/refs/tags/v1.2.3.tar.gz")
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def test_build_script_uses_metadata(monkeypatch: MonkeyPatch) -> None:
|
|
88
|
-
recorded: list[RunRecord] = []
|
|
89
|
-
monkeypatch.setattr(build, "run", _make_run_recorder(recorded))
|
|
90
|
-
runner = CliRunner()
|
|
91
|
-
result = runner.invoke(cli.main, ["build"])
|
|
92
|
-
assert result.exit_code == 0
|
|
93
|
-
commands = [" ".join(cmd) if not isinstance(cmd, str) else cmd for cmd, _ in recorded]
|
|
94
|
-
assert any("python -m build" in cmd for cmd in commands)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def test_dev_script_installs_dev_extras(monkeypatch: MonkeyPatch) -> None:
|
|
98
|
-
recorded: list[RunRecord] = []
|
|
99
|
-
monkeypatch.setattr(dev, "run", _make_run_recorder(recorded))
|
|
100
|
-
runner = CliRunner()
|
|
101
|
-
result = runner.invoke(cli.main, ["dev"])
|
|
102
|
-
assert result.exit_code == 0
|
|
103
|
-
first_command, _options = recorded[0]
|
|
104
|
-
assert isinstance(first_command, list)
|
|
105
|
-
assert first_command == [sys.executable, "-m", "pip", "install", "-e", ".[dev]"]
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def test_install_script_installs_package(monkeypatch: MonkeyPatch) -> None:
|
|
109
|
-
recorded: list[RunRecord] = []
|
|
110
|
-
monkeypatch.setattr(install, "run", _make_run_recorder(recorded))
|
|
111
|
-
runner = CliRunner()
|
|
112
|
-
result = runner.invoke(cli.main, ["install"])
|
|
113
|
-
assert result.exit_code == 0
|
|
114
|
-
first_command, _options = recorded[0]
|
|
115
|
-
assert isinstance(first_command, list)
|
|
116
|
-
assert first_command == [sys.executable, "-m", "pip", "install", "-e", "."]
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def test_run_cli_imports_dynamic_package(monkeypatch: MonkeyPatch) -> None:
|
|
120
|
-
seen: list[str] = []
|
|
121
|
-
|
|
122
|
-
def _run_cli_main(_args: Sequence[str] | None = None) -> int:
|
|
123
|
-
return 0
|
|
124
|
-
|
|
125
|
-
def fake_import(name: str) -> ModuleLike:
|
|
126
|
-
seen.append(name)
|
|
127
|
-
if name.endswith(".__main__"):
|
|
128
|
-
return SimpleNamespace()
|
|
129
|
-
if name.endswith(".cli"):
|
|
130
|
-
return SimpleNamespace(main=_run_cli_main)
|
|
131
|
-
raise AssertionError(f"unexpected import {name}")
|
|
132
|
-
|
|
133
|
-
monkeypatch.setattr(run_cli, "import_module", fake_import)
|
|
134
|
-
runner = CliRunner()
|
|
135
|
-
result = runner.invoke(cli.main, ["run"])
|
|
136
|
-
assert result.exit_code == 0
|
|
137
|
-
package = run_cli.PROJECT.import_package
|
|
138
|
-
assert f"{package}.cli" in seen
|
|
139
|
-
if len(seen) == 2:
|
|
140
|
-
assert seen == [f"{package}.__main__", f"{package}.cli"]
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def test_test_script_uses_pyproject_configuration(monkeypatch: MonkeyPatch) -> None:
|
|
144
|
-
recorded: list[RunRecord] = []
|
|
145
|
-
|
|
146
|
-
def _noop() -> None:
|
|
147
|
-
return None
|
|
148
|
-
|
|
149
|
-
def _always_false(_name: str) -> bool:
|
|
150
|
-
return False
|
|
151
|
-
|
|
152
|
-
monkeypatch.setattr(test_script, "bootstrap_dev", _noop)
|
|
153
|
-
monkeypatch.setattr(_utils, "cmd_exists", _always_false)
|
|
154
|
-
monkeypatch.setattr(test_script, "run", _make_run_recorder(recorded))
|
|
155
|
-
runner = CliRunner()
|
|
156
|
-
result = runner.invoke(cli.main, ["test"])
|
|
157
|
-
assert result.exit_code == 0
|
|
158
|
-
pytest_commands: list[list[str]] = []
|
|
159
|
-
for cmd, _ in recorded:
|
|
160
|
-
if isinstance(cmd, str):
|
|
161
|
-
continue
|
|
162
|
-
command_list = list(cmd)
|
|
163
|
-
if command_list[:3] == ["python", "-m", "pytest"]:
|
|
164
|
-
pytest_commands.append(command_list)
|
|
165
|
-
assert pytest_commands, "pytest not invoked"
|
|
166
|
-
assert any(f"--cov={test_script.COVERAGE_TARGET}" in " ".join(sequence) for sequence in pytest_commands)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def test_run_coverage_invokes_python_module(monkeypatch: MonkeyPatch) -> None:
|
|
170
|
-
recorded: list[RunRecord] = []
|
|
171
|
-
bootstrap_calls: list[str] = []
|
|
172
|
-
|
|
173
|
-
def _bootstrap() -> None:
|
|
174
|
-
bootstrap_calls.append("bootstrap")
|
|
175
|
-
|
|
176
|
-
monkeypatch.setattr(test_script, "bootstrap_dev", _bootstrap)
|
|
177
|
-
monkeypatch.setattr(test_script, "run", _make_run_recorder(recorded))
|
|
178
|
-
|
|
179
|
-
# create stale coverage artefacts to ensure cleanup happens first
|
|
180
|
-
Path(".coverage.stale").write_text("stale", encoding="utf-8")
|
|
181
|
-
Path("coverage.xml").write_text("old", encoding="utf-8")
|
|
182
|
-
Path("codecov.xml").write_text("old", encoding="utf-8")
|
|
183
|
-
|
|
184
|
-
test_script.run_coverage()
|
|
185
|
-
|
|
186
|
-
assert bootstrap_calls == ["bootstrap"]
|
|
187
|
-
assert len(recorded) == 2
|
|
188
|
-
|
|
189
|
-
first_cmd, first_opts = recorded[0]
|
|
190
|
-
assert isinstance(first_cmd, list)
|
|
191
|
-
assert first_cmd[:4] == [sys.executable, "-m", "coverage", "run"]
|
|
192
|
-
assert first_cmd[4:7] == ["-m", "pytest", "-vv"]
|
|
193
|
-
assert first_opts["capture"] is True
|
|
194
|
-
assert first_opts["env"] is not None
|
|
195
|
-
assert first_opts["env"].get("COVERAGE_NO_SQL") == "1"
|
|
196
|
-
coverage_file = first_opts["env"].get("COVERAGE_FILE", "")
|
|
197
|
-
assert coverage_file.endswith(".coverage")
|
|
198
|
-
assert coverage_file != ".coverage"
|
|
199
|
-
assert Path(coverage_file).is_absolute()
|
|
200
|
-
|
|
201
|
-
second_cmd, second_opts = recorded[1]
|
|
202
|
-
assert isinstance(second_cmd, list)
|
|
203
|
-
assert second_cmd[:5] == [sys.executable, "-m", "coverage", "report", "-m"]
|
|
204
|
-
assert second_opts["capture"] is True
|
|
205
|
-
assert second_opts["env"] is not None
|
|
206
|
-
assert second_opts["env"].get("COVERAGE_NO_SQL") == "1"
|
|
207
|
-
assert second_opts["env"].get("COVERAGE_FILE") == coverage_file
|
|
208
|
-
|
|
209
|
-
assert not Path(".coverage.stale").exists()
|
|
210
|
-
assert not Path("coverage.xml").exists()
|
|
211
|
-
assert not Path("codecov.xml").exists()
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def test_cli_coverage_command_toggles_verbose(monkeypatch: MonkeyPatch) -> None:
|
|
215
|
-
invoked: dict[str, bool] = {}
|
|
216
|
-
|
|
217
|
-
def _cover(*, verbose: bool) -> None:
|
|
218
|
-
invoked["verbose"] = verbose
|
|
219
|
-
|
|
220
|
-
monkeypatch.setattr(test_script, "run_coverage", _cover)
|
|
221
|
-
runner = CliRunner()
|
|
222
|
-
result = runner.invoke(cli.main, ["coverage", "--verbose"])
|
|
223
|
-
|
|
224
|
-
assert result.exit_code == 0
|
|
225
|
-
assert invoked == {"verbose": True}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
def test_target_metadata_includes_coverage_entry() -> None:
|
|
229
|
-
targets = target_metadata.get_targets()
|
|
230
|
-
coverage_entries = [t for t in targets if t.name == "coverage"]
|
|
231
|
-
assert coverage_entries
|
|
232
|
-
(entry,) = coverage_entries
|
|
233
|
-
assert entry.description.startswith("Run python -m coverage")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/docs/system-design/module_reference.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/adapters/__init__.py
RENAMED
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/adapters/signals.py
RENAMED
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/application/__init__.py
RENAMED
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/application/runner.py
RENAMED
|
File without changes
|
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/core/__init__.py
RENAMED
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/core/configuration.py
RENAMED
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/core/exit_codes.py
RENAMED
|
File without changes
|
{lib_cli_exit_tools-2.2.3 → lib_cli_exit_tools-2.2.4}/src/lib_cli_exit_tools/lib_cli_exit_tools.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|