This is an automated email from the ASF dual-hosted git repository.
Yicong-Huang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new a5b895715e fix(ci): place "(backported from commit X)" before trailers
in backport message (#4696)
a5b895715e is described below
commit a5b895715e589f7f74c1459cd314861288126532
Author: Yicong Huang <[email protected]>
AuthorDate: Sat May 2 17:46:53 2026 -0700
fix(ci): place "(backported from commit X)" before trailers in backport
message (#4696)
### What changes were proposed in this PR?
Direct backports currently append the `(backported from commit X)` note
at the very end of the commit message. Because GitHub's squash-merge
messages already carry a trailer block (`Co-Authored-By:` etc.) at the
end, the note ends up *after* the trailers:
```
fix: foo
Body.
Closes #123.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
(backported from commit abc1234) ← currently here
```
Git treats the trailer block as the contiguous run of `Key: value` lines
at the very end of the message, separated from the body by a blank line.
With a non-trailer line trailing the trailer block, `git
interpret-trailers --parse` sees zero trailers — tools that read
Co-Authored-By, Signed-off-by, etc. lose the metadata for backport
commits.
This PR re-orders the composition so the body comes first, then the
`(backported from commit X)` note as its own paragraph, then the trailer
block at the very end:
```
fix: foo
Body.
Closes #123.
(backported from commit abc1234) ← moved here
Co-Authored-By: Claude Opus 4.7 <[email protected]>
```
A small Python step inside the workflow splits the original message at
the trailer boundary using the standard `^[A-Za-z][A-Za-z0-9-]*:\s`
heuristic and reassembles. Cases handled:
| input | output |
|---|---|
| body + trailers | body + blank + note + blank + trailers |
| body, no trailers | body + blank + note |
| multiple trailers | body + blank + note + blank + all trailers
contiguous |
### Any related issues, documentation, discussions?
None — incidental fix to the backport job alongside the broader CI
cleanup work.
### How was this PR tested?
Ran the assembled Python step locally against five synthetic message
shapes:
| input | result |
|---|---|
| subject only (`docs: typo fix`) | subject + blank + note |
| subject + body, no trailers | subject + body + blank + note |
| subject + body + single trailer | subject + body + blank + note +
blank + trailer |
| subject + body + multiple trailers | subject + body + blank + note +
blank + all trailers contiguous |
| body containing a non-trailer `Word:` line | subject + body + blank +
note (body line not mis-classified) |
The last case is the trailer-detection tightening: a trailer block
exists only when there is a blank line in the message AND every line
after the last blank line is in trailer format. That avoids treating a
Conventional Commits subject (`feat: foo` for a one-line commit) as a
one-line trailer block.
The next direct-backport CI run on this branch's merge will exercise the
path end-to-end.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 4.7, 1M context)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
.github/workflows/direct-backport-push.yml | 46 ++++++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/direct-backport-push.yml
b/.github/workflows/direct-backport-push.yml
index c9fc6b20a1..215a888996 100644
--- a/.github/workflows/direct-backport-push.yml
+++ b/.github/workflows/direct-backport-push.yml
@@ -221,8 +221,48 @@ jobs:
git checkout -B "${TARGET_BRANCH}" "origin/${TARGET_BRANCH}"
git cherry-pick --no-commit "${MERGE_SHA}"
- {
- printf '%s\n\n(backported from commit %s)\n' "${merge_message}"
"${MERGE_SHA}"
- } | git commit -F - --author="${original_author}"
+ # Compose the final commit message. The "(backported from commit X)"
+ # note goes between the message body and the trailer block (the
+ # trailing run of `Key: value` lines such as Co-Authored-By and
+ # Signed-off-by) so trailers stay contiguous at the bottom of the
+ # message — that's where git itself parses them.
+ #
+ # The trailer block, by git convention, is the run of `Key: value`
+ # lines after the LAST blank line in the message, and only counts
+ # if EVERY line after that blank line is in trailer format. This
+ # avoids mis-detecting a Conventional Commits subject like
+ # "feat: foo" or a body line like "References:" as a trailer.
+ new_message=$(
+ printf '%s' "${merge_message}" | \
+ python3 -c '
+import re, sys
+sha = sys.argv[1]
+msg = sys.stdin.read().rstrip("\n")
+lines = msg.split("\n")
+trailer_re = re.compile(r"^[A-Za-z][A-Za-z0-9-]*:\s")
+
+last_blank = -1
+for idx in range(len(lines) - 1, -1, -1):
+ if lines[idx] == "":
+ last_blank = idx
+ break
+
+trailer_start = len(lines)
+if last_blank != -1:
+ candidate = lines[last_blank + 1:]
+ if candidate and all(trailer_re.match(l) for l in candidate):
+ trailer_start = last_blank + 1
+
+backport = f"(backported from commit {sha})"
+if trailer_start == len(lines):
+ print(msg + "\n\n" + backport)
+else:
+ body = "\n".join(lines[:trailer_start]).rstrip("\n")
+ trailers = "\n".join(lines[trailer_start:])
+ print(body + "\n\n" + backport + "\n\n" + trailers)
+' "${MERGE_SHA}"
+ )
+
+ printf '%s\n' "${new_message}" | git commit -F -
--author="${original_author}"
git push origin "HEAD:${TARGET_BRANCH}"