Skip to content

Commit d750bcf

Browse files
ci: add CI validation, release automation, and Dependabot
- test-full.yml: PR validation with dry-run generation + zero-diff check - semantic-pr-title.yml: conventional commits title enforcement - release-drafter.yml: auto-draft releases on push to main - publish.yml: PyPI publish via OIDC on release published - pre-release-command.yml: pre-release to PyPI from PR or manual trigger - slash-command-dispatch.yml: add /pre-release command alongside /generate - dependabot.yml: weekly updates for Speakeasy CLI, GitHub Actions, Python deps Co-Authored-By: AJ Steers <aj@airbyte.io>
1 parent 7605f4c commit d750bcf

7 files changed

Lines changed: 531 additions & 0 deletions

File tree

.github/dependabot.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Dependabot configuration for airbyte-api-python-sdk.
2+
#
3+
# `.speakeasy/workflow.yaml` uses `speakeasyVersion: pinned`, so the actual CLI
4+
# version is pinned in `.github/speakeasy/dummy-compose.yml` and bumped by the
5+
# docker-compose ecosystem entry below.
6+
7+
version: 2
8+
updates:
9+
# Speakeasy CLI version pin (image: tag in .github/speakeasy/dummy-compose.yml).
10+
# See that file for the full explanation.
11+
- package-ecosystem: docker-compose
12+
directory: /.github/speakeasy
13+
schedule:
14+
interval: weekly
15+
day: monday
16+
open-pull-requests-limit: 5
17+
commit-message:
18+
prefix: ci(speakeasy)
19+
labels:
20+
- dependencies
21+
- speakeasy
22+
23+
# GitHub Actions used in .github/workflows/*.yml
24+
- package-ecosystem: github-actions
25+
directory: /
26+
schedule:
27+
interval: weekly
28+
day: monday
29+
open-pull-requests-limit: 5
30+
commit-message:
31+
prefix: ci
32+
labels:
33+
- dependencies
34+
- github-actions
35+
36+
# Python dependencies (uv / pyproject.toml)
37+
- package-ecosystem: pip
38+
directory: /
39+
schedule:
40+
interval: weekly
41+
day: monday
42+
open-pull-requests-limit: 5
43+
commit-message:
44+
prefix: chore
45+
labels:
46+
- dependencies
47+
- python
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Pre-Release Workflow
2+
#
3+
# Builds and publishes a pre-release version of the Python SDK to PyPI.
4+
# Pre-releases are installable via `pip install airbyte-api==1.0.0rc1` but
5+
# are NOT the default version, so existing users are unaffected.
6+
#
7+
# Triggers:
8+
# - Manual workflow_dispatch: From the Actions tab
9+
# - Slash command: `/pre-release version=1.0.0rc1` on a PR comment
10+
#
11+
# Inputs:
12+
#
13+
# version (REQUIRED): The pre-release version string.
14+
# Must contain a PEP 440 pre-release suffix: rcN, betaN, alphaN, devN.
15+
# Examples: 1.0.0rc1, 1.0.0a1, 1.0.0b1, 1.0.0.dev1
16+
#
17+
# ref (optional, default: main): The branch, tag, or commit SHA to build from.
18+
# When triggered via slash command on a PR, defaults to the PR's head branch.
19+
20+
name: Pre-Release
21+
22+
on:
23+
workflow_dispatch:
24+
inputs:
25+
version:
26+
description: >-
27+
Pre-release version (e.g. 1.0.0rc1, 1.0.0a1).
28+
Must contain a PEP 440 pre-release suffix.
29+
required: true
30+
type: string
31+
ref:
32+
description: 'Branch, tag, or commit SHA to build from'
33+
required: false
34+
default: 'main'
35+
type: string
36+
pr:
37+
description: 'PR number (for slash command triggers)'
38+
required: false
39+
type: string
40+
comment-id:
41+
description: 'Comment ID (for slash command triggers)'
42+
required: false
43+
type: string
44+
45+
concurrency:
46+
group: pre-release-${{ inputs.version }}
47+
cancel-in-progress: true
48+
49+
permissions:
50+
contents: read
51+
52+
jobs:
53+
pre_release:
54+
name: Build & Publish Pre-Release
55+
runs-on: ubuntu-latest
56+
environment:
57+
name: pypi
58+
url: https://pypi.org/project/airbyte-api/
59+
permissions:
60+
contents: write
61+
pull-requests: write
62+
id-token: write
63+
steps:
64+
# ── Slash command: post starting comment ────────────────────────
65+
- name: Authenticate as GitHub App
66+
if: ${{ inputs.pr != '' }}
67+
uses: actions/create-github-app-token@v3
68+
id: get-app-token
69+
with:
70+
app-id: ${{ secrets.OCTAVIA_BOT_APP_ID }}
71+
private-key: ${{ secrets.OCTAVIA_BOT_PRIVATE_KEY }}
72+
73+
- name: Post starting comment
74+
if: ${{ inputs.pr != '' }}
75+
id: start-comment
76+
uses: peter-evans/create-or-update-comment@v5
77+
with:
78+
token: ${{ steps.get-app-token.outputs.token }}
79+
issue-number: ${{ inputs.pr }}
80+
comment-id: ${{ inputs.comment-id || '' }}
81+
body: |
82+
> **Pre-Release Job Info**
83+
>
84+
> Building pre-release `${{ inputs.version }}` from ref `${{ inputs.ref || 'PR head branch' }}`.
85+
86+
> Job started... [Check job output.](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
87+
88+
# ── Resolve ref from PR if not explicitly provided ──────────────
89+
- name: Resolve PR head branch
90+
if: ${{ inputs.pr != '' && inputs.ref == 'main' }}
91+
id: resolve-ref
92+
env:
93+
GH_TOKEN: ${{ steps.get-app-token.outputs.token || secrets.GITHUB_TOKEN }}
94+
run: |
95+
PR_HEAD=$(gh pr view "${{ inputs.pr }}" --repo "${{ github.repository }}" --json headRefName -q '.headRefName')
96+
echo "ref=$PR_HEAD" >> "$GITHUB_OUTPUT"
97+
98+
# ── Validate version input ──────────────────────────────────────
99+
- name: Validate pre-release version
100+
run: |
101+
VERSION="${{ inputs.version }}"
102+
103+
# PEP 440 pre-release pattern: X.Y.Z(a|b|rc|dev)N
104+
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(a|b|rc|dev|\.dev|\.post)[0-9]+$'; then
105+
echo "::error::Invalid version or missing pre-release suffix. Expected PEP 440 format: X.Y.Z(a|b|rc|dev)N (e.g. 1.0.0rc1). Got: $VERSION"
106+
exit 1
107+
fi
108+
109+
echo "Pre-release version validated: $VERSION"
110+
111+
# ── Checkout ────────────────────────────────────────────────────
112+
- name: Checkout repository
113+
uses: actions/checkout@v4
114+
with:
115+
ref: ${{ steps.resolve-ref.outputs.ref || inputs.ref }}
116+
117+
- name: Install uv
118+
uses: astral-sh/setup-uv@v5
119+
120+
- name: Set up Python
121+
uses: actions/setup-python@v5
122+
with:
123+
python-version: '3.12'
124+
125+
# ── Set version and build ───────────────────────────────────────
126+
- name: Set pre-release version in pyproject.toml
127+
run: |
128+
VERSION="${{ inputs.version }}"
129+
# Use sed to update version in pyproject.toml
130+
sed -i "s/^version = \".*\"/version = \"${VERSION}\"/" pyproject.toml
131+
echo "Updated pyproject.toml version to: $VERSION"
132+
grep 'version' pyproject.toml | head -1
133+
134+
- name: Build package
135+
run: uv build
136+
137+
- name: Publish to PyPI
138+
uses: pypa/gh-action-pypi-publish@release/v1
139+
140+
# ── Tag the commit ──────────────────────────────────────────────
141+
- name: Create and push tag
142+
run: |
143+
VERSION="${{ inputs.version }}"
144+
git config user.name "github-actions[bot]"
145+
git config user.email "github-actions[bot]@users.noreply.github.com"
146+
git tag -a "v${VERSION}" -m "Pre-release v${VERSION}"
147+
git push origin "v${VERSION}"
148+
149+
# ── Slash command: post result comment ──────────────────────────
150+
- name: Post result comment
151+
if: ${{ always() && inputs.pr != '' }}
152+
uses: peter-evans/create-or-update-comment@v5
153+
with:
154+
token: ${{ steps.get-app-token.outputs.token || secrets.GITHUB_TOKEN }}
155+
issue-number: ${{ inputs.pr }}
156+
body: |
157+
> **Pre-Release Result:** ${{ job.status == 'success' && 'Published' || 'Failed' }}
158+
>
159+
> Version: `${{ inputs.version }}`
160+
> Ref: `${{ steps.resolve-ref.outputs.ref || inputs.ref }}`
161+
> [View run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
162+
${{ job.status == 'success' && format('> Install: `pip install airbyte-api=={0}`', inputs.version) || '' }}

.github/workflows/publish.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# PyPI Publish Workflow
2+
#
3+
# Triggered when a GitHub Release is published (draft → published).
4+
# Builds the Python package and uploads it to PyPI using OIDC trusted publishing.
5+
#
6+
# Prerequisites:
7+
# - PyPI trusted publisher configured for this repository:
8+
# https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/
9+
# Owner: airbytehq
10+
# Repository: airbyte-api-python-sdk
11+
# Workflow: publish.yml
12+
# Environment: pypi
13+
14+
name: Publish to PyPI
15+
16+
on:
17+
release:
18+
types: [published]
19+
20+
permissions:
21+
contents: read
22+
23+
jobs:
24+
publish:
25+
name: Build & Publish to PyPI
26+
runs-on: ubuntu-latest
27+
environment:
28+
name: pypi
29+
url: https://pypi.org/project/airbyte-api/
30+
permissions:
31+
id-token: write
32+
steps:
33+
- name: Checkout repository
34+
uses: actions/checkout@v4
35+
with:
36+
ref: ${{ github.event.release.tag_name }}
37+
38+
- name: Install uv
39+
uses: astral-sh/setup-uv@v5
40+
41+
- name: Set up Python
42+
uses: actions/setup-python@v5
43+
with:
44+
python-version: '3.12'
45+
46+
- name: Build package
47+
run: uv build
48+
49+
- name: Publish to PyPI
50+
uses: pypa/gh-action-pypi-publish@release/v1
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Release Drafter Workflow
2+
#
3+
# This workflow automatically creates and updates draft releases based on merged PRs.
4+
# It uses semantic PR titles (conventional commits format) to categorize changes.
5+
#
6+
# How it works:
7+
# - On push to main: Updates the draft release with the merged PR
8+
# - Categories are determined by conventional commit type (feat, fix, chore, etc.)
9+
#
10+
# To publish a release:
11+
# 1. Go to the Releases page
12+
# 2. Find the draft release
13+
# 3. Edit the version number if needed
14+
# 4. Click "Publish release" - this creates the git tag and triggers the Publish workflow
15+
16+
name: Release Drafter
17+
18+
on:
19+
workflow_dispatch: {}
20+
push:
21+
branches:
22+
- main
23+
24+
concurrency:
25+
group: release-drafter
26+
cancel-in-progress: true
27+
28+
permissions:
29+
contents: read
30+
31+
jobs:
32+
draft_release:
33+
name: Draft Release
34+
permissions:
35+
contents: write
36+
pull-requests: write
37+
runs-on: ubuntu-latest
38+
steps:
39+
- name: Create draft release
40+
uses: aaronsteers/semantic-pr-release-drafter@v1.1.0
41+
id: release-drafter
42+
with:
43+
name-template: 'v$RESOLVED_VERSION'
44+
tag-template: 'v$RESOLVED_VERSION'
45+
change-template: '- $TITLE (#$NUMBER)'
46+
template: |
47+
## Changes
48+
49+
$CHANGES
50+
51+
## Installation
52+
53+
```bash
54+
pip install airbyte-api==$RESOLVED_VERSION
55+
```
56+
env:
57+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Semantic PR Title Validation
2+
#
3+
# This workflow validates that PR titles follow the Conventional Commits format.
4+
# This is required for the semantic-pr-release-drafter to correctly categorize changes.
5+
#
6+
# Valid formats:
7+
# - feat: Add new feature
8+
# - fix: Fix a bug
9+
# - chore: Maintenance task
10+
# - docs: Documentation changes
11+
# - ci: CI/CD changes
12+
# - refactor: Code refactoring
13+
# - test: Test changes
14+
# - perf: Performance improvements
15+
# - feat!: Breaking change (major version bump)
16+
#
17+
# Optional scope: feat(api): Add new endpoint
18+
19+
name: Validate PR Title
20+
21+
on:
22+
pull_request:
23+
types: [opened, edited, synchronize]
24+
25+
permissions:
26+
pull-requests: read
27+
statuses: write
28+
29+
jobs:
30+
validate:
31+
name: Validate Semantic PR Title
32+
runs-on: ubuntu-latest
33+
steps:
34+
- uses: amannn/action-semantic-pull-request@v6
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37+
with:
38+
types: |
39+
feat
40+
fix
41+
chore
42+
docs
43+
ci
44+
refactor
45+
test
46+
perf
47+
build
48+
revert
49+
requireScope: false
50+
scopes: ""
51+
wip: true
52+
validateSingleCommit: false

.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
issue-type: pull-request
3535
commands: |
3636
generate
37+
pre-release
3738
static-args: |
3839
pr=${{ github.event.issue.number }}
3940
comment-id=${{ github.event.comment.id }}

0 commit comments

Comments
 (0)