Skip to content

Commit e752d8a

Browse files
[mq] [skip ddci] working branch - merge 3500175 on top of main at e381a74
{"baseBranch":"main","baseCommit":"e381a74a441dfac8e45977f8fd6b45cc88778553","createdAt":"2026-03-12T12:04:16.735276Z","headSha":"35001755c31568f3c87fe632c6e55ba66cdd9740","id":"a0c4cead-dc32-461b-b832-384da2902381","nextMergeabilityCheckAt":"2026-03-12T13:32:03.461050Z","priority":"200","pullRequestNumber":"1710","queuedAt":"2026-03-12T12:32:10.659722Z","status":"STATUS_QUEUED"}
2 parents 33f43fb + 3500175 commit e752d8a

File tree

1 file changed

+29
-98
lines changed

1 file changed

+29
-98
lines changed

.github/workflows/pr-title-semver-check.yml

Lines changed: 29 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ permissions:
44
pull-requests: read
55
on:
66
pull_request:
7-
types: ['opened', 'edited', 'reopened', 'synchronize']
7+
types: ['opened', 'edited', 'reopened', 'synchronize', 'labeled', 'unlabeled']
88
branches-ignore:
99
- "v[0-9]+.[0-9]+.[0-9]+.[0-9]+"
1010
- release
@@ -15,6 +15,7 @@ env:
1515

