Skip to content

Commit 6370e08

Browse files
committed
Update copy_license script to ignore identation
1 parent d680b8b commit 6370e08

3 files changed

Lines changed: 138 additions & 48 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
steps:
2525
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
2626

27-
- run: ./scripts/copy_license && git diff --name-only --exit-code
27+
- run: ./scripts/copy_license --check
2828

2929
check-packed-files:
3030
name: Check package files

modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.swift

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
/*
2-
MIT License
3-
4-
Copyright 2023 - Present, Shopify Inc.
5-
6-
Permission is hereby granted, free of charge, to any person obtaining a copy
7-
of this software and associated documentation files (the "Software"), to deal
8-
in the Software without restriction, including without limitation the rights
9-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10-
copies of the Software, and to permit persons to whom the Software is
11-
furnished to do so, subject to the following conditions:
12-
13-
The above copyright notice and this permission notice shall be included in all
14-
copies or substantial portions of the Software.
15-
16-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22-
*/
2+
MIT License
3+
4+
Copyright 2023 - Present, Shopify Inc.
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
*/
2323

2424
import Foundation
2525
import React

scripts/copy_license

Lines changed: 116 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,124 @@
22

33
require 'find'
44

5-
license_text = "/*\n" + File.read('LICENSE') + "*/\n\n"
5+
##
6+
# Builds the canonical license block that will be inserted at the top of files
7+
# when needed.
8+
def build_license_block
9+
license_body = File.read('LICENSE')
10+
"/*\n#{license_body}*/\n\n"
11+
end
12+
13+
##
14+
# Normalizes a string by collapsing all whitespace (spaces, tabs, newlines)
15+
# into single spaces and trimming the ends. Used to compare license text while
16+
# ignoring formatting differences such as indentation or wrapping.
17+
def normalize_whitespace(text)
18+
text.gsub(/\s+/, ' ').strip
19+
end
20+
21+
##
22+
# Given the contents of a file, extracts the very first comment at the top of
23+
# the file if it exists and returns a tuple of:
24+
# - full_comment_with_markers: the raw comment including comment markers
25+
# - inner_comment_text: the text inside the comment with common decorations removed
26+
# - range_end_index: the index where the comment ends in the file contents
27+
# If there is no top-of-file comment, returns [nil, nil, 0].
28+
def extract_top_comment(content)
29+
# Handle optional UTF-8 BOM at start
30+
content = content.sub(/^\uFEFF/, '')
31+
32+
if content.start_with?('/*')
33+
end_idx = content.index('*/', 2)
34+
return [nil, nil, 0] unless end_idx
35+
full = content[0..(end_idx + 1)]
36+
inner = full[2..-3]
37+
# Remove leading '*' decoration often found in block comments
38+
inner = inner.lines.map { |line| line.sub(/^\s*\*\s?/, '') }.join
39+
return [full, inner, end_idx + 2]
40+
elsif content.start_with?('//')
41+
lines = []
42+
consumed = 0
43+
content.each_line do |line|
44+
break unless line.start_with?('//')
45+
lines << line
46+
consumed += line.bytesize
47+
end
48+
full = lines.join
49+
inner = lines.map { |l| l.sub(/^\/\/\s?/, '') }.join
50+
return [full, inner, consumed]
51+
else
52+
return [nil, nil, 0]
53+
end
54+
end
55+
56+
##
57+
# Returns true if the provided file content begins with a license comment whose
58+
# normalized text matches the repository LICENSE content, ignoring whitespace.
59+
def license_at_top?(content, normalized_license)
60+
_full, inner, _ = extract_top_comment(content)
61+
return false unless inner
62+
normalize_whitespace(inner) == normalized_license
63+
end
64+
65+
##
66+
# Processes a single file, ensuring the license block exists at the very top of
67+
# the file. If the file already has the license (with any whitespace formatting),
68+
# it is left unchanged. Otherwise, the license block is prepended above any
69+
# existing content.
70+
def process_file(path, license_block, normalized_license, write: true)
71+
content = File.read(path)
72+
73+
# If license already at the very top (ignoring whitespace differences), do nothing.
74+
return false if license_at_top?(content, normalized_license)
75+
76+
# Remove leading BOM and leading blank lines to place license at true top.
77+
content = content.sub(/^\uFEFF/, '')
78+
content = content.sub(/^\n+/, '')
79+
80+
updated = license_block + content
81+
if write
82+
File.write(path, updated)
83+
end
84+
true
85+
end
86+
87+
##
88+
# Iterates through a directory tree and applies the license update for supported
89+
# file extensions. Returns the list of files that would be or were modified.
90+
def copy_license(dir, license_block, normalized_license, check_only: false)
91+
modified = []
92+
supported_exts = %w[.swift .h .mm .java .js .ts .tsx]
693

7-
def copy_license(dir, text)
894
Find.find(dir) do |path|
9-
next unless File.file?(path) &&
10-
path.end_with?('.swift') ||
11-
path.end_with?('.h') ||
12-
path.end_with?('.mm') ||
13-
path.end_with?('.java') ||
14-
path.end_with?('.js') ||
15-
path.end_with?('.ts') ||
16-
path.end_with?('.tsx')
17-
18-
print("[copy_license] " + path + "\n")
19-
20-
content = File.read(path)
21-
22-
# Remove existing license
23-
content.sub!(/\/\*.*?\*\//m, '')
24-
# remove existing newlines from start of file
25-
content.gsub!(/\A\n*/, '')
26-
# Add new license
27-
content.prepend(text)
28-
29-
File.write(path, content)
95+
next unless File.file?(path) && supported_exts.any? { |ext| path.end_with?(ext) }
96+
97+
changed = process_file(path, license_block, normalized_license, write: !check_only)
98+
if changed
99+
modified << path
100+
puts("[copy_license] #{check_only ? 'would update' : 'updated'} #{path}")
101+
end
30102
end
103+
104+
modified
31105
end
32106

33-
copy_license('modules/@shopify/checkout-sheet-kit/ios', license_text)
34-
copy_license('modules/@shopify/checkout-sheet-kit/android', license_text)
35-
copy_license('modules/@shopify/checkout-sheet-kit/src', license_text)
107+
license_block = build_license_block
108+
normalized_license = normalize_whitespace(File.read('LICENSE'))
109+
110+
check_only = ARGV.include?('--check')
111+
112+
modified = []
113+
modified += copy_license('modules/@shopify/checkout-sheet-kit/ios', license_block, normalized_license, check_only: check_only)
114+
modified += copy_license('modules/@shopify/checkout-sheet-kit/android', license_block, normalized_license, check_only: check_only)
115+
modified += copy_license('modules/@shopify/checkout-sheet-kit/src', license_block, normalized_license, check_only: check_only)
116+
117+
if check_only
118+
if modified.empty?
119+
puts('[copy_license] all files compliant')
120+
exit 0
121+
else
122+
puts("[copy_license] non-compliant files: #{modified.count}")
123+
exit 1
124+
end
125+
end

0 commit comments

Comments
 (0)