Skip to content

Commit 2c4ff62

Browse files
committed
ci: comment on validate-pr-base failure, drop conventional-commit skip label, document workflow
Workflow changes: - validate-pr-base now posts (or updates) an explanatory PR comment when it fails, telling the contributor exactly how to resolve: either re-target the PR to `next` or add the `target-main` label. The comment is removed automatically when the check passes (re-target, label, or bot exemption). - validate-pr-title no longer honors the `skip-conventional-commit-check` label. Conventional Commits is enforced unconditionally so the release-please changelog stays consistent. Docs: - CONTRIBUTING.md gains (or updates) a "Contribution workflow" section covering the branch model and conventional commits, with the new CI enforcement notes and the `target-main` label escape hatch. - CLAUDE.md gains a short "Contribution workflow" section pointing to the same guidance for Claude Code sessions.
1 parent 3ed13c6 commit 2c4ff62

3 files changed

Lines changed: 98 additions & 8 deletions

File tree

.github/workflows/lint-pr.yaml

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ jobs:
1414
validate-pr-title:
1515
name: Validate PR title (Conventional Commits)
1616
runs-on: ubuntu-latest
17-
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-conventional-commit-check') }}
1817
steps:
1918
- name: Check Conventional Commits format
2019
env:
@@ -39,35 +38,82 @@ jobs:
3938
echo " feat: add new endpoint"
4039
echo " fix(client): handle empty response"
4140
echo " chore!: drop python 3.11 support"
42-
echo ""
43-
echo " Add the 'skip-conventional-commit-check' label to bypass this check."
4441
} >&2
4542
exit 1
4643
4744
validate-pr-base:
4845
name: Validate PR base branch
4946
runs-on: ubuntu-latest
50-
if: github.event.pull_request.base.ref == 'main'
5147
permissions:
52-
pull-requests: read
48+
pull-requests: write
5349
steps:
54-
- name: Check base branch
50+
- name: Validate base branch and manage PR comment
5551
env:
52+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53+
REPO: ${{ github.repository }}
54+
PR_NUMBER: ${{ github.event.pull_request.number }}
5655
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
56+
PR_BASE: ${{ github.event.pull_request.base.ref }}
5757
HAS_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'target-main') }}
5858
run: |
59-
# Exempt automated PRs (Stainless codegen, release-please, dependabot, etc.)
59+
MARKER='<!-- lint-pr-validate-base -->'
60+
61+
# Find any existing marker comment so we can update or delete it.
62+
existing_id=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" \
63+
--jq ".[] | select(.body | contains(\"$MARKER\")) | .id" | head -n1)
64+
65+
delete_comment() {
66+
if [ -n "$existing_id" ]; then
67+
gh api -X DELETE "repos/$REPO/issues/comments/$existing_id" >/dev/null 2>&1 || true
68+
fi
69+
}
70+
71+
# PR doesn't target main — nothing to enforce.
72+
if [ "$PR_BASE" != "main" ]; then
73+
delete_comment
74+
echo "PR base is '$PR_BASE'; check passes."
75+
exit 0
76+
fi
77+
78+
# Exempt automated PRs (Stainless codegen, release-please, dependabot, etc.).
6079
case "$PR_AUTHOR" in
6180
stainless-app|stainless-app\[bot\]|release-please\[bot\]|github-actions\[bot\]|dependabot\[bot\])
81+
delete_comment
6282
echo "PR is from automation ($PR_AUTHOR); allowing PR targeting main."
6383
exit 0
6484
;;
6585
esac
6686
87+
# Per-PR opt-out via label.
6788
if [ "$HAS_LABEL" = "true" ]; then
89+
delete_comment
6890
echo "Found 'target-main' label; allowing PR targeting main."
6991
exit 0
7092
fi
7193
72-
echo "::error title=PR should target 'next'::PRs should target the 'next' branch by default. The 'main' branch is reserved for release-please and Stainless automation. If this PR is an intentional hotfix or automation exception, add the 'target-main' label to bypass this check, or re-target the PR base to 'next'."
94+
# Failure: post or update an explanatory PR comment, then fail the check.
95+
body_file=$(mktemp)
96+
{
97+
echo "$MARKER"
98+
echo
99+
echo "**This PR is targeting \`main\`, but PRs should target the \`next\` branch by default.**"
100+
echo
101+
echo "The \`main\` branch is reserved for release-please and Stainless automation. To resolve, pick one of:"
102+
echo
103+
echo "- **Re-target the PR to \`next\`** (recommended). On the PR page, click **Edit** next to the title and change the base branch to \`next\`."
104+
echo "- **Add the \`target-main\` label** if this is an intentional exception (e.g. an urgent hotfix). The check will re-run and pass."
105+
echo
106+
echo "See \`CONTRIBUTING.md\` for the full branch model."
107+
} > "$body_file"
108+
109+
if [ -n "$existing_id" ]; then
110+
gh api -X PATCH "repos/$REPO/issues/comments/$existing_id" \
111+
-F body=@"$body_file" >/dev/null
112+
echo "Updated existing PR comment ($existing_id)."
113+
else
114+
gh pr comment "$PR_NUMBER" --repo "$REPO" --body-file "$body_file" >/dev/null
115+
echo "Posted new PR comment."
116+
fi
117+
118+
echo "::error title=PR should target 'next'::See the PR comment for resolution steps. Re-target to 'next' or add the 'target-main' label."
73119
exit 1

