@@ -7,234 +7,105 @@ jobs:
77 copyright-check :
88 name : Validate Copyright Headers
99 runs-on : ubuntu-latest
10-
10+
1111 steps :
12- - name : Checkout PR head (target repository code)
12+ - name : Checkout PR head
1313 uses : actions/checkout@v4
1414 with :
15- # Checkout the PR head - this gets the target repo code with changes
1615 ref : ${{ github.event.pull_request.head.sha }}
1716 path : target-repo
18-
19- - name : Checkout pr-workflows repository (for validation script)
17+
18+ - name : Checkout pr-workflows repo
2019 uses : actions/checkout@v4
2120 with :
2221 repository : ${{ github.repository_owner }}/pr-workflows
2322 ref : copyright
2423 path : pr-workflows
25-
26- - name : Setup copyright configuration
24+
25+ - name : Setup config
2726 id : setup-config
2827 run : |
29- echo "Setting up copyright configuration..."
30-
31- config_file="target-repo/.copyrightconfig"
32- config_source="PR head"
33-
34- # Check if config file exists in PR head
35- if [ ! -f "$config_file" ]; then
36- echo "Config file not in PR head, checking base branch..."
37-
38- # Checkout base repository to get config file
39- # Use GITHUB_TOKEN for authentication (works for both public and private repos)
28+ cfg="target-repo/.copyrightconfig"
29+ if [ ! -f "$cfg" ]; then
4030 git clone --depth 1 --branch ${{ github.event.pull_request.base.ref }} \
4131 https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git base-repo
42-
43- base_config_file="base-repo/.copyrightconfig"
44-
45- if [ -f "$base_config_file" ]; then
46- echo "Using config from base repository"
47- config_file="$base_config_file"
48- config_source="base repository"
49- else
50- echo "Error: .copyrightconfig not found" && exit 1
51- fi
52- else
53- echo "Using config from PR head"
54- fi
55-
56- # Validate config file content
57- if [ ! -s "$config_file" ]; then
58- echo "Error: empty config" && exit 1
59- fi
60-
61- # Check for required startyear
62- if ! grep -q "^startyear:" "$config_file"; then
63- echo "Error: startyear missing" && exit 1
32+ [ -f base-repo/.copyrightconfig ] && cfg="base-repo/.copyrightconfig"
6433 fi
65-
66- echo "✅ Using copyright configuration from $config_source"
67- echo "Configuration content:"
68- echo "========================"
69- cat "$config_file"
70- echo "========================"
71-
72- # Export config file path for later steps
73- echo "config-file=$config_file" >> $GITHUB_OUTPUT
74-
34+ [ -f "$cfg" ] || { echo "missing config"; exit 1; }
35+ [ -s "$cfg" ] || { echo "empty config"; exit 1; }
36+ grep -q '^startyear:' "$cfg" || { echo "startyear missing"; exit 1; }
37+ echo "config-file=$cfg" >> $GITHUB_OUTPUT
38+
7539 - name : Set up Python
7640 uses : actions/setup-python@v4
7741 with :
7842 python-version : ' 3.11'
79-
43+
8044 - name : Get changed files
8145 id : changed-files
8246 run : |
83- echo "Getting list of changed files..."
84-
8547 cd target-repo
86-
87- # Get the base and head refs for comparison
8848 base_sha="${{ github.event.pull_request.base.sha }}"
8949 head_sha="${{ github.event.pull_request.head.sha }}"
90-
91- echo "Getting changes introduced by the PR..."
92- echo "Base SHA: $base_sha"
93- echo "Head SHA: $head_sha"
94-
95- # Fetch the base branch to compare against
9650 git fetch origin ${{ github.event.pull_request.base.ref }}
97-
98- # Get files changed between base and PR head
99- changed_files=$(git diff --name-only --diff-filter=AMR "$base_sha" "$head_sha")
100-
101- if [ -z "$changed_files" ]; then
102- echo "No files changed in this PR"
103- echo "files-count=0" >> $GITHUB_OUTPUT
104- echo "skip-validation=true" >> $GITHUB_OUTPUT
105- exit 0
106- fi
107-
108- echo "Files changed by PR:"
109- echo "$changed_files"
110-
111- # Filter existing files and create list for validation
112- echo "$changed_files" | xargs -I {} sh -c '[ -f "{}" ] && echo "{}"' > ../files_to_check.txt
113- existing_count=$(cat ../files_to_check.txt | wc -l | tr -d ' ')
114-
115- if [ "$existing_count" -eq 0 ]; then
116- echo "No existing files to validate (all files were deleted)"
117- echo "files-count=0" >> $GITHUB_OUTPUT
51+ git diff --name-only --diff-filter=AMR "$base_sha" "$head_sha" | while read f; do [ -f "$f" ] && echo "$f"; done > ../files_to_check.txt
52+ count=$(wc -l < ../files_to_check.txt | tr -d ' ')
53+ if [ "$count" -eq 0 ]; then
11854 echo "skip-validation=true" >> $GITHUB_OUTPUT
11955 else
120- echo "Files to validate: $existing_count"
121- # Save file list for next step (as relative paths without prefixes)
122- echo "$changed_files" | xargs -I {} sh -c '[ -f "{}" ] && echo "{}"' > ../files_to_check.txt
123- echo "files-count=$existing_count" >> $GITHUB_OUTPUT
12456 echo "skip-validation=false" >> $GITHUB_OUTPUT
12557 fi
126-
58+ echo "files-count=$count" >> $GITHUB_OUTPUT
59+
12760 - name : Validate
12861 id : validate
12962 if : steps.changed-files.outputs.skip-validation != 'true'
13063 continue-on-error : true
13164 run : |
132- set -o pipefail
133- echo "Starting copyright validation..."
134-
135- # Debug: List current directory contents
136- echo "Current directory contents:"
137- ls -la
138-
139- # Debug: Check pr-workflows directory structure
140- echo "pr-workflows directory contents:"
141- ls -la pr-workflows/
142- if [ -d "pr-workflows/scripts" ]; then
143- echo "pr-workflows/scripts directory contents:"
144- ls -la pr-workflows/scripts/
145- else
146- echo "❌ pr-workflows/scripts directory does not exist"
147- fi
148-
149- script_path="pr-workflows/scripts/copyrightcheck.py"
150- config_file="${{ steps.setup-config.outputs.config-file }}"
151-
152- # Verify copyright script exists in pr-workflows repo
153- if [ ! -f "$script_path" ]; then
154- echo "❌ Error: $script_path not found in pr-workflows repository"
155- echo "Please ensure the copyright check script exists in the pr-workflows repository"
156- exit 1
157- fi
158-
159- # Make script executable
160- chmod +x "$script_path"
161-
162- # Read files to check
163- if [ ! -f "files_to_check.txt" ]; then
164- echo "❌ Error: No files to check"
165- exit 1
166- fi
167-
168- files_to_check=$(tr '\n' ' ' < files_to_check.txt)
169- echo "Validating files: $files_to_check"
170-
171- # Run validation (script always verbose now)
172- echo "Running copyright validation..."
173- echo "🔧 Command: python3 $script_path --config $config_file --working-dir target-repo $files_to_check"
174-
175- if python3 "$script_path" --config "$config_file" --working-dir target-repo $files_to_check > validation_output.txt 2>&1; then
176- echo "✅ Copyright validation passed"
177- echo "status=success" >> $GITHUB_OUTPUT
178- else
179- echo "❌ Copyright validation failed"
180- echo "status=failed" >> $GITHUB_OUTPUT
181- # Still proceed to allow summary extraction and proper job summary; final job result handled later
182- fi
183-
184- - name : Job Summary (Markdown block extraction)
65+ script="pr-workflows/scripts/copyrightcheck.py"
66+ cfg="${{ steps.setup-config.outputs.config-file }}"
67+ [ -f "$script" ] || { echo "script missing"; exit 1; }
68+ chmod +x "$script"
69+ files=$(tr '\n' ' ' < files_to_check.txt)
70+ python3 "$script" --config "$cfg" --working-dir target-repo $files > validation_output.txt 2>&1
71+ ec=$?
72+ if [ $ec -eq 0 ]; then echo "status=success" >> $GITHUB_OUTPUT; else echo "status=failed" >> $GITHUB_OUTPUT; fi
73+ exit $ec
74+
75+ - name : Extract Markdown summary
18576 if : always() && steps.changed-files.outputs.skip-validation != 'true'
18677 run : |
187- summary_file="$GITHUB_STEP_SUMMARY"
188- if [ ! -f validation_output.txt ]; then
189- echo "No validation output captured" >> "$summary_file"
190- exit 0
191- fi
192- awk '/^<<<COPYRIGHT-CHECK:MARKDOWN>>>/{flag=1;next}/^<<<END COPYRIGHT-CHECK:MARKDOWN>>>/{flag=0}flag' validation_output.txt >> "$summary_file"
193-
194- - name : Annotate Summary
78+ awk '/^<<<COPYRIGHT-CHECK:MARKDOWN>>>/{f=1;next}/^<<<END COPYRIGHT-CHECK:MARKDOWN>>>/{f=0}f' validation_output.txt > summary.md
79+ cat summary.md >> "$GITHUB_STEP_SUMMARY"
80+
81+ - name : Annotations (from markdown)
19582 if : always() && steps.changed-files.outputs.skip-validation != 'true'
19683 run : |
19784 python3 - <<'PY'
198- import re, json, pathlib
199- text = pathlib.Path('validation_output.txt').read_text()
200- # Exact block extraction (no fallback parsing)
201- m = re.search(r'<<<COPYRIGHT-CHECK:JSON>>>\s*(.*?)\s*<<<END COPYRIGHT-CHECK:JSON>>>', text, re.S)
85+ import re, sys
86+ md=open('summary.md').read()
87+ lines=[l for l in md.splitlines() if l.strip()]
88+ if len(lines)<2 :
89+ sys.exit(0)
90+ counts_line=lines[1]
91+ pat=r"Total:\s*(\d+).*?Passed:\s*(\d+).*?Failed:\s*(\d+)(?:.*?Skipped:\s*(\d+))?"
92+ m=re.search(pat, counts_line)
20293if not m :
203- # No annotation if block missing (no fallback)
204- raise SystemExit(0)
205- js = json.loads(m.group(1))
206- counts = js.get('counts', {})
207- failed = counts.get('invalid', 0)
208- summary_parts = [
209- f"Total {counts.get('total',0)}",
210- f"Passed {counts.get('valid',0)}",
211- f"Failed {failed}"
212- ]
213- skipped = counts.get('excluded',0)
214- if skipped :
215- summary_parts.append(f"Skipped {skipped}")
216- summary_line = ' | '.join(summary_parts)
217- if failed > 0 :
218- print(f"::error title=Copyright Summary::{summary_line}")
219- failed_files = js.get('failed', [])
220- if failed_files :
221- # Truncate list to first 10
222- display = failed_files[:10]
223- listing = ', '.join(f['file'] for f in display)
224- extra = '' if len(failed_files) <= 10 else f" (+{len(failed_files)-10} more)"
225- print(f"::error title=Failed Files::{listing}{extra}")
94+ sys.exit(0)
95+ Total,Passed,Failed,Skipped=m.groups()
96+ Total=int(Total); Passed=int(Passed); Failed=int(Failed); Skipped=int(Skipped) if Skipped else 0
97+ summary=f"Total {Total} | Passed {Passed} | Failed {Failed}" + (f" | Skipped {Skipped}" if Skipped else '')
98+ if Failed>0 :
99+ print(f"::error title=Copyright Summary::{summary}")
226100else :
227- print(f"::notice title=Copyright Summary::{summary_line }")
101+ print(f"::notice title=Copyright Summary::{summary }")
228102PY
229-
103+
230104 - name : Fail if needed
231105 if : always() && steps.changed-files.outputs.skip-validation != 'true'
232106 run : |
233- if [ "${{ steps.validate.outputs.status }}" != "success" ]; then
234- exit 1
235- fi
236-
107+ [ "${{ steps.validate.outputs.status }}" = "success" ] || exit 1
108+
237109 - name : No-op summary
238110 if : steps.changed-files.outputs.skip-validation == 'true'
239- run : |
240- echo "::notice title=Copyright Check::No files to validate"
111+ run : echo "::notice title=Copyright Check::No files to validate"
0 commit comments