Skip to content

Commit 48a13a3

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 ed7436f commit 48a13a3

7 files changed

Lines changed: 458 additions & 36 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

.github/workflows/pre-release-command.yml

Lines changed: 135 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
1-
# Stub: Pre-Release Workflow
1+
# Pre-Release Workflow
22
#
3-
# Minimal placeholder to register the workflow_dispatch trigger on main.
4-
# Full implementation arrives in a follow-up PR.
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.
519

620
name: Pre-Release
721

822
on:
923
workflow_dispatch:
1024
inputs:
1125
version:
12-
description: 'Pre-release version (e.g. 1.0.0rc1)'
26+
description: >-
27+
Pre-release version (e.g. 1.0.0rc1, 1.0.0a1).
28+
Must contain a PEP 440 pre-release suffix.
1329
required: true
1430
type: string
1531
ref:
@@ -26,10 +42,121 @@ on:
2642
required: false
2743
type: string
2844

45+
concurrency:
46+
group: pre-release-${{ inputs.version }}
47+
cancel-in-progress: true
48+
49+
permissions:
50+
contents: read
51+
2952
jobs:
30-
stub:
31-
name: Stub (placeholder)
32-
if: false
53+
pre_release:
54+
name: Build & Publish Pre-Release
3355
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
3463
steps:
35-
- run: echo "stub"
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: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,50 @@
1-
# Stub: Publish to PyPI Workflow
1+
# PyPI Publish Workflow
22
#
3-
# Minimal placeholder to register the release trigger on main.
4-
# Full implementation arrives in a follow-up PR.
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
513

614
name: Publish to PyPI
715

816
on:
917
release:
1018
types: [published]
1119

20+
permissions:
21+
contents: read
22+
1223
jobs:
13-
stub:
14-
name: Stub (placeholder)
15-
if: false
24+
publish:
25+
name: Build & Publish to PyPI
1626
runs-on: ubuntu-latest
27+
environment:
28+
name: pypi
29+
url: https://pypi.org/project/airbyte-api/
30+
permissions:
31+
id-token: write
1732
steps:
18-
- run: echo "stub"
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: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
# Stub: Release Drafter Workflow
1+
# Release Drafter Workflow
22
#
3-
# Minimal placeholder to register the workflow_dispatch trigger on main.
4-
# Full implementation arrives in a follow-up PR.
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
515

616
name: Release Drafter
717

@@ -11,10 +21,37 @@ on:
1121
branches:
1222
- main
1323

24+
concurrency:
25+
group: release-drafter
26+
cancel-in-progress: true
27+
28+
permissions:
29+
contents: read
30+
1431
jobs:
15-
stub:
16-
name: Stub (placeholder)
17-
if: false
32+
draft_release:
33+
name: Draft Release
34+
permissions:
35+
contents: write
36+
pull-requests: write
1837
runs-on: ubuntu-latest
1938
steps:
20-
- run: echo "stub"
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: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,52 @@
1-
# Stub: Validate PR Title Workflow
1+
# Semantic PR Title Validation
22
#
3-
# Minimal placeholder to register the pull_request trigger on main.
4-
# Full implementation arrives in a follow-up PR.
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
518

619
name: Validate PR Title
720

821
on:
922
pull_request:
1023
types: [opened, edited, synchronize]
1124

25+
permissions:
26+
pull-requests: read
27+
statuses: write
28+
1229
jobs:
13-
stub:
14-
name: Stub (placeholder)
15-
if: false
30+
validate:
31+
name: Validate Semantic PR Title
1632
runs-on: ubuntu-latest
1733
steps:
18-
- run: echo "stub"
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)