@@ -23,6 +23,101 @@ concurrency:
2323 cancel-in-progress : true
2424
2525jobs :
26+ dupe-check :
27+ runs-on : ubuntu-latest
28+
29+ steps :
30+ - name : Checkout code
31+ uses : actions/checkout@v4
32+ with :
33+ fetch-depth : 0
34+
35+ - name : Set up Node.js
36+ uses : actions/setup-node@v4
37+ with :
38+ node-version : ' 20'
39+
40+ - name : Install dependencies
41+ run : |
42+ npm install -g jscpd diff-so-fancy
43+
44+ - name : Run jscpd on entire codebase
45+ run : jscpd --config "$GITHUB_WORKSPACE/.github/workflows/jscpd.json"
46+
47+ - name : Get the diff
48+ run : git diff --name-only ${{ github.event.pull_request.base.ref }}...${{ github.head_ref }} >> diff_output.txt
49+
50+ - name : Upload unfiltered jscpd report
51+ if : always()
52+ uses : actions/upload-artifact@v4
53+ with :
54+ name : unfiltered-jscpd-report
55+ path : ./jscpd-report.json
56+
57+ - name : Filter jscpd report for changed files
58+ run : |
59+ if [ ! -f ./jscpd-report.json ]; then
60+ echo "jscpd-report.json not found"
61+ exit 1
62+ fi
63+ echo "Filtering jscpd report for changed files..."
64+ CHANGED_FILES=$(jq -R -s -c 'split("\n")[:-1]' diff_output.txt)
65+ echo "Changed files: $CHANGED_FILES"
66+ jq --argjson changed_files "$CHANGED_FILES" '
67+ .duplicates | map(select(
68+ (.firstFile?.name as $fname | $changed_files | any(. == $fname)) or
69+ (.secondFile?.name as $sname | $changed_files | any(. == $sname))
70+ ))
71+ ' ./jscpd-report.json > filtered-jscpd-report.json
72+ cat filtered-jscpd-report.json
73+
74+ - name : Check if filtered jscpd report exists
75+ id : check_filtered_report
76+ run : |
77+ if [ $(wc -l < ./filtered-jscpd-report.json) -gt 1 ]; then
78+ echo "filtered_report_exists=true" >> $GITHUB_ENV
79+ else
80+ echo "filtered_report_exists=false" >> $GITHUB_ENV
81+ fi
82+
83+ - name : Upload filtered jscpd report
84+ if : env.filtered_report_exists == 'true'
85+ uses : actions/upload-artifact@v4
86+ with :
87+ name : filtered-jscpd-report
88+ path : ./filtered-jscpd-report.json
89+
90+ - name : Post GitHub comment
91+ if : env.filtered_report_exists == 'true'
92+ uses : actions/github-script@v7
93+ with :
94+ script : |
95+ const fs = require('fs');
96+ const filteredReport = JSON.parse(fs.readFileSync('filtered-jscpd-report.json', 'utf8'));
97+ let comment = "Whoa there, partner! 🌵🤠 We wrangled some duplicated code in your PR:\n\n";
98+ function link(dup) {
99+ return `https://github.com/${{ github.event.repository.full_name }}/blob/${{ github.event.pull_request.head.sha }}/${dup.name}#L${dup.start + 1}-L${dup.end - 1}`
100+ }
101+ filteredReport.forEach(duplication => {
102+ const firstFile = duplication.firstFile;
103+ const secondFile = duplication.secondFile;
104+ const lines = duplication.lines;
105+ comment += `- [\`${firstFile.name}\`](${link(firstFile)}) has ${lines} duplicated lines with [\`${secondFile.name}\`](${link(secondFile)})\n`;
106+ });
107+ comment += "\nReducing code duplication by importing common functions from a library not only makes our code cleaner but also easier to maintain. Please move the common code from both files into a library and import it in each. We hate that we have to mention this, however, commits designed to hide from this utility by renaming variables or reordering an object are poor conduct. We will not look upon them kindly! Keep up the great work! 🚀";
108+ github.rest.issues.createComment({
109+ owner: context.repo.owner,
110+ repo: context.repo.repo,
111+ issue_number: context.issue.number,
112+ body: comment
113+ });
114+
115+ - name : Fail if duplications are found
116+ if : env.filtered_report_exists == 'true'
117+ run : |
118+ echo "Duplications found, failing the check."
119+ exit 1
120+
26121 lint-commits :
27122 runs-on : ubuntu-latest
28123 steps :
0 commit comments