Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/actions/release-toolchain/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Frozen release build scaffold
description: Install the identical hash-locked candidate and publishing toolchain
runs:
using: composite
steps:
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: '3.14.7'
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: '0.12.13'
- name: Install hash-locked preparation and build tools
shell: bash
run: python scripts/release_build.py bootstrap --output "$RUNNER_TEMP/wrapper-release-tools"
177 changes: 177 additions & 0 deletions .github/release-toolchain.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
{
"build_backend_requires": [
"setuptools==84.0.0",
"wheel==0.48.0",
"setuptools-scm==8.3.1",
"packaging==25.0"
],
"image_source": "https://github.com/actions/runner-images/releases/tag/ubuntu24/20260907.300",
"python": "3.14.7",
"python_source": "https://github.com/actions/python-versions/releases/tag/3.14.7-31064857500",
"runner": {
"arch": "X64",
"image_os": "ubuntu24",
"image_version": "20260907.300.1",
"os": "Linux"
},
"schema_version": 1,
"setup_actions": {
"actions/setup-python": {
"commit": "ece7cb06caefa5fff74198d8649806c4678c61a1",
"ref": "v6",
"source": "https://api.github.com/repos/actions/setup-python/git/ref/tags/v6"
},
"astral-sh/setup-uv": {
"commit": "08807647e7069bb48b6ef5acd8ec9567f424441b",
"ref": "v8.1.0",
"source": "https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/v8.1.0"
}
},
"tools": {
"build": {
"registry_json": "https://pypi.org/pypi/build/1.6.1/json",
"registry_json_sha256": "064e9dcb80e948b5de7a841c3fd9b5644a980eb27bb644fb7f562b7d773b157b",
"requires": [
"packaging>=24.0",
"pyproject_hooks"
],
"version": "1.6.1",
"wheels": [
{
"filename": "build-1.6.1-py3-none-any.whl",
"sha256": "ecd351a4be9d35a9eaaba244a7687143c9c7d4aea6ac964e7e7ddab20cbcf4e7",
"url": "https://files.pythonhosted.org/packages/ad/9b/9fb3585dabcd73a1b2a6267f63f62649347c9e6d072c9fde365b105abb2c/build-1.6.1-py3-none-any.whl"
}
]
},
"click": {
"registry_json": "https://pypi.org/pypi/click/8.5.0/json",
"registry_json_sha256": "4e36adc9b46f837e10ce801b7a478f9146fefdfb287292b7668fc64b1474e41d",
"requires": [],
"version": "8.5.0",
"wheels": [
{
"filename": "click-8.5.0-py3-none-any.whl",
"sha256": "255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360",
"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"
}
]
},
"jinja2": {
"registry_json": "https://pypi.org/pypi/jinja2/3.1.6/json",
"registry_json_sha256": "1bc757d7065f3e67d3a49e72ebc731d0774055575732592eede9820c136329cc",
"requires": [
"MarkupSafe>=2.0"
],
"version": "3.1.6",
"wheels": [
{
"filename": "jinja2-3.1.6-py3-none-any.whl",
"sha256": "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67",
"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"
}
]
},
"markupsafe": {
"registry_json": "https://pypi.org/pypi/markupsafe/3.0.3/json",
"registry_json_sha256": "20faf559f1a150d84e7b0e7567b933fb3d383e6ba82179a1caa32a44cdc96085",
"requires": [],
"version": "3.0.3",
"wheels": [
{
"filename": "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
"sha256": "457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97",
"url": "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"
}
]
},
"packaging": {
"registry_json": "https://pypi.org/pypi/packaging/25.0/json",
"registry_json_sha256": "6ab300d7b0735a50109912decebb1731ed292f1ed88a3ce5e4bb7876b182cac0",
"requires": [],
"version": "25.0",
"wheels": [
{
"filename": "packaging-25.0-py3-none-any.whl",
"sha256": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484",
"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"
}
]
},
"pyproject-hooks": {
"registry_json": "https://pypi.org/pypi/pyproject-hooks/1.2.0/json",
"registry_json_sha256": "e937e86433ebeed6e8c85538b0adbc7d3ce964b011fc141a7f9aec79c4e49d05",
"requires": [],
"version": "1.2.0",
"wheels": [
{
"filename": "pyproject_hooks-1.2.0-py3-none-any.whl",
"sha256": "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913",
"url": "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl"
}
]
},
"setuptools": {
"registry_json": "https://pypi.org/pypi/setuptools/84.0.0/json",
"registry_json_sha256": "24d07932459261bbf9e66e5cfdebfeba23a977234ab24bf9c3a1df053c53ba21",
"requires": [],
"version": "84.0.0",
"wheels": [
{
"filename": "setuptools-84.0.0-py3-none-any.whl",
"sha256": "51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670",
"url": "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"
}
]
},
"setuptools-scm": {
"registry_json": "https://pypi.org/pypi/setuptools-scm/8.3.1/json",
"registry_json_sha256": "f8afaee39a8af1a697a40dc7e80d39cb90756ae3aa4d25c47f107a3f17b48d88",
"requires": [
"packaging>=20",
"setuptools"
],
"version": "8.3.1",
"wheels": [
{
"filename": "setuptools_scm-8.3.1-py3-none-any.whl",
"sha256": "332ca0d43791b818b841213e76b1971b7711a960761c5bea5fc5cdb5196fbce3",
"url": "https://files.pythonhosted.org/packages/ab/ac/8f96ba9b4cfe3e4ea201f23f4f97165862395e9331a424ed325ae37024a8/setuptools_scm-8.3.1-py3-none-any.whl"
}
]
},
"towncrier": {
"registry_json": "https://pypi.org/pypi/towncrier/26.9.0/json",
"registry_json_sha256": "20e688a6205b29a19a6de1a3c7f2b404aceb78045a0eac6d359259b82da6b935",
"requires": [
"click",
"jinja2"
],
"version": "26.9.0",
"wheels": [
{
"filename": "towncrier-26.9.0-py3-none-any.whl",
"sha256": "ae4d223e6aadaff98d29b7f09e58d9c9ccf4cd3b455a2d2e0486d432cd8bf660",
"url": "https://files.pythonhosted.org/packages/82/88/f9340b545dafa64de053798e760515a2736fbb60092cf9aa6b146ccf3ede/towncrier-26.9.0-py3-none-any.whl"
}
]
},
"wheel": {
"registry_json": "https://pypi.org/pypi/wheel/0.48.0/json",
"registry_json_sha256": "03f655da3a6dd010d9ac41d4771d5d973109cb662a1e10eb9d967535ffd145f8",
"requires": [
"packaging>=24.0"
],
"version": "0.48.0",
"wheels": [
{
"filename": "wheel-0.48.0-py3-none-any.whl",
"sha256": "3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab",
"url": "https://files.pythonhosted.org/packages/2e/29/69cfbb602cd91690c55d38ba9fe53e6a7e76a6fa647bf38f19c138d25449/wheel-0.48.0-py3-none-any.whl"
}
]
}
},
"uv": "0.12.13",
"verified_at_utc": "2026-09-12T16:29:15.410657+00:00"
}
12 changes: 12 additions & 0 deletions .github/release-tools.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Exact artifacts for the frozen Linux x86_64 CPython 3.14 build scaffold.
# The separate base scaffold dependencies come from reviewed uv.lock.
build==1.6.1 --hash=sha256:ecd351a4be9d35a9eaaba244a7687143c9c7d4aea6ac964e7e7ddab20cbcf4e7
click==8.5.0 --hash=sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360
jinja2==3.1.6 --hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
markupsafe==3.0.3 --hash=sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97
packaging==25.0 --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484
pyproject-hooks==1.2.0 --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
setuptools==84.0.0 --hash=sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670
setuptools-scm==8.3.1 --hash=sha256:332ca0d43791b818b841213e76b1971b7711a960761c5bea5fc5cdb5196fbce3
towncrier==26.9.0 --hash=sha256:ae4d223e6aadaff98d29b7f09e58d9c9ccf4cd3b455a2d2e0486d432cd8bf660
wheel==0.48.0 --hash=sha256:3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab
68 changes: 68 additions & 0 deletions .github/workflows/pr_code_changes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,78 @@ on:
- changelog.d/**
- pyproject.toml
- uv.lock
- Makefile
- src/policyengine/data/bundle/manifest.json
workflow_dispatch:

jobs:
ReleaseCandidate:
name: Nonpublishing wrapper candidate (release)
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-24.04
permissions:
contents: read
actions: read
env:
GH_TOKEN: ${{ github.token }}
POLICYENGINE_SKIP_COUNTRY_IMPORTS: '1'
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0
persist-credentials: false
- uses: ./.github/actions/release-toolchain
- name: Prepare and build isolated candidate source
env:
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
run: python scripts/release_build.py candidate --flavor release --output "$RUNNER_TEMP/wrapper-candidate"
- name: Upload actual candidate wheel and preparation evidence
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: wrapper-release-candidate-${{ github.event.pull_request.head.sha }}-${{ github.event.pull_request.base.sha }}-release
path: ${{ runner.temp }}/wrapper-candidate/
if-no-files-found: error
retention-days: 90

NumericalCandidate:
name: Nonpublishing wrapper candidate (rc1)
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && vars.RELEASE_COUNTRY_CANDIDATE_ARTIFACT_ID != ''
runs-on: ubuntu-24.04
permissions:
contents: read
actions: read
env:
GH_TOKEN: ${{ github.token }}
POLICYENGINE_SKIP_COUNTRY_IMPORTS: '1'
RELEASE_COUNTRY_CANDIDATE_ARTIFACT_ID: ${{ vars.RELEASE_COUNTRY_CANDIDATE_ARTIFACT_ID }}
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0
persist-credentials: false
- name: Read selected country artifact with the existing GitHub App
id: country-token
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: PolicyEngine
repositories: policyengine-us
permission-actions: read
- uses: ./.github/actions/release-toolchain
- name: Prepare and build isolated candidate source
env:
GH_TOKEN: ${{ steps.country-token.outputs.token }}
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
run: python scripts/release_build.py candidate --flavor rc1 --output "$RUNNER_TEMP/wrapper-candidate"
- name: Upload actual candidate wheel and preparation evidence
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: wrapper-release-candidate-${{ github.event.pull_request.head.sha }}-${{ github.event.pull_request.base.sha }}-rc1
path: ${{ runner.temp }}/wrapper-candidate/
if-no-files-found: error
retention-days: 90

check-changelog:
name: Check changelog fragment
runs-on: ubuntu-latest
Expand Down
Loading
Loading