-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDangerfile
More file actions
218 lines (173 loc) · 7.52 KB
/
Dangerfile
File metadata and controls
218 lines (173 loc) · 7.52 KB
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
# frozen_string_literal: true
# ==============================================================================
# General PR checks
# ==============================================================================
# Warn when there is a big PR
warn('Big PR - consider breaking it into smaller chunks') if git.lines_of_code > 500
# Encourage smaller PRs
warn('Very large PR - review may take longer') if git.lines_of_code > 1000
# Check PR has a description
# if github.pr_body.length < 10
# fail('Please provide a meaningful PR description')
# end
# Check PR title follows conventional commits
unless github.pr_title =~ /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build)(\(.+\))?:/
warn('PR title should follow Conventional Commits format (e.g., "feat: add new feature")')
end
# ==============================================================================
# File checks
# ==============================================================================
test_files = git.modified_files + git.added_files
has_test_changes = test_files.any? { |path| path =~ %r{^Tests/.*\.swift$} }
has_app_changes = (git.modified_files + git.added_files).any? { |path| path =~ %r{^Sources/} }
has_package_changes = git.modified_files.include?('Package.swift')
has_readme_changes = git.modified_files.include?('README.md')
has_docs_changes = git.modified_files.grep(/\.md$/).any?
# ==============================================================================
# Tests
# ==============================================================================
# Non-trivial amounts of app changes without tests
if git.lines_of_code > 50 && has_app_changes && !has_test_changes
warn('This PR may need tests. Consider adding test coverage.')
end
# Encourage test coverage for new files
added_swift_files = git.added_files.grep(/Sources\/.*\.swift$/)
if added_swift_files.any? && !has_test_changes
warn("New Swift files added but no tests. Consider adding tests for: #{added_swift_files.join(', ')}")
end
# ==============================================================================
# Test file verification with project structure check
# ==============================================================================
# Helper function to check if a file exists in the project
def file_exists_in_project?(filepath)
File.exist?(filepath)
end
# All added/modified source files
source_files = (git.modified_files + git.added_files)
.grep(%r{^Sources/.*\.swift$})
.reject { |path| File.basename(path) =~ /\+/ }
# All added/modified test files inside Tests/
test_filenames = test_files
.grep(%r{^Tests/.*\.swift$})
.map { |p| File.basename(p) }
.to_set
missing_tests = []
missing_test_files = []
source_files.each do |path|
filename = File.basename(path, ".swift")
next if filename.start_with?('I')
expected_test_file = "#{filename}Tests.swift"
unless test_filenames.include?(expected_test_file)
possible_test_paths = [
"Tests/#{expected_test_file}",
"Tests/**/#{expected_test_file}",
"**/Tests/**/#{expected_test_file}"
]
test_file_exists = possible_test_paths.any? do |pattern|
!Dir.glob(pattern).empty?
end
if test_file_exists
missing_tests << {
file: filename,
expected: expected_test_file,
exists: true
}
else
missing_test_files << {
file: filename,
expected: expected_test_file,
exists: false
}
end
end
end
# Report missing tests (file exists but not updated)
if missing_tests.any?
list = missing_tests
.map { |m| "- `#{m[:file]}` → test file exists: `#{m[:expected]}` (consider updating if logic changed)" }
.join("\n")
message("ℹ️ Some source files have tests that weren't updated:\n#{list}")
end
# Report missing test files (file doesn't exist in project)
if missing_test_files.any?
list = missing_test_files
.map { |m| "- `#{m[:file]}` → expected test file: `#{m[:expected]}`" }
.join("\n")
warn("⚠️ Some source files are missing corresponding test files:\n#{list}")
end
# ==============================================================================
# Package.swift changes
# ==============================================================================
if has_package_changes
message('📦 Package.swift was modified - please ensure:')
message('- Dependencies are pinned to specific versions')
message('- New dependencies are documented in README')
message('- Platform requirements are correct')
# Check if README was updated when adding dependencies
package_diff = git.diff_for_file('Package.swift')
if package_diff.patch =~ /\.package\(/ && !has_readme_changes
warn('New dependency added but README not updated')
end
end
# ==============================================================================
# Documentation
# ==============================================================================
# Check if public API changes include documentation updates
public_api_changes = git.diff.select { |file|
file.path =~ /Sources\/.*\.swift$/ && file.patch =~ /(public |open )/
}
if public_api_changes.any? && !has_docs_changes
warn('Public API changed but no documentation updates found')
end
# ==============================================================================
# Code quality
# ==============================================================================
# Check for TODO/FIXME comments in modified files
git.modified_files.each do |file|
next unless file.end_with?('.swift')
diff = git.diff_for_file(file)
next unless diff
diff.patch.lines.each_with_index do |line, index|
if line.start_with?('+') && (line.include?('TODO') || line.include?('FIXME'))
warn("#{file}:#{index + 1} contains TODO/FIXME - create an issue for tracking", file: file, line: index + 1)
end
end
end
# Check for print statements (should use proper logging)
# Skip comments and string literals
git.modified_files.grep(/\.swift$/).each do |file|
diff = git.diff_for_file(file)
next unless diff
diff.patch.lines.each_with_index do |line, index|
# Skip if line is a comment (single line or doc comment)
next if line =~ /^\+\s*(\/\/|\/\*\*)/
# Check for actual print() calls (not in strings)
if line.start_with?('+') && line =~ /\bprint\s*\(/
warn("#{file}:#{index + 1} contains print() statement - consider using proper logging", file: file, line: index + 1)
end
end
end
# Check for force unwrapping in new code
git.modified_files.grep(/\.swift$/).each do |file|
diff = git.diff_for_file(file)
next unless diff
diff.patch.lines.each_with_index do |line, index|
if line.start_with?('+') && line =~ /!\s*(?:\)|\.|\[)/
warn("#{file}:#{index + 1} contains force unwrapping (!) - consider using safe unwrapping", file: file, line: index + 1)
end
end
end
# ==============================================================================
# Generated files
# ==============================================================================
generated_files = git.modified_files.grep(/Generated/)
if generated_files.any?
message("⚠️ Generated files were modified: #{generated_files.join(', ')}")
message('Please verify these changes are intentional')
end
# ==============================================================================
# Success message
# ==============================================================================
if status_report[:errors].empty? && status_report[:warnings].empty?
message('✅ Great job! All checks passed.')
end