From 6196d8fbd3829dad9ea4693b754fa538c66e6e5e Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Nov 2024 14:14:36 +0100 Subject: [PATCH 01/13] adding detect api changes workflow --- .github/workflows/detect-api.changes.yml | 65 ++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/workflows/detect-api.changes.yml diff --git a/.github/workflows/detect-api.changes.yml b/.github/workflows/detect-api.changes.yml new file mode 100644 index 0000000..a1efb54 --- /dev/null +++ b/.github/workflows/detect-api.changes.yml @@ -0,0 +1,65 @@ +name: 👀 Detect public API changes + +on: + pull_request: + types: [opened, synchronize, reopened] + workflow_dispatch: + inputs: + new: + description: 'Branch/tag of the new/updated version' + required: true + old: + description: 'Branch/tag of the old/comparison version' + required: true + +jobs: + + build: + runs-on: macos-14 # Apple Silicon Runner + + steps: + - uses: actions/checkout@v4 + - uses: n1hility/cancel-previous-runs@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Select latest Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '15.4' + + - name: 🚚 Fetch repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: 🔍 Detect Changes + run: | + PROJECT_FOLDER=$PWD + + NEW="${{ env.source }}~${{ env.githubRepo }}" + if [[ '${{ github.head_ref || env.noTargetBranch }}' == 'release/*' ]] + then + LATEST_TAG=$(git describe --tags --abbrev=0) + OLD="$LATEST_TAG~${{ env.githubRepo }}" + else + OLD="${{ env.target }}~${{ env.githubRepo }}" + fi + + cd Scripts + ./public-api-diff project --new "$NEW" --old "$OLD" --output "$PROJECT_FOLDER/api_comparison.md" --log-output "$PROJECT_FOLDER/logs.txt" + cat "$PROJECT_FOLDER/logs.txt" + cat "$PROJECT_FOLDER/api_comparison.md" >> $GITHUB_STEP_SUMMARY + env: + source: '${{ github.event.inputs.new || github.head_ref }}' + target: '${{ github.event.inputs.old || github.event.pull_request.base.ref }}' + githubRepo: '${{github.server_url}}/${{github.repository}}.git' + noTargetBranch: 'no target branch' + + - if: ${{ github.event.pull_request.base.ref != '' }} + name: 📝 Comment on PR + uses: thollander/actions-comment-pull-request@v3 + with: + file-path: "${{ github.workspace }}/api_comparison.md" + comment-tag: api_changes + mode: recreate From 205d76ed12da046fdb803f9c0bf15b6b1b238d0b Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Nov 2024 14:16:34 +0100 Subject: [PATCH 02/13] Fixing run command --- .github/workflows/detect-api.changes.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/detect-api.changes.yml b/.github/workflows/detect-api.changes.yml index a1efb54..57015b2 100644 --- a/.github/workflows/detect-api.changes.yml +++ b/.github/workflows/detect-api.changes.yml @@ -46,8 +46,7 @@ jobs: OLD="${{ env.target }}~${{ env.githubRepo }}" fi - cd Scripts - ./public-api-diff project --new "$NEW" --old "$OLD" --output "$PROJECT_FOLDER/api_comparison.md" --log-output "$PROJECT_FOLDER/logs.txt" + swift run public-api-diff project --new "$NEW" --old "$OLD" --output "$PROJECT_FOLDER/api_comparison.md" --log-output "$PROJECT_FOLDER/logs.txt" cat "$PROJECT_FOLDER/logs.txt" cat "$PROJECT_FOLDER/api_comparison.md" >> $GITHUB_STEP_SUMMARY env: From da4cf2a8d66d320f518fbb086ffaadaa9532a01a Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Nov 2024 14:19:29 +0100 Subject: [PATCH 03/13] debug loglevel --- .github/workflows/detect-api.changes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/detect-api.changes.yml b/.github/workflows/detect-api.changes.yml index 57015b2..c3a523b 100644 --- a/.github/workflows/detect-api.changes.yml +++ b/.github/workflows/detect-api.changes.yml @@ -46,7 +46,7 @@ jobs: OLD="${{ env.target }}~${{ env.githubRepo }}" fi - swift run public-api-diff project --new "$NEW" --old "$OLD" --output "$PROJECT_FOLDER/api_comparison.md" --log-output "$PROJECT_FOLDER/logs.txt" + swift run public-api-diff project --new "$NEW" --old "$OLD" --output "$PROJECT_FOLDER/api_comparison.md" --log-level debug --log-output "$PROJECT_FOLDER/logs.txt" cat "$PROJECT_FOLDER/logs.txt" cat "$PROJECT_FOLDER/api_comparison.md" >> $GITHUB_STEP_SUMMARY env: From 735a5e1acfc7140aafbc7a2aae16e93556caada2 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Nov 2024 14:21:40 +0100 Subject: [PATCH 04/13] echoing project folder --- .github/workflows/detect-api.changes.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/detect-api.changes.yml b/.github/workflows/detect-api.changes.yml index c3a523b..aa2f106 100644 --- a/.github/workflows/detect-api.changes.yml +++ b/.github/workflows/detect-api.changes.yml @@ -36,6 +36,7 @@ jobs: - name: 🔍 Detect Changes run: | PROJECT_FOLDER=$PWD + echo $PROJECT_FOLDER NEW="${{ env.source }}~${{ env.githubRepo }}" if [[ '${{ github.head_ref || env.noTargetBranch }}' == 'release/*' ]] From 19627dffdaf6df427e5d31a3375ac3d3d256cb4c Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Nov 2024 14:33:31 +0100 Subject: [PATCH 05/13] better cloning output --- Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift index 76424dc..3a82973 100644 --- a/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift +++ b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift @@ -46,7 +46,8 @@ internal struct Git { let command = "git clone -b \(branchOrTag) \(repository) \(targetDirectoryPath)" shell.execute(command) - guard fileHandler.fileExists(atPath: targetDirectoryPath) else { + let directoryContents = try fileHandler.contentsOfDirectory(atPath: targetDirectoryPath) + guard !directoryContents.isEmpty else { throw GitError.couldNotClone(branchOrTag: branchOrTag, repository: repository) } } From 9035221aa0bc205acf1b978dc5b2a1798993bdf4 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Nov 2024 14:38:55 +0100 Subject: [PATCH 06/13] debug logging --- .../PublicModules/PADProjectBuilder/ProjectSetup/Git.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift index 3a82973..e4df01e 100644 --- a/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift +++ b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift @@ -44,7 +44,9 @@ internal struct Git { func clone(_ repository: String, at branchOrTag: String, targetDirectoryPath: String) throws { logger?.log("🐱 Cloning \(repository) @ \(branchOrTag) into \(targetDirectoryPath)", from: String(describing: Self.self)) let command = "git clone -b \(branchOrTag) \(repository) \(targetDirectoryPath)" - shell.execute(command) + + let shellOutput = shell.execute(command) + logger?.debug(shellOutput, from: String(describing: Self.self)) let directoryContents = try fileHandler.contentsOfDirectory(atPath: targetDirectoryPath) guard !directoryContents.isEmpty else { From 53920f7c974a6db17a378af715493cc9ddf53cce Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 1 Nov 2024 14:56:28 +0100 Subject: [PATCH 07/13] Better clone error logging --- .../PublicModules/PADProjectBuilder/ProjectSetup/Git.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift index e4df01e..a151e40 100644 --- a/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift +++ b/Sources/PublicModules/PADProjectBuilder/ProjectSetup/Git.swift @@ -12,7 +12,7 @@ internal enum GitError: LocalizedError, Equatable { var errorDescription: String? { switch self { case let .couldNotClone(branchOrTag, repository): - "Could not clone \(repository) @ \(branchOrTag) - Please check the provided information" + "Could not clone \(repository) @ \(branchOrTag) - Please check the debug logs for more information" } } } @@ -48,8 +48,8 @@ internal struct Git { let shellOutput = shell.execute(command) logger?.debug(shellOutput, from: String(describing: Self.self)) - let directoryContents = try fileHandler.contentsOfDirectory(atPath: targetDirectoryPath) - guard !directoryContents.isEmpty else { + let directoryContents = try? fileHandler.contentsOfDirectory(atPath: targetDirectoryPath) + guard let directoryContents, !directoryContents.isEmpty else { throw GitError.couldNotClone(branchOrTag: branchOrTag, repository: repository) } } From 12283c3880a18aa601f4f567450a09e8477b2c53 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Thu, 7 Nov 2024 13:13:25 +0100 Subject: [PATCH 08/13] adjusting git tests --- Tests/UnitTests/GitTests.swift | 51 ++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/Tests/UnitTests/GitTests.swift b/Tests/UnitTests/GitTests.swift index 4fda4d8..461f5cb 100644 --- a/Tests/UnitTests/GitTests.swift +++ b/Tests/UnitTests/GitTests.swift @@ -14,21 +14,41 @@ class GitTests: XCTestCase { let repository = "repository" let branch = "branch" let targetDirectoryPath = "targetDirectoryPath" + let shellResult = "shell-result" + + let shellExpectation = expectation(description: "MockShell.execute was called once") + let fileHandlerExpectation = expectation(description: "MockFileHandler.handleContentsOfDirectory was called once") + let loggerLogExpectation = expectation(description: "MockLogger.handleLog was called once") + let loggerDebugExpectation = expectation(description: "MockLogger.handleDebug was called once") + let allExpectations = [shellExpectation, fileHandlerExpectation, loggerLogExpectation, loggerDebugExpectation] let mockShell = MockShell { command in XCTAssertEqual(command, "git clone -b \(branch) \(repository) \(targetDirectoryPath)") - return "" + shellExpectation.fulfill() + return shellResult + } + var mockFileHandler = MockFileHandler() + mockFileHandler.handleContentsOfDirectory = { directoryPath in + XCTAssertEqual(targetDirectoryPath, directoryPath) + fileHandlerExpectation.fulfill() + return ["NonEmpty"] } - - let mockFileHandler = MockFileHandler(handleFileExists: { _ in true }) var mockLogger = MockLogger() mockLogger.handleLog = { message, subsystem in XCTAssertEqual(message, "🐱 Cloning repository @ branch into targetDirectoryPath") XCTAssertEqual(subsystem, "Git") + loggerLogExpectation.fulfill() + } + mockLogger.handleDebug = { message, subsystem in + XCTAssertEqual(message, shellResult) + XCTAssertEqual(subsystem, "Git") + loggerDebugExpectation.fulfill() } let git = Git(shell: mockShell, fileHandler: mockFileHandler, logger: mockLogger) try git.clone(repository, at: branch, targetDirectoryPath: targetDirectoryPath) + + wait(for: allExpectations, timeout: 1) } func test_clone_fail() throws { @@ -36,17 +56,36 @@ class GitTests: XCTestCase { let repository = "repository" let branch = "branch" let targetDirectoryPath = "targetDirectoryPath" + let shellResult = "shell-result" + + let shellExpectation = expectation(description: "MockShell.execute was called once") + let fileHandlerExpectation = expectation(description: "MockFileHandler.handleContentsOfDirectory was called once") + let loggerLogExpectation = expectation(description: "MockLogger.handleLog was called once") + let loggerDebugExpectation = expectation(description: "MockLogger.handleDebug was called once") + let allExpectations = [shellExpectation, fileHandlerExpectation, loggerLogExpectation, loggerDebugExpectation] let mockShell = MockShell { command in XCTAssertEqual(command, "git clone -b \(branch) \(repository) \(targetDirectoryPath)") - return "" + shellExpectation.fulfill() + return shellResult } - let mockFileHandler = MockFileHandler(handleFileExists: { _ in false }) + var mockFileHandler = MockFileHandler() + mockFileHandler.handleContentsOfDirectory = { directoryPath in + XCTAssertEqual(targetDirectoryPath, directoryPath) + fileHandlerExpectation.fulfill() + return [] + } var mockLogger = MockLogger() mockLogger.handleLog = { message, subsystem in XCTAssertEqual(message, "🐱 Cloning repository @ branch into targetDirectoryPath") XCTAssertEqual(subsystem, "Git") + loggerLogExpectation.fulfill() + } + mockLogger.handleDebug = { message, subsystem in + XCTAssertEqual(message, shellResult) + XCTAssertEqual(subsystem, "Git") + loggerDebugExpectation.fulfill() } let git = Git(shell: mockShell, fileHandler: mockFileHandler, logger: mockLogger) @@ -58,5 +97,7 @@ class GitTests: XCTestCase { let fileHandlerError = try XCTUnwrap(error as? GitError) XCTAssertEqual(fileHandlerError, GitError.couldNotClone(branchOrTag: branch, repository: repository)) } + + wait(for: allExpectations, timeout: 1) } } From 00dce411461dbbde28be671bb77db60edd036a8d Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 13 Nov 2024 18:33:25 +0100 Subject: [PATCH 09/13] Adding support for macos + package swiftinterface --- .github/workflows/build-release.yml | 2 +- .github/workflows/detect-api.changes.yml | 2 +- .github/workflows/stale-issues.yml | 2 +- .swiftlint.yml | 36 +++++++++++++++++++ .../CommandLineTool+Extensions.swift | 1 + .../ProjectToOutputCommand.swift | 25 +++++++++++++ .../PADProjectBuilder/ProjectBuilder.swift | 6 ++++ .../PADProjectBuilder/ProjectPlatform.swift | 13 +++++++ .../SwiftInterfaceProducer.swift | 7 ++-- .../SwiftInterfaceProducer/XcodeTools.swift | 18 ++++++++-- .../SwiftPackageDescription.swift | 11 ++++-- .../SwiftPackageFileHelper.swift | 11 ++++-- .../SwiftInterfaceFileLocator.swift | 6 +++- .../SwiftInterfaceType.swift | 2 ++ 14 files changed, 128 insertions(+), 14 deletions(-) create mode 100644 .swiftlint.yml create mode 100644 Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 0df783f..8883779 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -24,7 +24,7 @@ jobs: - name: 🛠️ Build with release configuration run: | - swift build --configuration release -skipPackagePluginValidation | xcpretty --utf --color && exit ${PIPESTATUS[0]} + swift build --configuration release | xcpretty --utf --color && exit ${PIPESTATUS[0]} - uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/detect-api.changes.yml b/.github/workflows/detect-api.changes.yml index aa2f106..b0678a6 100644 --- a/.github/workflows/detect-api.changes.yml +++ b/.github/workflows/detect-api.changes.yml @@ -47,7 +47,7 @@ jobs: OLD="${{ env.target }}~${{ env.githubRepo }}" fi - swift run public-api-diff project --new "$NEW" --old "$OLD" --output "$PROJECT_FOLDER/api_comparison.md" --log-level debug --log-output "$PROJECT_FOLDER/logs.txt" + swift run public-api-diff project --new "$NEW" --old "$OLD" --platform macos --output "$PROJECT_FOLDER/api_comparison.md" --log-level debug --log-output "$PROJECT_FOLDER/logs.txt" cat "$PROJECT_FOLDER/logs.txt" cat "$PROJECT_FOLDER/api_comparison.md" >> $GITHUB_STEP_SUMMARY env: diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index d8459e1..f3162b0 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -3,7 +3,7 @@ # You can adjust the behavior by modifying this file. # For more information, see: # https://github.com/actions/stale -name: Manage stale issues +name: 🏷️ Manage stale issues on: schedule: diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..74ca312 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,36 @@ +disabled_rules: + - trailing_whitespace + - nesting + - todo + - for_where + +excluded: + - Build + - .build + - Tests + - Internal + - Docs + - Demo + - Package.swift + - DerivedData + - Carthage + - TempProject + - Scripts + +line_length: + ignores_function_declarations: true + ignores_urls: true + warning: 140 + +file_length: + warning: 500 + +function_parameter_count: + warning: 10 + error: 15 + +identifier_name: + min_length: + warning: 2 + max_length: + warning: 40 diff --git a/Sources/ExecutableTargets/CommandLineTool/CommandLineTool+Extensions.swift b/Sources/ExecutableTargets/CommandLineTool/CommandLineTool+Extensions.swift index e269abf..77ca052 100644 --- a/Sources/ExecutableTargets/CommandLineTool/CommandLineTool+Extensions.swift +++ b/Sources/ExecutableTargets/CommandLineTool/CommandLineTool+Extensions.swift @@ -14,6 +14,7 @@ extension SwiftInterfaceType: ExpressibleByArgument { switch argument { case "public": self = .public case "private": self = .private + case "package": self = .package default: return nil } } diff --git a/Sources/ExecutableTargets/CommandLineTool/ProjectToOutputCommand.swift b/Sources/ExecutableTargets/CommandLineTool/ProjectToOutputCommand.swift index 94179ca..3002b24 100644 --- a/Sources/ExecutableTargets/CommandLineTool/ProjectToOutputCommand.swift +++ b/Sources/ExecutableTargets/CommandLineTool/ProjectToOutputCommand.swift @@ -29,6 +29,9 @@ struct ProjectToOutputCommand: AsyncParsableCommand { @Option(help: "Specify the old version to compare to") public var old: String + @Option(help: "The platform to build the project for (iOS/macOS)") + public var platform: ProjectPlatform + /// The (optional) scheme to build /// /// Needed when comparing 2 xcode projects @@ -74,6 +77,7 @@ struct ProjectToOutputCommand: AsyncParsableCommand { oldSource: oldSource, newSource: newSource, projectType: projectType, + platform: platform, swiftInterfaceType: swiftInterfaceType, logger: logger ) @@ -136,12 +140,14 @@ private extension ProjectToOutputCommand { oldSource: ProjectSource, newSource: ProjectSource, projectType: ProjectType, + platform: ProjectPlatform, swiftInterfaceType: SwiftInterfaceType, logger: any Logging ) async throws -> ProjectBuilder.Result { let projectBuilder = ProjectBuilder( projectType: projectType, + platform: platform, swiftInterfaceType: swiftInterfaceType, logger: logger ) @@ -207,3 +213,22 @@ private extension ProjectToOutputCommand { ) } } + +extension ProjectPlatform: ExpressibleByArgument { + + static var mapping: [String: ProjectPlatform] = [ + "iOS": .iOS, + "macOS": .macOS + ] + + public init?(argument: String) { + for (key, value) in Self.mapping { + if argument.compare(key, options: .caseInsensitive) == .orderedSame { + self = value + return + } + } + + return nil + } +} diff --git a/Sources/PublicModules/PADProjectBuilder/ProjectBuilder.swift b/Sources/PublicModules/PADProjectBuilder/ProjectBuilder.swift index 7381ab6..4de7a1f 100644 --- a/Sources/PublicModules/PADProjectBuilder/ProjectBuilder.swift +++ b/Sources/PublicModules/PADProjectBuilder/ProjectBuilder.swift @@ -33,6 +33,7 @@ public struct ProjectBuilder { } private let projectType: ProjectType + private let platform: ProjectPlatform private let swiftInterfaceType: SwiftInterfaceType private let fileHandler: any FileHandling private let shell: any ShellHandling @@ -40,11 +41,13 @@ public struct ProjectBuilder { public init( projectType: ProjectType, + platform: ProjectPlatform, swiftInterfaceType: SwiftInterfaceType, logger: (any Logging)? = nil ) { self.init( projectType: projectType, + platform: platform, swiftInterfaceType: swiftInterfaceType, fileHandler: FileManager.default, shell: Shell(), @@ -54,12 +57,14 @@ public struct ProjectBuilder { init( projectType: ProjectType, + platform: ProjectPlatform, swiftInterfaceType: SwiftInterfaceType, fileHandler: any FileHandling = FileManager.default, shell: any ShellHandling = Shell(), logger: (any Logging)? ) { self.projectType = projectType + self.platform = platform self.swiftInterfaceType = swiftInterfaceType self.fileHandler = fileHandler self.shell = shell @@ -99,6 +104,7 @@ public struct ProjectBuilder { let producer = SwiftInterfaceProducer( workingDirectoryPath: workingDirectoryPath, projectType: projectType, + platform: platform, swiftInterfaceType: swiftInterfaceType, fileHandler: fileHandler, shell: shell, diff --git a/Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift b/Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift new file mode 100644 index 0000000..d49fe45 --- /dev/null +++ b/Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift @@ -0,0 +1,13 @@ +// +// ProjectPlatform.swift +// public-api-diff +// +// Created by Alexander Guretzki on 13/11/2024. +// + +/// The platform to build the project on +public enum ProjectPlatform { + + case macOS + case iOS +} diff --git a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer.swift b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer.swift index 43c0511..d70639a 100644 --- a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer.swift +++ b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/SwiftInterfaceProducer.swift @@ -22,6 +22,7 @@ struct SwiftInterfaceProducer { let workingDirectoryPath: String let projectType: ProjectType + let platform: ProjectPlatform let swiftInterfaceType: SwiftInterfaceType let fileHandler: any FileHandling let shell: any ShellHandling @@ -122,12 +123,14 @@ extension SwiftInterfaceProducer { let newDerivedDataPath = try await xcodeTools.archive( projectDirectoryPath: newProjectDirectoryPath, scheme: scheme, - projectType: projectType + projectType: projectType, + platform: platform ) let oldDerivedDataPath = try await xcodeTools.archive( projectDirectoryPath: oldProjectDirectoryPath, scheme: scheme, - projectType: projectType + projectType: projectType, + platform: platform ) return (newDerivedDataPath, oldDerivedDataPath) diff --git a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift index 005ecf7..086d541 100644 --- a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift +++ b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift @@ -49,16 +49,28 @@ struct XcodeTools { func archive( projectDirectoryPath: String, scheme: String, - projectType: ProjectType + projectType: ProjectType, + platform: ProjectPlatform ) async throws -> String { + var commandComponents = [ "cd \(projectDirectoryPath);", "xcodebuild clean build -scheme \"\(scheme)\"", - "-destination \"generic/platform=iOS\"", "-derivedDataPath \(Constants.derivedDataPath)", - "-sdk `\(Constants.simulatorSdkCommand)`", "BUILD_LIBRARY_FOR_DISTRIBUTION=YES" ] + + switch platform { + case .iOS: + commandComponents += [ + "-sdk `\(Constants.simulatorSdkCommand)`", + "-destination \"generic/platform=iOS\"", + ] + case .macOS: + commandComponents += [ + "-destination \"generic/platform=macOS\"", + ] + } switch projectType { case .swiftPackage: diff --git a/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift index 360af4e..a7209c1 100644 --- a/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift +++ b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageDescription.swift @@ -127,14 +127,19 @@ package extension SwiftPackageDescription.Dependency { // TODO: Which other requirements exist? package let exact: [String]? + package let range: [[String: String]]? } } extension SwiftPackageDescription.Dependency.Requirement: CustomStringConvertible { package var description: String { - if let exactVersion = exact?.first { - return "exact: \"\(exactVersion)\"" + if let version = exact?.first { + return "exact: \"\(version)\"" + } + + if let lowerUpper = range?.first, let lower = lowerUpper["lower_bound"], let upper = lowerUpper["upper_bound"] { + return "\"\(lower)\"..<\"\(upper)\"" } return "UNKNOWN_REQUIREMENT" @@ -155,6 +160,7 @@ package extension SwiftPackageDescription { case library = "library" case binary = "binary" case test = "test" + case executable = "executable" } package let name: String @@ -208,6 +214,7 @@ extension SwiftPackageDescription.Target.TargetType: CustomStringConvertible { case .binary: "binaryTarget" case .library: "target" case .test: "testTarget" + case .executable: "executableTarget" } } } diff --git a/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageFileHelper.swift b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageFileHelper.swift index 9b6d06b..bfe29df 100644 --- a/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageFileHelper.swift +++ b/Sources/Shared/Package/SwiftPackageFileHelperModule/SwiftPackageFileHelper.swift @@ -152,9 +152,14 @@ private extension SwiftPackageFileHelper { } func decodePackageDescription(from packageDescriptionData: Data, warnings: [String]) throws -> SwiftPackageDescription { - var packageDescription = try JSONDecoder().decode(SwiftPackageDescription.self, from: packageDescriptionData) - packageDescription.warnings = warnings - return packageDescription + do { + var packageDescription = try JSONDecoder().decode(SwiftPackageDescription.self, from: packageDescriptionData) + packageDescription.warnings = warnings + return packageDescription + } catch { + logger?.log(String(describing: error), from: String(describing: Self.self)) + throw error + } } } diff --git a/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceFileLocator.swift b/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceFileLocator.swift index fa961d1..47cd512 100644 --- a/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceFileLocator.swift +++ b/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceFileLocator.swift @@ -63,14 +63,18 @@ public struct SwiftInterfaceFileLocator { switch type { case .private: swiftInterfacePaths = swiftModuleContent.filter { $0.hasSuffix(".private.swiftinterface") } + case .package: + swiftInterfacePaths = swiftModuleContent.filter { $0.hasSuffix(".package.swiftinterface") } case .public: - swiftInterfacePaths = swiftModuleContent.filter { $0.hasSuffix(".swiftinterface") && !$0.hasSuffix(".private.swiftinterface") } + swiftInterfacePaths = swiftModuleContent.filter { $0.hasSuffix(".swiftinterface") && !$0.hasSuffix(".private.swiftinterface") && !$0.hasSuffix(".package.swiftinterface") } } guard let swiftInterfacePath = swiftInterfacePaths.first else { switch type { case .private: throw FileHandlerError.pathDoesNotExist(path: "'\(completeSwiftModulePath)/\(scheme).private.swiftinterface'") + case .package: + throw FileHandlerError.pathDoesNotExist(path: "'\(completeSwiftModulePath)/\(scheme).package.swiftinterface'") case .public: throw FileHandlerError.pathDoesNotExist(path: "'\(completeSwiftModulePath)/\(scheme).swiftinterface'") } diff --git a/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift b/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift index 407c997..11b45be 100644 --- a/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift +++ b/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift @@ -10,11 +10,13 @@ import Foundation public enum SwiftInterfaceType { case `private` case `public` + case `package` var name: String { switch self { case .private: "private" case .public: "public" + case .package: "package" } } } From 114945d067f4436dd701ad8485274c2a482c3720 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 13 Nov 2024 18:40:32 +0100 Subject: [PATCH 10/13] Fixing tests --- Tests/IntegrationTests/ReferencePackageTests.swift | 14 ++++++++++++-- Tests/UnitTests/XcodeToolsTests.swift | 12 ++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Tests/IntegrationTests/ReferencePackageTests.swift b/Tests/IntegrationTests/ReferencePackageTests.swift index c794fb8..c94302e 100644 --- a/Tests/IntegrationTests/ReferencePackageTests.swift +++ b/Tests/IntegrationTests/ReferencePackageTests.swift @@ -26,8 +26,18 @@ class ReferencePackageTests: XCTestCase { let xcodeTools = XcodeTools(logger: nil) - _ = try await xcodeTools.archive(projectDirectoryPath: oldReferencePackageDirectory.path(), scheme: "ReferencePackage", projectType: .swiftPackage) - _ = try await xcodeTools.archive(projectDirectoryPath: newReferencePackageDirectory.path(), scheme: "ReferencePackage", projectType: .swiftPackage) + _ = try await xcodeTools.archive( + projectDirectoryPath: oldReferencePackageDirectory.path(), + scheme: "ReferencePackage", + projectType: .swiftPackage, + platform: .iOS + ) + _ = try await xcodeTools.archive( + projectDirectoryPath: newReferencePackageDirectory.path(), + scheme: "ReferencePackage", + projectType: .swiftPackage, + platform: .iOS + ) } override static func tearDown() { diff --git a/Tests/UnitTests/XcodeToolsTests.swift b/Tests/UnitTests/XcodeToolsTests.swift index d43a31a..7cdefb2 100644 --- a/Tests/UnitTests/XcodeToolsTests.swift +++ b/Tests/UnitTests/XcodeToolsTests.swift @@ -17,7 +17,8 @@ class XcodeToolsTests: XCTestCase { try await testArchiving( projectDirectoryPath: projectDirectoryPath, scheme: scheme, - projectType: .swiftPackage + projectType: .swiftPackage, + platform: .iOS ) } @@ -29,7 +30,8 @@ class XcodeToolsTests: XCTestCase { try await testArchiving( projectDirectoryPath: projectDirectoryPath, scheme: scheme, - projectType: .xcodeProject(scheme: scheme) + projectType: .xcodeProject(scheme: scheme), + platform: .iOS ) } } @@ -39,7 +41,8 @@ private extension XcodeToolsTests { func testArchiving( projectDirectoryPath: String, scheme: String, - projectType: ProjectType + projectType: ProjectType, + platform: ProjectPlatform ) async throws { let archiveResult = "ARCHIVE_RESULT" @@ -93,7 +96,8 @@ private extension XcodeToolsTests { let derivedDataPath = try await xcodeTools.archive( projectDirectoryPath: projectDirectoryPath, scheme: scheme, - projectType: projectType + projectType: projectType, + platform: platform ) XCTAssertEqual(derivedDataPath, expectedDerivedDataPath) From 7936f14abb0f48aca41441e5e334f862d29ff208 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 13 Nov 2024 19:06:44 +0100 Subject: [PATCH 11/13] Fixing unittests --- Tests/UnitTests/XcodeToolsTests.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/UnitTests/XcodeToolsTests.swift b/Tests/UnitTests/XcodeToolsTests.swift index 7cdefb2..4609351 100644 --- a/Tests/UnitTests/XcodeToolsTests.swift +++ b/Tests/UnitTests/XcodeToolsTests.swift @@ -48,11 +48,13 @@ private extension XcodeToolsTests { let archiveResult = "ARCHIVE_RESULT" let expectedDerivedDataPath = "\(projectDirectoryPath)/.build" var expectedHandleExecuteCalls: [String] = { + let command = "cd \(projectDirectoryPath); xcodebuild clean build -scheme \"\(scheme)\" -derivedDataPath .build BUILD_LIBRARY_FOR_DISTRIBUTION=YES" + let iOSSpecificParameters = "-sdk `xcrun --sdk iphonesimulator --show-sdk-path` -destination \"generic/platform=iOS\"" switch projectType { case .swiftPackage: - ["cd \(projectDirectoryPath); xcodebuild clean build -scheme \"\(scheme)\" -destination \"generic/platform=iOS\" -derivedDataPath .build -sdk `xcrun --sdk iphonesimulator --show-sdk-path` BUILD_LIBRARY_FOR_DISTRIBUTION=YES -skipPackagePluginValidation"] + return ["\(command) \(iOSSpecificParameters) -skipPackagePluginValidation"] case let .xcodeProject(scheme): - ["cd \(projectDirectoryPath); xcodebuild clean build -scheme \"\(scheme)\" -destination \"generic/platform=iOS\" -derivedDataPath .build -sdk `xcrun --sdk iphonesimulator --show-sdk-path` BUILD_LIBRARY_FOR_DISTRIBUTION=YES"] + return ["\(command) \(iOSSpecificParameters)"] } }() var expectedHandleLogCalls: [(message: String, subsystem: String)] = [ From 61d4737035c5ae6c8d49a0c5a4ec28fe840f6275 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Thu, 14 Nov 2024 10:18:15 +0100 Subject: [PATCH 12/13] Adding platform docs to README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 704601f..b6a19bf 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ This method requires an iOS 17.5 Simulator to be installed ``` swift run public-api-diff project + --platform iOS --new "develop~https://github.com/Adyen/adyen-ios.git" --old "5.12.0~https://github.com/Adyen/adyen-ios.git" ``` @@ -28,11 +29,12 @@ swift run public-api-diff
--help: ``` -USAGE: public-api-diff project --new --old [--scheme ] [--swift-interface-type ] [--output ] [--log-output ] [--log-level ] +USAGE: public-api-diff project --new --old --platform [--scheme ] [--swift-interface-type ] [--output ] [--log-output ] [--log-level ] OPTIONS: --new Specify the updated version to compare to --old Specify the old version to compare to + --platform The platform to build the project for (iOS/macOS) --scheme [Optional] Which scheme to build (Needed when comparing 2 xcode projects) --swift-interface-type From ecc50f206489c743184309353ffb246c9f63b5b4 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Thu, 14 Nov 2024 10:38:54 +0100 Subject: [PATCH 13/13] Reducing code duplication --- .../PADProjectBuilder/ProjectPlatform.swift | 5 +- .../SwiftInterfaceProducer/XcodeTools.swift | 4 +- .../SwiftInterfaceType.swift | 2 +- Tests/UnitTests/GitTests.swift | 135 ++++++++++++------ Tests/UnitTests/XcodeToolsTests.swift | 75 +++++++--- 5 files changed, 152 insertions(+), 69 deletions(-) diff --git a/Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift b/Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift index d49fe45..216ef86 100644 --- a/Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift +++ b/Sources/PublicModules/PADProjectBuilder/ProjectPlatform.swift @@ -1,8 +1,7 @@ // -// ProjectPlatform.swift -// public-api-diff +// Copyright (c) 2024 Adyen N.V. // -// Created by Alexander Guretzki on 13/11/2024. +// This file is open source and available under the MIT license. See the LICENSE file for more info. // /// The platform to build the project on diff --git a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift index 086d541..350fc8a 100644 --- a/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift +++ b/Sources/PublicModules/PADProjectBuilder/SwiftInterfaceProducer/XcodeTools.swift @@ -64,11 +64,11 @@ struct XcodeTools { case .iOS: commandComponents += [ "-sdk `\(Constants.simulatorSdkCommand)`", - "-destination \"generic/platform=iOS\"", + "-destination \"generic/platform=iOS\"" ] case .macOS: commandComponents += [ - "-destination \"generic/platform=macOS\"", + "-destination \"generic/platform=macOS\"" ] } diff --git a/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift b/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift index 11b45be..d6b1dbb 100644 --- a/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift +++ b/Sources/Shared/Public/PADSwiftInterfaceFileLocator/SwiftInterfaceType.swift @@ -10,7 +10,7 @@ import Foundation public enum SwiftInterfaceType { case `private` case `public` - case `package` + case package var name: String { switch self { diff --git a/Tests/UnitTests/GitTests.swift b/Tests/UnitTests/GitTests.swift index 461f5cb..96f0972 100644 --- a/Tests/UnitTests/GitTests.swift +++ b/Tests/UnitTests/GitTests.swift @@ -16,36 +16,30 @@ class GitTests: XCTestCase { let targetDirectoryPath = "targetDirectoryPath" let shellResult = "shell-result" - let shellExpectation = expectation(description: "MockShell.execute was called once") - let fileHandlerExpectation = expectation(description: "MockFileHandler.handleContentsOfDirectory was called once") - let loggerLogExpectation = expectation(description: "MockLogger.handleLog was called once") - let loggerDebugExpectation = expectation(description: "MockLogger.handleDebug was called once") - let allExpectations = [shellExpectation, fileHandlerExpectation, loggerLogExpectation, loggerDebugExpectation] + let shellSetup = setupShell( + branch: branch, + repository: repository, + targetDirectoryPath: targetDirectoryPath, + result: shellResult + ) - let mockShell = MockShell { command in - XCTAssertEqual(command, "git clone -b \(branch) \(repository) \(targetDirectoryPath)") - shellExpectation.fulfill() - return shellResult - } - var mockFileHandler = MockFileHandler() - mockFileHandler.handleContentsOfDirectory = { directoryPath in - XCTAssertEqual(targetDirectoryPath, directoryPath) - fileHandlerExpectation.fulfill() - return ["NonEmpty"] - } - var mockLogger = MockLogger() - mockLogger.handleLog = { message, subsystem in - XCTAssertEqual(message, "🐱 Cloning repository @ branch into targetDirectoryPath") - XCTAssertEqual(subsystem, "Git") - loggerLogExpectation.fulfill() - } - mockLogger.handleDebug = { message, subsystem in - XCTAssertEqual(message, shellResult) - XCTAssertEqual(subsystem, "Git") - loggerDebugExpectation.fulfill() - } + let fileHandlerSetup = setupFileHandler( + targetDirectoryPath: targetDirectoryPath, + result: ["NonEmpty"] + ) + + let loggerSetup = setupLogger( + shellResult: shellResult + ) + + let allExpectations = [shellSetup.expectation, fileHandlerSetup.expectation] + loggerSetup.expectations + + let git = Git( + shell: shellSetup.shell, + fileHandler: fileHandlerSetup.fileHandler, + logger: loggerSetup.logger + ) - let git = Git(shell: mockShell, fileHandler: mockFileHandler, logger: mockLogger) try git.clone(repository, at: branch, targetDirectoryPath: targetDirectoryPath) wait(for: allExpectations, timeout: 1) @@ -58,24 +52,85 @@ class GitTests: XCTestCase { let targetDirectoryPath = "targetDirectoryPath" let shellResult = "shell-result" + let shellSetup = setupShell( + branch: branch, + repository: repository, + targetDirectoryPath: targetDirectoryPath, + result: shellResult + ) + + let fileHandlerSetup = setupFileHandler( + targetDirectoryPath: targetDirectoryPath, + result: [] + ) + + let loggerSetup = setupLogger( + shellResult: shellResult + ) + + let allExpectations = [shellSetup.expectation, fileHandlerSetup.expectation] + loggerSetup.expectations + + let git = Git( + shell: shellSetup.shell, + fileHandler: fileHandlerSetup.fileHandler, + logger: loggerSetup.logger + ) + + do { + try git.clone(repository, at: branch, targetDirectoryPath: targetDirectoryPath) + XCTFail("Clone should have thrown an error") + } catch { + let fileHandlerError = try XCTUnwrap(error as? GitError) + XCTAssertEqual(fileHandlerError, GitError.couldNotClone(branchOrTag: branch, repository: repository)) + } + + wait(for: allExpectations, timeout: 1) + } +} + +private extension GitTests { + + func setupShell( + branch: String, + repository: String, + targetDirectoryPath: String, + result: String + ) -> (shell: MockShell, expectation: XCTestExpectation) { + let shellExpectation = expectation(description: "MockShell.execute was called once") - let fileHandlerExpectation = expectation(description: "MockFileHandler.handleContentsOfDirectory was called once") - let loggerLogExpectation = expectation(description: "MockLogger.handleLog was called once") - let loggerDebugExpectation = expectation(description: "MockLogger.handleDebug was called once") - let allExpectations = [shellExpectation, fileHandlerExpectation, loggerLogExpectation, loggerDebugExpectation] let mockShell = MockShell { command in XCTAssertEqual(command, "git clone -b \(branch) \(repository) \(targetDirectoryPath)") shellExpectation.fulfill() - return shellResult + return result } + return (mockShell, shellExpectation) + } + + func setupFileHandler( + targetDirectoryPath: String, + result: [String] + ) -> (fileHandler: MockFileHandler, expectation: XCTestExpectation) { + + let fileHandlerExpectation = expectation(description: "MockFileHandler.handleContentsOfDirectory was called once") + var mockFileHandler = MockFileHandler() mockFileHandler.handleContentsOfDirectory = { directoryPath in XCTAssertEqual(targetDirectoryPath, directoryPath) fileHandlerExpectation.fulfill() - return [] + return result } + return (mockFileHandler, fileHandlerExpectation) + } + + func setupLogger( + shellResult: String + ) -> (logger: MockLogger, expectations: [XCTestExpectation]) { + + let loggerLogExpectation = expectation(description: "MockLogger.handleLog was called once") + let loggerDebugExpectation = expectation(description: "MockLogger.handleDebug was called once") + var mockLogger = MockLogger() mockLogger.handleLog = { message, subsystem in XCTAssertEqual(message, "🐱 Cloning repository @ branch into targetDirectoryPath") @@ -88,16 +143,6 @@ class GitTests: XCTestCase { loggerDebugExpectation.fulfill() } - let git = Git(shell: mockShell, fileHandler: mockFileHandler, logger: mockLogger) - - do { - try git.clone(repository, at: branch, targetDirectoryPath: targetDirectoryPath) - XCTFail("Clone should have thrown an error") - } catch { - let fileHandlerError = try XCTUnwrap(error as? GitError) - XCTAssertEqual(fileHandlerError, GitError.couldNotClone(branchOrTag: branch, repository: repository)) - } - - wait(for: allExpectations, timeout: 1) + return (mockLogger, [loggerLogExpectation, loggerDebugExpectation]) } } diff --git a/Tests/UnitTests/XcodeToolsTests.swift b/Tests/UnitTests/XcodeToolsTests.swift index 4609351..4761f4a 100644 --- a/Tests/UnitTests/XcodeToolsTests.swift +++ b/Tests/UnitTests/XcodeToolsTests.swift @@ -9,54 +9,93 @@ import XCTest class XcodeToolsTests: XCTestCase { - func test_archive_swiftPackage() async throws { + func test_archive_swiftPackage_iOS() async throws { let projectDirectoryPath = "PROJECT_DIRECTORY_PATH" - let scheme = "SCHEME" try await testArchiving( projectDirectoryPath: projectDirectoryPath, - scheme: scheme, projectType: .swiftPackage, platform: .iOS ) } - func test_archive_xcodeProject() async throws { + func test_archive_xcodeProject_iOS() async throws { let projectDirectoryPath = "PROJECT_DIRECTORY_PATH" - let scheme = "SCHEME" try await testArchiving( projectDirectoryPath: projectDirectoryPath, - scheme: scheme, - projectType: .xcodeProject(scheme: scheme), + projectType: .xcodeProject(scheme: "SCHEME"), platform: .iOS ) } + + func test_archive_swiftPackage_macOS() async throws { + + let projectDirectoryPath = "PROJECT_DIRECTORY_PATH" + + try await testArchiving( + projectDirectoryPath: projectDirectoryPath, + projectType: .swiftPackage, + platform: .macOS + ) + } + + func test_archive_xcodeProject_macOS() async throws { + + let projectDirectoryPath = "PROJECT_DIRECTORY_PATH" + + try await testArchiving( + projectDirectoryPath: projectDirectoryPath, + projectType: .xcodeProject(scheme: "SCHEME"), + platform: .macOS + ) + } } private extension XcodeToolsTests { + func expectedCommand(projectDirectoryPath: String, scheme: String, projectType: ProjectType, platform: ProjectPlatform) -> String { + + var commandComponents = [ + "cd \(projectDirectoryPath);", + "xcodebuild clean build -scheme \"\(scheme)\"", + "-derivedDataPath .build BUILD_LIBRARY_FOR_DISTRIBUTION=YES" + ] + + switch platform { + case .macOS: + commandComponents += ["-destination \"generic/platform=macOS\""] + case .iOS: + commandComponents += ["-sdk `xcrun --sdk iphonesimulator --show-sdk-path` -destination \"generic/platform=iOS\""] + } + + switch projectType { + case .swiftPackage: + commandComponents += ["-skipPackagePluginValidation"] + case .xcodeProject: + break // Nothing specific to add + } + + return String(commandComponents.joined(separator: " ")) + } + func testArchiving( projectDirectoryPath: String, - scheme: String, projectType: ProjectType, platform: ProjectPlatform ) async throws { + let scheme = "SCHEME" let archiveResult = "ARCHIVE_RESULT" let expectedDerivedDataPath = "\(projectDirectoryPath)/.build" - var expectedHandleExecuteCalls: [String] = { - let command = "cd \(projectDirectoryPath); xcodebuild clean build -scheme \"\(scheme)\" -derivedDataPath .build BUILD_LIBRARY_FOR_DISTRIBUTION=YES" - let iOSSpecificParameters = "-sdk `xcrun --sdk iphonesimulator --show-sdk-path` -destination \"generic/platform=iOS\"" - switch projectType { - case .swiftPackage: - return ["\(command) \(iOSSpecificParameters) -skipPackagePluginValidation"] - case let .xcodeProject(scheme): - return ["\(command) \(iOSSpecificParameters)"] - } - }() + var expectedHandleExecuteCalls: [String] = { [expectedCommand( + projectDirectoryPath: projectDirectoryPath, + scheme: scheme, + projectType: projectType, + platform: platform + )] }() var expectedHandleLogCalls: [(message: String, subsystem: String)] = [ ("📦 Archiving SCHEME from PROJECT_DIRECTORY_PATH", "XcodeTools") ]