nvda-addon-testkit 0.1.0__tar.gz → 0.1.3__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.
- nvda_addon_testkit-0.1.3/.github/CODEOWNERS +1 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/.github}/CONTRIBUTING.md +5 -5
- nvda_addon_testkit-0.1.3/.github/workflows/CI.yml +98 -0
- nvda_addon_testkit-0.1.3/.github/workflows/notify-docs.yml +52 -0
- nvda_addon_testkit-0.1.3/.github/workflows/prepare-release.yml +154 -0
- nvda_addon_testkit-0.1.3/.github/workflows/project-sync.yml +15 -0
- nvda_addon_testkit-0.1.3/.github/workflows/publish-python.yml +85 -0
- nvda_addon_testkit-0.1.3/.github/workflows/sonar-fork-coverage.yml +120 -0
- nvda_addon_testkit-0.1.3/.github/workflows/sonar-fork-scan.yml +205 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/.github/workflows/sonar.yml +23 -6
- nvda_addon_testkit-0.1.3/.github/workflows/stale.yml +43 -0
- nvda_addon_testkit-0.1.3/.github/workflows/zizmor.yml +32 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/.gitignore +1 -0
- nvda_addon_testkit-0.1.3/.sonarlint/connectedMode.json +5 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/PKG-INFO +22 -2
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/README.md +17 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/action.yml +11 -4
- nvda_addon_testkit-0.1.3/docs/antora.yml +5 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/docs/modules/ROOT}/examples/demo-addon/globalPlugins/testkit_demo.py +2 -6
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/docs/modules/ROOT}/examples/demo-addon/manifest.ini +4 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/docs/modules/ROOT/examples}/tests_e2e/conftest.py +0 -6
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/docs/modules/ROOT/examples}/tests_e2e/test_demo_addon.py +6 -7
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/docs/modules/ROOT/examples}/tests_e2e/test_smoke.py +6 -7
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/nav.adoc +15 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/ci-guide.adoc +143 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/contributing.adoc +3 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/example-project.adoc +71 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/guide/addons.adoc +40 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/guide/braille.adoc +18 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/guide/config.adoc +24 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/guide/fixtures.adoc +42 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/guide/keys.adoc +15 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/guide/log.adoc +17 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/guide/speech.adoc +16 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/index.adoc +72 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/installation.adoc +35 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/troubleshooting.adoc +112 -0
- nvda_addon_testkit-0.1.3/docs/modules/ROOT/pages/tutorial.adoc +110 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/pyproject.toml +22 -7
- nvda_addon_testkit-0.1.3/scripts/next-version.sh +55 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/__init__.py +4 -13
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/addons_api.py +0 -7
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/braille_tap.py +0 -5
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/config_api.py +0 -10
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/input_api.py +0 -3
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/log_tap.py +1 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/mainthread.py +0 -3
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/registry.py +0 -2
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/serialise.py +0 -3
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/server.py +0 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/speech_tap.py +0 -1
- nvda_addon_testkit-0.1.3/spy/manifest.ini +17 -0
- nvda_addon_testkit-0.1.3/src/nvda_testkit/_spy/nvda-testkit-spy.nvda-addon +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/_version.py +2 -2
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/client.py +0 -4
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/download.py +0 -3
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/plugin.py +0 -5
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/portable.py +0 -4
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/process.py +1 -15
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/provisioning.py +0 -6
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/rpcclient.py +0 -6
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/settings.py +0 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/speechtypes.py +0 -3
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/fake_nvda.py +0 -17
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/fixtures/snapshot_index_alpha.html +1 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_client.py +0 -6
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_download.py +0 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_fake_nvda.py +0 -5
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_plugin.py +0 -8
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_portable.py +0 -2
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_process.py +1 -3
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_resolve.py +0 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/nvda_stubs.py +0 -9
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_braille_tap.py +0 -2
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_config_api.py +0 -3
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_mainthread.py +0 -1
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_plugin.py +0 -5
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_server.py +0 -1
- nvda_addon_testkit-0.1.3/uv.lock +1188 -0
- nvda_addon_testkit-0.1.0/.github/release-drafter.yml +0 -36
- nvda_addon_testkit-0.1.0/.github/workflows/ci.yml +0 -74
- nvda_addon_testkit-0.1.0/.github/workflows/publish.yml +0 -40
- nvda_addon_testkit-0.1.0/.github/workflows/release-drafter.yml +0 -23
- nvda_addon_testkit-0.1.0/spy/manifest.ini +0 -8
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/.github/pull_request_template.md +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/.github}/renovate.json +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/LICENSE +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3/docs/modules/ROOT}/examples/demo-addon/build.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/ruff.toml +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/sonar-project.properties +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/spy/globalPlugins/nvda_testkit_spy/eval_api.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/__init__.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/cli.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/errors.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/namespaces/__init__.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/namespaces/addons.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/namespaces/braille.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/namespaces/config.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/namespaces/keys.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/namespaces/log.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/namespaces/speech.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/resolve.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/src/nvda_testkit/spybundle.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/conftest.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/fixtures/update_check_stable.txt +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_addons_namespace.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_braille_namespace.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_build_spy.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_cli.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_config_namespace.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_e2e_conftest.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_errors.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_keys_namespace.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_log_namespace.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_provisioning.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_rpcclient.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_settings.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_speech_namespace.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests/test_speechtypes.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/__init__.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/conftest.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_addons_api.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_eval_api.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_input_api.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_log_tap.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_registry.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_serialise.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tests_spy/test_speech_tap.py +0 -0
- {nvda_addon_testkit-0.1.0 → nvda_addon_testkit-0.1.3}/tools/build_spy.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @ZirekHQ/maintainers
|
|
@@ -54,11 +54,11 @@ Use the pull request template. Link the issue with `Closes #N` in the PR body wh
|
|
|
54
54
|
|
|
55
55
|
Releases are tag-driven, not version-bumped by hand — `pyproject.toml` has no `version` field. The `hatch-vcs` build hook derives the package version from the git tag at build time.
|
|
56
56
|
|
|
57
|
-
1.
|
|
58
|
-
2.
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
1. Run `prepare-release.yml` (Actions tab → **Prepare release** → Run workflow). Leave `new_tag` blank to let it compute the next version from Conventional Commit subjects since the last tag (`scripts/next-version.sh`); pass a `vX.Y.Z` value there instead to override it. Check `dry_run` to only see the computed version without tagging or publishing anything.
|
|
58
|
+
2. The `release` environment gate requires a maintainer approval before anything happens — that's the human checkpoint, not the version computation.
|
|
59
|
+
3. Once approved, `prepare-release.yml`'s `tag-and-release` job tags `main` at the resolved commit, force-moves the `v<major>` tag consumers pin (README and GitHub Marketplace listings use `@v1`), and publishes the GitHub Release with auto-generated notes.
|
|
60
|
+
4. That tag feeds `publish-python.yml`, which builds the sdist/wheel and uploads to PyPI via Trusted Publishing — no token to rotate.
|
|
61
61
|
|
|
62
62
|
### Why not fully automate this (conventional commits + semantic-release)?
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
The version bump itself *is* automated — computed from commit prefixes since the last tag. What's deliberately kept manual is the human approval gate before anything tags or publishes: pre-1.0 semver bumps (does this `feat:` deserve a minor, or does it actually break the fixture API?) are judgment calls worth a maintainer's eyes before they go to PyPI and the Marketplace. Worth revisiting if release volume ever makes that approval step the actual bottleneck.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
lint:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 10
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.13"
|
|
27
|
+
- run: 'pip install --only-binary :all: ruff'
|
|
28
|
+
- run: ruff check .
|
|
29
|
+
- run: ruff format --check .
|
|
30
|
+
|
|
31
|
+
dependency-audit:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
timeout-minutes: 10
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
36
|
+
with:
|
|
37
|
+
persist-credentials: false
|
|
38
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.13"
|
|
41
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
42
|
+
- run: 'pip install --only-binary :all: pip-audit'
|
|
43
|
+
- run: pip-audit
|
|
44
|
+
|
|
45
|
+
unit:
|
|
46
|
+
runs-on: ${{ matrix.os }}
|
|
47
|
+
timeout-minutes: 15
|
|
48
|
+
strategy:
|
|
49
|
+
fail-fast: false
|
|
50
|
+
matrix:
|
|
51
|
+
os: [ubuntu-latest, windows-2025]
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
54
|
+
with:
|
|
55
|
+
persist-credentials: false
|
|
56
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
57
|
+
with:
|
|
58
|
+
python-version: "3.13"
|
|
59
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
60
|
+
- run: python tools/build_spy.py
|
|
61
|
+
# Bare `pytest` so testpaths picks up tests_spy/ too. An explicit
|
|
62
|
+
# `pytest tests/` silently skips every spy test in CI.
|
|
63
|
+
- run: pytest -v
|
|
64
|
+
|
|
65
|
+
e2e:
|
|
66
|
+
runs-on: ${{ matrix.os }}
|
|
67
|
+
timeout-minutes: 30
|
|
68
|
+
strategy:
|
|
69
|
+
fail-fast: false
|
|
70
|
+
matrix:
|
|
71
|
+
# windows-2022 covers Windows 10 22H2 (ESU). Drop it once ESU
|
|
72
|
+
# coverage is no longer needed.
|
|
73
|
+
os: [windows-2025, windows-2022]
|
|
74
|
+
channel: [stable, alpha]
|
|
75
|
+
continue-on-error: ${{ matrix.channel == 'alpha' }}
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
78
|
+
with:
|
|
79
|
+
persist-credentials: false
|
|
80
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
81
|
+
with:
|
|
82
|
+
python-version: "3.13"
|
|
83
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
84
|
+
- run: python tools/build_spy.py
|
|
85
|
+
- name: Cache NVDA launchers
|
|
86
|
+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
|
87
|
+
with:
|
|
88
|
+
path: ~/.cache/nvda-testkit
|
|
89
|
+
key: nvda-launcher-${{ matrix.os }}-${{ matrix.channel }}-${{ github.run_id }}
|
|
90
|
+
restore-keys: nvda-launcher-${{ matrix.os }}-${{ matrix.channel }}-
|
|
91
|
+
- run: nvda-testkit doctor
|
|
92
|
+
- run: pytest tests_e2e/ -v --nvda-channel=${{ matrix.channel }}
|
|
93
|
+
- if: failure()
|
|
94
|
+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
|
95
|
+
with:
|
|
96
|
+
name: e2e-${{ matrix.os }}-${{ matrix.channel }}-artifacts
|
|
97
|
+
path: testOutput/
|
|
98
|
+
if-no-files-found: warn
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: Notify docs site
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
ref:
|
|
9
|
+
description: Ref or tag to notify about (defaults to the current ref)
|
|
10
|
+
required: false
|
|
11
|
+
type: string
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
dispatch:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 10
|
|
20
|
+
steps:
|
|
21
|
+
- name: Resolve ref
|
|
22
|
+
id: resolve
|
|
23
|
+
env:
|
|
24
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
25
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
26
|
+
INPUT_REF: ${{ inputs.ref }}
|
|
27
|
+
DEFAULT_REF: ${{ github.ref_name }}
|
|
28
|
+
run: |
|
|
29
|
+
if [ "$EVENT_NAME" = "release" ]; then
|
|
30
|
+
ref="$RELEASE_TAG"
|
|
31
|
+
else
|
|
32
|
+
ref="${INPUT_REF:-$DEFAULT_REF}"
|
|
33
|
+
fi
|
|
34
|
+
if ! git check-ref-format --branch "$ref" >/dev/null 2>&1 \
|
|
35
|
+
&& ! git check-ref-format "refs/tags/$ref" >/dev/null 2>&1; then
|
|
36
|
+
echo "Invalid ref: $ref" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
echo "ref=$ref" >> "$GITHUB_OUTPUT"
|
|
40
|
+
|
|
41
|
+
- name: Dispatch update to docs site
|
|
42
|
+
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
|
|
43
|
+
with:
|
|
44
|
+
token: ${{ secrets.DOCS_DISPATCH_TOKEN }}
|
|
45
|
+
repository: ZirekHQ/ZirekHQ.github.io
|
|
46
|
+
event-type: update-docs
|
|
47
|
+
client-payload: |-
|
|
48
|
+
{
|
|
49
|
+
"repository": ${{ toJSON(github.repository) }},
|
|
50
|
+
"ref": ${{ toJSON(steps.resolve.outputs.ref) }},
|
|
51
|
+
"actor": ${{ toJSON(github.actor) }}
|
|
52
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
name: Prepare release
|
|
2
|
+
|
|
3
|
+
# The single dispatch surface for cutting a release. hatch-vcs derives the version from the
|
|
4
|
+
# git tag (pyproject.toml), so there's no version file to bump or PR to open first -- the
|
|
5
|
+
# environment:release approval gate below is the human checkpoint instead.
|
|
6
|
+
#
|
|
7
|
+
# tag-and-release and pypi live here rather than in a separate workflow_call file: PyPI's
|
|
8
|
+
# trusted-publisher attestation check verifies the Build Config URI against the *root*
|
|
9
|
+
# dispatched workflow, not the immediate caller, so a second layer of workflow_call between
|
|
10
|
+
# this dispatch and publish-python.yml breaks it (confirmed by three failed release runs
|
|
11
|
+
# where the Build Config URI reported the wrong workflow entirely).
|
|
12
|
+
on:
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
inputs:
|
|
15
|
+
new_tag:
|
|
16
|
+
description: "Override the vX.Y.Z tag"
|
|
17
|
+
required: false
|
|
18
|
+
type: string
|
|
19
|
+
dry_run:
|
|
20
|
+
description: "Dry Run: compute the version, tag nothing, publish nothing"
|
|
21
|
+
required: false
|
|
22
|
+
type: boolean
|
|
23
|
+
default: false
|
|
24
|
+
|
|
25
|
+
permissions: {}
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
compute-version:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
timeout-minutes: 10
|
|
31
|
+
permissions:
|
|
32
|
+
contents: read
|
|
33
|
+
outputs:
|
|
34
|
+
version: ${{ steps.next.outputs.version }}
|
|
35
|
+
sha: ${{ steps.resolve-sha.outputs.sha }}
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
38
|
+
with:
|
|
39
|
+
ref: main
|
|
40
|
+
fetch-depth: 0
|
|
41
|
+
persist-credentials: false
|
|
42
|
+
|
|
43
|
+
# Exported so tag-and-release tags/checks-out this exact commit rather than the dispatch's
|
|
44
|
+
# own github.sha -- main can move during approve's wait, and this checkout is the only
|
|
45
|
+
# thing pinning which commit the computed version actually describes.
|
|
46
|
+
- name: Resolve commit SHA
|
|
47
|
+
id: resolve-sha
|
|
48
|
+
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
|
49
|
+
|
|
50
|
+
- name: Compute next version
|
|
51
|
+
id: next
|
|
52
|
+
env:
|
|
53
|
+
NEW_TAG: ${{ inputs.new_tag }}
|
|
54
|
+
run: |
|
|
55
|
+
set -euo pipefail
|
|
56
|
+
if [ -n "${NEW_TAG:-}" ]; then
|
|
57
|
+
version="${NEW_TAG#v}"
|
|
58
|
+
if ! echo "$version" | grep -qE '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'; then
|
|
59
|
+
echo "::error::new_tag '${NEW_TAG}' doesn't look like a vX.Y.Z tag" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
else
|
|
63
|
+
version="$(bash scripts/next-version.sh)"
|
|
64
|
+
fi
|
|
65
|
+
echo "version=${version}" >> "$GITHUB_OUTPUT"
|
|
66
|
+
echo "Computed v${version}"
|
|
67
|
+
|
|
68
|
+
approve:
|
|
69
|
+
name: Approve release
|
|
70
|
+
needs: compute-version
|
|
71
|
+
if: inputs.dry_run != true && github.ref == 'refs/heads/main'
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
timeout-minutes: 5
|
|
74
|
+
environment: release
|
|
75
|
+
permissions: {}
|
|
76
|
+
steps:
|
|
77
|
+
- env:
|
|
78
|
+
VERSION: ${{ needs.compute-version.outputs.version }}
|
|
79
|
+
run: echo "Approved v${VERSION} for release"
|
|
80
|
+
|
|
81
|
+
tag-and-release:
|
|
82
|
+
needs: [compute-version, approve]
|
|
83
|
+
if: always() && needs.compute-version.result == 'success' && needs.approve.result == 'success'
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
timeout-minutes: 10
|
|
86
|
+
permissions:
|
|
87
|
+
contents: write
|
|
88
|
+
env:
|
|
89
|
+
VERSION: ${{ needs.compute-version.outputs.version }}
|
|
90
|
+
SHA: ${{ needs.compute-version.outputs.sha }}
|
|
91
|
+
GH_TOKEN: ${{ github.token }}
|
|
92
|
+
steps:
|
|
93
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
94
|
+
with:
|
|
95
|
+
ref: ${{ needs.compute-version.outputs.sha }}
|
|
96
|
+
persist-credentials: true
|
|
97
|
+
|
|
98
|
+
- name: Push release tag
|
|
99
|
+
# Checked against origin (shallow fetch), not the local clone. An annotated tag peels to
|
|
100
|
+
# the commit SHA via a separate `^{}`-suffixed query -- ls-remote only returns that line
|
|
101
|
+
# when asked for it by name, so one unsuffixed query can't tell the two cases apart.
|
|
102
|
+
run: |
|
|
103
|
+
set -euo pipefail
|
|
104
|
+
git config user.name "github-actions[bot]"
|
|
105
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
106
|
+
existing="$(git ls-remote origin "refs/tags/v${VERSION}^{}" | cut -f1)"
|
|
107
|
+
if [ -z "$existing" ]; then
|
|
108
|
+
existing="$(git ls-remote origin "refs/tags/v${VERSION}" | cut -f1)"
|
|
109
|
+
fi
|
|
110
|
+
if [ -n "$existing" ]; then
|
|
111
|
+
if [ "$existing" != "$SHA" ]; then
|
|
112
|
+
echo "::error::v${VERSION} already exists on origin and points at ${existing}, not this commit (${SHA})" >&2
|
|
113
|
+
exit 1
|
|
114
|
+
fi
|
|
115
|
+
echo "v${VERSION} already exists on origin and points at this commit -- reusing it"
|
|
116
|
+
elif [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
|
117
|
+
git tag "v${VERSION}"
|
|
118
|
+
git push origin "v${VERSION}"
|
|
119
|
+
else
|
|
120
|
+
echo "::error::Refusing to create v${VERSION} from ${GITHUB_REF} -- release tags are only created from main" >&2
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# README documents `uses: zirekhq/nvda-addon-testkit@v1`, and GitHub Marketplace
|
|
125
|
+
# consumers pin the same tag -- this step keeps it on the latest release in its major line.
|
|
126
|
+
- name: Move major version tag
|
|
127
|
+
run: |
|
|
128
|
+
set -euo pipefail
|
|
129
|
+
major="v${VERSION%%.*}"
|
|
130
|
+
git tag -fa "$major" -m "$major" "$SHA"
|
|
131
|
+
git push origin "$major" --force
|
|
132
|
+
|
|
133
|
+
- name: Publish GitHub Release
|
|
134
|
+
# Replaces the release-drafter draft this step used to patch to non-draft --
|
|
135
|
+
# --generate-notes computes the same changelog from merged PRs on demand instead.
|
|
136
|
+
run: |
|
|
137
|
+
set -euo pipefail
|
|
138
|
+
if ! gh release view "v${VERSION}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
|
|
139
|
+
gh release create "v${VERSION}" \
|
|
140
|
+
--repo "${GITHUB_REPOSITORY}" \
|
|
141
|
+
--target "${SHA}" \
|
|
142
|
+
--title "v${VERSION}" \
|
|
143
|
+
--generate-notes
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
pypi:
|
|
147
|
+
name: PyPI
|
|
148
|
+
needs: [compute-version, tag-and-release]
|
|
149
|
+
permissions:
|
|
150
|
+
contents: read
|
|
151
|
+
id-token: write
|
|
152
|
+
uses: ./.github/workflows/publish-python.yml # zizmor: ignore[self-repository] low-severity style suggestion (use '$/...'), not a finding -- zizmor.yml doesn't pin a CLI version to confirm '$/' support
|
|
153
|
+
with:
|
|
154
|
+
ref: v${{ needs.compute-version.outputs.version }}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: Project sync
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types: [opened, assigned]
|
|
6
|
+
pull_request:
|
|
7
|
+
types: [opened]
|
|
8
|
+
|
|
9
|
+
permissions: {}
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
sync:
|
|
13
|
+
uses: ZirekHQ/.github/.github/workflows/project-sync.yml@54452127e2c87f8ecfe358fc88e0f1fe411859b3 # main
|
|
14
|
+
secrets:
|
|
15
|
+
PROJECT_SYNC_TOKEN: ${{ secrets.PROJECT_SYNC_TOKEN }}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
name: Publish Python
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
# Manual retry path (e.g. PyPI publish failed after the GitHub release already went out).
|
|
7
|
+
workflow_dispatch: {}
|
|
8
|
+
workflow_call:
|
|
9
|
+
inputs:
|
|
10
|
+
ref:
|
|
11
|
+
description: "Exact commit or tag to build and publish"
|
|
12
|
+
required: true
|
|
13
|
+
type: string
|
|
14
|
+
|
|
15
|
+
permissions: {}
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
# github.event_name mirrors the CALLING workflow's trigger through a workflow_call
|
|
19
|
+
# (prepare-release.yml's dispatch shows up as 'workflow_dispatch' here too) -- workflow_ref
|
|
20
|
+
# stays bound to the top-level caller, so this checks that, not event_name alone.
|
|
21
|
+
gate:
|
|
22
|
+
if: >-
|
|
23
|
+
github.event_name == 'workflow_dispatch' &&
|
|
24
|
+
startsWith(github.workflow_ref, format('{0}/.github/workflows/publish-python.yml@', github.repository))
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
timeout-minutes: 5
|
|
27
|
+
environment: release
|
|
28
|
+
permissions: {}
|
|
29
|
+
steps:
|
|
30
|
+
- run: echo "approved"
|
|
31
|
+
|
|
32
|
+
build:
|
|
33
|
+
needs: gate
|
|
34
|
+
if: always() && (needs.gate.result == 'success' || needs.gate.result == 'skipped')
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
timeout-minutes: 10
|
|
37
|
+
permissions:
|
|
38
|
+
contents: read
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
41
|
+
with:
|
|
42
|
+
ref: ${{ inputs.ref || github.sha }}
|
|
43
|
+
persist-credentials: false
|
|
44
|
+
fetch-depth: 0
|
|
45
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.13"
|
|
48
|
+
- run: "pip install --only-binary :all: build twine"
|
|
49
|
+
# Without this, hatchling's `artifacts = ["src/nvda_testkit/_spy/*.nvda-addon"]`
|
|
50
|
+
# matches nothing -- the bundle is gitignored and only exists once built --
|
|
51
|
+
# so the published wheel silently ships without it and every real (non-fake)
|
|
52
|
+
# provision() fails require_spy_bundle().
|
|
53
|
+
- run: python tools/build_spy.py
|
|
54
|
+
- run: python -m build
|
|
55
|
+
- run: twine check dist/*
|
|
56
|
+
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
|
57
|
+
with:
|
|
58
|
+
name: dist
|
|
59
|
+
path: dist/
|
|
60
|
+
|
|
61
|
+
publish:
|
|
62
|
+
needs: build
|
|
63
|
+
# Without this, publish silently no-ops on the release.yml call path: its default
|
|
64
|
+
# success() check walks the whole ancestor chain, and gate (an ancestor via build)
|
|
65
|
+
# is legitimately skipped there, not succeeded.
|
|
66
|
+
if: always() && needs.build.result == 'success'
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
timeout-minutes: 10
|
|
69
|
+
environment: pypi
|
|
70
|
+
permissions:
|
|
71
|
+
id-token: write
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
|
|
74
|
+
with:
|
|
75
|
+
name: dist
|
|
76
|
+
path: dist/
|
|
77
|
+
# pypa publishes security fixes to this branch without re-tagging v1, so
|
|
78
|
+
# pinning trades that auto-patching for the blanket pinning policy --
|
|
79
|
+
# bump this SHA by hand if pypa/gh-action-pypi-publish ships a fix.
|
|
80
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
81
|
+
with:
|
|
82
|
+
# PyPI doesn't support reusable workflows as a Trusted Publisher (pypi/warehouse#11096):
|
|
83
|
+
# this job runs via workflow_call from prepare-release.yml, so the attestation's Build
|
|
84
|
+
# Config URI is the caller, not this file, and PyPI rejects it. Drop once that's fixed.
|
|
85
|
+
attestations: false
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
name: Sonar fork coverage
|
|
2
|
+
|
|
3
|
+
# The Sonar job in sonar.yml is deliberately skipped for fork PRs because
|
|
4
|
+
# forks are never given SONAR_TOKEN. This workflow builds what a real scan
|
|
5
|
+
# needs -- a full checkout (including git history, for Sonar's blame/new-code
|
|
6
|
+
# detection) plus a coverage report -- using only the read-only, secret-less
|
|
7
|
+
# token that `pull_request` gets for fork PRs, and packages it as a plain tar
|
|
8
|
+
# archive artifact.
|
|
9
|
+
#
|
|
10
|
+
# sonar-fork-scan.yml (triggered by a maintainer commenting `/sonar` on the
|
|
11
|
+
# PR after reviewing the diff) extracts that archive with plain `tar`, never a
|
|
12
|
+
# git operation, so it never runs git fetch/checkout against fork content and
|
|
13
|
+
# never executes anything from the fork -- the archive is only read
|
|
14
|
+
# statically by the Sonar scanner. This workflow must never gain
|
|
15
|
+
# `secrets:` access and must never do anything beyond running the PR's own
|
|
16
|
+
# test suite, exactly as any other fork `pull_request` job already safely
|
|
17
|
+
# does.
|
|
18
|
+
|
|
19
|
+
on:
|
|
20
|
+
pull_request:
|
|
21
|
+
branches: [main]
|
|
22
|
+
|
|
23
|
+
permissions: {}
|
|
24
|
+
|
|
25
|
+
concurrency:
|
|
26
|
+
group: sonar-fork-coverage-${{ github.event.pull_request.number }}
|
|
27
|
+
cancel-in-progress: true
|
|
28
|
+
|
|
29
|
+
jobs:
|
|
30
|
+
# Mirrors sonar.yml's windows_coverage job: windows_only-marked tests only
|
|
31
|
+
# run on Windows, so without this leg they'd land in the fork's report as
|
|
32
|
+
# permanently uncovered.
|
|
33
|
+
windows_coverage:
|
|
34
|
+
name: Windows coverage for fork scan
|
|
35
|
+
runs-on: windows-2025
|
|
36
|
+
timeout-minutes: 20
|
|
37
|
+
permissions:
|
|
38
|
+
contents: read
|
|
39
|
+
if: github.event.pull_request.head.repo.full_name != github.repository
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
42
|
+
with:
|
|
43
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
44
|
+
persist-credentials: false
|
|
45
|
+
|
|
46
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.13"
|
|
49
|
+
|
|
50
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
51
|
+
- run: python tools/build_spy.py
|
|
52
|
+
|
|
53
|
+
- name: Run tests with coverage
|
|
54
|
+
env:
|
|
55
|
+
COVERAGE_FILE: .coverage.windows.tests
|
|
56
|
+
# `coverage run -m pytest`, not `pytest --cov`: this package registers
|
|
57
|
+
# itself as a pytest11 entry-point plugin, so pytest's own plugin
|
|
58
|
+
# loader imports nvda_testkit's modules before pytest-cov's --cov
|
|
59
|
+
# flag would start tracing, permanently miscounting every top-level
|
|
60
|
+
# def/class line in them as uncovered. Mirrors sonar.yml.
|
|
61
|
+
run: coverage run -m pytest -v
|
|
62
|
+
|
|
63
|
+
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
|
64
|
+
with:
|
|
65
|
+
name: sonar-fork-windows-coverage
|
|
66
|
+
path: .coverage.windows.*
|
|
67
|
+
include-hidden-files: true # coverage data files start with a dot
|
|
68
|
+
retention-days: 7
|
|
69
|
+
|
|
70
|
+
coverage:
|
|
71
|
+
name: Build coverage for fork scan
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
timeout-minutes: 20
|
|
74
|
+
needs: ["windows_coverage"]
|
|
75
|
+
permissions:
|
|
76
|
+
contents: read
|
|
77
|
+
# Same-repo PRs are scanned directly by sonar.yml; only forks need this.
|
|
78
|
+
if: github.event.pull_request.head.repo.full_name != github.repository
|
|
79
|
+
steps:
|
|
80
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
81
|
+
with:
|
|
82
|
+
# Pinned to the actual PR head, not actions/checkout's default
|
|
83
|
+
# ephemeral merge commit -- otherwise the scanner analyzes a
|
|
84
|
+
# commit SHA that doesn't match the PR, and SonarCloud can't
|
|
85
|
+
# attach its status to the commit branch protection actually
|
|
86
|
+
# checks.
|
|
87
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
88
|
+
fetch-depth: 0 # Sonar needs full history for new-code detection and blame
|
|
89
|
+
persist-credentials: false
|
|
90
|
+
|
|
91
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
92
|
+
with:
|
|
93
|
+
python-version: "3.13"
|
|
94
|
+
|
|
95
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
96
|
+
- run: python tools/build_spy.py
|
|
97
|
+
|
|
98
|
+
- name: Run tests with coverage
|
|
99
|
+
run: coverage run -m pytest -v
|
|
100
|
+
|
|
101
|
+
# After the run above, never before: `coverage run` erases any
|
|
102
|
+
# .coverage.* data files already sitting in the workspace.
|
|
103
|
+
- name: Download the Windows leg's coverage
|
|
104
|
+
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
|
|
105
|
+
with:
|
|
106
|
+
name: sonar-fork-windows-coverage
|
|
107
|
+
|
|
108
|
+
- name: Merge into one coverage report
|
|
109
|
+
run: |
|
|
110
|
+
python -m coverage combine --append
|
|
111
|
+
python -m coverage xml
|
|
112
|
+
|
|
113
|
+
- name: Archive workspace for the manual scan workflow
|
|
114
|
+
run: tar -czf "$RUNNER_TEMP/workspace.tar.gz" -C "$GITHUB_WORKSPACE" .
|
|
115
|
+
|
|
116
|
+
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
|
117
|
+
with:
|
|
118
|
+
name: sonar-fork-workspace
|
|
119
|
+
path: ${{ runner.temp }}/workspace.tar.gz
|
|
120
|
+
retention-days: 7
|