Skip to content

Commit 8d2c7e2

Browse files
fix: in-place zero-diff check, uv run for poe tasks, align semantic PR title with other repos
Co-Authored-By: AJ Steers <aj@airbyte.io>
1 parent 5b99701 commit 8d2c7e2

5 files changed

Lines changed: 71 additions & 172 deletions

File tree

.github/workflows/generate-command.yml

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -169,26 +169,6 @@ jobs:
169169
echo "Generating with version: $VERSION"
170170
uv run poe generate-full
171171
172-
- name: Verify generated code
173-
run: |
174-
if [ -f "pyproject.toml" ]; then
175-
echo "pyproject.toml found (v2 generator confirmed)"
176-
uv run python -c "import airbyte_api; print(f'SDK import OK: {airbyte_api.__name__}')" || echo "::warning::SDK import check failed"
177-
else
178-
echo "::warning::No pyproject.toml found. Generation may not have produced v2 output."
179-
fi
180-
181-
- name: Upload generated SDK as artifact
182-
if: ${{ inputs.dry_run }}
183-
uses: actions/upload-artifact@v7
184-
with:
185-
name: generated_sdk_code
186-
path: |
187-
src/
188-
pyproject.toml
189-
py.typed
190-
retention-days: 7
191-
192172
- name: Generation Summary
193173
run: |
194174
echo "=== Generation Summary ==="
@@ -199,18 +179,54 @@ jobs:
199179
fi
200180
201181
- name: Check for changes
202-
if: ${{ !inputs.dry_run }}
203182
id: changes
204183
run: |
205184
# Restore workflow.lock to HEAD to ignore non-deterministic
206185
# digest changes that cause infinite generate→merge loops.
207186
git checkout HEAD -- .speakeasy/workflow.lock 2>/dev/null || true
208187
if [ -n "$(git status --porcelain)" ]; then
209188
echo "has_changes=true" >> $GITHUB_OUTPUT
189+
echo "=== Changed files ==="
190+
git status --porcelain
191+
echo
192+
echo "=== Diff stat ==="
193+
git diff --stat
210194
else
211195
echo "has_changes=false" >> $GITHUB_OUTPUT
212196
fi
213197
198+
- name: Detect generation drift (dry run)
199+
if: ${{ inputs.dry_run && steps.changes.outputs.has_changes == 'true' }}
200+
id: drift
201+
run: |
202+
echo "::error::Generated code drift detected. The committed code does not match what the generation pipeline produces."
203+
SUMMARY=$(git diff --stat)
204+
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
205+
echo "summary<<$EOF" >> $GITHUB_OUTPUT
206+
echo "$SUMMARY" >> $GITHUB_OUTPUT
207+
echo "$EOF" >> $GITHUB_OUTPUT
208+
209+
- name: Post drift comment on PR
210+
if: ${{ inputs.dry_run && steps.changes.outputs.has_changes == 'true' && github.event_name == 'pull_request' }}
211+
uses: peter-evans/create-or-update-comment@v5
212+
with:
213+
issue-number: ${{ github.event.pull_request.number }}
214+
body: |
215+
<!-- zero-diff-check -->
216+
**Generated Code Drift Detected**
217+
218+
The committed code does not match what the generation pipeline produces.
219+
220+
**To fix:** Comment `/generate` on this PR to regenerate.
221+
222+
```
223+
${{ steps.drift.outputs.summary }}
224+
```
225+
226+
- name: Fail on drift (dry run)
227+
if: ${{ inputs.dry_run && steps.changes.outputs.has_changes == 'true' }}
228+
run: exit 1
229+
214230
# --- PR branch mode: commit and push to the existing PR branch ---
215231
- name: Push regenerated code to PR branch
216232
if: ${{ !inputs.dry_run && github.event.inputs.pr != '' && steps.changes.outputs.has_changes == 'true' }}
Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,32 @@
11
# Semantic PR Title Validation
22
#
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
3+
# This workflow validates PR titles follow conventional commit format.
184

19-
name: Validate PR Title
5+
name: Semantic PR Title Validation
206

217
on:
228
pull_request:
23-
types: [opened, edited, synchronize]
9+
types: [opened, edited, ready_for_review, synchronize]
2410

2511
permissions:
26-
pull-requests: read
27-
statuses: write
12+
contents: read
13+
pull-requests: write
2814