CLAUDE.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44

5+
## Contribution workflow
6+
7+
- This repository is a Stainless-generated SDK. Open PRs against the `next` branch (not `main`).
8+
Stainless watches `next` and release-please opens release PRs from `next``main`.
9+
- PR titles must follow [Conventional Commits](https://www.conventionalcommits.org/) — the
10+
`Validate PR title (Conventional Commits)` CI check enforces this on every PR.
11+
- The `Validate PR base branch` CI check fails on PRs targeting `main` from non-automation accounts
12+
and posts a comment with resolution steps. Add the `target-main` label only for genuine
13+
exceptions (e.g. an urgent hotfix).
14+
- See `CONTRIBUTING.md` for the full workflow.
15+
516
## Development Commands
617

718
### Package Management in the top level repo

CONTRIBUTING.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,39 @@ Alternatively if you don't want to install `Rye`, you can stick with the standar
3232
$ pip install -r requirements-dev.lock
3333
```
3434

35+
## Contribution workflow
36+
37+
This repository is generated and released by [Stainless](https://www.stainless.com/). To keep the
38+
release pipeline working, contributions need to follow the branch model and commit conventions below.
39+
40+
### Branch model
41+
42+
- Always open PRs against the `next` branch — not `main`. Stainless watches `next` to produce SDK
43+
builds and the automated version-bump PR.
44+
- Typical flow:
45+
1. Pull the latest `next` locally and branch off it.
46+
2. Make and push your changes, then open a PR targeting `next`.
47+
3. Get the PR reviewed and merged into `next`.
48+
4. Stainless will open (or update) a release PR bumping the version — review and merge that PR
49+
to ship to `main`/PyPI. A new release PR will not be cut while a previous one is still open,
50+
so unblock pending release PRs before expecting a new one.
51+
- Do not merge generated code directly into `next` via PR. Let the generator produce those changes.
52+
- The `Validate PR base branch` CI check fails on PRs targeting `main` from non-automation accounts
53+
and posts a comment with resolution steps. If you genuinely need to PR directly to `main` (e.g. an
54+
urgent hotfix), add the `target-main` label to bypass the check.
55+
56+
### Conventional commits
57+
58+
Commit messages and PR titles must follow [Conventional Commits](https://www.conventionalcommits.org/),
59+
because the changelog and release notes are derived from them. The `Validate PR title (Conventional Commits)`
60+
CI check enforces this on every PR. Common prefixes:
61+
62+
- `feat(api): ...` — new functionality
63+
- `fix(types): ...` — bug fixes
64+
- `docs(readme): ...` — documentation-only changes (required for manual README/docs overrides to be
65+
picked up by the generator)
66+
- `chore(internal): ...` — internal changes that don't affect users
67+
3568
## Modifying/Adding code
3669

3770
Most of the SDK is generated code. Modifications to code will be persisted between generations, but may

0 commit comments

Comments
 (0)