This is an automated email from the ASF dual-hosted git repository.
roryqi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new f077ce8421 [#12277] fix(ci): Guard cherry-pick conflict PRs with
title, label, and CI check (#12276)
f077ce8421 is described below
commit f077ce84211fedfa925ae40c1b76dcb8f942e1e6
Author: MaSai <[email protected]>
AuthorDate: Fri Jul 31 09:39:19 2026 +0800
[#12277] fix(ci): Guard cherry-pick conflict PRs with title, label, and CI
check (#12276)
### What changes were proposed in this pull request?
Improve handling of auto cherry-pick PRs that contain unresolved
conflicts:
1. **CI check** (`.github/workflows/conflict-marker-check.yml`)
- Fail when a PR/push introduces unresolved git conflict markers
(`<<<<<<< ` / whole-line `=======` / `>>>>>>> `).
- Standalone workflow so `build.yml` path filters cannot skip it.
2. **Cherry-pick PR signaling**
(`.github/workflows/cherry-pick-branch.yml`)
- On conflict: prefix the PR title with `[DO NOT MERGE]`.
- On conflict: add a `cherry-pick-conflict` label (created if missing).
- Keep opening the PR so humans can still resolve conflicts in place.
### Why are the changes needed?
When auto cherry-pick fails, `cherry-pick-branch.yml` commits conflict
markers and opens a PR. Today only the PR body says there are conflicts.
GitHub mergeability stays clean, and existing CI can stay green for
docs/conf/shell conflicts.
Maintainers asked for clearer signaling (title + label, similar to the
enterprise conflict flow) plus a CI check so these PRs are hard to merge
by mistake.
Fix: #12277
### Does this PR introduce _any_ user-facing change?
No. CI / automation only. No API, configuration, or runtime behaviour
changes.
### How was this patch tested?
Locally ran `git diff --check`: commits with conflict markers fail,
clean commits pass.
---------
Co-authored-by: Cursor <[email protected]>
---
.github/workflows/cherry-pick-branch.yml | 56 ++++++++++++++++----
.github/workflows/conflict-marker-check.yml | 82 +++++++++++++++++++++++++++++
2 files changed, 127 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/cherry-pick-branch.yml
b/.github/workflows/cherry-pick-branch.yml
index e685d6bd0e..3b5aaa8d41 100644
--- a/.github/workflows/cherry-pick-branch.yml
+++ b/.github/workflows/cherry-pick-branch.yml
@@ -39,6 +39,10 @@ jobs:
cherry-pick:
runs-on: ubuntu-latest
name: Cherry-pick to ${{ inputs.target-branch }}
+ permissions:
+ contents: write
+ pull-requests: write
+ issues: write
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -99,7 +103,8 @@ jobs:
run: |
# Use original commit message with branch prefix
TITLE="[Cherry-pick to ${TARGET_BRANCH}] ${COMMIT_MESSAGE}"
-
+ LABELS=(cherry-pick)
+
# Prepare body with cherry-pick info
if [ "${SUCCESS}" = "true" ]; then
BODY=$(cat <<'EOF'
@@ -110,25 +115,54 @@ jobs:
EOF
)
else
+ # Make conflicts visible in the PR list (title + label), not only
in the body.
+ TITLE="[DO NOT MERGE] ${TITLE}"
+ LABELS+=(cherry-pick-conflict)
+
BODY=$(cat <<'EOF'
**Cherry-pick Information:**
- Original commit: ${COMMIT_SHA}
- Target branch: `${TARGET_BRANCH}`
- Status: ⚠️ **Has conflicts - manual resolution required**
-
+
+ **Do not merge** until conflict markers are resolved and the
+ `cherry-pick-conflict` label is removed.
+
Please review and resolve the conflicts before merging.
EOF
)
fi
-
+
# Replace placeholders with actual values
BODY="${BODY//\$\{COMMIT_SHA\}/${COMMIT_SHA}}"
BODY="${BODY//\$\{TARGET_BRANCH\}/${TARGET_BRANCH}}"
-
- gh pr create \
- --title "$TITLE" \
- --body "$BODY" \
- --base ${{ inputs.target-branch }} \
- --head ${{ steps.cherry-pick.outputs.branch-name }} \
- --label cherry-pick \
- --reviewer jerryshao || echo "Failed to create PR, may already
exist"
+
+ # Ensure labels exist (forks may not have them yet).
+ gh label create cherry-pick \
+ --description "Automatically opened cherry-pick PR" \
+ --color 1D76DB \
+ --force >/dev/null 2>&1 || true
+ if [ "${SUCCESS}" != "true" ]; then
+ gh label create cherry-pick-conflict \
+ --description "Cherry-pick has conflicts; needs human resolution
before merge" \
+ --color B60205 \
+ --force >/dev/null 2>&1 || true
+ fi
+
+ LABEL_ARGS=()
+ for label in "${LABELS[@]}"; do
+ LABEL_ARGS+=(--label "$label")
+ done
+
+ CREATE_ARGS=(
+ --title "$TITLE"
+ --body "$BODY"
+ --base "${{ inputs.target-branch }}"
+ --head "${{ steps.cherry-pick.outputs.branch-name }}"
+ "${LABEL_ARGS[@]}"
+ )
+ # Reviewer is only valid on apache/gravitino.
+ if [ "${{ github.repository }}" = "apache/gravitino" ]; then
+ CREATE_ARGS+=(--reviewer jerryshao)
+ fi
+ gh pr create "${CREATE_ARGS[@]}" || echo "Failed to create PR, may
already exist"
diff --git a/.github/workflows/conflict-marker-check.yml
b/.github/workflows/conflict-marker-check.yml
new file mode 100644
index 0000000000..7b14e9cc7b
--- /dev/null
+++ b/.github/workflows/conflict-marker-check.yml
@@ -0,0 +1,82 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Conflict Marker Check
+
+# Standalone workflow so path filters on build.yml cannot skip this check.
+# Catches cherry-pick / sync PRs that commit unresolved git conflict markers.
+on:
+ pull_request:
+ branches: ["main", "branch-*"]
+ push:
+ branches: ["main", "branch-*"]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: conflict-marker-check-${{ github.event.pull_request.number ||
github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ conflict-marker-check:
+ name: conflict-marker-check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Fail if unresolved git conflict markers are introduced
+ run: |
+ set -euo pipefail
+
+ if [ "${{ github.event_name }}" = "pull_request" ]; then
+ BASE_SHA="${{ github.event.pull_request.base.sha }}"
+ HEAD_SHA="${{ github.event.pull_request.head.sha }}"
+ else
+ BASE_SHA="${{ github.event.before }}"
+ HEAD_SHA="${{ github.sha }}"
+ # First push / force-push edge case: before may be all zeros.
+ if [ -z "${BASE_SHA}" ] || [[ "${BASE_SHA}" =~ ^0+$ ]]; then
+ BASE_SHA="$(git rev-parse "${HEAD_SHA}^")"
+ fi
+ fi
+
+ echo "Checking range ${BASE_SHA}...${HEAD_SHA}"
+
+ # git's built-in check for conflict markers introduced in the diff.
+ git diff --check "${BASE_SHA}...${HEAD_SHA}"
+
+ # Explicit line-start scan on changed files (======= must be a whole
line).
+ failed=0
+ while IFS= read -r f; do
+ [ -f "$f" ] || continue
+ if grep -nE '^(<<<<<<< |>>>>>>> |=======$)' "$f"; then
+ echo "::error file=${f}::Unresolved conflict markers remain in
${f}"
+ failed=1
+ fi
+ done < <(git diff --name-only --diff-filter=ACMR
"${BASE_SHA}...${HEAD_SHA}")
+
+ if [ "${failed}" -ne 0 ]; then
+ echo "Unresolved git conflict markers found. Resolve them before
merging."
+ exit 1
+ fi
+
+ echo "No unresolved conflict markers found."