Skip to content

Commit 71bd9e2

Browse files
authored
Merge pull request #1479 from PolicyEngine/fix/pin-authlib-add-jwt-validation-test
Add JWT validation test and dependency lock file
2 parents c45af74 + 3d27c7d commit 71bd9e2

53 files changed

Lines changed: 4691 additions & 2017 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Thumbs.db
5353
docs/
5454
*.md
5555
README*
56+
!README.md
5657

5758
# Tests
5859
tests/

.github/bump_version.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
"""Infer semver bump from towncrier fragment types and update version."""
2+
3+
from __future__ import annotations
4+
5+
import re
6+
import sys
7+
from pathlib import Path
8+
9+
10+
class VersioningError(Exception):
11+
"""Raised when version bump inference cannot be completed."""
12+
13+
14+
def get_current_version(pyproject_path: Path) -> str:
15+
text = pyproject_path.read_text()
16+
match = re.search(r'^version\s*=\s*"(\d+\.\d+\.\d+)"', text, re.MULTILINE)
17+
if not match:
18+
raise VersioningError("Could not find version in pyproject.toml")
19+
return match.group(1)
20+
21+
22+
def get_fragment_category(fragment_path: Path) -> str | None:
23+
parts = fragment_path.name.split(".")
24+
if len(parts) >= 3:
25+
return parts[-2]
26+
if fragment_path.suffix and fragment_path.suffix != ".md":
27+
return fragment_path.suffix.lstrip(".")
28+
return None
29+
30+
31+
def infer_bump(changelog_dir: Path) -> str:
32+
fragments = [
33+
fragment
34+
for fragment in changelog_dir.iterdir()
35+
if fragment.is_file() and fragment.name != ".gitkeep"
36+
]
37+
if not fragments:
38+
raise VersioningError("No changelog fragments found")
39+
40+
categories = {
41+
category
42+
for fragment in fragments
43+
if (category := get_fragment_category(fragment))
44+
}
45+
46+
if "breaking" in categories:
47+
return "major"
48+
if "added" in categories or "removed" in categories:
49+
return "minor"
50+
return "patch"
51+
52+
53+
def bump_version(version: str, bump: str) -> str:
54+
major, minor, patch = (int(x) for x in version.split("."))
55+
if bump == "major":
56+
return f"{major + 1}.0.0"
57+
if bump == "minor":
58+
return f"{major}.{minor + 1}.0"
59+
return f"{major}.{minor}.{patch + 1}"
60+
61+
62+
def update_file(path: Path, old_version: str, new_version: str) -> bool:
63+
text = path.read_text()
64+
updated = text.replace(
65+
f'version = "{old_version}"',
66+
f'version = "{new_version}"',
67+
)
68+
if updated == text:
69+
return False
70+
path.write_text(updated)
71+
print(f" Updated {path}")
72+
return True
73+
74+
75+
def main(root: Path | None = None) -> str:
76+
root = root or Path(__file__).resolve().parent.parent
77+
pyproject = root / "pyproject.toml"
78+
changelog_dir = root / "changelog.d"
79+
80+
try:
81+
current = get_current_version(pyproject)
82+
bump = infer_bump(changelog_dir)
83+
except VersioningError as exc:
84+
print(str(exc), file=sys.stderr)
85+
raise SystemExit(1) from exc
86+
87+
new = bump_version(current, bump)
88+
print(f"Version: {current} -> {new} ({bump})")
89+
update_file(pyproject, current, new)
90+
return new
91+
92+
93+
if __name__ == "__main__":
94+
raise SystemExit(main())

.github/changelog_template.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

.github/get-changelog-diff.sh

Lines changed: 0 additions & 2 deletions
This file was deleted.

.github/is-version-number-acceptable.sh

Lines changed: 0 additions & 33 deletions
This file was deleted.

.github/publish-git-tag.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
#! /usr/bin/env bash
22