1616
jobs:
1717
detect-changes:
18+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-pr-title-semver-check') }}
1819
runs-on: ubuntu-latest
1920
outputs:
2021
changed_crates: ${{ steps.detect.outputs.crates }}
@@ -78,7 +79,7 @@ jobs:
7879
7980
semver-check:
8081
needs: detect-changes
81-
if: needs.detect-changes.outputs.has_rust_changes == 'true'
82+
if: ${{ needs.detect-changes.outputs.has_rust_changes == 'true' && !contains(github.event.pull_request.labels.*.name, 'skip-pr-title-semver-check') }}
8283
runs-on: ubuntu-latest
8384
outputs:
8485
result_json: ${{ steps.semver.outputs.result_json }}
@@ -156,7 +157,7 @@ jobs:
156157
157158
validate:
158159
needs: [detect-changes, semver-check]
159-
if: needs.detect-changes.outputs.has_rust_changes == 'true'
160+
if: ${{ needs.detect-changes.outputs.has_rust_changes == 'true' && !contains(github.event.pull_request.labels.*.name, 'skip-pr-title-semver-check') }}
160161
runs-on: ubuntu-latest
161162
steps:
162163
- name: Validate PR title against semver changes
@@ -206,52 +207,30 @@ jobs:
206207
echo ""
207208
208209
VALIDATION_FAILED="false"
210+
FAILURE_REASONS=()
209211
210-
# Validation rules
212+
# Rule: ci/docs/style/test/build cannot change the public API
211213
case "$TYPE" in
212-
fix)
213-
if [[ "$SEMVER_LEVEL" == "major" ]] && [[ -z "$IS_BREAKING_CHANGE" ]]; then
214+
ci|docs|style|test|build)
215+
if [[ "$SEMVER_LEVEL" == "major" ]] || [[ "$SEMVER_LEVEL" == "minor" ]]; then
216+
VALIDATION_FAILED="true"
217+
FAILURE_REASONS+=("'$TYPE' cannot have major or minor API changes. Use a different PR type, or avoid public API changes.")
218+
fi
219+
;;
220+
feat|fix|refactor|chore|perf|revert)
221+
# These can be any semver level (subject to breaking change rules below)
222+
;;
223+
*)
214224
VALIDATION_FAILED="true"
215-
elif [[ "$SEMVER_LEVEL" == "minor" ]] || [[ "$SEMVER_LEVEL" == "none" ]]; then
216-
VALIDATION_FAILED="true"
217-
fi
218-
;;
219-
220-
feat)
221-
if [[ "$SEMVER_LEVEL" == "major" ]] && [[ -z "$IS_BREAKING_CHANGE" ]]; then
222-
VALIDATION_FAILED="true"
223-
elif [[ "$SEMVER_LEVEL" == "patch" ]] || [[ "$SEMVER_LEVEL" == "none" ]]; then
224-
VALIDATION_FAILED="true"
225-
fi
226-
;;
227-
228-
chore|ci|docs|style|test|build|perf)
229-
# Breaking change marker shouldn't be there.
230-
if [[ -n "$IS_BREAKING_CHANGE" ]]; then
231-
VALIDATION_FAILED="true"
232-
fi
233-
234-
# These should not change public API
235-
if [[ "$SEMVER_LEVEL" == "major" ]] || [[ "$SEMVER_LEVEL" == "minor" ]]; then
236-
VALIDATION_FAILED="true"
237-
fi
238-
;;
239-
240-
refactor)
241-
if [[ "$SEMVER_LEVEL" == "major" ]] && [[ -z "$IS_BREAKING_CHANGE" ]]; then
242-
VALIDATION_FAILED="true"
243-
fi
244-
;;
245-
246-
revert)
247-
# Revert commits are allowed to have any semver level
248-
;;
225+
FAILURE_REASONS+=("Unknown PR type: '$TYPE'. Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert")
226+
;;
227+
esac
249228
250-
*)
251-
echo "$TYPE not handled";
229+
# Rule: major API changes must have a breaking change marker
230+
if [[ "$SEMVER_LEVEL" == "major" ]] && [[ -z "$IS_BREAKING_CHANGE" ]]; then
252231
VALIDATION_FAILED="true"
253-
;;
254-
esac
232+
FAILURE_REASONS+=("Major API changes require a breaking change marker. Add '!' to PR title (e.g. 'feat!:' or 'feat(scope)!:') or add 'BREAKING CHANGE:' footer in PR body.")
233+
fi
255234
256235
if [[ "$VALIDATION_FAILED" == "true" ]]; then
257236
echo ""
@@ -267,69 +246,21 @@ jobs:
267246
echo "--------------------------------------------"
268247
echo "WHAT WAS DETECTED:"
269248
echo "--------------------------------------------"
270-
# Show details for each crate
271249
echo "$SEMVER_RESULT_JSON" | jq -r '.crates[] | "Crate: \(.name)\n Level: \(.level)\n Reason: \(.reason)\n Details:\n\(.details | split("\n") | map(" " + .) | join("\n"))\n"'
272250
echo ""
273251
echo "--------------------------------------------"
274252
echo "WHY THIS FAILED:"
275253
echo "--------------------------------------------"
276-
case "$TYPE" in
277-
fix)
278-
if [[ "$SEMVER_LEVEL" == "major" ]] && [[ -z "$IS_BREAKING_CHANGE" ]]; then
279-
echo "'fix' with major changes requires breaking change marker."
280-
echo "Add '!' to PR title (fix!:) or add 'BREAKING CHANGE:' footer in PR body."
281-
elif [[ "$SEMVER_LEVEL" == "minor" ]]; then
282-
echo "'fix' cannot have minor-level changes (new public API)."
283-
echo "Use 'feat' type instead, or remove the new public API additions."
284-
elif [[ "$SEMVER_LEVEL" == "none" ]]; then
285-
echo "'fix' requires changes to published crates."
286-
echo "Use 'chore' or 'ci' for non-published changes."
287-
fi
288-
;;
289-
feat)
290-
if [[ "$SEMVER_LEVEL" == "major" ]] && [[ -z "$IS_BREAKING_CHANGE" ]]; then
291-
echo "'feat' with major changes requires breaking change marker."
292-
echo "Add '!' to PR title (feat!:) or add 'BREAKING CHANGE:' footer in PR body."
293-
elif [[ "$SEMVER_LEVEL" == "patch" ]]; then
294-
echo "'feat' requires minor-level changes (new public API)."
295-
echo "Use 'fix' for bug fixes, or ensure new items are marked 'pub'."
296-
elif [[ "$SEMVER_LEVEL" == "none" ]]; then
297-
echo "'feat' requires changes to published crates."
298-
echo "Use 'chore' for non-published changes."
299-
fi
300-
;;
301-
chore|ci|docs|style|test|build|perf)
302-
if [[ -n "$IS_BREAKING_CHANGE" ]]; then
303-
echo "'$TYPE' cannot have breaking change marker."
304-
echo "Remove '!' from title or use 'feat!', 'fix!', or 'refactor!' instead."
305-
elif [[ "$SEMVER_LEVEL" == "major" ]]; then
306-
echo "'$TYPE' cannot have major-level changes (breaking API)."
307-
echo "Use 'refactor!' or 'feat!' for intentional breaking changes."
308-
elif [[ "$SEMVER_LEVEL" == "minor" ]]; then
309-
echo "'$TYPE' cannot have minor-level changes (new public API)."
310-
echo "Use 'feat' for new features, or mark new items as pub(crate)."
311-
fi
312-
;;
313-
refactor)
314-
if [[ "$SEMVER_LEVEL" == "major" ]] && [[ -z "$IS_BREAKING_CHANGE" ]]; then
315-
echo "'refactor' with major changes requires breaking change marker."
316-
echo "Add '!' to PR title (refactor!:) or add 'BREAKING CHANGE:' footer in PR body."
317-
fi
318-
;;
319-
*)
320-
echo "Unknown PR type: '$TYPE'"
321-
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
322-
;;
323-
esac
254+
for reason in "${FAILURE_REASONS[@]}"; do
255+
echo "- $reason"
256+
done
324257
echo ""
325258
echo "--------------------------------------------"
326259
echo "VALID COMBINATIONS:"
327260
echo "--------------------------------------------"
328-
echo " fix -> patch, or major (with '!')"
329-
echo " feat -> minor, or major (with '!')"
330-
echo " refactor -> patch, minor, or major (with '!')"
331-
echo " chore/ci/docs/style/test/build/perf -> patch or none only"
332-
echo " revert -> any level"
261+
echo " ci/docs/style/test/build -> patch or none only (no public API changes)"
262+
echo " all other types -> any level allowed"
263+
echo " major changes -> must have '!' or 'BREAKING CHANGE:' footer"
333264
echo ""
334265
exit 1
335266
else

0 commit comments

Comments
 (0)