diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..86f7bd3 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,115 @@ +name: CD + +on: + workflow_dispatch: + inputs: + version: + description: "Version to build Zig wheels for" + required: true + default: "latest" + suffix: + description: > + Suffix to append to the version in the wheel filename. This is useful for dev versions and version specifiers + required: false + default: "" + platforms: + description: > + Comma-separated values of platforms to build wheels for + required: false + default: "x86_64-windows,x86-windows,x86_64-macos,aarch64-macos,i386-linux,x86-linux,x86_64-linux,aarch64-linux,armv7a-linux,powerpc64le-linux" + push_to_pypi: + description: > + Whether to push the built wheels to PyPI. Can be 'true' or 'false', defaults to 'false'. + required: true + default: "false" + +jobs: + build_wheels: + name: Build wheels + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: "3.x" + + - name: Install dependencies + run: | + python -m pip install . + + - name: Build wheels for all requested platforms + shell: bash + run: | + platforms=${{ github.event.inputs.platforms }} + IFS=',' read -r -a platform_array <<< "$platforms" + for platform in "${platform_array[@]}"; do + python make_wheels.py \ + --outdir dist/ \ + --version ${{ github.event.inputs.version }} \ + --suffix ${{ github.event.inputs.suffix }} \ + --platform "$platform" + done + + - name: Upload wheel artifacts + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: zig_wheels + path: dist/*.whl + if-no-files-found: error + + deploy_wheels: + name: Deploy wheels + needs: [build_wheels] + if: >- + github.event.inputs.push_to_pypi == 'true' && + github.repository == 'ziglang/zig-pypi' + environment: pypi + runs-on: ubuntu-latest + permissions: + id-token: write # for OIDC trusted publishing + attestations: write # for the GitHub Actions Attestations feature + contents: read + steps: + - name: Download all wheel artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + path: dist/ + merge-multiple: true + + - name: Sanity check wheel artifacts + run: ls -R dist/ + + - name: Generate artifact attestations + uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + with: + subject-path: dist/* + + # This will publish the list of wheels inputted to the action to PyPI (set to + # off, by default). + # The workflow may be triggered multiple times with the `push_to_pypi` input + # set to 'true' to publish the wheels for any configurable version (non-dev). + - name: Publish wheels to PyPI + uses: pypa/gh-action-pypi-publish@81e9d935c883d0b210363ab89cf05f3894778450 # v1.10.2 + with: + packages-dir: dist/ + + inspect_wheels: + name: Inspect wheels + needs: [build_wheels] + runs-on: ubuntu-latest + steps: + - name: Download all built wheel artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + path: dist/ + merge-multiple: true + + - name: Inspect wheel artifacts + shell: bash + run: | + echo -e '## A list of built wheels and their SHA-256 checksums \n' >> $GITHUB_STEP_SUMMARY + echo -e '```\n' >> $GITHUB_STEP_SUMMARY + for wheel in dist/*.whl; do + shasum --algorithm 256 "$wheel" >> $GITHUB_STEP_SUMMARY + done + echo -e '```\n' >> $GITHUB_STEP_SUMMARY diff --git a/README.md b/README.md index 2eb1627..7437a3c 100644 --- a/README.md +++ b/README.md @@ -49,16 +49,27 @@ The process of converting release archives to binary wheels is deterministic, an [pypidl]: https://pypi.org/project/ziglang/#files -Uploading wheels ----------------- +Uploading wheels to PyPI +------------------------ -Run the publishing utility: +Trigger the publishing workflow from this repository manually (requires authorization) +with the necessary inputs as mentioned in the [workflow file](.github/workflows/cd.yml) +or in the GitHub Actions UI. The wheels are checked with `twine` before they are uploaded. -```shell -pdm run twine dist/* -``` +The workflow will upload the wheels to PyPI to make them available for installation. It +is possible to trigger it multiple times to upload wheels for different versions or +platforms. + +Verifying the provenance of wheels uploaded to PyPI +--------------------------------------------------- + +To establish build provenance, the workflow generates attestations for the uploaded wheels +using the [GitHub Actions Attestations feature](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds) +when it is run. Please navigate to the [Attestations interface](https://github.com/ziglang/zig-pypi/attestations) +to view the attestations for the uploaded wheels. -This command will upload the binary wheels built in the previous step to PyPI. +The attestations may be verified via the [GitHub (`gh`) CLI](https://cli.github.com/manual/gh_attestation_verify) +or via the [GitHub API](https://docs.github.com/en/rest/users/attestations). License ------- diff --git a/pyproject.toml b/pyproject.toml index b4abd8c..55f3d7a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,8 @@ dependencies = [ "wheel~=0.41.0", ] +# To verify wheels locally instead of through +# the .github/workflows/cd.yml workflow [tool.pdm.dev-dependencies] upload = ["twine"]