Skip to content

Commit 53ff707

Browse files
committed
Merge remote-tracking branch 'upstream/main' into improving-ci-coverage-and-configuring-.coveragerc
2 parents bd27b88 + ce121e2 commit 53ff707

6 files changed

Lines changed: 928 additions & 0 deletions

File tree

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) The OGX Contributors.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the terms described in the LICENSE file in
6+
# the root directory of this source tree.
7+
8+
"""Update constraint-dependencies in pyproject.toml for Dependabot PRs.
9+
10+
Dependabot's uv ecosystem only modifies uv.lock directly. This script
11+
updates the >= lower bound in [tool.uv] constraint-dependencies so that
12+
pyproject.toml remains the source of truth.
13+
"""
14+
15+
import argparse
16+
import re
17+
import sys
18+
from pathlib import Path
19+
20+
21+
def parse_version(version_str: str) -> tuple[int, ...]:
22+
return tuple(int(x) for x in version_str.split("."))
23+
24+
25+
def normalize_pkg_pattern(pkg_name: str) -> str:
26+
"""Convert a package name into a regex pattern matching any PEP 503 equivalent."""
27+
return re.sub(r"[-_.]", "[-_.]", pkg_name.lower())
28+
29+
30+
def find_constraint_section(lines: list[str]) -> tuple[int, int] | None:
31+
"""Find the start and end line indices of the constraint-dependencies array."""
32+
start = None
33+
for i, line in enumerate(lines):
34+
if re.match(r"^constraint-dependencies\s*=\s*\[", line):
35+
start = i
36+
continue
37+
if start is not None and line.rstrip().rstrip(",").endswith("]"):
38+
return start, i
39+
return None
40+
41+
42+
def find_constraint_line(lines: list[str], pkg_name: str) -> int | None:
43+
section = find_constraint_section(lines)
44+
if section is None:
45+
return None
46+
start, end = section
47+
pattern = re.compile(rf'^\s*"{normalize_pkg_pattern(pkg_name)}', re.IGNORECASE)
48+
for i in range(start, end + 1):
49+
if pattern.match(lines[i]):
50+
return i
51+
return None
52+
53+
54+
def update_constraint(line: str, pkg_name: str, new_version: str) -> tuple[str, bool, str]:
55+
"""Update the >= lower bound in a constraint-dependencies line.
56+
57+
Returns (new_line, changed, reason).
58+
"""
59+
pkg_pattern = normalize_pkg_pattern(pkg_name)
60+
lower_bound_pattern = re.compile(rf'("{pkg_pattern}>=)([\d]+(?:\.[\d]+)*)', re.IGNORECASE)
61+
62+
match = lower_bound_pattern.search(line)
63+
if not match:
64+
return line, False, f"no >= lower bound for {pkg_name}"
65+
66+
old_version = match.group(2)
67+
if parse_version(new_version) <= parse_version(old_version):
68+
return line, False, (f"{pkg_name}: new version {new_version} <= current floor {old_version}")
69+
70+
upper_bound_match = re.search(rf'"{pkg_pattern}>=[^"]*,<([\d]+(?:\.[\d]+)*)"', line, re.IGNORECASE)
71+
if upper_bound_match:
72+
upper_version = upper_bound_match.group(1)
73+
if parse_version(new_version) >= parse_version(upper_version):
74+
return line, False, (f"{pkg_name}: new version {new_version} >= upper bound <{upper_version}, skipping")
75+
76+
new_line = lower_bound_pattern.sub(lambda m: m.group(1) + new_version, line)
77+
return new_line, True, (f"{pkg_name}: updated >= floor from {old_version} to {new_version}")
78+
79+
80+
def main() -> int:
81+
parser = argparse.ArgumentParser(description="Update constraint-dependencies in pyproject.toml")
82+
parser.add_argument("--dependency-name", required=True)
83+
parser.add_argument("--dependency-version", required=True)
84+
parser.add_argument(
85+
"--pyproject",
86+
default="pyproject.toml",
87+
help="Path to pyproject.toml (default: pyproject.toml)",
88+
)
89+
args = parser.parse_args()
90+
91+
pyproject_path = Path(args.pyproject)
92+
if not pyproject_path.exists():
93+
print(f"Error: {pyproject_path} not found", file=sys.stderr)
94+
return 1
95+
96+
content = pyproject_path.read_text()
97+
lines = content.splitlines(keepends=True)
98+
99+
line_idx = find_constraint_line(lines, args.dependency_name)
100+
if line_idx is None:
101+
print(f"SKIP: {args.dependency_name} not found in constraint-dependencies")
102+
print("updated=false")
103+
return 0
104+
105+
new_line, changed, reason = update_constraint(lines[line_idx], args.dependency_name, args.dependency_version)
106+
107+
if not changed:
108+
print(f"SKIP: {reason}")
109+
print("updated=false")
110+
return 0
111+
112+
lines[line_idx] = new_line
113+
pyproject_path.write_text("".join(lines))
114+
print(f"UPDATED: {reason}")
115+
print("updated=true")
116+
return 0
117+
118+
119+
if __name__ == "__main__":
120+
sys.exit(main())

.github/workflows/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ OGX uses GitHub Actions for Continuous Integration (CI). Below is a table detail
88
| Build Distribution Images | [build-distributions.yml](build-distributions.yml) | Build Distribution Images |
99
| CI Status | [ci-status.yml](ci-status.yml) | Aggregate CI check status |
1010
| CodeQL Workflow Security Scan | [codeql.yml](codeql.yml) | CodeQL Workflow Security Scan |
11+
| Commit Constraint Updates | [commit-constraint-updates.yml](commit-constraint-updates.yml) | Commit Constraint Updates |
1112
| Commit Recordings | [commit-recordings.yml](commit-recordings.yml) | Commit Recordings |
13+
| Dependabot constraint-dependencies | [dependabot-constraints.yml](dependabot-constraints.yml) | Update constraint-dependencies for Dependabot PR |
1214
| Documentation Build | [docs-build.yml](docs-build.yml) | Build and validate documentation |
1315
| File Processors Tests | [file-processors-tests.yml](file-processors-tests.yml) | Run file processors integration tests |
1416
| Installer CI | [install-script-ci.yml](install-script-ci.yml) | Test the installation script |

0 commit comments

Comments
 (0)