# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set-strictmode -version latest . "$(& git rev-parse --show-toplevel)/.github/workflows/common.ps1" # == begin common.ps1 extensions == $date_key = '%%DATE%%' $date_regex = '(?>(?>\d{4})-)?(?\d{4})' $timer = [System.Diagnostics.Stopwatch]::StartNew() $global:copyright_matchers = @( @{ files = @('.containerfile', '.dockerignore', '.pbtxt', '.ps1', '.py', '.sh', '.toml', '.tpl', '.txt', '.yaml', '.yml', 'Dockerfile') found_missing = $false matches = @( '# SPDX-FileCopyrightText: Copyright (c) ' + $date_key + ' NVIDIA CORPORATION & AFFILIATES. All rights reserved.' '# SPDX-License-Identifier: Apache-2.0' '# Licensed under the Apache License, Version 2.0 (the "License");' '# you may not use this file except in compliance with the License.' '# You may obtain a copy of the License at' '# http://www.apache.org/licenses/LICENSE-2.0' '# Unless required by applicable law or agreed to in writing, software' '# distributed under the License is distributed on an "AS IS" BASIS,' '# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.' '# See the License for the specific language governing permissions and' '# limitations under the License.' ) name = 'basic' regex = $null vertical_spacer = '#' } @{ files = @('.json') found_missing = $false matches = @( '"copyright": [' ' "SPDX-FileCopyrightText: Copyright (c) ' + $date_key + ' NVIDIA CORPORATION & AFFILIATES. All rights reserved.",' ' "SPDX-License-Identifier: Apache-2.0",' ' "Licensed under the Apache License, Version 2.0 (the \"License\");",' ' "you may not use this file except in compliance with the License.",' ' "You may obtain a copy of the License at",' ' "http://www.apache.org/licenses/LICENSE-2.0",' ' "Unless required by applicable law or agreed to in writing, software",' ' "distributed under the License is distributed on an \"AS IS\" BASIS,",' ' "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",' ' "See the License for the specific language governing permissions and",' ' "limitations under the License."' '],' ) name = 'json' regex = $null vertical_spacer = $null } @{ files = @('.md') found_missing = $false matches = @( '' ) name = 'markdown' regex = $null vertical_spacer = '' } @{ files = @('.proto', '.rs') found_missing = $false matches = @( '// SPDX-FileCopyrightText: Copyright (c) ' + $date_key + ' NVIDIA CORPORATION & AFFILIATES. All rights reserved.' '// SPDX-License-Identifier: Apache-2.0' '// Licensed under the Apache License, Version 2.0 (the "License");' '// you may not use this file except in compliance with the License.' '// You may obtain a copy of the License at' '// http://www.apache.org/licenses/LICENSE-2.0' '// Unless required by applicable law or agreed to in writing, software' '// distributed under the License is distributed on an "AS IS" BASIS,' '// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.' '// See the License for the specific language governing permissions and' '// limitations under the License.' ) name = 'c-like' regex = $null vertical_spacer = '//' } ) $global:copyright_results = @{ failed_date = @() failed_header = @() passed = @() skipped = @() unsupported = @() } # === end common.ps1 extensions === $ignored_files = @('.clang-format', '.gitattributes', '.gitignore', '.gitkeep', '.patch', 'Cargo.lock', 'LICENSE', 'uv.lock', 'rust-toolchain.toml', 'codespell.txt', 'exclusions.txt') write-debug " ignored_files = ['$($ignored_files -join "','")']." $ignored_paths = @('.github', '.mypy_cache', '.pytest_cache', 'lib/llm/tests/data/sample-models') write-debug " ignored_paths = ['$($ignored_paths -join "','")']." $ignored_types = @('.bat', '.gif', '.ico', '.ipynb', '.jpg', '.jpeg', '.patch', '.png', '.pyc', '.pyi', '.rst', '.zip', '.md', '.json') write-debug " ignored_types = ['$($ignored_types -join "', '")']." $ignored_folders = @('.git', '__pycache__') function is_ignored([string] $path) { # write-debug " path: \"${path}\"." if (($null -eq $path) -or ($path.length -eq 0) -or ($path.endswith('/'))) { write-debug " ignored: true." return $true } foreach ($ignored_path in $ignored_paths) { if ($path.startswith($ignored_path)) { write-debug " ignored: true." return $true } } foreach ($ignored_extension in $ignored_types) { if ($file.endswith($ignored_extension)) { write-debug " ignore = true." return $true } } foreach ($ignored_file in $ignored_files) { if ($file.endswith($ignored_file)) { write-debug " ignore = true." return $true } } $normalized_path = normalize_path $file foreach ($ignored_folder in $ignored_folders) { if ($normalized_path -contains "/${ignored_folder}/") { write-debug " ignore = true." return $true } } if (-not(test-path "${normalized_path}" -pathtype 'Leaf')) { write-debug " ignore = true." return $true } write-debug " ignore = false." return $false } function build_regex([object] $matcher) { write-debug " matcher.name: $($matcher.name)." $regex = '' foreach ($match in $matcher.matches) { $match = $match -replace '([\(\)\[\]\.\+\*\\])', '\$1' $match = $match -replace '\s+', '\s+' # Given the amount of inconsistency between using http and https, we'll just regex it away. $match = $match -replace 'https?://', 'https?://' # Replace the date matcher placeholder w/ the actual regex we'll need. $match = $match -replace $date_key, $date_regex $regex = "${regex}${match}[\n\r\s]+" if ($null -ne $matcher.vertical_spacer) { $regex = "${regex}(?>$($matcher.vertical_spacer)[\n\r\s]+)*" } } write-debug " -> '${regex}'." return $regex } function check_header([string] $path, [object] $matcher) { write-debug " path: ""${path}""." write-debug " matcher: ""$($matcher.name)""." $command = "git log -1 --pretty=""%cs"" -- ${file}" $output = invoke-expression $command | out-string $output = $output.trim() $last_modified = $output.substring(0, 4) -as [int] write-debug " last_modified: ${last_modified}." if ($null -eq $matcher.regex) { $matcher.regex = $(build_regex $matcher) } $regex = $matcher.regex write-debug " regex: ""${regex}""." $contents = read_content $path if (($null -eq $contents) -or ($contents.length -le 0)) { $global:copyright_results.skipped += $file write-detailed " [SKIP] ${file}" 'DarkGray' return } if ($contents -match $regex) { $capture_date = $Matches.year -as [int] if ($capture_date -lt $last_modified) { $global:copyright_results.failed_date += $file write-error " [FAIL] Incorrect Date in Header: ${path} (${capture_date})" } else { $global:copyright_results.passed += $file write-normal " [PASS] ${file}" } } else { $global:copyright_results.failed_header += $file write-error " [FAIL] Invalid/Missing Header: ${file}" $matcher.found_missing = $true } } function check_file([string] $file) { write-debug " file: ""${file}""." $path = normalize_path $file if (test-path $path -pathtype 'Leaf') { write-debug " path: ""${path}""." $is_checked = $false foreach ($matcher in $global:copyright_matchers) { foreach ($ext in $matcher.files) { if ($path.endswith($ext)) { check_header $path $matcher $is_checked = $true break } } if ($is_checked) { return } } write-warning " [WARN] Unsupported: ${file}" $global:copyright_results.unsupported += $file } } $current_year = "$(get-date -format 'yyyy')" -as [int] write-debug " current_year = ${current_year}." foreach ($file in $(git ls-tree -r --name-only HEAD)) { $file = $file.trim() write-debug " file: ""${file}""." if (is_ignored $file) { write-detailed " [SKIP] ${file}" 'DarkGray' $global:copyright_results.skipped += $file continue } check_file $file } function generate_report() { $reports_path = $env:NVBUILD_REPORTS_PATH if ($null -eq $reports_path) { return } if (-not (test-path $reports_path -pathtype 'Container')) { if (test-path $reports_path -pathtype 'Leaf') { return } new-item $reports_path -itemtype 'Directory' | out-null } write-debug " Generating check report." $check_results = "`n" if ($global:copyright_results.failed_header.count -gt 0) { $check_results += " `n" foreach ($file in $global:copyright_results.failed_header) { $check_results += " ${file}`n" } $check_results += " `n" } if ($global:copyright_results.failed_date.count -gt 0) { $check_results += " `n" foreach ($file in $global:copyright_results.failed_date) { $check_results += " ${file}`n" } $check_results += " `n" } if ($global:copyright_results.unsupported.count -gt 0) { $check_results += " `n" foreach ($file in $global:copyright_results.unsupported) { $check_results += " ${file}`n" } $check_results += " `n" } if ($global:copyright_results.passed.count -gt 0) { $check_results += " `n" foreach ($file in $global:copyright_results.passed) { $check_results += " ${file}`n" } $check_results += " `n" } if ($global:copyright_results.skipped.count -gt 0) { $check_results += " `n" foreach ($file in $global:copyright_results.skipped) { $check_results += " ${file}`n" } $check_results += " `n" } $check_results += "`n" $output_path = "${reports_path}/copyright-check.xml" write_content $check_results $output_path -overwrite write-minimal '' write-minimal "Copyright check report -> ${output_path}" } write-normal '' $timer.Stop() write-high "Pass: $($global:copyright_results.passed.count), Fail: $($global:copyright_results.failed_date.count + $global:copyright_results.failed_header.count)" -no_newline if ($global:copyright_results.skipped.count -gt 0) { write-high ", Skipped: $($global:copyright_results.skipped.count)" -no_newline } if ($global:copyright_results.unsupported.count -gt 0) { write-high ", Unsupported: $($global:copyright_results.unsupported.count)" -no_newline } write-minimal " ($($timer.Elapsed.TotalSeconds.ToString("0.000")) seconds)" $global:colors.low -no_newline write-minimal '' if ($global:copyright_results.failed_header.count -gt 0) { write-low '' write-low 'Copyright checkers detected missing or invalid copyright headers:' write-low '' foreach ($matcher in $global:copyright_matchers) { if ($matcher.found_missing) { write-low " name: $($matcher.name)" write-low " files: $($matcher.files -join ", ")" write-low " pattern:`n $($matcher.regex)" write-low '' } } } if (($global:copyright_results.failed_date.count -gt 0) -or ($global:copyright_results.failed_header.count -gt 0)) { write-high 'Files out of compliance:' # Final, end of output list of errors. foreach ($path in $global:copyright_results.failed_header) { write-error " [FAIL] invalid/missing header: ${path}" } foreach ($path in $global:copyright_results.failed_date) { write-error " [FAIL] incorrect date: ${path}" } exit(-1) }