diff --git a/Package.resolved b/Package.resolved
index 101d4e5..d12b253 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/nicklockwood/SwiftFormat",
"state" : {
- "revision" : "2d5a2b6bde636c1feae2c852ab9a50f221e98c66",
- "version" : "0.55.3"
+ "revision" : "4e92b81311f528cfdca8015d629c650d0aff94ce",
+ "version" : "0.55.4"
}
},
{
diff --git a/Sources/PublicModules/PADOutputGenerator/MarkdownOutputGenerator.swift b/Sources/PublicModules/PADOutputGenerator/MarkdownOutputGenerator.swift
index 6909e18..a683e62 100644
--- a/Sources/PublicModules/PADOutputGenerator/MarkdownOutputGenerator.swift
+++ b/Sources/PublicModules/PADOutputGenerator/MarkdownOutputGenerator.swift
@@ -31,6 +31,10 @@ public struct MarkdownOutputGenerator: OutputGenerating {
if let oldVersionName, let newVersionName {
lines += [Self.repoInfo(oldVersionName: oldVersionName, newVersionName: newVersionName)]
}
+
+ if !changes.isEmpty {
+ lines += [Self.totalChangesBreakdown(changesPerTarget: changesPerTarget)]
+ }
lines += [separator]
@@ -62,8 +66,29 @@ private extension MarkdownOutputGenerator {
return "# β
No changes detected"
}
- let totalChangeCount = changesPerTarget.totalChangeCount
- return "# π \(totalChangeCount) public \(totalChangeCount == 1 ? "change" : "changes") detected"
+ let totalChangeCount = changesPerTarget.totalCount(for: .allChanges)
+
+ if changesPerTarget.potentiallyBreakingChangesCount > 0 {
+ return "# β οΈ \(totalChangeCount) public \(totalChangeCount == 1 ? "change" : "changes") detected β οΈ"
+ } else {
+ return "# π \(totalChangeCount) public \(totalChangeCount == 1 ? "change" : "changes") detected"
+ }
+ }
+
+ static func totalChangesBreakdown(changesPerTarget: [String: [Change]]) -> String {
+
+ let additions = changesPerTarget.totalCount(for: .additions)
+ let changes = changesPerTarget.totalCount(for: .modifications)
+ let removals = changesPerTarget.totalCount(for: .removals)
+
+ guard additions + changes + removals > 0 else { return "" }
+
+ var breakdown = "
"
+ if additions > 0 { breakdown += "βοΈ | \(additions) \(additions == 1 ? "Addition" : "Additions") |
" }
+ if changes > 0 { breakdown += "π | \(changes) \(changes == 1 ? "Modification" : "Modifications") |
" }
+ if removals > 0 { breakdown += "β | \(removals) \(removals == 1 ? "Removal" : "Removals") |
" }
+ breakdown += "
"
+ return breakdown
}
static func repoInfo(oldVersionName: String, newVersionName: String) -> String {
@@ -106,11 +131,11 @@ private extension MarkdownOutputGenerator {
changes: changes.filter(\.changeType.isAddition)
)
let changeLines = changeSectionLines(
- title: "#### π Changed",
- changes: changes.filter(\.changeType.isChange)
+ title: "#### π Modified",
+ changes: changes.filter(\.changeType.isModification)
)
let removalLines = changeSectionLines(
- title: "#### πΆβπ«οΈ Removed",
+ title: "#### β Removed",
changes: changes.filter(\.changeType.isRemoval)
)
@@ -157,7 +182,7 @@ private extension MarkdownOutputGenerator {
return description
case let .removal(description):
return description
- case let .change(before, after):
+ case let .modification(before, after):
return "// From\n\(before)\n\n// To\n\(after)"
}
}
@@ -165,10 +190,30 @@ private extension MarkdownOutputGenerator {
private extension [String: [Change]] {
- var totalChangeCount: Int {
+ enum ChangeCountType {
+ case allChanges
+ case additions
+ case modifications
+ case removals
+ }
+
+ var potentiallyBreakingChangesCount: Int {
+ return totalCount(for: .modifications) + totalCount(for: .removals)
+ }
+
+ func totalCount(for countType: ChangeCountType) -> Int {
var totalChangeCount = 0
keys.forEach { targetName in
- totalChangeCount += self[targetName]?.count ?? 0
+ switch countType {
+ case .allChanges:
+ totalChangeCount += self[targetName]?.count ?? 0
+ case .additions:
+ totalChangeCount += self[targetName]?.reduce(0, { $0 + ($1.changeType.isAddition ? 1 : 0) }) ?? 0
+ case .modifications:
+ totalChangeCount += self[targetName]?.reduce(0, { $0 + ($1.changeType.isModification ? 1 : 0) }) ?? 0
+ case .removals:
+ totalChangeCount += self[targetName]?.reduce(0, { $0 + ($1.changeType.isRemoval ? 1 : 0) }) ?? 0
+ }
}
return totalChangeCount
}
diff --git a/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift b/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift
index 9d69162..c420728 100644
--- a/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift
+++ b/Sources/PublicModules/PADPackageFileAnalyzer/SwiftPackageFileAnalyzer.swift
@@ -124,7 +124,7 @@ private extension SwiftPackageFileAnalyzer {
guard let new, let old else { return [] }
return [.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "\(keyName): \"\(old)\"",
newDescription: "\(keyName): \"\(new)\""
),
@@ -143,7 +143,7 @@ private extension SwiftPackageFileAnalyzer {
let keyName = "name"
return [.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "\(keyName): \"\(old)\"",
newDescription: "\(keyName): \"\(new)\""
),
@@ -191,7 +191,7 @@ private extension SwiftPackageFileAnalyzer {
let newPlatformsString = new.map { "\($0.description)" }.joined(separator: ", ")
return [.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "platforms: [\(oldPlatformsString)]",
newDescription: "platforms: [\(newPlatformsString)]"
),
@@ -265,7 +265,7 @@ private extension SwiftPackageFileAnalyzer {
listOfChanges += removed.map { "Removed target \"\($0)\"" }
return [.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: oldProduct.description,
newDescription: newProduct.description
),
@@ -360,7 +360,7 @@ private extension SwiftPackageFileAnalyzer {
listOfChanges += removedProductDependencies.map { "Removed dependency .product(name: \"\($0)\", ...)" }
return [.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: oldTarget.description,
newDescription: newTarget.description
),
@@ -425,7 +425,7 @@ private extension SwiftPackageFileAnalyzer {
guard oldDependency != newDependency else { return [] }
return [.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: oldDependency.description,
newDescription: newDependency.description
),
@@ -443,7 +443,7 @@ private extension SwiftPackageFileAnalyzer {
guard old != new else { return [] }
return [.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "// swift-tools-version: \(old)",
newDescription: "// swift-tools-version: \(new)"
),
diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift
index 439fab7..f76e802 100644
--- a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift
+++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceAnalyzer/SwiftInterfaceChangeConsolidator.swift
@@ -58,7 +58,7 @@ struct SwiftInterfaceChangeConsolidator: SwiftInterfaceChangeConsolidating {
consolidatedChanges.append(
.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: oldDescription,
newDescription: newDescription
),
diff --git a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement+DiffHelper.swift b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement+DiffHelper.swift
index 937ceac..88de350 100644
--- a/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement+DiffHelper.swift
+++ b/Sources/PublicModules/PADSwiftInterfaceDiff/SwiftInterfaceParser/SwiftInterfaceElement/SwiftInterfaceElement+DiffHelper.swift
@@ -31,7 +31,7 @@ extension SwiftInterfaceElement {
}
switch changeType {
- case let .change(old, new):
+ case let .modification(old, new):
diffDescription += " from `\(old)` to `\(new)`"
case let .removal(string):
diffDescription += " `\(string)`"
@@ -74,13 +74,13 @@ extension SwiftInterfaceElement {
/// File-private helper to produce detailed descriptions
private enum ChangeType {
- case change(old: String, new: String)
+ case modification(old: String, new: String)
case removal(String)
case addition(String)
var title: String {
switch self {
- case .change: "Changed"
+ case .modification: "Modified"
case .removal: "Removed"
case .addition: "Added"
}
@@ -88,7 +88,7 @@ private enum ChangeType {
static func `for`(oldValue: String?, newValue: String?) -> Self? {
if oldValue == newValue { return nil }
- if let oldValue, let newValue { return .change(old: oldValue, new: newValue) }
+ if let oldValue, let newValue { return .modification(old: oldValue, new: newValue) }
if let oldValue { return .removal(oldValue) }
if let newValue { return .addition(newValue) }
return nil
diff --git a/Sources/Shared/Public/PADCore/Change.swift b/Sources/Shared/Public/PADCore/Change.swift
index 0d18af1..ebe4e1a 100644
--- a/Sources/Shared/Public/PADCore/Change.swift
+++ b/Sources/Shared/Public/PADCore/Change.swift
@@ -11,7 +11,7 @@ public struct Change: Equatable {
public enum ChangeType: Equatable {
case addition(description: String)
case removal(description: String)
- case change(oldDescription: String, newDescription: String)
+ case modification(oldDescription: String, newDescription: String)
}
public private(set) var changeType: ChangeType
@@ -38,7 +38,7 @@ extension Change.ChangeType {
return true
case .removal:
return false
- case .change:
+ case .modification:
return false
}
}
@@ -49,18 +49,18 @@ extension Change.ChangeType {
return false
case .removal:
return true
- case .change:
+ case .modification:
return false
}
}
- public var isChange: Bool {
+ public var isModification: Bool {
switch self {
case .addition:
return false
case .removal:
return false
- case .change:
+ case .modification:
return true
}
}
diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md
index e51cecc..7fc5952 100644
--- a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md
+++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-private.md
@@ -1,5 +1,6 @@
-# π 54 public changes detected
+# β οΈ 54 public changes detected β οΈ
_Comparing `new_private` to `old_private`_
+βοΈ | 31 Additions |
π | 21 Modifications |
β | 2 Removals |
---
## `ReferencePackage`
@@ -32,7 +33,7 @@ public protocol ParentProtocol {
public protocol SimpleProtocol
```
-#### π Changed
+#### π Modified
```javascript
// From
@_spi(SystemProgrammingInterface)
@@ -135,7 +136,7 @@ public subscript(index: Swift.Int) -> T? { get set }
public var lazyVar: Swift.String { get set }
```
-#### π Changed
+#### π Modified
```javascript
// From
@_Concurrency.MainActor
@@ -215,7 +216,7 @@ public struct NestedStructInExtension {
}
```
-#### π Changed
+#### π Modified
```javascript
// From
case caseWithTuple(
@@ -250,7 +251,7 @@ Changes:
- Removed parameter `ReferencePackage.CustomEnum`
*/
```
-#### πΆβπ«οΈ Removed
+#### β Removed
```javascript
case caseWithString(Swift.String)
```
@@ -272,7 +273,7 @@ associatedtype CustomAssociatedType: Swift.Equatable
associatedtype CustomAssociatedType: Swift.Equatable
```
-#### π Changed
+#### π Modified
```javascript
// From
func function() -> any Swift.Equatable
@@ -282,7 +283,7 @@ func function() -> Self.CustomAssociatedType
/**
Changes:
-- Changed return type from `any Swift.Equatable` to `Self.CustomAssociatedType`
+- Modified return type from `any Swift.Equatable` to `Self.CustomAssociatedType`
*/
```
```javascript
@@ -294,7 +295,7 @@ var getSetVar: Self.AnotherAssociatedType { get set }
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Self.AnotherAssociatedType`
+- Modified type from `any Swift.Equatable` to `Self.AnotherAssociatedType`
*/
```
```javascript
@@ -306,10 +307,10 @@ var getVar: Self.CustomAssociatedType { get }
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Self.CustomAssociatedType`
+- Modified type from `any Swift.Equatable` to `Self.CustomAssociatedType`
*/
```
-#### πΆβπ«οΈ Removed
+#### β Removed
```javascript
typealias CustomAssociatedType = Swift.Equatable
```
@@ -341,7 +342,7 @@ public typealias Iterator = [ReferencePackage.CustomStruct.AnotherAssociatedT
public typealias ParentType = Swift.Double
```
-#### π Changed
+#### π Modified
```javascript
// From
@discardableResult
@@ -353,7 +354,7 @@ public func function() -> Swift.Int
/**
Changes:
-- Changed return type from `any Swift.Equatable` to `Swift.Int`
+- Modified return type from `any Swift.Equatable` to `Swift.Int`
*/
```
```javascript
@@ -365,7 +366,7 @@ public var getSetVar: Swift.Double
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Swift.Double`
+- Modified type from `any Swift.Equatable` to `Swift.Double`
*/
```
```javascript
@@ -377,7 +378,7 @@ public var getVar: Swift.Int
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Swift.Int`
+- Modified type from `any Swift.Equatable` to `Swift.Int`
*/
```
### `OpenSpiConformingClass`
@@ -397,7 +398,7 @@ public typealias Iterator = [Swift.Double]
public typealias ParentType = Swift.Double
```
-#### π Changed
+#### π Modified
```javascript
// From
@_spi(SystemProgrammingInterface)
@@ -411,7 +412,7 @@ public func function() -> T
/**
Changes:
-- Changed return type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T`
+- Modified return type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T`
*/
```
```javascript
@@ -448,7 +449,7 @@ public typealias CustomAssociatedType = T
/**
Changes:
-- Changed assignment from `any Swift.Equatable` to `T`
+- Modified assignment from `any Swift.Equatable` to `T`
*/
```
```javascript
@@ -462,7 +463,7 @@ public var getSetVar: T
/**
Changes:
-- Changed type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T`
+- Modified type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T`
*/
```
```javascript
@@ -476,7 +477,7 @@ public var getVar: T
/**
Changes:
-- Changed type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T`
+- Modified type from `ReferencePackage.OpenSpiConformingClass.CustomAssociatedType` to `T`
*/
```
diff --git a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md
index 49ac36f..524fbba 100644
--- a/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md
+++ b/Tests/IntegrationTests/Resources/expected-reference-changes-swift-interface-public.md
@@ -1,5 +1,6 @@
-# π 45 public changes detected
+# β οΈ 45 public changes detected β οΈ
_Comparing `new_public` to `old_public`_
+βοΈ | 28 Additions |
π | 15 Modifications |
β | 2 Removals |
---
## `ReferencePackage`
@@ -32,7 +33,7 @@ public protocol ParentProtocol {
public protocol SimpleProtocol
```
-#### π Changed
+#### π Modified
```javascript
// From
public actor CustomActor
@@ -120,7 +121,7 @@ public subscript(index: Swift.Int) -> T? { get set }
public var lazyVar: Swift.String { get set }
```
-#### π Changed
+#### π Modified
```javascript
// From
@_Concurrency.MainActor
@@ -200,7 +201,7 @@ public struct NestedStructInExtension {
}
```
-#### π Changed
+#### π Modified
```javascript
// From
case caseWithTuple(
@@ -235,7 +236,7 @@ Changes:
- Removed parameter `ReferencePackage.CustomEnum`
*/
```
-#### πΆβπ«οΈ Removed
+#### β Removed
```javascript
case caseWithString(Swift.String)
```
@@ -257,7 +258,7 @@ associatedtype CustomAssociatedType: Swift.Equatable
associatedtype CustomAssociatedType: Swift.Equatable
```
-#### π Changed
+#### π Modified
```javascript
// From
func function() -> any Swift.Equatable
@@ -267,7 +268,7 @@ func function() -> Self.CustomAssociatedType
/**
Changes:
-- Changed return type from `any Swift.Equatable` to `Self.CustomAssociatedType`
+- Modified return type from `any Swift.Equatable` to `Self.CustomAssociatedType`
*/
```
```javascript
@@ -279,7 +280,7 @@ var getSetVar: Self.AnotherAssociatedType { get set }
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Self.AnotherAssociatedType`
+- Modified type from `any Swift.Equatable` to `Self.AnotherAssociatedType`
*/
```
```javascript
@@ -291,10 +292,10 @@ var getVar: Self.CustomAssociatedType { get }
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Self.CustomAssociatedType`
+- Modified type from `any Swift.Equatable` to `Self.CustomAssociatedType`
*/
```
-#### πΆβπ«οΈ Removed
+#### β Removed
```javascript
typealias CustomAssociatedType = Swift.Equatable
```
@@ -326,7 +327,7 @@ public typealias Iterator = [ReferencePackage.CustomStruct.AnotherAssociatedT
public typealias ParentType = Swift.Double
```
-#### π Changed
+#### π Modified
```javascript
// From
@discardableResult
@@ -338,7 +339,7 @@ public func function() -> Swift.Int
/**
Changes:
-- Changed return type from `any Swift.Equatable` to `Swift.Int`
+- Modified return type from `any Swift.Equatable` to `Swift.Int`
*/
```
```javascript
@@ -350,7 +351,7 @@ public var getSetVar: Swift.Double
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Swift.Double`
+- Modified type from `any Swift.Equatable` to `Swift.Double`
*/
```
```javascript
@@ -362,7 +363,7 @@ public var getVar: Swift.Int
/**
Changes:
-- Changed type from `any Swift.Equatable` to `Swift.Int`
+- Modified type from `any Swift.Equatable` to `Swift.Int`
*/
```
diff --git a/Tests/UnitTests/OutputGeneratorTests.swift b/Tests/UnitTests/OutputGeneratorTests.swift
index 566a145..2163001 100644
--- a/Tests/UnitTests/OutputGeneratorTests.swift
+++ b/Tests/UnitTests/OutputGeneratorTests.swift
@@ -35,7 +35,8 @@ class OutputGeneratorTests: XCTestCase {
let expectedOutput = """
# π 1 public change detected
_Comparing `new_source` to `old_source`_
-
+
+
---
## `Target_1`
#### βοΈ Added
@@ -62,8 +63,9 @@ class OutputGeneratorTests: XCTestCase {
func test_multipleChanges_multipleModules() {
let expectedOutput = """
- # π 4 public changes detected
+ # β οΈ 4 public changes detected β οΈ
_Comparing `new_source` to `old_repository @ old_branch`_
+ βοΈ | 2 Additions |
β | 2 Removals |
---
## `Target_1`
@@ -71,7 +73,7 @@ class OutputGeneratorTests: XCTestCase {
```javascript
Some Addition
```
- #### πΆβπ«οΈ Removed
+ #### β Removed
```javascript
Some Removal
```
@@ -80,7 +82,7 @@ class OutputGeneratorTests: XCTestCase {
```javascript
Another Addition
```
- #### πΆβπ«οΈ Removed
+ #### β Removed
```javascript
Another Removal
```
diff --git a/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift b/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift
index 18d7877..0f4f519 100644
--- a/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift
+++ b/Tests/UnitTests/SwiftPackageFileAnalyzerTests.swift
@@ -130,7 +130,7 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
let expectedChanges: [Change] = [
.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "// swift-tools-version: 2.0",
newDescription: "// swift-tools-version: 1.0"
),
@@ -138,7 +138,7 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
listOfChanges: []
),
.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "defaultLocalization: \"nl-nl\"",
newDescription: "defaultLocalization: \"en-us\""
),
@@ -146,7 +146,7 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
listOfChanges: []
),
.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "name: \"Old Name\"",
newDescription: "name: \"New Name\""
),
@@ -154,7 +154,7 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
listOfChanges: []
),
.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: "platforms: [.iOS(12.0), .macOS(10.0)]",
newDescription: "platforms: [.iOS(15.0), .visionOS(1.0)]"
),
@@ -173,7 +173,7 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
listOfChanges: []
),
.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: ".library(name: \"Some Library\", targets: [\"Some Target\", \"Old Target\"])",
newDescription: ".library(name: \"Some Library\", targets: [\"Some Target\", \"New Target\"])"
),
@@ -198,7 +198,7 @@ class SwiftPackageFileAnalyzerTests: XCTestCase {
listOfChanges: []
),
.init(
- changeType: .change(
+ changeType: .modification(
oldDescription: ".binaryTarget(name: \"Some Target\", dependencies: [.target(name: \"Some Target Dependency\"), .target(name: \"Old Target Dependency\"), .product(name: \"Some Product Dependency\", ...), .product(name: \"Old Product Dependency\", ...)], path: \"some/old/path\")",
newDescription: ".target(name: \"Some Target\", dependencies: [.target(name: \"Some Target Dependency\"), .target(name: \"New Target Dependency\"), .product(name: \"Some Product Dependency\", ...), .product(name: \"New Product Dependency\", ...)], path: \"some/new/path\")"
),