3-
git tag `python setup.py --version`
4-
git push --tags || true # update the repository version
3+
set -euo pipefail
4+
5+
version=$(python -c 'import tomllib; from pathlib import Path; print(tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"])')
6+
7+
if git rev-parse --verify --quiet "refs/tags/$version" >/dev/null
8+
then
9+
echo "Tag $version already exists."
10+
exit 0
11+
fi
12+
13+
git tag "$version"
14+
git push origin "$version"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
6+
cd "$ROOT"
7+
8+
ARTIFACT_TAG="${IMAGE_NAME:?}:${GITHUB_SHA:?}"
9+
GHCR_SHA_TAG="ghcr.io/${GITHUB_REPOSITORY:?}:${GITHUB_SHA}"
10+
GHCR_LATEST_TAG="ghcr.io/${GITHUB_REPOSITORY:?}:latest"
11+
12+
docker build \
13+
-f ./gcp/policyengine_household_api/Dockerfile.production \
14+
-t "${ARTIFACT_TAG}" \
15+
.
16+
docker push "${ARTIFACT_TAG}"
17+
18+
if [ "${GITHUB_EVENT_NAME:-}" = "push" ] && [ "${GITHUB_REF:-}" = "refs/heads/main" ]; then
19+
docker tag "${ARTIFACT_TAG}" "${GHCR_SHA_TAG}"
20+
docker push "${GHCR_SHA_TAG}"
21+
docker tag "${ARTIFACT_TAG}" "${GHCR_LATEST_TAG}"
22+
docker push "${GHCR_LATEST_TAG}"
23+
fi
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
6+
cd "$ROOT"
7+
8+
FRAGMENTS=$(find changelog.d -type f ! -name ".gitkeep" | wc -l | tr -d ' ')
9+
10+
if [ "$FRAGMENTS" -eq 0 ]; then
11+
echo "::error::No changelog fragment found in changelog.d/"
12+
echo "Add one with: echo 'Description.' > changelog.d/\$(git branch --show-current).<type>.md"
13+
echo "Types: added, changed, fixed, removed, breaking"
14+
exit 1
15+
fi
16+
17+
echo "Found $FRAGMENTS changelog fragment(s)."