2915
jobs:
30-
validate:
31-
name: Validate Semantic PR Title
16+
validate-pr-title:
17+
name: Validate PR Title
18+
# Skip if 'edited' event but the title wasn't changed (e.g., only description was edited)
19+
if: >
20+
github.event.action != 'edited'
21+
|| (
22+
github.event.changes.title &&
23+
github.event.changes.title.from != ''
24+
)
3225
runs-on: ubuntu-latest
3326
steps:
34-
- name: Validate Semantic PR Title
27+
- name: Check semantic PR title
3528
uses: amannn/action-semantic-pull-request@v6
29+
if: ${{ github.event.pull_request.draft == false }}
3630
env:
3731
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3832
with:
@@ -47,7 +41,14 @@ jobs:
4741
perf
4842
build
4943
revert
50-
requireScope: false
51-
scopes: ""
52-
wip: true
53-
validateSingleCommit: false
44+
style
45+
46+
- name: Check for "do not merge" in PR title
47+
if: ${{ github.event.pull_request.draft == false }}
48+
uses: actions/github-script@v8
49+
with:
50+
script: |
51+
const title = context.payload.pull_request.title.toLowerCase();
52+
if (title.includes('do not merge') || title.includes('do-not-merge')) {
53+
core.setFailed('PR title contains "do not merge" or "do-not-merge". Please remove this before merging.');
54+
}

.github/workflows/test-full.yml

Lines changed: 3 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@
33
# This workflow validates that Speakeasy generation can complete successfully
44
# and that the committed generated code matches what the generation pipeline produces.
55
#
6-
# Jobs:
7-
# 1. validate: Runs the full generation pipeline in dry-run mode
8-
# 2. zero-diff: Compares the dry-run artifacts against the committed code to detect drift.
9-
# If drift is detected, the check fails and posts a comment telling the author to run /generate.
10-
#
11-
# This workflow calls the main generation workflow with dry_run=true to ensure
12-
# both workflows use the same generation logic.
6+
# It calls the main generation workflow with dry_run=true. After generation,
7+
# the workflow checks `git status` in-place — if any tracked files changed,
8+
# drift is detected and the check fails with a PR comment.
139
#
1410
# Note: paths-ignore is NOT used at the workflow level because GitHub treats a
1511
# workflow that never runs as "expected" (pending), which blocks required checks.
@@ -25,7 +21,6 @@ on:
2521
permissions:
2622
contents: write
2723
pull-requests: write
28-
actions: read
2924

