Skip to content

Commit 60a087f

Browse files
feat: Add /prerelease slash command for PyPI prereleases (#910)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent f882e93 commit 60a087f

File tree

5 files changed

+154
-2
lines changed

5 files changed

+154
-2
lines changed

.github/pr-welcome-community.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ As needed or by request, Airbyte Maintainers can execute the following slash com
2727
- `/fix-pr` - Fixes most formatting and linting issues
2828
- `/poetry-lock` - Updates poetry.lock file
2929
- `/test-pr` - Runs tests with the updated PyAirbyte
30+
- `/prerelease` - Builds and publishes a prerelease version to PyPI
3031

3132
### Community Support
3233

.github/pr-welcome-internal.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Airbyte Maintainers can execute the following slash commands on your PR:
2626
- `/fix-pr` - Fixes most formatting and linting issues
2727
- `/poetry-lock` - Updates poetry.lock file
2828
- `/test-pr` - Runs tests with the updated PyAirbyte
29+
- `/prerelease` - Builds and publishes a prerelease version to PyPI
2930

3031
### Community Support
3132

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: On-Demand Prerelease
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
pr:
7+
description: 'PR Number'
8+
type: string
9+
required: true
10+
comment-id:
11+
description: 'Comment ID (Optional)'
12+
type: string
13+
required: false
14+
15+
env:
16+
AIRBYTE_ANALYTICS_ID: ${{ vars.AIRBYTE_ANALYTICS_ID }}
17+
18+
permissions:
19+
contents: read
20+
pull-requests: write
21+
issues: write
22+
23+
jobs:
24+
resolve-pr:
25+
name: Set up Workflow
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Resolve workflow variables
29+
id: vars
30+
uses: aaronsteers/resolve-ci-vars-action@2e56afab0344bbe03c047dfa39bae559d0291472 # v0.1.6
31+
32+
- name: Append comment with job run link
33+
id: first-comment-action
34+
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
35+
with:
36+
comment-id: ${{ github.event.inputs.comment-id }}
37+
issue-number: ${{ github.event.inputs.pr }}
38+
body: |
39+
> **Prerelease Build Started**
40+
>
41+
> Building and publishing prerelease package from this PR...
42+
> [Check job output.](${{ steps.vars.outputs.run-url }})
43+
44+
- name: Checkout to get latest tag
45+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
46+
with:
47+
fetch-depth: 0
48+
49+
- name: Compute prerelease version
50+
id: version
51+
run: |
52+
# Get the latest tag version (strip 'v' prefix if present)
53+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
54+
BASE_VERSION=${LATEST_TAG#v}
55+
# Create a unique prerelease version using PR number and run ID
56+
# Format: {base}.dev{pr_number}{run_id} (e.g., 0.34.0.dev825123456789)
57+
PRERELEASE_VERSION="${BASE_VERSION}.dev${{ github.event.inputs.pr }}${{ github.run_id }}"
58+
echo "version=$PRERELEASE_VERSION" >> $GITHUB_OUTPUT
59+
echo "Computed prerelease version: $PRERELEASE_VERSION"
60+
outputs:
61+
source-repo: ${{ steps.vars.outputs.pr-source-repo-name-full }}
62+
source-branch: ${{ steps.vars.outputs.pr-source-git-branch }}
63+
commit-sha: ${{ steps.vars.outputs.pr-source-git-sha }}
64+
pr-number: ${{ steps.vars.outputs.pr-number }}
65+
job-run-url: ${{ steps.vars.outputs.run-url }}
66+
first-comment-id: ${{ steps.first-comment-action.outputs.comment-id }}
67+
prerelease-version: ${{ steps.version.outputs.version }}
68+
69+
build-and-publish:
70+
name: Call Publish Workflow
71+
needs: [resolve-pr]
72+
uses: ./.github/workflows/pypi_publish.yml
73+
with:
74+
# Use refs/pull/<PR>/head instead of raw SHA for fork compatibility
75+
git_ref: refs/pull/${{ github.event.inputs.pr }}/head
76+
version_override: ${{ needs.resolve-pr.outputs.prerelease-version }}
77+
publish: true
78+
79+
post-result-comment:
80+
name: Write Status to PR
81+
needs: [resolve-pr, build-and-publish]
82+
if: always()
83+
runs-on: ubuntu-latest
84+
steps:
85+
- name: Post success comment
86+
if: needs.build-and-publish.result == 'success'
87+
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
88+
with:
89+
comment-id: ${{ needs.resolve-pr.outputs.first-comment-id }}
90+
issue-number: ${{ github.event.inputs.pr }}
91+
reactions: rocket
92+
body: |
93+
> **Prerelease Published to PyPI**
94+
>
95+
> Version: `${{ needs.resolve-pr.outputs.prerelease-version }}`
96+
>
97+
> Install with:
98+
> ```bash
99+
> pip install airbyte==${{ needs.resolve-pr.outputs.prerelease-version }}
100+
> ```
101+
- name: Post failure comment
102+
if: needs.build-and-publish.result == 'failure'
103+
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
104+
with:
105+
comment-id: ${{ needs.resolve-pr.outputs.first-comment-id }}
106+
issue-number: ${{ github.event.inputs.pr }}
107+
reactions: confused
108+
body: |
109+
> **Prerelease Build/Publish Failed**
110+
>
111+
> The prerelease encountered an error.
112+
> [Check job output](${{ needs.resolve-pr.outputs.job-run-url }}) for details.
113+
>
114+
> You can still install directly from this PR branch:
115+
> ```bash
116+
> pip install 'git+https://github.com/${{ needs.resolve-pr.outputs.source-repo }}.git@${{ needs.resolve-pr.outputs.source-branch }}'
117+
> ```

.github/workflows/pypi_publish.yml

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ on:
55

66
workflow_dispatch:
77

8+
workflow_call:
9+
inputs:
10+
git_ref:
11+
description: 'Git ref (SHA or branch) to checkout and build'
12+
required: true
13+
type: string
14+
version_override:
15+
description: 'Version to use (overrides dynamic versioning)'
16+
required: false
17+
type: string
18+
publish:
19+
description: 'Whether to publish to PyPI'
20+
required: false
21+
type: boolean
22+
default: false
23+
824
env:
925
AIRBYTE_ANALYTICS_ID: ${{ vars.AIRBYTE_ANALYTICS_ID }}
1026

@@ -14,8 +30,21 @@ jobs:
1430
steps:
1531
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
1632
with:
33+
ref: ${{ inputs.git_ref || github.ref }}
1734
fetch-depth: 0
18-
- uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0
35+
- name: Prepare version override
36+
id: version
37+
run: |
38+
echo "override=${{ inputs.version_override }}" >> $GITHUB_OUTPUT
39+
echo "has_override=${{ inputs.version_override != '' }}" >> $GITHUB_OUTPUT
40+
- name: Build package (with version override)
41+
if: steps.version.outputs.has_override == 'true'
42+
uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0
43+
env:
44+
POETRY_DYNAMIC_VERSIONING_BYPASS: ${{ steps.version.outputs.override }}
45+
- name: Build package (dynamic version)
46+
if: steps.version.outputs.has_override != 'true'
47+
uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0
1948

2049
publish:
2150
name: Publish to PyPI
@@ -27,13 +56,16 @@ jobs:
2756
environment:
2857
name: PyPi
2958
url: https://pypi.org/p/airbyte
30-
if: startsWith(github.ref, 'refs/tags/')
59+
# Publish when: (1) triggered by a tag push, OR (2) called with publish=true
60+
if: startsWith(github.ref, 'refs/tags/') || inputs.publish == true
3161
steps:
3262
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
3363
with:
3464
name: Packages
3565
path: dist
3666
- name: Upload wheel to release
67+
# Only upload to GitHub release when triggered by a tag
68+
if: startsWith(github.ref, 'refs/tags/')
3769
uses: svenstaro/upload-release-action@81c65b7cd4de9b2570615ce3aad67a41de5b1a13 # latest
3870
with:
3971
repo_token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/slash_command_dispatch.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
fix-pr
3535
test-pr
3636
poetry-lock
37+
prerelease
3738
static-args: |
3839
pr=${{ github.event.issue.number }}
3940
comment-id=${{ github.event.comment.id }}

0 commit comments

Comments
 (0)