.github/scripts/check_updates.py

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
Check for PolicyEngine package updates and generate PR summary.
44
55
This script checks PyPI for newer versions of PolicyEngine packages,
6-
updates setup.py if needed, and generates changelog summaries.
6+
updates pyproject.toml if needed, and generates changelog summaries.
77
"""
88

99
import os
1010
import re
1111
import sys
12+
import tomllib
13+
from pathlib import Path
1214

1315
import requests
1416

@@ -24,14 +26,21 @@ def parse_version(version_str):
2426
return tuple(map(int, version_str.split(".")))
2527

2628

27-
def get_current_versions(setup_content):
28-
"""Extract current package versions from setup.py content."""
29+
def get_current_versions(pyproject_content):
30+
"""Extract current package versions from pyproject.toml content."""
2931
current_versions = {}
32+
dependencies = tomllib.loads(pyproject_content)["project"].get(
33+
"dependencies", []
34+
)
3035
for pkg in PACKAGES:
31-
pattern = rf'{pkg.replace("_", "[-_]")}==([0-9]+\.[0-9]+\.[0-9]+)'
32-
match = re.search(pattern, setup_content)
33-
if match:
34-
current_versions[pkg] = match.group(1)
36+
package_names = (pkg, pkg.replace("_", "-"))
37+
for dependency in dependencies:
38+
for package_name in package_names:
39+
if dependency.startswith(f"{package_name}=="):
40+
current_versions[pkg] = dependency.split("==", 1)[1]
41+
break
42+
if pkg in current_versions:
43+
break
3544
return current_versions
3645

3746

@@ -59,12 +68,19 @@ def find_updates(current_versions, latest_versions):
5968
return updates
6069

6170

62-
def update_setup_content(setup_content, updates):
63-
"""Update setup.py content with new versions."""
64-
new_content = setup_content
71+
def update_pyproject_content(pyproject_content, updates):
72+
"""Update pyproject.toml content with new versions."""
73+
new_content = pyproject_content
6574
for pkg, versions in updates.items():
66-
pattern = rf'({pkg.replace("_", "[-_]")}==)[0-9]+\.[0-9]+\.[0-9]+'
67-
new_content = re.sub(pattern, rf'\g<1>{versions["new"]}', new_content)
75+
pattern = (
76+
rf'("{pkg.replace("_", "[-_]")}==)'
77+
rf'{re.escape(versions["old"])}(")'
78+
)
79+
new_content = re.sub(
80+
pattern,
81+
rf"\g<1>{versions['new']}\g<2>",
82+
new_content,
83+
)
6884
return new_content
6985

7086

@@ -214,14 +230,10 @@ def generate_summary(updates):
214230
return "\n\n".join(summary_parts)
215231

216232

217-
def generate_changelog_entry(updates):
218-
"""Generate changelog entry for this repo."""
233+
def generate_changelog_fragment(updates):
234+
"""Generate towncrier changelog fragment content for this repo."""
219235
new_version = updates["policyengine_us"]["new"]
220-
return f"""- bump: patch
221-
changes:
222-
changed:
223-
- Update PolicyEngine US to {new_version}
224-
"""
236+
return f"Update PolicyEngine US to {new_version}.\n"
225237

226238

227239
def write_github_output(key, value):
@@ -234,11 +246,11 @@ def write_github_output(key, value):
234246

235247
def main():
236248
"""Main entry point for the script."""
237-
# Read current versions from setup.py
238-
with open("setup.py", "r") as f:
239-
setup_content = f.read()
249+
# Read current versions from pyproject.toml
250+
with open("pyproject.toml", "r") as f:
251+
pyproject_content = f.read()
240252

241-
current_versions = get_current_versions(setup_content)
253+
current_versions = get_current_versions(pyproject_content)
242254
print(f"Current versions: {current_versions}")
243255

244256
# Get latest versions from PyPI
@@ -255,20 +267,24 @@ def main():
255267

256268
print(f"Updates available: {updates}")
257269

258-
# Update setup.py
259-
new_setup_content = update_setup_content(setup_content, updates)
260-
with open("setup.py", "w") as f:
261-
f.write(new_setup_content)
270+
# Update pyproject.toml
271+
new_pyproject_content = update_pyproject_content(
272+
pyproject_content, updates
273+
)
274+
with open("pyproject.toml", "w") as f:
275+
f.write(new_pyproject_content)
262276

263277
# Generate and save PR summary
264278
full_summary = generate_summary(updates)
265279
with open("pr_summary.md", "w") as f:
266280
f.write(full_summary)
267281

268-
# Create changelog entry
269-
changelog_entry = generate_changelog_entry(updates)
270-
with open("changelog_entry.yaml", "w") as f:
271-
f.write(changelog_entry)
282+
# Create changelog fragment
283+
changelog_dir = Path("changelog.d")
284+
changelog_dir.mkdir(exist_ok=True)
285+
new_version = updates["policyengine_us"]["new"]
286+
fragment_path = changelog_dir / f"policyengine-us-{new_version}.changed.md"
287+
fragment_path.write_text(generate_changelog_fragment(updates))
272288

273289
# Set outputs
274290
write_github_output("has_updates", "true")
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
6+
cd "$ROOT"
7+
8+
UPDATES_SUMMARY="${UPDATES_SUMMARY:?UPDATES_SUMMARY must be set}"
9+
BRANCH_NAME="bot/weekly-us-update"
10+
11+
git config user.name "github-actions[bot]"
12+
git config user.email "github-actions[bot]@users.noreply.github.com"
13+
git switch -C "$BRANCH_NAME"
14+
15+
shopt -s nullglob
16+
FRAGMENTS=(changelog.d/*.md)
17+
if [ "${#FRAGMENTS[@]}" -eq 0 ]; then
18+
echo "Expected at least one changelog fragment in changelog.d/"
19+
exit 1
20+
fi
21+
22+
git add pyproject.toml uv.lock "${FRAGMENTS[@]}"
23+
git commit -m "Update policyengine-us (${UPDATES_SUMMARY})"
24+
git push -f origin "$BRANCH_NAME"

0 commit comments

Comments
 (0)