Skip to content

Commit 42f9dfc

Browse files
hein-oboxgithub-actions[bot]
authored andcommitted
Cherry-pick PR #506 with conflicts - manual resolution needed
1 parent 890cf37 commit 42f9dfc

File tree

1 file changed

+348
-0
lines changed

1 file changed

+348
-0
lines changed
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
name: Cherry Pick Merged PR
2+
# Add a test comment.
3+
4+
on:
5+
pull_request_target:
6+
types:
7+
- closed
8+
- labeled
9+
10+
permissions:
11+
contents: write
12+
pull-requests: write
13+
14+
jobs:
15+
load-config:
16+
runs-on: ubuntu-latest
17+
outputs:
18+
ubuntu_version: ${{ steps.config.outputs.ubuntu_version }}
19+
theme_name: ${{ steps.config.outputs.theme_name }}
20+
main_branch: ${{ steps.config.outputs.main_branch }}
21+
allowed_repos: ${{ steps.config.outputs.allowed_repos }}
22+
blocked_actors: ${{ steps.config.outputs.blocked_actors }}
23+
release_branches: ${{ steps.config.outputs.release_branches }}
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
28+
- name: Load Release Configuration
29+
id: config
30+
run: |
31+
echo "📋 Loading release configuration..."
32+
CONFIG_FILE=".github/config/release.json"
33+
34+
if [ ! -f "$CONFIG_FILE" ]; then
35+
echo "❌ Error: Release configuration file not found: $CONFIG_FILE"
36+
exit 1
37+
fi
38+
39+
# Validate JSON syntax
40+
if ! jq empty "$CONFIG_FILE" 2>/dev/null; then
41+
echo "❌ Error: Invalid JSON in release configuration"
42+
exit 1
43+
fi
44+
45+
# Load configuration values (only what's needed for cherry-pick)
46+
UBUNTU_VERSION=$(jq -r '.environment.ubuntu_version' "$CONFIG_FILE")
47+
THEME_NAME=$(jq -r '.repository.name' "$CONFIG_FILE")
48+
MAIN_BRANCH=$(jq -r '.repository.main_branch' "$CONFIG_FILE")
49+
ALLOWED_REPOS=$(jq -r '.security.allowed_repositories[]' "$CONFIG_FILE" | tr '\n' ' ')
50+
BLOCKED_ACTORS=$(jq -r '.security.blocked_actors[]' "$CONFIG_FILE" | tr '\n' ' ')
51+
RELEASE_BRANCHES=$(jq -r '.repository.release_branches[]' "$CONFIG_FILE" | tr '\n' ' ')
52+
53+
# Set outputs
54+
echo "ubuntu_version=$UBUNTU_VERSION" >> "$GITHUB_OUTPUT"
55+
echo "theme_name=$THEME_NAME" >> "$GITHUB_OUTPUT"
56+
echo "main_branch=$MAIN_BRANCH" >> "$GITHUB_OUTPUT"
57+
echo "allowed_repos=$ALLOWED_REPOS" >> "$GITHUB_OUTPUT"
58+
echo "blocked_actors=$BLOCKED_ACTORS" >> "$GITHUB_OUTPUT"
59+
echo "release_branches=$RELEASE_BRANCHES" >> "$GITHUB_OUTPUT"
60+
61+
echo "✅ Release configuration loaded successfully"
62+
echo "Theme: $THEME_NAME"
63+
echo "Ubuntu: $UBUNTU_VERSION"
64+
echo "Main branch: $MAIN_BRANCH"
65+
echo "Release branches: $RELEASE_BRANCHES"
66+
67+
cherry-pick:
68+
needs: load-config
69+
if: ${{ github.event.pull_request.merged == true && (github.event.action == 'closed' || (github.event.action == 'labeled' && startsWith(github.event.label.name, 'cp_'))) }}
70+
runs-on: ${{ needs.load-config.outputs.ubuntu_version }}
71+
72+
env:
73+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
74+
HEAD_REF: ${{ github.event.pull_request.head.ref }}
75+
76+
steps:
77+
- name: Checkout repository
78+
uses: actions/checkout@v4
79+
with:
80+
token: ${{ secrets.GITHUB_TOKEN }}
81+
ref: ${{ github.event.pull_request.base.ref }}
82+
fetch-depth: 0
83+
persist-credentials: true
84+
85+
- name: Set Configuration Variables
86+
run: |
87+
echo "📋 Setting configuration variables from load-config job..."
88+
echo "UBUNTU_VERSION=${{ needs.load-config.outputs.ubuntu_version }}" >> $GITHUB_ENV
89+
echo "THEME_NAME=${{ needs.load-config.outputs.theme_name }}" >> $GITHUB_ENV
90+
echo "MAIN_BRANCH=${{ needs.load-config.outputs.main_branch }}" >> $GITHUB_ENV
91+
echo "ALLOWED_REPOS=${{ needs.load-config.outputs.allowed_repos }}" >> $GITHUB_ENV
92+
echo "BLOCKED_ACTORS=${{ needs.load-config.outputs.blocked_actors }}" >> $GITHUB_ENV
93+
echo "RELEASE_BRANCHES=${{ needs.load-config.outputs.release_branches }}" >> $GITHUB_ENV
94+
95+
echo "✅ Configuration variables set successfully"
96+
echo "Theme: ${{ needs.load-config.outputs.theme_name }}"
97+
echo "Ubuntu: ${{ needs.load-config.outputs.ubuntu_version }}"
98+
echo "Main branch: ${{ needs.load-config.outputs.main_branch }}"
99+
100+
- name: Security and Pre-flight Checks
101+
run: |
102+
echo "🔍 Security and pre-flight checks..."
103+
echo "Repository: ${{ github.repository }}"
104+
echo "Actor: ${{ github.actor }}"
105+
echo "Base branch: ${{ github.event.pull_request.base.ref }}"
106+
echo "Head branch: $HEAD_REF"
107+
108+
# Repository permissions validation
109+
REPO_ALLOWED=false
110+
IFS=' ' read -ra ALLOWED_REPOS_ARRAY <<< "${{ env.ALLOWED_REPOS }}"
111+
for allowed_repo in "${ALLOWED_REPOS_ARRAY[@]}"; do
112+
if [ "${{ github.repository }}" = "$allowed_repo" ]; then
113+
REPO_ALLOWED=true
114+
break
115+
fi
116+
done
117+
118+
if [ "$REPO_ALLOWED" != "true" ]; then
119+
echo "⚠️ Warning: Cherry-pick attempted on unauthorized repository: ${{ github.repository }}"
120+
echo "Allowed repositories: ${{ env.ALLOWED_REPOS }}"
121+
fi
122+
123+
# Check actor permissions (basic validation)
124+
IFS=' ' read -ra BLOCKED_ACTORS_ARRAY <<< "${{ env.BLOCKED_ACTORS }}"
125+
for blocked_actor in "${BLOCKED_ACTORS_ARRAY[@]}"; do
126+
if [ "${{ github.actor }}" = "$blocked_actor" ]; then
127+
echo "❌ Error: Blocked actor cannot create cherry-pick: ${{ github.actor }}"
128+
exit 1
129+
fi
130+
done
131+
132+
# Validate that this is a legitimate cherry-pick operation
133+
if [ "${{ github.event.pull_request.merged }}" != "true" ]; then
134+
echo "❌ Error: Cherry-pick can only be performed on merged PRs"
135+
exit 1
136+
fi
137+
138+
echo "✅ Security and pre-flight checks passed"
139+
140+
- name: Check if PR is from fork
141+
id: check_fork
142+
run: |
143+
IS_FORK="${{ github.event.pull_request.head.repo.full_name != github.repository }}"
144+
echo "is_fork=$IS_FORK" >> "$GITHUB_OUTPUT"
145+
echo "Fork status: $IS_FORK"
146+
shell: bash
147+
148+
- name: Log trigger and PR information
149+
run: |
150+
echo "Trigger: ${{ github.event.action }}"
151+
if [ "${{ github.event.action }}" = "labeled" ]; then
152+
echo "Added label: ${{ github.event.label.name }}"
153+
fi
154+
echo "PR #${{ github.event.pull_request.number }} from: ${{ github.event.pull_request.head.repo.full_name }}"
155+
echo "Target repository: ${{ github.repository }}"
156+
echo "Is fork PR: ${{ steps.check_fork.outputs.is_fork }}"
157+
echo "PR merged: ${{ github.event.pull_request.merged }}"
158+
shell: bash
159+
160+
- name: Get branch labels
161+
id: get_labels
162+
run: |
163+
LABELS=$(jq -r '.[].name' <<< '${{ toJSON(github.event.pull_request.labels) }}' | grep '^cp_' | paste -sd ',' || echo "")
164+
echo "filtered_labels_csv=$LABELS" >> "$GITHUB_OUTPUT"
165+
shell: bash
166+
167+
- name: Fetch all branches
168+
run: git fetch --all
169+
shell: bash
170+
171+
- name: Cherry-Pick and Create PRs
172+
if: ${{ steps.get_labels.outputs.filtered_labels_csv != '' }}
173+
env:
174+
PR_TITLE: ${{ github.event.pull_request.title }}
175+
PR_USER_LOGIN: ${{ github.event.pull_request.user.login }}
176+
LABEL_NAME: ${{ github.event.label.name }}
177+
run: |
178+
PR_NUMBER="${{ github.event.pull_request.number }}"
179+
MERGE_SHA="${{ github.event.pull_request.merge_commit_sha }}"
180+
ORIG_URL="${{ github.event.pull_request.html_url }}"
181+
182+
git config user.name "github-actions[bot]"
183+
git config user.email "github-actions[bot]@users.noreply.github.com"
184+
185+
IFS=',' read -ra BRANCHES <<< "${{ steps.get_labels.outputs.filtered_labels_csv }}"
186+
for lbl in "${BRANCHES[@]}"; do
187+
TARGET=${lbl#cp_}
188+
189+
# Create sanitized branch name from original branch name with timestamp for uniqueness
190+
ORIGINAL_BRANCH="${{ github.event.pull_request.head.ref }}"
191+
# Strip any word followed by '/' to ensure ticket numbers appear at the beginning
192+
CLEAN_BRANCH=$(echo "$ORIGINAL_BRANCH" | sed 's|^[^/]*/||g')
193+
SANITIZED_BRANCH=$(echo "$CLEAN_BRANCH" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
194+
# Limit length to 35 chars to leave room for PR number and timestamp suffix
195+
SANITIZED_BRANCH=${SANITIZED_BRANCH:0:35}
196+
TIMESTAMP=$(date +%s)
197+
BRANCH="${SANITIZED_BRANCH}-cherry-pick-pr${PR_NUMBER}-${TIMESTAMP}"
198+
199+
echo "🍒 Processing cherry-pick for branch: $TARGET"
200+
201+
# Create branch
202+
if ! git checkout -b "$BRANCH" "origin/$TARGET"; then
203+
echo "::warning:: Branch $TARGET does not exist - skipping"
204+
continue
205+
fi
206+
207+
# Cherry-pick
208+
if ! git cherry-pick -m 1 "$MERGE_SHA"; then
209+
echo "::error:: Cherry-pick conflicts detected for PR #${PR_NUMBER} on branch ${TARGET}"
210+
211+
# Create a conflict resolution branch
212+
CONFLICT_BRANCH="${BRANCH}-conflicts"
213+
214+
# Add conflict markers and create a commit for manual resolution
215+
git add .
216+
git commit -m "Cherry-pick PR #${PR_NUMBER} with conflicts - manual resolution needed"
217+
218+
# Push the conflict branch
219+
if git push --force-with-lease origin "$BRANCH:$CONFLICT_BRANCH"; then
220+
# Create draft PR with conflict information
221+
if ! gh pr list --head "$CONFLICT_BRANCH" --base "$TARGET" --state open | grep -q .; then
222+
CONFLICT_TRIGGER_INFO=""
223+
if [ "${{ github.event.action }}" = "labeled" ]; then
224+
CONFLICT_TRIGGER_INFO="
225+
**Trigger:** Label \`${LABEL_NAME}\` added to closed PR"
226+
fi
227+
228+
gh pr create \
229+
--base "$TARGET" \
230+
--head "$CONFLICT_BRANCH" \
231+
--title "🔧 [CONFLICTS] Cherry-pick PR #${PR_NUMBER} → ${TARGET}: ${PR_TITLE}" \
232+
--body "⚠️ **Manual Resolution Required**
233+
234+
This cherry-pick of [#${PR_NUMBER}](${ORIG_URL}) to \`${TARGET}\` branch has conflicts that need manual resolution.
235+
236+
**Theme-Specific Conflict Resolution:**
237+
- **Version Conflicts**: Check \`style.css\` header for version mismatches
238+
- **Schema Conflicts**: Validate \`theme.json\` structure changes
239+
- **Function Conflicts**: Resolve \`functions.php\` function name collisions
240+
241+
**Resolution Steps:**
242+
1. Check out this branch: \`git checkout $CONFLICT_BRANCH\`
243+
2. Resolve conflicts in the marked files
244+
3. Stage resolved files: \`git add <resolved-files>\`
245+
4. Amend the commit: \`git commit --amend\`
246+
5. Push changes: \`git push --force-with-lease\`
247+
6. Mark this PR as ready for review
248+
249+
**Automatic Validation:**
250+
Once you push resolved changes, the following workflows will run automatically:
251+
- Build validation (\`build.yml\`)
252+
- JavaScript linting (\`lint.yml\`)
253+
- Cherry-pick validation (\`cherry-pick-validation.yml\`)
254+
- Additional CI workflows as configured
255+
256+
**Original PR:** [#${PR_NUMBER}](${ORIG_URL})${CONFLICT_TRIGGER_INFO}" \
257+
--draft
258+
259+
echo "::notice:: Created draft PR for manual conflict resolution: $CONFLICT_BRANCH"
260+
else
261+
echo "::notice:: Draft PR already exists for conflict resolution: $CONFLICT_BRANCH"
262+
fi
263+
else
264+
echo "::warning:: Failed to push conflict branch $CONFLICT_BRANCH"
265+
git cherry-pick --abort
266+
fi
267+
continue
268+
else
269+
echo "✅ Cherry-pick successful for $TARGET"
270+
fi
271+
272+
# Basic theme structure validation (quick checks only)
273+
echo "🔍 Basic theme structure validation..."
274+
if [ ! -f "style.css" ]; then
275+
echo "::error:: Missing style.css after cherry-pick"
276+
continue
277+
fi
278+
if [ ! -f "functions.php" ]; then
279+
echo "::error:: Missing functions.php after cherry-pick"
280+
continue
281+
fi
282+
if [ ! -f "theme.json" ]; then
283+
echo "::error:: Missing theme.json after cherry-pick"
284+
continue
285+
fi
286+
287+
# Check for obvious conflict markers
288+
if grep -q "<<<<<<< HEAD" style.css functions.php theme.json 2>/dev/null; then
289+
echo "::warning:: Conflict markers detected - this should not happen in successful cherry-pick"
290+
fi
291+
292+
# Push (force push to handle existing branches)
293+
if ! git push --force-with-lease origin "$BRANCH"; then
294+
echo "::error:: Failed to push branch $BRANCH"
295+
exit 1
296+
fi
297+
298+
# Create PR via gh CLI (token already in env: GH_TOKEN)
299+
# Check if PR already exists
300+
if gh pr list --head "$BRANCH" --base "$TARGET" --state open | grep -q .; then
301+
echo "PR already exists for branch $BRANCH -> $TARGET, skipping creation"
302+
else
303+
TRIGGER_INFO=""
304+
if [ "${{ github.event.action }}" = "labeled" ]; then
305+
TRIGGER_INFO="
306+
**Trigger:** Label \`${LABEL_NAME}\` added to closed PR"
307+
fi
308+
309+
# Extract tickets and add to title for Jira compatibility
310+
PR_TICKETS=$(echo "$PR_TITLE" | grep -o '\[[A-Z]\{2,\}-[0-9]\+\]' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
311+
312+
# Create title with tickets at the end
313+
if [ -n "$PR_TICKETS" ]; then
314+
CHERRY_PICK_TITLE="$PR_TITLE (🍒 CP #${PR_NUMBER}→${TARGET}) ${PR_TICKETS}"
315+
else
316+
CHERRY_PICK_TITLE="$PR_TITLE (🍒 CP #${PR_NUMBER}→${TARGET})"
317+
fi
318+
319+
gh pr create \
320+
--base "$TARGET" \
321+
--head "$BRANCH" \
322+
--title "$CHERRY_PICK_TITLE" \
323+
--body "Automatic cherry-pick of [#${PR_NUMBER}](${ORIG_URL}) to \`${TARGET}\` branch.
324+
325+
**Theme Information:**
326+
- **Theme:** ${THEME_NAME}
327+
- **Source:** ${{ github.event.pull_request.head.repo.full_name }}
328+
- **Original Author:** @${PR_USER_LOGIN}${TRIGGER_INFO}
329+
330+
**Automatic Validation:**
331+
The following workflows will run automatically to validate this cherry-pick:
332+
- 🏗️ **Build validation** (\`build.yml\`) - Theme compilation and asset building
333+
- 🧹 **JavaScript linting** (\`lint.yml\`) - Code quality checks
334+
- ✅ **Cherry-pick validation** (\`cherry-pick-validation.yml\`) - Theme-specific validation
335+
- 🔍 **Additional CI workflows** - As configured for the repository
336+
337+
**Next Steps:**
338+
- Wait for validation workflows to complete
339+
- Review automated validation results
340+
- Test theme functionality if needed
341+
- Merge when all checks pass
342+
343+
**Note:** Build and validation happen automatically via PR workflows, following the same process as regular PRs."
344+
fi
345+
346+
echo "✅ Successfully created cherry-pick PR for $TARGET"
347+
done
348+
shell: bash

0 commit comments

Comments
 (0)