Skip to content

Commit 1b3586d

Browse files
authored
Merge pull request #95 from Adyen/target-rule-diff
Adding Swift Package Target Resource diffing
2 parents 5902cd4 + 735f026 commit 1b3586d

File tree

5 files changed

+134
-13
lines changed

5 files changed

+134
-13
lines changed

ReferencePackages/UpdatedPackage/Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let package = Package(
1717
// Targets are the basic building blocks of a package, defining a module or a test suite.
1818
// Targets can depend on other targets in this package and products from dependencies.
1919
.target(
20-
name: "ReferencePackage")
20+
name: "ReferencePackage"
21+
)
2122
]
2223
)

Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,23 @@ private extension SwiftPackageFileAnalyzer {
328328
) throws -> [Change] {
329329
guard oldTarget != newTarget else { return [] }
330330

331+
// MARK: Target Resources
332+
333+
let oldResourcePaths = Set(oldTarget.resources?.map(\.path) ?? [])
334+
let newResourcePaths = Set(newTarget.resources?.map(\.path) ?? [])
335+
336+
let addedResourcePaths = newResourcePaths.subtracting(oldResourcePaths)
337+
let consistentResourcePaths = oldResourcePaths.intersection(newResourcePaths)
338+
let removedResourcePaths = oldResourcePaths.subtracting(newResourcePaths)
339+
331340
// MARK: Target Dependencies
332341

333342
let oldTargetDependencies = Set(oldTarget.targetDependencies ?? [])
334343
let newTargetDependencies = Set(newTarget.targetDependencies ?? [])
335344

336345
let addedTargetDependencies = newTargetDependencies.subtracting(oldTargetDependencies)
337346
let removedTargetDependencies = oldTargetDependencies.subtracting(newTargetDependencies)
338-
347+
339348
// MARK: Product Dependencies
340349

341350
let oldProductDependencies = Set(oldTarget.productDependencies ?? [])
@@ -344,7 +353,29 @@ private extension SwiftPackageFileAnalyzer {
344353
let addedProductDependencies = newProductDependencies.subtracting(oldProductDependencies)
345354
let removedProductDependencies = oldProductDependencies.subtracting(newProductDependencies)
346355

356+
// MARK: Compiling list of changes
357+
347358
var listOfChanges = [String]()
359+
360+
listOfChanges += addedResourcePaths.compactMap { path in
361+
guard let resource = newTarget.resources?.first(where: { $0.path == path }) else { return nil }
362+
return "Added resource \(resource.description)"
363+
}
364+
365+
listOfChanges += consistentResourcePaths.compactMap { path in
366+
guard
367+
let newResource = newTarget.resources?.first(where: { $0.path == path }),
368+
let oldResource = oldTarget.resources?.first(where: { $0.path == path })
369+
else { return nil }
370+
371+
return "Changed resource from `\(oldResource.description)` to `\(newResource.description)`"
372+
}
373+
374+
listOfChanges += removedResourcePaths.compactMap { path in
375+
guard let resource = oldTarget.resources?.first(where: { $0.path == path }) else { return nil }
376+
return "Removed resource \(resource.description)"
377+
}
378+
348379
listOfChanges += addedTargetDependencies.map { "Added dependency .target(name: \"\($0)\")" }
349380
listOfChanges += addedProductDependencies.map { "Added dependency .product(name: \"\($0)\", ...)" }
350381

Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ package extension SwiftPackageDescription {
7474

7575
struct Product: Codable, Equatable, Hashable {
7676

77-
// TODO: Add `rule` property
77+
// TODO: Add `type` property
7878

7979
package let name: String
8080
package let targets: [String]
@@ -179,28 +179,31 @@ package extension SwiftPackageDescription {
179179
package let productDependencies: [String]?
180180
/// `.target(name: ...) dependency
181181
package let targetDependencies: [String]?
182-
182+
/// The resources used by the Target
183+
package let resources: [Resource]?
184+
183185
// Ignoring following properties for now as they are not handled in the `PackageAnalyzer`
184186
// and thus would produce changes that are not visible
185187
//
186188
// let productMemberships: [String]?
187189
// let sources: [String]
188-
// let resources: [Resource]?
189190

190191
init(
191192
name: String,
192193
type: TargetType,
193194
path: String,
194195
moduleType: ModuleType,
195196
productDependencies: [String]? = nil,
196-
targetDependencies: [String]? = nil
197+
targetDependencies: [String]? = nil,
198+
resources: [Resource]? = nil
197199
) {
198200
self.name = name
199201
self.type = type
200202
self.path = path
201203
self.moduleType = moduleType
202204
self.productDependencies = productDependencies
203205
self.targetDependencies = targetDependencies
206+
self.resources = resources
204207
}
205208

206209
enum CodingKeys: String, CodingKey {
@@ -210,6 +213,7 @@ package extension SwiftPackageDescription {
210213
case targetDependencies = "target_dependencies"
211214
case type
212215
case path
216+
case resources
213217
}
214218
}
215219
}
@@ -257,9 +261,78 @@ extension SwiftPackageDescription.Target: CustomStringConvertible {
257261
package extension SwiftPackageDescription.Target {
258262

259263
struct Resource: Codable, Equatable {
264+
package let path: String
265+
package let rule: Rule
266+
}
267+
}
260268

261-
// TODO: Add `rule` property
269+
extension SwiftPackageDescription.Target.Resource: CustomStringConvertible {
262270

263-
package let path: String
271+
package var description: String {
272+
return switch rule {
273+
case .copy: ".copy(\"\(path)\")"
274+
case .embeddInCode: ".embeddInCode(\"\(path)\")"
275+
case let .process(metadata):
276+
if let localization = metadata["localization"] {
277+
".process(\"\(path)\", localization: \"\(localization)\")"
278+
} else {
279+
".process(\"\(path)\")"
280+
}
281+
}
282+
}
283+
}
284+
285+
286+
package extension SwiftPackageDescription.Target.Resource {
287+
288+
enum Rule: Codable, Equatable {
289+
case copy
290+
case embeddInCode
291+
case process([String: String])
292+
293+
package init(from decoder: any Decoder) throws {
294+
295+
enum RuleError: Error {
296+
case unsupportedRule
297+
}
298+
299+
let container = try decoder.container(keyedBy: CodingKeys.self)
300+
301+
if (try? container.decode([String: String].self, forKey: .copy)) != nil {
302+
self = .copy
303+
return
304+
}
305+
306+
if (try? container.decode([String: String].self, forKey: .embeddInCode)) != nil {
307+
self = .embeddInCode
308+
return
309+
}
310+
311+
if let metadata = try? container.decode([String: String].self, forKey: .process) {
312+
self = .process(metadata)
313+
return
314+
}
315+
316+
throw RuleError.unsupportedRule
317+
}
318+
319+
package func encode(to encoder: any Encoder) throws {
320+
var container = encoder.container(keyedBy: CodingKeys.self)
321+
322+
switch self {
323+
case .copy:
324+
try container.encode([:] as [String: String], forKey: .copy)
325+
case .embeddInCode:
326+
try container.encode([:] as [String: String], forKey: .embeddInCode)
327+
case let .process(metadata):
328+
try container.encode(metadata, forKey: .process)
329+
}
330+
}
331+
332+
enum CodingKeys: String, CodingKey {
333+
case copy
334+
case embeddInCode = "embed_in_code"
335+
case process
336+
}
264337
}
265338
}

Sources/Shared/Public/PADCore/Change.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public struct Change: Equatable {
2626
) {
2727
self.changeType = changeType
2828
self.parentPath = parentPath
29-
self.listOfChanges = listOfChanges
29+
self.listOfChanges = listOfChanges.sorted()
3030
}
3131
}
3232

Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,12 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
8484
path: "some/new/path",
8585
moduleType: .swiftTarget,
8686
productDependencies: ["Some Product Dependency", "New Product Dependency"],
87-
targetDependencies: ["Some Target Dependency", "New Target Dependency"]
87+
targetDependencies: ["Some Target Dependency", "New Target Dependency"],
88+
resources: [
89+
.init(path: "copy-path", rule: .copy),
90+
.init(path: "process-path", rule: .process([:])),
91+
.init(path: "process-localization-path", rule: .process(["localization":"en_US"])),
92+
]
8893
)
8994
],
9095
toolsVersion: "1.0"
@@ -106,7 +111,13 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
106111
path: "some/old/path",
107112
moduleType: .swiftTarget,
108113
productDependencies: ["Some Product Dependency", "Old Product Dependency"],
109-
targetDependencies: ["Some Target Dependency", "Old Target Dependency"]
114+
targetDependencies: ["Some Target Dependency", "Old Target Dependency"],
115+
resources: [
116+
.init(path: "new-copy-path", rule: .copy),
117+
.init(path: "process-path", rule: .process(["localization":"en_US"])),
118+
.init(path: "process-localization-path", rule: .process([:])),
119+
.init(path: "embedd-in-code-path", rule: .embeddInCode),
120+
]
110121
)
111122
],
112123
toolsVersion: "2.0"
@@ -204,13 +215,18 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
204215
),
205216
parentPath: ".targets",
206217
listOfChanges: [
218+
"Added resource .copy(\"copy-path\")",
219+
"Changed resource from `.process(\"process-path\", localization: \"en_US\")` to `.process(\"process-path\")`",
220+
"Changed resource from `.process(\"process-localization-path\")` to `.process(\"process-localization-path\", localization: \"en_US\")`",
221+
"Removed resource .copy(\"new-copy-path\")",
222+
"Removed resource .embeddInCode(\"embedd-in-code-path\")",
207223
"Added dependency .target(name: \"New Target Dependency\")",
208224
"Added dependency .product(name: \"New Product Dependency\", ...)",
209225
"Changed path from \"some/old/path\" to \"some/new/path\"",
210226
"Changed type from `.binaryTarget` to `.target`",
211227
"Removed dependency .target(name: \"Old Target Dependency\")",
212228
"Removed dependency .product(name: \"Old Product Dependency\", ...)"
213-
]
229+
].sorted()
214230
),
215231
.init(
216232
changeType: .removal(
@@ -220,7 +236,7 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
220236
listOfChanges: []
221237
)
222238
]
223-
239+
224240
XCTAssertEqual(changes.changes, expectedChanges)
225241

226242
waitForExpectations(timeout: 1)

0 commit comments

Comments
 (0)