Skip to content

Commit a94dd82

Browse files
chore: Rewriting the workflow to use push instead of PR (#4)
* chore: Rewriting the workflow to use push instead of PR Because of Github actions security policies, a PR comming from a fork cannot access repository or organization secrets making it impossible to run the sync when external contributors submit their own pull requests. With this change the workflow is triggered by push events and uses commit messages and PR APIs to fetch more details making it run exclusivily on the repo * Update .github/workflows/reverse-sync-push.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent f8d30b3 commit a94dd82

File tree

1 file changed

+331
-0
lines changed

1 file changed

+331
-0
lines changed
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
name: Reverse Sync on Push
2+
3+
env:
4+
TARGET_REPO: alaudadevops/tektoncd-operator
5+
# Ignoring the files or folders in this prefix (uses comma to split)
6+
IGNORE_PATHS: .github/,README.md
7+
# will check these files change to create a new patch
8+
SYNCED_PATHS: "docs/ theme/ .yarn/ doom.config.yml yarn.lock tsconfig.json package.json sites.yaml"
9+
10+
on:
11+
push:
12+
branches:
13+
- main
14+
- release-*
15+
16+
# Limit token capabilities to what the job really needs
17+
permissions:
18+
contents: read # checkout / git diff
19+
pull-requests: write # create PR in target repo
20+
21+
# (Optional) Prevent multiple syncs of the same ref running in parallel
22+
concurrency:
23+
group: reverse-sync-${{ github.ref }}
24+
cancel-in-progress: true
25+
jobs:
26+
reverse-sync:
27+
runs-on: ubuntu-latest
28+
29+
steps:
30+
- name: Checkout devops-pipelines-docs repository
31+
uses: actions/checkout@v4
32+
with:
33+
token: ${{ secrets.GH_TOKEN }}
34+
fetch-depth: 0
35+
36+
- name: Check if commit is from merged PR
37+
id: check_pr_commit
38+
run: |
39+
# Get the latest commit
40+
commit_sha="${{ github.sha }}"
41+
echo "commit_sha=$commit_sha" >> $GITHUB_OUTPUT
42+
43+
# Get commit message
44+
commit_message=$(git log -1 --pretty=format:"%s" $commit_sha)
45+
echo "commit_message=$commit_message" >> $GITHUB_OUTPUT
46+
47+
# Get commit author
48+
commit_author=$(git log -1 --pretty=format:"%an" $commit_sha)
49+
commit_author_email=$(git log -1 --pretty=format:"%ae" $commit_sha)
50+
echo "commit_author=$commit_author" >> $GITHUB_OUTPUT
51+
echo "commit_author_email=$commit_author_email" >> $GITHUB_OUTPUT
52+
53+
echo "=> Commit: $commit_sha"
54+
echo "=> Message: $commit_message"
55+
echo "=> Author: $commit_author <$commit_author_email>"
56+
57+
# Check if this is a merge commit from GitHub (squash merge creates a single commit)
58+
# Look for PR number in commit message (GitHub automatically adds this)
59+
if [[ "$commit_message" =~ \(#([0-9]+)\)$ ]]; then
60+
pr_number="${BASH_REMATCH[1]}"
61+
echo "pr_number=$pr_number" >> $GITHUB_OUTPUT
62+
echo "is_pr_commit=true" >> $GITHUB_OUTPUT
63+
echo "✅ Detected commit from PR #$pr_number"
64+
else
65+
echo "is_pr_commit=false" >> $GITHUB_OUTPUT
66+
echo "ℹ️ Not a PR commit - skipping reverse sync"
67+
fi
68+
69+
# Skip if the commit is from our sync bot
70+
if [[ "$commit_author_email" == "[email protected]" ]] && [[ "$commit_message" == *"[reverse-sync]"* ]]; then
71+
echo "skip_sync=true" >> $GITHUB_OUTPUT
72+
echo "🤖 Commit is from sync bot - skipping reverse sync"
73+
elif [[ "$commit_message" == *"Sync documentation"* ]] || [[ "$commit_message" == *"sync-docs"* ]]; then
74+
echo "skip_sync=true" >> $GITHUB_OUTPUT
75+
echo "🤖 Commit appears to be from sync process - skipping reverse sync"
76+
else
77+
echo "skip_sync=false" >> $GITHUB_OUTPUT
78+
echo "👥 Commit is from external contributor - proceeding with reverse sync"
79+
fi
80+
81+
- name: Get PR information
82+
if: steps.check_pr_commit.outputs.is_pr_commit == 'true' && steps.check_pr_commit.outputs.skip_sync == 'false'
83+
id: get_pr_info
84+
run: |
85+
pr_number="${{ steps.check_pr_commit.outputs.pr_number }}"
86+
87+
# Get PR information using GitHub API
88+
pr_info=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
89+
"https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number")
90+
91+
pr_title=$(echo "$pr_info" | jq -r '.title')
92+
pr_author=$(echo "$pr_info" | jq -r '.user.login')
93+
pr_url=$(echo "$pr_info" | jq -r '.html_url')
94+
pr_base_ref=$(echo "$pr_info" | jq -r '.base.ref')
95+
96+
echo "pr_title=$pr_title" >> $GITHUB_OUTPUT
97+
echo "pr_author=$pr_author" >> $GITHUB_OUTPUT
98+
echo "pr_url=$pr_url" >> $GITHUB_OUTPUT
99+
echo "pr_base_ref=$pr_base_ref" >> $GITHUB_OUTPUT
100+
101+
echo "=> PR #$pr_number: $pr_title"
102+
echo "=> Author: $pr_author"
103+
echo "=> URL: $pr_url"
104+
105+
- name: Get commit changes
106+
if: steps.check_pr_commit.outputs.is_pr_commit == 'true' && steps.check_pr_commit.outputs.skip_sync == 'false'
107+
id: get_changes
108+
run: |
109+
commit_sha="${{ steps.check_pr_commit.outputs.commit_sha }}"
110+
111+
# Get the parent commit (previous commit before this one)
112+
parent_commit=$(git rev-parse ${commit_sha}^)
113+
echo "parent_commit=$parent_commit" >> $GITHUB_OUTPUT
114+
115+
# Get list of changed files in the commit, excluding ignored paths
116+
ignore_pattern=$(echo "$IGNORE_PATHS" | sed 's/,/|/g' | sed 's|/$||g')
117+
echo "🙈 Ignored paths: $ignore_pattern"
118+
119+
git diff --name-only $parent_commit $commit_sha | grep -v -E "^($ignore_pattern)" > changed_files.txt || true
120+
121+
echo "📋 Changed files in commit:"
122+
cat changed_files.txt
123+
124+
# Check if any relevant files were changed
125+
if [ -s changed_files.txt ]; then
126+
echo "has_doc_changes=true" >> $GITHUB_OUTPUT
127+
echo "✅ Documentation changes detected"
128+
else
129+
echo "has_doc_changes=false" >> $GITHUB_OUTPUT
130+
echo "ℹ️ No documentation changes detected"
131+
fi
132+
133+
- name: Checkout target repository
134+
if: steps.check_pr_commit.outputs.is_pr_commit == 'true' && steps.check_pr_commit.outputs.skip_sync == 'false' && steps.get_changes.outputs.has_doc_changes == 'true'
135+
uses: actions/checkout@v4
136+
with:
137+
repository: ${{env.TARGET_REPO}}
138+
token: ${{ secrets.GH_TOKEN }}
139+
path: target-docs
140+
fetch-depth: 0
141+
ref: ${{ steps.get_pr_info.outputs.pr_base_ref }}
142+
143+
- name: Create reverse sync branch
144+
if: steps.check_pr_commit.outputs.is_pr_commit == 'true' && steps.check_pr_commit.outputs.skip_sync == 'false' && steps.get_changes.outputs.has_doc_changes == 'true'
145+
id: create_branch
146+
run: |
147+
cd target-docs
148+
149+
# Create a unique branch name
150+
pr_number="${{ steps.check_pr_commit.outputs.pr_number }}"
151+
branch_name="reverse-sync/pr-$pr_number-$(date +%s)"
152+
echo "branch_name=$branch_name" >> $GITHUB_OUTPUT
153+
154+
git checkout -b "$branch_name"
155+
156+
# Configure git
157+
git config user.name "Documentation Sync Bot"
158+
git config user.email "[email protected]"
159+
160+
echo "📝 Created branch: $branch_name"
161+
162+
- name: Apply changes from devops-pipelines-docs
163+
if: steps.check_pr_commit.outputs.is_pr_commit == 'true' && steps.check_pr_commit.outputs.skip_sync == 'false' && steps.get_changes.outputs.has_doc_changes == 'true'
164+
run: |
165+
commit_sha="${{ steps.check_pr_commit.outputs.commit_sha }}"
166+
parent_commit="${{ steps.get_changes.outputs.parent_commit }}"
167+
168+
# Create a patch with only the synced paths
169+
echo "📑 Will only sync these paths: $SYNCED_PATHS"
170+
git format-patch $parent_commit..$commit_sha --stdout -- $SYNCED_PATHS > changes.patch
171+
172+
cd target-docs
173+
174+
# Apply the patch
175+
if [ -s ../changes.patch ]; then
176+
echo "📦 Applying changes from devops-pipelines-docs..."
177+
git apply ../changes.patch || {
178+
echo "⚠️ Patch application failed, trying manual copy..."
179+
180+
# Fallback: manual copy of changed files
181+
while IFS= read -r file; do
182+
if [ -f "../$file" ]; then
183+
mkdir -p "$(dirname "$file")"
184+
cp "../$file" "$file"
185+
echo "✅ Copied: $file"
186+
fi
187+
done < ../changed_files.txt
188+
}
189+
else
190+
echo "⚠️ No patch generated, using manual copy..."
191+
192+
# Manual copy approach
193+
while IFS= read -r file; do
194+
if [ -f "../$file" ]; then
195+
mkdir -p "$(dirname "$file")"
196+
cp "../$file" "$file"
197+
echo "✅ Copied: $file"
198+
fi
199+
done < ../changed_files.txt
200+
fi
201+
202+
- name: Commit changes
203+
if: steps.check_pr_commit.outputs.is_pr_commit == 'true' && steps.check_pr_commit.outputs.skip_sync == 'false' && steps.get_changes.outputs.has_doc_changes == 'true'
204+
id: commit_changes
205+
run: |
206+
cd target-docs
207+
208+
git add .
209+
210+
if git diff --staged --quiet; then
211+
echo "has_changes=false" >> $GITHUB_OUTPUT
212+
echo "ℹ️ No changes to commit"
213+
else
214+
echo "has_changes=true" >> $GITHUB_OUTPUT
215+
216+
pr_number="${{ steps.check_pr_commit.outputs.pr_number }}"
217+
pr_title="${{ steps.get_pr_info.outputs.pr_title }}"
218+
pr_author="${{ steps.get_pr_info.outputs.pr_author }}"
219+
pr_url="${{ steps.get_pr_info.outputs.pr_url }}"
220+
commit_sha="${{ steps.check_pr_commit.outputs.commit_sha }}"
221+
222+
# Create commit message with reverse sync marker
223+
cat > commit_message.txt << EOF
224+
[reverse-sync] Sync documentation changes from devops-pipelines-docs PR #$pr_number
225+
226+
This commit incorporates changes from external contributors to the devops-pipelines-docs repository.
227+
228+
📋 Original PR Details:
229+
- Title: $pr_title
230+
- Author: $pr_author
231+
- URL: $pr_url
232+
- Commit: $commit_sha
233+
234+
🔄 This is a reverse sync commit - it should not trigger forward sync.
235+
EOF
236+
237+
git commit -F commit_message.txt
238+
rm commit_message.txt
239+
240+
echo "✅ Changes committed successfully"
241+
fi
242+
243+
- name: Push branch and create PR
244+
if: steps.check_pr_commit.outputs.is_pr_commit == 'true' && steps.check_pr_commit.outputs.skip_sync == 'false' && steps.get_changes.outputs.has_doc_changes == 'true' && steps.commit_changes.outputs.has_changes == 'true'
245+
run: |
246+
cd target-docs
247+
branch_name="${{ steps.create_branch.outputs.branch_name }}"
248+
pr_base_ref="${{ steps.get_pr_info.outputs.pr_base_ref }}"
249+
pr_number="${{ steps.check_pr_commit.outputs.pr_number }}"
250+
pr_title="${{ steps.get_pr_info.outputs.pr_title }}"
251+
pr_author="${{ steps.get_pr_info.outputs.pr_author }}"
252+
pr_url="${{ steps.get_pr_info.outputs.pr_url }}"
253+
254+
# Push the branch
255+
git push origin "$branch_name"
256+
257+
# Create PR body with proper JSON escaping
258+
pr_body=$(cat << 'EOF'
259+
### 🔄 Reverse Sync from devops-pipelines-docs
260+
261+
This PR incorporates documentation changes from external contributors to the devops-pipelines-docs repository.
262+
263+
#### Original PR Details
264+
- **Repository**: danielfbm/devops-pipelines-docs
265+
- **PR**: #%PR_NUMBER% - %PR_TITLE%
266+
- **Author**: @%PR_AUTHOR%
267+
- **URL**: %PR_URL%
268+
269+
#### Changes
270+
This PR includes changes to documentation files that were contributed by external contributors to the public devops-pipelines-docs repository.
271+
272+
#### Important Notes
273+
- ⚠️ This PR contains the `[reverse-sync]` marker to prevent infinite sync loops
274+
- ✅ Once merged, this will NOT trigger a forward sync back to devops-pipelines-docs
275+
- 🔍 Please review the changes to ensure they align with internal documentation standards
276+
277+
---
278+
*This PR was automatically created by the reverse sync workflow.*
279+
EOF)
280+
281+
# Replace placeholders in the PR body
282+
pr_body=$(echo "$pr_body" | sed "s/%PR_NUMBER%/$pr_number/g")
283+
pr_body=$(echo "$pr_body" | sed "s/%PR_TITLE%/$pr_title/g")
284+
pr_body=$(echo "$pr_body" | sed "s/%PR_AUTHOR%/$pr_author/g")
285+
pr_body=$(echo "$pr_body" | sed "s|%PR_URL%|$pr_url|g")
286+
287+
# Create JSON payload with proper escaping
288+
json_payload=$(jq -n \
289+
--arg title "[reverse-sync] Documentation changes from devops-pipelines-docs PR #$pr_number" \
290+
--arg head "$branch_name" \
291+
--arg base "$pr_base_ref" \
292+
--arg body "$pr_body" \
293+
'{title: $title, head: $head, base: $base, body: $body}')
294+
295+
# Create the PR using GitHub API
296+
curl -X POST \
297+
-H "Authorization: token ${{ secrets.GH_TOKEN }}" \
298+
-H "Accept: application/vnd.github.v3+json" \
299+
-H "Content-Type: application/json" \
300+
https://api.github.com/repos/${{env.TARGET_REPO}}/pulls \
301+
-d "$json_payload"
302+
303+
- name: Create workflow summary
304+
run: |
305+
if [ "${{ steps.check_pr_commit.outputs.is_pr_commit }}" == "false" ]; then
306+
echo "## ℹ️ Not a PR Commit" >> $GITHUB_STEP_SUMMARY
307+
echo "" >> $GITHUB_STEP_SUMMARY
308+
echo "This commit was not created from a merged PR, so no reverse sync was performed." >> $GITHUB_STEP_SUMMARY
309+
elif [ "${{ steps.check_pr_commit.outputs.skip_sync }}" == "true" ]; then
310+
echo "## 🤖 Sync Bot Commit - Reverse Sync Skipped" >> $GITHUB_STEP_SUMMARY
311+
echo "" >> $GITHUB_STEP_SUMMARY
312+
echo "This commit was created by the sync bot, so reverse sync was skipped to prevent loops." >> $GITHUB_STEP_SUMMARY
313+
elif [ "${{ steps.get_changes.outputs.has_doc_changes }}" == "false" ]; then
314+
echo "## ℹ️ No Documentation Changes" >> $GITHUB_STEP_SUMMARY
315+
echo "" >> $GITHUB_STEP_SUMMARY
316+
echo "This commit didn't contain any documentation changes, so no reverse sync was needed." >> $GITHUB_STEP_SUMMARY
317+
elif [ "${{ steps.commit_changes.outputs.has_changes }}" == "false" ]; then
318+
echo "## ℹ️ No Changes to Sync" >> $GITHUB_STEP_SUMMARY
319+
echo "" >> $GITHUB_STEP_SUMMARY
320+
echo "The documentation changes were already present in target-docs." >> $GITHUB_STEP_SUMMARY
321+
else
322+
echo "## 🎉 Reverse Sync Completed" >> $GITHUB_STEP_SUMMARY
323+
echo "" >> $GITHUB_STEP_SUMMARY
324+
echo "Successfully created a PR in target-docs with the documentation changes." >> $GITHUB_STEP_SUMMARY
325+
echo "" >> $GITHUB_STEP_SUMMARY
326+
echo "### Details:" >> $GITHUB_STEP_SUMMARY
327+
echo "- **Source PR**: #${{ steps.check_pr_commit.outputs.pr_number }} by @${{ steps.get_pr_info.outputs.pr_author }}" >> $GITHUB_STEP_SUMMARY
328+
echo "- **Branch**: ${{ steps.create_branch.outputs.branch_name }}" >> $GITHUB_STEP_SUMMARY
329+
echo "- **Base ref**: ${{ steps.get_pr_info.outputs.pr_base_ref }}" >> $GITHUB_STEP_SUMMARY
330+
echo "- **Target repository**: ${{env.TARGET_REPO}}" >> $GITHUB_STEP_SUMMARY
331+
fi

0 commit comments

Comments
 (0)