1+ name : DevConfig Comment Handler
2+
3+ on :
4+ issue_comment :
5+ types : [created]
6+
7+ permissions :
8+ contents : write
9+ pull-requests : write
10+ issues : write
11+
12+ jobs :
13+ check-comment :
14+ runs-on : ubuntu-latest
15+ if : contains(github.event.comment.body, '/add-devconfig') || contains(github.event.comment.body, '/delete-devconfig') || contains(github.event.comment.body, '/amend-devconfig')
16+ outputs :
17+ should_process : ${{ steps.check.outputs.should_process }}
18+ pr_number : ${{ github.event.issue.number }}
19+ has_custom_json : ${{ steps.extract-json.outputs.has_custom_json }}
20+ custom_json : ${{ steps.extract-json.outputs.custom_json }}
21+ command : ${{ steps.determine-command.outputs.command }}
22+ steps :
23+ - name : Check if comment is on a PR
24+ id : check
25+ run : |
26+ if [ "${{ github.event.issue.pull_request != '' }}" = "true" ]; then
27+ echo "should_process=true" >> $GITHUB_OUTPUT
28+ echo "Comment is on PR #${{ github.event.issue.number }}"
29+ else
30+ echo "should_process=false" >> $GITHUB_OUTPUT
31+ echo "Comment is not on a PR"
32+ fi
33+
34+ - name : Determine command
35+ id : determine-command
36+ if : steps.check.outputs.should_process == 'true'
37+ run : |
38+ # Save the comment to a file to avoid shell interpretation issues
39+ echo '${{ github.event.comment.body }}' > comment_raw.txt
40+
41+ # Convert Windows line endings to Unix and extract first line
42+ tr -d '\r' < comment_raw.txt | head -n 1 > first_line.txt
43+ FIRST_LINE=$(cat first_line.txt)
44+
45+ echo "First line of comment: $FIRST_LINE"
46+
47+ if [[ "$FIRST_LINE" == "/add-devconfig"* ]]; then
48+ echo "command=add" >> $GITHUB_OUTPUT
49+ echo "Command: add-devconfig"
50+ elif [[ "$FIRST_LINE" == "/delete-devconfig"* ]]; then
51+ echo "command=delete" >> $GITHUB_OUTPUT
52+ echo "Command: delete-devconfig"
53+ elif [[ "$FIRST_LINE" == "/amend-devconfig"* ]]; then
54+ echo "command=amend" >> $GITHUB_OUTPUT
55+ echo "Command: amend-devconfig"
56+ else
57+ echo "No valid command found in first line"
58+ exit 1
59+ fi
60+
61+ - name : Extract custom JSON
62+ id : extract-json
63+ if : steps.check.outputs.should_process == 'true' && (steps.determine-command.outputs.command == 'add' || steps.determine-command.outputs.command == 'amend')
64+ run : |
65+ # Save the comment to a file to avoid shell interpretation issues
66+ echo '${{ github.event.comment.body }}' > comment.txt
67+
68+ # Convert Windows line endings to Unix
69+ tr -d '\r' < comment.txt > comment_unix.txt
70+
71+ # Check if the comment contains JSON
72+ if grep -q '```json' comment_unix.txt; then
73+ echo "Found JSON block in comment"
74+
75+ # Extract everything between ```json and ``` markers
76+ # Use sed to extract the content between markers
77+ sed -n '/```json/,/```/p' comment_unix.txt | sed '1d;$d' > extracted_json.txt
78+
79+ if [ -s extracted_json.txt ]; then
80+ echo "has_custom_json=true" >> $GITHUB_OUTPUT
81+ echo "custom_json<<EOF" >> $GITHUB_OUTPUT
82+ cat extracted_json.txt >> $GITHUB_OUTPUT
83+ echo "EOF" >> $GITHUB_OUTPUT
84+ echo "JSON content extracted successfully"
85+ else
86+ echo "has_custom_json=false" >> $GITHUB_OUTPUT
87+ echo "No JSON content found between markers"
88+ fi
89+ else
90+ echo "has_custom_json=false" >> $GITHUB_OUTPUT
91+ echo "No JSON block found in comment"
92+ fi
93+
94+ - name : Add processing comment to PR
95+ if : steps.check.outputs.should_process == 'true'
96+ uses : actions/github-script@v7
97+ with :
98+ github-token : ${{ secrets.GITHUB_TOKEN }}
99+ script : |
100+ const command = '${{ steps.determine-command.outputs.command }}';
101+ let message = '';
102+
103+ if (command === 'add') {
104+ message = '⏳ Processing `/add-devconfig` command... DevConfig file is being generated and will be added to this PR shortly.';
105+ } else if (command === 'delete') {
106+ message = '⏳ Processing `/delete-devconfig` command... DevConfig file will be removed from this PR shortly.';
107+ } else if (command === 'amend') {
108+ message = '⏳ Processing `/amend-devconfig` command... DevConfig file is being updated in this PR.';
109+ }
110+
111+ await github.rest.issues.createComment({
112+ issue_number: ${{ github.event.issue.number }},
113+ owner: context.repo.owner,
114+ repo: context.repo.repo,
115+ body: message
116+ });
117+
118+ process-comment :
119+ needs : check-comment
120+ if : needs.check-comment.outputs.should_process == 'true'
121+ runs-on : ubuntu-latest
122+ steps :
123+ - name : Checkout repository
124+ uses : actions/checkout@v4
125+ with :
126+ fetch-depth : 0
127+ token : ${{ secrets.GITHUB_TOKEN }}
128+
129+ - name : Get PR details
130+ id : pr-details
131+ run : |
132+ PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}"
133+ echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
134+
135+ # Get PR head ref
136+ PR_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
137+ "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER")
138+ HEAD_REF=$(echo "$PR_DATA" | jq -r .head.ref)
139+ echo "pr_head_ref=$HEAD_REF" >> $GITHUB_OUTPUT
140+
141+ echo "PR Number: $PR_NUMBER"
142+ echo "PR Head Ref: $HEAD_REF"
143+
144+ - name : Checkout PR branch
145+ run : |
146+ git fetch origin
147+ git checkout ${{ steps.pr-details.outputs.pr_head_ref }}
148+
149+ - name : Add DevConfig file
150+ id : add-devconfig
151+ if : needs.check-comment.outputs.command == 'add'
152+ run : |
153+ # Create DevConfig directory
154+ mkdir -p ./generator/.DevConfigs
155+
156+ # Use PR number for the filename
157+ PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}"
158+ DEVCONFIG_FILE="./generator/.DevConfigs/pr-${PR_NUMBER}.json"
159+
160+ # Check if custom content was provided
161+ if [ "${{ needs.check-comment.outputs.has_custom_json }}" == "true" ]; then
162+ # Use the provided content
163+ echo '${{ needs.check-comment.outputs.custom_json }}' > $DEVCONFIG_FILE
164+ echo "Using custom DevConfig content from comment"
165+ else
166+ # Generate content based on detected changes
167+ echo "Generating DevConfig content based on detected changes"
168+
169+ # Get PR title as the changelog message
170+ PR_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
171+ "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER")
172+ COMMIT_MSG=$(echo "$PR_DATA" | jq -r .title)
173+
174+ # If PR title is empty, fall back to the latest commit message
175+ if [ -z "$COMMIT_MSG" ]; then
176+ COMMIT_MSG=$(git log -1 --pretty=%B)
177+ fi
178+
179+ # Start building the DevConfig JSON
180+ echo "{" > $DEVCONFIG_FILE
181+
182+ # Check for core changes
183+ CORE_CHANGES=$(git diff --name-only origin/main... | grep -v "^sdk/src/Services/" | wc -l || echo 0)
184+ if [ $CORE_CHANGES -gt 0 ]; then
185+ echo ' "core": {' >> $DEVCONFIG_FILE
186+ echo ' "changeLogMessages": [' >> $DEVCONFIG_FILE
187+ echo " \"$COMMIT_MSG\"" >> $DEVCONFIG_FILE
188+ echo ' ],' >> $DEVCONFIG_FILE
189+ echo ' "type": "patch",' >> $DEVCONFIG_FILE
190+ echo ' "updateMinimum": true' >> $DEVCONFIG_FILE
191+ echo ' }' >> $DEVCONFIG_FILE
192+ fi
193+
194+ # Check for service changes
195+ SERVICE_CHANGES=$(git diff --name-only origin/main... | grep "^sdk/src/Services/" | wc -l || echo 0)
196+ if [ $SERVICE_CHANGES -gt 0 ]; then
197+ # If we added a core section, we need a comma
198+ if [ $CORE_CHANGES -gt 0 ]; then
199+ echo ',' >> $DEVCONFIG_FILE
200+ fi
201+
202+ echo ' "services": [' >> $DEVCONFIG_FILE
203+
204+ # Extract service names
205+ SERVICES=$(git diff --name-only origin/main... | grep "^sdk/src/Services/" | cut -d'/' -f4 | sort | uniq | jq -R -s -c 'split("\n") | map(select(length > 0))')
206+ SERVICES_ARRAY=$(echo $SERVICES | jq -c '.')
207+
208+ FIRST=true
209+ echo $SERVICES_ARRAY | jq -c '.[]' | while read -r SERVICE; do
210+ # Remove quotes from service name
211+ SERVICE=$(echo $SERVICE | tr -d '"')
212+
213+ if [ "$FIRST" == "true" ]; then
214+ FIRST=false
215+ else
216+ echo ',' >> $DEVCONFIG_FILE
217+ fi
218+
219+ echo ' {' >> $DEVCONFIG_FILE
220+ echo " \"serviceName\": \"$SERVICE\"," >> $DEVCONFIG_FILE
221+ echo ' "type": "patch",' >> $DEVCONFIG_FILE
222+ echo ' "changeLogMessages": [' >> $DEVCONFIG_FILE
223+ echo " \"$COMMIT_MSG\"" >> $DEVCONFIG_FILE
224+ echo ' ]' >> $DEVCONFIG_FILE
225+ echo ' }' >> $DEVCONFIG_FILE
226+ done
227+
228+ echo ' ]' >> $DEVCONFIG_FILE
229+ fi
230+
231+ echo "}" >> $DEVCONFIG_FILE
232+ fi
233+
234+ # Format the JSON for better readability
235+ cat $DEVCONFIG_FILE | jq . > ${DEVCONFIG_FILE}.formatted || cp $DEVCONFIG_FILE ${DEVCONFIG_FILE}.formatted
236+ mv ${DEVCONFIG_FILE}.formatted $DEVCONFIG_FILE
237+
238+ echo "Applied DevConfig file:"
239+ cat $DEVCONFIG_FILE
240+
241+ - name : Amend DevConfig file
242+ id : amend-devconfig
243+ if : needs.check-comment.outputs.command == 'amend' && needs.check-comment.outputs.has_custom_json == 'true'
244+ run : |
245+ # Create DevConfig directory if it doesn't exist
246+ mkdir -p ./generator/.DevConfigs
247+
248+ # Use PR number for the filename
249+ PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}"
250+ DEVCONFIG_FILE="./generator/.DevConfigs/pr-${PR_NUMBER}.json"
251+
252+ # Use the provided content
253+ echo '${{ needs.check-comment.outputs.custom_json }}' > $DEVCONFIG_FILE
254+ echo "Using custom DevConfig content from comment"
255+
256+ # Format the JSON for better readability
257+ cat $DEVCONFIG_FILE | jq . > ${DEVCONFIG_FILE}.formatted || cp $DEVCONFIG_FILE ${DEVCONFIG_FILE}.formatted
258+ mv ${DEVCONFIG_FILE}.formatted $DEVCONFIG_FILE
259+
260+ echo "Updated DevConfig file:"
261+ cat $DEVCONFIG_FILE
262+
263+ - name : Delete DevConfig file
264+ id : delete-devconfig
265+ if : needs.check-comment.outputs.command == 'delete'
266+ run : |
267+ # Use PR number for the filename
268+ PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}"
269+ DEVCONFIG_FILE="./generator/.DevConfigs/pr-${PR_NUMBER}.json"
270+
271+ if [ -f "$DEVCONFIG_FILE" ]; then
272+ rm "$DEVCONFIG_FILE"
273+ echo "DevConfig file deleted: $DEVCONFIG_FILE"
274+ else
275+ echo "DevConfig file not found: $DEVCONFIG_FILE"
276+ exit 1
277+ fi
278+
279+ - name : Commit and push changes
280+ run : |
281+ git config --global user.name "GitHub Action"
282+ git config --global user.email "[email protected] " 283+
284+ COMMAND="${{ needs.check-comment.outputs.command }}"
285+ PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}"
286+
287+ if [ "$COMMAND" == "add" ]; then
288+ git add ./generator/.DevConfigs/pr-${PR_NUMBER}.json
289+ git commit -m "Add DevConfig file for PR #${PR_NUMBER}"
290+ elif [ "$COMMAND" == "amend" ]; then
291+ git add ./generator/.DevConfigs/pr-${PR_NUMBER}.json
292+ git commit -m "Update DevConfig file for PR #${PR_NUMBER}"
293+ elif [ "$COMMAND" == "delete" ]; then
294+ git add -A ./generator/.DevConfigs/
295+ git commit -m "Remove DevConfig file for PR #${PR_NUMBER}"
296+ fi
297+
298+ git push origin ${{ steps.pr-details.outputs.pr_head_ref }}
299+
300+ - name : Add confirmation comment to PR
301+ uses : actions/github-script@v7
302+ with :
303+ github-token : ${{ secrets.GITHUB_TOKEN }}
304+ script : |
305+ const command = '${{ needs.check-comment.outputs.command }}';
306+ let message = '';
307+
308+ if (command === 'add') {
309+ message = '✅ DevConfig file has been added to this PR.';
310+ } else if (command === 'delete') {
311+ message = '✅ DevConfig file has been removed from this PR.';
312+ } else if (command === 'amend') {
313+ message = '✅ DevConfig file has been updated in this PR.';
314+ }
315+
316+ await github.rest.issues.createComment({
317+ issue_number: ${{ needs.check-comment.outputs.pr_number }},
318+ owner: context.repo.owner,
319+ repo: context.repo.repo,
320+ body: message
321+ });
0 commit comments