sourcelock 0.1.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.
- sourcelock-0.1.0/.github/workflows/ci.yml +104 -0
- sourcelock-0.1.0/.github/workflows/release.yml +210 -0
- sourcelock-0.1.0/.gitignore +20 -0
- sourcelock-0.1.0/ADAPTER_GUIDE.md +449 -0
- sourcelock-0.1.0/LICENSE +21 -0
- sourcelock-0.1.0/MORNING-REPORT.md +168 -0
- sourcelock-0.1.0/PKG-INFO +272 -0
- sourcelock-0.1.0/README.md +232 -0
- sourcelock-0.1.0/RELEASING.md +130 -0
- sourcelock-0.1.0/action/action.yml +133 -0
- sourcelock-0.1.0/action/dry-run.sh +48 -0
- sourcelock-0.1.0/action/run_doctor.py +414 -0
- sourcelock-0.1.0/docs/ci.md +161 -0
- sourcelock-0.1.0/examples/sourcelock-example-adapter/README.md +74 -0
- sourcelock-0.1.0/examples/sourcelock-example-adapter/pyproject.toml +21 -0
- sourcelock-0.1.0/examples/sourcelock-example-adapter/sourcelock_example_adapter.py +203 -0
- sourcelock-0.1.0/hc_source/__init__.py +5 -0
- sourcelock-0.1.0/hc_source/adapters/__init__.py +500 -0
- sourcelock-0.1.0/hc_source/adapters/_demo.py +258 -0
- sourcelock-0.1.0/hc_source/adapters/_demo_fixture.json +25 -0
- sourcelock-0.1.0/hc_source/adapters/_leie_sample.csv +15 -0
- sourcelock-0.1.0/hc_source/adapters/codes.py +1232 -0
- sourcelock-0.1.0/hc_source/adapters/coverage.py +1569 -0
- sourcelock-0.1.0/hc_source/adapters/hcc.py +1450 -0
- sourcelock-0.1.0/hc_source/adapters/leie.py +1310 -0
- sourcelock-0.1.0/hc_source/adapters/provider.py +1159 -0
- sourcelock-0.1.0/hc_source/cache.py +664 -0
- sourcelock-0.1.0/hc_source/cli.py +959 -0
- sourcelock-0.1.0/hc_source/cli_manifest.py +207 -0
- sourcelock-0.1.0/hc_source/data/codes/hcpcs_2026q3.csv.gz +0 -0
- sourcelock-0.1.0/hc_source/data/codes/icd10cm_fy2026.csv.gz +0 -0
- sourcelock-0.1.0/hc_source/data/codes/icd10cm_fy2027.csv.gz +0 -0
- sourcelock-0.1.0/hc_source/data/codes/manifest.json +75 -0
- sourcelock-0.1.0/hc_source/data/codes/regenerate.py +291 -0
- sourcelock-0.1.0/hc_source/data/hcc/hcc_data.json.zlib +0 -0
- sourcelock-0.1.0/hc_source/doctor.py +472 -0
- sourcelock-0.1.0/hc_source/guard.py +877 -0
- sourcelock-0.1.0/hc_source/http.py +541 -0
- sourcelock-0.1.0/hc_source/interfaces.py +395 -0
- sourcelock-0.1.0/hc_source/lockfile.py +236 -0
- sourcelock-0.1.0/hc_source/manifest.py +422 -0
- sourcelock-0.1.0/hc_source/mcp_server.py +203 -0
- sourcelock-0.1.0/hc_source/npi.py +50 -0
- sourcelock-0.1.0/hc_source/receipts.py +74 -0
- sourcelock-0.1.0/hc_source/schemas.py +339 -0
- sourcelock-0.1.0/pyproject.toml +53 -0
- sourcelock-0.1.0/qa/FIX-WAVE-2-BRIEF.md +54 -0
- sourcelock-0.1.0/qa/breaker-round1.md +456 -0
- sourcelock-0.1.0/scripts/check_wheel.py +380 -0
- sourcelock-0.1.0/scripts/wheel_check.sh +35 -0
- sourcelock-0.1.0/source-lock.json +152 -0
- sourcelock-0.1.0/tests/adapters/README.md +3 -0
- sourcelock-0.1.0/tests/adapters/test_codes.py +560 -0
- sourcelock-0.1.0/tests/adapters/test_coverage.py +923 -0
- sourcelock-0.1.0/tests/adapters/test_hcc.py +1131 -0
- sourcelock-0.1.0/tests/adapters/test_leie.py +953 -0
- sourcelock-0.1.0/tests/adapters/test_provider.py +736 -0
- sourcelock-0.1.0/tests/conftest.py +102 -0
- sourcelock-0.1.0/tests/fixtures/README.md +4 -0
- sourcelock-0.1.0/tests/fixtures/codes/cdc_root_listing.html +3 -0
- sourcelock-0.1.0/tests/fixtures/codes/cms_landing_trimmed.html +100 -0
- sourcelock-0.1.0/tests/fixtures/coverage/README.md +34 -0
- sourcelock-0.1.0/tests/fixtures/coverage/articles_report_trimmed.json +55 -0
- sourcelock-0.1.0/tests/fixtures/coverage/contract_types.json +1 -0
- sourcelock-0.1.0/tests/fixtures/coverage/error_400_invalid_ncdid.json +1 -0
- sourcelock-0.1.0/tests/fixtures/coverage/error_401_lcd_no_token.json +15 -0
- sourcelock-0.1.0/tests/fixtures/coverage/final_lcds_report_trimmed.json +69 -0
- sourcelock-0.1.0/tests/fixtures/coverage/lcd_related_documents_33818.json +1 -0
- sourcelock-0.1.0/tests/fixtures/coverage/lcd_related_documents_head.csv +4 -0
- sourcelock-0.1.0/tests/fixtures/coverage/local_data_schedule.json +1 -0
- sourcelock-0.1.0/tests/fixtures/coverage/ncd_detail_11.json +1 -0
- sourcelock-0.1.0/tests/fixtures/coverage/ncd_report_trimmed.json +61 -0
- sourcelock-0.1.0/tests/fixtures/coverage/ncd_zip_range_headers.json +11 -0
- sourcelock-0.1.0/tests/fixtures/coverage/openapi_spec_trimmed.json +106 -0
- sourcelock-0.1.0/tests/fixtures/coverage/states.json +1 -0
- sourcelock-0.1.0/tests/fixtures/coverage/whats_new_local_trimmed.json +55 -0
- sourcelock-0.1.0/tests/fixtures/coverage/whats_new_national.json +1 -0
- sourcelock-0.1.0/tests/fixtures/hcc/VERIFIED_ADDENDUM.md +88 -0
- sourcelock-0.1.0/tests/fixtures/hcc/derive_report.txt +17 -0
- sourcelock-0.1.0/tests/fixtures/hcc/head_C2419P1M.csv +25 -0
- sourcelock-0.1.0/tests/fixtures/hcc/head_C2824T2N.csv +25 -0
- sourcelock-0.1.0/tests/fixtures/hcc/head_F2425P1M.txt +30 -0
- sourcelock-0.1.0/tests/fixtures/hcc/head_F2826T1N.txt +30 -0
- sourcelock-0.1.0/tests/fixtures/hcc/mirror_py2026.bin +1 -0
- sourcelock-0.1.0/tests/fixtures/hcc/mirror_sw2025.bin +1 -0
- sourcelock-0.1.0/tests/fixtures/hcc/mirror_sw2026.bin +3 -0
- sourcelock-0.1.0/tests/fixtures/hcc/mirror_sw2026_republished.bin +2 -0
- sourcelock-0.1.0/tests/fixtures/hcc/regenerate_vendored_data.py +503 -0
- sourcelock-0.1.0/tests/fixtures/leie/provenance.json +18 -0
- sourcelock-0.1.0/tests/fixtures/leie/updated_drift.csv +16 -0
- sourcelock-0.1.0/tests/fixtures/leie/updated_ok.csv +15 -0
- sourcelock-0.1.0/tests/fixtures/leie/updated_schema_changed.csv +15 -0
- sourcelock-0.1.0/tests/fixtures/leie/updated_unquoted.csv +15 -0
- sourcelock-0.1.0/tests/fixtures/leie/waivers_page.html +8 -0
- sourcelock-0.1.0/tests/fixtures/provider/PROVENANCE.md +22 -0
- sourcelock-0.1.0/tests/fixtures/provider/lookup_npi_missing.json +1 -0
- sourcelock-0.1.0/tests/fixtures/provider/lookup_npi_ok.json +1 -0
- sourcelock-0.1.0/tests/fixtures/provider/npi_api_error_noversion.json +1 -0
- sourcelock-0.1.0/tests/fixtures/provider/npi_files.html +128 -0
- sourcelock-0.1.0/tests/fixtures/provider/npi_files_v1_only.html +128 -0
- sourcelock-0.1.0/tests/fixtures/provider/pecos_dataset_resources.json +1 -0
- sourcelock-0.1.0/tests/fixtures/provider/pecos_filter_miss.json +1 -0
- sourcelock-0.1.0/tests/fixtures/provider/pecos_filter_ok.json +1 -0
- sourcelock-0.1.0/tests/fixtures/provider/pecos_size1.json +1 -0
- sourcelock-0.1.0/tests/fixtures/provider/pecos_stats.json +1 -0
- sourcelock-0.1.0/tests/test_action.py +422 -0
- sourcelock-0.1.0/tests/test_adapter_contract.py +103 -0
- sourcelock-0.1.0/tests/test_cache.py +1037 -0
- sourcelock-0.1.0/tests/test_canary_severity.py +625 -0
- sourcelock-0.1.0/tests/test_cli.py +212 -0
- sourcelock-0.1.0/tests/test_cli_failure_modes.py +188 -0
- sourcelock-0.1.0/tests/test_codes_cpt_claim.py +311 -0
- sourcelock-0.1.0/tests/test_demo_adapter.py +120 -0
- sourcelock-0.1.0/tests/test_doctor.py +195 -0
- sourcelock-0.1.0/tests/test_doctor_classification.py +215 -0
- sourcelock-0.1.0/tests/test_doctor_honesty.py +192 -0
- sourcelock-0.1.0/tests/test_guard.py +138 -0
- sourcelock-0.1.0/tests/test_guard_bypass.py +179 -0
- sourcelock-0.1.0/tests/test_guard_must_pass.py +145 -0
- sourcelock-0.1.0/tests/test_http.py +100 -0
- sourcelock-0.1.0/tests/test_http_limits.py +219 -0
- sourcelock-0.1.0/tests/test_lock_init_safety.py +294 -0
- sourcelock-0.1.0/tests/test_manifest.py +371 -0
- sourcelock-0.1.0/tests/test_mcp_server.py +126 -0
- sourcelock-0.1.0/tests/test_no_echo_residue.py +205 -0
- sourcelock-0.1.0/tests/test_no_input_echo.py +472 -0
- sourcelock-0.1.0/tests/test_npi.py +42 -0
- sourcelock-0.1.0/tests/test_offline_doctor.py +161 -0
- sourcelock-0.1.0/tests/test_packaging.py +212 -0
- sourcelock-0.1.0/tests/test_plugin_discovery.py +612 -0
- sourcelock-0.1.0/tests/test_receipt_provenance.py +123 -0
- sourcelock-0.1.0/tests/test_release_workflow.py +329 -0
- sourcelock-0.1.0/tests/test_schemas.py +213 -0
- sourcelock-0.1.0/tests/test_shortcuts.py +491 -0
- sourcelock-0.1.0/tests/test_stale_canaries.py +199 -0
- sourcelock-0.1.0/tests/test_strict_discovery.py +117 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Tests on every supported Python, then the wheel-install check that
|
|
2
|
+
# pyproject.toml used to claim existed.
|
|
3
|
+
#
|
|
4
|
+
# The two jobs answer different questions. `tests` asks "does the code in this
|
|
5
|
+
# checkout work". `wheel` asks "does the artifact we would publish work" -- it
|
|
6
|
+
# builds the wheel, installs THAT wheel into a fresh venv outside the checkout,
|
|
7
|
+
# and proves the installed copy carries every vendored data file, loads every
|
|
8
|
+
# adapter, answers on every CLI command, and declares the dependencies
|
|
9
|
+
# pyproject declares. Those are separable failures: the last wheel anyone built
|
|
10
|
+
# from this repo passed the test suite and was still missing `cryptography` and
|
|
11
|
+
# the manifest modules.
|
|
12
|
+
name: ci
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [master, main]
|
|
17
|
+
pull_request:
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: "ci-${{ github.ref }}"
|
|
25
|
+
cancel-in-progress: true
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
tests:
|
|
29
|
+
name: "pytest (py${{ matrix.python-version }})"
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
# Floor comes from pyproject's requires-python (>=3.11); the ceiling is
|
|
35
|
+
# the newest release we have actually run the suite on.
|
|
36
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
39
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
40
|
+
with:
|
|
41
|
+
python-version: "${{ matrix.python-version }}"
|
|
42
|
+
- name: "Install with dev extras"
|
|
43
|
+
run: |
|
|
44
|
+
python -m pip install --upgrade pip
|
|
45
|
+
python -m pip install -e ".[dev]"
|
|
46
|
+
- name: "pytest"
|
|
47
|
+
# The suite is offline by contract (tests/conftest.py blocks sockets),
|
|
48
|
+
# so a network blip here is a real failure, not flake to be retried.
|
|
49
|
+
run: python -m pytest
|
|
50
|
+
|
|
51
|
+
wheel:
|
|
52
|
+
name: "wheel install (py${{ matrix.python-version }})"
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
strategy:
|
|
55
|
+
fail-fast: false
|
|
56
|
+
matrix:
|
|
57
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
60
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
61
|
+
with:
|
|
62
|
+
python-version: "${{ matrix.python-version }}"
|
|
63
|
+
- name: "Build the wheel, install it clean, and check it"
|
|
64
|
+
run: bash scripts/wheel_check.sh python
|
|
65
|
+
|
|
66
|
+
action:
|
|
67
|
+
name: "composite action, offline"
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
71
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
72
|
+
with:
|
|
73
|
+
python-version: "3.12"
|
|
74
|
+
- name: "run_doctor.py against a saved report"
|
|
75
|
+
# The action's annotation and exit-code logic, with no network and no
|
|
76
|
+
# CMS: a saved report in, workflow commands out. Live doctor belongs on
|
|
77
|
+
# a schedule (docs/ci.md), not on every push -- a CI job that fails when
|
|
78
|
+
# CMS has a bad afternoon is a job people learn to ignore.
|
|
79
|
+
run: |
|
|
80
|
+
python - <<'PY'
|
|
81
|
+
import json, subprocess, sys
|
|
82
|
+
report = {
|
|
83
|
+
"exit_code": 1,
|
|
84
|
+
"lockfile_present": True,
|
|
85
|
+
"summary": {"ok": 1, "drift": 1, "schema_changed": 0, "unreachable": 0,
|
|
86
|
+
"unpinned": 0, "stale": 0, "error": 0, "fallback": 0},
|
|
87
|
+
"load_errors": [],
|
|
88
|
+
"results": [
|
|
89
|
+
{"canary_id": "demo.fixture_release", "source_id": "demo", "status": "ok",
|
|
90
|
+
"observed": "r1", "expected": "r1", "checked_at": "2026-01-01T00:00:00+00:00",
|
|
91
|
+
"remediation": "", "warnings": [], "fallback_used": False},
|
|
92
|
+
{"canary_id": "demo.fixture_hash", "source_id": "demo", "status": "drift",
|
|
93
|
+
"observed": "b", "expected": "a", "checked_at": "2026-01-01T00:00:00+00:00",
|
|
94
|
+
"remediation": "re-pin with `hc-source lock init`", "warnings": [],
|
|
95
|
+
"fallback_used": False},
|
|
96
|
+
],
|
|
97
|
+
}
|
|
98
|
+
open("report.json", "w").write(json.dumps(report))
|
|
99
|
+
proc = subprocess.run([sys.executable, "action/run_doctor.py", "--from-json", "report.json"],
|
|
100
|
+
capture_output=True, text=True)
|
|
101
|
+
print(proc.stdout, proc.stderr)
|
|
102
|
+
assert proc.returncode == 1, proc.returncode
|
|
103
|
+
assert "::error title=demo.fixture_hash [drift]" in proc.stdout
|
|
104
|
+
PY
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Tag -> release. One push, and the artifact people install exists.
|
|
2
|
+
#
|
|
3
|
+
# git tag v0.1.0 && git push origin v0.1.0
|
|
4
|
+
#
|
|
5
|
+
# What happens: the full test suite runs across the same Python matrix ci.yml
|
|
6
|
+
# uses, the tag is checked against pyproject's version, the sdist and wheel are
|
|
7
|
+
# built once, the wheel is installed clean and checked (scripts/check_wheel.py
|
|
8
|
+
# -- the same check CI runs), SHA256SUMS is generated, and a GitHub Release is
|
|
9
|
+
# created carrying all three. Publishing to PyPI is a separate job gated the
|
|
10
|
+
# same way, using Trusted Publishing (OIDC) so there is no long-lived token to
|
|
11
|
+
# leak. See RELEASING.md.
|
|
12
|
+
#
|
|
13
|
+
# Nothing downstream of `tests` can start until every matrix leg is green: a
|
|
14
|
+
# tag that fails on 3.11 must not produce a release just because 3.13 passed.
|
|
15
|
+
# The build happens ONCE and every downstream job consumes that artifact. A
|
|
16
|
+
# second `python -m build` would produce a second wheel, and then the checksums
|
|
17
|
+
# in the release would describe bytes nobody verified.
|
|
18
|
+
name: release
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
push:
|
|
22
|
+
tags: ["v*"]
|
|
23
|
+
workflow_dispatch:
|
|
24
|
+
inputs:
|
|
25
|
+
tag:
|
|
26
|
+
description: "Existing tag to build (workflow_dispatch only)."
|
|
27
|
+
required: true
|
|
28
|
+
|
|
29
|
+
permissions:
|
|
30
|
+
contents: read
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
tests:
|
|
34
|
+
name: "pytest (py${{ matrix.python-version }})"
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
strategy:
|
|
37
|
+
fail-fast: false
|
|
38
|
+
matrix:
|
|
39
|
+
# Same floor/ceiling as ci.yml's `tests` job. A release built from a
|
|
40
|
+
# tag that only passed on one Python is not "tested" in any sense
|
|
41
|
+
# RELEASING.md's promises rely on -- mirror the matrix, don't shrink it.
|
|
42
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
45
|
+
with:
|
|
46
|
+
ref: "${{ github.event.inputs.tag || github.ref }}"
|
|
47
|
+
|
|
48
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
49
|
+
with:
|
|
50
|
+
python-version: "${{ matrix.python-version }}"
|
|
51
|
+
|
|
52
|
+
- name: "Install with dev extras"
|
|
53
|
+
run: |
|
|
54
|
+
python -m pip install --upgrade pip
|
|
55
|
+
python -m pip install -e ".[dev]"
|
|
56
|
+
|
|
57
|
+
- name: "pytest"
|
|
58
|
+
# Offline by contract (tests/conftest.py blocks sockets): a network
|
|
59
|
+
# blip here is a real failure, not flake to retry past.
|
|
60
|
+
run: python -m pytest
|
|
61
|
+
|
|
62
|
+
build:
|
|
63
|
+
name: "build + verify"
|
|
64
|
+
needs: tests
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
outputs:
|
|
67
|
+
version: "${{ steps.version.outputs.version }}"
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
70
|
+
with:
|
|
71
|
+
ref: "${{ github.event.inputs.tag || github.ref }}"
|
|
72
|
+
|
|
73
|
+
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
|
74
|
+
with:
|
|
75
|
+
python-version: "3.12"
|
|
76
|
+
|
|
77
|
+
- name: "The tag and pyproject must agree"
|
|
78
|
+
env:
|
|
79
|
+
RAW_TAG: "${{ github.event.inputs.tag || github.ref_name }}"
|
|
80
|
+
run: |
|
|
81
|
+
set -euo pipefail
|
|
82
|
+
python - <<'PY'
|
|
83
|
+
import os, re, sys, tomllib
|
|
84
|
+
raw = os.environ["RAW_TAG"]
|
|
85
|
+
if not re.fullmatch(r"v[0-9A-Za-z.+_-]{1,60}", raw):
|
|
86
|
+
sys.exit(f"refusing to build from tag {raw!r}: expected vMAJOR.MINOR.PATCH")
|
|
87
|
+
tag = raw[1:]
|
|
88
|
+
declared = tomllib.load(open("pyproject.toml", "rb"))["project"]["version"]
|
|
89
|
+
if tag != declared:
|
|
90
|
+
sys.exit(
|
|
91
|
+
f"tag {raw} does not match pyproject version {declared}. Bump "
|
|
92
|
+
"pyproject.toml and re-tag; a release whose filename disagrees with its "
|
|
93
|
+
"metadata is the supply-chain problem this product exists to catch."
|
|
94
|
+
)
|
|
95
|
+
with open(os.environ["GITHUB_OUTPUT"], "a") as fh:
|
|
96
|
+
fh.write(f"version={tag}\n")
|
|
97
|
+
print(f"tag {raw} matches pyproject version {declared}")
|
|
98
|
+
PY
|
|
99
|
+
id: version
|
|
100
|
+
|
|
101
|
+
- name: "Build sdist + wheel"
|
|
102
|
+
run: |
|
|
103
|
+
set -euo pipefail
|
|
104
|
+
python -m pip install --upgrade pip build
|
|
105
|
+
python -m build --outdir dist .
|
|
106
|
+
ls -l dist
|
|
107
|
+
|
|
108
|
+
- name: "Install the built wheel clean and check it"
|
|
109
|
+
run: |
|
|
110
|
+
set -euo pipefail
|
|
111
|
+
python -m venv /tmp/relcheck
|
|
112
|
+
/tmp/relcheck/bin/python -m pip install --quiet --upgrade pip
|
|
113
|
+
/tmp/relcheck/bin/python -m pip install --quiet dist/*.whl
|
|
114
|
+
cd /tmp # never import hc_source from the checkout
|
|
115
|
+
/tmp/relcheck/bin/python "${GITHUB_WORKSPACE}/scripts/check_wheel.py" \
|
|
116
|
+
--source-root "${GITHUB_WORKSPACE}"
|
|
117
|
+
|
|
118
|
+
- name: "SHA256SUMS"
|
|
119
|
+
run: |
|
|
120
|
+
set -euo pipefail
|
|
121
|
+
cd dist
|
|
122
|
+
sha256sum -- *.whl *.tar.gz > SHA256SUMS
|
|
123
|
+
cat SHA256SUMS
|
|
124
|
+
|
|
125
|
+
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
|
126
|
+
with:
|
|
127
|
+
name: dist
|
|
128
|
+
path: dist/
|
|
129
|
+
if-no-files-found: error
|
|
130
|
+
|
|
131
|
+
github-release:
|
|
132
|
+
name: "GitHub Release"
|
|
133
|
+
needs: [tests, build]
|
|
134
|
+
runs-on: ubuntu-latest
|
|
135
|
+
permissions:
|
|
136
|
+
contents: write # creating a release is the only write this workflow needs
|
|
137
|
+
steps:
|
|
138
|
+
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
139
|
+
with:
|
|
140
|
+
name: dist
|
|
141
|
+
path: dist
|
|
142
|
+
- name: "Create the release"
|
|
143
|
+
env:
|
|
144
|
+
GH_TOKEN: "${{ github.token }}"
|
|
145
|
+
TAG: "${{ github.event.inputs.tag || github.ref_name }}"
|
|
146
|
+
VERSION: "${{ needs.build.outputs.version }}"
|
|
147
|
+
REPO: "${{ github.repository }}"
|
|
148
|
+
run: |
|
|
149
|
+
set -euo pipefail
|
|
150
|
+
{
|
|
151
|
+
echo "SourceLock ${VERSION}."
|
|
152
|
+
echo
|
|
153
|
+
echo '```'
|
|
154
|
+
cat dist/SHA256SUMS
|
|
155
|
+
echo '```'
|
|
156
|
+
echo
|
|
157
|
+
echo "Verify before you install:"
|
|
158
|
+
echo
|
|
159
|
+
echo '```'
|
|
160
|
+
echo "sha256sum -c SHA256SUMS"
|
|
161
|
+
echo "pipx install ./sourcelock-${VERSION}-py3-none-any.whl"
|
|
162
|
+
echo '```'
|
|
163
|
+
echo
|
|
164
|
+
echo "The wheel in this release was installed into a clean virtualenv and"
|
|
165
|
+
echo "checked by scripts/check_wheel.py before the release was created:"
|
|
166
|
+
echo "every vendored data file present, every adapter loading, every CLI"
|
|
167
|
+
echo "command answering, and metadata matching pyproject.toml. The full"
|
|
168
|
+
echo "test suite passed on Python 3.11, 3.12, and 3.13 before this build"
|
|
169
|
+
echo "ran."
|
|
170
|
+
} > notes.md
|
|
171
|
+
gh release create "${TAG}" dist/* \
|
|
172
|
+
--repo "${REPO}" \
|
|
173
|
+
--title "SourceLock ${VERSION}" \
|
|
174
|
+
--notes-file notes.md
|
|
175
|
+
|
|
176
|
+
pypi:
|
|
177
|
+
name: "PyPI (Trusted Publishing)"
|
|
178
|
+
needs: [tests, build]
|
|
179
|
+
runs-on: ubuntu-latest
|
|
180
|
+
environment:
|
|
181
|
+
# A GitHub Environment, not just a name: configure it (Settings ->
|
|
182
|
+
# Environments -> pypi) with "Deployment branches and tags" restricted to
|
|
183
|
+
# `v*` so a token-less OIDC exchange can still only fire from a real
|
|
184
|
+
# release tag. Required by PyPI Trusted Publishing's publisher config,
|
|
185
|
+
# which is registered against this exact repo/workflow/environment
|
|
186
|
+
# triple -- see RELEASING.md.
|
|
187
|
+
name: pypi
|
|
188
|
+
url: https://pypi.org/project/sourcelock/
|
|
189
|
+
permissions:
|
|
190
|
+
id-token: write # the OIDC token Trusted Publishing exchanges for an upload credential
|
|
191
|
+
steps:
|
|
192
|
+
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
193
|
+
with:
|
|
194
|
+
name: dist
|
|
195
|
+
path: dist
|
|
196
|
+
|
|
197
|
+
- name: "Drop the checksum manifest -- it is a release asset, not a distribution"
|
|
198
|
+
run: rm -f dist/SHA256SUMS
|
|
199
|
+
|
|
200
|
+
- name: "Publish"
|
|
201
|
+
# No password/token input: Trusted Publishing mints a short-lived PyPI
|
|
202
|
+
# API token from this job's OIDC identity (the `id-token: write`
|
|
203
|
+
# permission above) inside the action itself. There is no
|
|
204
|
+
# PYPI_API_TOKEN secret sitting in this job's environment while
|
|
205
|
+
# anything gets pip-installed from the network -- that was the finding
|
|
206
|
+
# this replaces. If the trusted publisher is not yet registered on
|
|
207
|
+
# PyPI's side, this step fails with a clear error; the GitHub Release
|
|
208
|
+
# above already succeeded independently, so a first release still
|
|
209
|
+
# produces installable artifacts even before PyPI is wired up.
|
|
210
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.coverage
|
|
12
|
+
htmlcov/
|
|
13
|
+
*.log
|
|
14
|
+
.DS_Store
|
|
15
|
+
|
|
16
|
+
# ops material (runbooks, signing keys) lives in ~/sourcelock-ops, never here
|
|
17
|
+
sourcelock-ops/
|
|
18
|
+
keys/
|
|
19
|
+
*.key
|
|
20
|
+
sourcelock-manifest.json
|