3025
jobs:
3126
check-paths:
@@ -54,116 +49,3 @@ jobs:
5449
with:
5550
dry_run: true
5651
secrets: inherit
57-
58-
zero-diff:
59-
name: Zero-Diff Check (Generated Code)
60-
needs: [check-paths, validate]
61-
if: needs.check-paths.outputs.should_run == 'true' && github.event_name == 'pull_request'
62-
runs-on: ubuntu-latest
63-
permissions:
64-
contents: read
65-
pull-requests: write
66-
steps:
67-
- name: Checkout PR branch
68-
uses: actions/checkout@v4
69-
70-
- name: Download generated SDK artifact
71-
uses: actions/download-artifact@v8
72-
with:
73-
name: generated_sdk_code
74-
path: /tmp/generated/
75-
76-
- name: Compare generated code against committed code
77-
id: diff-check
78-
run: |
79-
DIFF_SUMMARY=""
80-
81-
echo "=== Comparing generated SDK code ==="
82-
# Compare src/ directory
83-
if [ -d "src/" ] && [ -d "/tmp/generated/src/" ]; then
84-
while IFS= read -r line; do
85-
# Extract relative path from diff output
86-
FILE=$(echo "$line" | sed 's|^Files ||; s| and /tmp/generated/.*||')
87-
ADDED=$(diff -u "$FILE" "/tmp/generated/$FILE" 2>/dev/null | tail -n +3 | grep -c '^+' || echo "0")
88-
REMOVED=$(diff -u "$FILE" "/tmp/generated/$FILE" 2>/dev/null | tail -n +3 | grep -c '^-' || echo "0")
89-
DIFF_SUMMARY="${DIFF_SUMMARY}${FILE} (+${ADDED}/-${REMOVED})"$'\n'
90-
done < <(diff -rq src/ /tmp/generated/src/ 2>&1 | grep "^Files" || true)
91-
92-
# Check for files only in one side
93-
ONLY_LINES=$(diff -rq src/ /tmp/generated/src/ 2>&1 | grep "^Only" || true)
94-
if [ -n "$ONLY_LINES" ]; then
95-
while IFS= read -r line; do
96-
DIR=$(echo "$line" | sed 's|^Only in /tmp/generated/||; s|^Only in ||; s|: |/|')
97-
if echo "$line" | grep -q "^Only in /tmp/generated/"; then
98-
DIFF_SUMMARY="${DIFF_SUMMARY}${DIR} (new file)"$'\n'
99-
else
100-
DIFF_SUMMARY="${DIFF_SUMMARY}${DIR} (deleted)"$'\n'
101-
fi
102-
done <<< "$ONLY_LINES"
103-
fi
104-
elif [ -d "/tmp/generated/src/" ]; then
105-
DIFF_SUMMARY="src/ directory missing in committed code but present in generated output"$'\n'
106-
fi
107-
108-
# Compare pyproject.toml
109-
if [ -f "/tmp/generated/pyproject.toml" ]; then
110-
TOML_DIFF=$(diff -q pyproject.toml /tmp/generated/pyproject.toml 2>&1 || true)
111-
if [ -n "$TOML_DIFF" ]; then
112-
ADDED=$(diff -u pyproject.toml /tmp/generated/pyproject.toml 2>/dev/null | tail -n +3 | grep -c '^+' || echo "0")
113-
REMOVED=$(diff -u pyproject.toml /tmp/generated/pyproject.toml 2>/dev/null | tail -n +3 | grep -c '^-' || echo "0")
114-
DIFF_SUMMARY="${DIFF_SUMMARY}pyproject.toml (+${ADDED}/-${REMOVED})"$'\n'
115-
fi
116-
fi
117-
118-
if [ -n "$DIFF_SUMMARY" ]; then
119-
echo "has_diff=true" >> $GITHUB_OUTPUT
120-
echo "::warning::Generated code drift detected. The committed code does not match what the generation pipeline produces."
121-
echo "$DIFF_SUMMARY"
122-
echo "$DIFF_SUMMARY" > /tmp/diff_summary.txt
123-
else
124-
echo "has_diff=false" >> $GITHUB_OUTPUT
125-
echo "Zero-diff check passed. Committed code matches generation output."
126-
fi
127-
128-
- name: Prepare diff summary
129-
if: steps.diff-check.outputs.has_diff == 'true'
130-
id: diff-summary
131-
run: |
132-
SUMMARY=$(cat /tmp/diff_summary.txt 2>/dev/null || echo "(see job logs for full details)")
133-
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
134-
echo "content<<$EOF" >> $GITHUB_OUTPUT
135-
echo "$SUMMARY" >> $GITHUB_OUTPUT
136-
echo "$EOF" >> $GITHUB_OUTPUT
137-
138-
- name: Find existing drift comment
139-
if: steps.diff-check.outputs.has_diff == 'true'
140-
uses: peter-evans/find-comment@v3
141-
id: find-drift-comment
142-
with:
143-
issue-number: ${{ github.event.pull_request.number }}
144-
body-includes: '<!-- zero-diff-check -->'
145-
146-
- name: Post drift comment on PR
147-
if: steps.diff-check.outputs.has_diff == 'true'
148-
uses: peter-evans/create-or-update-comment@v5
149-
with:
150-
issue-number: ${{ github.event.pull_request.number }}
151-
comment-id: ${{ steps.find-drift-comment.outputs.comment-id || '' }}
152-
edit-mode: replace
153-
body: |
154-
<!-- zero-diff-check -->
155-
**Generated Code Drift Detected**
156-
157-
The committed code does not match what the generation pipeline produces.
158-
159-
**To fix:** Comment `/generate` on this PR to regenerate.
160-
161-
```
162-
${{ steps.diff-summary.outputs.content }}
163-
```
164-
165-
- name: Fail if drift detected
166-
if: steps.diff-check.outputs.has_diff == 'true'
167-
run: |
168-
echo "::error::Generated code drift detected. Run /generate on this PR to fix."
169-
exit 1

poe_tasks.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ speakeasy run $ARGS
1313
[tasks._post-generate]
1414
help = "Run post-generation patches."
1515
shell = """
16-
python3 scripts/post_generate.py
16+
uv run python scripts/post_generate.py
1717
"""
1818

1919
[tasks._generate-readme]
2020
help = "Generate README-PYPI.md from README.md (rewrites relative links to absolute GitHub URLs)."
2121
shell = """
22-
python3 scripts/prepare_readme.py
22+
uv run python scripts/prepare_readme.py
2323
"""
2424

2525
[tasks.lint]
@@ -55,5 +55,5 @@ uv build
5555
"""
5656

5757
[tasks.generate-full]
58-
help = "Full generation pipeline: generate code, post-generate patches, prepare readme."
58+
help = "Full generation pipeline: generate code, prepare readme, post-generate patches."
5959
sequence = ["_generate-code", "_generate-readme", "_post-generate"]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ source = "src/airbyte_api/_version.py"
3636
pattern = "__version__: str = \"(?P<version>[^\"]+)\""
3737

3838
[tool.hatch.build.targets.sdist]
39-
include = ["src/airbyte_api", "py.typed"]
39+
include = ["src/airbyte_api", "py.typed", "README-PYPI.md"]
4040

4141
[tool.hatch.build.targets.wheel]
4242
packages = ["src/airbyte_api"]

0 commit comments

Comments
 (0)