PYTHON-5433: Create an sbom-requirements.txt file to capture optional dependencies (#2649)

This commit is contained in:
Jib 2025-12-16 14:29:15 -05:00 committed by GitHub
parent 0cfba4994d
commit f9f48bab95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 81 additions and 3 deletions

View File

@ -11,6 +11,9 @@ on:
branches: ['master']
paths:
- 'requirements.txt'
- 'requirements/**.txt'
- '!requirements/docs.txt'
- '!requirements/test.txt'
permissions:
contents: write
@ -39,7 +42,8 @@ jobs:
run: |
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python tools/generate_sbom_requirements.py
pip install -r sbom-requirements.txt
pip install .
pip uninstall -y pip setuptools
deactivate
@ -60,7 +64,7 @@ jobs:
- name: Cleanup
if: always()
run: rm -rf .venv .venv-sbom
run: rm -rf .venv .venv-sbom sbom-requirements.txt
- name: Upload SBOM artifact
uses: actions/upload-artifact@v6
@ -76,7 +80,7 @@ jobs:
commit-message: 'chore: Update SBOM after dependency changes'
branch: auto-update-sbom-${{ github.run_id }}
delete-branch: true
title: 'chore: Update SBOM'
title: 'Automation: Update SBOM'
body: |
## Automated SBOM Update

View File

@ -0,0 +1,74 @@
"""
Concatenate requirements files into sbom-requirements.txt at repository root.
- Includes repo_root/requirements.txt if present
- Includes all files matching repo_root/requirements/**/*.txt
- Excludes docs.txt and test.txt in the requirements folder
- Writes output to sbom-requirements.txt (overwrites)
"""
from __future__ import annotations
from pathlib import Path
EXCLUDED_NAMES = {"docs.txt", "test.txt"}
def collect_files(root: Path) -> list[Path]:
"""Collect requirement files to include in SBOM requirements.
Args:
root (Path): The root directory of the repository.
Returns:
list[Path]: A list of Paths to requirement files to include in the SBOM.
"""
files = []
# requirements.txt + all requirements/**/*.txt
for p in [root / "requirements.txt", *root.glob("requirements/**/*.txt")]:
if p.is_file() and p.name not in EXCLUDED_NAMES:
files.append(p)
return files
def write_combined_req_files(root: Path, files: list[Path], outname: str) -> Path:
"""Concatenate requirement files and write to outname file.
Args:
root (Path): The root directory of the repository.
files (list[Path]): A list of Paths to requirement files to include in the SBOM.
outname (str): The name of the output file.
Raises:
RuntimeError: If writing to the output file fails.
Returns:
Path: The path to the output file.
"""
outpath = root / outname
try:
with outpath.open("w", encoding="utf-8") as f:
for p in files:
with p.open("r", encoding="utf-8") as r:
content = r.read().rstrip()
if content:
f.write(content + "\n")
return outpath
except Exception as e:
raise RuntimeError(f"Failed to write {outpath}: {e}") from e
def main():
root = Path(__file__).parent.parent.resolve()
files = collect_files(root)
if not files:
raise FileNotFoundError(f"No requirement files found from {root}")
outpath = write_combined_req_files(root, files, "sbom-requirements.txt")
print(f"Wrote concatenated requirements to: {outpath}")
if __name__ == "__main__":
main()