forked from CocoaLumberjack/CocoaLumberjack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Dangerfile.swift
199 lines (182 loc) · 7.89 KB
/
Dangerfile.swift
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
import Foundation
import Danger
fileprivate extension Danger.File {
var isInSources: Bool { hasPrefix("Sources/") }
var isInTests: Bool { hasPrefix("Tests/") }
var isInDemos: Bool { hasPrefix("Demos/") }
var isInBenchmarking: Bool { hasPrefix("Benchmarking/") }
var isInVendor: Bool { contains("/Vendor/") }
var isInFMDB: Bool { contains("/FMDB/") }
var isSourceFile: Bool {
fileType == .swift || fileType == .m || fileType == .mm || fileType == .h
}
private static let spmOnlyTargetNames: Set<String> = [
"CocoaLumberjackSwiftLogBackend",
]
var isSPMOnlySourceFile: Bool {
guard isSourceFile else { return false }
if isInSources {
return Self.spmOnlyTargetNames.contains(where: { contains("/\($0)/") })
} else if isInTests {
return Self.spmOnlyTargetNames.contains(where: { contains("/\($0)Tests/") })
}
return false
}
var isSwiftPackageDefintion: Bool {
hasPrefix("Package") && fileType == .swift
}
var isDangerfile: Bool {
self == "Dangerfile.swift"
}
}
let danger = Danger()
let git = danger.git
// Sometimes it's a README fix, or something like that - which isn't relevant for
// including in a project's CHANGELOG for example
let isDeclaredTrivial = danger.github?.pullRequest.title.contains("#trivial") ?? false
let hasSourceChanges = (git.modifiedFiles + git.createdFiles).contains { $0.isInSources }
// Make it more obvious that a PR is a work in progress and shouldn't be merged yet
if danger.github?.pullRequest.title.contains("WIP") == true {
warn("PR is marked as Work in Progress")
}
// Warn when there is a big PR
if let additions = danger.github?.pullRequest.additions,
let deletions = danger.github?.pullRequest.deletions,
case let sum = additions + deletions, sum > 1000 {
warn("Pull request is relatively big (\(sum) lines changed). If this PR contains multiple changes, consider splitting it into separate PRs for easier reviews.")
}
// Changelog entries are required for changes to library files.
if hasSourceChanges && !isDeclaredTrivial && !git.modifiedFiles.contains("CHANGELOG.md") {
warn("Any changes to library code should be reflected in the CHANGELOG. Please consider adding a note there about your change.")
}
// Warn when library files has been updated but not tests.
if hasSourceChanges && !git.modifiedFiles.contains(where: { $0.isInTests }) {
warn("The library files were changed, but the tests remained unmodified. Consider updating or adding to the tests to match the library changes.")
}
// Run SwiftLint
SwiftLint.lint(.modifiedAndCreatedFiles(directory: "Sources"), inline: true)
// Added (or removed) library files need to be added (or removed) from the
// Carthage Xcode project to avoid breaking things for our Carthage users.
let xcodeProjectFile: Danger.File = "Lumberjack.xcodeproj/project.pbxproj"
let xcodeProjectWasModified = git.modifiedFiles.contains(xcodeProjectFile)
if (git.createdFiles + git.deletedFiles).contains(where: { $0.isInSources && $0.isSourceFile && !$0.isSPMOnlySourceFile })
&& !xcodeProjectWasModified {
fail("Added or removed library files require the Carthage Xcode project to be updated.")
}
// Check xcodeproj settings are not changed
// Check to see if any of our project files contains a line with "SOURCE_ROOT" which indicates that the file isn't in sync with Finder.
if xcodeProjectWasModified {
let acceptedSettings: Set<String> = [
"APPLICATION_EXTENSION_API_ONLY",
"ASSETCATALOG_COMPILER_APPICON_NAME",
"ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME",
"ATTRIBUTES",
"CODE_SIGN_IDENTITY",
"COMBINE_HIDPI_IMAGES",
"FRAMEWORK_VERSION",
"GCC_PRECOMPILE_PREFIX_HEADER",
"GCC_PREFIX_HEADER",
"IBSC_MODULE",
"INFOPLIST_FILE",
"MODULEMAP_FILE",
"PRIVATE_HEADERS_FOLDER_PATH",
"PRODUCT_BUNDLE_IDENTIFIER",
"PRODUCT_NAME",
"PUBLIC_HEADERS_FOLDER_PATH",
"SDKROOT",
"SUPPORTED_PLATFORMS",
"TARGETED_DEVICE_FAMILY",
"WRAPPER_EXTENSION",
]
[xcodeProjectFile]
.lazy
.filter { FileManager.default.fileExists(atPath: $0) }
.forEach { projectFile in
danger.utils.readFile(projectFile).split(separator: "\n").enumerated().forEach { (offset, line) in
if line.contains("sourceTree = SOURCE_ROOT;") &&
line.contains("PBXFileReference") &&
!line.contains("path = Sources/CocoaLumberjackSwiftSupport/include/") {
warn(message: "Files should be in sync with project structure", file: projectFile, line: offset + 1)
}
if let range = line.range(of: "[A-Z_]+ = .*;", options: .regularExpression) {
let setting = String(line[range].prefix(while: { $0 != " " }))
if !acceptedSettings.contains(setting) {
warn(message: "Xcode settings need to remain in Configs/*.xcconfig. Please move " + setting + " to the xcconfig file", file: projectFile, line: offset + 1)
}
}
}
}
}
// Check Copyright
let copyrightLines = (
source: [
"// Software License Agreement (BSD License)",
"//",
"// Copyright (c) 2010-2024, Deusty, LLC",
"// All rights reserved.",
"//",
"// Redistribution and use of this software in source and binary forms,",
"// with or without modification, are permitted provided that the following conditions are met:",
"//",
"// * Redistributions of source code must retain the above copyright notice,",
"// this list of conditions and the following disclaimer.",
"//",
"// * Neither the name of Deusty nor the names of its contributors may be used",
"// to endorse or promote products derived from this software without specific",
"// prior written permission of Deusty, LLC.",
],
demos: [
"//",
"// ",
"// ",
"//",
"// CocoaLumberjack Demos",
"//",
],
benchmarking: [
"//",
"// ",
"// ",
"//",
"// CocoaLumberjack Benchmarking",
"//",
]
)
// let sourcefilesToCheck = Dir.glob("*/*/*") // uncomment when we want to test all the files (locally)
let sourcefilesToCheck = Set(git.modifiedFiles + git.createdFiles)
let filesWithInvalidCopyright = sourcefilesToCheck.lazy
.filter { $0.isSourceFile }
.filter { !$0.isSwiftPackageDefintion }
.filter { !$0.isDangerfile }
.filter { !$0.isInVendor && !$0.isInFMDB }
.filter { FileManager.default.fileExists(atPath: $0) }
.filter {
// Use correct copyright lines depending on source file location
let (expectedLines, shouldMatchExactly): (Array<String>, Bool)
if $0.isInDemos {
expectedLines = copyrightLines.demos
shouldMatchExactly = false
} else if $0.isInBenchmarking {
expectedLines = copyrightLines.benchmarking
shouldMatchExactly = false
} else {
expectedLines = copyrightLines.source
shouldMatchExactly = true
}
let actualLines = danger.utils.readFile($0).split(separator: "\n").lazy.map(String.init)
if shouldMatchExactly {
return !actualLines.starts(with: expectedLines)
} else {
return !zip(actualLines, expectedLines).allSatisfy { $0.starts(with: $1) }
}
}
if !filesWithInvalidCopyright.isEmpty {
filesWithInvalidCopyright.sorted().forEach {
warn(message: "Invalid copyright!", file: $0, line: 1)
}
warn("""
Copyright is not valid. See our default copyright in all of our files (Sources, Demos and Benchmarking use different formats).<br/>
Invalid files:<br/>
\(filesWithInvalidCopyright.map { "- \($0)" }.joined(separator: "<br/>\n"))
""")
}