diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 20eb70c..0b73e82 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,8 +10,28 @@ on: permissions: {} jobs: - tests: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.14" + - name: Install tox + run: | + python -m pip install --upgrade pip + python -m pip install --upgrade tox + - name: Build wheel and sdist + run: tox -e build + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: dist + path: dist/ + tests: + needs: build runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -38,19 +58,24 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: dist + path: dist/ - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install --upgrade tox - name: Run tests + shell: bash run: | - tox + tox --installpkg dist/tzdata-*.whl other: runs-on: "ubuntu-latest" strategy: matrix: - toxenv: ["build", "precommit", "typing", "docs"] + toxenv: ["precommit", "typing", "docs"] env: TOXENV: ${{ matrix.toxenv }} diff --git a/sbom.cdx.json b/sbom.cdx.json new file mode 100644 index 0000000..7591f86 --- /dev/null +++ b/sbom.cdx.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json", + "version": 1, + "bomFormat": "CycloneDX", + "specVersion": "1.7", + "metadata": { + "component": { + "bom-ref": "pkg:pypi/tzdata@2026.1", + "name": "tzdata", + "version": "2026.1", + "purl": "pkg:pypi/tzdata@2026.1", + "type": "library", + "components": [ + { + "bom-ref": "https://www.iana.org/time-zones", + "name": "tz", + "version": "2026a", + "type": "data", + "data": [ + { + "type": "dataset", + "name": "IANA Time Zone Database", + "description": "zic-compiled TZif timezone files" + } + ], + "licenses": [ + { + "license": { + "name": "tz database license", + "url": "https://data.iana.org/time-zones/tz-link.html" + } + } + ] + } + ] + } + } +} diff --git a/templates/sbom.cdx.json.in b/templates/sbom.cdx.json.in new file mode 100644 index 0000000..1648d8b --- /dev/null +++ b/templates/sbom.cdx.json.in @@ -0,0 +1,38 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json", + "version": 1, + "bomFormat": "CycloneDX", + "specVersion": "1.7", + "metadata": { + "component": { + "bom-ref": "pkg:pypi/tzdata@%%PACKAGE_VERSION%%", + "name": "tzdata", + "version": "%%PACKAGE_VERSION%%", + "purl": "pkg:pypi/tzdata@%%PACKAGE_VERSION%%", + "type": "library", + "components": [ + { + "bom-ref": "https://www.iana.org/time-zones", + "name": "tz", + "version": "%%IANA_VERSION%%", + "type": "data", + "data": [ + { + "type": "dataset", + "name": "IANA Time Zone Database", + "description": "zic-compiled TZif timezone files" + } + ], + "licenses": [ + { + "license": { + "name": "tz database license", + "url": "https://data.iana.org/time-zones/tz-link.html" + } + } + ] + } + ] + } + } +} diff --git a/tox.ini b/tox.ini index 83e7708..1a9d172 100644 --- a/tox.ini +++ b/tox.ini @@ -81,4 +81,7 @@ commands = python -c "from pathlib import Path; \ [x.unlink(missing_ok=True) for x in Path('{toxinidir}/dist').glob('*')]" python -m build -o {toxinidir}/dist {toxinidir} + python -c "import re, zipfile; from pathlib import Path; \ + d = Path('{toxinidir}/sbom.cdx.json').read_bytes(); \ + [((z := zipfile.ZipFile(w, 'a')).writestr(re.match(r'(.+?-.+?)-', w.name)[1] + '.dist-info/sboms/sbom.cdx.json', d), z.close()) for w in Path('{toxinidir}/dist').glob('*.whl')]" twine check {toxinidir}/dist/* diff --git a/update.py b/update.py index d11773a..da361f8 100644 --- a/update.py +++ b/update.py @@ -196,6 +196,15 @@ def create_package(version: str, zonenames: Sequence[str], zoneinfo_dir: pathlib with open(target_dir / "__init__.py", "w") as f_out: f_out.write(contents) + # Generate the SBOM from a template. + with open(TEMPLATES_DIR / "sbom.cdx.json.in", "r") as f_in: + contents = f_in.read() + contents = contents.replace("%%PACKAGE_VERSION%%", package_version) + contents = contents.replace("%%IANA_VERSION%%", version) + + with open(REPO_ROOT / "sbom.cdx.json", "w") as f_out: + f_out.write(contents) + with open(REPO_ROOT / "VERSION", "w") as f: f.write(package_version)