Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 4 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ name: Release and Publish

on:
push:
branches: [ main ]
tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ]

permissions:
id-token: write
contents: write
contents: read

jobs:
build:
Expand All @@ -17,6 +16,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
with:
Expand All @@ -33,27 +34,10 @@ jobs:
name: dist
path: dist/
retention-days: 1
release:
name: Release to GitHub
runs-on: ubuntu-latest
needs: build
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Download artifact
uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- name: Publish to GitHub release page
uses: softprops/action-gh-release@v3
with:
files: |
./dist/*.whl
./dist/*.tar.gz
publish:
name: Publish to PyPI
runs-on: ubuntu-latest
needs: release
needs: build
environment: pypi
steps:
- name: Download artifact
Expand Down
45 changes: 45 additions & 0 deletions .github/workflows/semantic-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Semantic Release

on:
schedule:
# 2 AM on Sunday
- cron: "0 2 * * 0"
workflow_dispatch:

concurrency:
group: release
cancel-in-progress: false

jobs:
semantic-release:
if: github.repository == 'substrait-io/substrait-python'
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v3
id: app-token
with:
client-id: ${{ secrets.RELEASER_ID }}
private-key: ${{ secrets.RELEASER_KEY }}
- name: Checkout code
uses: actions/checkout@v6
with:
token: ${{ steps.app-token.outputs.token }}
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version: "24"
- name: Get bot user ID
id: bot-user-id
run: |
echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
- name: Run semantic-release
run: ./ci/release/run.sh
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
GIT_AUTHOR_NAME: "${{ steps.app-token.outputs.app-slug }}[bot]"
GIT_COMMITTER_NAME: "${{ steps.app-token.outputs.app-slug }}[bot]"
GIT_AUTHOR_EMAIL: "${{ steps.bot-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com"
GIT_COMMITTER_EMAIL: "${{ steps.bot-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com"
35 changes: 35 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"branches": ["main"],
"preset": "conventionalcommits",
"plugins": [
"@semantic-release/release-notes-generator",
[
"@semantic-release/commit-analyzer",
{
"releaseRules": [
{ "breaking": true, "release": "minor" }
]
}
],
[
"@semantic-release/changelog",
{
"changelogTitle": "Release Notes\n---",
"changelogFile": "CHANGELOG.md"
}
],
[
"@semantic-release/github",
{
"successComment": false
}
],
[
"@semantic-release/git",
{
"assets": ["CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version}"
}
]
]
}
51 changes: 43 additions & 8 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
# Releasing substrait-python

Given that you are a Substrait committer or PMC member and have the appropriate permissions, releasing a new version of substrait-python is done by simply creating new Github Release through the UI:
Releases of substrait-python are **fully automated** using
[semantic-release](https://semantic-release.gitbook.io/) and follow the same model
as the other Substrait projects (e.g. substrait-java).

1. Go to https://github.com/substrait-io/substrait-python/releases
2. Click `Draft a new release`
3. Enter the version to be released in the `Tag` field prefixed with a lower case `v`, e.g. `v0.99.0`. Then click `Create new tag` which tells Github to create the tag on publication of the release.
4. Click `Generate release notes` which will automatically populate the release title and release notes fields.
5. If you are happy with the release notes and you are ready for an immediate release simply click `Publish release` otherwise save the release as a draft for later.
6. Monitor the Github Actions release build for the newly created release and tag.
The [Semantic Release](.github/workflows/semantic-release.yml) workflow runs on a
weekly schedule (2 AM UTC on Sundays). It inspects the [Conventional
Commits](https://www.conventionalcommits.org/en/v1.0.0/) merged since the last
release, computes the next version, updates `CHANGELOG.md`, creates the `vX.Y.Z`
git tag, and publishes a GitHub Release with auto-generated notes.

Creating the tag triggers the [Release and Publish](.github/workflows/release.yml)
workflow, which builds the package (the version is derived from the tag via
`setuptools_scm`) and publishes it to [PyPI](https://pypi.org/project/substrait/)
using Trusted Publishing.

As a result, there is nothing to do by hand for a normal release — just make sure
your PR titles/commit messages follow the Conventional Commits specification (this
is enforced by the [PR Title Check](.github/workflows/pr_title.yml) workflow).

## Triggering an off-cycle release

If you need a release before the next scheduled run (and you are a Substrait
committer or PMC member with the appropriate permissions):

1. Go to https://github.com/substrait-io/substrait-python/actions/workflows/semantic-release.yml
2. Click `Run workflow` and select the `main` branch.
3. Monitor the workflow run, then the triggered `Release and Publish` run, to
confirm the new version reaches PyPI.

If there are no release-worthy commits since the last release (only `chore`, `docs`,
`ci`, etc.), semantic-release will report that no release is necessary and do
nothing.

## Versioning

substrait-python follows semantic versioning as described for the Substrait specification here: https://substrait.io/spec/versioning/.
Version bumps are derived from commit types:

| Commit type | Version bump |
| -------------------------------------------- | ------------ |
| `fix:` | patch |
| `feat:` | minor |
| breaking change (`feat!:`, `BREAKING CHANGE`)| minor |

substrait-python follows semantic versioning as described for the Substrait
specification here: https://substrait.io/spec/versioning/. Because the project is
pre-1.0, breaking changes produce a **minor** bump rather than a major one (matching
substrait-java).
14 changes: 14 additions & 0 deletions ci/release/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# shellcheck shell=bash

set -euo pipefail

npx --yes \
-p semantic-release \
-p "@semantic-release/commit-analyzer" \
-p "@semantic-release/release-notes-generator" \
-p "@semantic-release/changelog" \
-p "@semantic-release/github" \
-p "@semantic-release/git" \
-p "conventional-changelog-conventionalcommits" \
semantic-release --ci
Loading