-
-
Notifications
You must be signed in to change notification settings - Fork 83.2k
707 lines (582 loc) Β· 35.3 KB
/
auto-pr-merge.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
name: Auto-merge PRs
on:
pull_request_target:
types: [opened, synchronize, reopened]
paths:
- "Contributors.md" # <- only run if only contributors file changed
jobs:
# Job for checking all modified files PR
check-modified-files-and-content:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
outputs:
pr_files: ${{ steps.get_pr_files.outputs.pr_files }}
files_changed: ${{ steps.check_num_of_files_modified_step.outputs.files_changed }}
is_only_contributors_file_changed: ${{ steps.check_num_of_files_modified_step.outputs.only_contributors }}
is_only_one_line_modified: ${{ steps.check_num_of_lines_modified_step.outputs.only_one_line_edited }}
contributors_md_content: ${{ steps.check_num_of_lines_modified_step.outputs.contributors_md_content }}
steps:
- name: Checkout to PR branch
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 2
- name: Get PR files
id: get_pr_files
run: |
# Get a list of files changed in the pull request
PR_FILES=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files")
# Trim leading and trailing whitespaces
PR_FILES=$(echo $PR_FILES )
# set the output
echo "pr_files=$PR_FILES" >> $GITHUB_OUTPUT
# set the env for this job
echo "pr_files=$PR_FILES" >> $GITHUB_ENV
# Check if the pull request only modifies the Contributors.md file
- name: Check only Contributors.md file modified
id: check_num_of_files_modified_step
uses: actions/github-script@v5
with:
script: |
async function run() {
try {
// Extract the filenames from the API response
const filesChanged = JSON.parse(process.env.pr_files);
const filenames = filesChanged.map(file => file.filename);
// Check if only 'Contributors.md' is in the list of changed files
const isOnlyContributorsFileChanged = filenames.length === 1 && filenames[0] === 'Contributors.md';
// file names stored in output
core.setOutput('files_changed', filenames);
// file names stored in env
core.exportVariable('files_changed', filenames);
if (isOnlyContributorsFileChanged) {
// Find the 'Contributors.md' file in the response
const contributorsFile = filesChanged.find(file => file.filename === 'Contributors.md');
// Extract the additions, changes, and deletions fields
const additions = contributorsFile.additions;
core.exportVariable('additions', additions);
const changes = contributorsFile.changes;
core.exportVariable('changes', changes);
const deletions = contributorsFile.deletions;
core.exportVariable('deletions', deletions);
// Extracting the patch field (content which are added)
const patch_text = contributorsFile.patch;
core.exportVariable('patched_content', patch_text);
// core.setOutput('patched_content', patch_text);
console.log(`additions=${additions}`);
console.log(`changes=${changes}`);
console.log(`deletions=${deletions}`);
console.log(`patched_content=${patch_text}`);
}
// Set output and environment variable
core.setOutput('only_contributors', isOnlyContributorsFileChanged);
core.exportVariable('only_contributors', isOnlyContributorsFileChanged);
} catch (error) {
core.setFailed(error.message);
}
}
run();
# Run only if there only Contributors.md file modified in the PR
- name: Check only one line modified in Contributors.md
id: check_num_of_lines_modified_step
if: env.only_contributors == 'true'
uses: actions/github-script@v5
with:
script: |
// Get the environment variables
const numLineAdditions = process.env.num_line_additions;
const numLineChanges = process.env.num_line_changes;
const numLineDeletions = process.env.num_line_deletions;
const patchedContent = process.env.patched_content;
const is_one_line_changed = ((numLineAdditions === '1' && numLineChanges === '1' && numLineDeletions === '0') || (numLineAdditions === '0' && numLineChanges === '1' && numLineDeletions === '1'));
// Check only one line added, or only one line changed, or only one line deleted and one line added which makes 2 number of changes in Contributors.md file
if (is_one_line_changed) {
// Get the patch content from env variable
const contributorsMdContent = patchedContent;
// This command uses a regular expression to extract lines from the variable 'contributorsMdContent' that were added in a diff.
const onlyAddedContents = contributorsMdContent.split('\n').filter(line => line.startsWith('+')).map(line => line.substring(1));
// Set the output
core.setOutput('contributors_md_content', onlyAddedContents.join('\n'));
}
// More than one line was edited in Contributors.md file
core.setOutput('only_one_line_edited', is_one_line_changed);
core.exportVariable('only_one_line_edited', is_one_line_changed);
# run: |
# # Extract the additions and changes fields from the API response
# # ADDITIONS=$(echo $pr_files_url | jq '.[] | select(.filename == "Contributors.md") | .additions')
# # CHANGES=$(echo $pr_files_url | jq '.[] | select(.filename == "Contributors.md") | .changes')
# # DELETIONS=$(echo $pr_files_url | jq '.[] | select(.filename == "Contributors.md") | .deletions')
# ADDITIONS=$(echo $num_line_additions)
# CHANGES=$(echo $num_line_changes)
# DELETIONS=$(echo $num_line_deletions)
# # check only one line added, or only one line changed, or only one line deleted and one line added which makes 2 number of changes in Contributors.md file
# if [[ ( $ADDITIONS -eq 1 && $CHANGES -eq 1 && $DELETIONS -eq 0 ) || ( $ADDITIONS -eq 0 && $CHANGES -eq 1 && $DELETIONS -eq 1 ) ]]; then
# # add to job output
# echo "only_one_line_edited=true" >> "$GITHUB_OUTPUT"
# # env variable
# echo "only_one_line_edited=true" >> $GITHUB_ENV
# # toJSON convert to JSON and jq -r get the value from "patch" as raw
# # CONTRIBUTORS_MD_CONTENT=$(echo ${{ toJSON(env.pr_files ) }} | jq -r '.[].patch')
# #Get the patch content from env variable
# CONTRIBUTORS_MD_CONTENT=$(echo $patched_content);
# echo "$CONTRIBUTORS_MD_CONTENT"
# echo $CONTRIBUTORS_MD_CONTENT
# # This command uses 'awk' to extract lines from the variable 'CONTRIBUTORS_MD_CONTENT' that were added in a diff.
# # 'awk' processes each line as a separate record (due to 'BEGIN{RS="\\n"}').
# # It then matches lines starting with a '+' sign (corresponding to lines added in a diff) and prints each matching line, excluding the first character (which is the '+' sign).
# # only_added_contents=$(echo "$CONTRIBUTORS_MD_CONTENT" | awk 'BEGIN{RS="\\n"} /^\+/{print substr($0, 2)}')
# only_added_contents=$(echo ${{ toJSON(env.patched_content) }} | awk 'BEGIN{RS="\\n"} /^\+/{print substr($0, 2)}')
# echo $only_added_contents
# echo "$only_added_contents"
# echo "contributors_md_content=$only_added_contents" >> "$GITHUB_OUTPUT"
# else
# # More than one line was edited in Contributors.md file
# echo "only_one_line_edited=false" >> "$GITHUB_OUTPUT"
# echo "only_one_line_edited=false" >> $GITHUB_ENV
# fi
env:
pr_files_url: ${{env.pr_files}}
patched_content: ${{env.patched_content}}
num_line_additions: ${{env.additions}}
num_line_changes: ${{env.changes}}
num_line_deletions: ${{env.deletions}}
- name: Delete previous comments from the bot
uses: actions/github-script@v5
with:
script: |
try{
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
})
// get the comments by the bot
const bot_comments = comments.data.filter(comment => comment.user.login === 'github-actions[bot]')
// delete the comments from the bot
for (const comment of bot_comments) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id
})
}
} catch (error) {
console.error("Error deleting comments:", error.message);
}
# Post comment on PR when PR modifies multiple lines in Contributors.md file
- name: Post comment on PR when PR modifies multiple lines in Contributors.md file
if: env.only_contributors == 'true' && env.only_one_line_edited == 'false'
uses: actions/github-script@v5
with:
script: |
try{
const body = `Hello @${context.payload.pull_request.user.login}, Thank you for your contribution! We appreciate your effort and time.\n\n However, It seems that you replaced the existing line or made multiple changes in the Contributors.md file. \n\nPlease add only one new line to the Contributors.md file. For a better understanding, please refer to the [3rd bullet point in the Contributing Guidelines](https://github.com/firstcontributions/first-contributions/issues/35892) \n\n## How to fix this?\n\nYou can follow [this guide](https://www.gitkraken.com/learn/git/problems/undo-git-commit). \n\nIf you need any help, feel free to ask.\n\nKeep up the good work! π`
const review = {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
body: body,
event: 'REQUEST_CHANGES'
};
github.rest.pulls.createReview(review);
core.setFailed('Please only add one new line to the Contributors.md file. Please do not make multiple changes in the Contributors.md file');
} catch (error) {
console.error("Error posting comment:", error.message);
core.setFailed(error.message);
}
- name: Post comment on PR about required review
if: env.only_contributors != 'true'
uses: actions/github-script@v5
with:
script: |
try{
const filesChanged = JSON.parse(process.env.files_changed.trim());
const fileList = filesChanged.map(file => `- ${file}`).join('\n');
const body = `Hey @${context.payload.pull_request.user.login}, thank you for your pull request. This pull request contains changes in files which requires review. The following files were changed:\n\n${fileList}`;
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
} catch (error) {
console.error("Error posting comment:", error.message);
}
github-token: ${{ secrets.GITHUB_TOKEN }}
env:
files_changed: ${{ env.files_changed }}
# Add review label to PR if there are multiple files changed
- name: Add review label to PR
if: env.only_contributors != 'true'
uses: actions/github-script@v5
with:
script: |
try{
github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: [":woman_technologist: waiting for review"]
});
core.setFailed("PR needs review.")
} catch (error) {
console.error("Error adding label:", error.message);
core.setFailed(error.message);
}
github-token: ${{ secrets.GITHUB_TOKEN }}
# Job for checking offensive and malicious links
check-non-safe-content:
# job run after completion of this job
needs: check-modified-files-and-content
runs-on: ubuntu-latest
permissions:
# Only read permission to Github token
contents: read
pull-requests: write
outputs:
is_safe_contents: ${{ steps.check_inappropriate_words.outputs.is_safe_contents_text }}
# replaced_safe_contents: ${{ steps.check-non-safe-content.outputs.replaced_safe_contents }}
env:
get_pr_files: ${{needs.check-modified-files-and-content.outputs.pr_files }}
get_is_only_contributors_file_changed: ${{ needs.check-modified-files-and-content.outputs.is_only_contributors_file_changed }}
get_is_only_one_line_modified: ${{ needs.check-modified-files-and-content.outputs.is_only_one_line_modified }}
get_contributors_md_content: ${{ needs.check-modified-files-and-content.outputs.contributors_md_content }}
steps:
- name: Separate the texts and links from the content
id: separate_text_and_links_from_content
if: env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true'
run: |
echo $get_contributors_md_content
echo "$get_contributors_md_content"
#the regular expression ((https?:\/\/|www\.)[^\s]+|[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}) will match any word that starts with http://, https://, or www., or any word that looks like a domain name (one or more alphanumeric characters or hyphens, followed by a dot and two or more alphabetic characters).
only_added_links=$(echo $get_contributors_md_content | awk 'BEGIN{RS=" ";} /((https?:\/\/|www\.)[^\s]+|[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/{print}' | sed 's/[.,;]$//')
echo "Pirnt out of what is only_added_links"
echo $only_added_links
echo get_contributors_md_content
echo $get_contributors_md_content
echo "$get_contributors_md_content"
#alternative one (replace the grep to awk)
: << 'END_COMMENT'
The below code extracts all URLs from the variable 'get_contributors_md_content' and stores them in the array "only_added_links".
It then removes these URLs from "get_contributors_md_content".
The URLs can start with http://, https://, or www., or they can be a domain name (one or more alphanumeric characters or hyphens, followed by a dot and two or more alphabetic characters).
END_COMMENT
# initialise empty array
only_added_links=()
for word in $get_contributors_md_content; do
if [[ $word =~ ((https?:\/\/|www\.)[^\s]+|[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}) ]]; then
# add link to array
only_added_links+=("$word")
#store text and ignore link
only_text_content=${get_contributors_md_content//$word/}
else
# store text
only_text_content+="$word "
fi
done
# set the env variables
echo "only_added_texts=$only_text_content" >> $GITHUB_ENV
echo "only_added_links=${only_added_links[@]}" >> $GITHUB_ENV
#FIXME: There are no strict and reliable ways to check if the links are safe or not. The current implementation is using Google's Safe Browsing API to check if the links are safe. However, this is not a reliable solution as it only checks for the links that are already reported as malicious. We need to find a better solution for this.
# - name: Check if the links are safe
# id: check_if_links_are_safe
# with:
# script: |
# # check with the Google's Safe Browsing API
# try{
# const response = await fetch('https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${{ secrets.GOOGLE_SAFE_BROWSING_API_KEY }}', {
# method: 'POST',
# body: JSON.stringify({
# client: {
# clientId: 'first-contributions',
# clientVersion: '1.0.0'
# },
# threatInfo: {
# threatTypes: ['MALWARE', 'SOCIAL_ENGINEERING', 'UNWANTED_SOFTWARE', 'POTENTIALLY_HARMFUL_APPLICATION'],
# platformTypes: ['ANY_PLATFORM'],
# threatEntryTypes: ['URL'],
# "threatEntries": [
# for url in "${{ env.array_of_threat_links }}" {
# {
# "url": "${{ url }}",
# }
# }
# ]
# }
# })
# })
# const data = await response.json()
# // check if the response is empty
# if (data.matches.length === 0) {
# console.log('No threats found in the links')
# core.setOutput('is_safe_contents_text', true)
# } else {
# console.log('Threats found in the links')
# core.setOutput('is_safe_contents_link', false)
# }
# } catch (error) {
# console.error("Error checking links:", error.message);
# }
- name: Check inappropriate words in the texts
id: check_inappropriate_words
if: env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true'
uses: actions/github-script@ba6cf3fe7cf53f06998ea428adfe8f0da42d62fa
with:
script: |
async function checkProfanity() {
try {
const response = await fetch(`https://www.purgomalum.com/service/containsprofanity?text="${{ env.only_added_texts }}"`);
if (!response.ok) {
core.setFailed(`HTTP error! status: ${response.status}`);
}
const text = await response.text();
// check if the response is empty
if (text === 'true') {
console.log('Inappropriate words found in the texts');
core.setOutput('is_safe_contents_text', false);
core.exportVariable('is_safe_contents_text', 'false');
} else if (text === 'false') {
console.log('No inappropriate words found in the texts');
core.setOutput('is_safe_contents_text', true);
core.exportVariable('is_safe_contents_text', 'true');
} else {
throw new Error('Unexpected response: ' + text);
core.setFailed('Unexpected response: ' + text);
}
} catch (error) {
core.setFailed(error.message);
console.log(error.message);
}
}
checkProfanity();
# Post comment on offensive content PR about code of conduct
- name: Post comment on PR containing offensive content about code of conduct
if: env.is_safe_contents_text == 'false' && env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true'
uses: actions/github-script@v5
with:
script: |
try{
const body = `Hello @${context.payload.pull_request.user.login}, Thank you for your contribution! π\n\nWe appreciate your contribution to the project. However, we have a [code of conduct](https://github.com/firstcontributions/first-contributions/blob/main/CODE_OF_CONDUCT.md) that we expect all contributors to follow. \n\nPlease remove the offensive content from your pull request and then push your changes again. \n\nIf you need any help, feel free to ask.`
const review = {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
body: body,
event: 'REQUEST_CHANGES'
};
github.rest.pulls.createReview(review);
} catch (error) {
console.error("Error posting comment:", error.message);
core.setFailed(error.message);
}
# Close the PR if it contains offensive content
- name: Close PR if it contains offensive content
if: env.is_safe_contents_text == 'false' && env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true'
uses: actions/github-script@v5
with:
script: |
try{
github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
state: 'closed'
});
core.setFailed("status: closed PR due to offensive content contains!");
} catch (error) {
console.error("Error closing pull request:", error.message);
core.setFailed(error.message);
}
merge-pr:
# job run after completion of this job
needs: [check-modified-files-and-content, check-non-safe-content]
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
env:
get_pr_files: ${{needs.check-modified-files-and-content.outputs.pr_files }}
get_is_only_contributors_file_changed: ${{ needs.check-modified-files-and-content.outputs.is_only_contributors_file_changed }}
get_is_only_one_line_modified: ${{ needs.check-modified-files-and-content.outputs.is_only_one_line_modified }}
get_contributors_md_content: ${{ needs.check-modified-files-and-content.outputs.contributors_md_content }}
get_is_safe_contents: ${{ needs.check-non-safe-content.outputs.is_safe_contents }}
steps:
# Check out the repository code
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 2
#Check mergeability of PR
- name: Check mergeability
if: env.get_is_safe_contents == 'true' && env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true'
id: check_mergeability
uses: actions/github-script@v5
with:
script: |
const checkMergeability = async () => {
try {
const {owner, repo} = context.repo;
const pull_number = context.issue.number;
let mergeable;
let retries = 0;
const maxRetries = 3; // Maximum number of retries
// Keep checking the mergeability of the pull request until it is no longer null
while ((mergeable === null || mergeable === undefined ) && retries < maxRetries) {
const {data: pullRequest} = await github.rest.pulls.get({
owner,
repo,
pull_number
});
mergeable = pullRequest.mergeable;
if ((mergeable === null || mergeable === undefined )) {
// Wait 3 seconds before retrying the request
await new Promise(resolve => setTimeout(resolve, 3000));
retries++;
}
}
if(retries === maxRetries) {
console.log('Maximum number of retries exceeded. Mergeability is still null.')
core.setFailed('Maximum number of retries exceeded. Mergeability is still null.');
}
if (mergeable === true) {
core.setOutput('is_pr_mergeable', true);
core.exportVariable('is_pr_mergeable', true);
} else if (mergeable === false){
console.log('Not mergeable')
core.setOutput('is_pr_mergeable', false);
core.exportVariable('is_pr_mergeable', false);
} else {
console.log('Something when wrong while check mergeability of PR - merge status $mergeable');
core.setFailed("Unexpected status value of mergeability status - $mergeable");
}
} catch (error) {
console.error("Error checking mergeability:", error.message);
core.setFailed(error.message);
}
}
checkMergeability();
- name: Merge PR
id: merge_pr
if: env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true' && env.get_is_safe_contents == 'true' && env.is_pr_mergeable == 'true'
uses: actions/github-script@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
try{
// Attempt to merge the pull request using the squash method
const response = await github.rest.pulls.merge({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
merge_method: "squash"
});
console.log(response);
// Check if the merge was successful by checking the status code of the response
if (response.status === 200) {
core.setOutput('is_merged_successfully', true);
core.exportVariable('is_merged_successfully', true);
}
} catch (error) {
console.log(error);
let errMsg = "";
console.error("Error merging pull request:", error.message);
// set the output error message
core.setOutput('is_merged_successfully', false);
core.setOutput('merge_error_message', error.message);
core.exportVariable('is_merged_successfully', false);
core.setFailed(error.message);
}
# Post comment on merge conflict when PR only modifies single line in Contributors.md file
- name: Post comment on merge conflict
if: env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true' && env.get_is_safe_contents == 'true' && env.is_pr_mergeable == 'false'
uses: actions/github-script@v5
with:
script: |
try{
const body = `Hello @${context.payload.pull_request.user.login}, Thank you for your contribution! π\n\nUnfortunately, there is a merge conflict in your Pull Request. Please pull the latest changes from the main branch, [resolve the conflict](additional-material/git_workflow_scenarios/resolving-merge-conflicts.md), and then push your changes again.\n\nIf you need any help, feel free to ask.\n\nKeep up the good work! π`
const review = {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
body: body,
event: 'REQUEST_CHANGES'
};
github.rest.pulls.createReview(review);
} catch (error) {
console.error("Error posting comment:", error.message);
core.setFailed(error.message);
}
- name: Post success comment on PR
if: env.get_is_only_contributors_file_changed == 'true' && env.get_is_only_one_line_modified == 'true' && env.get_is_safe_contents == 'true' && env.is_merged_successfully == 'true' && env.is_pr_mergeable == 'true'
uses: actions/github-script@v5
with:
script: |
try{
const celebrationGifs = [
'https://c.tenor.com/ZCq4SwgCfxAAAAAC/snoopy-peanuts.gif',
'https://c.tenor.com/Z0ojZS2kpO0AAAAC/milk-and-mocha-happy.gif',
'https://c.tenor.com/LffD4a8ET9AAAAAC/heart-celebrate.gif',
'https://c.tenor.com/HJ0iSKwIG28AAAAC/yes-baby.gif',
'https://c.tenor.com/4blWuIh5MIYAAAAC/baby-yoda.gif',
'https://c.tenor.com/B_zYdea4l-4AAAAC/yay-minions.gif',
'https://media1.giphy.com/media/artj92V8o75VPL7AeQ/giphy.gif',
'https://media2.giphy.com/media/IwAZ6dvvvaTtdI8SD5/giphy.gif',
'https://media0.giphy.com/media/z8gtBVdZVrH20/giphy.gif',
'https://media2.giphy.com/media/26gN16cJ6gy4LzZSw/giphy.gif',
'https://media1.giphy.com/media/LZElUsjl1Bu6c/giphy.gif',
'https://media1.giphy.com/media/gHnwTttExPf4nwOWm7/giphy.gif',
]
const getRandomGif = () => celebrationGifs[Math.floor(Math.random() * celebrationGifs.length)]
// social media links
const web_url = 'https://firstcontributions.github.io';
const slack_invite_url = 'https://join.slack.com/t/firstcontributors/shared_invite/zt-2vqegkew0-ZuzGM1LO33C6Ts4nZyat1Q'
const twitter_tweet_share = 'https://twitter.com/intent/tweet?text=Yay%21%20I%20just%20made%20my%20first%20open%20source%20contribution%20with%20@1stcontribution.%20You%20can%20too%20at%20https%3A//goo.gl/66Axwe%0A&hashtags=OpenSource,CodeNewbie'
const fb_share_link = 'https://www.facebook.com/sharer/sharer.php?u=https://roshanjossey.github.io/first-contributions"e=Yay%21%20I%20just%20made%20my%20first%20open%20source%20contribution%20with%20First%20Contributions.%20You%20can%20too,%20by%20following%20a%20simple%20tutorial%20at%20https%3A//goo.gl/66Axwe&hashtag=%23OpenSource'
const reddit_link = 'https://www.reddit.com/submit?url=https%3A%2F%2Fgithub.com%2Ffirstcontributions%2Ffirst-contributions&title=Learn%20how%20to%20contribute%20to%20open%20source%20projects%20in%205%20minutes'
const linkedin_share_link = 'https://www.linkedin.com/sharing/share-offsite/?url=https://github.com/firstcontributions/first-contributions';
const dev_share_link = "https://dev.to/new?prefill=---%0Atitle%3A%20First%20Contributions%3A%20learn%20how%20to%20contribute%20to%20open%20source%20projects%0Apublished%3A%20true%0Atags%3A%20opensource%2C%20beginners%2C%20tutorial%0A---%0A%0AI%20followed%20the%20hands-on%20tutorial%20in%20the%20Readme%20of%20first%20contributions%20and%20made%20my%20first%20pull%20request%20to%20the%20same%20repo.%0A%0A%0A%7B%25%20embed%20https%3A%2F%2Fgithub.com%2Ffirstcontributions%2Ffirst-contributions%20%25%7D";
const hackernews_share_link = 'https://news.ycombinator.com/submitlink?u=https%3A%2F%2Fgithub.com%2Ffirstcontributions%2Ffirst-contributions&t=Show%20HN%3A%20Hands%20on%20tutorial%20for%20open%20source%20contribution'
// social logo
const repo_logo = "https://avatars0.githubusercontent.com/u/65761570?s=88&u=640f39b808c75c6b86460aa907dd030bcca2f3c7&v=4"
const slack_logo = "https://edent.github.io/SuperTinyIcons/images/svg/slack.svg"
const twitter_logo = "https://edent.github.io/SuperTinyIcons/images/svg/twitter.svg"
const fb_logo = "https://edent.github.io/SuperTinyIcons/images/svg/facebook.svg"
const reddit_logo = "https://edent.github.io/SuperTinyIcons/images/svg/reddit.svg"
const linkedin_logo = "https://edent.github.io/SuperTinyIcons/images/svg/linkedin.svg";
const dev_logo = "https://edent.github.io/SuperTinyIcons/images/svg/dev_to.svg";
const hackernews_logo = "https://edent.github.io/SuperTinyIcons/images/svg/hackernews.svg";
const getMergeMessage = (username) => {
const greeting = `Hello @${username}, congratulations! Your pull request has been successfully approved and merged. π`;
const starRepoMessage = `If you liked the tutorial, please star this repo by clicking the star button on the top right of this page. <img alt="star screenshot" title="star button" src="https://firstcontributions.github.io/assets/star.png">`;
const nextSteps = `# Next steps \n - Continue contributing: If you're looking for projects to contribute to, checkout our [<img src="${repo_logo}" width="22" title="web app" /> webapp](${web_url}). \n - Join our Slack group: We have a community to help/support contributors. [<img src="${slack_logo}" width="22" title="Slack" /> Join slack group](${slack_invite_url}). \n - Share on social media: You can share this content to help more people. [ <img alt="twitter" title="twitter" src="${twitter_logo}" width="22"> tweet](${twitter_tweet_share}). [<img alt="twitter" title="twitter" src="${fb_logo}" width="22"> share](${fb_share_link}). [ <img alt="reddit" title="reddit" src="${reddit_logo}" width="22"> share](${reddit_link}). [<img alt="linkedin" title="linkedin" src="${linkedin_logo}" width="22"> post](${linkedin_share_link}). [<img alt="devio" title="devio" src="${dev_logo}" width="22"> publish](${dev_share_link}). [<img src="${hackernews_logo}" width="22" title="HackerNews" /> Post on HackerNews](${hackernews_share_link}).`;
const feedbackMessage = `We'd love to hear your thoughts about this project. Let us know how we can improve by commenting or opening an issue here.`;
const gif = `})`;
return `${greeting}\n\n${starRepoMessage}\n\n${nextSteps}\n\n${feedbackMessage}\n\n${gif}`;
}
// Generate the merge message using the getMergeMessage function
const message = getMergeMessage(context.payload.pull_request.user.login);
// post a comment on the PR with approval and merge message
const approval = {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
body: message,
event: 'APPROVE'
};
github.rest.pulls.createReview(approval);
# await github.rest.issues.createComment({
# owner: context.repo.owner,
# repo: context.repo.repo,
# issue_number: context.issue.number,
# body: message
# })
} catch (error) {
console.error("Error posting comment:", error.message);
core.setFailed(error.message);
}