@@ -13,22 +13,27 @@ jobs:
1313 contents : write
1414 pull-requests : write
1515
16+ env :
17+ BASE_BRANCH : sagan/docs-sync-test # change to develop later if needed
18+ SYNC_BRANCH_PREFIX : chore/sync-sdk-docs
19+
1620 steps :
1721 - name : Checkout delight-ai-docs
1822 uses : actions/checkout@v4
1923 with :
20- ref : sagan/docs-sync-test
24+ ref : ${{ env.BASE_BRANCH }}
2125 token : ${{ secrets.BOT_TOKEN }}
2226
2327 - name : Checkout delight-ai-agent
2428 uses : actions/checkout@v4
2529 with :
2630 repository : sendbird/delight-ai-agent
27- ref : sagan/docs-sync-test
31+ ref : sagan/docs-sync-test # or main in production
2832 path : delight-ai-agent
2933 token : ${{ secrets.BOT_TOKEN }}
3034
3135 - name : Sync mapped files from delight-ai-agent to sdk-docs
36+ id : sync-files
3237 run : |
3338 python << 'EOF'
3439 import shutil
@@ -66,51 +71,165 @@ jobs:
6671 "js/react/TEMPLATE-LAYOUT-CUSTOMIZATION-GUIDE.md": "sdk-docs/react-npm/template-based-layout-component-customization-guide.md",
6772 }
6873
69- updated_files = []
74+ updated_targets = []
7075
7176 for src, dst in MAPPING.items():
7277 src_path = agent_root / src
7378 dst_path = docs_root / dst
7479
75- if src_path.is_file():
76- dst_path.parent.mkdir(parents=True, exist_ok=True)
77- shutil.copy2(src_path, dst_path)
78- updated_files.append(dst)
79- print(f"Copied {src} -> {dst}")
80- else:
80+ if not src_path.is_file():
8181 print(f"[WARN] Missing source: {src}")
82+ continue
83+
84+ dst_path.parent.mkdir(parents=True, exist_ok=True)
85+ shutil.copy2(src_path, dst_path)
86+ updated_targets.append(str(dst_path))
87+ print(f"Copied {src} -> {dst}")
88+
89+ # Write updated targets for later steps
90+ with open("updated_files.txt", "w", encoding="utf-8") as f:
91+ f.write("\n".join(updated_targets))
8292
83- if not updated_files :
84- print("No updates detected.")
93+ if not updated_targets :
94+ print("No updates detected (no mapped files copied) .")
8595 EOF
8696
87- - name : Create pull request
88- id : cpr
89- uses : peter-evans/create-pull-request@v6
90- with :
91- token : ${{ secrets.BOT_TOKEN }}
92- commit-message : " chore: sync SDK docs from delight-ai-agent"
93- title : " chore: sync SDK docs from delight-ai-agent"
94- body : |
95- Automated sync from **delight-ai-agent → delight-ai-docs**.
96- base : sagan/docs-sync-test
97- branch : chore/sync-sdk-docs
98- branch-suffix : timestamp
99- labels : |
100- docs
101- automated-pr
102-
103- - name : Approve pull request
104- if : steps.cpr.outputs.pull-request-number != ''
105- uses : juliangruber/approve-pull-request-action@v1
106- with :
107- github-token : ${{ secrets.APPROVE_BOT_TOKEN }}
108- number : ${{ steps.cpr.outputs.pull-request-number }}
109-
110- # Optional auto-merge (enable if desired)
111- # - name: Merge PR
112- # if: steps.cpr.outputs.pull-request-number != ''
113- # uses: peter-evans/enable-pull-request-automerge@v3
114- # with:
115- # token: ${{ secrets.APPROVE_BOT_TOKEN }}
116- # pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
97+ - name : Commit changes (one commit per changed file)
98+ id : commit-changes
99+ run : |
100+ # If the file doesn't exist or is empty, nothing to do
101+ if [ ! -f updated_files.txt ] || [ ! -s updated_files.txt ]; then
102+ echo "No updated files recorded. Skipping commit and PR."
103+ echo "skip_pr=true" >> "$GITHUB_OUTPUT"
104+ exit 0
105+ fi
106+
107+ git config user.name "docs-sync-bot"
108+ git config user.email "docs-sync-bot@users.noreply.github.com"
109+
110+ # We'll track which files we *actually* committed (have a diff)
111+ > committed_files.txt
112+
113+ echo "Creating commits..."
114+ while IFS= read -r file; do
115+ if [ -z "$file" ]; then
116+ continue
117+ fi
118+
119+ # If there is no diff for this file, skip committing it
120+ if git diff --quiet -- "$file"; then
121+ echo "No changes in $file, skipping commit."
122+ continue
123+ fi
124+
125+ echo "Committing $file"
126+ git add "$file"
127+ git commit -m "[Sync] update $file"
128+ echo "$file" >> committed_files.txt
129+ done < updated_files.txt
130+
131+ # Clean up helper file so it doesn't accidentally get committed
132+ rm -f updated_files.txt
133+
134+ # If we didn't commit anything, skip PR creation
135+ if [ ! -s committed_files.txt ]; then
136+ echo "No commits were created. Skipping PR."
137+ echo "skip_pr=true" >> "$GITHUB_OUTPUT"
138+ # Leave committed_files.txt for debugging if needed
139+ exit 0
140+ fi
141+
142+ echo "Building PR body..."
143+ {
144+ echo "Automated sync from **delight-ai-agent → delight-ai-docs**."
145+ echo ""
146+ echo "Updated files:"
147+ while IFS= read -r file; do
148+ if [ -n "$file" ]; then
149+ echo "- \`$file\`"
150+ fi
151+ done < committed_files.txt
152+ } > PR_BODY.md
153+
154+ echo "skip_pr=false" >> "$GITHUB_OUTPUT"
155+
156+ - name : Push branch and create PR via API
157+ id : push-and-pr
158+ if : steps.commit-changes.outputs.skip_pr == 'false'
159+ env :
160+ GITHUB_TOKEN : ${{ secrets.BOT_TOKEN }}
161+ REPO : sendbird/delight-ai-docs
162+ BASE_BRANCH : ${{ env.BASE_BRANCH }}
163+ SYNC_BRANCH : ${{ env.SYNC_BRANCH_PREFIX }}-${{ github.run_id }}
164+ run : |
165+ set -e
166+
167+ echo "Pushing branch $SYNC_BRANCH"
168+ # --force just in case a branch with the same name exists from a previous run
169+ git push --force origin HEAD:$SYNC_BRANCH
170+
171+ echo "Creating PR..."
172+ PR_DATA=$(python - << 'EOF'
173+ import json, os
174+ with open("PR_BODY.md", "r", encoding="utf-8") as f:
175+ body = f.read()
176+ data = {
177+ "title": "[SDK] updated from delight-ai-agent",
178+ "body": body,
179+ "head": os.environ["SYNC_BRANCH"],
180+ "base": os.environ["BASE_BRANCH"],
181+ }
182+ print(json.dumps(data))
183+ EOF
184+ )
185+
186+ RESPONSE=$(curl -sS -w "%{http_code}" -o pr_response.json \
187+ -X POST \
188+ -H "Authorization: Bearer $GITHUB_TOKEN" \
189+ -H "Accept: application/vnd.github+json" \
190+ "https://api.github.com/repos/$REPO/pulls" \
191+ -d "$PR_DATA")
192+
193+ echo "GitHub API status: $RESPONSE"
194+ echo "PR API response:"
195+ cat pr_response.json
196+
197+ if [ "$RESPONSE" -lt 200 ] || [ "$RESPONSE" -ge 300 ]; then
198+ echo "Failed to create PR (status $RESPONSE)."
199+ exit 1
200+ fi
201+
202+ PR_NUMBER=$(python - << 'EOF'
203+ import json
204+ with open("pr_response.json", "r", encoding="utf-8") as f:
205+ data = json.load(f)
206+ print(data.get("number", ""))
207+ EOF
208+ )
209+
210+ if [ -z "$PR_NUMBER" ]; then
211+ echo "PR number missing in API response."
212+ exit 1
213+ fi
214+
215+ echo "Created PR #$PR_NUMBER"
216+ echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
217+
218+ - name : Approve pull request via API
219+ if : steps.push-and-pr.outputs.pr_number != '' && steps.commit-changes.outputs.skip_pr == 'false'
220+ env :
221+ APPROVE_TOKEN : ${{ secrets.APPROVE_BOT_TOKEN }}
222+ REPO : sendbird/delight-ai-docs
223+ PR_NUMBER : ${{ steps.push-and-pr.outputs.pr_number }}
224+ run : |
225+ echo "Approving PR #$PR_NUMBER"
226+ RESP=$(curl -sS -w "%{http_code}" -o approve_response.json \
227+ -X POST \
228+ -H "Authorization: Bearer $APPROVE_TOKEN" \
229+ -H "Accept: application/vnd.github+json" \
230+ "https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/reviews" \
231+ -d '{"event":"APPROVE"}')
232+
233+ echo "Approve API status: $RESP"
234+ echo "Approve API response:"
235+ cat approve_response.json
0 commit comments