mdka 2.2.2__tar.gz → 2.3.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.
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/ci.yaml +43 -8
- mdka-2.3.0/.github/workflows/crates-package-gate.yaml +103 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/docs-example-gate.yaml +8 -4
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/docs.yaml +6 -1
- mdka-2.3.0/.github/workflows/pypi-published-gate.yaml +114 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-pypi.yaml +80 -4
- mdka-2.3.0/.github/workflows/scripts/check-docs-examples.py +794 -0
- mdka-2.3.0/.github/workflows/scripts/check-wheel-matrix.py +245 -0
- mdka-2.3.0/CHANGELOG.md +760 -0
- {mdka-2.2.2 → mdka-2.3.0}/Cargo.lock +25 -7
- {mdka-2.2.2 → mdka-2.3.0}/Cargo.toml +7 -2
- mdka-2.2.2/README.md → mdka-2.3.0/PKG-INFO +57 -15
- mdka-2.2.2/PKG-INFO → mdka-2.3.0/README.md +39 -28
- {mdka-2.2.2 → mdka-2.3.0}/ROADMAP.md +174 -20
- {mdka-2.2.2 → mdka-2.3.0}/docs/book.toml +7 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/core.md +20 -14
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/elements.md +73 -14
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/errors.md +5 -2
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/options.md +20 -3
- mdka-2.3.0/docs/src/api/text-processing.md +127 -0
- mdka-2.3.0/docs/src/design/architecture.md +120 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/design/performance-characteristics.md +17 -0
- mdka-2.3.0/docs/src/getting-started/installation.md +104 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-cli.md +6 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-nodejs.md +55 -8
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-python.md +38 -4
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-rust.md +20 -14
- {mdka-2.2.2 → mdka-2.3.0}/pyproject.toml +9 -2
- {mdka-2.2.2 → mdka-2.3.0}/python/Cargo.toml +2 -2
- {mdka-2.2.2 → mdka-2.3.0}/python/README.md +39 -15
- {mdka-2.2.2 → mdka-2.3.0}/python/src/lib.rs +8 -2
- {mdka-2.2.2 → mdka-2.3.0}/python/test_mdka.py +17 -2
- mdka-2.3.0/python/wheel-matrix.toml +27 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/README.md +13 -15
- mdka-2.3.0/rfcs/done/010-escaping-and-text-round-trip.md +182 -0
- {mdka-2.2.2/rfcs/accepted → mdka-2.3.0/rfcs/done}/024-inline-composition-output-sink.md +92 -1
- {mdka-2.2.2/rfcs/accepted → mdka-2.3.0/rfcs/done}/025-output-validity-harness.md +57 -1
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/026-consumer-artifact-gates.md +61 -0
- {mdka-2.2.2/rfcs/accepted → mdka-2.3.0/rfcs/done}/028-emphasis-around-block-content.md +89 -8
- mdka-2.3.0/rfcs/done/029-published-surface-documentation-repair.md +126 -0
- mdka-2.3.0/rfcs/done/030-crates-package-gate-workspace-resolution.md +199 -0
- mdka-2.3.0/rfcs/done/031-docs-gate-must-model-mdbook.md +229 -0
- mdka-2.3.0/rfcs/done/032-gates-report-everything-and-execute-examples.md +127 -0
- mdka-2.3.0/rfcs/done/033-published-docs-source-is-what-the-reader-gets.md +232 -0
- mdka-2.3.0/rfcs/done/034-pypi-declared-wheel-matrix.md +327 -0
- mdka-2.3.0/rfcs/done/035-block-structure-inside-containers.md +131 -0
- mdka-2.3.0/rfcs/handoffs/010-escaping-and-text-round-trip/implementation-handoff.md +152 -0
- mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024b.md +107 -0
- mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024c.md +78 -0
- mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024d.md +72 -0
- mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024e.md +65 -0
- mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/implementation-handoff.md +147 -0
- mdka-2.3.0/rfcs/handoffs/025-output-validity-harness/addendum-025c.md +121 -0
- mdka-2.3.0/rfcs/handoffs/025-output-validity-harness/implementation-handoff.md +285 -0
- mdka-2.3.0/rfcs/handoffs/028-emphasis-around-block-content/addendum-028b.md +82 -0
- mdka-2.3.0/rfcs/handoffs/028-emphasis-around-block-content/implementation-handoff.md +201 -0
- mdka-2.3.0/rfcs/handoffs/029-published-surface-documentation-repair/implementation-handoff.md +195 -0
- mdka-2.3.0/rfcs/handoffs/030-crates-package-gate-workspace-resolution/implementation-handoff.md +159 -0
- mdka-2.3.0/rfcs/handoffs/031-docs-gate-must-model-mdbook/followup-031b.md +156 -0
- mdka-2.3.0/rfcs/handoffs/031-docs-gate-must-model-mdbook/implementation-handoff.md +215 -0
- mdka-2.3.0/rfcs/handoffs/032-gates-report-everything-and-execute-examples/implementation-handoff.md +182 -0
- mdka-2.3.0/rfcs/handoffs/033-published-docs-source-is-what-the-reader-gets/implementation-handoff.md +189 -0
- mdka-2.3.0/rfcs/handoffs/034-pypi-declared-wheel-matrix/followup-034b.md +85 -0
- mdka-2.3.0/rfcs/handoffs/034-pypi-declared-wheel-matrix/implementation-handoff.md +252 -0
- mdka-2.3.0/rfcs/handoffs/035-block-structure-inside-containers/implementation-handoff.md +127 -0
- {mdka-2.2.2 → mdka-2.3.0}/src/lib.rs +5 -4
- {mdka-2.2.2 → mdka-2.3.0}/src/options.rs +10 -7
- mdka-2.3.0/src/renderer/escape/tests.rs +164 -0
- mdka-2.3.0/src/renderer/escape.rs +402 -0
- mdka-2.3.0/src/renderer/sink/tests.rs +133 -0
- mdka-2.3.0/src/renderer/sink.rs +752 -0
- mdka-2.3.0/src/renderer.rs +597 -0
- mdka-2.3.0/src/traversal.rs +283 -0
- mdka-2.3.0/src/utils/tests.rs +147 -0
- mdka-2.3.0/src/utils.rs +175 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/anchor_drift_guard.rs +8 -8
- {mdka-2.2.2 → mdka-2.3.0}/tests/block_elements.rs +53 -1
- {mdka-2.2.2 → mdka-2.3.0}/tests/hr_newline_reset.rs +4 -1
- mdka-2.3.0/tests/inline_around_blocks.rs +292 -0
- mdka-2.3.0/tests/inline_composition.rs +160 -0
- mdka-2.3.0/tests/output_validity/block_in_container.rs +56 -0
- mdka-2.3.0/tests/output_validity/block_in_inline.rs +75 -0
- mdka-2.3.0/tests/output_validity/code_context.rs +77 -0
- mdka-2.3.0/tests/output_validity/corpus/README.md +16 -0
- mdka-2.3.0/tests/output_validity/corpus.rs +96 -0
- mdka-2.3.0/tests/output_validity/corpus_proof/linked_inline.html +3 -0
- mdka-2.3.0/tests/output_validity/corpus_proof/valid.html +2 -0
- mdka-2.3.0/tests/output_validity/corpus_proof/violating.html +1 -0
- mdka-2.3.0/tests/output_validity/escaping.rs +134 -0
- mdka-2.3.0/tests/output_validity/field_reports.rs +32 -0
- mdka-2.3.0/tests/output_validity/gfm.rs +28 -0
- mdka-2.3.0/tests/output_validity/harness/properties.rs +728 -0
- mdka-2.3.0/tests/output_validity/harness/structure.rs +221 -0
- mdka-2.3.0/tests/output_validity/harness.rs +254 -0
- mdka-2.3.0/tests/output_validity/inline_in_container.rs +110 -0
- mdka-2.3.0/tests/output_validity/main.rs +59 -0
- mdka-2.3.0/tests/output_validity/proofs.rs +640 -0
- mdka-2.3.0/tests/output_validity/runner_fixtures/article.html +32 -0
- mdka-2.3.0/tests/output_validity/runner_fixtures/word-style-fragment.html +9 -0
- mdka-2.3.0/tests/output_validity/well_formedness.rs +44 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/preserve_ids_anchors.rs +8 -7
- mdka-2.2.2/.github/workflows/crates-package-gate.yaml +0 -78
- mdka-2.2.2/.github/workflows/scripts/check-docs-examples.py +0 -307
- mdka-2.2.2/CHANGELOG.md +0 -394
- mdka-2.2.2/docs/src/api/text-processing.md +0 -57
- mdka-2.2.2/docs/src/design/architecture.md +0 -78
- mdka-2.2.2/docs/src/getting-started/installation.md +0 -53
- mdka-2.2.2/rfcs/handoffs/024-inline-composition-output-sink/implementation-handoff.md +0 -152
- mdka-2.2.2/rfcs/handoffs/025-output-validity-harness/implementation-handoff.md +0 -147
- mdka-2.2.2/rfcs/handoffs/028-emphasis-around-block-content/implementation-handoff.md +0 -217
- mdka-2.2.2/src/renderer.rs +0 -455
- mdka-2.2.2/src/traversal.rs +0 -100
- mdka-2.2.2/src/utils/tests.rs +0 -93
- mdka-2.2.2/src/utils.rs +0 -147
- {mdka-2.2.2 → mdka-2.3.0}/.gitattributes +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/CODE_OF_CONDUCT.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/CONTRIBUTING.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/SECURITY.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/create-release.yaml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/npm-install-gate.yaml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/pypi-wheel-gate.yaml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-crates.yaml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-executable.yaml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-npm.yaml +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/scripts/install-rust.sh +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.gitignore +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.vscode/extensions.json +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/.vscode/settings.json +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/LICENSE +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/NOTICE +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/bench_common.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/deep_nest.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/flat.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/large.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/malformed.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/medium.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/scale_500k.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/scale_50k.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/scale_5m.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/small.html +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/convert.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/memory.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/parallel.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/benches/scaling.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/cargo-publish.sh +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/SUMMARY.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/index.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/modes.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/assets/logo.png +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/design/features.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/design/philosophy.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/docs/src/introduction.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/examples/measure_mem.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/examples/quick_bench.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/examples/quick_compare.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/examples/quick_mem.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/mdka/__init__.py +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/python/example.py +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/000-rfc-lifecycle-policy.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/001-ci-quality-gates.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/002-governance-artifacts.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/003-architecture-doc-reconciliation.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/004-preprocessor-disposition.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/005-conversion-options-semantics.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/006-option-docs-and-binding-parity.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/007-english-only-public-surface.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/014-release-time-ci-verification.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/015-release-tooling-completion.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/016-hr-newline-reset.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/017-pre-fence-newline-reset.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/018-readme-prebuilt-binaries.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/019-release-creation-via-dispatch.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/020-npm-distribution-repair.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/021-bulk-output-collision-safety.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/022-cli-allocator-and-jemalloc.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/023-getting-started-doc-reconciliation.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/027-verification-discipline.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/001-ci-quality-gates/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/002-governance-artifacts/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/003-architecture-doc-reconciliation/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/004-preprocessor-disposition/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/005-conversion-options-semantics/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/005-conversion-options-semantics/slice-b1-placement-correction-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/005-conversion-options-semantics/slices-bc-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/006-option-docs-and-binding-parity/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/007-english-only-public-surface/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/014-release-time-ci-verification/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/015-release-tooling-completion/amendment-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/015-release-tooling-completion/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/015-release-tooling-completion/restore-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/016-hr-newline-reset/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/017-pre-fence-newline-reset/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/018-readme-prebuilt-binaries/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/019-release-creation-via-dispatch/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/020-npm-distribution-repair/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/021-bulk-output-collision-safety/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/022-cli-allocator-and-jemalloc/alloc-counter-deprecation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/022-cli-allocator-and-jemalloc/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/023-getting-started-doc-reconciliation/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/026-consumer-artifact-gates/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/027-verification-discipline/implementation-handoff.md +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/src/alloc_counter.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/src/traversal/tests.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/characterisation_attributes.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/characterisation_elements.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/characterisation_structural.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/common.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/compat.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/file_conversion.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/inline_elements.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/pre_fence_newline_reset.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/tests/robustness.rs +0 -0
- {mdka-2.2.2 → mdka-2.3.0}/version.sh +0 -0
|
@@ -46,14 +46,20 @@ jobs:
|
|
|
46
46
|
- name: cargo fmt --check
|
|
47
47
|
run: cargo fmt --check
|
|
48
48
|
|
|
49
|
+
# --keep-going (RFC 032): report every crate's lint failures, not just the
|
|
50
|
+
# first crate's. clippy --help does not list it, but clippy passes it to
|
|
51
|
+
# cargo check and it was seen to change the output. Keep it before `--`.
|
|
49
52
|
- name: cargo clippy
|
|
50
|
-
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
53
|
+
run: cargo clippy --workspace --all-targets --all-features --keep-going -- -D warnings
|
|
51
54
|
|
|
55
|
+
# --no-fail-fast (RFC 032): without it the first failing test binary stops
|
|
56
|
+
# the rest, so a failure in one binary hides failures in all later ones.
|
|
52
57
|
- name: cargo test
|
|
53
|
-
run: cargo test --workspace --all-features --locked
|
|
58
|
+
run: cargo test --workspace --all-features --locked --no-fail-fast
|
|
54
59
|
|
|
60
|
+
# --keep-going (RFC 032): report every target that fails to compile.
|
|
55
61
|
- name: cargo build
|
|
56
|
-
run: cargo build --workspace --locked
|
|
62
|
+
run: cargo build --workspace --locked --keep-going
|
|
57
63
|
|
|
58
64
|
msrv:
|
|
59
65
|
runs-on: ubuntu-latest
|
|
@@ -87,8 +93,10 @@ jobs:
|
|
|
87
93
|
# --all-targets is deliberately omitted: bench dev-dependencies require a
|
|
88
94
|
# newer toolchain and are advisory only, not part of the published MSRV.
|
|
89
95
|
# --locked verifies the same dependency set the `rust` job saw.
|
|
96
|
+
# --keep-going (RFC 032): report every crate that fails to check on the
|
|
97
|
+
# MSRV toolchain, not just the first. Verified on 1.88.
|
|
90
98
|
- name: cargo check
|
|
91
|
-
run: cargo check --workspace --locked
|
|
99
|
+
run: cargo check --workspace --locked --keep-going
|
|
92
100
|
|
|
93
101
|
node:
|
|
94
102
|
runs-on: ubuntu-latest
|
|
@@ -136,6 +144,14 @@ jobs:
|
|
|
136
144
|
python:
|
|
137
145
|
runs-on: ubuntu-latest
|
|
138
146
|
timeout-minutes: 20
|
|
147
|
+
strategy:
|
|
148
|
+
fail-fast: false
|
|
149
|
+
matrix:
|
|
150
|
+
# RFC 034: the declared floor (python/wheel-matrix.toml python-floor)
|
|
151
|
+
# and the newest stable CPython. The floor entry is asserted equal to
|
|
152
|
+
# python-floor below. When CI can no longer install the floor, this
|
|
153
|
+
# job goes red -- that is trigger 1 for raising it.
|
|
154
|
+
python: ["3.10", "3.x"]
|
|
139
155
|
|
|
140
156
|
steps:
|
|
141
157
|
- name: Checkout repository
|
|
@@ -144,7 +160,7 @@ jobs:
|
|
|
144
160
|
- name: Setup Python
|
|
145
161
|
uses: actions/setup-python@v6
|
|
146
162
|
with:
|
|
147
|
-
python-version:
|
|
163
|
+
python-version: ${{ matrix.python }}
|
|
148
164
|
|
|
149
165
|
- name: Cache cargo dependencies and build
|
|
150
166
|
uses: actions/cache@v5
|
|
@@ -153,9 +169,9 @@ jobs:
|
|
|
153
169
|
~/.cargo/registry
|
|
154
170
|
~/.cargo/git
|
|
155
171
|
target
|
|
156
|
-
key: ${{ runner.os }}-cargo-python-${{ hashFiles('**/Cargo.lock') }}
|
|
172
|
+
key: ${{ runner.os }}-cargo-python-${{ matrix.python }}-${{ hashFiles('**/Cargo.lock') }}
|
|
157
173
|
restore-keys: |
|
|
158
|
-
${{ runner.os }}-cargo-python-
|
|
174
|
+
${{ runner.os }}-cargo-python-${{ matrix.python }}-
|
|
159
175
|
|
|
160
176
|
# python/pyproject.toml declares readme = "README.md" but the README lives
|
|
161
177
|
# at the repository root. Required — omitting this fails the build (see
|
|
@@ -166,9 +182,27 @@ jobs:
|
|
|
166
182
|
- name: Install uv
|
|
167
183
|
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
168
184
|
|
|
185
|
+
# The script needs Python >= 3.11 (tomllib), so uv supplies one
|
|
186
|
+
# separately from the interpreter under test.
|
|
187
|
+
- name: Declared floor matches this matrix and the manifests
|
|
188
|
+
run: |
|
|
189
|
+
set -euo pipefail
|
|
190
|
+
check() {
|
|
191
|
+
uv run --no-project --python 3.13 --with packaging -- \
|
|
192
|
+
python .github/workflows/scripts/check-wheel-matrix.py "$@"
|
|
193
|
+
}
|
|
194
|
+
if [ "${{ matrix.python }}" != "3.x" ]; then
|
|
195
|
+
check floor-equals "ci.yaml python matrix" "${{ matrix.python }}"
|
|
196
|
+
fi
|
|
197
|
+
check floor-manifests
|
|
198
|
+
|
|
199
|
+
# `uv venv` alone may pick a different interpreter than the matrix one;
|
|
200
|
+
# name it explicitly and print what the venv actually runs.
|
|
169
201
|
- name: Install maturin and pytest
|
|
170
202
|
run: |
|
|
171
|
-
uv venv
|
|
203
|
+
uv venv --python "$(python -c 'import sys; print(sys.executable)')"
|
|
204
|
+
source .venv/bin/activate
|
|
205
|
+
python --version
|
|
172
206
|
uv pip install maturin pytest
|
|
173
207
|
|
|
174
208
|
- name: maturin develop
|
|
@@ -181,4 +215,5 @@ jobs:
|
|
|
181
215
|
working-directory: python
|
|
182
216
|
run: |
|
|
183
217
|
source ../.venv/bin/activate
|
|
218
|
+
python --version
|
|
184
219
|
python -m pytest test_mdka.py
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
name: crates package gate
|
|
2
|
+
|
|
3
|
+
# RFC 026 §4.2. The `rust` job in ci.yaml runs `cargo test` in-workspace,
|
|
4
|
+
# where every path dependency resolves and every file is present. It cannot
|
|
5
|
+
# see a crate that compiles here and fails standalone -- through a missing
|
|
6
|
+
# `include`, a path dependency with no version, or a file absent from the
|
|
7
|
+
# packaged .crate.
|
|
8
|
+
#
|
|
9
|
+
# `cargo package` (without --no-verify) packages each crate and then builds
|
|
10
|
+
# from the extracted package, where path dependencies are stripped. That is
|
|
11
|
+
# the consumer's build.
|
|
12
|
+
#
|
|
13
|
+
# RFC 030: this is ONE `--workspace` invocation, not four per-crate steps,
|
|
14
|
+
# and that is deliberate. Packaging the dependents separately makes each
|
|
15
|
+
# resolve `mdka` from crates.io -- but on main the workspace version is the
|
|
16
|
+
# NEXT version, which is not published yet, so mdka-cli failed with
|
|
17
|
+
# "failed to select a version for the requirement mdka = ^X.Y.Z" at every
|
|
18
|
+
# release commit. Worse, that failure skipped mdka-node and mdka-python
|
|
19
|
+
# entirely, so the red masked the gate's own coverage: across 2.2.2 and
|
|
20
|
+
# 2.2.3 nothing verified that those two package and build standalone.
|
|
21
|
+
#
|
|
22
|
+
# `--workspace` builds a temporary local registry from the packaged members
|
|
23
|
+
# (target/package/tmp-registry/) and resolves the dependents against it, so
|
|
24
|
+
# it works whether or not the version is published. Do not "simplify" this
|
|
25
|
+
# back into four steps.
|
|
26
|
+
#
|
|
27
|
+
# Its own workflow file, not ci.yaml -- see RFC 026 §3.5 and RFC 020's
|
|
28
|
+
# correction record.
|
|
29
|
+
|
|
30
|
+
on:
|
|
31
|
+
push:
|
|
32
|
+
branches: [main]
|
|
33
|
+
pull_request:
|
|
34
|
+
branches: [main]
|
|
35
|
+
workflow_dispatch:
|
|
36
|
+
|
|
37
|
+
permissions:
|
|
38
|
+
contents: read
|
|
39
|
+
|
|
40
|
+
concurrency:
|
|
41
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
42
|
+
cancel-in-progress: true
|
|
43
|
+
|
|
44
|
+
defaults:
|
|
45
|
+
run:
|
|
46
|
+
shell: bash
|
|
47
|
+
|
|
48
|
+
jobs:
|
|
49
|
+
crates-package-gate:
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
timeout-minutes: 30
|
|
52
|
+
|
|
53
|
+
steps:
|
|
54
|
+
- name: Checkout repository
|
|
55
|
+
uses: actions/checkout@v6
|
|
56
|
+
|
|
57
|
+
- name: Cache cargo dependencies and build
|
|
58
|
+
uses: actions/cache@v5
|
|
59
|
+
with:
|
|
60
|
+
path: |
|
|
61
|
+
~/.cargo/registry
|
|
62
|
+
~/.cargo/git
|
|
63
|
+
target
|
|
64
|
+
key: ${{ runner.os }}-cargo-package-gate-${{ hashFiles('**/Cargo.lock') }}
|
|
65
|
+
restore-keys: |
|
|
66
|
+
${{ runner.os }}-cargo-package-gate-
|
|
67
|
+
|
|
68
|
+
# No --no-verify anywhere. Packaging without building the result would
|
|
69
|
+
# check that the tarball can be produced, not that it works -- which is
|
|
70
|
+
# the distinction this whole milestone is about.
|
|
71
|
+
#
|
|
72
|
+
# No --keep-going either, deliberately (RFC 032). cargo package --help
|
|
73
|
+
# lists it, but it changed nothing when tested: package verifies members
|
|
74
|
+
# one after another, and the flag only continues within a single build.
|
|
75
|
+
# A second broken crate is still reported only after the first is fixed.
|
|
76
|
+
- name: cargo package --workspace
|
|
77
|
+
run: cargo package --workspace --locked
|
|
78
|
+
|
|
79
|
+
# Scoped to the workspace's current version, and asserts there are four
|
|
80
|
+
# of them. target/ is restored from the cache, so an unfiltered glob
|
|
81
|
+
# lists every version packaged since the cache was last cold -- twelve
|
|
82
|
+
# .crate files across three versions, at the time of writing -- which
|
|
83
|
+
# reads as though this run produced them all. The count check also turns
|
|
84
|
+
# the listing from decoration into an assertion that every member was
|
|
85
|
+
# packaged.
|
|
86
|
+
- name: Show what each package actually contains
|
|
87
|
+
run: |
|
|
88
|
+
set -euo pipefail
|
|
89
|
+
version=$(cargo metadata --format-version 1 --no-deps \
|
|
90
|
+
| python3 -c 'import json,sys; print(next(p["version"] for p in json.load(sys.stdin)["packages"] if p["name"] == "mdka"))')
|
|
91
|
+
echo "workspace version: $version"
|
|
92
|
+
|
|
93
|
+
mapfile -t crates < <(ls target/package/*-"$version".crate)
|
|
94
|
+
if [ "${#crates[@]}" -ne 4 ]; then
|
|
95
|
+
echo "::error::expected 4 .crate files at $version, found ${#crates[@]}"
|
|
96
|
+
printf ' %s\n' "${crates[@]}"
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
for crate in "${crates[@]}"; do
|
|
101
|
+
echo "=== $crate"
|
|
102
|
+
tar -tzf "$crate" | sed 's/^/ /'
|
|
103
|
+
done
|
|
@@ -60,9 +60,13 @@ jobs:
|
|
|
60
60
|
restore-keys: |
|
|
61
61
|
${{ runner.os }}-cargo-docs-gate-
|
|
62
62
|
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
|
|
63
|
+
# Builds the native binding as well as the declarations, and BOTH are
|
|
64
|
+
# used: TypeScript examples type-check against index.d.ts, and JavaScript
|
|
65
|
+
# examples are EXECUTED against the built binding (RFC 031) -- a syntax
|
|
66
|
+
# check alone passed an example that failed at load. Without this step
|
|
67
|
+
# every JS example is reported as a failure ("no built binding"), so the
|
|
68
|
+
# gate goes red rather than quietly skipping execution.
|
|
69
|
+
- name: Build the Node binding and its TypeScript declarations
|
|
66
70
|
working-directory: node
|
|
67
71
|
run: |
|
|
68
72
|
npm ci
|
|
@@ -88,7 +92,7 @@ jobs:
|
|
|
88
92
|
python -m venv "$RUNNER_TEMP/docs-venv"
|
|
89
93
|
"$RUNNER_TEMP/docs-venv/bin/pip" install --no-index "$RUNNER_TEMP"/wheels/mdka-*.whl
|
|
90
94
|
|
|
91
|
-
- name: Check every runnable example in docs/src/
|
|
95
|
+
- name: Check every runnable example in docs/src/ and README.md
|
|
92
96
|
run: |
|
|
93
97
|
python .github/workflows/scripts/check-docs-examples.py \
|
|
94
98
|
--python "$RUNNER_TEMP/docs-venv/bin/python"
|
|
@@ -31,8 +31,13 @@ jobs:
|
|
|
31
31
|
id: pages
|
|
32
32
|
uses: actions/configure-pages@v6
|
|
33
33
|
|
|
34
|
+
# Pinned exactly (RFC 033). The docs example gate models this mdBook: its
|
|
35
|
+
# wrapping of Rust examples, its hidden-line rule, and its copy button,
|
|
36
|
+
# which omits hidden lines. Before moving the pin, re-check all three in
|
|
37
|
+
# .github/workflows/scripts/check-docs-examples.py. 0.5.4 is what `^0.5`
|
|
38
|
+
# resolved to when pinned.
|
|
34
39
|
- name: Install mdBook
|
|
35
|
-
run: cargo install mdbook --no-default-features --features search --vers "
|
|
40
|
+
run: cargo install mdbook --no-default-features --features search --vers "=0.5.4" --locked
|
|
36
41
|
|
|
37
42
|
- name: Build book
|
|
38
43
|
run: mdbook build
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: pypi published gate
|
|
2
|
+
|
|
3
|
+
# RFC 034 §4.4. Checks what PyPI actually serves for the latest release, the
|
|
4
|
+
# way the npm install gate checks npm:
|
|
5
|
+
#
|
|
6
|
+
# 1. the published file set equals python/wheel-matrix.toml -- the same
|
|
7
|
+
# script release-pypi.yaml runs before upload, so the two cannot disagree;
|
|
8
|
+
# 2. the release installs FROM PyPI, wheel only, at the declared floor and
|
|
9
|
+
# at the newest stable CPython, and converts;
|
|
10
|
+
# 3. installation.md states the declared floor.
|
|
11
|
+
#
|
|
12
|
+
# Its own workflow file, not ci.yaml: the release workflows gate on ci.yaml's
|
|
13
|
+
# conclusion, so a gate there can block the release that would make it pass
|
|
14
|
+
# (RFC 020's correction record).
|
|
15
|
+
#
|
|
16
|
+
# `pypi wheel gate` is a different check: it installs a wheel BUILT FROM THE
|
|
17
|
+
# TREE. This one reports on the LAST PUBLISHED release, so it lags the tree --
|
|
18
|
+
# a published artifact cannot be verified before it is published.
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
push:
|
|
22
|
+
branches: [main]
|
|
23
|
+
pull_request:
|
|
24
|
+
branches: [main]
|
|
25
|
+
workflow_dispatch:
|
|
26
|
+
schedule:
|
|
27
|
+
# Catch a registry-side change even when nobody pushes.
|
|
28
|
+
- cron: '0 6 * * 1'
|
|
29
|
+
|
|
30
|
+
permissions:
|
|
31
|
+
contents: read
|
|
32
|
+
|
|
33
|
+
defaults:
|
|
34
|
+
run:
|
|
35
|
+
shell: bash
|
|
36
|
+
|
|
37
|
+
jobs:
|
|
38
|
+
file-set:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
timeout-minutes: 10
|
|
41
|
+
outputs:
|
|
42
|
+
version: ${{ steps.pypi.outputs.version }}
|
|
43
|
+
floor: ${{ steps.floor.outputs.floor }}
|
|
44
|
+
|
|
45
|
+
steps:
|
|
46
|
+
- name: Checkout repository
|
|
47
|
+
uses: actions/checkout@v6
|
|
48
|
+
|
|
49
|
+
- name: Setup Python
|
|
50
|
+
uses: actions/setup-python@v6
|
|
51
|
+
with:
|
|
52
|
+
python-version: 3.x
|
|
53
|
+
|
|
54
|
+
- name: Install packaging
|
|
55
|
+
run: python -m pip install packaging
|
|
56
|
+
|
|
57
|
+
- name: Read the latest release from PyPI
|
|
58
|
+
id: pypi
|
|
59
|
+
run: |
|
|
60
|
+
set -euo pipefail
|
|
61
|
+
curl -fsSL https://pypi.org/pypi/mdka/json -o "$RUNNER_TEMP/pypi.json"
|
|
62
|
+
version=$(python -c "import json,sys; print(json.load(open(sys.argv[1]))['info']['version'])" "$RUNNER_TEMP/pypi.json")
|
|
63
|
+
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
64
|
+
|
|
65
|
+
- name: Read the declared floor
|
|
66
|
+
id: floor
|
|
67
|
+
run: echo "floor=$(python .github/workflows/scripts/check-wheel-matrix.py floor)" >> "$GITHUB_OUTPUT"
|
|
68
|
+
|
|
69
|
+
# Before applies-from this prints a ::notice:: and passes: the policy
|
|
70
|
+
# never governed that release. It is not silent, and it ends by itself
|
|
71
|
+
# when the first release under the policy publishes.
|
|
72
|
+
- name: Published file set equals the declared matrix
|
|
73
|
+
run: python .github/workflows/scripts/check-wheel-matrix.py published "$RUNNER_TEMP/pypi.json"
|
|
74
|
+
|
|
75
|
+
- name: installation.md states the declared floor
|
|
76
|
+
run: python .github/workflows/scripts/check-wheel-matrix.py floor-doc docs/src/getting-started/installation.md
|
|
77
|
+
|
|
78
|
+
install:
|
|
79
|
+
needs: [file-set]
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
timeout-minutes: 10
|
|
82
|
+
strategy:
|
|
83
|
+
fail-fast: false
|
|
84
|
+
matrix:
|
|
85
|
+
# The declared floor comes from wheel-matrix.toml via file-set; "3.x"
|
|
86
|
+
# is the newest stable CPython.
|
|
87
|
+
python: [floor, "3.x"]
|
|
88
|
+
|
|
89
|
+
steps:
|
|
90
|
+
- name: Setup Python
|
|
91
|
+
uses: actions/setup-python@v6
|
|
92
|
+
with:
|
|
93
|
+
python-version: ${{ matrix.python == 'floor' && needs.file-set.outputs.floor || matrix.python }}
|
|
94
|
+
|
|
95
|
+
# --only-binary :all: is the point of this step. The runner has a Rust
|
|
96
|
+
# toolchain: without the flag a missing wheel falls back to building
|
|
97
|
+
# the sdist, the install succeeds, and the gate passes on exactly the
|
|
98
|
+
# defect it exists to catch.
|
|
99
|
+
- name: Install the published wheel from PyPI and convert
|
|
100
|
+
env:
|
|
101
|
+
VERSION: ${{ needs.file-set.outputs.version }}
|
|
102
|
+
run: |
|
|
103
|
+
set -euo pipefail
|
|
104
|
+
python -m venv "$RUNNER_TEMP/venv"
|
|
105
|
+
source "$RUNNER_TEMP/venv/bin/activate"
|
|
106
|
+
python --version
|
|
107
|
+
cd "$RUNNER_TEMP"
|
|
108
|
+
python -m pip install --only-binary :all: --no-cache-dir "mdka==${VERSION}"
|
|
109
|
+
python -c "
|
|
110
|
+
import mdka
|
|
111
|
+
out = mdka.html_to_markdown('<h1>x</h1>')
|
|
112
|
+
assert '# x' in out, repr(out)
|
|
113
|
+
print('OK: mdka', mdka.version(), 'installs from a wheel and converts:', repr(out))
|
|
114
|
+
"
|
|
@@ -78,10 +78,24 @@ jobs:
|
|
|
78
78
|
with:
|
|
79
79
|
working-directory: python
|
|
80
80
|
target: ${{ matrix.platform.target }}
|
|
81
|
-
|
|
81
|
+
# RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
|
|
82
|
+
# cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
|
|
83
|
+
# exactly one wheel instead of one per interpreter the runner happens
|
|
84
|
+
# to carry. The declared set is python/wheel-matrix.toml.
|
|
85
|
+
args: --release --out dist
|
|
82
86
|
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
83
87
|
manylinux: auto
|
|
84
88
|
|
|
89
|
+
- name: Require exactly one wheel
|
|
90
|
+
run: |
|
|
91
|
+
set -euo pipefail
|
|
92
|
+
ls -la python/dist
|
|
93
|
+
count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
|
|
94
|
+
if [ "$count" -ne 1 ]; then
|
|
95
|
+
echo "::error::expected exactly 1 wheel in python/dist, found $count"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
|
|
85
99
|
- name: Upload wheels
|
|
86
100
|
uses: actions/upload-artifact@v7
|
|
87
101
|
with:
|
|
@@ -126,10 +140,24 @@ jobs:
|
|
|
126
140
|
with:
|
|
127
141
|
working-directory: python
|
|
128
142
|
target: ${{ matrix.platform.target }}
|
|
129
|
-
|
|
143
|
+
# RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
|
|
144
|
+
# cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
|
|
145
|
+
# exactly one wheel instead of one per interpreter the runner happens
|
|
146
|
+
# to carry. The declared set is python/wheel-matrix.toml.
|
|
147
|
+
args: --release --out dist
|
|
130
148
|
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
131
149
|
manylinux: musllinux_1_2
|
|
132
150
|
|
|
151
|
+
- name: Require exactly one wheel
|
|
152
|
+
run: |
|
|
153
|
+
set -euo pipefail
|
|
154
|
+
ls -la python/dist
|
|
155
|
+
count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
|
|
156
|
+
if [ "$count" -ne 1 ]; then
|
|
157
|
+
echo "::error::expected exactly 1 wheel in python/dist, found $count"
|
|
158
|
+
exit 1
|
|
159
|
+
fi
|
|
160
|
+
|
|
133
161
|
- name: Upload wheels
|
|
134
162
|
uses: actions/upload-artifact@v7
|
|
135
163
|
with:
|
|
@@ -173,9 +201,23 @@ jobs:
|
|
|
173
201
|
with:
|
|
174
202
|
working-directory: python
|
|
175
203
|
target: ${{ matrix.platform.target }}
|
|
176
|
-
|
|
204
|
+
# RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
|
|
205
|
+
# cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
|
|
206
|
+
# exactly one wheel instead of one per interpreter the runner happens
|
|
207
|
+
# to carry. The declared set is python/wheel-matrix.toml.
|
|
208
|
+
args: --release --out dist
|
|
177
209
|
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
178
210
|
|
|
211
|
+
- name: Require exactly one wheel
|
|
212
|
+
run: |
|
|
213
|
+
set -euo pipefail
|
|
214
|
+
ls -la python/dist
|
|
215
|
+
count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
|
|
216
|
+
if [ "$count" -ne 1 ]; then
|
|
217
|
+
echo "::error::expected exactly 1 wheel in python/dist, found $count"
|
|
218
|
+
exit 1
|
|
219
|
+
fi
|
|
220
|
+
|
|
179
221
|
- name: Upload wheels
|
|
180
222
|
uses: actions/upload-artifact@v7
|
|
181
223
|
with:
|
|
@@ -218,9 +260,23 @@ jobs:
|
|
|
218
260
|
with:
|
|
219
261
|
working-directory: python
|
|
220
262
|
target: ${{ matrix.platform.target }}
|
|
221
|
-
|
|
263
|
+
# RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
|
|
264
|
+
# cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
|
|
265
|
+
# exactly one wheel instead of one per interpreter the runner happens
|
|
266
|
+
# to carry. The declared set is python/wheel-matrix.toml.
|
|
267
|
+
args: --release --out dist
|
|
222
268
|
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
223
269
|
|
|
270
|
+
- name: Require exactly one wheel
|
|
271
|
+
run: |
|
|
272
|
+
set -euo pipefail
|
|
273
|
+
ls -la python/dist
|
|
274
|
+
count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
|
|
275
|
+
if [ "$count" -ne 1 ]; then
|
|
276
|
+
echo "::error::expected exactly 1 wheel in python/dist, found $count"
|
|
277
|
+
exit 1
|
|
278
|
+
fi
|
|
279
|
+
|
|
224
280
|
- name: Upload wheels
|
|
225
281
|
uses: actions/upload-artifact@v7
|
|
226
282
|
with:
|
|
@@ -263,6 +319,10 @@ jobs:
|
|
|
263
319
|
contents: read
|
|
264
320
|
|
|
265
321
|
steps:
|
|
322
|
+
# For python/wheel-matrix.toml, pyproject.toml and the check script.
|
|
323
|
+
# Checked out before the download, so it cannot clean the artifacts away.
|
|
324
|
+
- uses: actions/checkout@v6
|
|
325
|
+
|
|
266
326
|
- name: Install uv
|
|
267
327
|
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
268
328
|
|
|
@@ -279,6 +339,22 @@ jobs:
|
|
|
279
339
|
find artifacts -type f \( -name '*.whl' -o -name '*.tar.gz' \) -exec cp -f {} dist/ \;
|
|
280
340
|
ls -la dist
|
|
281
341
|
|
|
342
|
+
# RFC 034 §4.3. The last point where a wrong file set can be prevented:
|
|
343
|
+
# a PyPI filename can never be re-uploaded. Runs on tags AND on
|
|
344
|
+
# workflow_dispatch, so a dry run exercises it. `cp -f` above would let a
|
|
345
|
+
# same-named file from one job overwrite another's; with one wheel per
|
|
346
|
+
# job that cannot happen, and if it ever does it shows up here as a
|
|
347
|
+
# missing file. The published gate runs the same script after upload.
|
|
348
|
+
- name: Check distributables against the declared wheel matrix
|
|
349
|
+
env:
|
|
350
|
+
TAG: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || '' }}
|
|
351
|
+
run: |
|
|
352
|
+
set -euo pipefail
|
|
353
|
+
tag_args=()
|
|
354
|
+
if [ -n "$TAG" ]; then tag_args=(--tag "$TAG"); fi
|
|
355
|
+
uv run --no-project --python 3.13 --with packaging -- \
|
|
356
|
+
python .github/workflows/scripts/check-wheel-matrix.py files --dir dist "${tag_args[@]}"
|
|
357
|
+
|
|
282
358
|
- name: Publish to PyPI
|
|
283
359
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
|
284
360
|
run: uv publish dist/*
|