OilPriceAPI Python SDK v1.12.8 #19
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish to PyPI | |
| on: | |
| release: | |
| types: [published] | |
| permissions: | |
| contents: read | |
| jobs: | |
| verify: | |
| name: Verify release candidate | |
| if: github.event.release.prerelease == false | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 | |
| with: | |
| python-version: "3.12" | |
| - name: Install verification dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install -e '.[dev]' pip-audit 'build==1.5.0' 'jsonschema>=4.17,<4.24' | |
| - name: Verify release tag matches package version and protected main | |
| env: | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| set -euo pipefail | |
| PACKAGE_VERSION="$(python scripts/package_version.py)" | |
| if [ "$RELEASE_TAG" != "v$PACKAGE_VERSION" ]; then | |
| echo "::error::Release tag $RELEASE_TAG does not match package version $PACKAGE_VERSION" | |
| exit 1 | |
| fi | |
| git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main | |
| RELEASE_COMMIT="$(git rev-parse "$RELEASE_TAG^{commit}")" | |
| if [ "$RELEASE_COMMIT" != "$(git rev-parse HEAD)" ]; then | |
| echo "::error::Checked-out commit does not match $RELEASE_TAG" | |
| exit 1 | |
| fi | |
| if ! git merge-base --is-ancestor "$RELEASE_COMMIT" origin/main; then | |
| echo "::error::$RELEASE_TAG is not reachable from protected main" | |
| exit 1 | |
| fi | |
| - name: Lint source with ruff | |
| run: ruff check oilpriceapi/ | |
| - name: Run unit tests | |
| run: pytest tests/ --ignore=tests/integration --ignore=tests/contract -m 'not slow' --cov=oilpriceapi -v | |
| - name: Audit installed dependencies | |
| run: pip-audit | |
| - name: Validate public storefront claims | |
| run: python scripts/validate_storefront_claims.py | |
| - name: Build package | |
| run: python -m build | |
| - name: Validate exact built source distribution | |
| run: | | |
| set -euo pipefail | |
| PACKAGE_VERSION="$(python scripts/package_version.py)" | |
| SDIST="dist/oilpriceapi-${PACKAGE_VERSION}.tar.gz" | |
| if [ ! -f "$SDIST" ]; then | |
| echo "::error::Exact source distribution not found: $SDIST" | |
| exit 1 | |
| fi | |
| python scripts/validate_storefront_claims.py --sdist "$SDIST" | |
| - name: Install and import the exact built wheel | |
| run: ./scripts/clean-wheel-smoke.sh | |
| - name: Build signed snippet manifest | |
| run: | | |
| python scripts/generate_snippet_manifest.py \ | |
| --source-commit "$(git rev-parse HEAD)" \ | |
| --output artifacts/snippets/oilpriceapi-python-snippets-v1.json | |
| - name: Prepare checksummed release artifact | |
| run: | | |
| set -euo pipefail | |
| ARTIFACT_DIR="$RUNNER_TEMP/release-artifact" | |
| mkdir -p "$ARTIFACT_DIR/dist" "$ARTIFACT_DIR/snippets" | |
| cp dist/* "$ARTIFACT_DIR/dist/" | |
| cp artifacts/snippets/* "$ARTIFACT_DIR/snippets/" | |
| PACKAGE_VERSION="$(python scripts/package_version.py)" | |
| printf 'PACKAGE_VERSION=%s\n' "$PACKAGE_VERSION" > "$ARTIFACT_DIR/release.env" | |
| ( | |
| cd "$ARTIFACT_DIR" | |
| find dist snippets -type f -print0 \ | |
| | sort -z \ | |
| | xargs -0 sha256sum > artifact.sha256 | |
| sha256sum release.env >> artifact.sha256 | |
| ) | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: verified-pypi-package | |
| path: ${{ runner.temp }}/release-artifact/ | |
| if-no-files-found: error | |
| retention-days: 1 | |
| publish: | |
| name: Publish verified package to PyPI | |
| needs: verify | |
| if: github.event.release.prerelease == false | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| environment: pypi | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: verified-pypi-package | |
| path: ${{ runner.temp }}/release-artifact | |
| - name: Verify exact artifact checksums | |
| working-directory: ${{ runner.temp }}/release-artifact | |
| run: | | |
| set -euo pipefail | |
| manifest_files="$RUNNER_TEMP/manifest-files" | |
| actual_files="$RUNNER_TEMP/actual-files" | |
| sed -n 's/^[0-9a-f]\{64\} //p' artifact.sha256 \ | |
| | LC_ALL=C sort > "$manifest_files" | |
| { | |
| find dist snippets -type f -print | |
| printf '%s\n' release.env | |
| } | LC_ALL=C sort > "$actual_files" | |
| if [ -n "$(find dist snippets -type l -print -quit)" ]; then | |
| echo "::error::Verified release artifact contains a symlink" | |
| exit 1 | |
| fi | |
| if ! cmp -s "$manifest_files" "$actual_files"; then | |
| echo "::error::Checksum manifest does not cover the exact release files" | |
| exit 1 | |
| fi | |
| sha256sum -c artifact.sha256 | |
| - name: Publish exact verified distributions | |
| uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1 2026-07-28 | |
| with: | |
| packages-dir: ${{ runner.temp }}/release-artifact/dist/ | |
| skip-existing: true | |
| readback: | |
| name: Verify public PyPI artifact hashes | |
| needs: publish | |
| if: github.event.release.prerelease == false | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: verified-pypi-package | |
| path: ${{ runner.temp }}/release-artifact | |
| - name: Verify exact public PyPI hashes | |
| working-directory: ${{ runner.temp }}/release-artifact | |
| run: | | |
| set -euo pipefail | |
| sha256sum -c artifact.sha256 | |
| PACKAGE_VERSION="$(sed -n 's/^PACKAGE_VERSION=//p' release.env)" | |
| if ! printf '%s' "$PACKAGE_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "::error::Invalid package version in verified artifact" | |
| exit 1 | |
| fi | |
| for attempt in $(seq 1 24); do | |
| curl --fail --silent --show-error --max-time 10 \ | |
| "https://pypi.org/pypi/oilpriceapi/$PACKAGE_VERSION/json" \ | |
| > "$RUNNER_TEMP/pypi.json" || true | |
| all_present=true | |
| for file in dist/*; do | |
| filename="$(basename "$file")" | |
| expected="$(sha256sum "$file" | cut -d' ' -f1)" | |
| actual="$(jq -r --arg filename "$filename" \ | |
| '[.urls[]? | select(.filename == $filename) | .digests.sha256][0] // empty' \ | |
| "$RUNNER_TEMP/pypi.json" 2>/dev/null || true)" | |
| if [ -z "$actual" ]; then | |
| all_present=false | |
| elif [ "$actual" != "$expected" ]; then | |
| echo "::error::PyPI $filename has an unexpected immutable hash" | |
| exit 1 | |
| fi | |
| done | |
| if [ "$all_present" = true ]; then | |
| echo "Verified every public oilpriceapi $PACKAGE_VERSION distribution hash." | |
| exit 0 | |
| fi | |
| if [ "$attempt" -lt 6 ]; then | |
| sleep_seconds=$((attempt * 2)) | |
| else | |
| sleep_seconds=10 | |
| fi | |
| sleep "$sleep_seconds" | |
| done | |
| echo "::error::PyPI public readback did not expose every verified distribution" | |
| exit 1 | |
| release_assets: | |
| name: Attach verified release assets | |
| needs: readback | |
| if: github.event.release.prerelease == false | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: verified-pypi-package | |
| path: ${{ runner.temp }}/release-artifact | |
| - name: Attach checksummed snippet manifest | |
| working-directory: ${{ runner.temp }}/release-artifact | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| set -euo pipefail | |
| sha256sum -c artifact.sha256 | |
| gh release upload "$RELEASE_TAG" snippets/* artifact.sha256 --clobber |