From 2867c7b53a4d89f665063f0500da500d5dee6e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Pi=C3=B1era=20Buend=C3=ADa?= <663605+pepicrft@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:29:20 +0100 Subject: [PATCH] Scope logger to test cases (#7194) * Add apple-service-context dependency * Rename TuistApp to TuistCLI * Use the service context to pass the logger instance * Adjust TuistSupport to use the logger from the context service * Adjust TuistCore to use the logger from the service context * Adjust TuistServer to read the logger from the ServiceContext in the task local * Adjust TuistPlugin to use the logger from the ServiceContext in the task local * Update TuistHasher to use the logger from the ServiceContext instance in the task local * Update TuistGenerator to get the logger from the ServiceContext instance in the task local * Update TuistAutomation to use the logger from the ServiceContext in the task local * Update TuistMigration to get the logger from the ServiceContext instance in the taxk actor * Update TuistLoader to read the ServiceContext from the task local * Update TuistDependencies to use ServiceContext from the task local * Update TuistAsyncQueue to use the logger from the ServiceContext in the task local * Update TuistKit to use the logger from the ServiceContext in the task local * Create an interface to dependency-inject the testing logger * Fix tests * Make implicit dependency explicit * Add missing dependency to the Package.swift * Some lint fixes --- Package.resolved | 20 +- Package.swift | 3 + .../ServerAcceptanceTestCase.swift | 1 - .../TuistAcceptanceTestCase.swift | 4 - .../TuistAcceptanceTestCaseLogHandler.swift | 48 - Sources/TuistAnalytics/Log/Logger.swift | 3 - Sources/TuistAsyncQueue/AsyncQueue.swift | 18 +- Sources/TuistAsyncQueue/Log/Logger.swift | 3 - .../Device/DeviceController.swift | 6 +- Sources/TuistAutomation/Log/Logger.swift | 3 - .../SkipUITestsProjectMapper.swift | 3 +- .../SourceRootPathProjectMapper.swift | 3 +- .../TuistAutomation/Utilities/AppRunner.swift | 5 +- .../Utilities/BuildGraphInspector.swift | 3 +- .../Utilities/TargetBuilder.swift | 9 +- .../Utilities/TargetRunner.swift | 10 +- .../XcodeBuild/XcodeBuildController.swift | 7 +- Sources/TuistCore/Log/Logger.swift | 3 - .../XCFrameworkMetadataProvider.swift | 3 +- Sources/TuistCore/Models/LintingIssue.swift | 5 +- .../Simulator/SimulatorController.swift | 6 +- Sources/TuistDependencies/Log/Logger.swift | 3 - ...lProjectsPlatformNarrowerGraphMapper.swift | 3 +- ...runeOrphanExternalTargetsGraphMapper.swift | 4 +- .../SideEffectDescriptorExecutor.swift | 3 +- .../ProjectDescriptorGenerator.swift | 3 +- .../WorkspaceDescriptorGenerator.swift | 3 +- Sources/TuistGenerator/Log/Logger.swift | 3 - .../AutogeneratedSchemesProjectMapper.swift | 3 +- ...eratedWorkspaceSchemeWorkspaceMapper.swift | 4 +- .../DeleteDerivedDirectoryProjectMapper.swift | 3 +- .../ExplicitDependencyGraphMapper.swift | 3 +- .../GenerateEntitlementsProjectMapper.swift | 3 +- .../GenerateInfoPlistProjectMapper.swift | 3 +- ...GeneratePrivacyManifestProjectMapper.swift | 3 +- .../Mappers/IDETemplateMacrosMapper.swift | 7 +- .../LastUpgradeVersionWorkspaceMapper.swift | 4 +- .../Mappers/ModuleMapMapper.swift | 3 +- .../Mappers/ResourcesProjectMapper.swift | 3 +- ...esizedResourceInterfaceProjectMapper.swift | 5 +- ...ctionDisableShowEnvVarsProjectMapper.swift | 3 +- .../Utils/SwiftPackageManagerInteractor.swift | 7 +- Sources/TuistHasher/Log/Logger.swift | 3 - .../TargetScriptsContentHasher.swift | 3 +- Sources/TuistKit/Commands/BuildCommand.swift | 3 +- .../Cache/CachePrintHashesService.swift | 7 +- .../Commands/Cache/CacheService.swift | 3 +- Sources/TuistKit/Commands/TestCommand.swift | 5 +- Sources/TuistKit/Commands/TuistCommand.swift | 7 +- Sources/TuistKit/Generator/Generator.swift | 5 +- Sources/TuistKit/Log/Logger.swift | 3 - .../UpdateWorkspaceProjectsGraphMapper.swift | 3 +- .../TreeShakePrunedTargetsGraphMapper.swift | 3 +- .../TuistWorkspaceIdentifierMapper.swift | 3 +- .../TuistWorkspaceRenderMarkdownMapper.swift | 3 +- .../ProjectEditor/ProjectEditorMapper.swift | 3 +- Sources/TuistKit/Services/BuildService.swift | 5 +- Sources/TuistKit/Services/CleanService.swift | 10 +- Sources/TuistKit/Services/DumpService.swift | 3 +- Sources/TuistKit/Services/EditService.swift | 10 +- .../TuistKit/Services/GenerateService.swift | 5 +- Sources/TuistKit/Services/GraphService.swift | 7 +- Sources/TuistKit/Services/InitService.swift | 5 +- .../InspecImplicitImportsService.swift | 3 +- .../TuistKit/Services/InstallService.swift | 9 +- Sources/TuistKit/Services/ListService.swift | 5 +- Sources/TuistKit/Services/LoginService.swift | 14 +- ...igrationTargetsByDependenciesService.swift | 3 +- .../OrganizationCreateService.swift | 3 +- .../OrganizationDeleteService.swift | 3 +- .../OrganizationInviteService.swift | 3 +- .../OrganizationListService.swift | 8 +- .../OrganizationRemoveInviteService.swift | 4 +- .../OrganizationRemoveMemberService.swift | 4 +- .../OrganizationRemoveSSOService.swift | 3 +- .../OrganizationShowService.swift | 5 +- .../OrganizationUpdateMemberService.swift | 3 +- .../OrganizationUpdateService.swift | 3 +- .../Plugin/PluginArchiveService.swift | 7 +- .../Project/ProjectCreateService.swift | 3 +- .../Project/ProjectDeleteService.swift | 3 +- .../Services/Project/ProjectListService.swift | 8 +- .../Services/Project/ProjectShowService.swift | 3 +- .../Project/ProjectTokensCreateService.swift | 3 +- .../Project/ProjectTokensListService.swift | 6 +- .../Project/ProjectTokensRevokeService.swift | 3 +- .../Project/ProjectUpdateService.swift | 3 +- .../Registry/RegistryLoginService.swift | 5 +- .../Registry/RegistryLogoutService.swift | 5 +- .../Registry/RegistrySetupService.swift | 5 +- Sources/TuistKit/Services/RunService.swift | 8 +- .../TuistKit/Services/ScaffoldService.swift | 3 +- Sources/TuistKit/Services/ShareService.swift | 8 +- Sources/TuistKit/Services/TestService.swift | 28 +- Sources/TuistKit/Services/TuistService.swift | 3 +- Sources/TuistKit/Services/WhoamiService.swift | 5 +- .../Utils/TuistAnalyticsServerBackend.swift | 3 +- .../Loaders/CachedManifestLoader.swift | 3 +- .../TuistLoader/Loaders/ManifestLoader.swift | 14 +- .../SwiftPackageManagerGraphLoader.swift | 4 +- Sources/TuistLoader/Log/Logger.swift | 3 - .../CopyFileElement+ManifestMapper.swift | 11 +- .../FileElement+ManifestMapper.swift | 11 +- .../ResourceFileElement+ManifestMapper.swift | 11 +- .../Workspace+ManifestMapper.swift | 3 +- .../ProjectDescriptionHelpersBuilder.swift | 3 +- .../PackageInfoMapper.swift | 7 +- Sources/TuistMigration/Log/Logger.swift | 3 - .../Utilities/EmptyBuildSettingsChecker.swift | 4 +- .../SettingsToXCConfigExtractor.swift | 8 +- Sources/TuistPlugin/Logger.swift | 3 - Sources/TuistPlugin/PluginService.swift | 13 +- ...ServerClientOutputWarningsMiddleware.swift | 4 +- ...ServerClientVerboseLoggingMiddleware.swift | 5 +- Sources/TuistServer/Log/Logger.swift | 3 - .../Session/ServerSessionController.swift | 5 +- .../TuistServer/Utilities/RetryProvider.swift | 3 +- .../ServerAuthenticationController.swift | 6 +- .../TuistSupport/Errors/ErrorHandler.swift | 5 +- Sources/TuistSupport/Logging/Logger.swift | 68 +- .../SwiftPackageManagerController.swift | 3 +- Sources/TuistSupport/System/System.swift | 9 +- Sources/TuistSupport/UserInputReader.swift | 9 +- .../Extensions/XCTestCase+Extras.swift | 28 +- .../TestCase/ServiceContext+Tests.swift | 37 + .../TestCase/TuistTestCase.swift | 27 +- .../Utils/TestingLogHandler.swift | 47 +- .../tuist/{TuistApp.swift => TuistCLI.swift} | 33 +- .../XCFrameworkMetadataProviderTests.swift | 111 +- .../DependenciesAcceptanceTests.swift | 26 +- .../GenerateAcceptanceTests.swift | 35 +- ...dResourceInterfaceProjectMapperTests.swift | 560 ++++----- .../CacheAcceptanceTests.swift | 23 +- .../InspectAcceptanceTests.swift | 9 +- .../ListTargetsAcceptanceTests.swift | 13 +- .../ProjectAcceptanceTests.swift | 148 +-- .../ShareAcceptanceTests.swift | 147 +-- .../DumpServiceIntegrationTests.swift | 645 +++++----- .../Services/BuildServiceTests.swift | 55 +- .../Cache/CachePrintHashesServiceTests.swift | 51 +- .../Services/CleanServiceTests.swift | 87 +- .../Services/GenerateServiceTests.swift | 49 +- .../Services/GraphServiceTests.swift | 123 +- .../Services/ListServiceTests.swift | 173 +-- .../Services/LoginServiceTests.swift | 209 ++-- .../OrganizationInviteServiceTests.swift | 49 +- .../OrganizationListServiceTests.swift | 55 +- .../OrganizationRemoveSSOServiceTests.swift | 37 +- .../OrganizationShowServiceTests.swift | 215 ++-- .../OrganizationUpdateSSOServiceTests.swift | 81 +- .../Plugin/PluginArchiveServiceTests.swift | 45 +- .../Project/ProjectListServiceTests.swift | 59 +- .../Project/ProjectShowServiceTests.swift | 244 ++-- .../ProjectTokensCreateServiceTests.swift | 30 +- .../ProjectTokensListServiceTests.swift | 89 +- .../ProjectTokensRevokeServiceTests.swift | 35 +- .../Project/ProjectUpdateServiceTests.swift | 103 +- .../Services/ShareServiceTests.swift | 1089 +++++++++-------- .../Services/TestServiceTests.swift | 735 +++++------ .../Services/WhoamiServiceTests.swift | 37 +- .../TuistAnalyticsServerBackendTests.swift | 175 +-- .../Loaders/ManifestModelConverterTests.swift | 43 +- .../SwiftPackageManagerGraphLoaderTests.swift | 155 +-- .../CopyFileElement+ManifestMapperTests.swift | 131 +- .../FileElement+ManifestMapperTests.swift | 143 ++- ...sourceFileElementManifestMapperTests.swift | 303 ++--- ...BuildSettingsCheckerIntegrationTests.swift | 43 +- ...sToXCConfigExtractorIntegrationTests.swift | 217 ++-- ...rClientOutputWarningsMiddlewareTests.swift | 47 +- .../ServerSessionControllerTests.swift | 73 +- .../ServerAuthenticationControllerTests.swift | 197 +-- .../Errors/ErrorHandlerTests.swift | 29 +- .../Utils/UserInputReaderTests.swift | 51 +- Tuist/ProjectDescriptionHelpers/Module.swift | 3 + 174 files changed, 4180 insertions(+), 3716 deletions(-) delete mode 100644 Sources/TuistAcceptanceTesting/TuistAcceptanceTestCaseLogHandler.swift delete mode 100644 Sources/TuistAnalytics/Log/Logger.swift delete mode 100644 Sources/TuistAsyncQueue/Log/Logger.swift delete mode 100644 Sources/TuistAutomation/Log/Logger.swift delete mode 100644 Sources/TuistCore/Log/Logger.swift delete mode 100644 Sources/TuistDependencies/Log/Logger.swift delete mode 100644 Sources/TuistGenerator/Log/Logger.swift delete mode 100644 Sources/TuistHasher/Log/Logger.swift delete mode 100644 Sources/TuistKit/Log/Logger.swift delete mode 100644 Sources/TuistLoader/Log/Logger.swift delete mode 100644 Sources/TuistMigration/Log/Logger.swift delete mode 100644 Sources/TuistPlugin/Logger.swift delete mode 100644 Sources/TuistServer/Log/Logger.swift create mode 100644 Sources/TuistSupportTesting/TestCase/ServiceContext+Tests.swift rename Sources/tuist/{TuistApp.swift => TuistCLI.swift} (60%) diff --git a/Package.resolved b/Package.resolved index 4210ef622ec..9c92d40c23c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "bf0667dacb79660d6272837f5c8857de0bc8cebff357be450933f9d91e77965e", + "originHash" : "a5463ecc4f8a522ac814a97c426e0720fabee269b69720a02aeea1507736824f", "pins" : [ { "identity" : "aexml", @@ -235,6 +235,15 @@ "version" : "1.6.1" } }, + { + "identity" : "swift-log-oslog", + "kind" : "remoteSourceControl", + "location" : "https://github.com/chrisaljoudi/swift-log-oslog.git", + "state" : { + "revision" : "176d41d46429e79c806333025b226e0c50a0c602", + "version" : "0.2.2" + } + }, { "identity" : "swift-nio", "kind" : "remoteSourceControl", @@ -262,6 +271,15 @@ "version" : "1.0.2" } }, + { + "identity" : "swift-service-context", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-service-context", + "state" : { + "revision" : "0c62c5b4601d6c125050b5c3a97f20cce881d32b", + "version" : "1.1.0" + } + }, { "identity" : "swift-syntax", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index def3a59cb95..87ec2b83bdf 100644 --- a/Package.swift +++ b/Package.swift @@ -121,6 +121,7 @@ let targets: [Target] = [ "Mockable", "FileSystem", "Command", + .product(name: "ServiceContextModule", package: "swift-service-context"), ], swiftSettings: [ .define("MOCKING", .when(configuration: .debug)), @@ -517,6 +518,8 @@ let package = Package( .package(url: "https://github.com/tuist/Command.git", exact: "0.8.0"), .package(url: "https://github.com/sparkle-project/Sparkle.git", from: "2.6.4"), .package(url: "https://github.com/apple/swift-collections", .upToNextMajor(from: "1.1.4")), + .package(url: "https://github.com/apple/swift-service-context", .upToNextMajor(from: "1.0.0")), + .package(url: "https://github.com/chrisaljoudi/swift-log-oslog.git", .upToNextMajor(from: "0.2.2")), ], targets: targets ) diff --git a/Sources/TuistAcceptanceTesting/ServerAcceptanceTestCase.swift b/Sources/TuistAcceptanceTesting/ServerAcceptanceTestCase.swift index d3d92c33ce1..cfa6b031a73 100644 --- a/Sources/TuistAcceptanceTesting/ServerAcceptanceTestCase.swift +++ b/Sources/TuistAcceptanceTesting/ServerAcceptanceTestCase.swift @@ -38,7 +38,6 @@ open class ServerAcceptanceTestCase: TuistAcceptanceTestCase { try await run(ProjectDeleteCommand.self, fullHandle) try await run(OrganizationDeleteCommand.self, organizationHandle) try await run(LogoutCommand.self) - TestingLogHandler.reset() try await super.tearDown() } } diff --git a/Sources/TuistAcceptanceTesting/TuistAcceptanceTestCase.swift b/Sources/TuistAcceptanceTesting/TuistAcceptanceTestCase.swift index ada95ae9693..ab8d761821f 100644 --- a/Sources/TuistAcceptanceTesting/TuistAcceptanceTestCase.swift +++ b/Sources/TuistAcceptanceTesting/TuistAcceptanceTestCase.swift @@ -32,10 +32,6 @@ open class TuistAcceptanceTestCase: XCTestCase { fileSystem = FileSystem() - DispatchQueue.once(token: "io.tuist.test.logging") { - LoggingSystem.bootstrap { AcceptanceTestCaseLogHandler(label: $0) } - } - derivedDataDirectory = try TemporaryDirectory(removeTreeOnDeinit: true) fixtureTemporaryDirectory = try TemporaryDirectory(removeTreeOnDeinit: true) diff --git a/Sources/TuistAcceptanceTesting/TuistAcceptanceTestCaseLogHandler.swift b/Sources/TuistAcceptanceTesting/TuistAcceptanceTestCaseLogHandler.swift deleted file mode 100644 index 698b46b9164..00000000000 --- a/Sources/TuistAcceptanceTesting/TuistAcceptanceTestCaseLogHandler.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Foundation -import TuistSupport -import TuistSupportTesting - -public struct AcceptanceTestCaseLogHandler: LogHandler { - private let standardLogHandler: StandardLogHandler - private let testingLogHandler: TestingLogHandler - - public init(label: String) { - standardLogHandler = StandardLogHandler(label: label, logLevel: logLevel) - testingLogHandler = TestingLogHandler(label: label) - } - - public func log( - level: Logger.Level, - message: Logger.Message, - metadata: Logger.Metadata?, - source _: String, - file: String, - function: String, - line: UInt - ) { - standardLogHandler.log( - level: level, - message: message, - metadata: metadata, - file: file, - function: function, - line: line - ) - testingLogHandler.log( - level: level, - message: message, - metadata: metadata, - file: file, - function: function, - line: line - ) - } - - public subscript(metadataKey key: String) -> Logger.Metadata.Value? { - get { metadata[key] } - set { metadata[key] = newValue } - } - - public var metadata = Logging.Logger.Metadata() - public var logLevel: Logging.Logger.Level = .info -} diff --git a/Sources/TuistAnalytics/Log/Logger.swift b/Sources/TuistAnalytics/Log/Logger.swift deleted file mode 100644 index a4d4e6e2f0a..00000000000 --- a/Sources/TuistAnalytics/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.analytics") diff --git a/Sources/TuistAsyncQueue/AsyncQueue.swift b/Sources/TuistAsyncQueue/AsyncQueue.swift index 6e730bda8eb..834c484d50b 100644 --- a/Sources/TuistAsyncQueue/AsyncQueue.swift +++ b/Sources/TuistAsyncQueue/AsyncQueue.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Queuer +import ServiceContextModule import TuistCore import TuistSupport @@ -73,7 +74,8 @@ public class AsyncQueue: AsyncQueuing { public func dispatch(event: some AsyncQueueEvent) throws { guard let dispatcher = dispatchers[event.dispatcherId] else { - logger.debug("Couldn't find dispatcher with id: \(event.dispatcherId), skipping dispatching \(event.id)") + ServiceContext.current?.logger? + .debug("Couldn't find dispatcher with id: \(event.dispatcherId), skipping dispatching \(event.id)") return } @@ -89,7 +91,8 @@ public class AsyncQueue: AsyncQueuing { private func liveDispatchOperation(event: some AsyncQueueEvent, dispatcher: AsyncQueueDispatching) -> Operation { AsyncConcurrentOperation(name: event.id.uuidString) { operation in - logger.debug("Dispatching event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'") + ServiceContext.current?.logger? + .debug("Dispatching event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'") do { try dispatcher.dispatch(event: event) { try await self.persistor.delete(event: event) @@ -108,7 +111,8 @@ public class AsyncQueue: AsyncQueuing { private func dispatchPersisted(eventTuple: AsyncQueueEventTuple) async throws { guard let dispatcher = dispatchers.first(where: { $0.key == eventTuple.dispatcherId })?.value else { try await deletePersistedEvent(filename: eventTuple.filename) - logger.error("Couldn't find dispatcher for persisted event with id: \(eventTuple.dispatcherId)") + ServiceContext.current?.logger? + .error("Couldn't find dispatcher for persisted event with id: \(eventTuple.dispatcherId)") return } @@ -122,12 +126,14 @@ public class AsyncQueue: AsyncQueuing { ) -> Operation { ConcurrentOperation(name: event.id.uuidString) { _ in do { - logger.debug("Dispatching persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'") + ServiceContext.current?.logger? + .debug("Dispatching persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'") try dispatcher.dispatchPersisted(data: event.data) { try await self.deletePersistedEvent(filename: event.filename) } } catch { - logger.debug("Failed to dispatch persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'") + ServiceContext.current?.logger? + .debug("Failed to dispatch persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'") } } } @@ -139,7 +145,7 @@ public class AsyncQueue: AsyncQueuing { try await dispatchPersisted(eventTuple: event) } } catch { - logger.debug("Error loading persisted events: \(error)") + ServiceContext.current?.logger?.debug("Error loading persisted events: \(error)") } } diff --git a/Sources/TuistAsyncQueue/Log/Logger.swift b/Sources/TuistAsyncQueue/Log/Logger.swift deleted file mode 100644 index a7c4210612b..00000000000 --- a/Sources/TuistAsyncQueue/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.async-queue") diff --git a/Sources/TuistAutomation/Device/DeviceController.swift b/Sources/TuistAutomation/Device/DeviceController.swift index 793dede4916..cfd4c4d191e 100644 --- a/Sources/TuistAutomation/Device/DeviceController.swift +++ b/Sources/TuistAutomation/Device/DeviceController.swift @@ -3,6 +3,7 @@ import FileSystem import Foundation import Mockable import Path +import ServiceContextModule import TuistSupport import XcodeGraph @@ -84,7 +85,7 @@ public final class DeviceController: DeviceControlling { at path: AbsolutePath, device: PhysicalDevice ) async throws { - logger.debug("Installing app at \(path) on simulator device with id \(device.id)") + ServiceContext.current?.logger?.debug("Installing app at \(path) on simulator device with id \(device.id)") do { _ = try await commandRunner.run( arguments: [ @@ -108,7 +109,8 @@ public final class DeviceController: DeviceControlling { bundleId: String, device: PhysicalDevice ) async throws { - logger.debug("Launching app with bundle id \(bundleId) on a physical device with id \(device.id)") + ServiceContext.current?.logger? + .debug("Launching app with bundle id \(bundleId) on a physical device with id \(device.id)") _ = try await commandRunner.run( arguments: [ "/usr/bin/xcrun", "devicectl", diff --git a/Sources/TuistAutomation/Log/Logger.swift b/Sources/TuistAutomation/Log/Logger.swift deleted file mode 100644 index 6b01338a82f..00000000000 --- a/Sources/TuistAutomation/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.automation") diff --git a/Sources/TuistAutomation/ProjectMappers/SkipUITestsProjectMapper.swift b/Sources/TuistAutomation/ProjectMappers/SkipUITestsProjectMapper.swift index a62b7acef40..88203e430a6 100644 --- a/Sources/TuistAutomation/ProjectMappers/SkipUITestsProjectMapper.swift +++ b/Sources/TuistAutomation/ProjectMappers/SkipUITestsProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import XcodeGraph @@ -7,7 +8,7 @@ public final class SkipUITestsProjectMapper: ProjectMapping { public init() {} public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Pruning UI tests targets") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Pruning UI tests targets") var project = project project.targets = project.targets.mapValues { target in diff --git a/Sources/TuistAutomation/ProjectMappers/SourceRootPathProjectMapper.swift b/Sources/TuistAutomation/ProjectMappers/SourceRootPathProjectMapper.swift index 0dd41a88f4b..1ebec45b999 100644 --- a/Sources/TuistAutomation/ProjectMappers/SourceRootPathProjectMapper.swift +++ b/Sources/TuistAutomation/ProjectMappers/SourceRootPathProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import XcodeGraph @@ -12,7 +13,7 @@ public final class SourceRootPathProjectMapper: ProjectMapping { public init() {} public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Setting $SRCROOT to \(project.name)") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Setting $SRCROOT to \(project.name)") var project = project var base = project.settings.base diff --git a/Sources/TuistAutomation/Utilities/AppRunner.swift b/Sources/TuistAutomation/Utilities/AppRunner.swift index 05ae877a402..6c6db437c50 100644 --- a/Sources/TuistAutomation/Utilities/AppRunner.swift +++ b/Sources/TuistAutomation/Utilities/AppRunner.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Mockable import Path +import ServiceContextModule import struct TSCUtility.Version import TuistCore import TuistSupport @@ -171,11 +172,11 @@ public final class AppRunner: AppRunning { }) else { throw AppRunnerError.selectedPlatformNotFound(simulatorPlatform.caseValue) } - logger.notice("Installing and launching \(appBundle.infoPlist.name) on \(simulator.device.name)") + ServiceContext.current?.logger?.notice("Installing and launching \(appBundle.infoPlist.name) on \(simulator.device.name)") let device = try simulatorController.booted(device: simulator.device) try simulatorController.installApp(at: appBundle.path, device: device) try await simulatorController.launchApp(bundleId: appBundle.infoPlist.bundleId, device: device, arguments: []) - logger.notice("\(appBundle.infoPlist.name) was successfully launched 📲", metadata: .success) + ServiceContext.current?.logger?.notice("\(appBundle.infoPlist.name) was successfully launched 📲", metadata: .success) } } diff --git a/Sources/TuistAutomation/Utilities/BuildGraphInspector.swift b/Sources/TuistAutomation/Utilities/BuildGraphInspector.swift index 6fe5574b389..238db47b89b 100644 --- a/Sources/TuistAutomation/Utilities/BuildGraphInspector.swift +++ b/Sources/TuistAutomation/Utilities/BuildGraphInspector.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Mockable import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -93,7 +94,7 @@ public final class BuildGraphInspector: BuildGraphInspecting { if configurations.contains(where: { $0.key.name == configuration }) { arguments.append(.configuration(configuration)) } else { - logger + ServiceContext.current?.logger? .warning( "The scheme's targets don't have the given configuration \(configuration). Defaulting to the scheme's default." ) diff --git a/Sources/TuistAutomation/Utilities/TargetBuilder.swift b/Sources/TuistAutomation/Utilities/TargetBuilder.swift index bfd2c1ebabe..632118335a2 100644 --- a/Sources/TuistAutomation/Utilities/TargetBuilder.swift +++ b/Sources/TuistAutomation/Utilities/TargetBuilder.swift @@ -1,5 +1,6 @@ import FileSystem import Path +import ServiceContextModule import TSCUtility import TuistCore import TuistSupport @@ -95,7 +96,7 @@ public final class TargetBuilder: TargetBuilding { graphTraverser: GraphTraversing, passthroughXcodeBuildArguments: [String] ) async throws { - logger.log(level: .notice, "Building scheme \(scheme.name)", metadata: .section) + ServiceContext.current?.logger?.log(level: .notice, "Building scheme \(scheme.name)", metadata: .section) let buildArguments = buildGraphInspector.buildArguments( project: target.project, @@ -160,7 +161,11 @@ public final class TargetBuilder: TargetBuilding { if try await !fileSystem.exists(buildOutputPath) { try FileHandler.shared.createFolder(buildOutputPath) } - logger.log(level: .notice, "Copying build products to \(buildOutputPath.pathString)", metadata: .subsection) + ServiceContext.current?.logger?.log( + level: .notice, + "Copying build products to \(buildOutputPath.pathString)", + metadata: .subsection + ) for product in try FileHandler.shared.contentsOfDirectory(xcodeSchemeBuildPath) { let productOutputPath = buildOutputPath.appending(component: product.basename) diff --git a/Sources/TuistAutomation/Utilities/TargetRunner.swift b/Sources/TuistAutomation/Utilities/TargetRunner.swift index efbd618610e..76b8b5beb7b 100644 --- a/Sources/TuistAutomation/Utilities/TargetRunner.swift +++ b/Sources/TuistAutomation/Utilities/TargetRunner.swift @@ -1,5 +1,6 @@ import FileSystem import Path +import ServiceContextModule import struct TSCUtility.Version import TuistCore import TuistSupport @@ -137,8 +138,8 @@ public final class TargetRunner: TargetRunning { } private func runExecutable(_ executablePath: AbsolutePath, arguments: [String]) throws { - logger.notice("Running executable \(executablePath.basename)", metadata: .section) - logger.debug("Forwarding arguments: \(arguments.joined(separator: ", "))") + ServiceContext.current?.logger?.notice("Running executable \(executablePath.basename)", metadata: .section) + ServiceContext.current?.logger?.debug("Forwarding arguments: \(arguments.joined(separator: ", "))") try System.shared.runAndPrint([executablePath.pathString] + arguments) } @@ -164,8 +165,9 @@ public final class TargetRunner: TargetRunning { deviceName: deviceName ) - logger.debug("Running app \(appPath.pathString) with arguments [\(arguments.joined(separator: ", "))]") - logger.notice("Running app \(bundleId) on \(simulator.device.name)", metadata: .section) + ServiceContext.current?.logger? + .debug("Running app \(appPath.pathString) with arguments [\(arguments.joined(separator: ", "))]") + ServiceContext.current?.logger?.notice("Running app \(bundleId) on \(simulator.device.name)", metadata: .section) try simulatorController.installApp(at: appPath, device: simulator.device) try await simulatorController.launchApp(bundleId: bundleId, device: simulator.device, arguments: arguments) } diff --git a/Sources/TuistAutomation/XcodeBuild/XcodeBuildController.swift b/Sources/TuistAutomation/XcodeBuild/XcodeBuildController.swift index e557f477695..c0f55363c3b 100644 --- a/Sources/TuistAutomation/XcodeBuild/XcodeBuildController.swift +++ b/Sources/TuistAutomation/XcodeBuild/XcodeBuildController.swift @@ -2,6 +2,7 @@ import Foundation import Path import TuistCore import TuistSupport +import ServiceContextModule public final class XcodeBuildController: XcodeBuildControlling { // MARK: - Attributes @@ -311,14 +312,14 @@ public final class XcodeBuildController: XcodeBuildControlling { let lines = format(bytes).split(separator: "\n") for line in lines where !line.isEmpty { if isError { - logger.error("\(line)") + ServiceContext.current?.logger?.error("\(line)") } else { - logger.info("\(line)") + ServiceContext.current?.logger?.info("\(line)") } } } - logger.debug("Running xcodebuild command: \(command.joined(separator: " "))") + ServiceContext.current?.logger?.debug("Running xcodebuild command: \(command.joined(separator: " "))") try system.run(command, verbose: false, diff --git a/Sources/TuistCore/Log/Logger.swift b/Sources/TuistCore/Log/Logger.swift deleted file mode 100644 index f00ac15166a..00000000000 --- a/Sources/TuistCore/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.core") diff --git a/Sources/TuistCore/MetadataProviders/XCFrameworkMetadataProvider.swift b/Sources/TuistCore/MetadataProviders/XCFrameworkMetadataProvider.swift index ff04ea56304..9d1b06559c2 100644 --- a/Sources/TuistCore/MetadataProviders/XCFrameworkMetadataProvider.swift +++ b/Sources/TuistCore/MetadataProviders/XCFrameworkMetadataProvider.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Mockable import Path +import ServiceContextModule import TuistSupport import XcodeGraph @@ -193,7 +194,7 @@ public final class XCFrameworkMetadataProvider: PrecompiledMetadataProvider, let relativeArchitectureBinaryPath = binaryPath.components.suffix(3).joined( separator: "/" ) - logger + ServiceContext.current?.logger? .warning( "\(xcframeworkPath.basename) is missing architecture \(relativeArchitectureBinaryPath) defined in the Info.plist" ) diff --git a/Sources/TuistCore/Models/LintingIssue.swift b/Sources/TuistCore/Models/LintingIssue.swift index 0f16e006d2f..24ef5caee84 100644 --- a/Sources/TuistCore/Models/LintingIssue.swift +++ b/Sources/TuistCore/Models/LintingIssue.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistSupport public struct LintingError: FatalError, Equatable { @@ -42,7 +43,7 @@ extension [LintingIssue] { let errorIssues = filter { $0.severity == .error } for issue in errorIssues { - logger.error("\(issue.description)") + ServiceContext.current?.logger?.error("\(issue.description)") } if !errorIssues.isEmpty { throw LintingError() } @@ -54,7 +55,7 @@ extension [LintingIssue] { let warningIssues = filter { $0.severity == .warning } for issue in warningIssues { - logger.warning("\(issue.description)") + ServiceContext.current?.logger?.warning("\(issue.description)") } } } diff --git a/Sources/TuistCore/Simulator/SimulatorController.swift b/Sources/TuistCore/Simulator/SimulatorController.swift index 8939d0c199d..9005c49a552 100644 --- a/Sources/TuistCore/Simulator/SimulatorController.swift +++ b/Sources/TuistCore/Simulator/SimulatorController.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import struct TSCUtility.Version import TuistSupport import XcodeGraph @@ -270,13 +271,14 @@ public final class SimulatorController: SimulatorControlling { } public func installApp(at path: AbsolutePath, device: SimulatorDevice) throws { - logger.debug("Installing app at \(path) on simulator device with id \(device.udid)") + ServiceContext.current?.logger?.debug("Installing app at \(path) on simulator device with id \(device.udid)") let device = try device.booted(using: system) try system.run(["/usr/bin/xcrun", "simctl", "install", device.udid, path.pathString]) } public func launchApp(bundleId: String, device: SimulatorDevice, arguments: [String]) async throws { - logger.debug("Launching app with bundle id \(bundleId) on simulator device with id \(device.udid)") + ServiceContext.current?.logger? + .debug("Launching app with bundle id \(bundleId) on simulator device with id \(device.udid)") let device = try device.booted(using: system) let simulator = try await xcodeController.selected()?.path.appending( components: "Contents", diff --git a/Sources/TuistDependencies/Log/Logger.swift b/Sources/TuistDependencies/Log/Logger.swift deleted file mode 100644 index ec8780f3e1e..00000000000 --- a/Sources/TuistDependencies/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.dependencies") diff --git a/Sources/TuistDependencies/Mappers/ExternalProjectsPlatformNarrowerGraphMapper.swift b/Sources/TuistDependencies/Mappers/ExternalProjectsPlatformNarrowerGraphMapper.swift index b006b429cb0..17a13a78dcb 100644 --- a/Sources/TuistDependencies/Mappers/ExternalProjectsPlatformNarrowerGraphMapper.swift +++ b/Sources/TuistDependencies/Mappers/ExternalProjectsPlatformNarrowerGraphMapper.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistCore import XcodeGraph @@ -16,7 +17,7 @@ public struct ExternalProjectsPlatformNarrowerGraphMapper: GraphMapping { // swi graph: Graph, environment: MapperEnvironment ) async throws -> (Graph, [TuistCore.SideEffectDescriptor], MapperEnvironment) { - logger.debug("Transforming graph \(graph.name): Aligning external target platforms with locals'") + ServiceContext.current?.logger?.debug("Transforming graph \(graph.name): Aligning external target platforms with locals'") // If the project has no external dependencies we skip this. if graph.projects.values.first( diff --git a/Sources/TuistDependencies/Mappers/PruneOrphanExternalTargetsGraphMapper.swift b/Sources/TuistDependencies/Mappers/PruneOrphanExternalTargetsGraphMapper.swift index b3979879b16..017518e650d 100644 --- a/Sources/TuistDependencies/Mappers/PruneOrphanExternalTargetsGraphMapper.swift +++ b/Sources/TuistDependencies/Mappers/PruneOrphanExternalTargetsGraphMapper.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistCore import XcodeGraph @@ -14,7 +15,8 @@ public struct PruneOrphanExternalTargetsGraphMapper: GraphMapping { graph: XcodeGraph.Graph, environment: MapperEnvironment ) async throws -> (XcodeGraph.Graph, [TuistCore.SideEffectDescriptor], MapperEnvironment) { - logger.debug("Transforming graph \(graph.name): Tree-shaking orphan external targets (e.g. test targets)") + ServiceContext.current?.logger? + .debug("Transforming graph \(graph.name): Tree-shaking orphan external targets (e.g. test targets)") let graphTraverser = GraphTraverser(graph: graph) let orphanExternalTargets = graphTraverser.allOrphanExternalTargets() diff --git a/Sources/TuistGenerator/Descriptors/SideEffectDescriptorExecutor.swift b/Sources/TuistGenerator/Descriptors/SideEffectDescriptorExecutor.swift index 0db2c1b1135..12a7b50ed39 100644 --- a/Sources/TuistGenerator/Descriptors/SideEffectDescriptorExecutor.swift +++ b/Sources/TuistGenerator/Descriptors/SideEffectDescriptorExecutor.swift @@ -1,5 +1,6 @@ import FileSystem import Foundation +import ServiceContextModule import TuistCore import TuistSupport @@ -21,7 +22,7 @@ public final class SideEffectDescriptorExecutor: SideEffectDescriptorExecuting { public func execute(sideEffects: [SideEffectDescriptor]) async throws { for sideEffect in sideEffects { - logger.debug("Side effect: \(sideEffect)") + ServiceContext.current?.logger?.debug("Side effect: \(sideEffect)") switch sideEffect { case let .command(commandDescriptor): try perform(command: commandDescriptor) diff --git a/Sources/TuistGenerator/Generator/ProjectDescriptorGenerator.swift b/Sources/TuistGenerator/Generator/ProjectDescriptorGenerator.swift index d3ed61de60a..54e1e9f49d9 100644 --- a/Sources/TuistGenerator/Generator/ProjectDescriptorGenerator.swift +++ b/Sources/TuistGenerator/Generator/ProjectDescriptorGenerator.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -85,7 +86,7 @@ final class ProjectDescriptorGenerator: ProjectDescriptorGenerating { project: Project, graphTraverser: GraphTraversing ) async throws -> ProjectDescriptor { - logger.notice("Generating project \(project.name)") + ServiceContext.current?.logger?.notice("Generating project \(project.name)") let selfRef = XCWorkspaceDataFileRef(location: .current("")) let selfRefFile = XCWorkspaceDataElement.file(selfRef) diff --git a/Sources/TuistGenerator/Generator/WorkspaceDescriptorGenerator.swift b/Sources/TuistGenerator/Generator/WorkspaceDescriptorGenerator.swift index ac4bf45d74c..bcfaf0fb7eb 100644 --- a/Sources/TuistGenerator/Generator/WorkspaceDescriptorGenerator.swift +++ b/Sources/TuistGenerator/Generator/WorkspaceDescriptorGenerator.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeProj @@ -90,7 +91,7 @@ final class WorkspaceDescriptorGenerator: WorkspaceDescriptorGenerating { func generate(graphTraverser: GraphTraversing) async throws -> WorkspaceDescriptor { let workspaceName = "\(graphTraverser.name).xcworkspace" - logger.notice("Generating workspace \(workspaceName)", metadata: .section) + ServiceContext.current?.logger?.notice("Generating workspace \(workspaceName)", metadata: .section) /// Projects let projects = try await Array(graphTraverser.projects.values) diff --git a/Sources/TuistGenerator/Log/Logger.swift b/Sources/TuistGenerator/Log/Logger.swift deleted file mode 100644 index 27afc88c525..00000000000 --- a/Sources/TuistGenerator/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.generator") diff --git a/Sources/TuistGenerator/Mappers/AutogeneratedSchemesProjectMapper.swift b/Sources/TuistGenerator/Mappers/AutogeneratedSchemesProjectMapper.swift index 341c8af9de6..bb174790abd 100644 --- a/Sources/TuistGenerator/Mappers/AutogeneratedSchemesProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/AutogeneratedSchemesProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import XcodeGraph @@ -14,7 +15,7 @@ public final class AutogeneratedSchemesProjectMapper: ProjectMapping { // swiftl // swiftlint:disable:next function_body_length public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Auto-generating project schemes") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Auto-generating project schemes") let userDefinedSchemes = project.schemes let userDefinedSchemeNames = Set(project.schemes.map(\.name)) diff --git a/Sources/TuistGenerator/Mappers/AutogeneratedWorkspaceSchemeWorkspaceMapper.swift b/Sources/TuistGenerator/Mappers/AutogeneratedWorkspaceSchemeWorkspaceMapper.swift index 647eb16212b..dc2b03d4aa6 100644 --- a/Sources/TuistGenerator/Mappers/AutogeneratedWorkspaceSchemeWorkspaceMapper.swift +++ b/Sources/TuistGenerator/Mappers/AutogeneratedWorkspaceSchemeWorkspaceMapper.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistCore import XcodeGraph @@ -18,7 +19,8 @@ public final class AutogeneratedWorkspaceSchemeWorkspaceMapper: WorkspaceMapping else { return (workspace, []) } - logger.debug("Transforming workspace \(workspace.workspace.name): Auto-generating workspace scheme") + ServiceContext.current?.logger? + .debug("Transforming workspace \(workspace.workspace.name): Auto-generating workspace scheme") let platforms = Set( workspace.projects diff --git a/Sources/TuistGenerator/Mappers/DeleteDerivedDirectoryProjectMapper.swift b/Sources/TuistGenerator/Mappers/DeleteDerivedDirectoryProjectMapper.swift index a57b6b725e6..bec44929d37 100644 --- a/Sources/TuistGenerator/Mappers/DeleteDerivedDirectoryProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/DeleteDerivedDirectoryProjectMapper.swift @@ -1,5 +1,6 @@ import FileSystem import Foundation +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -23,7 +24,7 @@ public final class DeleteDerivedDirectoryProjectMapper: ProjectMapping { // MARK: - ProjectMapping public func map(project: Project) async throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Deleting /Derived directory") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Deleting /Derived directory") let derivedDirectoryPath = project.path.appending(component: derivedDirectoryName) diff --git a/Sources/TuistGenerator/Mappers/ExplicitDependencyGraphMapper.swift b/Sources/TuistGenerator/Mappers/ExplicitDependencyGraphMapper.swift index 88e1eb15ceb..cce58020e21 100644 --- a/Sources/TuistGenerator/Mappers/ExplicitDependencyGraphMapper.swift +++ b/Sources/TuistGenerator/Mappers/ExplicitDependencyGraphMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -19,7 +20,7 @@ public struct ExplicitDependencyGraphMapper: GraphMapping { environment ) } - logger.debug("Transforming graph \(graph.name): Enforcing explicit dependencies") + ServiceContext.current?.logger?.debug("Transforming graph \(graph.name): Enforcing explicit dependencies") let graphTraverser = GraphTraverser(graph: graph) diff --git a/Sources/TuistGenerator/Mappers/GenerateEntitlementsProjectMapper.swift b/Sources/TuistGenerator/Mappers/GenerateEntitlementsProjectMapper.swift index 070bdf7ae76..2ffba7d3d7a 100644 --- a/Sources/TuistGenerator/Mappers/GenerateEntitlementsProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/GenerateEntitlementsProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -21,7 +22,7 @@ public final class GenerateEntitlementsProjectMapper: ProjectMapping { // MARK: - ProjectMapping public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Synthesizing entitlement files'") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Synthesizing entitlement files'") let results = try project.targets.values .reduce(into: (targets: [String: Target](), sideEffects: [SideEffectDescriptor]())) { results, target in diff --git a/Sources/TuistGenerator/Mappers/GenerateInfoPlistProjectMapper.swift b/Sources/TuistGenerator/Mappers/GenerateInfoPlistProjectMapper.swift index fa305ca867d..d5a6155c4a2 100644 --- a/Sources/TuistGenerator/Mappers/GenerateInfoPlistProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/GenerateInfoPlistProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -35,7 +36,7 @@ public final class GenerateInfoPlistProjectMapper: ProjectMapping { // MARK: - ProjectMapping public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Synthesizing Info.plist") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Synthesizing Info.plist") let results = try project.targets.values .reduce(into: (targets: [String: Target](), sideEffects: [SideEffectDescriptor]())) { results, target in diff --git a/Sources/TuistGenerator/Mappers/GeneratePrivacyManifestProjectMapper.swift b/Sources/TuistGenerator/Mappers/GeneratePrivacyManifestProjectMapper.swift index 19c3f0a4ef6..8256c2fc69f 100644 --- a/Sources/TuistGenerator/Mappers/GeneratePrivacyManifestProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/GeneratePrivacyManifestProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -12,7 +13,7 @@ public final class GeneratePrivacyManifestProjectMapper: ProjectMapping { // MARK: - ProjectMapping public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Synthesizing privacy manifest files'") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Synthesizing privacy manifest files'") let results = try project.targets.values .reduce(into: (targets: [String: Target](), sideEffects: [SideEffectDescriptor]())) { results, target in diff --git a/Sources/TuistGenerator/Mappers/IDETemplateMacrosMapper.swift b/Sources/TuistGenerator/Mappers/IDETemplateMacrosMapper.swift index c2ca8499aa6..917877d5af8 100644 --- a/Sources/TuistGenerator/Mappers/IDETemplateMacrosMapper.swift +++ b/Sources/TuistGenerator/Mappers/IDETemplateMacrosMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import XcodeGraph @@ -7,12 +8,14 @@ public final class IDETemplateMacrosMapper: ProjectMapping, WorkspaceMapping { public init() {} public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger.debug("Transforming project \(project.name): Generating xcshareddata/IDETemplateMacros.plist") + ServiceContext.current?.logger? + .debug("Transforming project \(project.name): Generating xcshareddata/IDETemplateMacros.plist") return (project, try sideEffects(for: project.ideTemplateMacros, to: project.xcodeProjPath)) } public func map(workspace: WorkspaceWithProjects) throws -> (WorkspaceWithProjects, [SideEffectDescriptor]) { - logger.debug("Transforming workspace \(workspace.workspace.name): Generating xcshareddata/IDETemplateMacros.plist") + ServiceContext.current?.logger? + .debug("Transforming workspace \(workspace.workspace.name): Generating xcshareddata/IDETemplateMacros.plist") return (workspace, try sideEffects(for: workspace.workspace.ideTemplateMacros, to: workspace.workspace.xcWorkspacePath)) } diff --git a/Sources/TuistGenerator/Mappers/LastUpgradeVersionWorkspaceMapper.swift b/Sources/TuistGenerator/Mappers/LastUpgradeVersionWorkspaceMapper.swift index 429cbfb2c0f..49197755b5f 100644 --- a/Sources/TuistGenerator/Mappers/LastUpgradeVersionWorkspaceMapper.swift +++ b/Sources/TuistGenerator/Mappers/LastUpgradeVersionWorkspaceMapper.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TSCUtility import TuistCore @@ -11,7 +12,8 @@ public final class LastUpgradeVersionWorkspaceMapper: WorkspaceMapping { guard let lastXcodeUpgradeCheck = workspace.workspace.generationOptions.lastXcodeUpgradeCheck else { return (workspace, []) } - logger.debug("Transforming workspace \(workspace.workspace.name): Updating projects' last upgrade check") + ServiceContext.current?.logger? + .debug("Transforming workspace \(workspace.workspace.name): Updating projects' last upgrade check") var projects = workspace.projects projects.indices.forEach { projects[$0].lastUpgradeCheck = projects[$0].lastUpgradeCheck ?? lastXcodeUpgradeCheck } diff --git a/Sources/TuistGenerator/Mappers/ModuleMapMapper.swift b/Sources/TuistGenerator/Mappers/ModuleMapMapper.swift index 0f00eefffe2..eef7ff550ad 100644 --- a/Sources/TuistGenerator/Mappers/ModuleMapMapper.swift +++ b/Sources/TuistGenerator/Mappers/ModuleMapMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -27,7 +28,7 @@ public final class ModuleMapMapper: GraphMapping { // swiftlint:disable:this typ // swiftlint:disable function_body_length public func map(graph: Graph, environment: MapperEnvironment) throws -> (Graph, [SideEffectDescriptor], MapperEnvironment) { - logger + ServiceContext.current?.logger? .debug( "Transforming graph \(graph.name): Mapping MODULE_MAP build setting to -fmodule-map-file compiler flag" ) diff --git a/Sources/TuistGenerator/Mappers/ResourcesProjectMapper.swift b/Sources/TuistGenerator/Mappers/ResourcesProjectMapper.swift index d92cc39804f..12ab97022f7 100644 --- a/Sources/TuistGenerator/Mappers/ResourcesProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/ResourcesProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -15,7 +16,7 @@ public class ResourcesProjectMapper: ProjectMapping { // swiftlint:disable:this guard !project.options.disableBundleAccessors else { return (project, []) } - logger.debug("Transforming project \(project.name): Generating bundles for libraries'") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Generating bundles for libraries'") var sideEffects: [SideEffectDescriptor] = [] var targets: [String: Target] = [:] diff --git a/Sources/TuistGenerator/Mappers/SynthesizedResourceInterfaceProjectMapper.swift b/Sources/TuistGenerator/Mappers/SynthesizedResourceInterfaceProjectMapper.swift index 9339489b699..581721165eb 100644 --- a/Sources/TuistGenerator/Mappers/SynthesizedResourceInterfaceProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/SynthesizedResourceInterfaceProjectMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import SwiftGenKit import TuistCore import TuistSupport @@ -50,7 +51,7 @@ public final class SynthesizedResourceInterfaceProjectMapper: ProjectMapping { / guard !project.options.disableSynthesizedResourceAccessors else { return (project, []) } - logger.debug("Transforming project \(project.name): Synthesizing resource accessors") + ServiceContext.current?.logger?.debug("Transforming project \(project.name): Synthesizing resource accessors") let mappings = try project.targets.values .map { try mapTarget($0, project: project) } @@ -196,7 +197,7 @@ public final class SynthesizedResourceInterfaceProjectMapper: ProjectMapping { / } else { if try !FileHandler.shared.readFile(path).isEmpty { return true } } - logger.log( + ServiceContext.current?.logger?.log( level: .warning, "Skipping synthesizing accessors for \(path.pathString) because its contents are empty." ) diff --git a/Sources/TuistGenerator/Mappers/TargetActionDisableShowEnvVarsProjectMapper.swift b/Sources/TuistGenerator/Mappers/TargetActionDisableShowEnvVarsProjectMapper.swift index ebc62f9a244..0f977d4bf70 100644 --- a/Sources/TuistGenerator/Mappers/TargetActionDisableShowEnvVarsProjectMapper.swift +++ b/Sources/TuistGenerator/Mappers/TargetActionDisableShowEnvVarsProjectMapper.swift @@ -1,3 +1,4 @@ +import ServiceContextModule import TuistCore import XcodeGraph @@ -7,7 +8,7 @@ public final class TargetActionDisableShowEnvVarsProjectMapper: ProjectMapping { public init() {} public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) { - logger + ServiceContext.current?.logger? .debug( "Transforming project \(project.name): Configuring 'disable show environment vars in script' in project targets' script phases" ) diff --git a/Sources/TuistGenerator/Utils/SwiftPackageManagerInteractor.swift b/Sources/TuistGenerator/Utils/SwiftPackageManagerInteractor.swift index 4865df7f1f8..c1c1f1a6f43 100644 --- a/Sources/TuistGenerator/Utils/SwiftPackageManagerInteractor.swift +++ b/Sources/TuistGenerator/Utils/SwiftPackageManagerInteractor.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -72,7 +73,7 @@ public class SwiftPackageManagerInteractor: SwiftPackageManagerInteracting { } let workspacePath = path.appending(component: workspaceName) - logger.notice("Resolving package dependencies using xcodebuild") + ServiceContext.current?.logger?.notice("Resolving package dependencies using xcodebuild") // -list parameter is a workaround to resolve package dependencies for given workspace without specifying scheme var arguments = ["xcodebuild", "-resolvePackageDependencies"] @@ -96,10 +97,10 @@ public class SwiftPackageManagerInteractor: SwiftPackageManagerInteracting { environment: System.shared.env, redirection: .stream(stdout: { bytes in let output = String(decoding: bytes, as: Unicode.UTF8.self) - logger.debug("\(output)") + ServiceContext.current?.logger?.debug("\(output)") }, stderr: { bytes in let error = String(decoding: bytes, as: Unicode.UTF8.self) - logger.error("\(error)") + ServiceContext.current?.logger?.error("\(error)") }) ) diff --git a/Sources/TuistHasher/Log/Logger.swift b/Sources/TuistHasher/Log/Logger.swift deleted file mode 100644 index a4d4e6e2f0a..00000000000 --- a/Sources/TuistHasher/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.analytics") diff --git a/Sources/TuistHasher/TargetScriptsContentHasher.swift b/Sources/TuistHasher/TargetScriptsContentHasher.swift index a8519b230d2..b08b076dc0d 100644 --- a/Sources/TuistHasher/TargetScriptsContentHasher.swift +++ b/Sources/TuistHasher/TargetScriptsContentHasher.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistCore import XcodeGraph @@ -39,7 +40,7 @@ public struct TargetScriptsContentHasher: TargetScriptsContentHashing { for path in dynamicPaths { if path.pathString.contains("$") { stringsToHash.append(path.relative(to: sourceRootPath).pathString) - logger.notice( + ServiceContext.current?.logger?.notice( "The path of the file \'\(path.url.lastPathComponent)\' is hashed, not the content. Because it has a build variable." ) } else { diff --git a/Sources/TuistKit/Commands/BuildCommand.swift b/Sources/TuistKit/Commands/BuildCommand.swift index 7e1a38ac498..a594ab2c118 100644 --- a/Sources/TuistKit/Commands/BuildCommand.swift +++ b/Sources/TuistKit/Commands/BuildCommand.swift @@ -1,6 +1,7 @@ import ArgumentParser import Foundation import Path +import ServiceContextModule import TuistServer import TuistSupport import XcodeGraph @@ -156,7 +157,7 @@ public struct BuildCommand: AsyncParsableCommand { // Suggest the user to use passthrough arguments if already supported by xcodebuild if let derivedDataPath = buildOptions.derivedDataPath { - logger + ServiceContext.current?.logger? .warning( "--derivedDataPath is deprecated please use -derivedDataPath \(derivedDataPath) after the terminator (--) instead to passthrough parameters to xcodebuild" ) diff --git a/Sources/TuistKit/Commands/Cache/CachePrintHashesService.swift b/Sources/TuistKit/Commands/Cache/CachePrintHashesService.swift index 1371959a2f2..cc5827ed8d1 100644 --- a/Sources/TuistKit/Commands/Cache/CachePrintHashesService.swift +++ b/Sources/TuistKit/Commands/Cache/CachePrintHashesService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistAutomation import TuistCache import TuistCore @@ -63,13 +64,13 @@ final class CachePrintHashesService { let duration = timer.stop() let time = String(format: "%.3f", duration) guard hashes.count > 0 else { - logger.notice("No cacheable targets were found") + ServiceContext.current?.logger?.notice("No cacheable targets were found") return } let sortedHashes = hashes.sorted { $0.key.target.name < $1.key.target.name } for (target, hash) in sortedHashes { - logger.info("\(target.target.name) - \(hash)") + ServiceContext.current?.logger?.info("\(target.target.name) - \(hash)") } - logger.notice("Total time taken: \(time)s") + ServiceContext.current?.logger?.notice("Total time taken: \(time)s") } } diff --git a/Sources/TuistKit/Commands/Cache/CacheService.swift b/Sources/TuistKit/Commands/Cache/CacheService.swift index b26c263ef9f..99e65afedd6 100644 --- a/Sources/TuistKit/Commands/Cache/CacheService.swift +++ b/Sources/TuistKit/Commands/Cache/CacheService.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule public protocol CacheServicing { func run( @@ -20,7 +21,7 @@ final class EmptyCacheService: CacheServicing { generateOnly _: Bool, analyticsDelegate _: TrackableParametersDelegate? ) async throws { - logger + ServiceContext.current?.logger? .notice( "Caching is currently not opensourced. Please, report issues with caching on GitHub and the Tuist team will take a look." ) diff --git a/Sources/TuistKit/Commands/TestCommand.swift b/Sources/TuistKit/Commands/TestCommand.swift index 7e19d871951..c09d41dac7f 100644 --- a/Sources/TuistKit/Commands/TestCommand.swift +++ b/Sources/TuistKit/Commands/TestCommand.swift @@ -2,6 +2,7 @@ import AnyCodable import ArgumentParser import Foundation import Path +import ServiceContextModule import TuistCore import TuistServer import TuistSupport @@ -207,13 +208,13 @@ public struct TestCommand: AsyncParsableCommand, HasTrackableParameters { // Suggest the user to use passthrough arguments if already supported by xcodebuild if let derivedDataPath { - logger + ServiceContext.current?.logger? .warning( "--derivedDataPath is deprecated please use -derivedDataPath \(derivedDataPath) after the terminator (--) instead to passthrough parameters to xcodebuild" ) } if retryCount > 0 { - logger + ServiceContext.current?.logger? .warning( "--retryCount is deprecated please use -retry-tests-on-failure -test-iterations \(retryCount + 1) after the terminator (--) instead to passthrough parameters to xcodebuild" ) diff --git a/Sources/TuistKit/Commands/TuistCommand.swift b/Sources/TuistKit/Commands/TuistCommand.swift index 0fb7aa13c02..fafd426db3d 100644 --- a/Sources/TuistKit/Commands/TuistCommand.swift +++ b/Sources/TuistKit/Commands/TuistCommand.swift @@ -2,6 +2,7 @@ import Foundation import OpenAPIRuntime import Path +import ServiceContextModule import TuistAnalytics import TuistCore import TuistLoader @@ -127,7 +128,7 @@ public struct TuistCommand: AsyncParsableCommand { } catch let error as ClientError where error.underlyingError is ServerClientAuthenticationError { WarningController.shared.flush() // swiftlint:disable:next force_cast - logger.error("\((error.underlyingError as! ServerClientAuthenticationError).description)") + ServiceContext.current?.logger?.error("\((error.underlyingError as! ServerClientAuthenticationError).description)") _exit(exitCode(for: error).rawValue) } catch { WarningController.shared.flush() @@ -154,9 +155,9 @@ public struct TuistCommand: AsyncParsableCommand { private static func handleParseError(_ error: Error) -> Never { let exitCode = exitCode(for: error).rawValue if exitCode == 0 { - logger.notice("\(fullMessage(for: error))") + ServiceContext.current?.logger?.notice("\(fullMessage(for: error))") } else { - logger.error("\(fullMessage(for: error))") + ServiceContext.current?.logger?.error("\(fullMessage(for: error))") } _exit(exitCode) } diff --git a/Sources/TuistKit/Generator/Generator.swift b/Sources/TuistKit/Generator/Generator.swift index 488b213f87d..6dffe263240 100644 --- a/Sources/TuistKit/Generator/Generator.swift +++ b/Sources/TuistKit/Generator/Generator.swift @@ -3,6 +3,7 @@ import Foundation import Mockable import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistDependencies import TuistGenerator @@ -87,8 +88,8 @@ public class Generator: Generating { } func load(path: AbsolutePath) async throws -> (Graph, [SideEffectDescriptor], MapperEnvironment) { - logger.notice("Loading and constructing the graph", metadata: .section) - logger.notice("It might take a while if the cache is empty") + ServiceContext.current?.logger?.notice("Loading and constructing the graph", metadata: .section) + ServiceContext.current?.logger?.notice("It might take a while if the cache is empty") let (graph, sideEffectDescriptors, environment, issues) = try await manifestGraphLoader.load(path: path) diff --git a/Sources/TuistKit/Log/Logger.swift b/Sources/TuistKit/Log/Logger.swift deleted file mode 100644 index 20bce74e86c..00000000000 --- a/Sources/TuistKit/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist") diff --git a/Sources/TuistKit/Mappers/Graph/UpdateWorkspaceProjectsGraphMapper.swift b/Sources/TuistKit/Mappers/Graph/UpdateWorkspaceProjectsGraphMapper.swift index 3949adb0f51..e80e3e0d9b4 100644 --- a/Sources/TuistKit/Mappers/Graph/UpdateWorkspaceProjectsGraphMapper.swift +++ b/Sources/TuistKit/Mappers/Graph/UpdateWorkspaceProjectsGraphMapper.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistCore import XcodeGraph @@ -8,7 +9,7 @@ public final class UpdateWorkspaceProjectsGraphMapper: GraphMapping { public init() {} public func map(graph: Graph, environment: MapperEnvironment) throws -> (Graph, [SideEffectDescriptor], MapperEnvironment) { - logger.debug("Transforming graph \(graph.name): Aligning workspace projects with the graph's") + ServiceContext.current?.logger?.debug("Transforming graph \(graph.name): Aligning workspace projects with the graph's") var graph = graph let graphProjects = Set(graph.projects.map(\.key)) diff --git a/Sources/TuistKit/Mappers/TreeShakePrunedTargetsGraphMapper.swift b/Sources/TuistKit/Mappers/TreeShakePrunedTargetsGraphMapper.swift index 7cf078f87e0..e26732804b5 100644 --- a/Sources/TuistKit/Mappers/TreeShakePrunedTargetsGraphMapper.swift +++ b/Sources/TuistKit/Mappers/TreeShakePrunedTargetsGraphMapper.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import XcodeGraph @@ -9,7 +10,7 @@ public final class TreeShakePrunedTargetsGraphMapper: GraphMapping { public func map(graph: Graph, environment: MapperEnvironment) throws -> ( Graph, [SideEffectDescriptor], MapperEnvironment ) { - logger.debug("Transforming graph \(graph.name): Tree-shaking nodes") + ServiceContext.current?.logger?.debug("Transforming graph \(graph.name): Tree-shaking nodes") let sourceTargets: Set = Set( graph.projects.flatMap { projectPath, project -> [TargetReference] in return project.targets.compactMap { _, target -> TargetReference? in diff --git a/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceIdentifierMapper.swift b/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceIdentifierMapper.swift index 49be12e0e40..d04ee828f83 100644 --- a/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceIdentifierMapper.swift +++ b/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceIdentifierMapper.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistCore import TuistSupport @@ -8,7 +9,7 @@ import TuistSupport /// This is used to help identify the workspace as one that has been generated by tuist. final class TuistWorkspaceIdentifierMapper: WorkspaceMapping { func map(workspace: WorkspaceWithProjects) throws -> (WorkspaceWithProjects, [SideEffectDescriptor]) { - logger.debug("Transforming workspace \(workspace.workspace.name): Signing the workspace") + ServiceContext.current?.logger?.debug("Transforming workspace \(workspace.workspace.name): Signing the workspace") let tuistGeneratedFileDescriptor = FileDescriptor( path: workspace diff --git a/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceRenderMarkdownMapper.swift b/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceRenderMarkdownMapper.swift index d8c20bd8c35..0829dbfc5ea 100644 --- a/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceRenderMarkdownMapper.swift +++ b/Sources/TuistKit/Mappers/Workspace/TuistWorkspaceRenderMarkdownMapper.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistCore import TuistSupport @@ -8,7 +9,7 @@ import TuistSupport /// This is used to render markdown inside the workspace. final class TuistWorkspaceRenderMarkdownReadmeMapper: WorkspaceMapping { func map(workspace: WorkspaceWithProjects) throws -> (WorkspaceWithProjects, [SideEffectDescriptor]) { - logger.debug("Transforming workspace \(workspace.workspace.name): Including .xcodesample.plist") + ServiceContext.current?.logger?.debug("Transforming workspace \(workspace.workspace.name): Including .xcodesample.plist") let tuistGeneratedFileDescriptor = FileDescriptor( path: workspace diff --git a/Sources/TuistKit/ProjectEditor/ProjectEditorMapper.swift b/Sources/TuistKit/ProjectEditor/ProjectEditorMapper.swift index ae23c4ccdf2..02210d38ea0 100644 --- a/Sources/TuistKit/ProjectEditor/ProjectEditorMapper.swift +++ b/Sources/TuistKit/ProjectEditor/ProjectEditorMapper.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistSupport @@ -57,7 +58,7 @@ final class ProjectEditorMapper: ProjectEditorMapping { stencils: [AbsolutePath], projectDescriptionSearchPath: AbsolutePath ) async throws -> Graph { - logger.notice("Building the editable project graph") + ServiceContext.current?.logger?.notice("Building the editable project graph") let swiftVersion = try SwiftVersionProvider.shared.swiftVersion() let pluginsProject = try await mapPluginsProject( diff --git a/Sources/TuistKit/Services/BuildService.swift b/Sources/TuistKit/Services/BuildService.swift index d6f6cc9c309..5b0b49ab9af 100644 --- a/Sources/TuistKit/Services/BuildService.swift +++ b/Sources/TuistKit/Services/BuildService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistAutomation import TuistCore import TuistLoader @@ -107,7 +108,7 @@ public final class BuildService { ) } - logger.log( + ServiceContext.current?.logger?.log( level: .debug, "Found the following buildable schemes: \(buildableSchemes.map(\.name).joined(separator: ", "))" ) @@ -180,6 +181,6 @@ public final class BuildService { } } - logger.log(level: .notice, "The project built successfully", metadata: .success) + ServiceContext.current?.logger?.log(level: .notice, "The project built successfully", metadata: .success) } } diff --git a/Sources/TuistKit/Services/CleanService.swift b/Sources/TuistKit/Services/CleanService.swift index f71418c9b1f..566cca13db0 100644 --- a/Sources/TuistKit/Services/CleanService.swift +++ b/Sources/TuistKit/Services/CleanService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistServer @@ -125,9 +126,12 @@ final class CleanService { { try await fileSystem.remove(directory) try await fileSystem.makeDirectory(at: directory) - logger.notice("Successfully cleaned artifacts at path \(directory.pathString)", metadata: .success) + ServiceContext.current?.logger?.notice( + "Successfully cleaned artifacts at path \(directory.pathString)", + metadata: .success + ) } else { - logger.notice("There's nothing to clean for \(category.defaultValueDescription)") + ServiceContext.current?.logger?.notice("There's nothing to clean for \(category.defaultValueDescription)") } } @@ -140,7 +144,7 @@ final class CleanService { fullHandle: fullHandle ) - logger.notice("Successfully cleaned the remote storage.") + ServiceContext.current?.logger?.notice("Successfully cleaned the remote storage.") } } } diff --git a/Sources/TuistKit/Services/DumpService.swift b/Sources/TuistKit/Services/DumpService.swift index 474a70103f9..0802daec17b 100644 --- a/Sources/TuistKit/Services/DumpService.swift +++ b/Sources/TuistKit/Services/DumpService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TSCBasic import TuistCore import TuistLoader @@ -45,7 +46,7 @@ final class DumpService { } let json: JSON = try encoded.toJSON() - logger.notice("\(json.toString(prettyPrint: true))", metadata: .json) + ServiceContext.current?.logger?.notice("\(json.toString(prettyPrint: true))", metadata: .json) } } diff --git a/Sources/TuistKit/Services/EditService.swift b/Sources/TuistKit/Services/EditService.swift index 11ce0521917..7268a9baccc 100644 --- a/Sources/TuistKit/Services/EditService.swift +++ b/Sources/TuistKit/Services/EditService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistGenerator import TuistLoader @@ -68,7 +69,7 @@ final class EditService { onlyCurrentDirectory: onlyCurrentDirectory, plugins: plugins ) - logger.notice("Opening Xcode to edit the project.", metadata: .pretty) + ServiceContext.current?.logger?.notice("Opening Xcode to edit the project.", metadata: .pretty) try opener.open(path: workspacePath, application: selectedXcode.path, wait: false) } else { @@ -78,7 +79,7 @@ final class EditService { onlyCurrentDirectory: onlyCurrentDirectory, plugins: plugins ) - logger.notice("Xcode project generated at \(workspacePath.pathString)", metadata: .success) + ServiceContext.current?.logger?.notice("Xcode project generated at \(workspacePath.pathString)", metadata: .success) } } @@ -94,7 +95,7 @@ final class EditService { private func loadPlugins(at path: AbsolutePath) async -> Plugins { guard let config = try? await configLoader.loadConfig(path: path) else { - logger + ServiceContext.current?.logger? .warning( "Unable to load \(Constants.tuistManifestFileName), fix any compiler errors and re-run for plugins to be loaded." ) @@ -102,7 +103,8 @@ final class EditService { } guard let plugins = try? await pluginService.loadPlugins(using: config) else { - logger.warning("Unable to load Plugin.swift manifest, fix and re-run in order to use plugin(s).") + ServiceContext.current?.logger? + .warning("Unable to load Plugin.swift manifest, fix and re-run in order to use plugin(s).") return .none } diff --git a/Sources/TuistKit/Services/GenerateService.swift b/Sources/TuistKit/Services/GenerateService.swift index 3173eac2243..b2ff4064f4b 100644 --- a/Sources/TuistKit/Services/GenerateService.swift +++ b/Sources/TuistKit/Services/GenerateService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCache import TuistCore import TuistGenerator @@ -62,8 +63,8 @@ final class GenerateService { if !noOpen { try await opener.open(path: workspacePath) } - logger.notice("Project generated.", metadata: .success) - logger.notice(timeTakenLoggerFormatter.timeTakenMessage(for: timer)) + ServiceContext.current?.logger?.notice("Project generated.", metadata: .success) + ServiceContext.current?.logger?.notice(timeTakenLoggerFormatter.timeTakenMessage(for: timer)) } // MARK: - Helpers diff --git a/Sources/TuistKit/Services/GraphService.swift b/Sources/TuistKit/Services/GraphService.swift index 7a93519b5a7..fd825722f59 100644 --- a/Sources/TuistKit/Services/GraphService.swift +++ b/Sources/TuistKit/Services/GraphService.swift @@ -4,6 +4,7 @@ import Foundation import GraphViz import Path import ProjectAutomation +import ServiceContextModule import Tools import TuistCore import TuistGenerator @@ -57,7 +58,7 @@ final class GraphService { let filePath = outputPath.appending(component: "graph.\(format.rawValue)") if try await fileSystem.exists(filePath) { - logger.notice("Deleting existing graph at \(filePath.pathString)") + ServiceContext.current?.logger?.notice("Deleting existing graph at \(filePath.pathString)") try await fileSystem.remove(filePath) } @@ -77,7 +78,7 @@ final class GraphService { try outputGraph.export(to: filePath) } - logger.notice("Graph exported to \(filePath.pathString)", metadata: .success) + ServiceContext.current?.logger?.notice("Graph exported to \(filePath.pathString)", metadata: .success) } private func export( @@ -127,7 +128,7 @@ final class GraphService { } private func installGraphViz() throws { - logger.notice("Installing GraphViz...") + ServiceContext.current?.logger?.notice("Installing GraphViz...") var env = System.shared.env env["HOMEBREW_NO_AUTO_UPDATE"] = "1" try System.shared.runAndPrint(["brew", "install", "graphviz"], verbose: false, environment: env) diff --git a/Sources/TuistKit/Services/InitService.swift b/Sources/TuistKit/Services/InitService.swift index a43570125ca..2bc494ccec1 100644 --- a/Sources/TuistKit/Services/InitService.swift +++ b/Sources/TuistKit/Services/InitService.swift @@ -1,5 +1,6 @@ import FileSystem import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistScaffold @@ -155,11 +156,11 @@ class InitService { ) } - logger.notice( + ServiceContext.current?.logger?.notice( "Project generated at path \(path.pathString). Run `tuist generate` to generate the project and open it in Xcode. Use `tuist edit` to easily update the Tuist project definition.", metadata: .success ) - logger + ServiceContext.current?.logger? .info( "To learn more about tuist features, such as how to add external dependencies or how to use our ProjectDescription helpers, head to our tutorials page: https://docs.tuist.io/tutorials/tuist-tutorials" ) diff --git a/Sources/TuistKit/Services/Inspect/InspecImplicitImportsService.swift b/Sources/TuistKit/Services/Inspect/InspecImplicitImportsService.swift index 31eeaa3f238..afb322ef0a4 100644 --- a/Sources/TuistKit/Services/Inspect/InspecImplicitImportsService.swift +++ b/Sources/TuistKit/Services/Inspect/InspecImplicitImportsService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistSupport @@ -55,7 +56,7 @@ final class InspectImplicitImportsService { guard issues.isEmpty else { throw InspectImplicitImportsServiceError.implicitImportsFound(issues) } - logger.log(level: .info, "We did not find any implicit dependencies in your project.") + ServiceContext.current?.logger?.log(level: .info, "We did not find any implicit dependencies in your project.") } private func lint(graphTraverser: GraphTraverser) async throws -> [InspectImplicitImportsServiceErrorIssue] { diff --git a/Sources/TuistKit/Services/InstallService.swift b/Sources/TuistKit/Services/InstallService.swift index 07778917ce5..80a7d5112af 100644 --- a/Sources/TuistKit/Services/InstallService.swift +++ b/Sources/TuistKit/Services/InstallService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistCore import TuistDependencies import TuistLoader @@ -56,12 +57,12 @@ final class InstallService { } private func fetchPlugins(path: AbsolutePath) async throws { - logger.notice("Resolving and fetching plugins.", metadata: .section) + ServiceContext.current?.logger?.notice("Resolving and fetching plugins.", metadata: .section) let config = try await configLoader.loadConfig(path: path) _ = try await pluginService.loadPlugins(using: config) - logger.notice("Plugins resolved and fetched successfully.", metadata: .success) + ServiceContext.current?.logger?.notice("Plugins resolved and fetched successfully.", metadata: .success) } private func fetchDependencies(path: AbsolutePath, update: Bool) async throws { @@ -73,7 +74,7 @@ final class InstallService { let config = try await configLoader.loadConfig(path: path) if update { - logger.notice("Updating dependencies.", metadata: .section) + ServiceContext.current?.logger?.notice("Updating dependencies.", metadata: .section) try swiftPackageManagerController.update( at: packageManifestPath.parentDirectory, @@ -81,7 +82,7 @@ final class InstallService { printOutput: true ) } else { - logger.notice("Resolving and fetching dependencies.", metadata: .section) + ServiceContext.current?.logger?.notice("Resolving and fetching dependencies.", metadata: .section) try swiftPackageManagerController.resolve( at: packageManifestPath.parentDirectory, diff --git a/Sources/TuistKit/Services/ListService.swift b/Sources/TuistKit/Services/ListService.swift index 541c9464511..3cae7f0b8c2 100644 --- a/Sources/TuistKit/Services/ListService.swift +++ b/Sources/TuistKit/Services/ListService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistPlugin @@ -65,11 +66,11 @@ class ListService { TextTable.Column(title: "Name", value: $0.name), TextTable.Column(title: "Description", value: $0.description), ] } - logger.notice("\(textTable.render(templates))") + ServiceContext.current?.logger?.notice("\(textTable.render(templates))") case .json: let json = try templates.toJSON() - logger.notice("\(json.toString(prettyPrint: true))", metadata: .json) + ServiceContext.current?.logger?.notice("\(json.toString(prettyPrint: true))", metadata: .json) } } diff --git a/Sources/TuistKit/Services/LoginService.swift b/Sources/TuistKit/Services/LoginService.swift index 3493b624494..806c7b119bf 100644 --- a/Sources/TuistKit/Services/LoginService.swift +++ b/Sources/TuistKit/Services/LoginService.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistServer @@ -88,7 +89,7 @@ final class LoginService: LoginServicing { ), serverURL: serverURL ) - logger.notice("Successfully logged in.", metadata: .success) + ServiceContext.current?.logger?.notice("Successfully logged in.", metadata: .success) } private func authenticateWithBrowserLogin( @@ -98,16 +99,19 @@ final class LoginService: LoginServicing { serverURL: serverURL, deviceCodeType: .cli, onOpeningBrowser: { authURL in - logger.notice("Opening \(authURL.absoluteString) to start the authentication flow") + ServiceContext.current?.logger?.notice("Opening \(authURL.absoluteString) to start the authentication flow") }, onAuthWaitBegin: { if Environment.shared.shouldOutputBeColoured { - logger.notice("Press \("CTRL + C".cyan()) once to cancel the process.", metadata: .pretty) + ServiceContext.current?.logger?.notice( + "Press \("CTRL + C".cyan()) once to cancel the process.", + metadata: .pretty + ) } else { - logger.notice("Press CTRL + C once to cancel the process.") + ServiceContext.current?.logger?.notice("Press CTRL + C once to cancel the process.") } } ) - logger.notice("Successfully logged in.", metadata: .success) + ServiceContext.current?.logger?.notice("Successfully logged in.", metadata: .success) } } diff --git a/Sources/TuistKit/Services/Migration/MigrationTargetsByDependenciesService.swift b/Sources/TuistKit/Services/Migration/MigrationTargetsByDependenciesService.swift index 698529b4079..e17e289394b 100644 --- a/Sources/TuistKit/Services/Migration/MigrationTargetsByDependenciesService.swift +++ b/Sources/TuistKit/Services/Migration/MigrationTargetsByDependenciesService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistMigration import TuistSupport @@ -19,7 +20,7 @@ final class MigrationTargetsByDependenciesService { func run(xcodeprojPath: AbsolutePath) async throws { let sortedTargets = try await targetsExtractor.targetsSortedByDependencies(xcodeprojPath: xcodeprojPath) let sortedTargetsJson = try makeJson(from: sortedTargets) - logger.notice("\(sortedTargetsJson)") + ServiceContext.current?.logger?.notice("\(sortedTargetsJson)") } private func makeJson(from sortedTargets: [TargetDependencyCount]) throws -> String { diff --git a/Sources/TuistKit/Services/Organization/OrganizationCreateService.swift b/Sources/TuistKit/Services/Organization/OrganizationCreateService.swift index 240d5bc6480..954a24dc714 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationCreateService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationCreateService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -44,6 +45,6 @@ final class OrganizationCreateService: OrganizationCreateServicing { serverURL: serverURL ) - logger.info("Tuist organization \(organization.name) was successfully created 🎉") + ServiceContext.current?.logger?.info("Tuist organization \(organization.name) was successfully created 🎉") } } diff --git a/Sources/TuistKit/Services/Organization/OrganizationDeleteService.swift b/Sources/TuistKit/Services/Organization/OrganizationDeleteService.swift index a798d867978..5f66573c689 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationDeleteService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationDeleteService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -44,6 +45,6 @@ final class OrganizationDeleteService: OrganizationDeleteServicing { serverURL: serverURL ) - logger.info("Tuist organization \(organizationName) was successfully deleted.") + ServiceContext.current?.logger?.info("Tuist organization \(organizationName) was successfully deleted.") } } diff --git a/Sources/TuistKit/Services/Organization/OrganizationInviteService.swift b/Sources/TuistKit/Services/Organization/OrganizationInviteService.swift index e5e37a0c0bc..eadfb84ec43 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationInviteService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationInviteService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -52,7 +53,7 @@ final class OrganizationInviteService: OrganizationInviteServicing { .appendingPathComponent("invitations") .appendingPathComponent(invitation.token) - logger.info(""" + ServiceContext.current?.logger?.info(""" \(invitation.inviteeEmail) was successfully invited to the \(organizationName) organization 🎉 You can also share with them the invite link directly: \(invitationURL.absoluteString) diff --git a/Sources/TuistKit/Services/Organization/OrganizationListService.swift b/Sources/TuistKit/Services/Organization/OrganizationListService.swift index e266672ba78..5ce7dc0d294 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationListService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationListService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -45,17 +46,18 @@ final class OrganizationListService: OrganizationListServicing { if json { let json = organizations.toJSON() - logger.info(.init(stringLiteral: json.toString(prettyPrint: true)), metadata: .json) + ServiceContext.current?.logger?.info(.init(stringLiteral: json.toString(prettyPrint: true)), metadata: .json) return } if organizations.isEmpty { - logger.info("You currently have no Cloud organizations. Create one by running `tuist organization create`.") + ServiceContext.current?.logger? + .info("You currently have no Cloud organizations. Create one by running `tuist organization create`.") return } let organizationsString = "Listing all your organizations:\n" + organizations.map { " • \($0)" } .joined(separator: "\n") - logger.info("\(organizationsString)") + ServiceContext.current?.logger?.info("\(organizationsString)") } } diff --git a/Sources/TuistKit/Services/Organization/OrganizationRemoveInviteService.swift b/Sources/TuistKit/Services/Organization/OrganizationRemoveInviteService.swift index 07901ceccfa..a417502ad84 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationRemoveInviteService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationRemoveInviteService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -47,6 +48,7 @@ final class OrganizationRemoveInviteService: OrganizationRemoveInviteServicing { serverURL: serverURL ) - logger.info("The invitation for \(email) to the \(organizationName) organization was successfully cancelled.") + ServiceContext.current?.logger? + .info("The invitation for \(email) to the \(organizationName) organization was successfully cancelled.") } } diff --git a/Sources/TuistKit/Services/Organization/OrganizationRemoveMemberService.swift b/Sources/TuistKit/Services/Organization/OrganizationRemoveMemberService.swift index 246530e7ad0..d22d877eb8f 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationRemoveMemberService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationRemoveMemberService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -47,6 +48,7 @@ final class OrganizationRemoveMemberService: OrganizationRemoveMemberServicing { serverURL: serverURL ) - logger.info("The member \(username) was successfully removed from the \(organizationName) organization.") + ServiceContext.current?.logger? + .info("The member \(username) was successfully removed from the \(organizationName) organization.") } } diff --git a/Sources/TuistKit/Services/Organization/OrganizationRemoveSSOService.swift b/Sources/TuistKit/Services/Organization/OrganizationRemoveSSOService.swift index 0f8eef53d45..2759c667f15 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationRemoveSSOService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationRemoveSSOService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -45,6 +46,6 @@ final class OrganizationRemoveSSOService: OrganizationRemoveSSOServicing { ssoOrganization: nil ) - logger.info("SSO for \(organizationName) was removed.") + ServiceContext.current?.logger?.info("SSO for \(organizationName) was removed.") } } diff --git a/Sources/TuistKit/Services/Organization/OrganizationShowService.swift b/Sources/TuistKit/Services/Organization/OrganizationShowService.swift index e4b240b4189..3915e1f930b 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationShowService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationShowService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -56,7 +57,7 @@ final class OrganizationShowService: OrganizationShowServicing { if json { let json = try organization.toJSON() - logger.info(.init(stringLiteral: json.toString(prettyPrint: true)), metadata: .json) + ServiceContext.current?.logger?.info(.init(stringLiteral: json.toString(prettyPrint: true)), metadata: .json) return } @@ -94,7 +95,7 @@ final class OrganizationShowService: OrganizationShowServicing { } } - logger.info(""" + ServiceContext.current?.logger?.info(""" \(baseInfo.joined(separator: "\n")) \("Usage".bold()) (current calendar month) diff --git a/Sources/TuistKit/Services/Organization/OrganizationUpdateMemberService.swift b/Sources/TuistKit/Services/Organization/OrganizationUpdateMemberService.swift index 12dd0e5b99d..7c4bbebb4bf 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationUpdateMemberService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationUpdateMemberService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -50,6 +51,6 @@ final class OrganizationUpdateMemberService: OrganizationUpdateMemberServicing { serverURL: serverURL ) - logger.info("The member \(username) role was successfully updated to \(member.role.rawValue).") + ServiceContext.current?.logger?.info("The member \(username) role was successfully updated to \(member.role.rawValue).") } } diff --git a/Sources/TuistKit/Services/Organization/OrganizationUpdateService.swift b/Sources/TuistKit/Services/Organization/OrganizationUpdateService.swift index 6e720d8a7c8..9258f1ae13f 100644 --- a/Sources/TuistKit/Services/Organization/OrganizationUpdateService.swift +++ b/Sources/TuistKit/Services/Organization/OrganizationUpdateService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -57,7 +58,7 @@ final class OrganizationUpdateSSOService: OrganizationUpdateSSOServicing { ssoOrganization: ssoOrganization ) - logger + ServiceContext.current?.logger? .info( "\(organizationName) now uses \(provider.rawValue.capitalized) SSO with \(organizationId). Users authenticated with the \(organizationId) SSO organization will automatically have access to the \(organizationName) projects." ) diff --git a/Sources/TuistKit/Services/Plugin/PluginArchiveService.swift b/Sources/TuistKit/Services/Plugin/PluginArchiveService.swift index 41a7a5d1a15..5dc09257f35 100644 --- a/Sources/TuistKit/Services/Plugin/PluginArchiveService.swift +++ b/Sources/TuistKit/Services/Plugin/PluginArchiveService.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistDependencies import TuistLoader import TuistSupport @@ -44,7 +45,7 @@ final class PluginArchiveService { .filter { $0.hasPrefix("tuist-") } if taskProducts.isEmpty { - logger + ServiceContext.current?.logger? .warning("No tasks found - make sure you have executable products with `tuist-` prefix defined in your manifest.") return } @@ -79,7 +80,7 @@ final class PluginArchiveService { ) async throws { let artifactsPath = temporaryDirectory.appending(component: "artifacts") for product in taskProducts { - logger.notice("Building \(product)...") + ServiceContext.current?.logger?.notice("Building \(product)...") try await swiftPackageManagerController.buildFatReleaseBinary( packagePath: path, product: product, @@ -103,7 +104,7 @@ final class PluginArchiveService { ) try await archiver.delete() - logger.notice( + ServiceContext.current?.logger?.notice( "Plugin was successfully archived. Create a new Github release and attach the file \(zipPath.pathString) as an artifact.", metadata: .success ) diff --git a/Sources/TuistKit/Services/Project/ProjectCreateService.swift b/Sources/TuistKit/Services/Project/ProjectCreateService.swift index baa36f47725..74fc973e5b2 100644 --- a/Sources/TuistKit/Services/Project/ProjectCreateService.swift +++ b/Sources/TuistKit/Services/Project/ProjectCreateService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -45,6 +46,6 @@ final class ProjectCreateService: ProjectCreateServicing { serverURL: serverURL ) - logger.info("Tuist project \(project.fullName) was successfully created 🎉") + ServiceContext.current?.logger?.info("Tuist project \(project.fullName) was successfully created 🎉") } } diff --git a/Sources/TuistKit/Services/Project/ProjectDeleteService.swift b/Sources/TuistKit/Services/Project/ProjectDeleteService.swift index da1b0441931..8718736d2bf 100644 --- a/Sources/TuistKit/Services/Project/ProjectDeleteService.swift +++ b/Sources/TuistKit/Services/Project/ProjectDeleteService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -52,6 +53,6 @@ final class ProjectDeleteService: ProjectDeleteServicing { serverURL: serverURL ) - logger.info("Successfully deleted the \(project.fullName) project.") + ServiceContext.current?.logger?.info("Successfully deleted the \(project.fullName) project.") } } diff --git a/Sources/TuistKit/Services/Project/ProjectListService.swift b/Sources/TuistKit/Services/Project/ProjectListService.swift index 2e1c265435c..e0185ede0d3 100644 --- a/Sources/TuistKit/Services/Project/ProjectListService.swift +++ b/Sources/TuistKit/Services/Project/ProjectListService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -45,16 +46,17 @@ final class ProjectListService: ProjectListServicing { if json { let json = try projects.toJSON() - logger.info(.init(stringLiteral: json.toString(prettyPrint: true)), metadata: .json) + ServiceContext.current?.logger?.info(.init(stringLiteral: json.toString(prettyPrint: true)), metadata: .json) return } if projects.isEmpty { - logger.info("You currently have no Tuist projects. Create one by running `tuist project create`.") + ServiceContext.current?.logger? + .info("You currently have no Tuist projects. Create one by running `tuist project create`.") return } let projectsString = "Listing all your projects:\n" + projects.map { " • \($0.fullName)" }.joined(separator: "\n") - logger.info("\(projectsString)") + ServiceContext.current?.logger?.info("\(projectsString)") } } diff --git a/Sources/TuistKit/Services/Project/ProjectShowService.swift b/Sources/TuistKit/Services/Project/ProjectShowService.swift index 9f3b4346d44..e2262f1750d 100644 --- a/Sources/TuistKit/Services/Project/ProjectShowService.swift +++ b/Sources/TuistKit/Services/Project/ProjectShowService.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -74,7 +75,7 @@ struct ProjectShowService { projectInfo.append("Default branch: \(project.defaultBranch)") projectInfo.append("Visibility: \(project.visibility.rawValue)") - logger.info("\(projectInfo.joined(separator: "\n"))") + ServiceContext.current?.logger?.info("\(projectInfo.joined(separator: "\n"))") } } diff --git a/Sources/TuistKit/Services/Project/ProjectTokensCreateService.swift b/Sources/TuistKit/Services/Project/ProjectTokensCreateService.swift index c27bffe2791..57241a503cd 100644 --- a/Sources/TuistKit/Services/Project/ProjectTokensCreateService.swift +++ b/Sources/TuistKit/Services/Project/ProjectTokensCreateService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -52,6 +53,6 @@ final class ProjectTokensCreateService: ProjectTokensCreateServicing { serverURL: serverURL ) - logger.info(.init(stringLiteral: token)) + ServiceContext.current?.logger?.info(.init(stringLiteral: token)) } } diff --git a/Sources/TuistKit/Services/Project/ProjectTokensListService.swift b/Sources/TuistKit/Services/Project/ProjectTokensListService.swift index fa75163589c..20f60730809 100644 --- a/Sources/TuistKit/Services/Project/ProjectTokensListService.swift +++ b/Sources/TuistKit/Services/Project/ProjectTokensListService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -45,13 +46,14 @@ final class ProjectTokensListService: ProjectTokensListServicing { ) if tokens.isEmpty { - logger.notice("No project tokens found. Create one by running `tuist project tokens create \(fullHandle).") + ServiceContext.current?.logger? + .notice("No project tokens found. Create one by running `tuist project tokens create \(fullHandle).") } else { let textTable = TextTable { [ TextTable.Column(title: "ID", value: $0.id), TextTable.Column(title: "Created at", value: $0.insertedAt), ] } - logger.notice("\(textTable.render(tokens))") + ServiceContext.current?.logger?.notice("\(textTable.render(tokens))") } } } diff --git a/Sources/TuistKit/Services/Project/ProjectTokensRevokeService.swift b/Sources/TuistKit/Services/Project/ProjectTokensRevokeService.swift index 7e0b50f1b97..3e7ab6a0d37 100644 --- a/Sources/TuistKit/Services/Project/ProjectTokensRevokeService.swift +++ b/Sources/TuistKit/Services/Project/ProjectTokensRevokeService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -47,6 +48,6 @@ final class ProjectTokensRevokeService: ProjectTokensRevokeServicing { serverURL: serverURL ) - logger.info("The project token \(projectTokenId) was successfully revoked.") + ServiceContext.current?.logger?.info("The project token \(projectTokenId) was successfully revoked.") } } diff --git a/Sources/TuistKit/Services/Project/ProjectUpdateService.swift b/Sources/TuistKit/Services/Project/ProjectUpdateService.swift index 8dea192ca76..4d179f6504d 100644 --- a/Sources/TuistKit/Services/Project/ProjectUpdateService.swift +++ b/Sources/TuistKit/Services/Project/ProjectUpdateService.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -62,7 +63,7 @@ struct ProjectUpdateService { visibility: visibility ) - logger.notice("The project \(fullHandle) was successfully updated 🎉", metadata: .success) + ServiceContext.current?.logger?.notice("The project \(fullHandle) was successfully updated 🎉", metadata: .success) } // MARK: - Helpers diff --git a/Sources/TuistKit/Services/Registry/RegistryLoginService.swift b/Sources/TuistKit/Services/Registry/RegistryLoginService.swift index e4470490e49..380c7dae87c 100644 --- a/Sources/TuistKit/Services/Registry/RegistryLoginService.swift +++ b/Sources/TuistKit/Services/Registry/RegistryLoginService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -64,7 +65,7 @@ struct RegistryLoginService { guard let fullHandle = config.fullHandle else { throw RegistryLoginServiceError.missingFullHandle } let accountHandle = try fullHandleService.parse(fullHandle).accountHandle - logger.info("Logging into the registry...") + ServiceContext.current?.logger?.info("Logging into the registry...") let serverURL = try serverURLService.url(configServerURL: config.url) let token: String @@ -90,7 +91,7 @@ struct RegistryLoginService { registryURL: registryURL ) - logger.info("Successfully logged in to the \(accountHandle) registry 🎉") + ServiceContext.current?.logger?.info("Successfully logged in to the \(accountHandle) registry 🎉") } private func path(_ path: String?) async throws -> AbsolutePath { diff --git a/Sources/TuistKit/Services/Registry/RegistryLogoutService.swift b/Sources/TuistKit/Services/Registry/RegistryLogoutService.swift index c55851bdf68..9ec4600b49d 100644 --- a/Sources/TuistKit/Services/Registry/RegistryLogoutService.swift +++ b/Sources/TuistKit/Services/Registry/RegistryLogoutService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -29,14 +30,14 @@ final class RegistryLogoutService { let path = try await self.path(path) let config = try await configLoader.loadConfig(path: path) - logger.info("Logging out of the registry...") + ServiceContext.current?.logger?.info("Logging out of the registry...") let serverURL = try serverURLService.url(configServerURL: config.url) try await swiftPackageManagerController.packageRegistryLogout( registryURL: serverURL ) - logger.info("Successfully logged out of the registry.") + ServiceContext.current?.logger?.info("Successfully logged out of the registry.") } private func path(_ path: String?) async throws -> AbsolutePath { diff --git a/Sources/TuistKit/Services/Registry/RegistrySetupService.swift b/Sources/TuistKit/Services/Registry/RegistrySetupService.swift index 61d493ecaa4..776588b297b 100644 --- a/Sources/TuistKit/Services/Registry/RegistrySetupService.swift +++ b/Sources/TuistKit/Services/Registry/RegistrySetupService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -55,7 +56,7 @@ final class RegistrySetupService { guard let fullHandle = config.fullHandle else { throw RegistrySetupServiceError.missingFullHandle } let accountHandle = try fullHandleService.parse(fullHandle).accountHandle - logger.info("Logging into the registry...") + ServiceContext.current?.logger?.info("Logging into the registry...") let serverURL = try serverURLService.url(configServerURL: config.url) let swiftPackageManagerPath: AbsolutePath @@ -85,7 +86,7 @@ final class RegistrySetupService { at: configurationJSONPath ) - logger.info(""" + ServiceContext.current?.logger?.info(""" Generated the \(accountHandle) registry configuration file at \(configurationJSONPath). Make sure to commit this file to share the configuration with the rest of your team. To log in to the registry, run 'tuist registry login'. diff --git a/Sources/TuistKit/Services/RunService.swift b/Sources/TuistKit/Services/RunService.swift index 06b478bf361..09ddda63d74 100644 --- a/Sources/TuistKit/Services/RunService.swift +++ b/Sources/TuistKit/Services/RunService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import struct TSCUtility.Version import TuistAutomation import TuistCore @@ -202,7 +203,7 @@ final class RunService { device: String?, version: Version? ) async throws { - logger.notice("Runnning \(previewLink.absoluteString)...") + ServiceContext.current?.logger?.notice("Runnning \(previewLink.absoluteString)...") guard let scheme = previewLink.scheme, let host = previewLink.host, let serverURL = URL(string: "\(scheme)://\(host)\(previewLink.port.map { ":" + String($0) } ?? "")"), @@ -252,7 +253,7 @@ final class RunService { let generator = generatorFactory.defaultGenerator(config: config, sources: []) let workspacePath = try await buildGraphInspector.workspacePath(directory: path) if generate || workspacePath == nil { - logger.notice("Generating project for running", metadata: .section) + ServiceContext.current?.logger?.notice("Generating project for running", metadata: .section) graph = try await generator.generateWithGraph(path: path).1 } else { graph = try await generator.load(path: path) @@ -265,7 +266,8 @@ final class RunService { let graphTraverser = GraphTraverser(graph: graph) let runnableSchemes = buildGraphInspector.runnableSchemes(graphTraverser: graphTraverser) - logger.debug("Found the following runnable schemes: \(runnableSchemes.map(\.name).joined(separator: ", "))") + ServiceContext.current?.logger? + .debug("Found the following runnable schemes: \(runnableSchemes.map(\.name).joined(separator: ", "))") guard let scheme = runnableSchemes.first(where: { $0.name == scheme }) else { throw RunServiceError.schemeNotFound(scheme: scheme, existing: runnableSchemes.map(\.name)) diff --git a/Sources/TuistKit/Services/ScaffoldService.swift b/Sources/TuistKit/Services/ScaffoldService.swift index 3a2ae5eb6d8..fd87f497123 100644 --- a/Sources/TuistKit/Services/ScaffoldService.swift +++ b/Sources/TuistKit/Services/ScaffoldService.swift @@ -1,4 +1,5 @@ import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistPlugin @@ -106,7 +107,7 @@ final class ScaffoldService { attributes: parsedAttributes ) - logger.notice("Template \(templateName) was successfully generated", metadata: .success) + ServiceContext.current?.logger?.notice("Template \(templateName) was successfully generated", metadata: .success) } // MARK: - Helpers diff --git a/Sources/TuistKit/Services/ShareService.swift b/Sources/TuistKit/Services/ShareService.swift index f8c4a398e5a..3140d74485d 100644 --- a/Sources/TuistKit/Services/ShareService.swift +++ b/Sources/TuistKit/Services/ShareService.swift @@ -2,6 +2,7 @@ import AnyCodable import FileSystem import Foundation import Path +import ServiceContextModule import TuistAutomation import TuistCore import TuistLoader @@ -409,7 +410,7 @@ struct ShareService { serverURL: URL, json: Bool ) async throws { - logger.notice("Uploading \(displayName)...") + ServiceContext.current?.logger?.notice("Uploading \(displayName)...") let preview = try await previewsUploadService.uploadPreviews( previewUploadType, displayName: displayName, @@ -420,7 +421,8 @@ struct ShareService { fullHandle: fullHandle, serverURL: serverURL ) - logger.notice("\(displayName) uploaded – share it with others using the following link: \(preview.url.absoluteString)") + ServiceContext.current?.logger? + .notice("\(displayName) uploaded – share it with others using the following link: \(preview.url.absoluteString)") ShareCommand.analyticsDelegate?.addParameters( [ @@ -430,7 +432,7 @@ struct ShareService { if json { let previewJSON = try preview.toJSON() - logger.info( + ServiceContext.current?.logger?.info( .init( stringLiteral: previewJSON.toString(prettyPrint: true) ), diff --git a/Sources/TuistKit/Services/TestService.swift b/Sources/TuistKit/Services/TestService.swift index ee16364c8f1..f9e234aa75d 100644 --- a/Sources/TuistKit/Services/TestService.swift +++ b/Sources/TuistKit/Services/TestService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import struct TSCUtility.Version import TuistAutomation import TuistCore @@ -205,7 +206,7 @@ final class TestService { // swiftlint:disable:this type_body_length cacheStorage: cacheStorage ) - logger.notice("Generating project for testing", metadata: .section) + ServiceContext.current?.logger?.notice("Generating project for testing", metadata: .section) let (_, graph, mapperEnvironment) = try await testGenerator.generateWithGraph( path: path ) @@ -223,7 +224,7 @@ final class TestService { // swiftlint:disable:this type_body_length let version = osVersion?.version() let testableSchemes = buildGraphInspector.testableSchemes(graphTraverser: graphTraverser) + buildGraphInspector.workspaceSchemes(graphTraverser: graphTraverser) - logger.log( + ServiceContext.current?.logger?.log( level: .debug, "Found the following testable schemes: \(Set(testableSchemes.map(\.name)).joined(separator: ", "))" ) @@ -253,7 +254,10 @@ final class TestService { // swiftlint:disable:this type_body_length else { let schemes = mapperEnvironment.initialGraph.map(GraphTraverser.init)?.schemes() ?? graphTraverser.schemes() if let scheme = schemes.first(where: { $0.name == schemeName }) { - logger.log(level: .info, "The scheme \(schemeName)'s test action has no tests to run, finishing early.") + ServiceContext.current?.logger?.log( + level: .info, + "The scheme \(schemeName)'s test action has no tests to run, finishing early." + ) updateTestServiceAnalytics( analyticsDelegate: analyticsDelegate, mapperEnvironment: mapperEnvironment, @@ -280,10 +284,16 @@ final class TestService { // swiftlint:disable:this type_body_length case (_, false, _): break case (nil, true, _), (nil, nil, _): - logger.log(level: .info, "The scheme \(schemeName)'s test action has no tests to run, finishing early.") + ServiceContext.current?.logger?.log( + level: .info, + "The scheme \(schemeName)'s test action has no tests to run, finishing early." + ) return case (_?, _, true), (_?, _, nil): - logger.log(level: .info, "The scheme \(schemeName)'s test action has no test plans to run, finishing early.") + ServiceContext.current?.logger?.log( + level: .info, + "The scheme \(schemeName)'s test action has no test plans to run, finishing early." + ) return default: break @@ -404,7 +414,7 @@ final class TestService { // swiftlint:disable:this type_body_length cacheStorage: uploadCacheStorage ) - logger.log(level: .notice, "The project tests ran successfully", metadata: .success) + ServiceContext.current?.logger?.log(level: .notice, "The project tests ran successfully", metadata: .success) } private func updateTestServiceAnalytics( @@ -490,12 +500,12 @@ final class TestService { // swiftlint:disable:this type_body_length } if testSchemes.isEmpty { - logger.log(level: .info, "There are no tests to run, finishing early") + ServiceContext.current?.logger?.log(level: .info, "There are no tests to run, finishing early") return false } if !skippedTestTargets.isEmpty { - logger + ServiceContext.current?.logger? .notice( "The following targets have not changed since the last successful run and will be skipped: \(skippedTestTargets.map(\.target.name).joined(separator: ", "))" ) @@ -627,7 +637,7 @@ final class TestService { // swiftlint:disable:this type_body_length testPlanConfiguration: TestPlanConfiguration?, passthroughXcodeBuildArguments: [String] ) async throws { - logger.log(level: .notice, "Testing scheme \(scheme.name)", metadata: .section) + ServiceContext.current?.logger?.log(level: .notice, "Testing scheme \(scheme.name)", metadata: .section) if let testPlan = testPlanConfiguration?.testPlan, let testPlans = scheme.testAction?.testPlans, !testPlans.contains(where: { $0.name == testPlan }) { diff --git a/Sources/TuistKit/Services/TuistService.swift b/Sources/TuistKit/Services/TuistService.swift index 0881864e818..4cb1cc00239 100644 --- a/Sources/TuistKit/Services/TuistService.swift +++ b/Sources/TuistKit/Services/TuistService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistPlugin @@ -49,7 +50,7 @@ final class TuistService: NSObject { if let pluginPath: String = ProcessInfo.processInfo.environment["TUIST_CONFIG_PLUGIN_BINARY_PATH"] { let absolutePath = try AbsolutePath(validating: pluginPath) - logger.debug("Using plugin absolutePath \(absolutePath.description)", metadata: .subsection) + ServiceContext.current?.logger?.debug("Using plugin absolutePath \(absolutePath.description)", metadata: .subsection) pluginPaths.append(absolutePath) } diff --git a/Sources/TuistKit/Services/WhoamiService.swift b/Sources/TuistKit/Services/WhoamiService.swift index c2ffe1769ee..95bcd90ea15 100644 --- a/Sources/TuistKit/Services/WhoamiService.swift +++ b/Sources/TuistKit/Services/WhoamiService.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistServer @@ -40,9 +41,9 @@ final class WhoamiService: WhoamiServicing { let config = try await configLoader.loadConfig(path: directoryPath) let serverURL = try serverURLService.url(configServerURL: config.url) if let whoami = try await serverSessionController.whoami(serverURL: serverURL) { - logger.notice("\(whoami)") + ServiceContext.current?.logger?.notice("\(whoami)") } else { - logger.notice("You are not logged in. Run 'tuist auth login'.") + ServiceContext.current?.logger?.notice("You are not logged in. Run 'tuist auth login'.") } } } diff --git a/Sources/TuistKit/Utils/TuistAnalyticsServerBackend.swift b/Sources/TuistKit/Utils/TuistAnalyticsServerBackend.swift index b3da042ac89..7d8052c2a50 100644 --- a/Sources/TuistKit/Utils/TuistAnalyticsServerBackend.swift +++ b/Sources/TuistKit/Utils/TuistAnalyticsServerBackend.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistAnalytics import TuistAsyncQueue import TuistCore @@ -86,7 +87,7 @@ public class TuistAnalyticsServerBackend: TuistAnalyticsBackend { } if #available(macOS 13.0, *), ciChecker.isCI() { - logger + ServiceContext.current?.logger? .info( "You can view a detailed report at: \(serverCommandEvent.url.absoluteString)" ) diff --git a/Sources/TuistLoader/Loaders/CachedManifestLoader.swift b/Sources/TuistLoader/Loaders/CachedManifestLoader.swift index c98fb785681..37628152f17 100644 --- a/Sources/TuistLoader/Loaders/CachedManifestLoader.swift +++ b/Sources/TuistLoader/Loaders/CachedManifestLoader.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport @@ -146,7 +147,7 @@ public class CachedManifestLoader: ManifestLoading { ) guard let hashes = calculatedHashes else { - logger.warning("Unable to calculate manifest hash at path: \(path)") + ServiceContext.current?.logger?.warning("Unable to calculate manifest hash at path: \(path)") return try await loader() } diff --git a/Sources/TuistLoader/Loaders/ManifestLoader.swift b/Sources/TuistLoader/Loaders/ManifestLoader.swift index e1eac798725..15cdc55b3d7 100644 --- a/Sources/TuistLoader/Loaders/ManifestLoader.swift +++ b/Sources/TuistLoader/Loaders/ManifestLoader.swift @@ -3,6 +3,7 @@ import Foundation import Mockable import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -336,8 +337,8 @@ public class ManifestLoader: ManifestLoading { let preManifestLogs = String(string[string.startIndex ..< startTokenRange.lowerBound]).chomp() let postManifestLogs = String(string[endTokenRange.upperBound ..< string.endIndex]).chomp() - if !preManifestLogs.isEmpty { logger.notice("\(path.pathString): \(preManifestLogs)") } - if !postManifestLogs.isEmpty { logger.notice("\(path.pathString):\(postManifestLogs)") } + if !preManifestLogs.isEmpty { ServiceContext.current?.logger?.notice("\(path.pathString): \(preManifestLogs)") } + if !postManifestLogs.isEmpty { ServiceContext.current?.logger?.notice("\(path.pathString):\(postManifestLogs)") } let manifest = string[startTokenRange.upperBound ..< endTokenRange.lowerBound] return manifest.data(using: .utf8)! @@ -440,10 +441,11 @@ public class ManifestLoader: ManifestLoading { let defaultHelpersName = ProjectDescriptionHelpersBuilder.defaultHelpersName if errorMessage.contains(defaultHelpersName) { - logger.error("Cannot import \(defaultHelpersName) in \(manifest.fileName(path))") - logger.notice("Project description helpers that depend on plugins are not allowed in \(manifest.fileName(path))") + ServiceContext.current?.logger?.error("Cannot import \(defaultHelpersName) in \(manifest.fileName(path))") + ServiceContext.current?.logger? + .notice("Project description helpers that depend on plugins are not allowed in \(manifest.fileName(path))") } else if errorMessage.contains("import") { - logger.error("Helper plugins are not allowed in \(manifest.fileName(path))") + ServiceContext.current?.logger?.error("Helper plugins are not allowed in \(manifest.fileName(path))") } } @@ -455,6 +457,6 @@ public class ManifestLoader: ManifestLoading { let pluginHelpers = plugins.projectDescriptionHelpers guard let pluginHelper = pluginHelpers.first(where: { errorMessage.contains($0.name) }) else { return } - logger.error("Unable to build plugin \(pluginHelper.name) located at \(pluginHelper.path)") + ServiceContext.current?.logger?.error("Unable to build plugin \(pluginHelper.name) located at \(pluginHelper.path)") } } diff --git a/Sources/TuistLoader/Loaders/SwiftPackageManagerGraphLoader.swift b/Sources/TuistLoader/Loaders/SwiftPackageManagerGraphLoader.swift index c9932693f9b..a236cdadc44 100644 --- a/Sources/TuistLoader/Loaders/SwiftPackageManagerGraphLoader.swift +++ b/Sources/TuistLoader/Loaders/SwiftPackageManagerGraphLoader.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import ProjectDescription +import ServiceContextModule import TSCUtility import TuistCore import TuistSupport @@ -233,7 +234,8 @@ public final class SwiftPackageManagerGraphLoader: SwiftPackageManagerGraphLoadi } if currentData != savedData { - logger.warning("We detected outdated dependencies. Please run \"tuist install\" to update them.") + ServiceContext.current?.logger? + .warning("We detected outdated dependencies. Please run \"tuist install\" to update them.") } } } diff --git a/Sources/TuistLoader/Log/Logger.swift b/Sources/TuistLoader/Log/Logger.swift deleted file mode 100644 index e6f04b3c7d5..00000000000 --- a/Sources/TuistLoader/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.loader") diff --git a/Sources/TuistLoader/Models+ManifestMappers/CopyFileElement+ManifestMapper.swift b/Sources/TuistLoader/Models+ManifestMappers/CopyFileElement+ManifestMapper.swift index df59b797100..421d9fcbeb8 100644 --- a/Sources/TuistLoader/Models+ManifestMappers/CopyFileElement+ManifestMapper.swift +++ b/Sources/TuistLoader/Models+ManifestMappers/CopyFileElement+ManifestMapper.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -31,10 +32,11 @@ extension XcodeGraph.CopyFileElement { if files.isEmpty { if FileHandler.shared.isFolder(path) { - logger.warning("'\(path.pathString)' is a directory, try using: '\(path.pathString)/**' to list its files") + ServiceContext.current?.logger? + .warning("'\(path.pathString)' is a directory, try using: '\(path.pathString)/**' to list its files") } else { // FIXME: This should be done in a linter. - logger.warning("No files found at: \(path.pathString)") + ServiceContext.current?.logger?.warning("No files found at: \(path.pathString)") } } @@ -44,13 +46,14 @@ extension XcodeGraph.CopyFileElement { func folderReferences(_ path: AbsolutePath) async throws -> [AbsolutePath] { guard try await fileSystem.exists(path) else { // FIXME: This should be done in a linter. - logger.warning("\(path.pathString) does not exist") + ServiceContext.current?.logger?.warning("\(path.pathString) does not exist") return [] } guard FileHandler.shared.isFolder(path) else { // FIXME: This should be done in a linter. - logger.warning("\(path.pathString) is not a directory - folder reference paths need to point to directories") + ServiceContext.current?.logger? + .warning("\(path.pathString) is not a directory - folder reference paths need to point to directories") return [] } diff --git a/Sources/TuistLoader/Models+ManifestMappers/FileElement+ManifestMapper.swift b/Sources/TuistLoader/Models+ManifestMappers/FileElement+ManifestMapper.swift index a5223e32b46..193e78a4b3d 100644 --- a/Sources/TuistLoader/Models+ManifestMappers/FileElement+ManifestMapper.swift +++ b/Sources/TuistLoader/Models+ManifestMappers/FileElement+ManifestMapper.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -30,10 +31,11 @@ extension XcodeGraph.FileElement { if files.isEmpty { if FileHandler.shared.isFolder(path) { - logger.warning("'\(path.pathString)' is a directory, try using: '\(path.pathString)/**' to list its files") + ServiceContext.current?.logger? + .warning("'\(path.pathString)' is a directory, try using: '\(path.pathString)/**' to list its files") } else { // FIXME: This should be done in a linter. - logger.warning("No files found at: \(path.pathString)") + ServiceContext.current?.logger?.warning("No files found at: \(path.pathString)") } } @@ -43,13 +45,14 @@ extension XcodeGraph.FileElement { func folderReferences(_ path: AbsolutePath) async throws -> [AbsolutePath] { guard try await fileSystem.exists(path) else { // FIXME: This should be done in a linter. - logger.warning("\(path.pathString) does not exist") + ServiceContext.current?.logger?.warning("\(path.pathString) does not exist") return [] } guard FileHandler.shared.isFolder(path) else { // FIXME: This should be done in a linter. - logger.warning("\(path.pathString) is not a directory - folder reference paths need to point to directories") + ServiceContext.current?.logger? + .warning("\(path.pathString) is not a directory - folder reference paths need to point to directories") return [] } diff --git a/Sources/TuistLoader/Models+ManifestMappers/ResourceFileElement+ManifestMapper.swift b/Sources/TuistLoader/Models+ManifestMappers/ResourceFileElement+ManifestMapper.swift index 61608dcba22..182dec84ff9 100644 --- a/Sources/TuistLoader/Models+ManifestMappers/ResourceFileElement+ManifestMapper.swift +++ b/Sources/TuistLoader/Models+ManifestMappers/ResourceFileElement+ManifestMapper.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -38,10 +39,11 @@ extension XcodeGraph.ResourceFileElement { if files.isEmpty { if FileHandler.shared.isFolder(path) { - logger.warning("'\(path.pathString)' is a directory, try using: '\(path.pathString)/**' to list its files") + ServiceContext.current?.logger? + .warning("'\(path.pathString)' is a directory, try using: '\(path.pathString)/**' to list its files") } else { // FIXME: This should be done in a linter. - logger.warning("No files found at: \(path.pathString)") + ServiceContext.current?.logger?.warning("No files found at: \(path.pathString)") } } @@ -53,13 +55,14 @@ extension XcodeGraph.ResourceFileElement { func folderReferences(_ path: AbsolutePath) async throws -> [AbsolutePath] { guard try await fileSystem.exists(path) else { // FIXME: This should be done in a linter. - logger.warning("\(path.pathString) does not exist") + ServiceContext.current?.logger?.warning("\(path.pathString) does not exist") return [] } guard FileHandler.shared.isFolder(path) else { // FIXME: This should be done in a linter. - logger.warning("\(path.pathString) is not a directory - folder reference paths need to point to directories") + ServiceContext.current?.logger? + .warning("\(path.pathString) is not a directory - folder reference paths need to point to directories") return [] } diff --git a/Sources/TuistLoader/Models+ManifestMappers/Workspace+ManifestMapper.swift b/Sources/TuistLoader/Models+ManifestMappers/Workspace+ManifestMapper.swift index ea635e4e8a2..9f170cd2bf7 100644 --- a/Sources/TuistLoader/Models+ManifestMappers/Workspace+ManifestMapper.swift +++ b/Sources/TuistLoader/Models+ManifestMappers/Workspace+ManifestMapper.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -36,7 +37,7 @@ extension XcodeGraph.Workspace { // FIXME: This should be done in a linter. // Before we can do that we have to change the linters to run with the TuistCore models and not the // ProjectDescription ones. - logger.warning("No projects found at: \(path.pathString)") + ServiceContext.current?.logger?.warning("No projects found at: \(path.pathString)") } return Array(projects) diff --git a/Sources/TuistLoader/ProjectDescriptionHelpers/ProjectDescriptionHelpersBuilder.swift b/Sources/TuistLoader/ProjectDescriptionHelpers/ProjectDescriptionHelpersBuilder.swift index 95f3bd1c5df..60168bc0440 100644 --- a/Sources/TuistLoader/ProjectDescriptionHelpers/ProjectDescriptionHelpersBuilder.swift +++ b/Sources/TuistLoader/ProjectDescriptionHelpers/ProjectDescriptionHelpersBuilder.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport @@ -193,7 +194,7 @@ public final class ProjectDescriptionHelpersBuilder: ProjectDescriptionHelpersBu try System.shared.runAndPrint(command, verbose: false, environment: Environment.shared.manifestLoadingVariables) let duration = timer.stop() let time = String(format: "%.3f", duration) - logger.debug("Built \(name) in (\(time)s)", metadata: .success) + ServiceContext.current?.logger?.debug("Built \(name) in (\(time)s)", metadata: .success) return module } diff --git a/Sources/TuistLoader/SwiftPackageManager/PackageInfoMapper.swift b/Sources/TuistLoader/SwiftPackageManager/PackageInfoMapper.swift index b4b5cc6df1c..1d98b5ad8de 100644 --- a/Sources/TuistLoader/SwiftPackageManager/PackageInfoMapper.swift +++ b/Sources/TuistLoader/SwiftPackageManager/PackageInfoMapper.swift @@ -3,6 +3,7 @@ import Foundation import Mockable import Path import ProjectDescription +import ServiceContextModule import TSCUtility import TuistCore import TuistSupport @@ -383,13 +384,13 @@ public final class PackageInfoMapper: PackageInfoMapping { case .test, .executable: switch packageType { case .external: - logger.debug("Target \(target.name) of type \(target.type) ignored") + ServiceContext.current?.logger?.debug("Target \(target.name) of type \(target.type) ignored") return nil case .local: break } default: - logger.debug("Target \(target.name) of type \(target.type) ignored") + ServiceContext.current?.logger?.debug("Target \(target.name) of type \(target.type) ignored") return nil } @@ -402,7 +403,7 @@ public final class PackageInfoMapper: PackageInfoMapping { productTypes: productTypes ) else { - logger.debug("Target \(target.name) ignored by product type") + ServiceContext.current?.logger?.debug("Target \(target.name) ignored by product type") return nil } diff --git a/Sources/TuistMigration/Log/Logger.swift b/Sources/TuistMigration/Log/Logger.swift deleted file mode 100644 index 862e66ab1ed..00000000000 --- a/Sources/TuistMigration/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.migration") diff --git a/Sources/TuistMigration/Utilities/EmptyBuildSettingsChecker.swift b/Sources/TuistMigration/Utilities/EmptyBuildSettingsChecker.swift index dfb64fc421b..96d091d09a3 100644 --- a/Sources/TuistMigration/Utilities/EmptyBuildSettingsChecker.swift +++ b/Sources/TuistMigration/Utilities/EmptyBuildSettingsChecker.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import PathKit +import ServiceContextModule import TuistSupport import XcodeProj @@ -65,7 +66,8 @@ public class EmptyBuildSettingsChecker: EmptyBuildSettingsChecking { let nonEmptyBuildSettings = buildConfigurations.compactMap { config -> String? in if config.buildSettings.isEmpty { return nil } for (key, _) in config.buildSettings { - logger.notice("The build setting '\(key)' of build configuration '\(config.name)' is not empty.") + ServiceContext.current?.logger? + .notice("The build setting '\(key)' of build configuration '\(config.name)' is not empty.") } return config.name } diff --git a/Sources/TuistMigration/Utilities/SettingsToXCConfigExtractor.swift b/Sources/TuistMigration/Utilities/SettingsToXCConfigExtractor.swift index 7d6881a4705..24a98345a5f 100644 --- a/Sources/TuistMigration/Utilities/SettingsToXCConfigExtractor.swift +++ b/Sources/TuistMigration/Utilities/SettingsToXCConfigExtractor.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Path import PathKit +import ServiceContextModule import TuistSupport import XcodeProj @@ -57,7 +58,7 @@ public final class SettingsToXCConfigExtractor: SettingsToXCConfigExtracting { let buildConfigurations = try buildConfigurations(pbxproj: pbxproj, targetName: targetName) if buildConfigurations.isEmpty { - logger.notice("The list of configurations is empty. Exiting...") + ServiceContext.current?.logger?.notice("The list of configurations is empty. Exiting...") return } @@ -99,7 +100,10 @@ public final class SettingsToXCConfigExtractor: SettingsToXCConfigExtracting { buildSettingsLines.sorted().joined(separator: "\n"), ].joined(separator: "\n\n") try FileHandler.shared.write(buildSettingsContent, path: xcconfigPath, atomically: true) - logger.notice("Build settings successfully extracted into \(xcconfigPath.pathString)", metadata: .success) + ServiceContext.current?.logger?.notice( + "Build settings successfully extracted into \(xcconfigPath.pathString)", + metadata: .success + ) } private func buildConfigurations(pbxproj: PBXProj, targetName: String?) throws -> [XCBuildConfiguration] { diff --git a/Sources/TuistPlugin/Logger.swift b/Sources/TuistPlugin/Logger.swift deleted file mode 100644 index b96cfdec0ef..00000000000 --- a/Sources/TuistPlugin/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.plugin") diff --git a/Sources/TuistPlugin/PluginService.swift b/Sources/TuistPlugin/PluginService.swift index f20db51dd3a..8e812476bda 100644 --- a/Sources/TuistPlugin/PluginService.swift +++ b/Sources/TuistPlugin/PluginService.swift @@ -1,6 +1,7 @@ import FileSystem import Foundation import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistScaffold @@ -147,7 +148,7 @@ public struct PluginService: PluginServicing { .compactMap { pluginLocation in switch pluginLocation { case let .local(path): - logger.debug("Using plugin \(pluginLocation.description)", metadata: .subsection) + ServiceContext.current?.logger?.debug("Using plugin \(pluginLocation.description)", metadata: .subsection) return try AbsolutePath(validating: path) case .git: return nil @@ -257,12 +258,12 @@ public struct PluginService: PluginServicing { let pluginRepositoryDirectory = pluginCacheDirectory.appending(component: PluginServiceConstants.repository) guard try await !fileSystem.exists(pluginRepositoryDirectory) else { - logger.debug("Using cached git plugin \(url)") + ServiceContext.current?.logger?.debug("Using cached git plugin \(url)") return } - logger.notice("Cloning plugin from \(url) @ \(gitId)", metadata: .subsection) - logger.notice("\(pluginRepositoryDirectory.pathString)", metadata: .subsection) + ServiceContext.current?.logger?.notice("Cloning plugin from \(url) @ \(gitId)", metadata: .subsection) + ServiceContext.current?.logger?.notice("\(pluginRepositoryDirectory.pathString)", metadata: .subsection) try gitController.clone(url: url, to: pluginRepositoryDirectory) try gitController.checkout(id: gitId, in: pluginRepositoryDirectory) } @@ -281,7 +282,7 @@ public struct PluginService: PluginServicing { let pluginReleaseDirectory = pluginCacheDirectory.appending(component: PluginServiceConstants.release) guard try await !fileSystem.exists(pluginReleaseDirectory) else { - logger.debug("Using cached git plugin release \(url)") + ServiceContext.current?.logger?.debug("Using cached git plugin release \(url)") return } @@ -289,7 +290,7 @@ public struct PluginService: PluginServicing { guard let releaseURL = getPluginDownloadUrl(gitUrl: url, gitTag: gitTag, pluginName: plugin.name, releaseUrl: releaseUrl) else { throw PluginServiceError.invalidURL(url) } - logger.debug("Cloning plugin release from \(url) @ \(gitTag)") + ServiceContext.current?.logger?.debug("Cloning plugin release from \(url) @ \(gitTag)") try await FileHandler.shared.inTemporaryDirectory { _ in // Download the release. // Currently, we assume the release path exists. diff --git a/Sources/TuistServer/Client/ServerClientOutputWarningsMiddleware.swift b/Sources/TuistServer/Client/ServerClientOutputWarningsMiddleware.swift index 4b8b6168a8f..b9afe605934 100644 --- a/Sources/TuistServer/Client/ServerClientOutputWarningsMiddleware.swift +++ b/Sources/TuistServer/Client/ServerClientOutputWarningsMiddleware.swift @@ -1,6 +1,7 @@ import Foundation import HTTPTypes import OpenAPIRuntime +import ServiceContextModule import TuistSupport enum CloudClientOutputWarningsMiddlewareError: FatalError { @@ -57,7 +58,8 @@ struct ServerClientOutputWarningsMiddleware: ClientMiddleware { throw CloudClientOutputWarningsMiddlewareError.invalidSchema } - json.forEach { logger.warning("\($0)") } + let logger = ServiceContext.$current.get()?.logger + json.forEach { logger?.warning("\($0)") } return (response, body) } diff --git a/Sources/TuistServer/Client/ServerClientVerboseLoggingMiddleware.swift b/Sources/TuistServer/Client/ServerClientVerboseLoggingMiddleware.swift index 27bff0f42fb..9b5399e7d2c 100644 --- a/Sources/TuistServer/Client/ServerClientVerboseLoggingMiddleware.swift +++ b/Sources/TuistServer/Client/ServerClientVerboseLoggingMiddleware.swift @@ -1,6 +1,7 @@ import Foundation import HTTPTypes import OpenAPIRuntime +import ServiceContextModule import TuistSupport /// A middleware that outputs in debug mode the request and responses sent and received from the server @@ -13,7 +14,7 @@ struct ServerClientVerboseLoggingMiddleware: ClientMiddleware { next: (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?) ) async throws -> (HTTPResponse, HTTPBody?) { let (requestBodyToLog, requestBodyForNext) = try await process(body) - logger.debug(""" + ServiceContext.current?.logger?.debug(""" Sending HTTP request to Tuist: - Method: \(request.method.rawValue) - URL: \(baseURL.absoluteString) @@ -25,7 +26,7 @@ struct ServerClientVerboseLoggingMiddleware: ClientMiddleware { let (response, responseBody) = try await next(request, requestBodyForNext, baseURL) let (responseBodyToLog, responseBodyForNext) = try await process(responseBody) - logger.debug(""" + ServiceContext.current?.logger?.debug(""" Received HTTP response from Tuist: - URL: \(baseURL.absoluteString) - Path: \(request.path ?? "") diff --git a/Sources/TuistServer/Log/Logger.swift b/Sources/TuistServer/Log/Logger.swift deleted file mode 100644 index 0bee730bfa2..00000000000 --- a/Sources/TuistServer/Log/Logger.swift +++ /dev/null @@ -1,3 +0,0 @@ -import TuistSupport - -let logger = Logger(label: "io.tuist.app") diff --git a/Sources/TuistServer/Session/ServerSessionController.swift b/Sources/TuistServer/Session/ServerSessionController.swift index 2faa0001e63..371565e38c2 100644 --- a/Sources/TuistServer/Session/ServerSessionController.swift +++ b/Sources/TuistServer/Session/ServerSessionController.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistSupport /// Type of device code used for authentication. @@ -112,7 +113,7 @@ public final class ServerSessionController: ServerSessionControlling { refreshToken: tokens.refreshToken ) try await credentialsStore.store(credentials: credentials, serverURL: serverURL) - logger.notice("Credentials stored successfully", metadata: .success) + ServiceContext.current?.logger?.notice("Credentials stored successfully", metadata: .success) } public func whoami(serverURL: URL) async throws -> String? { @@ -127,7 +128,7 @@ public final class ServerSessionController: ServerSessionControlling { public func logout(serverURL: URL) async throws { try await credentialsStore.delete(serverURL: serverURL) - logger.notice("Successfully logged out.", metadata: .success) + ServiceContext.current?.logger?.notice("Successfully logged out.", metadata: .success) } private func getAuthTokens( diff --git a/Sources/TuistServer/Utilities/RetryProvider.swift b/Sources/TuistServer/Utilities/RetryProvider.swift index 6a88382d1bf..58109721c95 100644 --- a/Sources/TuistServer/Utilities/RetryProvider.swift +++ b/Sources/TuistServer/Utilities/RetryProvider.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule public protocol RetryProviding { func runWithRetries( @@ -24,7 +25,7 @@ public struct RetryProvider: RetryProviding { do { return try await operation() } catch { - logger.debug(""" + ServiceContext.current?.logger?.debug(""" The following error happened for retry \(retry): \(error.localizedDescription). Retrying... """) diff --git a/Sources/TuistServer/Utilities/ServerAuthenticationController.swift b/Sources/TuistServer/Utilities/ServerAuthenticationController.swift index 8aa0a5ddc55..484cc005dad 100644 --- a/Sources/TuistServer/Utilities/ServerAuthenticationController.swift +++ b/Sources/TuistServer/Utilities/ServerAuthenticationController.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistSupport @Mockable @@ -79,7 +80,7 @@ public final class ServerAuthenticationController: ServerAuthenticationControlli if let configToken = environment.tuistVariables[Constants.EnvironmentVariables.token] { return .project(configToken) } else if let deprecatedToken = environment.tuistVariables[Constants.EnvironmentVariables.deprecatedToken] { - logger + ServiceContext.current?.logger? .warning( "Use `TUIST_CONFIG_TOKEN` environment variable instead of `TUIST_CONFIG_CLOUD_TOKEN` to authenticate on the CI" ) @@ -100,7 +101,8 @@ public final class ServerAuthenticationController: ServerAuthenticationControlli refreshToken: try parseJWT(refreshToken) ) } else { - logger.warning("You are using a deprecated user token. Please, reauthenticate by running 'tuist auth login'.") + ServiceContext.current?.logger? + .warning("You are using a deprecated user token. Please, reauthenticate by running 'tuist auth login'.") return .user( legacyToken: $0.token, accessToken: nil, diff --git a/Sources/TuistSupport/Errors/ErrorHandler.swift b/Sources/TuistSupport/Errors/ErrorHandler.swift index 0b33f838133..193a7a5e827 100644 --- a/Sources/TuistSupport/Errors/ErrorHandler.swift +++ b/Sources/TuistSupport/Errors/ErrorHandler.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule /// Objects that conform this protocol provide a way of handling fatal errors /// that are thrown during the execution of an app. @@ -23,7 +24,7 @@ public final class ErrorHandler: ErrorHandling { public func fatal(error: FatalError) { let isSilent = error.type == .abortSilent || error.type == .bugSilent if !error.description.isEmpty, !isSilent { - logger.error( + ServiceContext.current?.logger?.error( """ \(error.description) Consider creating an issue using the following link: https://github.com/tuist/tuist/issues/new/choose @@ -34,7 +35,7 @@ public final class ErrorHandler: ErrorHandling { An unexpected error happened. We've opened an issue to fix it as soon as possible. We are sorry for any inconveniences it might have caused. """ - logger.error("\(message)") + ServiceContext.current?.logger?.error("\(message)") } } } diff --git a/Sources/TuistSupport/Logging/Logger.swift b/Sources/TuistSupport/Logging/Logger.swift index 8867589efe2..63276aa207a 100644 --- a/Sources/TuistSupport/Logging/Logger.swift +++ b/Sources/TuistSupport/Logging/Logger.swift @@ -1,7 +1,20 @@ import class Foundation.ProcessInfo @_exported import Logging +import ServiceContextModule -let logger = Logger(label: "io.tuist.support") +private enum LoggerServiceContextKey: ServiceContextKey { + typealias Value = Logger +} + +extension ServiceContext { + public var logger: Logger? { + get { + self[LoggerServiceContextKey.self] + } set { + self[LoggerServiceContextKey.self] = newValue + } + } +} public struct LoggingConfig { public init(loggerType: LoggerType, verbose: Bool) { @@ -21,6 +34,31 @@ public struct LoggingConfig { public var verbose: Bool } +extension Logger { + public static func defaultLoggerHandler(config: LoggingConfig = .default) -> (String) -> any LogHandler { + let handler: VerboseLogHandler.Type + + switch config.loggerType { + case .osLog: + handler = OSLogHandler.self + case .detailed: + handler = DetailedLogHandler.self + case .console: + handler = StandardLogHandler.self + case .json: + handler = JSONLogHandler.self + case .quiet: + return quietLogHandler + } + + if config.verbose { + return handler.verbose + } else { + return handler.init + } + } +} + extension LoggingConfig { public static var `default`: LoggingConfig { let env = ProcessInfo.processInfo.environment @@ -42,34 +80,6 @@ extension LoggingConfig { } } -public enum LogOutput { - static var environment = ProcessInfo.processInfo.environment - - public static func bootstrap(config: LoggingConfig = .default) { - let handler: VerboseLogHandler.Type - - switch config.loggerType { - case .osLog: - handler = OSLogHandler.self - case .detailed: - handler = DetailedLogHandler.self - case .console: - handler = StandardLogHandler.self - case .json: - handler = JSONLogHandler.self - case .quiet: - LoggingSystem.bootstrap(quietLogHandler) - return - } - - if config.verbose { - LoggingSystem.bootstrap(handler.verbose) - } else { - LoggingSystem.bootstrap(handler.init) - } - } -} - // A `VerboseLogHandler` allows for a LogHandler to be initialised with the `debug` logLevel. protocol VerboseLogHandler: LogHandler { static func verbose(label: String) -> LogHandler diff --git a/Sources/TuistSupport/SwiftPackageManager/SwiftPackageManagerController.swift b/Sources/TuistSupport/SwiftPackageManager/SwiftPackageManagerController.swift index 6f59091e1c3..c2a0c23257e 100644 --- a/Sources/TuistSupport/SwiftPackageManager/SwiftPackageManagerController.swift +++ b/Sources/TuistSupport/SwiftPackageManager/SwiftPackageManagerController.swift @@ -3,6 +3,7 @@ import FileSystem import Foundation import Mockable import Path +import ServiceContextModule import TSCUtility /// Protocol that defines an interface to interact with the Swift Package Manager. @@ -71,7 +72,7 @@ public struct SwiftPackageManagerController: SwiftPackageManagerControlling { self.init( system: System.shared, fileSystem: FileSystem(), - commandRunner: CommandRunner(logger: logger) + commandRunner: CommandRunner(logger: ServiceContext.$current.get()?.logger) ) } diff --git a/Sources/TuistSupport/System/System.swift b/Sources/TuistSupport/System/System.swift index c62e1a98688..bf70acdfcdd 100644 --- a/Sources/TuistSupport/System/System.swift +++ b/Sources/TuistSupport/System/System.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TSCBasic extension ProcessResult { @@ -108,13 +109,13 @@ public final class System: Systeming { loggingHandler: verbose ? { stdoutStream.send($0).send("\n").flush() } : nil ) - logger.debug("\(escaped(arguments: arguments))") + ServiceContext.current?.logger?.debug("\(escaped(arguments: arguments))") try process.launch() let result = try process.waitUntilExit() let output = try result.utf8Output() - logger.debug("\(output)") + ServiceContext.current?.logger?.debug("\(output)") try result.throwIfErrored() @@ -163,7 +164,7 @@ public final class System: Systeming { startNewProcessGroup: true ) - logger.debug("\(escaped(arguments: arguments))") + ServiceContext.current?.logger?.debug("\(escaped(arguments: arguments))") try process.launch() } @@ -205,7 +206,7 @@ public final class System: Systeming { loggingHandler: verbose ? { stdoutStream.send($0).send("\n").flush() } : nil ) - logger.debug("\(escaped(arguments: arguments))") + ServiceContext.current?.logger?.debug("\(escaped(arguments: arguments))") try process.launch() let result = try process.waitUntilExit() diff --git a/Sources/TuistSupport/UserInputReader.swift b/Sources/TuistSupport/UserInputReader.swift index 51274168383..ca1fb7bbe44 100644 --- a/Sources/TuistSupport/UserInputReader.swift +++ b/Sources/TuistSupport/UserInputReader.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule enum UserInputReaderError: FatalError, Equatable { case noValuesProvided(String) @@ -72,22 +73,22 @@ public struct UserInputReader: UserInputReading { public func readInt(asking prompt: String, maxValueAllowed: Int) -> Int { while true { - logger.notice("\(prompt)") + ServiceContext.current?.logger?.notice("\(prompt)") if let input = reader(true), !input.isEmpty, let intValue = Int(input), intValue < maxValueAllowed { return intValue } else { - logger.notice("Invalid input. Please enter a valid integer.") + ServiceContext.current?.logger?.notice("Invalid input. Please enter a valid integer.") } } } public func readString(asking prompt: String) -> String { while true { - logger.notice("\(prompt)") + ServiceContext.current?.logger?.notice("\(prompt)") if let input = reader(true), !input.isEmpty { return input } else { - logger.notice("The value is empty. Please, enter a non-empty value.") + ServiceContext.current?.logger?.notice("The value is empty. Please, enter a non-empty value.") } } } diff --git a/Sources/TuistSupportTesting/Extensions/XCTestCase+Extras.swift b/Sources/TuistSupportTesting/Extensions/XCTestCase+Extras.swift index 6c2fbfd9f0b..c463f70af0d 100644 --- a/Sources/TuistSupportTesting/Extensions/XCTestCase+Extras.swift +++ b/Sources/TuistSupportTesting/Extensions/XCTestCase+Extras.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistSupport import XCTest @@ -67,7 +68,14 @@ extension XCTestCase { } public func XCTAssertStandardOutput(pattern: String, file: StaticString = #file, line: UInt = #line) { - let standardOutput = TestingLogHandler.collected[.info, <=] + guard let testingLogHandler = ServiceContext.current?.testingLogHandler else { + return XCTFail( + "The testing log handler hasn't been set with ServiceContext.withTestingDependencies.", + file: file, + line: line + ) + } + let standardOutput = testingLogHandler.collected[.info, <=] let message = """ The standard output: @@ -83,7 +91,14 @@ extension XCTestCase { } public func XCTAssertStandardOutputNotContains(_ pattern: String, file: StaticString = #file, line: UInt = #line) { - let standardOutput = TestingLogHandler.collected[.info, <=] + guard let testingLogHandler = ServiceContext.current?.testingLogHandler else { + return XCTFail( + "The testing log handler hasn't been set with ServiceContext.withTestingDependencies.", + file: file, + line: line + ) + } + let standardOutput = testingLogHandler.collected[.info, <=] let message = """ The standard output: @@ -99,7 +114,14 @@ extension XCTestCase { } public func XCTAssertStandardError(pattern: String, file: StaticString = #file, line: UInt = #line) { - let standardError = TestingLogHandler.collected[.error, ==] + guard let testingLogHandler = ServiceContext.current?.testingLogHandler else { + return XCTFail( + "The testing log handler hasn't been set with ServiceContext.withTestingDependencies.", + file: file, + line: line + ) + } + let standardError = testingLogHandler.collected[.error, <=] let message = """ The standard error: diff --git a/Sources/TuistSupportTesting/TestCase/ServiceContext+Tests.swift b/Sources/TuistSupportTesting/TestCase/ServiceContext+Tests.swift new file mode 100644 index 00000000000..464965cbd20 --- /dev/null +++ b/Sources/TuistSupportTesting/TestCase/ServiceContext+Tests.swift @@ -0,0 +1,37 @@ +import Logging +import ServiceContextModule + +private enum TestingLogHandlerServiceContextKey: ServiceContextKey { + typealias Value = TestingLogHandler +} + +extension ServiceContext { + public var testingLogHandler: TestingLogHandler? { + get { + self[TestingLogHandlerServiceContextKey.self] + } set { + self[TestingLogHandlerServiceContextKey.self] = newValue + } + } +} + +extension ServiceContext { + /// It uses service-context, which uses task locals (from structured concurrency), to inject + /// instances of core utilities like logger to mock their behaviour for unit tests. + /// + /// - Parameters: + /// - forwardLogs: When true, it forwards the logs through the standard output and error. + /// - closure: The closure that will be executed with the task-local context set. + public static func withTestingDependencies(forwardLogs: Bool = false, _ closure: () async throws -> Void) async throws { + var context = ServiceContext.topLevel + let label = "dev.tuist.test" + let testingLogHandler = TestingLogHandler(label: label, forwardLogs: forwardLogs) + context.testingLogHandler = testingLogHandler + context.logger = Logger(label: label, factory: { _ in + return testingLogHandler + }) + try await ServiceContext.withValue(context) { + try await closure() + } + } +} diff --git a/Sources/TuistSupportTesting/TestCase/TuistTestCase.swift b/Sources/TuistSupportTesting/TestCase/TuistTestCase.swift index 4ca7d445510..23f4db46152 100644 --- a/Sources/TuistSupportTesting/TestCase/TuistTestCase.swift +++ b/Sources/TuistSupportTesting/TestCase/TuistTestCase.swift @@ -2,6 +2,7 @@ import Difference import FileSystem import Foundation import Path +import ServiceContextModule import XCTest @testable import TuistSupport @@ -106,13 +107,6 @@ public final class MockFileHandler: FileHandler { open class TuistTestCase: XCTestCase { fileprivate var temporaryDirectory: TemporaryDirectory! - override public static func setUp() { - super.setUp() - DispatchQueue.once(token: "io.tuist.test.logging") { - LoggingSystem.bootstrap(TestingLogHandler.init) - } - } - public var environment: MockEnvironment! public var fileHandler: MockFileHandler! @@ -134,7 +128,6 @@ open class TuistTestCase: XCTestCase { override open func tearDown() { temporaryDirectory = nil - TestingLogHandler.reset() super.tearDown() } @@ -220,7 +213,14 @@ open class TuistTestCase: XCTestCase { _ comparison: (Logger.Level, Logger.Level) -> Bool, file: StaticString = #file, line: UInt = #line ) { - let output = TestingLogHandler.collected[level, comparison] + guard let testingLogHandler = ServiceContext.current?.testingLogHandler else { + return XCTFail( + "The testing log handler hasn't been set with ServiceContext.withTestingDependencies.", + file: file, + line: line + ) + } + let output = testingLogHandler.collected[level, comparison] let message = """ The output: @@ -241,7 +241,14 @@ open class TuistTestCase: XCTestCase { _ comparison: (Logger.Level, Logger.Level) -> Bool, file: StaticString = #file, line: UInt = #line ) { - let output = TestingLogHandler.collected[level, comparison] + guard let testingLogHandler = ServiceContext.current?.testingLogHandler else { + return XCTFail( + "The testing log handler hasn't been set with ServiceContext.withTestingDependencies.", + file: file, + line: line + ) + } + let output = testingLogHandler.collected[level, comparison] let message = """ The output: diff --git a/Sources/TuistSupportTesting/Utils/TestingLogHandler.swift b/Sources/TuistSupportTesting/Utils/TestingLogHandler.swift index 5a9edfe16cc..7d33845ce03 100644 --- a/Sources/TuistSupportTesting/Utils/TestingLogHandler.swift +++ b/Sources/TuistSupportTesting/Utils/TestingLogHandler.swift @@ -1,32 +1,55 @@ import Foundation import TuistSupport -public struct TestingLogHandler: LogHandler { - public static var collected: [Logger.Level: [String]] { +public class TestingLogHandler: LogHandler { + public var collected: [Logger.Level: [String]] { collectionQueue.sync { collectedLogs } } - private static var collectionQueue = DispatchQueue(label: "io.tuist.tuistTestingSupport.logging") - private static var collectedLogs: [Logger.Level: [String]] = [:] + private var collectionQueue = DispatchQueue(label: "io.tuist.tuistTestingSupport.logging") + private var collectedLogs: [Logger.Level: [String]] = [:] + private let standardLogHandler: StandardLogHandler public var logLevel: Logger.Level public let label: String + public let forwardLogs: Bool - public init(label: String) { + public init(label: String, forwardLogs: Bool) { self.label = label logLevel = .trace + standardLogHandler = StandardLogHandler(label: label, logLevel: logLevel) + self.forwardLogs = forwardLogs + } + + public func flush() { + collectionQueue.async { + self.collectedLogs = [:] + } } public func log( level: Logger.Level, message: Logger.Message, - metadata _: Logger.Metadata?, - file _: String, function _: String, line _: UInt + metadata: Logger.Metadata?, + source _: String, + file: String, + function: String, + line: UInt ) { - TestingLogHandler.collectionQueue.async { - TestingLogHandler.collectedLogs[level, default: []].append(message.description) + if forwardLogs { + standardLogHandler.log( + level: level, + message: message, + metadata: metadata, + file: file, + function: function, + line: line + ) + } + collectionQueue.async { + self.collectedLogs[level, default: []].append(message.description) } } @@ -36,12 +59,6 @@ public struct TestingLogHandler: LogHandler { get { metadata[key] } set { metadata[key] = newValue } } - - public static func reset() { - TestingLogHandler.collectionQueue.async { - TestingLogHandler.collectedLogs = [:] - } - } } extension [Logger.Level: [String]] { diff --git a/Sources/tuist/TuistApp.swift b/Sources/tuist/TuistCLI.swift similarity index 60% rename from Sources/tuist/TuistApp.swift rename to Sources/tuist/TuistCLI.swift index 0aa4aaa4898..f3b4de7e77c 100644 --- a/Sources/tuist/TuistApp.swift +++ b/Sources/tuist/TuistCLI.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TSCBasic import TuistKit import TuistLoader @@ -7,14 +8,14 @@ import TuistSupport @main @_documentation(visibility: private) -private enum TuistServer { +private enum TuistCLI { static func main() async throws { if CommandLine.arguments.contains("--quiet") && CommandLine.arguments.contains("--verbose") { - throw TuistAppError.exclusiveOptionError("quiet", "verbose") + throw TuistCLIError.exclusiveOptionError("quiet", "verbose") } if CommandLine.arguments.contains("--quiet") && CommandLine.arguments.contains("--json") { - throw TuistAppError.exclusiveOptionError("quiet", "json") + throw TuistCLIError.exclusiveOptionError("quiet", "json") } if CommandLine.arguments.contains("--verbose") { @@ -26,25 +27,33 @@ private enum TuistServer { } let machineReadableCommands = [DumpCommand.self] + // swiftformat:disable all let isCommandMachineReadable = CommandLine.arguments.count > 1 && machineReadableCommands.map { $0._commandName }.contains(CommandLine.arguments[1]) // swiftformat:enable all - if isCommandMachineReadable || CommandLine.arguments.contains("--json") { - TuistSupport.LogOutput.bootstrap( - config: LoggingConfig( - loggerType: .json, - verbose: ProcessEnv.vars[Constants.EnvironmentVariables.verbose] != nil - ) + let loggingConfig = if isCommandMachineReadable || CommandLine.arguments.contains("--json") { + LoggingConfig( + loggerType: .json, + verbose: ProcessEnv.vars[Constants.EnvironmentVariables.verbose] != nil ) } else { - TuistSupport.LogOutput.bootstrap() + LoggingConfig.default } + let loggerHandler = Logger.defaultLoggerHandler(config: loggingConfig) + + /// This is the old initialization method and will eventually go away. + LoggingSystem.bootstrap(loggerHandler) - try await TuistCommand.main() + var context = ServiceContext.topLevel + context.logger = Logger(label: "dev.tuist.cli", factory: loggerHandler) + + try await ServiceContext.withValue(context) { + try await TuistCommand.main() + } } } -private enum TuistAppError: FatalError { +private enum TuistCLIError: FatalError { case exclusiveOptionError(String, String) var description: String { diff --git a/Tests/TuistCoreTests/MetadataProviders/XCFrameworkMetadataProviderTests.swift b/Tests/TuistCoreTests/MetadataProviders/XCFrameworkMetadataProviderTests.swift index a3eaaf493fc..5900ab9a967 100644 --- a/Tests/TuistCoreTests/MetadataProviders/XCFrameworkMetadataProviderTests.swift +++ b/Tests/TuistCoreTests/MetadataProviders/XCFrameworkMetadataProviderTests.swift @@ -1,4 +1,5 @@ import Path +import ServiceContextModule import XCTest @testable import TuistCore @@ -262,64 +263,66 @@ final class XCFrameworkMetadataProviderTests: TuistUnitTestCase { } func test_loadMetadata_frameworkMissingArchitecture() async throws { - // Given - let frameworkPath = fixturePath( - path: try RelativePath(validating: "MyFrameworkMissingArch.xcframework") - ) + try await ServiceContext.withTestingDependencies { + // Given + let frameworkPath = fixturePath( + path: try RelativePath(validating: "MyFrameworkMissingArch.xcframework") + ) - // When - let metadata = try await subject.loadMetadata(at: frameworkPath, status: .required) + // When + let metadata = try await subject.loadMetadata(at: frameworkPath, status: .required) - // Then - let expectedInfoPlist = XCFrameworkInfoPlist(libraries: [ - XCFrameworkInfoPlist.Library( - identifier: "ios-x86_64-simulator", // Not present on disk - path: try RelativePath(validating: "MyFrameworkMissingArch.framework"), - mergeable: false, - platform: .iOS, - architectures: [.x8664] - ), - XCFrameworkInfoPlist.Library( - identifier: "ios-arm64", - path: try RelativePath(validating: "MyFrameworkMissingArch.framework"), - mergeable: false, - platform: .iOS, - architectures: [.arm64] - ), - ]) - XCTAssertEqual( - metadata, - XCFrameworkMetadata( - path: frameworkPath, - infoPlist: expectedInfoPlist, - linking: .dynamic, - mergeable: false, - status: .required, - macroPath: nil, - swiftModules: [ - frameworkPath.appending( - components: "ios-arm64", - "MyFrameworkMissingArch.framework", - "Modules", - "MyFramework.swiftmodule" - ), - ], - moduleMaps: [ - frameworkPath.appending( - components: "ios-arm64", - "MyFrameworkMissingArch.framework", - "Modules", - "module.modulemap" - ), - ] + // Then + let expectedInfoPlist = XCFrameworkInfoPlist(libraries: [ + XCFrameworkInfoPlist.Library( + identifier: "ios-x86_64-simulator", // Not present on disk + path: try RelativePath(validating: "MyFrameworkMissingArch.framework"), + mergeable: false, + platform: .iOS, + architectures: [.x8664] + ), + XCFrameworkInfoPlist.Library( + identifier: "ios-arm64", + path: try RelativePath(validating: "MyFrameworkMissingArch.framework"), + mergeable: false, + platform: .iOS, + architectures: [.arm64] + ), + ]) + XCTAssertEqual( + metadata, + XCFrameworkMetadata( + path: frameworkPath, + infoPlist: expectedInfoPlist, + linking: .dynamic, + mergeable: false, + status: .required, + macroPath: nil, + swiftModules: [ + frameworkPath.appending( + components: "ios-arm64", + "MyFrameworkMissingArch.framework", + "Modules", + "MyFramework.swiftmodule" + ), + ], + moduleMaps: [ + frameworkPath.appending( + components: "ios-arm64", + "MyFrameworkMissingArch.framework", + "Modules", + "module.modulemap" + ), + ] + ) ) - ) - XCTAssertPrinterOutputContains( - """ - MyFrameworkMissingArch.xcframework is missing architecture ios-x86_64-simulator/MyFrameworkMissingArch.framework/MyFrameworkMissingArch defined in the Info.plist - """ - ) + XCTAssertPrinterOutputContains( + """ + MyFrameworkMissingArch.xcframework is missing architecture ios-x86_64-simulator/MyFrameworkMissingArch.framework/MyFrameworkMissingArch defined in the Info.plist + """ + ) + } } func test_loadMetadata_when_containsMacros() async throws { diff --git a/Tests/TuistDependenciesAcceptanceTests/DependenciesAcceptanceTests.swift b/Tests/TuistDependenciesAcceptanceTests/DependenciesAcceptanceTests.swift index 59fab00fd9d..e9540216134 100644 --- a/Tests/TuistDependenciesAcceptanceTests/DependenciesAcceptanceTests.swift +++ b/Tests/TuistDependenciesAcceptanceTests/DependenciesAcceptanceTests.swift @@ -1,5 +1,6 @@ import Command import Path +import ServiceContextModule import TuistAcceptanceTesting import TuistSupport import TuistSupportTesting @@ -85,17 +86,20 @@ final class DependenciesAcceptanceTestIosAppWithSPMDependenciesForceResolvedVers final class DependenciesAcceptanceTestIosAppWithSPMDependenciesWithOutdatedDependencies: TuistAcceptanceTestCase { func test() async throws { - try await setUpFixture(.iosAppWithSpmDependencies) - try await run(InstallCommand.self) - let packageResolvedPath = fixturePath.appending(components: ["Tuist", "Package.resolved"]) - let packageResolvedContents = try await fileSystem.readTextFile(at: packageResolvedPath) - try FileHandler.shared.write(packageResolvedContents + " ", path: packageResolvedPath, atomically: true) - try await run(GenerateCommand.self) - XCTAssertStandardOutput(pattern: "We detected outdated dependencies. Please run \"tuist install\" to update them.") - TestingLogHandler.reset() - try await run(InstallCommand.self) - try await run(GenerateCommand.self) - XCTAssertStandardOutputNotContains("We detected outdated dependencies. Please run \"tuist install\" to update them.") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithSpmDependencies) + try await run(InstallCommand.self) + let packageResolvedPath = fixturePath.appending(components: ["Tuist", "Package.resolved"]) + let packageResolvedContents = try await fileSystem.readTextFile(at: packageResolvedPath) + try FileHandler.shared.write(packageResolvedContents + " ", path: packageResolvedPath, atomically: true) + try await run(GenerateCommand.self) + XCTAssertStandardOutput(pattern: "We detected outdated dependencies. Please run \"tuist install\" to update them.") + + ServiceContext.current?.testingLogHandler?.flush() + try await run(InstallCommand.self) + try await run(GenerateCommand.self) + XCTAssertStandardOutputNotContains("We detected outdated dependencies. Please run \"tuist install\" to update them.") + } } } diff --git a/Tests/TuistGeneratorAcceptanceTests/GenerateAcceptanceTests.swift b/Tests/TuistGeneratorAcceptanceTests/GenerateAcceptanceTests.swift index bbfe1a7af14..eae50c25f6d 100644 --- a/Tests/TuistGeneratorAcceptanceTests/GenerateAcceptanceTests.swift +++ b/Tests/TuistGeneratorAcceptanceTests/GenerateAcceptanceTests.swift @@ -1,4 +1,5 @@ import Path +import ServiceContextModule import TuistAcceptanceTesting import TuistSupport import TuistSupportTesting @@ -396,18 +397,20 @@ final class GenerateAcceptanceTestiOSAppWithMultiConfigs: TuistAcceptanceTestCas final class GenerateAcceptanceTestiOSAppWithIncompatibleXcode: TuistAcceptanceTestCase { func test_ios_app_with_incompatible_xcode() async throws { - try await setUpFixture(.iosAppWithIncompatibleXcode) - do { - try await run(GenerateCommand.self) - XCTFail("Generate should have failed") - } catch { - XCTAssertStandardError( - pattern: "which is not compatible with this project's Xcode version requirement of 3.2.1." - ) - XCTAssertEqual( - (error as? FatalError)?.description, - "Fatal linting issues found" - ) + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithIncompatibleXcode) + do { + try await run(GenerateCommand.self) + XCTFail("Generate should have failed") + } catch { + XCTAssertStandardError( + pattern: "which is not compatible with this project's Xcode version requirement of 3.2.1." + ) + XCTAssertEqual( + (error as? FatalError)?.description, + "Fatal linting issues found" + ) + } } } } @@ -738,9 +741,11 @@ final class GenerateAcceptanceTestmacOSAppWithCopyFiles: TuistAcceptanceTestCase final class GenerateAcceptanceTestManifestWithLogs: TuistAcceptanceTestCase { func test_manifest_with_logs() async throws { - try await setUpFixture(.manifestWithLogs) - try await run(GenerateCommand.self) - XCTAssertStandardOutput(pattern: "Target name - App") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.manifestWithLogs) + try await run(GenerateCommand.self) + XCTAssertStandardOutput(pattern: "Target name - App") + } } } diff --git a/Tests/TuistGeneratorTests/ProjectMappers/SynthesizedResourceInterfaceProjectMapperTests.swift b/Tests/TuistGeneratorTests/ProjectMappers/SynthesizedResourceInterfaceProjectMapperTests.swift index e28b54581f9..6719a519c32 100644 --- a/Tests/TuistGeneratorTests/ProjectMappers/SynthesizedResourceInterfaceProjectMapperTests.swift +++ b/Tests/TuistGeneratorTests/ProjectMappers/SynthesizedResourceInterfaceProjectMapperTests.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -32,302 +33,305 @@ final class SynthesizedResourceInterfaceProjectMapperTests: TuistUnitTestCase { super.tearDown() } - func test_map() throws { - // Given - var templateStrings: [String] = [] - var parserOptionsStrings: [ResourceSynthesizer.Parser: String] = [:] - synthesizedResourceInterfacesGenerator.renderStub = { parser, parserOptions, templateString, _, _, paths in - templateStrings.append(templateString) - parserOptionsStrings[parser] = parserOptions.map { "\($0.key): \($0.value.value)" }.sorted().joined(separator: ", ") - let content = paths.map { $0.components.suffix(2).joined(separator: "/") }.joined(separator: ", ") - return content - } - - let projectPath = try temporaryPath() - let targetAPath = projectPath.appending(component: "TargetA") - let aAssets = targetAPath.appending(component: "a.xcassets") - let aAsset = aAssets.appending(component: "asset") - let frenchStrings = targetAPath.appending(components: "fr.lproj", "aStrings.strings") - let frenchStringsDict = targetAPath.appending(components: "fr.lproj", "aStrings.stringsdict") - let englishStrings = targetAPath.appending(components: "en.lproj", "aStrings.strings") - let englishStringsDict = targetAPath.appending(components: "en.lproj", "aStrings.stringsdict") - let environmentPlist = targetAPath.appending(component: "Environment.plist") - let emptyPlist = targetAPath.appending(component: "Empty.plist") - let ttfFont = targetAPath.appending(component: "ttfFont.ttf") - let otfFont = targetAPath.appending(component: "otfFont.otf") - let ttcFont = targetAPath.appending(component: "ttcFont.ttc") - let lottieFile = targetAPath.appending(component: "LottieAnimation.lottie") - let coreDataModelFolder = targetAPath.appending(component: "CoreDataModel.xcdatamodeld") - let coreDataModelVersionFile = targetAPath.appending( - components: "CoreDataModel.xcdatamodeld", - "CoreDataModel.xcdatamodel" - ) - - try fileHandler.createFolder(aAssets) - try fileHandler.touch(aAsset) - try fileHandler.touch(frenchStrings) - try fileHandler.touch(frenchStringsDict) - try fileHandler.touch(englishStrings) - try fileHandler.touch(englishStringsDict) - try fileHandler.touch(coreDataModelVersionFile) - try fileHandler.write("a", path: frenchStrings, atomically: true) - try fileHandler.write("a", path: frenchStringsDict, atomically: true) - try fileHandler.write("a", path: englishStrings, atomically: true) - try fileHandler.write("a", path: englishStringsDict, atomically: true) - try fileHandler.touch(emptyPlist) - try fileHandler.write("a", path: environmentPlist, atomically: true) - try fileHandler.write("a", path: ttfFont, atomically: true) - try fileHandler.write("a", path: otfFont, atomically: true) - try fileHandler.write("a", path: ttcFont, atomically: true) - let lottieTemplatePath = projectPath.appending(component: "Lottie.stencil") - try fileHandler.write("lottie template", path: lottieTemplatePath, atomically: true) - try fileHandler.write("a", path: lottieFile, atomically: true) - let stringsTemplatePath = projectPath.appending(component: "Strings.stencil") - try fileHandler.write("strings template", path: stringsTemplatePath, atomically: true) - let coreDataTemplatePath = projectPath.appending(component: "CoreData.stencil") - try fileHandler.write("core data template", path: coreDataTemplatePath, atomically: true) - try fileHandler.createFolder(coreDataModelFolder) - try fileHandler.write("a", path: coreDataModelVersionFile, atomically: true) + func test_map() async throws { + try await ServiceContext.withTestingDependencies { + // Given + var templateStrings: [String] = [] + var parserOptionsStrings: [ResourceSynthesizer.Parser: String] = [:] + synthesizedResourceInterfacesGenerator.renderStub = { parser, parserOptions, templateString, _, _, paths in + templateStrings.append(templateString) + parserOptionsStrings[parser] = parserOptions.map { "\($0.key): \($0.value.value)" }.sorted() + .joined(separator: ", ") + let content = paths.map { $0.components.suffix(2).joined(separator: "/") }.joined(separator: ", ") + return content + } + + let projectPath = try temporaryPath() + let targetAPath = projectPath.appending(component: "TargetA") + let aAssets = targetAPath.appending(component: "a.xcassets") + let aAsset = aAssets.appending(component: "asset") + let frenchStrings = targetAPath.appending(components: "fr.lproj", "aStrings.strings") + let frenchStringsDict = targetAPath.appending(components: "fr.lproj", "aStrings.stringsdict") + let englishStrings = targetAPath.appending(components: "en.lproj", "aStrings.strings") + let englishStringsDict = targetAPath.appending(components: "en.lproj", "aStrings.stringsdict") + let environmentPlist = targetAPath.appending(component: "Environment.plist") + let emptyPlist = targetAPath.appending(component: "Empty.plist") + let ttfFont = targetAPath.appending(component: "ttfFont.ttf") + let otfFont = targetAPath.appending(component: "otfFont.otf") + let ttcFont = targetAPath.appending(component: "ttcFont.ttc") + let lottieFile = targetAPath.appending(component: "LottieAnimation.lottie") + let coreDataModelFolder = targetAPath.appending(component: "CoreDataModel.xcdatamodeld") + let coreDataModelVersionFile = targetAPath.appending( + components: "CoreDataModel.xcdatamodeld", + "CoreDataModel.xcdatamodel" + ) - let targetA = Target.test( - name: "TargetA", - resources: .init( - [ - .folderReference(path: aAssets), - .file(path: frenchStrings), - .file(path: frenchStringsDict), - .file(path: englishStrings), - .file(path: englishStringsDict), - .file(path: emptyPlist), - .file(path: environmentPlist), - .file(path: ttfFont), - .file(path: otfFont), - .file(path: ttcFont), - .file(path: lottieFile), - ] - ), - coreDataModels: [ - CoreDataModel( - path: coreDataModelFolder, - versions: [ - coreDataModelVersionFile, - ], - currentVersion: "CoreDataModel" + try fileHandler.createFolder(aAssets) + try fileHandler.touch(aAsset) + try fileHandler.touch(frenchStrings) + try fileHandler.touch(frenchStringsDict) + try fileHandler.touch(englishStrings) + try fileHandler.touch(englishStringsDict) + try fileHandler.touch(coreDataModelVersionFile) + try fileHandler.write("a", path: frenchStrings, atomically: true) + try fileHandler.write("a", path: frenchStringsDict, atomically: true) + try fileHandler.write("a", path: englishStrings, atomically: true) + try fileHandler.write("a", path: englishStringsDict, atomically: true) + try fileHandler.touch(emptyPlist) + try fileHandler.write("a", path: environmentPlist, atomically: true) + try fileHandler.write("a", path: ttfFont, atomically: true) + try fileHandler.write("a", path: otfFont, atomically: true) + try fileHandler.write("a", path: ttcFont, atomically: true) + let lottieTemplatePath = projectPath.appending(component: "Lottie.stencil") + try fileHandler.write("lottie template", path: lottieTemplatePath, atomically: true) + try fileHandler.write("a", path: lottieFile, atomically: true) + let stringsTemplatePath = projectPath.appending(component: "Strings.stencil") + try fileHandler.write("strings template", path: stringsTemplatePath, atomically: true) + let coreDataTemplatePath = projectPath.appending(component: "CoreData.stencil") + try fileHandler.write("core data template", path: coreDataTemplatePath, atomically: true) + try fileHandler.createFolder(coreDataModelFolder) + try fileHandler.write("a", path: coreDataModelVersionFile, atomically: true) + + let targetA = Target.test( + name: "TargetA", + resources: .init( + [ + .folderReference(path: aAssets), + .file(path: frenchStrings), + .file(path: frenchStringsDict), + .file(path: englishStrings), + .file(path: englishStringsDict), + .file(path: emptyPlist), + .file(path: environmentPlist), + .file(path: ttfFont), + .file(path: otfFont), + .file(path: ttcFont), + .file(path: lottieFile), + ] ), - ] - ) - - let resourceSynthesizers: [ResourceSynthesizer] = [ - .init( - parser: .assets, - parserOptions: [ - "stringValue": "test", - "intValue": 999, - "boolValue": true, - "doubleValue": 1.0, - ], - extensions: ["xcassets"], - template: .defaultTemplate("Assets") - ), - .init( - parser: .strings, - parserOptions: [ - "stringValue": "test", - "intValue": 999, - "boolValue": true, - "doubleValue": 1.0, - ], - extensions: ["strings", "stringsdict"], - template: .file(stringsTemplatePath) - ), - .init( - parser: .plists, - parserOptions: [ - "stringValue": "test", - "intValue": 999, - "boolValue": true, - "doubleValue": 1.0, - ], - extensions: ["plist"], - template: .defaultTemplate("Plists") - ), - .init( - parser: .fonts, - parserOptions: [ - "stringValue": "test", - "intValue": 999, - "boolValue": true, - "doubleValue": 1.0, - ], - extensions: ["otf", "ttc", "ttf", "woff"], - template: .defaultTemplate("Fonts") - ), - .init( - parser: .json, - parserOptions: [ - "stringValue": "test", - "intValue": 999, - "boolValue": true, - "doubleValue": 1.0, - ], - extensions: ["lottie"], - template: .file(lottieTemplatePath) - ), - .init( - parser: .coreData, - parserOptions: [ - "stringValue": "test", - "intValue": 999, - "boolValue": true, - "doubleValue": 1.0, - ], - extensions: ["xcdatamodeld"], - template: .file(coreDataTemplatePath) - ), - ] - - let project = Project.test( - path: projectPath, - targets: [ - targetA, - ], - resourceSynthesizers: resourceSynthesizers - ) - - // When - let (mappedProject, sideEffects) = try subject.map(project: project) + coreDataModels: [ + CoreDataModel( + path: coreDataModelFolder, + versions: [ + coreDataModelVersionFile, + ], + currentVersion: "CoreDataModel" + ), + ] + ) - // Then - let derivedPath = projectPath - .appending(component: Constants.DerivedDirectory.name) - let derivedSourcesPath = derivedPath - .appending(component: Constants.DerivedDirectory.sources) - XCTAssertEqual( - sideEffects, - [ - .file( - FileDescriptor( - path: derivedSourcesPath.appending(component: "TuistAssets+TargetA.swift"), - contents: "TargetA/a.xcassets".data(using: .utf8) - ) + let resourceSynthesizers: [ResourceSynthesizer] = [ + .init( + parser: .assets, + parserOptions: [ + "stringValue": "test", + "intValue": 999, + "boolValue": true, + "doubleValue": 1.0, + ], + extensions: ["xcassets"], + template: .defaultTemplate("Assets") ), - .file( - FileDescriptor( - path: derivedSourcesPath.appending(component: "TuistStrings+TargetA.swift"), - contents: "en.lproj/aStrings.strings, en.lproj/aStrings.stringsdict" - .data(using: .utf8) - ) + .init( + parser: .strings, + parserOptions: [ + "stringValue": "test", + "intValue": 999, + "boolValue": true, + "doubleValue": 1.0, + ], + extensions: ["strings", "stringsdict"], + template: .file(stringsTemplatePath) ), - .file( - FileDescriptor( - path: derivedSourcesPath.appending(component: "TuistPlists+TargetA.swift"), - contents: "TargetA/Environment.plist".data(using: .utf8) - ) + .init( + parser: .plists, + parserOptions: [ + "stringValue": "test", + "intValue": 999, + "boolValue": true, + "doubleValue": 1.0, + ], + extensions: ["plist"], + template: .defaultTemplate("Plists") ), - .file( - FileDescriptor( - path: derivedSourcesPath.appending(component: "TuistFonts+TargetA.swift"), - contents: "TargetA/otfFont.otf, TargetA/ttcFont.ttc, TargetA/ttfFont.ttf".data(using: .utf8) - ) + .init( + parser: .fonts, + parserOptions: [ + "stringValue": "test", + "intValue": 999, + "boolValue": true, + "doubleValue": 1.0, + ], + extensions: ["otf", "ttc", "ttf", "woff"], + template: .defaultTemplate("Fonts") ), - .file( - FileDescriptor( - path: derivedSourcesPath.appending(component: "TuistLottie+TargetA.swift"), - contents: "TargetA/LottieAnimation.lottie".data(using: .utf8) - ) + .init( + parser: .json, + parserOptions: [ + "stringValue": "test", + "intValue": 999, + "boolValue": true, + "doubleValue": 1.0, + ], + extensions: ["lottie"], + template: .file(lottieTemplatePath) ), - .file( - FileDescriptor( - path: derivedSourcesPath.appending(component: "TuistCoreData+TargetA.swift"), - contents: "TargetA/CoreDataModel.xcdatamodeld".data(using: .utf8) - ) + .init( + parser: .coreData, + parserOptions: [ + "stringValue": "test", + "intValue": 999, + "boolValue": true, + "doubleValue": 1.0, + ], + extensions: ["xcdatamodeld"], + template: .file(coreDataTemplatePath) ), ] - ) - XCTAssertEqual( - mappedProject, - Project.test( + + let project = Project.test( path: projectPath, targets: [ - Target.test( - name: targetA.name, - sources: [ - SourceFile( - path: derivedSourcesPath - .appending(component: "TuistAssets+TargetA.swift"), - compilerFlags: nil, - contentHash: try contentHasher.hash("TargetA/a.xcassets".data(using: .utf8)!) - ), - SourceFile( - path: derivedSourcesPath - .appending(component: "TuistStrings+TargetA.swift"), - compilerFlags: nil, - contentHash: try contentHasher.hash( - "en.lproj/aStrings.strings, en.lproj/aStrings.stringsdict".data(using: .utf8)! - ) - ), - SourceFile( - path: derivedSourcesPath - .appending(component: "TuistPlists+TargetA.swift"), - compilerFlags: nil, - contentHash: try contentHasher.hash("TargetA/Environment.plist".data(using: .utf8)!) - ), - SourceFile( - path: derivedSourcesPath - .appending(component: "TuistFonts+TargetA.swift"), - compilerFlags: nil, - contentHash: try contentHasher - .hash("TargetA/otfFont.otf, TargetA/ttcFont.ttc, TargetA/ttfFont.ttf".data(using: .utf8)!) - ), - SourceFile( - path: derivedSourcesPath - .appending(component: "TuistLottie+TargetA.swift"), - compilerFlags: nil, - contentHash: try contentHasher.hash("TargetA/LottieAnimation.lottie".data(using: .utf8)!) - ), - SourceFile( - path: derivedSourcesPath - .appending(component: "TuistCoreData+TargetA.swift"), - compilerFlags: nil, - contentHash: try contentHasher.hash("TargetA/CoreDataModel.xcdatamodeld".data(using: .utf8)!) - ), - ], - resources: targetA.resources, - coreDataModels: targetA.coreDataModels - ), + targetA, ], resourceSynthesizers: resourceSynthesizers ) - ) - XCTAssertEqual( - templateStrings, - [ - SynthesizedResourceInterfaceTemplates.assetsTemplate, - "strings template", - SynthesizedResourceInterfaceTemplates.plistsTemplate, - SynthesizedResourceInterfaceTemplates.fontsTemplate, - "lottie template", - "core data template", - ] - ) - [ - ResourceSynthesizer.Parser.assets, - ResourceSynthesizer.Parser.strings, - ResourceSynthesizer.Parser.plists, - ResourceSynthesizer.Parser.fonts, - ResourceSynthesizer.Parser.json, - ResourceSynthesizer.Parser.coreData, - ].forEach { parser in + + // When + let (mappedProject, sideEffects) = try subject.map(project: project) + + // Then + let derivedPath = projectPath + .appending(component: Constants.DerivedDirectory.name) + let derivedSourcesPath = derivedPath + .appending(component: Constants.DerivedDirectory.sources) + XCTAssertEqual( + sideEffects, + [ + .file( + FileDescriptor( + path: derivedSourcesPath.appending(component: "TuistAssets+TargetA.swift"), + contents: "TargetA/a.xcassets".data(using: .utf8) + ) + ), + .file( + FileDescriptor( + path: derivedSourcesPath.appending(component: "TuistStrings+TargetA.swift"), + contents: "en.lproj/aStrings.strings, en.lproj/aStrings.stringsdict" + .data(using: .utf8) + ) + ), + .file( + FileDescriptor( + path: derivedSourcesPath.appending(component: "TuistPlists+TargetA.swift"), + contents: "TargetA/Environment.plist".data(using: .utf8) + ) + ), + .file( + FileDescriptor( + path: derivedSourcesPath.appending(component: "TuistFonts+TargetA.swift"), + contents: "TargetA/otfFont.otf, TargetA/ttcFont.ttc, TargetA/ttfFont.ttf".data(using: .utf8) + ) + ), + .file( + FileDescriptor( + path: derivedSourcesPath.appending(component: "TuistLottie+TargetA.swift"), + contents: "TargetA/LottieAnimation.lottie".data(using: .utf8) + ) + ), + .file( + FileDescriptor( + path: derivedSourcesPath.appending(component: "TuistCoreData+TargetA.swift"), + contents: "TargetA/CoreDataModel.xcdatamodeld".data(using: .utf8) + ) + ), + ] + ) + XCTAssertEqual( + mappedProject, + Project.test( + path: projectPath, + targets: [ + Target.test( + name: targetA.name, + sources: [ + SourceFile( + path: derivedSourcesPath + .appending(component: "TuistAssets+TargetA.swift"), + compilerFlags: nil, + contentHash: try contentHasher.hash("TargetA/a.xcassets".data(using: .utf8)!) + ), + SourceFile( + path: derivedSourcesPath + .appending(component: "TuistStrings+TargetA.swift"), + compilerFlags: nil, + contentHash: try contentHasher.hash( + "en.lproj/aStrings.strings, en.lproj/aStrings.stringsdict".data(using: .utf8)! + ) + ), + SourceFile( + path: derivedSourcesPath + .appending(component: "TuistPlists+TargetA.swift"), + compilerFlags: nil, + contentHash: try contentHasher.hash("TargetA/Environment.plist".data(using: .utf8)!) + ), + SourceFile( + path: derivedSourcesPath + .appending(component: "TuistFonts+TargetA.swift"), + compilerFlags: nil, + contentHash: try contentHasher + .hash("TargetA/otfFont.otf, TargetA/ttcFont.ttc, TargetA/ttfFont.ttf".data(using: .utf8)!) + ), + SourceFile( + path: derivedSourcesPath + .appending(component: "TuistLottie+TargetA.swift"), + compilerFlags: nil, + contentHash: try contentHasher.hash("TargetA/LottieAnimation.lottie".data(using: .utf8)!) + ), + SourceFile( + path: derivedSourcesPath + .appending(component: "TuistCoreData+TargetA.swift"), + compilerFlags: nil, + contentHash: try contentHasher.hash("TargetA/CoreDataModel.xcdatamodeld".data(using: .utf8)!) + ), + ], + resources: targetA.resources, + coreDataModels: targetA.coreDataModels + ), + ], + resourceSynthesizers: resourceSynthesizers + ) + ) XCTAssertEqual( - parserOptionsStrings[parser], - "boolValue: true, doubleValue: 1.0, intValue: 999, stringValue: test" + templateStrings, + [ + SynthesizedResourceInterfaceTemplates.assetsTemplate, + "strings template", + SynthesizedResourceInterfaceTemplates.plistsTemplate, + SynthesizedResourceInterfaceTemplates.fontsTemplate, + "lottie template", + "core data template", + ] + ) + [ + ResourceSynthesizer.Parser.assets, + ResourceSynthesizer.Parser.strings, + ResourceSynthesizer.Parser.plists, + ResourceSynthesizer.Parser.fonts, + ResourceSynthesizer.Parser.json, + ResourceSynthesizer.Parser.coreData, + ].forEach { parser in + XCTAssertEqual( + parserOptionsStrings[parser], + "boolValue: true, doubleValue: 1.0, intValue: 999, stringValue: test" + ) + } + XCTAssertPrinterContains( + "Skipping synthesizing accessors for \(emptyPlist.pathString) because its contents are empty.", + at: .warning, + == ) } - XCTAssertPrinterContains( - "Skipping synthesizing accessors for \(emptyPlist.pathString) because its contents are empty.", - at: .warning, - == - ) } func testMap_whenDisableSynthesizedResourceAccessors() throws { diff --git a/Tests/TuistKitAcceptanceTests/CacheAcceptanceTests.swift b/Tests/TuistKitAcceptanceTests/CacheAcceptanceTests.swift index 1219d929369..93b9e48d0b1 100644 --- a/Tests/TuistKitAcceptanceTests/CacheAcceptanceTests.swift +++ b/Tests/TuistKitAcceptanceTests/CacheAcceptanceTests.swift @@ -1,17 +1,20 @@ import Foundation +import ServiceContextModule import TuistAcceptanceTesting final class CacheAcceptanceTestiOSAppWithFrameworks: TuistAcceptanceTestCase { func test_ios_app_with_frameworks() async throws { - try await setUpFixture(.iosAppWithFrameworks) - try await run(CacheCommand.self, "--print-hashes") - XCTAssertStandardOutput(pattern: """ - Framework1 - f8feceb31f42a34ebcce8b80496b4933 - Framework2-iOS - 464281b69abc95f4f2824efc01f58348 - Framework2-macOS - 2e787be6f1ac74b7db40e9cedebbac1f - Framework3 - a4e947f548f5f16bd805719517eb7d47 - Framework4 - 5fbc3d8985c9ac2104b6100119ca61db - Framework5 - 05a2ec5f66ed485ced57f57d6dec507a - """) + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithFrameworks) + try await run(CacheCommand.self, "--print-hashes") + XCTAssertStandardOutput(pattern: """ + Framework1 - f8feceb31f42a34ebcce8b80496b4933 + Framework2-iOS - 464281b69abc95f4f2824efc01f58348 + Framework2-macOS - 2e787be6f1ac74b7db40e9cedebbac1f + Framework3 - a4e947f548f5f16bd805719517eb7d47 + Framework4 - 5fbc3d8985c9ac2104b6100119ca61db + Framework5 - 05a2ec5f66ed485ced57f57d6dec507a + """) + } } } diff --git a/Tests/TuistKitAcceptanceTests/InspectAcceptanceTests.swift b/Tests/TuistKitAcceptanceTests/InspectAcceptanceTests.swift index 0a19e6b96d0..58e149f9588 100644 --- a/Tests/TuistKitAcceptanceTests/InspectAcceptanceTests.swift +++ b/Tests/TuistKitAcceptanceTests/InspectAcceptanceTests.swift @@ -1,13 +1,16 @@ import Foundation +import ServiceContextModule import TuistAcceptanceTesting import XCTest @testable import TuistKit final class LintAcceptanceTests: TuistAcceptanceTestCase { func test_ios_app_with_headers() async throws { - try await setUpFixture(.iosAppWithHeaders) - try await run(InspectImplicitImportsCommand.self) - XCTAssertStandardOutput(pattern: "We did not find any implicit dependencies in your project.") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithHeaders) + try await run(InspectImplicitImportsCommand.self) + XCTAssertStandardOutput(pattern: "We did not find any implicit dependencies in your project.") + } } func test_ios_app_with_implicit_dependencies() async throws { diff --git a/Tests/TuistKitAcceptanceTests/ListTargetsAcceptanceTests.swift b/Tests/TuistKitAcceptanceTests/ListTargetsAcceptanceTests.swift index 128e026e704..67b8ffc79cb 100644 --- a/Tests/TuistKitAcceptanceTests/ListTargetsAcceptanceTests.swift +++ b/Tests/TuistKitAcceptanceTests/ListTargetsAcceptanceTests.swift @@ -1,4 +1,5 @@ import Path +import ServiceContextModule import TuistAcceptanceTesting import TuistSupport import TuistSupportTesting @@ -7,11 +8,13 @@ import XCTest final class ListTargetsAcceptanceTestiOSWorkspaceWithMicrofeatureArchitecture: TuistAcceptanceTestCase { func test_ios_workspace_with_microfeature_architecture() async throws { - try await setUpFixture(.iosWorkspaceWithMicrofeatureArchitecture) - try await run(GenerateCommand.self) - try await listTargets(for: "UIComponents") - try await listTargets(for: "Core") - try await listTargets(for: "Data") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosWorkspaceWithMicrofeatureArchitecture) + try await run(GenerateCommand.self) + try await listTargets(for: "UIComponents") + try await listTargets(for: "Core") + try await listTargets(for: "Data") + } } } diff --git a/Tests/TuistKitAcceptanceTests/ProjectAcceptanceTests.swift b/Tests/TuistKitAcceptanceTests/ProjectAcceptanceTests.swift index 932c5363852..ddc60ee90ec 100644 --- a/Tests/TuistKitAcceptanceTests/ProjectAcceptanceTests.swift +++ b/Tests/TuistKitAcceptanceTests/ProjectAcceptanceTests.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistAcceptanceTesting import TuistSupport import TuistSupportTesting @@ -9,96 +10,101 @@ import XCTest final class ProjectAcceptanceTestProjects: ServerAcceptanceTestCase { func test_list_project() async throws { - try await setUpFixture(.iosAppWithFrameworks) - try await run(ProjectListCommand.self) - XCTAssertStandardOutput(pattern: "Listing all your projects:") - XCTAssertStandardOutput(pattern: "• \(fullHandle)") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithFrameworks) + try await run(ProjectListCommand.self) + XCTAssertStandardOutput(pattern: "Listing all your projects:") + XCTAssertStandardOutput(pattern: "• \(fullHandle)") + } } } final class ProjectAcceptanceTestProjectTokens: ServerAcceptanceTestCase { func test_create_list_and_revoke_project_token() async throws { - try await setUpFixture(.iosAppWithFrameworks) - try await run(ProjectTokensCreateCommand.self, fullHandle) - TestingLogHandler.reset() - try await run(ProjectTokensListCommand.self, fullHandle) - let id = try XCTUnwrap( - TestingLogHandler.collected[.info, <=] - .components(separatedBy: .newlines) - .dropLast().last? - .components(separatedBy: .whitespaces) - .first - ) - try await run(ProjectTokensRevokeCommand.self, id, fullHandle) - TestingLogHandler.reset() - try await run(ProjectTokensListCommand.self, fullHandle) - XCTAssertStandardOutput( - pattern: "No project tokens found. Create one by running `tuist project tokens create \(fullHandle)." - ) + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithFrameworks) + try await run(ProjectTokensCreateCommand.self, fullHandle) + try await run(ProjectTokensListCommand.self, fullHandle) + let id = try XCTUnwrap( + ServiceContext.current?.testingLogHandler?.collected[.info, <=] + .components(separatedBy: .newlines) + .dropLast().last? + .components(separatedBy: .whitespaces) + .first + ) + try await run(ProjectTokensRevokeCommand.self, id, fullHandle) + try await run(ProjectTokensListCommand.self, fullHandle) + XCTAssertStandardOutput( + pattern: "No project tokens found. Create one by running `tuist project tokens create \(fullHandle)." + ) + } } } final class ProjectAcceptanceTestProjectDefaultBranch: ServerAcceptanceTestCase { func test_update_default_branch() async throws { - try await setUpFixture(.iosAppWithFrameworks) - try await run(ProjectShowCommand.self, fullHandle) - XCTAssertStandardOutput( - pattern: """ - Full handle: \(fullHandle) - Default branch: main - """ - ) - try await run(ProjectUpdateCommand.self, fullHandle, "--default-branch", "new-default-branch") - TestingLogHandler.reset() - try await run(ProjectShowCommand.self, fullHandle) - XCTAssertStandardOutput( - pattern: """ - Full handle: \(fullHandle) - Default branch: new-default-branch - """ - ) + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithFrameworks) + try await run(ProjectShowCommand.self, fullHandle) + XCTAssertStandardOutput( + pattern: """ + Full handle: \(fullHandle) + Default branch: main + """ + ) + try await run(ProjectUpdateCommand.self, fullHandle, "--default-branch", "new-default-branch") + try await run(ProjectShowCommand.self, fullHandle) + XCTAssertStandardOutput( + pattern: """ + Full handle: \(fullHandle) + Default branch: new-default-branch + """ + ) + } } } final class ProjectAcceptanceTestProjectVisibility: ServerAcceptanceTestCase { func test_update_visibility() async throws { - try await setUpFixture(.iosAppWithFrameworks) - try await run(ProjectShowCommand.self, fullHandle) - XCTAssertStandardOutput( - pattern: """ - Visibility: private - """ - ) - try await run(ProjectUpdateCommand.self, fullHandle, "--visibility", "public") - TestingLogHandler.reset() - try await run(ProjectShowCommand.self, fullHandle) - XCTAssertStandardOutput( - pattern: """ - Visibility: public - """ - ) + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithFrameworks) + try await run(ProjectShowCommand.self, fullHandle) + XCTAssertStandardOutput( + pattern: """ + Visibility: private + """ + ) + try await run(ProjectUpdateCommand.self, fullHandle, "--visibility", "public") + try await run(ProjectShowCommand.self, fullHandle) + XCTAssertStandardOutput( + pattern: """ + Visibility: public + """ + ) + } } } final class ProjectAcceptanceTestProjectRepository: ServerAcceptanceTestCase { func test_update_repository() async throws { - try await setUpFixture(.iosAppWithFrameworks) - try await run(ProjectShowCommand.self, fullHandle) - XCTAssertStandardOutput( - pattern: """ - Full handle: \(fullHandle) - Default branch: main - """ - ) - try await run(ProjectUpdateCommand.self, fullHandle, "--repository-url", "https://github.com/tuist/tuist") - TestingLogHandler.reset() - try await run(ProjectShowCommand.self, fullHandle) - XCTAssertStandardOutput( - pattern: """ - Full handle: \(fullHandle) - Repository: https://github.com/tuist/tuist - Default branch: main - """ - ) + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithFrameworks) + try await run(ProjectShowCommand.self, fullHandle) + XCTAssertStandardOutput( + pattern: """ + Full handle: \(fullHandle) + Default branch: main + """ + ) + try await run(ProjectUpdateCommand.self, fullHandle, "--repository-url", "https://github.com/tuist/tuist") + try await run(ProjectShowCommand.self, fullHandle) + XCTAssertStandardOutput( + pattern: """ + Full handle: \(fullHandle) + Repository: https://github.com/tuist/tuist + Default branch: main + """ + ) + } } } diff --git a/Tests/TuistKitAcceptanceTests/ShareAcceptanceTests.swift b/Tests/TuistKitAcceptanceTests/ShareAcceptanceTests.swift index 344b8e28116..210aaf3adb2 100644 --- a/Tests/TuistKitAcceptanceTests/ShareAcceptanceTests.swift +++ b/Tests/TuistKitAcceptanceTests/ShareAcceptanceTests.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import TuistAcceptanceTesting import TuistCore import TuistSupport @@ -10,92 +11,100 @@ import XCTest final class ShareAcceptanceTests: ServerAcceptanceTestCase { func test_share_ios_app_with_frameworks() async throws { - try await setUpFixture(.iosAppWithFrameworks) - try await run(BuildCommand.self, "App") - try await run(ShareCommand.self) - let shareLink = try previewLink() - try await run(RunCommand.self, shareLink, "-destination", "iPhone 16 Pro") - XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 16 Pro") - XCTAssertStandardOutput(pattern: "App was successfully launched 📲") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithFrameworks) + try await run(BuildCommand.self, "App") + try await run(ShareCommand.self) + let shareLink = try previewLink() + try await run(RunCommand.self, shareLink, "-destination", "iPhone 16 Pro") + XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 16 Pro") + XCTAssertStandardOutput(pattern: "App was successfully launched 📲") + } } func test_share_ios_app_with_appclip() async throws { - try await setUpFixture(.iosAppWithAppClip) - try await run(BuildCommand.self) - try await run(ShareCommand.self, "App") - let shareLink = try previewLink("App") - try await run(RunCommand.self, shareLink, "-destination", "iPhone 16") - XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 16") - XCTAssertStandardOutput(pattern: "App was successfully launched 📲") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.iosAppWithAppClip) + try await run(BuildCommand.self) + try await run(ShareCommand.self, "App") + let shareLink = try previewLink("App") + try await run(RunCommand.self, shareLink, "-destination", "iPhone 16") + XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 16") + XCTAssertStandardOutput(pattern: "App was successfully launched 📲") - try await run(ShareCommand.self, "AppClip1") - let appClipShareLink = try previewLink("AppClip1") - try await run(RunCommand.self, appClipShareLink, "-destination", "iPhone 16") - XCTAssertStandardOutput(pattern: "Installing and launching AppClip1 on iPhone 16") - XCTAssertStandardOutput(pattern: "AppClip1 was successfully launched 📲") + try await run(ShareCommand.self, "AppClip1") + let appClipShareLink = try previewLink("AppClip1") + try await run(RunCommand.self, appClipShareLink, "-destination", "iPhone 16") + XCTAssertStandardOutput(pattern: "Installing and launching AppClip1 on iPhone 16") + XCTAssertStandardOutput(pattern: "AppClip1 was successfully launched 📲") + } } func test_share_xcode_app() async throws { - try await setUpFixture(.xcodeApp) - try System.shared.runAndPrint( - [ - "/usr/bin/xcrun", - "xcodebuild", - "clean", - "build", - "-project", - fixturePath.appending(component: "App.xcodeproj").pathString, - "-scheme", - "App", - "-sdk", - "iphonesimulator", - "-derivedDataPath", - derivedDataPath.pathString, - ] - ) - try await run(ShareCommand.self, "App", "--platforms", "ios") - try await run(RunCommand.self, try previewLink(), "-destination", "iPhone 16 Plus") - XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 16 Plus") - XCTAssertStandardOutput(pattern: "App was successfully launched 📲") + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.xcodeApp) + try System.shared.runAndPrint( + [ + "/usr/bin/xcrun", + "xcodebuild", + "clean", + "build", + "-project", + fixturePath.appending(component: "App.xcodeproj").pathString, + "-scheme", + "App", + "-sdk", + "iphonesimulator", + "-derivedDataPath", + derivedDataPath.pathString, + ] + ) + try await run(ShareCommand.self, "App", "--platforms", "ios") + try await run(RunCommand.self, try previewLink(), "-destination", "iPhone 16 Plus") + XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 16 Plus") + XCTAssertStandardOutput(pattern: "App was successfully launched 📲") + } } func test_share_xcode_app_files() async throws { - try await setUpFixture(.xcodeApp) - let buildDirectory = fixturePath.appending(component: "Build") - try System.shared.runAndPrint( - [ - "/usr/bin/xcrun", - "xcodebuild", - "clean", - "build", - "-project", - fixturePath.appending(component: "App.xcodeproj").pathString, - "-scheme", - "App", - "-sdk", - "iphonesimulator", - "-derivedDataPath", - derivedDataPath.pathString, - "CONFIGURATION_BUILD_DIR=\(buildDirectory)", - ] - ) + try await ServiceContext.withTestingDependencies { + try await setUpFixture(.xcodeApp) + let buildDirectory = fixturePath.appending(component: "Build") + try System.shared.runAndPrint( + [ + "/usr/bin/xcrun", + "xcodebuild", + "clean", + "build", + "-project", + fixturePath.appending(component: "App.xcodeproj").pathString, + "-scheme", + "App", + "-sdk", + "iphonesimulator", + "-derivedDataPath", + derivedDataPath.pathString, + "CONFIGURATION_BUILD_DIR=\(buildDirectory)", + ] + ) - // Testing sharing `.app` file directly - try await run( - ShareCommand.self, - buildDirectory.appending(component: "App.app").pathString, - "--platforms", "ios" - ) - try await run(RunCommand.self, try previewLink(), "-destination", "iPhone 15 Pro Max") - XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 15 Pro Max") - XCTAssertStandardOutput(pattern: "App was successfully launched 📲") + // Testing sharing `.app` file directly + try await run( + ShareCommand.self, + buildDirectory.appending(component: "App.app").pathString, + "--platforms", "ios" + ) + try await run(RunCommand.self, try previewLink(), "-destination", "iPhone 15 Pro Max") + XCTAssertStandardOutput(pattern: "Installing and launching App on iPhone 15 Pro Max") + XCTAssertStandardOutput(pattern: "App was successfully launched 📲") + } } } extension ServerAcceptanceTestCase { fileprivate func previewLink(_ displayName: String = "App") throws -> String { try XCTUnwrap( - TestingLogHandler.collected[.notice, >=] + ServiceContext.current?.testingLogHandler?.collected[.notice, >=] .components(separatedBy: .newlines) .first(where: { $0.contains("\(displayName) uploaded – share") })? .components(separatedBy: .whitespaces) diff --git a/Tests/TuistKitIntegrationTests/Commands/DumpServiceIntegrationTests.swift b/Tests/TuistKitIntegrationTests/Commands/DumpServiceIntegrationTests.swift index 6a3a1a917a8..6675f1248c9 100644 --- a/Tests/TuistKitIntegrationTests/Commands/DumpServiceIntegrationTests.swift +++ b/Tests/TuistKitIntegrationTests/Commands/DumpServiceIntegrationTests.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Mockable import Path +import ServiceContextModule import TuistSupport import XCTest @@ -26,372 +27,386 @@ final class DumpServiceTests: TuistTestCase { } func test_prints_the_manifest_when_project_manifest() async throws { - let tmpDir = try temporaryPath() - let config = """ - import ProjectDescription - - let project = Project( - name: "tuist", - organizationName: "tuist", - settings: nil, - targets: [], - resourceSynthesizers: [] - ) - """ - try config.write( - toFile: tmpDir.appending(component: "Project.swift").pathString, - atomically: true, - encoding: .utf8 - ) - try await subject.run(path: tmpDir.pathString, manifest: .project) - let expectedStart = """ - { - "additionalFiles": [ - - ], - "name": "tuist", - "options": { - "automaticSchemesOptions": { - "enabled": { - "codeCoverageEnabled": false, - "targetSchemesGrouping": { - "byNameSuffix": { - "build": [ - """ - // middle part is ignored as order of suffixes is not predictable - let expectedEnd = """ - ] + try await ServiceContext.withTestingDependencies { + let tmpDir = try temporaryPath() + let config = """ + import ProjectDescription + + let project = Project( + name: "tuist", + organizationName: "tuist", + settings: nil, + targets: [], + resourceSynthesizers: [] + ) + """ + try config.write( + toFile: tmpDir.appending(component: "Project.swift").pathString, + atomically: true, + encoding: .utf8 + ) + try await subject.run(path: tmpDir.pathString, manifest: .project) + let expectedStart = """ + { + "additionalFiles": [ + + ], + "name": "tuist", + "options": { + "automaticSchemesOptions": { + "enabled": { + "codeCoverageEnabled": false, + "targetSchemesGrouping": { + "byNameSuffix": { + "build": [ + """ + // middle part is ignored as order of suffixes is not predictable + let expectedEnd = """ + ] + } + }, + "testingOptions": 0 } }, - "testingOptions": 0 - } - }, - "disableBundleAccessors": false, - "disableShowEnvironmentVarsInScriptPhases": false, - "disableSynthesizedResourceAccessors": false, - "textSettings": { + "disableBundleAccessors": false, + "disableShowEnvironmentVarsInScriptPhases": false, + "disableSynthesizedResourceAccessors": false, + "textSettings": { - } - }, - "organizationName": "tuist", - "packages": [ + } + }, + "organizationName": "tuist", + "packages": [ - ], - "resourceSynthesizers": [ + ], + "resourceSynthesizers": [ - ], - "schemes": [ + ], + "schemes": [ - ], - "targets": [ + ], + "targets": [ - ] - } + ] + } - """ + """ - XCTAssertPrinterOutputContains(expectedStart) - XCTAssertPrinterOutputContains(expectedEnd) + XCTAssertPrinterOutputContains(expectedStart) + XCTAssertPrinterOutputContains(expectedEnd) + } } func test_prints_the_manifest_when_workspace_manifest() async throws { - let tmpDir = try temporaryPath() - let config = """ - import ProjectDescription - - let workspace = Workspace( - name: "tuist", - projects: [], - schemes: [], - fileHeaderTemplate: nil, - additionalFiles: [] - ) - """ - try config.write( - toFile: tmpDir.appending(component: "Workspace.swift").pathString, - atomically: true, - encoding: .utf8 - ) - try await subject.run(path: tmpDir.pathString, manifest: .workspace) - let expected = """ - { - "additionalFiles": [ - - ], - "generationOptions": { - "autogeneratedWorkspaceSchemes": { - "enabled": { - "codeCoverageMode": { - "disabled": { + try await ServiceContext.withTestingDependencies { + let tmpDir = try temporaryPath() + let config = """ + import ProjectDescription + + let workspace = Workspace( + name: "tuist", + projects: [], + schemes: [], + fileHeaderTemplate: nil, + additionalFiles: [] + ) + """ + try config.write( + toFile: tmpDir.appending(component: "Workspace.swift").pathString, + atomically: true, + encoding: .utf8 + ) + try await subject.run(path: tmpDir.pathString, manifest: .workspace) + let expected = """ + { + "additionalFiles": [ + ], + "generationOptions": { + "autogeneratedWorkspaceSchemes": { + "enabled": { + "codeCoverageMode": { + "disabled": { + + } + }, + "testingOptions": 0 } }, - "testingOptions": 0 - } - }, - "enableAutomaticXcodeSchemes": false, - "renderMarkdownReadme": false - }, - "name": "tuist", - "projects": [ - - ], - "schemes": [ - - ] - } + "enableAutomaticXcodeSchemes": false, + "renderMarkdownReadme": false + }, + "name": "tuist", + "projects": [ + + ], + "schemes": [ + + ] + } - """ + """ - XCTAssertPrinterOutputContains(expected) + XCTAssertPrinterOutputContains(expected) + } } func test_prints_the_manifest_when_config_manifest() async throws { - let tmpDir = try temporaryPath() - let config = """ - import ProjectDescription - - let config = Config( - compatibleXcodeVersions: .all, - fullHandle: "tuist/tuist", - swiftVersion: nil, - plugins: [], - generationOptions: .options(), - installOptions: .options( - passthroughSwiftPackageManagerArguments: [ - "--replace-scm-with-registry" - ] + try await ServiceContext.withTestingDependencies { + let tmpDir = try temporaryPath() + let config = """ + import ProjectDescription + + let config = Config( + compatibleXcodeVersions: .all, + fullHandle: "tuist/tuist", + swiftVersion: nil, + plugins: [], + generationOptions: .options(), + installOptions: .options( + passthroughSwiftPackageManagerArguments: [ + "--replace-scm-with-registry" + ] + ) ) - ) - """ - try config.write( - toFile: tmpDir.appending(components: "Tuist.swift").pathString, - atomically: true, - encoding: .utf8 - ) - try await subject.run(path: tmpDir.pathString, manifest: .config) - let expected = """ - { - "fullHandle": "tuist/tuist", - "project": { - "tuist": { - "compatibleXcodeVersions": { - "all": { - - } - }, - "generationOptions": { - "disablePackageVersionLocking": false, - "enforceExplicitDependencies": false, - "optionalAuthentication": false, - "resolveDependenciesWithSystemScm": false, - "staticSideEffectsWarningTargets": { - "all": { + """ + try config.write( + toFile: tmpDir.appending(components: "Tuist.swift").pathString, + atomically: true, + encoding: .utf8 + ) + try await subject.run(path: tmpDir.pathString, manifest: .config) + let expected = """ + { + "fullHandle": "tuist/tuist", + "project": { + "tuist": { + "compatibleXcodeVersions": { + "all": { + + } + }, + "generationOptions": { + "disablePackageVersionLocking": false, + "enforceExplicitDependencies": false, + "optionalAuthentication": false, + "resolveDependenciesWithSystemScm": false, + "staticSideEffectsWarningTargets": { + "all": { + + } + } + }, + "installOptions": { + "passthroughSwiftPackageManagerArguments": [ + "--replace-scm-with-registry" + ] + }, + "plugins": [ - } + ] } }, - "installOptions": { - "passthroughSwiftPackageManagerArguments": [ - "--replace-scm-with-registry" - ] - }, - "plugins": [ - - ] + "url": "https://tuist.dev" } - }, - "url": "https://tuist.dev" - } - """ + """ - XCTAssertPrinterOutputContains(expected) + XCTAssertPrinterOutputContains(expected) + } } func test_prints_the_manifest_when_template_manifest() async throws { - let tmpDir = try temporaryPath() - let config = """ - import ProjectDescription - - let template = Template( - description: "tuist", - attributes: [], - items: [] - ) - """ - try config.write( - toFile: tmpDir.appending(component: "\(tmpDir.basenameWithoutExt).swift").pathString, - atomically: true, - encoding: .utf8 - ) - try await subject.run(path: tmpDir.pathString, manifest: .template) - let expected = """ - { - "attributes": [ - - ], - "description": "tuist", - "items": [ - - ] - } + try await ServiceContext.withTestingDependencies { + let tmpDir = try temporaryPath() + let config = """ + import ProjectDescription + + let template = Template( + description: "tuist", + attributes: [], + items: [] + ) + """ + try config.write( + toFile: tmpDir.appending(component: "\(tmpDir.basenameWithoutExt).swift").pathString, + atomically: true, + encoding: .utf8 + ) + try await subject.run(path: tmpDir.pathString, manifest: .template) + let expected = """ + { + "attributes": [ + + ], + "description": "tuist", + "items": [ - """ + ] + } - XCTAssertPrinterOutputContains(expected) + """ + + XCTAssertPrinterOutputContains(expected) + } } func test_prints_the_manifest_when_plugin_manifest() async throws { - let tmpDir = try temporaryPath() - let config = """ - import ProjectDescription - - let plugin = Plugin( - name: "tuist" - ) - """ - try config.write( - toFile: tmpDir.appending(component: "Plugin.swift").pathString, - atomically: true, - encoding: .utf8 - ) - try await subject.run(path: tmpDir.pathString, manifest: .plugin) - let expected = """ - { - "name": "tuist" - } + try await ServiceContext.withTestingDependencies { + let tmpDir = try temporaryPath() + let config = """ + import ProjectDescription - """ + let plugin = Plugin( + name: "tuist" + ) + """ + try config.write( + toFile: tmpDir.appending(component: "Plugin.swift").pathString, + atomically: true, + encoding: .utf8 + ) + try await subject.run(path: tmpDir.pathString, manifest: .plugin) + let expected = """ + { + "name": "tuist" + } + + """ - XCTAssertPrinterOutputContains(expected) + XCTAssertPrinterOutputContains(expected) + } } func test_prints_the_manifest_when_package_manifest() async throws { - let tmpDir = try temporaryPath() - let config = """ - // swift-tools-version: 5.9 - import PackageDescription - - #if TUIST - import ProjectDescription - - let packageSettings = PackageSettings( - targetSettings: ["TargetA": ["OTHER_LDFLAGS": "-ObjC"]] - ) - - #endif - - let package = Package( - name: "PackageName", - dependencies: [] - ) - - """ - try fileHandler.createFolder(tmpDir.appending(component: Constants.tuistDirectoryName)) - try config.write( - toFile: tmpDir.appending( - component: Constants.SwiftPackageManager.packageSwiftName - ).pathString, - atomically: true, - encoding: .utf8 - ) - try await subject.run(path: tmpDir.pathString, manifest: .package) - let expected = """ - { - "baseSettings": { - "base": { - - }, - "configurations": [ - { - "name": { - "rawValue": "Debug" - }, - "settings": { + try await ServiceContext.withTestingDependencies { + let tmpDir = try temporaryPath() + let config = """ + // swift-tools-version: 5.9 + import PackageDescription - }, - "variant": "debug" - }, - { - "name": { - "rawValue": "Release" - }, - "settings": { + #if TUIST + import ProjectDescription + + let packageSettings = PackageSettings( + targetSettings: ["TargetA": ["OTHER_LDFLAGS": "-ObjC"]] + ) + + #endif + + let package = Package( + name: "PackageName", + dependencies: [] + ) + + """ + try fileHandler.createFolder(tmpDir.appending(component: Constants.tuistDirectoryName)) + try config.write( + toFile: tmpDir.appending( + component: Constants.SwiftPackageManager.packageSwiftName + ).pathString, + atomically: true, + encoding: .utf8 + ) + try await subject.run(path: tmpDir.pathString, manifest: .package) + let expected = """ + { + "baseSettings": { + "base": { }, - "variant": "release" - } - ], - "defaultSettings": { - "recommended": { - "excluding": [ - - ] - } - } - }, - """ + "configurations": [ + { + "name": { + "rawValue": "Debug" + }, + "settings": { + + }, + "variant": "debug" + }, + { + "name": { + "rawValue": "Release" + }, + "settings": { + + }, + "variant": "release" + } + ], + "defaultSettings": { + "recommended": { + "excluding": [ - XCTAssertPrinterOutputContains(expected) + ] + } + } + }, + """ + + XCTAssertPrinterOutputContains(expected) + } } func test_prints_the_manifest_when_package_manifest_without_package_settings() async throws { - let tmpDir = try temporaryPath() - let config = """ - // swift-tools-version: 5.9 - import PackageDescription - - let package = Package( - name: "PackageName", - dependencies: [] - ) - - """ - try await fileSystem.makeDirectory(at: tmpDir.appending(component: Constants.tuistDirectoryName)) - try await fileSystem.writeText( - config, - at: tmpDir.appending( - component: Constants.SwiftPackageManager.packageSwiftName + try await ServiceContext.withTestingDependencies { + let tmpDir = try temporaryPath() + let config = """ + // swift-tools-version: 5.9 + import PackageDescription + + let package = Package( + name: "PackageName", + dependencies: [] ) - ) - try await subject.run(path: tmpDir.pathString, manifest: .package) - let expected = """ - { - "baseSettings": { - "base": { - - }, - "configurations": [ - { - "name": { - "rawValue": "Debug" - }, - "settings": { - }, - "variant": "debug" - }, - { - "name": { - "rawValue": "Release" - }, - "settings": { + """ + try await fileSystem.makeDirectory(at: tmpDir.appending(component: Constants.tuistDirectoryName)) + try await fileSystem.writeText( + config, + at: tmpDir.appending( + component: Constants.SwiftPackageManager.packageSwiftName + ) + ) + try await subject.run(path: tmpDir.pathString, manifest: .package) + let expected = """ + { + "baseSettings": { + "base": { }, - "variant": "release" - } - ], - "defaultSettings": { - "recommended": { - "excluding": [ - - ] - } - } - }, - """ + "configurations": [ + { + "name": { + "rawValue": "Debug" + }, + "settings": { + + }, + "variant": "debug" + }, + { + "name": { + "rawValue": "Release" + }, + "settings": { + + }, + "variant": "release" + } + ], + "defaultSettings": { + "recommended": { + "excluding": [ - XCTAssertPrinterOutputContains(expected) + ] + } + } + }, + """ + + XCTAssertPrinterOutputContains(expected) + } } func test_run_throws_when_project_and_file_doesnt_exist() async throws { diff --git a/Tests/TuistKitTests/Services/BuildServiceTests.swift b/Tests/TuistKitTests/Services/BuildServiceTests.swift index b305b58a286..1336fc61bba 100644 --- a/Tests/TuistKitTests/Services/BuildServiceTests.swift +++ b/Tests/TuistKitTests/Services/BuildServiceTests.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TSCUtility import TuistAutomation import TuistCore @@ -299,34 +300,36 @@ final class BuildServiceTests: TuistUnitTestCase { } func test_run_lists_schemes() async throws { - // Given - let path = try temporaryPath() - let workspacePath = path.appending(component: "App.xcworkspace") - let graph = Graph.test() - let schemeA = Scheme.test(name: "A") - let schemeB = Scheme.test(name: "B") - given(generator) - .load(path: .value(path)) - .willReturn(graph) - given(buildGraphInspector) - .workspacePath(directory: .value(path)) - .willReturn(workspacePath) - given(buildGraphInspector) - .buildableSchemes(graphTraverser: .any) - .willReturn( - [ - schemeA, - schemeB, - ] - ) + try await ServiceContext.withTestingDependencies { + // Given + let path = try temporaryPath() + let workspacePath = path.appending(component: "App.xcworkspace") + let graph = Graph.test() + let schemeA = Scheme.test(name: "A") + let schemeB = Scheme.test(name: "B") + given(generator) + .load(path: .value(path)) + .willReturn(graph) + given(buildGraphInspector) + .workspacePath(directory: .value(path)) + .willReturn(workspacePath) + given(buildGraphInspector) + .buildableSchemes(graphTraverser: .any) + .willReturn( + [ + schemeA, + schemeB, + ] + ) - // When - try await subject.testRun( - path: path - ) + // When + try await subject.testRun( + path: path + ) - // Then - XCTAssertPrinterContains("Found the following buildable schemes: A, B", at: .debug, ==) + // Then + XCTAssertPrinterContains("Found the following buildable schemes: A, B", at: .debug, ==) + } } } diff --git a/Tests/TuistKitTests/Services/Cache/CachePrintHashesServiceTests.swift b/Tests/TuistKitTests/Services/Cache/CachePrintHashesServiceTests.swift index 73d65f78824..551d5ee1097 100644 --- a/Tests/TuistKitTests/Services/Cache/CachePrintHashesServiceTests.swift +++ b/Tests/TuistKitTests/Services/Cache/CachePrintHashesServiceTests.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistCache import TuistCore import TuistLoader @@ -172,30 +173,32 @@ final class CachePrintHashesServiceTests: TuistUnitTestCase { } func test_run_outputs_correct_hashes() async throws { - // Given - let target1 = GraphTarget.test(target: .test(name: "ShakiOne")) - let target2 = GraphTarget.test(target: .test(name: "ShakiTwo")) - given(cacheGraphContentHasher) - .contentHashes(for: .any, configuration: .any, config: .any, excludedTargets: .any) - .willReturn([target1: "hash1", target2: "hash2"]) - - given(generator) - .load(path: .any) - .willReturn(.test()) - - subject = CachePrintHashesService( - generatorFactory: generatorFactory, - cacheGraphContentHasher: cacheGraphContentHasher, - clock: clock, - configLoader: configLoader - ) - - // When - _ = try await subject.run(path: path, configuration: nil) - - // Then - XCTAssertPrinterOutputContains("ShakiOne - hash1") - XCTAssertPrinterOutputContains("ShakiTwo - hash2") + try await ServiceContext.withTestingDependencies { + // Given + let target1 = GraphTarget.test(target: .test(name: "ShakiOne")) + let target2 = GraphTarget.test(target: .test(name: "ShakiTwo")) + given(cacheGraphContentHasher) + .contentHashes(for: .any, configuration: .any, config: .any, excludedTargets: .any) + .willReturn([target1: "hash1", target2: "hash2"]) + + given(generator) + .load(path: .any) + .willReturn(.test()) + + subject = CachePrintHashesService( + generatorFactory: generatorFactory, + cacheGraphContentHasher: cacheGraphContentHasher, + clock: clock, + configLoader: configLoader + ) + + // When + _ = try await subject.run(path: path, configuration: nil) + + // Then + XCTAssertPrinterOutputContains("ShakiOne - hash1") + XCTAssertPrinterOutputContains("ShakiTwo - hash2") + } } func test_run_gives_correct_configuration_type_to_hasher() async throws { diff --git a/Tests/TuistKitTests/Services/CleanServiceTests.swift b/Tests/TuistKitTests/Services/CleanServiceTests.swift index f9f734b334b..6528d4495b5 100644 --- a/Tests/TuistKitTests/Services/CleanServiceTests.swift +++ b/Tests/TuistKitTests/Services/CleanServiceTests.swift @@ -2,6 +2,7 @@ import FileSystem import Foundation import Mockable import Path +import ServiceContextModule import TuistCore import TuistCoreTesting import TuistLoader @@ -191,52 +192,54 @@ final class CleanServiceTests: TuistUnitTestCase { } func test_run_with_remote() async throws { - // Given - let url = URL(string: "https://cloud.com")! - - given(configLoader) - .loadConfig(path: .any) - .willReturn( - Config.test( - fullHandle: "tuist/tuist", - url: url + try await ServiceContext.withTestingDependencies { + // Given + let url = URL(string: "https://cloud.com")! + + given(configLoader) + .loadConfig(path: .any) + .willReturn( + Config.test( + fullHandle: "tuist/tuist", + url: url + ) ) - ) - given(serverURLService) - .url(configServerURL: .any) - .willReturn(url) + given(serverURLService) + .url(configServerURL: .any) + .willReturn(url) - given(cleanCacheService) - .cleanCache( - serverURL: .value(url), - fullHandle: .value("tuist/tuist") + given(cleanCacheService) + .cleanCache( + serverURL: .value(url), + fullHandle: .value("tuist/tuist") + ) + .willReturn(()) + + given(cacheDirectoriesProvider) + .cacheDirectory(for: .any) + .willReturn(try temporaryPath()) + + let projectPath = try temporaryPath() + given(rootDirectoryLocator) + .locate(from: .any) + .willReturn(projectPath) + given(manifestFilesLocator) + .locatePackageManifest(at: .any) + .willReturn(nil) + + // When + try await subject.run( + categories: TuistCleanCategory.allCases, + remote: true, + path: nil ) - .willReturn(()) - - given(cacheDirectoriesProvider) - .cacheDirectory(for: .any) - .willReturn(try temporaryPath()) - let projectPath = try temporaryPath() - given(rootDirectoryLocator) - .locate(from: .any) - .willReturn(projectPath) - given(manifestFilesLocator) - .locatePackageManifest(at: .any) - .willReturn(nil) - - // When - try await subject.run( - categories: TuistCleanCategory.allCases, - remote: true, - path: nil - ) - - // Then - verify(cleanCacheService) - .cleanCache(serverURL: .any, fullHandle: .any) - .called(1) - XCTAssertStandardOutput(pattern: "Successfully cleaned the remote storage.") + // Then + verify(cleanCacheService) + .cleanCache(serverURL: .any, fullHandle: .any) + .called(1) + XCTAssertStandardOutput(pattern: "Successfully cleaned the remote storage.") + } } } diff --git a/Tests/TuistKitTests/Services/GenerateServiceTests.swift b/Tests/TuistKitTests/Services/GenerateServiceTests.swift index 527f20b2234..7d787922823 100644 --- a/Tests/TuistKitTests/Services/GenerateServiceTests.swift +++ b/Tests/TuistKitTests/Services/GenerateServiceTests.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistCache import TuistCore import TuistLoader @@ -144,32 +145,34 @@ final class GenerateServiceTests: TuistUnitTestCase { } func test_run_timeIsPrinted() async throws { - // Given - let workspacePath = try AbsolutePath(validating: "/test.xcworkspace") + try await ServiceContext.withTestingDependencies { + // Given + let workspacePath = try AbsolutePath(validating: "/test.xcworkspace") - given(opener) - .open(path: .any) - .willReturn() + given(opener) + .open(path: .any) + .willReturn() - given(generator) - .generateWithGraph(path: .any) - .willReturn((workspacePath, .test(), MapperEnvironment())) - clock.assertOnUnexpectedCalls = true - clock.primedTimers = [ - 0.234, - ] + given(generator) + .generateWithGraph(path: .any) + .willReturn((workspacePath, .test(), MapperEnvironment())) + clock.assertOnUnexpectedCalls = true + clock.primedTimers = [ + 0.234, + ] - // When - try await subject.run( - path: nil, - sources: [], - noOpen: false, - configuration: nil, - ignoreBinaryCache: false, - analyticsDelegate: analyticsDelegate - ) + // When + try await subject.run( + path: nil, + sources: [], + noOpen: false, + configuration: nil, + ignoreBinaryCache: false, + analyticsDelegate: analyticsDelegate + ) - // Then - XCTAssertPrinterOutputContains("Total time taken: 0.234s") + // Then + XCTAssertPrinterOutputContains("Total time taken: 0.234s") + } } } diff --git a/Tests/TuistKitTests/Services/GraphServiceTests.swift b/Tests/TuistKitTests/Services/GraphServiceTests.swift index 8d662ddac35..547ef6295c4 100644 --- a/Tests/TuistKitTests/Services/GraphServiceTests.swift +++ b/Tests/TuistKitTests/Services/GraphServiceTests.swift @@ -4,6 +4,7 @@ import GraphViz import Mockable import Path import ProjectAutomation +import ServiceContextModule import TuistCore import TuistPlugin import TuistSupport @@ -40,74 +41,78 @@ final class GraphServiceTests: TuistUnitTestCase { } func test_run_whenDot() async throws { - // Given - let temporaryPath = try temporaryPath() - let graphPath = temporaryPath.appending(component: "graph.dot") - let projectManifestPath = temporaryPath.appending(component: "Project.swift") + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let graphPath = temporaryPath.appending(component: "graph.dot") + let projectManifestPath = temporaryPath.appending(component: "Project.swift") - try FileHandler.shared.touch(graphPath) - try FileHandler.shared.touch(projectManifestPath) - graphVizMapper.stubMap = Graph() + try FileHandler.shared.touch(graphPath) + try FileHandler.shared.touch(projectManifestPath) + graphVizMapper.stubMap = Graph() - given(manifestGraphLoader) - .load(path: .any) - .willReturn((.test(), [], MapperEnvironment(), [])) + given(manifestGraphLoader) + .load(path: .any) + .willReturn((.test(), [], MapperEnvironment(), [])) - // When - try await subject.run( - format: .dot, - layoutAlgorithm: .dot, - skipTestTargets: false, - skipExternalDependencies: false, - open: false, - platformToFilter: nil, - targetsToFilter: [], - path: temporaryPath, - outputPath: temporaryPath - ) - let got = try FileHandler.shared.readTextFile(graphPath) - let expected = "graph { }" - // Then - XCTAssertEqual(got, expected) - XCTAssertPrinterOutputContains(""" - Deleting existing graph at \(graphPath.pathString) - Graph exported to \(graphPath.pathString) - """) + // When + try await subject.run( + format: .dot, + layoutAlgorithm: .dot, + skipTestTargets: false, + skipExternalDependencies: false, + open: false, + platformToFilter: nil, + targetsToFilter: [], + path: temporaryPath, + outputPath: temporaryPath + ) + let got = try FileHandler.shared.readTextFile(graphPath) + let expected = "graph { }" + // Then + XCTAssertEqual(got, expected) + XCTAssertPrinterOutputContains(""" + Deleting existing graph at \(graphPath.pathString) + Graph exported to \(graphPath.pathString) + """) + } } func test_run_whenJson() async throws { - // Given - let temporaryPath = try temporaryPath() - let graphPath = temporaryPath.appending(component: "graph.json") - let projectManifestPath = temporaryPath.appending(component: "Project.swift") + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let graphPath = temporaryPath.appending(component: "graph.json") + let projectManifestPath = temporaryPath.appending(component: "Project.swift") - try FileHandler.shared.touch(graphPath) - try FileHandler.shared.touch(projectManifestPath) + try FileHandler.shared.touch(graphPath) + try FileHandler.shared.touch(projectManifestPath) - given(manifestGraphLoader) - .load(path: .any) - .willReturn((.test(), [], MapperEnvironment(), [])) + given(manifestGraphLoader) + .load(path: .any) + .willReturn((.test(), [], MapperEnvironment(), [])) - // When - try await subject.run( - format: .json, - layoutAlgorithm: .dot, - skipTestTargets: false, - skipExternalDependencies: false, - open: false, - platformToFilter: nil, - targetsToFilter: [], - path: temporaryPath, - outputPath: temporaryPath - ) - let got = try FileHandler.shared.readTextFile(graphPath) + // When + try await subject.run( + format: .json, + layoutAlgorithm: .dot, + skipTestTargets: false, + skipExternalDependencies: false, + open: false, + platformToFilter: nil, + targetsToFilter: [], + path: temporaryPath, + outputPath: temporaryPath + ) + let got = try FileHandler.shared.readTextFile(graphPath) - let result = try JSONDecoder().decode(ProjectAutomation.Graph.self, from: got.data(using: .utf8)!) - // Then - XCTAssertEqual(result, ProjectAutomation.Graph(name: "graph", path: "/", projects: [:])) - XCTAssertPrinterOutputContains(""" - Deleting existing graph at \(graphPath.pathString) - Graph exported to \(graphPath.pathString) - """) + let result = try JSONDecoder().decode(ProjectAutomation.Graph.self, from: got.data(using: .utf8)!) + // Then + XCTAssertEqual(result, ProjectAutomation.Graph(name: "graph", path: "/", projects: [:])) + XCTAssertPrinterOutputContains(""" + Deleting existing graph at \(graphPath.pathString) + Graph exported to \(graphPath.pathString) + """) + } } } diff --git a/Tests/TuistKitTests/Services/ListServiceTests.swift b/Tests/TuistKitTests/Services/ListServiceTests.swift index 177c2e3f2bf..a0dd4afab02 100644 --- a/Tests/TuistKitTests/Services/ListServiceTests.swift +++ b/Tests/TuistKitTests/Services/ListServiceTests.swift @@ -1,5 +1,6 @@ import Mockable import Path +import ServiceContextModule import TuistCore import TuistLoader import TuistLoaderTesting @@ -38,95 +39,101 @@ final class ListServiceTests: TuistUnitTestCase { } func test_lists_available_templates_table_format() async throws { - // Given - let expectedTemplates = ["template", "customTemplate"] - let expectedOutput = """ - Name Description - ────────────── ─────────── - template description - customTemplate description - """ - - given(templatesDirectoryLocator) - .templateDirectories(at: .any) - .willReturn(try expectedTemplates.map(temporaryPath().appending)) - - given(templateLoader) - .loadTemplate(at: .any, plugins: .any) - .willReturn( - Template(description: "description", items: []) - ) - - // When - try await subject.run(path: nil, outputFormat: .table) - - // Then - XCTAssertPrinterContains(expectedOutput, at: .notice, ==) + try await ServiceContext.withTestingDependencies { + // Given + let expectedTemplates = ["template", "customTemplate"] + let expectedOutput = """ + Name Description + ────────────── ─────────── + template description + customTemplate description + """ + + given(templatesDirectoryLocator) + .templateDirectories(at: .any) + .willReturn(try expectedTemplates.map(temporaryPath().appending)) + + given(templateLoader) + .loadTemplate(at: .any, plugins: .any) + .willReturn( + Template(description: "description", items: []) + ) + + // When + try await subject.run(path: nil, outputFormat: .table) + + // Then + XCTAssertPrinterContains(expectedOutput, at: .notice, ==) + } } func test_lists_available_templates_json_format() async throws { - // Given - let expectedTemplates = ["template", "customTemplate"] - let expectedOutput = """ - [ - { - "description": "description", - "name": "template" - }, - { - "description": "description", - "name": "customTemplate" - } - ] - """ - - given(templatesDirectoryLocator) - .templateDirectories(at: .any) - .willReturn(try expectedTemplates.map(temporaryPath().appending)) - - given(templateLoader) - .loadTemplate(at: .any, plugins: .any) - .willReturn( - Template(description: "description", items: []) - ) - - // When - try await subject.run(path: nil, outputFormat: .json) - - // Then - XCTAssertPrinterContains(expectedOutput, at: .notice, ==) + try await ServiceContext.withTestingDependencies { + // Given + let expectedTemplates = ["template", "customTemplate"] + let expectedOutput = """ + [ + { + "description": "description", + "name": "template" + }, + { + "description": "description", + "name": "customTemplate" + } + ] + """ + + given(templatesDirectoryLocator) + .templateDirectories(at: .any) + .willReturn(try expectedTemplates.map(temporaryPath().appending)) + + given(templateLoader) + .loadTemplate(at: .any, plugins: .any) + .willReturn( + Template(description: "description", items: []) + ) + + // When + try await subject.run(path: nil, outputFormat: .json) + + // Then + XCTAssertPrinterContains(expectedOutput, at: .notice, ==) + } } func test_lists_available_templates_with_plugins() async throws { - // Given - let expectedTemplates = ["template", "customTemplate", "pluginTemplate"] - let expectedOutput = """ - Name Description - ────────────── ─────────── - template description - customTemplate description - pluginTemplate description - """ - - let pluginTemplatePath = try temporaryPath().appending(component: "PluginTemplate") - pluginService.loadPluginsStub = { _ in - Plugins.test(templatePaths: [pluginTemplatePath]) + try await ServiceContext.withTestingDependencies { + // Given + let expectedTemplates = ["template", "customTemplate", "pluginTemplate"] + let expectedOutput = """ + Name Description + ────────────── ─────────── + template description + customTemplate description + pluginTemplate description + """ + + let pluginTemplatePath = try temporaryPath().appending(component: "PluginTemplate") + pluginService.loadPluginsStub = { _ in + Plugins.test(templatePaths: [pluginTemplatePath]) + } + + given(templatesDirectoryLocator) + .templateDirectories(at: .any) + .willReturn(try expectedTemplates.map(temporaryPath().appending)) + + given(templateLoader) + .loadTemplate(at: .any, plugins: .any) + .willReturn( + Template(description: "description", items: []) + ) + + // When + try await subject.run(path: nil, outputFormat: .table) + + // Then + XCTAssertPrinterContains(expectedOutput, at: .notice, ==) } - - given(templatesDirectoryLocator) - .templateDirectories(at: .any) - .willReturn(try expectedTemplates.map(temporaryPath().appending)) - - given(templateLoader) - .loadTemplate(at: .any, plugins: .any) - .willReturn( - Template(description: "description", items: []) - ) - - // When - try await subject.run(path: nil, outputFormat: .table) - - // Then - XCTAssertPrinterContains(expectedOutput, at: .notice, ==) } } diff --git a/Tests/TuistKitTests/Services/LoginServiceTests.swift b/Tests/TuistKitTests/Services/LoginServiceTests.swift index 4954d320e10..c6a262cbb6b 100644 --- a/Tests/TuistKitTests/Services/LoginServiceTests.swift +++ b/Tests/TuistKitTests/Services/LoginServiceTests.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistCore import TuistCoreTesting import TuistLoader @@ -81,130 +82,136 @@ final class LoginServiceTests: TuistUnitTestCase { } func test_authenticate_when_password_is_provided() async throws { - // Given - given(userInputReader) - .readString(asking: .value("Email:")) - .willReturn("email@tuist.io") - - given(serverCredentialsStore) - .store( - credentials: .value( - ServerCredentials( - token: nil, + try await ServiceContext.withTestingDependencies { + // Given + given(userInputReader) + .readString(asking: .value("Email:")) + .willReturn("email@tuist.io") + + given(serverCredentialsStore) + .store( + credentials: .value( + ServerCredentials( + token: nil, + accessToken: "access-token", + refreshToken: "refresh-token" + ) + ), + serverURL: .any + ) + .willReturn() + + given(authenticateService) + .authenticate( + email: .value("email@tuist.io"), + password: .value("password"), + serverURL: .value(serverURL) + ) + .willReturn( + ServerAuthenticationTokens( accessToken: "access-token", refreshToken: "refresh-token" ) - ), - serverURL: .any - ) - .willReturn() - - given(authenticateService) - .authenticate( - email: .value("email@tuist.io"), - password: .value("password"), - serverURL: .value(serverURL) - ) - .willReturn( - ServerAuthenticationTokens( - accessToken: "access-token", - refreshToken: "refresh-token" ) - ) - // When - try await subject.run( - email: nil, - password: "password", - directory: nil - ) + // When + try await subject.run( + email: nil, + password: "password", + directory: nil + ) - // Then - XCTAssertStandardOutput(pattern: "Successfully logged in.") + // Then + XCTAssertStandardOutput(pattern: "Successfully logged in.") + } } func test_authenticate_when_email_is_provided() async throws { - // Given - given(userInputReader) - .readString(asking: .value("Password:")) - .willReturn("password") - - given(serverCredentialsStore) - .store( - credentials: .value( - ServerCredentials( - token: nil, + try await ServiceContext.withTestingDependencies { + // Given + given(userInputReader) + .readString(asking: .value("Password:")) + .willReturn("password") + + given(serverCredentialsStore) + .store( + credentials: .value( + ServerCredentials( + token: nil, + accessToken: "access-token", + refreshToken: "refresh-token" + ) + ), + serverURL: .any + ) + .willReturn() + + given(authenticateService) + .authenticate( + email: .value("email@tuist.io"), + password: .value("password"), + serverURL: .value(serverURL) + ) + .willReturn( + ServerAuthenticationTokens( accessToken: "access-token", refreshToken: "refresh-token" ) - ), - serverURL: .any - ) - .willReturn() - - given(authenticateService) - .authenticate( - email: .value("email@tuist.io"), - password: .value("password"), - serverURL: .value(serverURL) - ) - .willReturn( - ServerAuthenticationTokens( - accessToken: "access-token", - refreshToken: "refresh-token" ) - ) - // When - try await subject.run( - email: "email@tuist.io", - password: nil, - directory: nil - ) + // When + try await subject.run( + email: "email@tuist.io", + password: nil, + directory: nil + ) - // Then - XCTAssertStandardOutput(pattern: "Successfully logged in.") + // Then + XCTAssertStandardOutput(pattern: "Successfully logged in.") + } } func test_authenticate_when_email_and_password_are_provided() async throws { - // Given - given(serverCredentialsStore) - .store( - credentials: .value( - ServerCredentials( - token: nil, + try await ServiceContext.withTestingDependencies { + // Given + given(serverCredentialsStore) + .store( + credentials: .value( + ServerCredentials( + token: nil, + accessToken: "access-token", + refreshToken: "refresh-token" + ) + ), + serverURL: .any + ) + .willReturn() + + given(authenticateService) + .authenticate( + email: .value("email@tuist.io"), + password: .value("password"), + serverURL: .value(serverURL) + ) + .willReturn( + ServerAuthenticationTokens( accessToken: "access-token", refreshToken: "refresh-token" ) - ), - serverURL: .any - ) - .willReturn() - - given(authenticateService) - .authenticate( - email: .value("email@tuist.io"), - password: .value("password"), - serverURL: .value(serverURL) - ) - .willReturn( - ServerAuthenticationTokens( - accessToken: "access-token", - refreshToken: "refresh-token" ) - ) - // When - try await subject.run( - email: "email@tuist.io", - password: "password", - directory: nil - ) + // When + try await subject.run( + email: "email@tuist.io", + password: "password", + directory: nil + ) - // Then - XCTAssertStandardOutput(pattern: "Successfully logged in.") - verify(userInputReader) - .readString(asking: .any) - .called(0) + // Then + XCTAssertStandardOutput(pattern: "Successfully logged in.") + verify(userInputReader) + .readString(asking: .any) + .called(0) + } } } diff --git a/Tests/TuistKitTests/Services/Organization/OrganizationInviteServiceTests.swift b/Tests/TuistKitTests/Services/Organization/OrganizationInviteServiceTests.swift index f9dc81e6b7a..ab9ac5ea38e 100644 --- a/Tests/TuistKitTests/Services/Organization/OrganizationInviteServiceTests.swift +++ b/Tests/TuistKitTests/Services/Organization/OrganizationInviteServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -36,32 +37,34 @@ final class OrganizationInviteServiceTests: TuistUnitTestCase { } func test_invite() async throws { - // Given - given(createOrganizationInviteService) - .createOrganizationInvite( - organizationName: .value("tuist"), - email: .value("tuist@test.io"), - serverURL: .value(serverURL) - ) - .willReturn( - .test( - inviteeEmail: "tuist@test.io", - token: "invitation-token" + try await ServiceContext.withTestingDependencies { + // Given + given(createOrganizationInviteService) + .createOrganizationInvite( + organizationName: .value("tuist"), + email: .value("tuist@test.io"), + serverURL: .value(serverURL) + ) + .willReturn( + .test( + inviteeEmail: "tuist@test.io", + token: "invitation-token" + ) ) - ) - // When - try await subject.run( - organizationName: "tuist", - email: "tuist@test.io", - directory: nil - ) + // When + try await subject.run( + organizationName: "tuist", + email: "tuist@test.io", + directory: nil + ) - // Then - XCTAssertPrinterOutputContains(""" - tuist@test.io was successfully invited to the tuist organization 🎉 + // Then + XCTAssertPrinterOutputContains(""" + tuist@test.io was successfully invited to the tuist organization 🎉 - You can also share with them the invite link directly: \(serverURL.absoluteString)/auth/invitations/invitation-token - """) + You can also share with them the invite link directly: \(serverURL.absoluteString)/auth/invitations/invitation-token + """) + } } } diff --git a/Tests/TuistKitTests/Services/Organization/OrganizationListServiceTests.swift b/Tests/TuistKitTests/Services/Organization/OrganizationListServiceTests.swift index 4f6a4882378..f8ee04a3415 100644 --- a/Tests/TuistKitTests/Services/Organization/OrganizationListServiceTests.swift +++ b/Tests/TuistKitTests/Services/Organization/OrganizationListServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupportTesting @@ -35,37 +36,41 @@ final class OrganizationListServiceTests: TuistUnitTestCase { } func test_organization_list() async throws { - // Given - given(listOrganizationsService).listOrganizations(serverURL: .any) - .willReturn( - [ - "test-one", - "test-two", - ] - ) + try await ServiceContext.withTestingDependencies { + // Given + given(listOrganizationsService).listOrganizations(serverURL: .any) + .willReturn( + [ + "test-one", + "test-two", + ] + ) - // When - try await subject.run(json: false, directory: nil) + // When + try await subject.run(json: false, directory: nil) - // Then - XCTAssertPrinterOutputContains(""" - Listing all your organizations: - • test-one - • test-two - """) + // Then + XCTAssertPrinterOutputContains(""" + Listing all your organizations: + • test-one + • test-two + """) + } } func test_organization_list_when_none() async throws { - // Given - given(listOrganizationsService).listOrganizations(serverURL: .any) - .willReturn([]) + try await ServiceContext.withTestingDependencies { + // Given + given(listOrganizationsService).listOrganizations(serverURL: .any) + .willReturn([]) - // When - try await subject.run(json: false, directory: nil) + // When + try await subject.run(json: false, directory: nil) - // Then - XCTAssertPrinterOutputContains( - "You currently have no Cloud organizations. Create one by running `tuist organization create`." - ) + // Then + XCTAssertPrinterOutputContains( + "You currently have no Cloud organizations. Create one by running `tuist organization create`." + ) + } } } diff --git a/Tests/TuistKitTests/Services/Organization/OrganizationRemoveSSOServiceTests.swift b/Tests/TuistKitTests/Services/Organization/OrganizationRemoveSSOServiceTests.swift index 2ccaa589428..743c6f80aff 100644 --- a/Tests/TuistKitTests/Services/Organization/OrganizationRemoveSSOServiceTests.swift +++ b/Tests/TuistKitTests/Services/Organization/OrganizationRemoveSSOServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupportTesting @@ -36,24 +37,26 @@ final class OrganizationRemoveSSOServiceTests: TuistUnitTestCase { } func test_organization_remove_sso() async throws { - // Given - given(updateOrganizationService) - .updateOrganization( - organizationName: .value("tuist"), - serverURL: .value(serverURL), - ssoOrganization: .value(nil) + try await ServiceContext.withTestingDependencies { + // Given + given(updateOrganizationService) + .updateOrganization( + organizationName: .value("tuist"), + serverURL: .value(serverURL), + ssoOrganization: .value(nil) + ) + .willReturn(.test()) + + // When + try await subject.run( + organizationName: "tuist", + directory: nil ) - .willReturn(.test()) - // When - try await subject.run( - organizationName: "tuist", - directory: nil - ) - - // Then - XCTAssertPrinterOutputContains(""" - SSO for tuist was removed. - """) + // Then + XCTAssertPrinterOutputContains(""" + SSO for tuist was removed. + """) + } } } diff --git a/Tests/TuistKitTests/Services/Organization/OrganizationShowServiceTests.swift b/Tests/TuistKitTests/Services/Organization/OrganizationShowServiceTests.swift index da13bb40362..dd96cc69233 100644 --- a/Tests/TuistKitTests/Services/Organization/OrganizationShowServiceTests.swift +++ b/Tests/TuistKitTests/Services/Organization/OrganizationShowServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -40,128 +41,134 @@ final class OrganizationShowServiceTests: TuistUnitTestCase { } func test_organization_show() async throws { - // Given - given(getOrganizationService) - .getOrganization(organizationName: .any, serverURL: .any) - .willReturn( - .test( - name: "test-one", - plan: .air, - members: [ - .test( - name: "name-one", - email: "name-one@email.io", - role: .user - ), - .test( - name: "name-two", - email: "name-two@email.io", - role: .admin - ), - ], - invitations: [ - .test( - inviteeEmail: "invitee@email.io", - inviter: .test(name: "some-inviter") - ), - ] + try await ServiceContext.withTestingDependencies { + // Given + given(getOrganizationService) + .getOrganization(organizationName: .any, serverURL: .any) + .willReturn( + .test( + name: "test-one", + plan: .air, + members: [ + .test( + name: "name-one", + email: "name-one@email.io", + role: .user + ), + .test( + name: "name-two", + email: "name-two@email.io", + role: .admin + ), + ], + invitations: [ + .test( + inviteeEmail: "invitee@email.io", + inviter: .test(name: "some-inviter") + ), + ] + ) ) - ) - given(getOrganizationUsageService) - .getOrganizationUsage(organizationName: .any, serverURL: .any) - .willReturn(.test(currentMonthRemoteCacheHits: 210)) + given(getOrganizationUsageService) + .getOrganizationUsage(organizationName: .any, serverURL: .any) + .willReturn(.test(currentMonthRemoteCacheHits: 210)) - // When - try await subject.run( - organizationName: "tuist", - json: false, - directory: nil - ) + // When + try await subject.run( + organizationName: "tuist", + json: false, + directory: nil + ) - // Then - XCTAssertPrinterOutputContains(""" - \(TerminalStyle.bold.open)Organization\(TerminalStyle.reset.open) - Name: test-one - Plan: Air + // Then + XCTAssertPrinterOutputContains(""" + \(TerminalStyle.bold.open)Organization\(TerminalStyle.reset.open) + Name: test-one + Plan: Air - \(TerminalStyle.bold.open)Usage\(TerminalStyle.reset.open) (current calendar month) - Remote cache hits: 210 + \(TerminalStyle.bold.open)Usage\(TerminalStyle.reset.open) (current calendar month) + Remote cache hits: 210 - \(TerminalStyle.bold.open)Organization members\(TerminalStyle.reset.open) (total number: 2) - username email role - name-one name-one@email.io user - name-two name-two@email.io admin + \(TerminalStyle.bold.open)Organization members\(TerminalStyle.reset.open) (total number: 2) + username email role + name-one name-one@email.io user + name-two name-two@email.io admin - \(TerminalStyle.bold.open)Invitations\(TerminalStyle.reset.open) (total number: 1) - inviter invitee email - some-inviter invitee@email.io - """) + \(TerminalStyle.bold.open)Invitations\(TerminalStyle.reset.open) (total number: 1) + inviter invitee email + some-inviter invitee@email.io + """) + } } func test_organization_show_when_has_google_as_sso_provider() async throws { - // Given - given(getOrganizationService) - .getOrganization(organizationName: .any, serverURL: .any) - .willReturn( - .test( - name: "test-one", - plan: .pro, - ssoOrganization: .google("tuist.io") + try await ServiceContext.withTestingDependencies { + // Given + given(getOrganizationService) + .getOrganization(organizationName: .any, serverURL: .any) + .willReturn( + .test( + name: "test-one", + plan: .pro, + ssoOrganization: .google("tuist.io") + ) ) + given(getOrganizationUsageService) + .getOrganizationUsage(organizationName: .any, serverURL: .any) + .willReturn(.test()) + + // When + try await subject.run( + organizationName: "tuist", + json: false, + directory: nil ) - given(getOrganizationUsageService) - .getOrganizationUsage(organizationName: .any, serverURL: .any) - .willReturn(.test()) - - // When - try await subject.run( - organizationName: "tuist", - json: false, - directory: nil - ) - // Then - XCTAssertPrinterOutputContains( - """ - \(TerminalStyle.bold.open)Organization\(TerminalStyle.reset.open) - Name: test-one - Plan: Pro - SSO: Google (tuist.io) - """ - ) + // Then + XCTAssertPrinterOutputContains( + """ + \(TerminalStyle.bold.open)Organization\(TerminalStyle.reset.open) + Name: test-one + Plan: Pro + SSO: Google (tuist.io) + """ + ) + } } func test_organization_show_when_has_okta_as_sso_provider() async throws { - // Given - given(getOrganizationService) - .getOrganization(organizationName: .any, serverURL: .any) - .willReturn( - .test( - name: "test-one", - plan: .pro, - ssoOrganization: .okta("tuist.okta.com") + try await ServiceContext.withTestingDependencies { + // Given + given(getOrganizationService) + .getOrganization(organizationName: .any, serverURL: .any) + .willReturn( + .test( + name: "test-one", + plan: .pro, + ssoOrganization: .okta("tuist.okta.com") + ) ) + given(getOrganizationUsageService) + .getOrganizationUsage(organizationName: .any, serverURL: .any) + .willReturn(.test()) + + // When + try await subject.run( + organizationName: "tuist", + json: false, + directory: nil ) - given(getOrganizationUsageService) - .getOrganizationUsage(organizationName: .any, serverURL: .any) - .willReturn(.test()) - - // When - try await subject.run( - organizationName: "tuist", - json: false, - directory: nil - ) - // Then - XCTAssertPrinterOutputContains( - """ - \(TerminalStyle.bold.open)Organization\(TerminalStyle.reset.open) - Name: test-one - Plan: Pro - SSO: Okta (tuist.okta.com) - """ - ) + // Then + XCTAssertPrinterOutputContains( + """ + \(TerminalStyle.bold.open)Organization\(TerminalStyle.reset.open) + Name: test-one + Plan: Pro + SSO: Okta (tuist.okta.com) + """ + ) + } } } diff --git a/Tests/TuistKitTests/Services/Organization/OrganizationUpdateSSOServiceTests.swift b/Tests/TuistKitTests/Services/Organization/OrganizationUpdateSSOServiceTests.swift index 611dadb8be2..a6d98bbd09b 100644 --- a/Tests/TuistKitTests/Services/Organization/OrganizationUpdateSSOServiceTests.swift +++ b/Tests/TuistKitTests/Services/Organization/OrganizationUpdateSSOServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupportTesting @@ -36,50 +37,54 @@ final class OrganizationUpdateSSOServiceTests: TuistUnitTestCase { } func test_organization_update_sso() async throws { - // Given - given(updateOrganizationService) - .updateOrganization( - organizationName: .value("tuist"), - serverURL: .value(serverURL), - ssoOrganization: .value(.google("tuist.io")) - ) - .willReturn(.test()) + try await ServiceContext.withTestingDependencies { + // Given + given(updateOrganizationService) + .updateOrganization( + organizationName: .value("tuist"), + serverURL: .value(serverURL), + ssoOrganization: .value(.google("tuist.io")) + ) + .willReturn(.test()) - // When - try await subject.run( - organizationName: "tuist", - provider: .google, - organizationId: "tuist.io", - directory: nil - ) + // When + try await subject.run( + organizationName: "tuist", + provider: .google, + organizationId: "tuist.io", + directory: nil + ) - // Then - XCTAssertPrinterOutputContains(""" - tuist now uses Google SSO with tuist.io. Users authenticated with the tuist.io SSO organization will automatically have access to the tuist projects. - """) + // Then + XCTAssertPrinterOutputContains(""" + tuist now uses Google SSO with tuist.io. Users authenticated with the tuist.io SSO organization will automatically have access to the tuist projects. + """) + } } func test_organization_update_sso_with_okta() async throws { - // Given - given(updateOrganizationService) - .updateOrganization( - organizationName: .value("tuist"), - serverURL: .value(serverURL), - ssoOrganization: .value(.okta("tuist.okta.com")) - ) - .willReturn(.test()) + try await ServiceContext.withTestingDependencies { + // Given + given(updateOrganizationService) + .updateOrganization( + organizationName: .value("tuist"), + serverURL: .value(serverURL), + ssoOrganization: .value(.okta("tuist.okta.com")) + ) + .willReturn(.test()) - // When - try await subject.run( - organizationName: "tuist", - provider: .okta, - organizationId: "tuist.okta.com", - directory: nil - ) + // When + try await subject.run( + organizationName: "tuist", + provider: .okta, + organizationId: "tuist.okta.com", + directory: nil + ) - // Then - XCTAssertPrinterOutputContains(""" - tuist now uses Okta SSO with tuist.okta.com. Users authenticated with the tuist.okta.com SSO organization will automatically have access to the tuist projects. - """) + // Then + XCTAssertPrinterOutputContains(""" + tuist now uses Okta SSO with tuist.okta.com. Users authenticated with the tuist.okta.com SSO organization will automatically have access to the tuist projects. + """) + } } } diff --git a/Tests/TuistKitTests/Services/Plugin/PluginArchiveServiceTests.swift b/Tests/TuistKitTests/Services/Plugin/PluginArchiveServiceTests.swift index b86f94f0862..1f42c231775 100644 --- a/Tests/TuistKitTests/Services/Plugin/PluginArchiveServiceTests.swift +++ b/Tests/TuistKitTests/Services/Plugin/PluginArchiveServiceTests.swift @@ -1,5 +1,6 @@ import Mockable import Path +import ServiceContextModule import TuistLoader import TuistSupport import TuistSupportTesting @@ -37,30 +38,32 @@ final class PluginArchiveServiceTests: TuistUnitTestCase { } func test_run_when_no_task_products_defined() async throws { - // Given - given(packageInfoLoader) - .loadPackageInfo(at: .any) - .willReturn( - PackageInfo.test( - products: [ - PackageInfo.Product( - name: "my-non-task-executable", - type: .executable, - targets: [] - ), - ] + try await ServiceContext.withTestingDependencies { + // Given + given(packageInfoLoader) + .loadPackageInfo(at: .any) + .willReturn( + PackageInfo.test( + products: [ + PackageInfo.Product( + name: "my-non-task-executable", + type: .executable, + targets: [] + ), + ] + ) ) - ) - // When - try await subject.run(path: nil) + // When + try await subject.run(path: nil) - // Then - XCTAssertPrinterContains( - "No tasks found - make sure you have executable products with `tuist-` prefix defined in your manifest.", - at: .warning, - == - ) + // Then + XCTAssertPrinterContains( + "No tasks found - make sure you have executable products with `tuist-` prefix defined in your manifest.", + at: .warning, + == + ) + } } func test_run() async throws { diff --git a/Tests/TuistKitTests/Services/Project/ProjectListServiceTests.swift b/Tests/TuistKitTests/Services/Project/ProjectListServiceTests.swift index 669a6528732..8835498150d 100644 --- a/Tests/TuistKitTests/Services/Project/ProjectListServiceTests.swift +++ b/Tests/TuistKitTests/Services/Project/ProjectListServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupportTesting @@ -35,39 +36,43 @@ final class ProjectListServiceTests: TuistUnitTestCase { } func test_project_list() async throws { - // Given - given(listProjectsService) - .listProjects(serverURL: .value(serverURL)) - .willReturn( - [ - .test(id: 0, fullName: "tuist/test-one"), - .test(id: 1, fullName: "tuist/test-two"), - ] - ) + try await ServiceContext.withTestingDependencies { + // Given + given(listProjectsService) + .listProjects(serverURL: .value(serverURL)) + .willReturn( + [ + .test(id: 0, fullName: "tuist/test-one"), + .test(id: 1, fullName: "tuist/test-two"), + ] + ) - // When - try await subject.run(json: false, directory: nil) + // When + try await subject.run(json: false, directory: nil) - // Then - XCTAssertPrinterOutputContains(""" - Listing all your projects: - • tuist/test-one - • tuist/test-two - """) + // Then + XCTAssertPrinterOutputContains(""" + Listing all your projects: + • tuist/test-one + • tuist/test-two + """) + } } func test_project_list_when_none() async throws { - // Given - given(listProjectsService) - .listProjects(serverURL: .value(serverURL)) - .willReturn([]) + try await ServiceContext.withTestingDependencies { + // Given + given(listProjectsService) + .listProjects(serverURL: .value(serverURL)) + .willReturn([]) - // When - try await subject.run(json: false, directory: nil) + // When + try await subject.run(json: false, directory: nil) - // Then - XCTAssertPrinterOutputContains( - "You currently have no Tuist projects. Create one by running `tuist project create`." - ) + // Then + XCTAssertPrinterOutputContains( + "You currently have no Tuist projects. Create one by running `tuist project create`." + ) + } } } diff --git a/Tests/TuistKitTests/Services/Project/ProjectShowServiceTests.swift b/Tests/TuistKitTests/Services/Project/ProjectShowServiceTests.swift index b29cdd60858..a00e92fa7c4 100644 --- a/Tests/TuistKitTests/Services/Project/ProjectShowServiceTests.swift +++ b/Tests/TuistKitTests/Services/Project/ProjectShowServiceTests.swift @@ -1,12 +1,12 @@ import Foundation import Mockable +import ServiceContextModule import TuistCore import TuistLoader import TuistServer import TuistSupport import TuistSupportTesting import XCTest - @testable import TuistKit final class ProjectShowServiceTests: TuistUnitTestCase { @@ -91,149 +91,159 @@ final class ProjectShowServiceTests: TuistUnitTestCase { } func test_run_when_full_handle_is_provided() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test()) - given(getProjectService) - .getProject( - fullHandle: .value("tuist/tuist"), - serverURL: .any - ) - .willReturn( - .test( - fullName: "tuist/tuist", - defaultBranch: "main" + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test()) + given(getProjectService) + .getProject( + fullHandle: .value("tuist/tuist"), + serverURL: .any + ) + .willReturn( + .test( + fullName: "tuist/tuist", + defaultBranch: "main" + ) ) - ) - // When - try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) + // When + try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) - // Then - XCTAssertStandardOutput( - pattern: """ - Full handle: tuist/tuist - Default branch: main - """ - ) + // Then + XCTAssertStandardOutput( + pattern: """ + Full handle: tuist/tuist + Default branch: main + """ + ) + } } func test_run_when_project_is_public() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test()) - given(getProjectService) - .getProject( - fullHandle: .value("tuist/tuist"), - serverURL: .any - ) - .willReturn( - .test( - visibility: .public + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test()) + given(getProjectService) + .getProject( + fullHandle: .value("tuist/tuist"), + serverURL: .any + ) + .willReturn( + .test( + visibility: .public + ) ) - ) - // When - try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) + // When + try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) - // Then - XCTAssertStandardOutput( - pattern: """ - Visibility: public - """ - ) + // Then + XCTAssertStandardOutput( + pattern: """ + Visibility: public + """ + ) + } } func test_run_when_project_is_private() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test()) - given(getProjectService) - .getProject( - fullHandle: .value("tuist/tuist"), - serverURL: .any - ) - .willReturn( - .test( - visibility: .private + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test()) + given(getProjectService) + .getProject( + fullHandle: .value("tuist/tuist"), + serverURL: .any + ) + .willReturn( + .test( + visibility: .private + ) ) - ) - // When - try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) + // When + try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) - // Then - XCTAssertStandardOutput( - pattern: """ - Visibility: private - """ - ) + // Then + XCTAssertStandardOutput( + pattern: """ + Visibility: private + """ + ) + } } func test_run_when_repositoryURL_is_defined() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test()) - given(getProjectService) - .getProject( - fullHandle: .value("tuist/tuist"), - serverURL: .any - ) - .willReturn( - .test( - fullName: "tuist/tuist", - defaultBranch: "main", - repositoryURL: "https://github.com/tuist/tuist" + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test()) + given(getProjectService) + .getProject( + fullHandle: .value("tuist/tuist"), + serverURL: .any + ) + .willReturn( + .test( + fullName: "tuist/tuist", + defaultBranch: "main", + repositoryURL: "https://github.com/tuist/tuist" + ) ) - ) - // When - try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) + // When + try await subject.run(fullHandle: "tuist/tuist", web: false, path: nil) - // Then - XCTAssertStandardOutput( - pattern: """ - Full handle: tuist/tuist - Repository: https://github.com/tuist/tuist - Default branch: main - """ - ) + // Then + XCTAssertStandardOutput( + pattern: """ + Full handle: tuist/tuist + Repository: https://github.com/tuist/tuist + Default branch: main + """ + ) + } } func test_run_when_full_handle_is_not_provided() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn( - .test( - fullHandle: "tuist/tuist" + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn( + .test( + fullHandle: "tuist/tuist" + ) ) - ) - given(getProjectService) - .getProject( - fullHandle: .value("tuist/tuist"), - serverURL: .any - ) - .willReturn( - .test( - fullName: "tuist/tuist", - defaultBranch: "main" + given(getProjectService) + .getProject( + fullHandle: .value("tuist/tuist"), + serverURL: .any + ) + .willReturn( + .test( + fullName: "tuist/tuist", + defaultBranch: "main" + ) ) - ) - // When - try await subject.run(fullHandle: nil, web: false, path: nil) + // When + try await subject.run(fullHandle: nil, web: false, path: nil) - // Then - XCTAssertStandardOutput( - pattern: """ - Full handle: tuist/tuist - Default branch: main - """ - ) + // Then + XCTAssertStandardOutput( + pattern: """ + Full handle: tuist/tuist + Default branch: main + """ + ) + } } } diff --git a/Tests/TuistKitTests/Services/Project/ProjectTokensCreateServiceTests.swift b/Tests/TuistKitTests/Services/Project/ProjectTokensCreateServiceTests.swift index 0d65b90b0de..33f5dcb61a3 100644 --- a/Tests/TuistKitTests/Services/Project/ProjectTokensCreateServiceTests.swift +++ b/Tests/TuistKitTests/Services/Project/ProjectTokensCreateServiceTests.swift @@ -1,10 +1,10 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupportTesting import XCTest - @testable import TuistKit final class ProjectTokensCreateServiceTests: TuistUnitTestCase { @@ -45,18 +45,20 @@ final class ProjectTokensCreateServiceTests: TuistUnitTestCase { } func test_create_project_token() async throws { - // Given - given(createProjectTokenService) - .createProjectToken( - fullHandle: .value("tuist-org/tuist"), - serverURL: .any - ) - .willReturn("new-token") - - // When - try await subject.run(fullHandle: "tuist-org/tuist", directory: nil) - - // Then - XCTAssertStandardOutput(pattern: "new-token") + try await ServiceContext.withTestingDependencies { + // Given + given(createProjectTokenService) + .createProjectToken( + fullHandle: .value("tuist-org/tuist"), + serverURL: .any + ) + .willReturn("new-token") + + // When + try await subject.run(fullHandle: "tuist-org/tuist", directory: nil) + + // Then + XCTAssertStandardOutput(pattern: "new-token") + } } } diff --git a/Tests/TuistKitTests/Services/Project/ProjectTokensListServiceTests.swift b/Tests/TuistKitTests/Services/Project/ProjectTokensListServiceTests.swift index 27399de91f9..3b90b1d77b4 100644 --- a/Tests/TuistKitTests/Services/Project/ProjectTokensListServiceTests.swift +++ b/Tests/TuistKitTests/Services/Project/ProjectTokensListServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupportTesting @@ -45,54 +46,58 @@ final class ProjectTokensListServiceTests: TuistUnitTestCase { } func test_list_project_tokens() async throws { - // Given - given(listProjectTokensService) - .listProjectTokens( - fullHandle: .value("tuist-org/tuist"), - serverURL: .any - ) - .willReturn( - [ - .test( - id: "project-token-one", - insertedAt: Date(timeIntervalSince1970: 0) - ), - .test( - id: "project-token-two", - insertedAt: Date(timeIntervalSince1970: 10) - ), - ] - ) + try await ServiceContext.withTestingDependencies { + // Given + given(listProjectTokensService) + .listProjectTokens( + fullHandle: .value("tuist-org/tuist"), + serverURL: .any + ) + .willReturn( + [ + .test( + id: "project-token-one", + insertedAt: Date(timeIntervalSince1970: 0) + ), + .test( + id: "project-token-two", + insertedAt: Date(timeIntervalSince1970: 10) + ), + ] + ) - // When - try await subject.run(fullHandle: "tuist-org/tuist", directory: nil) + // When + try await subject.run(fullHandle: "tuist-org/tuist", directory: nil) - // Then - XCTAssertStandardOutput( - pattern: """ - ID Created at - ───────────────── ───────────────────────── - project-token-one 1970-01-01 00:00:00 +0000 - project-token-two 1970-01-01 00:00:10 +0000 - """ - ) + // Then + XCTAssertStandardOutput( + pattern: """ + ID Created at + ───────────────── ───────────────────────── + project-token-one 1970-01-01 00:00:00 +0000 + project-token-two 1970-01-01 00:00:10 +0000 + """ + ) + } } func test_list_project_tokens_when_none_present() async throws { - // Given - given(listProjectTokensService) - .listProjectTokens( - fullHandle: .value("tuist-org/tuist"), - serverURL: .any - ) - .willReturn([]) + try await ServiceContext.withTestingDependencies { + // Given + given(listProjectTokensService) + .listProjectTokens( + fullHandle: .value("tuist-org/tuist"), + serverURL: .any + ) + .willReturn([]) - // When - try await subject.run(fullHandle: "tuist-org/tuist", directory: nil) + // When + try await subject.run(fullHandle: "tuist-org/tuist", directory: nil) - // Then - XCTAssertStandardOutput( - pattern: "No project tokens found. Create one by running `tuist project tokens create tuist-org/tuist." - ) + // Then + XCTAssertStandardOutput( + pattern: "No project tokens found. Create one by running `tuist project tokens create tuist-org/tuist." + ) + } } } diff --git a/Tests/TuistKitTests/Services/Project/ProjectTokensRevokeServiceTests.swift b/Tests/TuistKitTests/Services/Project/ProjectTokensRevokeServiceTests.swift index 3babd510122..c6ef5413ec4 100644 --- a/Tests/TuistKitTests/Services/Project/ProjectTokensRevokeServiceTests.swift +++ b/Tests/TuistKitTests/Services/Project/ProjectTokensRevokeServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupportTesting @@ -45,23 +46,25 @@ final class ProjectTokensRevokeServiceTests: TuistUnitTestCase { } func test_revoke_project_token() async throws { - // Given - given(revokeProjectTokenService) - .revokeProjectToken( - projectTokenId: .value("project-token-id"), - fullHandle: .value("tuist-org/tuist"), - serverURL: .any - ) - .willReturn() + try await ServiceContext.withTestingDependencies { + // Given + given(revokeProjectTokenService) + .revokeProjectToken( + projectTokenId: .value("project-token-id"), + fullHandle: .value("tuist-org/tuist"), + serverURL: .any + ) + .willReturn() - // When - try await subject.run( - projectTokenId: "project-token-id", - fullHandle: "tuist-org/tuist", - directory: nil - ) + // When + try await subject.run( + projectTokenId: "project-token-id", + fullHandle: "tuist-org/tuist", + directory: nil + ) - // Then - XCTAssertStandardOutput(pattern: "The project token project-token-id was successfully revoked.") + // Then + XCTAssertStandardOutput(pattern: "The project token project-token-id was successfully revoked.") + } } } diff --git a/Tests/TuistKitTests/Services/Project/ProjectUpdateServiceTests.swift b/Tests/TuistKitTests/Services/Project/ProjectUpdateServiceTests.swift index 8f7cda74b01..2edc4b9f23e 100644 --- a/Tests/TuistKitTests/Services/Project/ProjectUpdateServiceTests.swift +++ b/Tests/TuistKitTests/Services/Project/ProjectUpdateServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistLoader import TuistServer import TuistSupport @@ -53,35 +54,37 @@ final class ProjectUpdateServiceTests: TuistUnitTestCase { } func test_run_when_full_handle_is_not_provided() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn( - .test( - fullHandle: "tuist/tuist" + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn( + .test( + fullHandle: "tuist/tuist" + ) ) - ) - - // When - try await subject.run( - fullHandle: nil, - defaultBranch: "new-default-branch", - repositoryURL: "https://github.com/tuist/tuist", - visibility: .public, - path: nil - ) - // Then - verify(updateProjectService) - .updateProject( - fullHandle: .value("tuist/tuist"), - serverURL: .any, - defaultBranch: .value("new-default-branch"), - repositoryURL: .value("https://github.com/tuist/tuist"), - visibility: .value(.public) + // When + try await subject.run( + fullHandle: nil, + defaultBranch: "new-default-branch", + repositoryURL: "https://github.com/tuist/tuist", + visibility: .public, + path: nil ) - .called(1) - XCTAssertStandardOutput(pattern: "The project tuist/tuist was successfully updated 🎉") + + // Then + verify(updateProjectService) + .updateProject( + fullHandle: .value("tuist/tuist"), + serverURL: .any, + defaultBranch: .value("new-default-branch"), + repositoryURL: .value("https://github.com/tuist/tuist"), + visibility: .value(.public) + ) + .called(1) + XCTAssertStandardOutput(pattern: "The project tuist/tuist was successfully updated 🎉") + } } func test_run_when_full_handle_is_not_provided_and_is_not_in_config() async throws { @@ -108,30 +111,32 @@ final class ProjectUpdateServiceTests: TuistUnitTestCase { } func test_run_when_full_handle_is_provided() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test()) + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test()) - // When - try await subject.run( - fullHandle: "tuist/tuist", - defaultBranch: "new-default-branch", - repositoryURL: nil, - visibility: nil, - path: nil - ) - - // Then - verify(updateProjectService) - .updateProject( - fullHandle: .value("tuist/tuist"), - serverURL: .any, - defaultBranch: .value("new-default-branch"), - repositoryURL: .value(nil), - visibility: .value(nil) + // When + try await subject.run( + fullHandle: "tuist/tuist", + defaultBranch: "new-default-branch", + repositoryURL: nil, + visibility: nil, + path: nil ) - .called(1) - XCTAssertStandardOutput(pattern: "The project tuist/tuist was successfully updated 🎉") + + // Then + verify(updateProjectService) + .updateProject( + fullHandle: .value("tuist/tuist"), + serverURL: .any, + defaultBranch: .value("new-default-branch"), + repositoryURL: .value(nil), + visibility: .value(nil) + ) + .called(1) + XCTAssertStandardOutput(pattern: "The project tuist/tuist was successfully updated 🎉") + } } } diff --git a/Tests/TuistKitTests/Services/ShareServiceTests.swift b/Tests/TuistKitTests/Services/ShareServiceTests.swift index 49ea35fbe9f..e5d5c7c13df 100644 --- a/Tests/TuistKitTests/Services/ShareServiceTests.swift +++ b/Tests/TuistKitTests/Services/ShareServiceTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistAutomation import TuistCore import TuistLoader @@ -127,128 +128,130 @@ final class ShareServiceTests: TuistUnitTestCase { } func test_share_tuist_project() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test(fullHandle: "tuist/tuist")) - - let projectPath = try temporaryPath() - let appTarget: Target = .test( - name: "AppTarget", - destinations: [.appleVision, .iPhone], - productName: "App" - ) - let appTargetTwo: Target = .test(name: "AppTwo") - let project: Project = .test( - targets: [ - appTarget, - appTargetTwo, - ] - ) - let graphAppTarget = GraphTarget(path: projectPath, target: appTarget, project: project) - let graphAppTargetTwo = GraphTarget(path: projectPath, target: appTargetTwo, project: project) - - given(manifestGraphLoader) - .load(path: .any) - .willReturn( - ( - .test( - projects: [ - projectPath: project, - ] - ), - [], - MapperEnvironment(), - [] - ) + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test(fullHandle: "tuist/tuist")) + + let projectPath = try temporaryPath() + let appTarget: Target = .test( + name: "AppTarget", + destinations: [.appleVision, .iPhone], + productName: "App" ) - - given(userInputReader) - .readValue( - asking: .any, - values: .value([ - graphAppTarget, - graphAppTargetTwo, - ]), - valueDescription: .any + let appTargetTwo: Target = .test(name: "AppTwo") + let project: Project = .test( + targets: [ + appTarget, + appTargetTwo, + ] ) - .willReturn(graphAppTarget) + let graphAppTarget = GraphTarget(path: projectPath, target: appTarget, project: project) + let graphAppTargetTwo = GraphTarget(path: projectPath, target: appTargetTwo, project: project) + + given(manifestGraphLoader) + .load(path: .any) + .willReturn( + ( + .test( + projects: [ + projectPath: project, + ] + ), + [], + MapperEnvironment(), + [] + ) + ) - given(defaultConfigurationFetcher) - .fetch(configuration: .any, config: .any, graph: .any) - .willReturn("Debug") + given(userInputReader) + .readValue( + asking: .any, + values: .value([ + graphAppTarget, + graphAppTargetTwo, + ]), + valueDescription: .any + ) + .willReturn(graphAppTarget) + + given(defaultConfigurationFetcher) + .fetch(configuration: .any, config: .any, graph: .any) + .willReturn("Debug") + + let iosPath = try temporaryPath() + let iosDevicePath = try temporaryPath().appending(component: "iphoneos") + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.simulator(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(iosPath) + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.device(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(iosDevicePath) + try fileHandler.touch(iosPath.appending(component: "App.app")) + try fileHandler.touch(iosDevicePath.appending(component: "App.app")) + + let visionOSPath = try temporaryPath() + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.simulator(.visionOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(visionOSPath) + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.device(.visionOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(try temporaryPath().appending(component: "visionOS")) + try fileHandler.touch(visionOSPath.appending(component: "App.app")) - let iosPath = try temporaryPath() - let iosDevicePath = try temporaryPath().appending(component: "iphoneos") - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.simulator(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(iosPath) - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.device(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(iosDevicePath) - try fileHandler.touch(iosPath.appending(component: "App.app")) - try fileHandler.touch(iosDevicePath.appending(component: "App.app")) + given(appBundleLoader) + .load(.any) + .willReturn(.test()) - let visionOSPath = try temporaryPath() - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.simulator(.visionOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(visionOSPath) - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.device(.visionOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any + // When + try await subject.run( + path: nil, + apps: [], + configuration: nil, + platforms: [], + derivedDataPath: nil, + json: false ) - .willReturn(try temporaryPath().appending(component: "visionOS")) - try fileHandler.touch(visionOSPath.appending(component: "App.app")) - given(appBundleLoader) - .load(.any) - .willReturn(.test()) - - // When - try await subject.run( - path: nil, - apps: [], - configuration: nil, - platforms: [], - derivedDataPath: nil, - json: false - ) + // Then + verify(previewsUploadService) + .uploadPreviews( + .any, + displayName: .any, + version: .any, + bundleIdentifier: .any, + icon: .any, + supportedPlatforms: .any, + fullHandle: .value("tuist/tuist"), + serverURL: .value(Constants.URLs.production) + ) + .called(1) - // Then - verify(previewsUploadService) - .uploadPreviews( - .any, - displayName: .any, - version: .any, - bundleIdentifier: .any, - icon: .any, - supportedPlatforms: .any, - fullHandle: .value("tuist/tuist"), - serverURL: .value(Constants.URLs.production) + XCTAssertStandardOutput( + pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" ) - .called(1) - - XCTAssertStandardOutput( - pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" - ) + } } func test_share_tuist_project_when_no_app_found() async throws { @@ -336,285 +339,291 @@ final class ShareServiceTests: TuistUnitTestCase { } func test_share_tuist_project_with_a_specified_app() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test(fullHandle: "tuist/tuist")) - - let projectPath = try temporaryPath() - let appTarget: Target = .test( - name: "App", - destinations: [.appleVision, .iPhone] - ) - let appTargetTwo: Target = .test(name: "AppTwo") - let project: Project = .test( - targets: [ - appTarget, - appTargetTwo, - ] - ) - let graphAppTargetTwo = GraphTarget(path: projectPath, target: appTargetTwo, project: project) - - given(manifestGraphLoader) - .load(path: .any) - .willReturn( - ( - .test( - projects: [ - projectPath: project, - ] - ), - [], - MapperEnvironment(), - [] - ) + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test(fullHandle: "tuist/tuist")) + + let projectPath = try temporaryPath() + let appTarget: Target = .test( + name: "App", + destinations: [.appleVision, .iPhone] ) - - given(userInputReader) - .readValue( - asking: .any, - values: .value([ - graphAppTargetTwo, - ]), - valueDescription: .any + let appTargetTwo: Target = .test(name: "AppTwo") + let project: Project = .test( + targets: [ + appTarget, + appTargetTwo, + ] ) - .willReturn(graphAppTargetTwo) - - given(defaultConfigurationFetcher) - .fetch(configuration: .any, config: .any, graph: .any) - .willReturn("Debug") + let graphAppTargetTwo = GraphTarget(path: projectPath, target: appTargetTwo, project: project) + + given(manifestGraphLoader) + .load(path: .any) + .willReturn( + ( + .test( + projects: [ + projectPath: project, + ] + ), + [], + MapperEnvironment(), + [] + ) + ) - let iosPath = try temporaryPath() - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.simulator(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(iosPath) - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.device(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(try temporaryPath().appending(component: "iphoneos")) - try fileHandler.touch(iosPath.appending(component: "AppTwo.app")) + given(userInputReader) + .readValue( + asking: .any, + values: .value([ + graphAppTargetTwo, + ]), + valueDescription: .any + ) + .willReturn(graphAppTargetTwo) + + given(defaultConfigurationFetcher) + .fetch(configuration: .any, config: .any, graph: .any) + .willReturn("Debug") + + let iosPath = try temporaryPath() + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.simulator(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(iosPath) + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.device(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(try temporaryPath().appending(component: "iphoneos")) + try fileHandler.touch(iosPath.appending(component: "AppTwo.app")) - given(appBundleLoader) - .load(.any) - .willReturn( - .test( - infoPlist: .test( - version: Version(1, 0, 0), - bundleId: "com.tuist.app", - supportedPlatforms: [.simulator(.iOS)] + given(appBundleLoader) + .load(.any) + .willReturn( + .test( + infoPlist: .test( + version: Version(1, 0, 0), + bundleId: "com.tuist.app", + supportedPlatforms: [.simulator(.iOS)] + ) ) ) + + // When + try await subject.run( + path: nil, + apps: ["AppTwo"], + configuration: nil, + platforms: [], + derivedDataPath: nil, + json: false ) - // When - try await subject.run( - path: nil, - apps: ["AppTwo"], - configuration: nil, - platforms: [], - derivedDataPath: nil, - json: false - ) + // Then + verify(previewsUploadService) + .uploadPreviews( + .any, + displayName: .any, + version: .value("1.0.0"), + bundleIdentifier: .value("com.tuist.app"), + icon: .any, + supportedPlatforms: .value([.simulator(.iOS)]), + fullHandle: .value("tuist/tuist"), + serverURL: .value(Constants.URLs.production) + ) + .called(1) - // Then - verify(previewsUploadService) - .uploadPreviews( - .any, - displayName: .any, - version: .value("1.0.0"), - bundleIdentifier: .value("com.tuist.app"), - icon: .any, - supportedPlatforms: .value([.simulator(.iOS)]), - fullHandle: .value("tuist/tuist"), - serverURL: .value(Constants.URLs.production) + XCTAssertStandardOutput( + pattern: "AppTwo uploaded – share it with others using the following link: \(shareURL.absoluteString)" ) - .called(1) - - XCTAssertStandardOutput( - pattern: "AppTwo uploaded – share it with others using the following link: \(shareURL.absoluteString)" - ) + } } func test_share_tuist_project_with_a_specified_app_and_json_flag() async throws { - // Given - let projectPath = try temporaryPath() - let appTarget: Target = .test( - name: "App" - ) - let project: Project = .test( - targets: [ - appTarget, - ] - ) - let graphAppTarget = GraphTarget(path: projectPath, target: appTarget, project: project) - - given(appBundleLoader) - .load(.any) - .willReturn(.test()) - - given(manifestGraphLoader) - .load(path: .any) - .willReturn( - ( - .test( - projects: [ - projectPath: project, - ] - ), - [], - MapperEnvironment(), - [] - ) + try await ServiceContext.withTestingDependencies { + // Given + let projectPath = try temporaryPath() + let appTarget: Target = .test( + name: "App" ) - - given(userInputReader) - .readValue( - asking: .any, - values: .any, - valueDescription: .any + let project: Project = .test( + targets: [ + appTarget, + ] ) - .willReturn(graphAppTarget) + let graphAppTarget = GraphTarget(path: projectPath, target: appTarget, project: project) + + given(appBundleLoader) + .load(.any) + .willReturn(.test()) + + given(manifestGraphLoader) + .load(path: .any) + .willReturn( + ( + .test( + projects: [ + projectPath: project, + ] + ), + [], + MapperEnvironment(), + [] + ) + ) - given(defaultConfigurationFetcher) - .fetch(configuration: .any, config: .any, graph: .any) - .willReturn("Debug") + given(userInputReader) + .readValue( + asking: .any, + values: .any, + valueDescription: .any + ) + .willReturn(graphAppTarget) + + given(defaultConfigurationFetcher) + .fetch(configuration: .any, config: .any, graph: .any) + .willReturn("Debug") + + let iosPath = try temporaryPath() + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.simulator(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(iosPath) + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.device(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(try temporaryPath().appending(component: "iphoneos")) + try fileHandler.touch(iosPath.appending(component: "App.app")) - let iosPath = try temporaryPath() - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.simulator(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(iosPath) - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.device(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any + // When + try await subject.run( + path: nil, + apps: ["AppTwo"], + configuration: nil, + platforms: [], + derivedDataPath: nil, + json: true ) - .willReturn(try temporaryPath().appending(component: "iphoneos")) - try fileHandler.touch(iosPath.appending(component: "App.app")) - - // When - try await subject.run( - path: nil, - apps: ["AppTwo"], - configuration: nil, - platforms: [], - derivedDataPath: nil, - json: true - ) - XCTAssertStandardOutput( - pattern: """ - { - "bundleIdentifier": "com.tuist.app", - "displayName": "App", - "iconURL": "https://cloud.tuist.io/tuist/tuist/previews/preview-id/icon.png", - "id": "preview-id", - "qrCodeURL": "https://tuist.dev/tuist/tuist/previews/preview-id/qr-code.svg", - "url": "https://test.tuist.io" - } - """ - ) + XCTAssertStandardOutput( + pattern: """ + { + "bundleIdentifier": "com.tuist.app", + "displayName": "App", + "iconURL": "https://cloud.tuist.io/tuist/tuist/previews/preview-id/icon.png", + "id": "preview-id", + "qrCodeURL": "https://tuist.dev/tuist/tuist/previews/preview-id/qr-code.svg", + "url": "https://test.tuist.io" + } + """ + ) + } } func test_share_tuist_project_with_a_specified_appclip() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test(fullHandle: "tuist/tuist")) - - let projectPath = try temporaryPath() - let appClipTarget: Target = .test( - name: "AppClip", - product: .appClip - ) - let appTarget: Target = .test(name: "App") - let project: Project = .test( - targets: [ - appClipTarget, - appTarget, - ] - ) - let graphAppClipTarget = GraphTarget(path: projectPath, target: appClipTarget, project: project) - - given(manifestGraphLoader) - .load(path: .any) - .willReturn( - ( - .test( - projects: [ - projectPath: project, - ] - ), - [], - MapperEnvironment(), - [] - ) + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test(fullHandle: "tuist/tuist")) + + let projectPath = try temporaryPath() + let appClipTarget: Target = .test( + name: "AppClip", + product: .appClip ) - - given(userInputReader) - .readValue( - asking: .any, - values: .any, - valueDescription: .any + let appTarget: Target = .test(name: "App") + let project: Project = .test( + targets: [ + appClipTarget, + appTarget, + ] ) - .willReturn(graphAppClipTarget) - - given(defaultConfigurationFetcher) - .fetch(configuration: .any, config: .any, graph: .any) - .willReturn("Debug") + let graphAppClipTarget = GraphTarget(path: projectPath, target: appClipTarget, project: project) + + given(manifestGraphLoader) + .load(path: .any) + .willReturn( + ( + .test( + projects: [ + projectPath: project, + ] + ), + [], + MapperEnvironment(), + [] + ) + ) - let iosPath = try temporaryPath() - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.simulator(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(iosPath) - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.device(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(try temporaryPath().appending(component: "iphoneos")) - try fileHandler.touch(iosPath.appending(component: "AppClip.app")) + given(userInputReader) + .readValue( + asking: .any, + values: .any, + valueDescription: .any + ) + .willReturn(graphAppClipTarget) + + given(defaultConfigurationFetcher) + .fetch(configuration: .any, config: .any, graph: .any) + .willReturn("Debug") + + let iosPath = try temporaryPath() + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.simulator(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(iosPath) + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.device(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(try temporaryPath().appending(component: "iphoneos")) + try fileHandler.touch(iosPath.appending(component: "AppClip.app")) - given(appBundleLoader) - .load(.any) - .willReturn(.test()) + given(appBundleLoader) + .load(.any) + .willReturn(.test()) - // When - try await subject.run( - path: nil, - apps: ["AppClip"], - configuration: nil, - platforms: [], - derivedDataPath: nil, - json: false - ) + // When + try await subject.run( + path: nil, + apps: ["AppClip"], + configuration: nil, + platforms: [], + derivedDataPath: nil, + json: false + ) - // Then - XCTAssertStandardOutput( - pattern: "AppClip uploaded – share it with others using the following link: \(shareURL.absoluteString)" - ) + // Then + XCTAssertStandardOutput( + pattern: "AppClip uploaded – share it with others using the following link: \(shareURL.absoluteString)" + ) + } } func test_share_xcode_app_when_no_app_specified() async throws { @@ -724,71 +733,73 @@ final class ShareServiceTests: TuistUnitTestCase { } func test_share_xcode_app() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test(fullHandle: "tuist/tuist")) - - manifestLoader.reset() - - given(manifestLoader) - .hasRootManifest(at: .any) - .willReturn(false) + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test(fullHandle: "tuist/tuist")) + + manifestLoader.reset() + + given(manifestLoader) + .hasRootManifest(at: .any) + .willReturn(false) + + let path = try temporaryPath() + let xcodeprojPath = try temporaryPath().appending(component: "App.xcodeproj") + try fileHandler.touch(xcodeprojPath) + + let iosPath = try temporaryPath() + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.simulator(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(iosPath) + given(xcodeProjectBuildDirectoryLocator) + .locate( + destinationType: .value(.device(.iOS)), + projectPath: .any, + derivedDataPath: .any, + configuration: .any + ) + .willReturn(try temporaryPath().appending(component: "iphoneos")) + try fileHandler.touch(iosPath.appending(component: "App.app")) - let path = try temporaryPath() - let xcodeprojPath = try temporaryPath().appending(component: "App.xcodeproj") - try fileHandler.touch(xcodeprojPath) + given(appBundleLoader) + .load(.any) + .willReturn(.test()) - let iosPath = try temporaryPath() - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.simulator(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any - ) - .willReturn(iosPath) - given(xcodeProjectBuildDirectoryLocator) - .locate( - destinationType: .value(.device(.iOS)), - projectPath: .any, - derivedDataPath: .any, - configuration: .any + // When + try await subject.run( + path: path.pathString, + apps: ["App"], + configuration: nil, + platforms: [.iOS], + derivedDataPath: nil, + json: false ) - .willReturn(try temporaryPath().appending(component: "iphoneos")) - try fileHandler.touch(iosPath.appending(component: "App.app")) - - given(appBundleLoader) - .load(.any) - .willReturn(.test()) - // When - try await subject.run( - path: path.pathString, - apps: ["App"], - configuration: nil, - platforms: [.iOS], - derivedDataPath: nil, - json: false - ) + // Then + verify(previewsUploadService) + .uploadPreviews( + .any, + displayName: .any, + version: .any, + bundleIdentifier: .any, + icon: .any, + supportedPlatforms: .any, + fullHandle: .value("tuist/tuist"), + serverURL: .value(Constants.URLs.production) + ) + .called(1) - // Then - verify(previewsUploadService) - .uploadPreviews( - .any, - displayName: .any, - version: .any, - bundleIdentifier: .any, - icon: .any, - supportedPlatforms: .any, - fullHandle: .value("tuist/tuist"), - serverURL: .value(Constants.URLs.production) + XCTAssertStandardOutput( + pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" ) - .called(1) - - XCTAssertStandardOutput( - pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" - ) + } } func test_share_different_apps() async throws { @@ -858,139 +869,143 @@ final class ShareServiceTests: TuistUnitTestCase { } func test_share_app_bundles() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test(fullHandle: "tuist/tuist")) - - let iosApp = try temporaryPath().appending(components: "iOS", "App.app") - let visionOSApp = try temporaryPath().appending(components: "visionOs", "App.app") - try await fileSystem.makeDirectory(at: iosApp) - let iosIconPath = iosApp.appending(component: "AppIcon60x60@2x.png") - try await fileSystem.touch(iosIconPath) - try await fileSystem.makeDirectory(at: visionOSApp) - - given(appBundleLoader) - .load(.value(iosApp)) - .willReturn( - .test( - path: iosApp, - infoPlist: .test( - name: "App", - bundleIcons: .test( - primaryIcon: .test( - iconFiles: [ - "AppIcon60x60", - ] + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test(fullHandle: "tuist/tuist")) + + let iosApp = try temporaryPath().appending(components: "iOS", "App.app") + let visionOSApp = try temporaryPath().appending(components: "visionOs", "App.app") + try await fileSystem.makeDirectory(at: iosApp) + let iosIconPath = iosApp.appending(component: "AppIcon60x60@2x.png") + try await fileSystem.touch(iosIconPath) + try await fileSystem.makeDirectory(at: visionOSApp) + + given(appBundleLoader) + .load(.value(iosApp)) + .willReturn( + .test( + path: iosApp, + infoPlist: .test( + name: "App", + bundleIcons: .test( + primaryIcon: .test( + iconFiles: [ + "AppIcon60x60", + ] + ) ) ) ) ) - ) - given(appBundleLoader) - .load(.value(visionOSApp)) - .willReturn(.test(infoPlist: .test(name: "App"))) - - // When - try await subject.run( - path: nil, - apps: [ - iosApp.pathString, - visionOSApp.pathString, - ], - configuration: nil, - platforms: [], - derivedDataPath: nil, - json: false - ) + given(appBundleLoader) + .load(.value(visionOSApp)) + .willReturn(.test(infoPlist: .test(name: "App"))) - // Then - verify(previewsUploadService) - .uploadPreviews( - .value(.appBundles([iosApp, visionOSApp])), - displayName: .value("App"), - version: .any, - bundleIdentifier: .any, - icon: .value(iosIconPath), - supportedPlatforms: .any, - fullHandle: .value("tuist/tuist"), - serverURL: .value(Constants.URLs.production) + // When + try await subject.run( + path: nil, + apps: [ + iosApp.pathString, + visionOSApp.pathString, + ], + configuration: nil, + platforms: [], + derivedDataPath: nil, + json: false ) - .called(1) - XCTAssertStandardOutput( - pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" - ) + // Then + verify(previewsUploadService) + .uploadPreviews( + .value(.appBundles([iosApp, visionOSApp])), + displayName: .value("App"), + version: .any, + bundleIdentifier: .any, + icon: .value(iosIconPath), + supportedPlatforms: .any, + fullHandle: .value("tuist/tuist"), + serverURL: .value(Constants.URLs.production) + ) + .called(1) + + XCTAssertStandardOutput( + pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" + ) + } } func test_share_ipa() async throws { - // Given - given(configLoader) - .loadConfig(path: .any) - .willReturn(.test(fullHandle: "tuist/tuist")) - - let ipaPath = try temporaryPath().appending(components: "App.ipa") - let payloadPath = try temporaryPath().appending(components: "Payload") - let appBundlePath = payloadPath.appending(components: "App.app") - let iconPath = appBundlePath.appending(component: "AppIcon60x60@2x.png") - try await fileSystem.makeDirectory(at: ipaPath) - try await fileSystem.makeDirectory(at: payloadPath) - try await fileSystem.makeDirectory(at: appBundlePath) - try await fileSystem.touch(iconPath) - given(fileUnarchiver) - .unzip() - .willReturn(payloadPath) - - given(appBundleLoader) - .load(.value(appBundlePath)) - .willReturn( - .test( - path: appBundlePath, - infoPlist: .test( - version: Version(1, 0, 0), - name: "App", - bundleId: "com.tuist.app", - bundleIcons: .test( - primaryIcon: .test( - iconFiles: [ - "AppIcon60x60", - ] + try await ServiceContext.withTestingDependencies { + // Given + given(configLoader) + .loadConfig(path: .any) + .willReturn(.test(fullHandle: "tuist/tuist")) + + let ipaPath = try temporaryPath().appending(components: "App.ipa") + let payloadPath = try temporaryPath().appending(components: "Payload") + let appBundlePath = payloadPath.appending(components: "App.app") + let iconPath = appBundlePath.appending(component: "AppIcon60x60@2x.png") + try await fileSystem.makeDirectory(at: ipaPath) + try await fileSystem.makeDirectory(at: payloadPath) + try await fileSystem.makeDirectory(at: appBundlePath) + try await fileSystem.touch(iconPath) + given(fileUnarchiver) + .unzip() + .willReturn(payloadPath) + + given(appBundleLoader) + .load(.value(appBundlePath)) + .willReturn( + .test( + path: appBundlePath, + infoPlist: .test( + version: Version(1, 0, 0), + name: "App", + bundleId: "com.tuist.app", + bundleIcons: .test( + primaryIcon: .test( + iconFiles: [ + "AppIcon60x60", + ] + ) ) ) ) ) + + // When + try await subject.run( + path: nil, + apps: [ + ipaPath.pathString, + ], + configuration: nil, + platforms: [], + derivedDataPath: nil, + json: false ) - // When - try await subject.run( - path: nil, - apps: [ - ipaPath.pathString, - ], - configuration: nil, - platforms: [], - derivedDataPath: nil, - json: false - ) + // Then + verify(previewsUploadService) + .uploadPreviews( + .value(.ipa(ipaPath)), + displayName: .value("App"), + version: .value("1.0.0"), + bundleIdentifier: .value("com.tuist.app"), + icon: .value(iconPath), + supportedPlatforms: .any, + fullHandle: .value("tuist/tuist"), + serverURL: .value(Constants.URLs.production) + ) + .called(1) - // Then - verify(previewsUploadService) - .uploadPreviews( - .value(.ipa(ipaPath)), - displayName: .value("App"), - version: .value("1.0.0"), - bundleIdentifier: .value("com.tuist.app"), - icon: .value(iconPath), - supportedPlatforms: .any, - fullHandle: .value("tuist/tuist"), - serverURL: .value(Constants.URLs.production) + XCTAssertStandardOutput( + pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" ) - .called(1) - - XCTAssertStandardOutput( - pattern: "App uploaded – share it with others using the following link: \(shareURL.absoluteString)" - ) + } } func test_share_ipa_when_it_does_not_contain_any_app_bundle() async throws { diff --git a/Tests/TuistKitTests/Services/TestServiceTests.swift b/Tests/TuistKitTests/Services/TestServiceTests.swift index 3475b89ac75..ddb24264137 100644 --- a/Tests/TuistKitTests/Services/TestServiceTests.swift +++ b/Tests/TuistKitTests/Services/TestServiceTests.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistAutomation import TuistCache import TuistCore @@ -567,35 +568,37 @@ final class TestServiceTests: TuistUnitTestCase { func test_run_tests_individual_scheme_with_no_test_actions() async throws { // Given - givenGenerator() - given(buildGraphInspector) - .testableSchemes(graphTraverser: .any) - .willReturn([]) - given(generator) - .generateWithGraph(path: .any) - .willProduce { path in - ( - path, - .test(workspace: .test(schemes: [.test(name: "ProjectSchemeOne", testAction: .test(targets: []))])), - MapperEnvironment() - ) - } - try fileHandler.touch( - testsCacheTemporaryDirectory.path.appending(component: "A") - ) - try fileHandler.touch( - testsCacheTemporaryDirectory.path.appending(component: "B") - ) + try await ServiceContext.withTestingDependencies { + givenGenerator() + given(buildGraphInspector) + .testableSchemes(graphTraverser: .any) + .willReturn([]) + given(generator) + .generateWithGraph(path: .any) + .willProduce { path in + ( + path, + .test(workspace: .test(schemes: [.test(name: "ProjectSchemeOne", testAction: .test(targets: []))])), + MapperEnvironment() + ) + } + try fileHandler.touch( + testsCacheTemporaryDirectory.path.appending(component: "A") + ) + try fileHandler.touch( + testsCacheTemporaryDirectory.path.appending(component: "B") + ) - // When - try await testRun( - schemeName: "ProjectSchemeOne", - path: try temporaryPath() - ) + // When + try await testRun( + schemeName: "ProjectSchemeOne", + path: try temporaryPath() + ) - // Then - XCTAssertStandardOutput(pattern: "The scheme ProjectSchemeOne's test action has no tests to run, finishing early.") - XCTAssertEmpty(testedSchemes) + // Then + XCTAssertStandardOutput(pattern: "The scheme ProjectSchemeOne's test action has no tests to run, finishing early.") + XCTAssertEmpty(testedSchemes) + } } func test_throws_when_scheme_does_not_exist_and_initial_graph_is_nil() async throws { @@ -670,361 +673,371 @@ final class TestServiceTests: TuistUnitTestCase { } func test_skips_running_tests_when_scheme_is_in_initial_graph_only() async throws { - // Given - givenGenerator() - var environment = MapperEnvironment() - environment.initialGraph = .test( - projects: [ - try temporaryPath(): .test(schemes: [.test(name: "ProjectSchemeOne")]), - ] - ) - given(generator) - .generateWithGraph(path: .any) - .willProduce { path in - ( - path, - .test(), - environment - ) - } + try await ServiceContext.withTestingDependencies { + // Given + givenGenerator() + var environment = MapperEnvironment() + environment.initialGraph = .test( + projects: [ + try temporaryPath(): .test(schemes: [.test(name: "ProjectSchemeOne")]), + ] + ) + given(generator) + .generateWithGraph(path: .any) + .willProduce { path in + ( + path, + .test(), + environment + ) + } - // When - try await testRun( - schemeName: "ProjectSchemeOne", - path: try temporaryPath() - ) + // When + try await testRun( + schemeName: "ProjectSchemeOne", + path: try temporaryPath() + ) - // Then - XCTAssertEmpty(testedSchemes) - XCTAssertStandardOutput(pattern: "The scheme ProjectSchemeOne's test action has no tests to run, finishing early.") + // Then + XCTAssertEmpty(testedSchemes) + XCTAssertStandardOutput(pattern: "The scheme ProjectSchemeOne's test action has no tests to run, finishing early.") + } } func test_skips_running_tests_when_all_tests_are_cached() async throws { - // Given - givenGenerator() - var environment = MapperEnvironment() - environment.initialGraph = .test( - projects: [ - try temporaryPath(): .test(schemes: [.test(name: "ProjectSchemeOne")]), - ] - ) - given(generator) - .generateWithGraph(path: .any) - .willProduce { path in - ( - path, - .test(), - environment - ) - } + try await ServiceContext.withTestingDependencies { + // Given + givenGenerator() + var environment = MapperEnvironment() + environment.initialGraph = .test( + projects: [ + try temporaryPath(): .test(schemes: [.test(name: "ProjectSchemeOne")]), + ] + ) + given(generator) + .generateWithGraph(path: .any) + .willProduce { path in + ( + path, + .test(), + environment + ) + } - // When - try await testRun( - path: try temporaryPath() - ) + // When + try await testRun( + path: try temporaryPath() + ) - // Then - XCTAssertEmpty(testedSchemes) - XCTAssertStandardOutput(pattern: "There are no tests to run, finishing early") + // Then + XCTAssertEmpty(testedSchemes) + XCTAssertStandardOutput(pattern: "There are no tests to run, finishing early") + } } func test_skips_running_tests_when_all_tests_are_cached_with_a_custom_result_bundle_path() async throws { - // Given - givenGenerator() - var environment = MapperEnvironment() - environment.initialGraph = .test( - projects: [ - try temporaryPath(): .test(schemes: [.test(name: "ProjectSchemeOne")]), - ] - ) - given(generator) - .generateWithGraph(path: .any) - .willProduce { path in - ( - path, - .test(), - environment - ) - } + try await ServiceContext.withTestingDependencies { + // Given + givenGenerator() + var environment = MapperEnvironment() + environment.initialGraph = .test( + projects: [ + try temporaryPath(): .test(schemes: [.test(name: "ProjectSchemeOne")]), + ] + ) + given(generator) + .generateWithGraph(path: .any) + .willProduce { path in + ( + path, + .test(), + environment + ) + } - let resultBundlePath = try temporaryPath() - .appending(component: "test.xcresult") + let resultBundlePath = try temporaryPath() + .appending(component: "test.xcresult") - // When - try await testRun( - path: try temporaryPath(), - resultBundlePath: resultBundlePath - ) + // When + try await testRun( + path: try temporaryPath(), + resultBundlePath: resultBundlePath + ) - // Then - XCTAssertEmpty(testedSchemes) - XCTAssertStandardOutput(pattern: "There are no tests to run, finishing early") + // Then + XCTAssertEmpty(testedSchemes) + XCTAssertStandardOutput(pattern: "There are no tests to run, finishing early") + } } func test_run_tests_when_part_is_cached() async throws { - // Given - givenGenerator() - given(configLoader) - .loadConfig(path: .any) - .willReturn(.default) - given(buildGraphInspector) - .testableSchemes(graphTraverser: .any) - .willReturn([]) - - let projectPathOne = try temporaryPath().appending(component: "ProjectOne") - let schemeOne = Scheme.test( - name: "ProjectSchemeOne", - testAction: .test( - targets: [ - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), - ] + try await ServiceContext.withTestingDependencies { + // Given + givenGenerator() + given(configLoader) + .loadConfig(path: .any) + .willReturn(.default) + given(buildGraphInspector) + .testableSchemes(graphTraverser: .any) + .willReturn([]) + + let projectPathOne = try temporaryPath().appending(component: "ProjectOne") + let schemeOne = Scheme.test( + name: "ProjectSchemeOne", + testAction: .test( + targets: [ + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), + ] + ) ) - ) - let schemeTwo = Scheme.test( - name: "ProjectSchemeTwo", - testAction: .test( - targets: [] + let schemeTwo = Scheme.test( + name: "ProjectSchemeTwo", + testAction: .test( + targets: [] + ) ) - ) - given(buildGraphInspector) - .workspaceSchemes(graphTraverser: .any) - .willReturn([schemeOne, schemeTwo]) - given(buildGraphInspector) - .testableTarget( - scheme: .any, - testPlan: .any, - testTargets: .any, - skipTestTargets: .any, - graphTraverser: .any + given(buildGraphInspector) + .workspaceSchemes(graphTraverser: .any) + .willReturn([schemeOne, schemeTwo]) + given(buildGraphInspector) + .testableTarget( + scheme: .any, + testPlan: .any, + testTargets: .any, + skipTestTargets: .any, + graphTraverser: .any + ) + .willReturn(.test()) + + var environment = MapperEnvironment() + environment.initialGraph = .test( + projects: [ + projectPathOne: .test( + path: projectPathOne, + targets: [ + .test(name: "TargetA", bundleId: "io.tuist.TargetA"), + .test(name: "TargetB", bundleId: "io.tuist.TargetB"), + .test(name: "TargetC", bundleId: "io.tuist.TargetC"), + ], + schemes: [ + .test( + name: "ProjectSchemeOne", + testAction: .test( + targets: [ + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetB")), + ] + ) + ), + .test( + name: "ProjectSchemeTwo", + testAction: .test( + targets: [ + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetC")), + ] + ) + ), + ] + ), + ] ) - .willReturn(.test()) - - var environment = MapperEnvironment() - environment.initialGraph = .test( - projects: [ - projectPathOne: .test( - path: projectPathOne, - targets: [ - .test(name: "TargetA", bundleId: "io.tuist.TargetA"), - .test(name: "TargetB", bundleId: "io.tuist.TargetB"), - .test(name: "TargetC", bundleId: "io.tuist.TargetC"), - ], - schemes: [ - .test( - name: "ProjectSchemeOne", - testAction: .test( - targets: [ - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetB")), - ] - ) - ), + environment.targetTestHashes = [ + projectPathOne: [ + "TargetA": "hash-a", + "TargetB": "hash-b", + "TargetC": "hash-c", + ], + ] + environment.targetCacheItems = [ + projectPathOne: [ + "TargetB": .test( + source: .local, + cacheCategory: .selectiveTests + ), + "TargetC": .test( + source: .remote, + cacheCategory: .selectiveTests + ), + ], + ] + given(generator) + .generateWithGraph(path: .any) + .willProduce { path in + ( + path, .test( - name: "ProjectSchemeTwo", - testAction: .test( - targets: [ - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetC")), - ] - ) + projects: [ + projectPathOne: .test( + path: projectPathOne, + targets: [ + .test(name: "TargetA"), + .test(name: "TargetB"), + ], + schemes: [schemeOne, schemeTwo] + ), + ] ), - ] - ), - ] - ) - environment.targetTestHashes = [ - projectPathOne: [ - "TargetA": "hash-a", - "TargetB": "hash-b", - "TargetC": "hash-c", - ], - ] - environment.targetCacheItems = [ - projectPathOne: [ - "TargetB": .test( - source: .local, - cacheCategory: .selectiveTests - ), - "TargetC": .test( - source: .remote, - cacheCategory: .selectiveTests - ), - ], - ] - given(generator) - .generateWithGraph(path: .any) - .willProduce { path in - ( - path, - .test( - projects: [ - projectPathOne: .test( - path: projectPathOne, - targets: [ - .test(name: "TargetA"), - .test(name: "TargetB"), - ], - schemes: [schemeOne, schemeTwo] - ), + environment + ) + } + + // When + try await testRun( + path: try temporaryPath() + ) + + // Then + XCTAssertEqual(testedSchemes, ["ProjectSchemeOne"]) + XCTAssertStandardOutput( + pattern: "The following targets have not changed since the last successful run and will be skipped: TargetB, TargetC" + ) + verify(analyticsDelegate) + .selectiveTestsAnalytics( + newValue: .value( + SelectiveTestsAnalytics( + testTargets: ["TargetA", "TargetB", "TargetC"], + localTestTargetHits: ["TargetB"], + remoteTestTargetHits: ["TargetC"] + ) + ) + ) + .setCalled(1) + verify(cacheStorage) + .store( + .value( + [ + CacheStorableItem(name: "TargetA", hash: "hash-a"): [], ] ), - environment + cacheCategory: .value(.selectiveTests) ) - } + .called(1) + } + } - // When - try await testRun( - path: try temporaryPath() - ) + func test_run_tests_when_part_is_cached_and_scheme_is_passed() async throws { + try await ServiceContext.withTestingDependencies { + // Given + givenGenerator() - // Then - XCTAssertEqual(testedSchemes, ["ProjectSchemeOne"]) - XCTAssertStandardOutput( - pattern: "The following targets have not changed since the last successful run and will be skipped: TargetB, TargetC" - ) - verify(analyticsDelegate) - .selectiveTestsAnalytics( - newValue: .value( - SelectiveTestsAnalytics( - testTargets: ["TargetA", "TargetB", "TargetC"], - localTestTargetHits: ["TargetB"], - remoteTestTargetHits: ["TargetC"] - ) + let projectPathOne = try temporaryPath().appending(component: "ProjectOne") + let schemeOne = Scheme.test( + name: "ProjectSchemeOne", + testAction: .test( + targets: [ + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), + ] ) ) - .setCalled(1) - verify(cacheStorage) - .store( - .value( - [ - CacheStorableItem(name: "TargetA", hash: "hash-a"): [], + let schemeTwo = Scheme.test( + name: "ProjectSchemeTwo", + testAction: .test( + targets: [ + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetD")), ] - ), - cacheCategory: .value(.selectiveTests) + ) ) - .called(1) - } - - func test_run_tests_when_part_is_cached_and_scheme_is_passed() async throws { - // Given - givenGenerator() - let projectPathOne = try temporaryPath().appending(component: "ProjectOne") - let schemeOne = Scheme.test( - name: "ProjectSchemeOne", - testAction: .test( - targets: [ - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), + given(buildGraphInspector) + .workspaceSchemes(graphTraverser: .any) + .willReturn([schemeOne, schemeTwo]) + given(buildGraphInspector) + .testableTarget( + scheme: .any, + testPlan: .any, + testTargets: .any, + skipTestTargets: .any, + graphTraverser: .any + ) + .willReturn(.test()) + var environment = MapperEnvironment() + environment.initialGraph = .test( + projects: [ + projectPathOne: .test( + path: projectPathOne, + targets: [ + .test(name: "TargetA", bundleId: "io.tuist.TargetA"), + .test(name: "TargetB", bundleId: "io.tuist.TargetB"), + .test(name: "TargetC", bundleId: "io.tuist.TargetC"), + .test(name: "TargetD", bundleId: "io.tuist.TargetD"), + ], + schemes: [ + .test( + name: "ProjectSchemeOne", + testAction: .test( + targets: [ + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetB")), + ] + ) + ), + .test( + name: "ProjectSchemeTwo", + testAction: .test( + targets: [ + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetC")), + .test(target: TargetReference(projectPath: projectPathOne, name: "TargetD")), + ] + ) + ), + ] + ), ] ) - ) - let schemeTwo = Scheme.test( - name: "ProjectSchemeTwo", - testAction: .test( - targets: [ - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetD")), - ] + environment.targetTestHashes = [ + projectPathOne: [ + "TargetA": "hash-a", + "TargetB": "hash-b", + "TargetC": "hash-c", + "TargetD": "hash-d", + ], + ] + given(generator) + .generateWithGraph(path: .any) + .willProduce { path in + ( + path, + .test( + projects: [ + projectPathOne: .test( + path: projectPathOne, + targets: [ + .test(name: "TargetA"), + .test(name: "TargetB"), + .test(name: "TargetC"), + .test(name: "TargetD"), + ], + schemes: [schemeOne, schemeTwo] + ), + ] + ), + environment + ) + } + + // When + try await testRun( + schemeName: "ProjectSchemeTwo", + path: try temporaryPath() ) - ) - given(buildGraphInspector) - .workspaceSchemes(graphTraverser: .any) - .willReturn([schemeOne, schemeTwo]) - given(buildGraphInspector) - .testableTarget( - scheme: .any, - testPlan: .any, - testTargets: .any, - skipTestTargets: .any, - graphTraverser: .any + // Then + XCTAssertEqual(testedSchemes, ["ProjectSchemeTwo"]) + XCTAssertStandardOutput( + pattern: "The following targets have not changed since the last successful run and will be skipped: TargetC" ) - .willReturn(.test()) - var environment = MapperEnvironment() - environment.initialGraph = .test( - projects: [ - projectPathOne: .test( - path: projectPathOne, - targets: [ - .test(name: "TargetA", bundleId: "io.tuist.TargetA"), - .test(name: "TargetB", bundleId: "io.tuist.TargetB"), - .test(name: "TargetC", bundleId: "io.tuist.TargetC"), - .test(name: "TargetD", bundleId: "io.tuist.TargetD"), - ], - schemes: [ - .test( - name: "ProjectSchemeOne", - testAction: .test( - targets: [ - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetA")), - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetB")), - ] - ) - ), - .test( - name: "ProjectSchemeTwo", - testAction: .test( - targets: [ - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetC")), - .test(target: TargetReference(projectPath: projectPathOne, name: "TargetD")), - ] - ) - ), - ] - ), - ] - ) - environment.targetTestHashes = [ - projectPathOne: [ - "TargetA": "hash-a", - "TargetB": "hash-b", - "TargetC": "hash-c", - "TargetD": "hash-d", - ], - ] - given(generator) - .generateWithGraph(path: .any) - .willProduce { path in - ( - path, - .test( - projects: [ - projectPathOne: .test( - path: projectPathOne, - targets: [ - .test(name: "TargetA"), - .test(name: "TargetB"), - .test(name: "TargetC"), - .test(name: "TargetD"), - ], - schemes: [schemeOne, schemeTwo] - ), + verify(cacheStorage) + .store( + .value( + [ + CacheStorableItem(name: "TargetD", hash: "hash-d"): [], ] ), - environment + cacheCategory: .value(.selectiveTests) ) - } - - // When - try await testRun( - schemeName: "ProjectSchemeTwo", - path: try temporaryPath() - ) - - // Then - XCTAssertEqual(testedSchemes, ["ProjectSchemeTwo"]) - XCTAssertStandardOutput( - pattern: "The following targets have not changed since the last successful run and will be skipped: TargetC" - ) - verify(cacheStorage) - .store( - .value( - [ - CacheStorableItem(name: "TargetD", hash: "hash-d"): [], - ] - ), - cacheCategory: .value(.selectiveTests) - ) - .called(1) + .called(1) + } } func test_run_tests_with_skipped_targets() async throws { @@ -1131,26 +1144,28 @@ final class TestServiceTests: TuistUnitTestCase { } func test_run_tests_when_no_project_schemes_present() async throws { - // Given - givenGenerator() - - let graph: Graph = .test() - var environment = MapperEnvironment() - environment.initialGraph = graph - given(generator) - .generateWithGraph(path: .any) - .willProduce { path in - (path, .test(), environment) - } + try await ServiceContext.withTestingDependencies { + // Given + givenGenerator() + + let graph: Graph = .test() + var environment = MapperEnvironment() + environment.initialGraph = graph + given(generator) + .generateWithGraph(path: .any) + .willProduce { path in + (path, .test(), environment) + } - // When - try await testRun( - path: try temporaryPath() - ) + // When + try await testRun( + path: try temporaryPath() + ) - // Then - XCTAssertEmpty(testedSchemes) - XCTAssertPrinterOutputContains("There are no tests to run, finishing early") + // Then + XCTAssertEmpty(testedSchemes) + XCTAssertPrinterOutputContains("There are no tests to run, finishing early") + } } func test_run_uses_resource_bundle_path() async throws { diff --git a/Tests/TuistKitTests/Services/WhoamiServiceTests.swift b/Tests/TuistKitTests/Services/WhoamiServiceTests.swift index e24e0860870..886c00de7e7 100644 --- a/Tests/TuistKitTests/Services/WhoamiServiceTests.swift +++ b/Tests/TuistKitTests/Services/WhoamiServiceTests.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistCore import TuistCoreTesting import TuistLoader @@ -40,28 +41,32 @@ final class WhoamiServiceTests: TuistUnitTestCase { } func test_whoami_when_logged_in() async throws { - // Given - given(serverSessionController) - .whoami(serverURL: .value(serverURL)) - .willReturn("tuist@tuist.io") + try await ServiceContext.withTestingDependencies { + // Given + given(serverSessionController) + .whoami(serverURL: .value(serverURL)) + .willReturn("tuist@tuist.io") - // When - try await subject.run(directory: nil) + // When + try await subject.run(directory: nil) - // Then - XCTAssertPrinterOutputContains("tuist@tuist.io") + // Then + XCTAssertPrinterOutputContains("tuist@tuist.io") + } } func test_whoami_when_logged_out() async throws { - // Given - given(serverSessionController) - .whoami(serverURL: .value(serverURL)) - .willReturn(nil) + try await ServiceContext.withTestingDependencies { + // Given + given(serverSessionController) + .whoami(serverURL: .value(serverURL)) + .willReturn(nil) - // When - try await subject.run(directory: nil) + // When + try await subject.run(directory: nil) - // Then - XCTAssertPrinterOutputContains("You are not logged in.") + // Then + XCTAssertPrinterOutputContains("You are not logged in.") + } } } diff --git a/Tests/TuistKitTests/Utils/TuistAnalyticsServerBackendTests.swift b/Tests/TuistKitTests/Utils/TuistAnalyticsServerBackendTests.swift index f152290635f..5caf72dae16 100644 --- a/Tests/TuistKitTests/Utils/TuistAnalyticsServerBackendTests.swift +++ b/Tests/TuistKitTests/Utils/TuistAnalyticsServerBackendTests.swift @@ -1,5 +1,6 @@ import FileSystem import Mockable +import ServiceContextModule import TuistAnalytics import TuistCore import TuistCoreTesting @@ -47,107 +48,113 @@ final class TuistAnalyticsServerBackendTests: TuistUnitTestCase { } func test_send_when_is_not_ci() async throws { - // Given - given(cacheDirectoriesProvider) - .cacheDirectory(for: .value(.runs)) - .willReturn(try temporaryPath()) - given(ciChecker) - .isCI() - .willReturn(false) - let event = CommandEvent.test() - given(createCommandEventService) - .createCommandEvent( - commandEvent: .value(event), - projectId: .value(fullHandle), - serverURL: .value(Constants.URLs.production) - ) - .willReturn( - .test( - id: 10, - url: URL(string: "https://tuist.dev/tuist-org/tuist/runs/10")! + try await ServiceContext.withTestingDependencies { + // Given + given(cacheDirectoriesProvider) + .cacheDirectory(for: .value(.runs)) + .willReturn(try temporaryPath()) + given(ciChecker) + .isCI() + .willReturn(false) + let event = CommandEvent.test() + given(createCommandEventService) + .createCommandEvent( + commandEvent: .value(event), + projectId: .value(fullHandle), + serverURL: .value(Constants.URLs.production) + ) + .willReturn( + .test( + id: 10, + url: URL(string: "https://tuist.dev/tuist-org/tuist/runs/10")! + ) ) - ) - // When - try await subject.send(commandEvent: event) + // When + try await subject.send(commandEvent: event) - // Then - XCTAssertPrinterOutputNotContains("You can view a detailed report at: https://tuist.dev/tuist-org/tuist/runs/10") + // Then + XCTAssertPrinterOutputNotContains("You can view a detailed report at: https://tuist.dev/tuist-org/tuist/runs/10") + } } func test_send_when_is_ci() async throws { - // Given - given(cacheDirectoriesProvider) - .cacheDirectory(for: .value(.runs)) - .willReturn(try temporaryPath()) - given(ciChecker) - .isCI() - .willReturn(true) - let event = CommandEvent.test() - given(createCommandEventService) - .createCommandEvent( - commandEvent: .value(event), - projectId: .value(fullHandle), - serverURL: .value(Constants.URLs.production) - ) - .willReturn( - .test( - id: 10, - url: URL(string: "https://tuist.dev/tuist-org/tuist/runs/10")! + try await ServiceContext.withTestingDependencies { + // Given + given(cacheDirectoriesProvider) + .cacheDirectory(for: .value(.runs)) + .willReturn(try temporaryPath()) + given(ciChecker) + .isCI() + .willReturn(true) + let event = CommandEvent.test() + given(createCommandEventService) + .createCommandEvent( + commandEvent: .value(event), + projectId: .value(fullHandle), + serverURL: .value(Constants.URLs.production) + ) + .willReturn( + .test( + id: 10, + url: URL(string: "https://tuist.dev/tuist-org/tuist/runs/10")! + ) ) - ) - // When - try await subject.send(commandEvent: event) + // When + try await subject.send(commandEvent: event) - // Then - XCTAssertStandardOutput(pattern: "You can view a detailed report at: https://tuist.dev/tuist-org/tuist/runs/10") + // Then + XCTAssertStandardOutput(pattern: "You can view a detailed report at: https://tuist.dev/tuist-org/tuist/runs/10") + } } func test_send_when_is_ci_and_result_bundle_exists() async throws { - // Given - given(ciChecker) - .isCI() - .willReturn(true) - let event = CommandEvent.test() - given(createCommandEventService) - .createCommandEvent( - commandEvent: .value(event), - projectId: .value(fullHandle), - serverURL: .value(Constants.URLs.production) - ) - .willReturn( - .test( - id: 10, - url: URL(string: "https://tuist.dev/tuist-org/tuist/runs/10")! + try await ServiceContext.withTestingDependencies { + // Given + given(ciChecker) + .isCI() + .willReturn(true) + let event = CommandEvent.test() + given(createCommandEventService) + .createCommandEvent( + commandEvent: .value(event), + projectId: .value(fullHandle), + serverURL: .value(Constants.URLs.production) + ) + .willReturn( + .test( + id: 10, + url: URL(string: "https://tuist.dev/tuist-org/tuist/runs/10")! + ) ) - ) - given(cacheDirectoriesProvider) - .cacheDirectory(for: .value(.runs)) - .willReturn(try temporaryPath()) + given(cacheDirectoriesProvider) + .cacheDirectory(for: .value(.runs)) + .willReturn(try temporaryPath()) - let resultBundle = try cacheDirectoriesProvider - .cacheDirectory(for: .runs) - .appending(components: event.runId, "\(Constants.resultBundleName).xcresult") - try fileHandler.createFolder(resultBundle) + let resultBundle = try cacheDirectoriesProvider + .cacheDirectory(for: .runs) + .appending(components: event.runId, "\(Constants.resultBundleName).xcresult") + try fileHandler.createFolder(resultBundle) - given(analyticsArtifactUploadService) - .uploadResultBundle( - .value(resultBundle), - targetHashes: .any, - graphPath: .any, - commandEventId: .value(10), - serverURL: .value(Constants.URLs.production) - ) - .willReturn(()) + given(analyticsArtifactUploadService) + .uploadResultBundle( + .value(resultBundle), + targetHashes: .any, + graphPath: .any, + commandEventId: .value(10), + serverURL: .value(Constants.URLs.production) + ) + .willReturn(()) - // When - try await subject.send(commandEvent: event) + // When + try await subject.send(commandEvent: event) - // Then - XCTAssertStandardOutput(pattern: "You can view a detailed report at: https://tuist.dev/tuist-org/tuist/runs/10") - let exists = try await fileSystem.exists(resultBundle) - XCTAssertFalse(exists) + // Then + XCTAssertStandardOutput(pattern: "You can view a detailed report at: https://tuist.dev/tuist-org/tuist/runs/10") + let exists = try await fileSystem.exists(resultBundle) + XCTAssertFalse(exists) + } } } diff --git a/Tests/TuistLoaderTests/Loaders/ManifestModelConverterTests.swift b/Tests/TuistLoaderTests/Loaders/ManifestModelConverterTests.swift index 0e0a9969089..3da11922207 100644 --- a/Tests/TuistLoaderTests/Loaders/ManifestModelConverterTests.swift +++ b/Tests/TuistLoaderTests/Loaders/ManifestModelConverterTests.swift @@ -1,8 +1,10 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistCore import TuistSupport +import XcodeGraph import XCTest @testable import ProjectDescription @@ -302,21 +304,32 @@ final class ManifestModelConverterTests: TuistUnitTestCase { } func test_loadWorkspace_withInvalidProjectsPaths() async throws { - // Given - let temporaryPath = try temporaryPath() - let manifest = WorkspaceManifest.test(name: "SomeWorkspace", projects: ["A", "B"]) - let manifestLoader = makeManifestLoader(with: [ - temporaryPath: manifest, - ]) - let subject = makeSubject(with: manifestLoader) - - // When - let model = try await subject.convert(manifest: manifest, path: temporaryPath) - - // Then - XCTAssertPrinterOutputContains("No projects found at: A") - XCTAssertPrinterOutputContains("No projects found at: B") - XCTAssertEqual(model.projects, []) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + + try await fileSystem.makeDirectory(at: rootDirectory.appending(component: "Resources")) + + let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Resources/**") + + // When + let model = try await XcodeGraph.ResourceFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) + + // Then + XCTAssertPrinterOutputContains( + "No files found at: \(rootDirectory.appending(components: "Resources", "**"))" + ) + XCTAssertEqual(model, []) + } } // MARK: - Helpers diff --git a/Tests/TuistLoaderTests/Loaders/SwiftPackageManagerGraphLoaderTests.swift b/Tests/TuistLoaderTests/Loaders/SwiftPackageManagerGraphLoaderTests.swift index b4731fe3b63..ed431ffed33 100644 --- a/Tests/TuistLoaderTests/Loaders/SwiftPackageManagerGraphLoaderTests.swift +++ b/Tests/TuistLoaderTests/Loaders/SwiftPackageManagerGraphLoaderTests.swift @@ -1,4 +1,5 @@ import Mockable +import ServiceContextModule import TuistCore import TuistSupport import TuistSupportTesting @@ -34,89 +35,93 @@ final class SwiftPackageManagerGraphLoaderTests: TuistUnitTestCase { } func test_load() async throws { - // Given - let temporaryPath = try temporaryPath() - let packageSettings = PackageSettings.test() - - let workspacePath = temporaryPath.appending(components: [".build", "workspace-state.json"]) - try fileHandler.createFolder(workspacePath.parentDirectory) - try fileHandler.write( - """ - { - "object" : { - "artifacts" : [], - "dependencies" : [] - } - } - """, - path: workspacePath, - atomically: true - ) - - try fileHandler.touch(temporaryPath.appending(components: [".build", "Derived", "Package.resolved"])) - try fileHandler.touch(temporaryPath.appending(component: "Package.resolved")) - - given(packageInfoMapper) - .resolveExternalDependencies( - packageInfos: .any, - packageToFolder: .any, - packageToTargetsToArtifactPaths: .any, - packageModuleAliases: .any + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let packageSettings = PackageSettings.test() + + let workspacePath = temporaryPath.appending(components: [".build", "workspace-state.json"]) + try fileHandler.createFolder(workspacePath.parentDirectory) + try fileHandler.write( + """ + { + "object" : { + "artifacts" : [], + "dependencies" : [] + } + } + """, + path: workspacePath, + atomically: true ) - .willReturn([:]) - // When - let _ = try await subject.load( - packagePath: temporaryPath.appending(component: "Package.swift"), - packageSettings: packageSettings - ) + try fileHandler.touch(temporaryPath.appending(components: [".build", "Derived", "Package.resolved"])) + try fileHandler.touch(temporaryPath.appending(component: "Package.resolved")) + + given(packageInfoMapper) + .resolveExternalDependencies( + packageInfos: .any, + packageToFolder: .any, + packageToTargetsToArtifactPaths: .any, + packageModuleAliases: .any + ) + .willReturn([:]) + + // When + let _ = try await subject.load( + packagePath: temporaryPath.appending(component: "Package.swift"), + packageSettings: packageSettings + ) - // Then - XCTAssertPrinterOutputNotContains("We detected outdated dependencies. Please run \"tuist install\" to update them.") + // Then + XCTAssertPrinterOutputNotContains("We detected outdated dependencies. Please run \"tuist install\" to update them.") + } } func test_load_warnOutdatedDependencies() async throws { - // Given - let temporaryPath = try temporaryPath() - let packageSettings = PackageSettings.test() - - let workspacePath = temporaryPath.appending(components: [".build", "workspace-state.json"]) - try fileHandler.createFolder(workspacePath.parentDirectory) - try fileHandler.write( - """ - { - "object" : { - "artifacts" : [], - "dependencies" : [] - } - } - """, - path: workspacePath, - atomically: true - ) - - let savedPackageResolvedPath = temporaryPath.appending(components: [".build", "Derived", "Package.resolved"]) - let currentPackageResolvedPath = temporaryPath.appending(component: "Package.resolved") - try fileHandler.touch(savedPackageResolvedPath) - try fileHandler.write("outdated", path: savedPackageResolvedPath, atomically: true) - try fileHandler.touch(currentPackageResolvedPath) - - given(packageInfoMapper) - .resolveExternalDependencies( - packageInfos: .any, - packageToFolder: .any, - packageToTargetsToArtifactPaths: .any, - packageModuleAliases: .any + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let packageSettings = PackageSettings.test() + + let workspacePath = temporaryPath.appending(components: [".build", "workspace-state.json"]) + try fileHandler.createFolder(workspacePath.parentDirectory) + try fileHandler.write( + """ + { + "object" : { + "artifacts" : [], + "dependencies" : [] + } + } + """, + path: workspacePath, + atomically: true ) - .willReturn([:]) - // When - let _ = try await subject.load( - packagePath: temporaryPath.appending(component: "Package.swift"), - packageSettings: packageSettings - ) + let savedPackageResolvedPath = temporaryPath.appending(components: [".build", "Derived", "Package.resolved"]) + let currentPackageResolvedPath = temporaryPath.appending(component: "Package.resolved") + try fileHandler.touch(savedPackageResolvedPath) + try fileHandler.write("outdated", path: savedPackageResolvedPath, atomically: true) + try fileHandler.touch(currentPackageResolvedPath) + + given(packageInfoMapper) + .resolveExternalDependencies( + packageInfos: .any, + packageToFolder: .any, + packageToTargetsToArtifactPaths: .any, + packageModuleAliases: .any + ) + .willReturn([:]) + + // When + let _ = try await subject.load( + packagePath: temporaryPath.appending(component: "Package.swift"), + packageSettings: packageSettings + ) - // Then - XCTAssertPrinterOutputContains("We detected outdated dependencies. Please run \"tuist install\" to update them.") + // Then + XCTAssertPrinterOutputContains("We detected outdated dependencies. Please run \"tuist install\" to update them.") + } } } diff --git a/Tests/TuistLoaderTests/Models+ManifestMappers/CopyFileElement+ManifestMapperTests.swift b/Tests/TuistLoaderTests/Models+ManifestMappers/CopyFileElement+ManifestMapperTests.swift index de42c744ebc..4087fcb0b60 100644 --- a/Tests/TuistLoaderTests/Models+ManifestMappers/CopyFileElement+ManifestMapperTests.swift +++ b/Tests/TuistLoaderTests/Models+ManifestMappers/CopyFileElement+ManifestMapperTests.swift @@ -1,6 +1,7 @@ import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -11,82 +12,88 @@ import XCTest final class CopyFileElementManifestMapperTests: TuistUnitTestCase { func test_from_outputs_a_warning_when_the_paths_point_to_directories() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - try await createFiles([ - "Documentation/README.md", - "Documentation/USAGE.md", - ]) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + try await createFiles([ + "Documentation/README.md", + "Documentation/USAGE.md", + ]) - let manifest = ProjectDescription.CopyFileElement.glob(pattern: "Documentation") + let manifest = ProjectDescription.CopyFileElement.glob(pattern: "Documentation") - // When - let model = try await XcodeGraph.CopyFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem, - includeFiles: { !FileHandler.shared.isFolder($0) } - ) + // When + let model = try await XcodeGraph.CopyFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem, + includeFiles: { !FileHandler.shared.isFolder($0) } + ) - // Then - let documentationPath = temporaryPath.appending(component: "Documentation").pathString - XCTAssertPrinterOutputContains( - "'\(documentationPath)' is a directory, try using: '\(documentationPath)/**' to list its files" - ) - XCTAssertEqual(model, []) + // Then + let documentationPath = temporaryPath.appending(component: "Documentation").pathString + XCTAssertPrinterOutputContains( + "'\(documentationPath)' is a directory, try using: '\(documentationPath)/**' to list its files" + ) + XCTAssertEqual(model, []) + } } func test_from_outputs_a_warning_when_the_folder_reference_is_invalid() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - try await createFiles([ - "README.md", - ]) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + try await createFiles([ + "README.md", + ]) - let manifest = ProjectDescription.CopyFileElement.folderReference(path: "README.md") + let manifest = ProjectDescription.CopyFileElement.folderReference(path: "README.md") - // When - let model = try await XcodeGraph.CopyFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) + // When + let model = try await XcodeGraph.CopyFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) - // Then - XCTAssertPrinterOutputContains("README.md is not a directory - folder reference paths need to point to directories") - XCTAssertEqual(model, []) + // Then + XCTAssertPrinterOutputContains("README.md is not a directory - folder reference paths need to point to directories") + XCTAssertEqual(model, []) + } } func test_copyFileElement_warning_withMissingFolderReference() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - let manifest = ProjectDescription.CopyFileElement.folderReference(path: "Documentation") + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + let manifest = ProjectDescription.CopyFileElement.folderReference(path: "Documentation") - // When - let model = try await XcodeGraph.CopyFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) + // When + let model = try await XcodeGraph.CopyFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) - // Then - XCTAssertPrinterOutputContains("Documentation does not exist") - XCTAssertEqual(model, []) + // Then + XCTAssertPrinterOutputContains("Documentation does not exist") + XCTAssertEqual(model, []) + } } func test_throws_when_the_glob_is_invalid() async throws { diff --git a/Tests/TuistLoaderTests/Models+ManifestMappers/FileElement+ManifestMapperTests.swift b/Tests/TuistLoaderTests/Models+ManifestMappers/FileElement+ManifestMapperTests.swift index 00db0fa60a9..fe2db0489a5 100644 --- a/Tests/TuistLoaderTests/Models+ManifestMappers/FileElement+ManifestMapperTests.swift +++ b/Tests/TuistLoaderTests/Models+ManifestMappers/FileElement+ManifestMapperTests.swift @@ -1,6 +1,7 @@ import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -11,34 +12,36 @@ import XCTest final class FileElementManifestMapperTests: TuistUnitTestCase { func test_from_outputs_a_warning_when_the_paths_point_to_directories() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - try await createFiles([ - "Documentation/README.md", - "Documentation/USAGE.md", - ]) - - let manifest = ProjectDescription.FileElement.glob(pattern: "Documentation") - - // When - let model = try await XcodeGraph.FileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem, - includeFiles: { !FileHandler.shared.isFolder($0) } - ) - - // Then - let documentationPath = temporaryPath.appending(component: "Documentation").pathString - XCTAssertPrinterOutputContains( - "'\(documentationPath)' is a directory, try using: '\(documentationPath)/**' to list its files" - ) - XCTAssertEqual(model, []) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + try await createFiles([ + "Documentation/README.md", + "Documentation/USAGE.md", + ]) + + let manifest = ProjectDescription.FileElement.glob(pattern: "Documentation") + + // When + let model = try await XcodeGraph.FileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem, + includeFiles: { !FileHandler.shared.isFolder($0) } + ) + + // Then + let documentationPath = temporaryPath.appending(component: "Documentation").pathString + XCTAssertPrinterOutputContains( + "'\(documentationPath)' is a directory, try using: '\(documentationPath)/**' to list its files" + ) + XCTAssertEqual(model, []) + } } func test_from_with_hidden_files() async throws { @@ -68,51 +71,55 @@ final class FileElementManifestMapperTests: TuistUnitTestCase { } func test_from_outputs_a_warning_when_the_folder_reference_is_invalid() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - try await createFiles([ - "README.md", - ]) - - let manifest = ProjectDescription.FileElement.folderReference(path: "README.md") - - // When - let model = try await XcodeGraph.FileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + try await createFiles([ + "README.md", + ]) + + let manifest = ProjectDescription.FileElement.folderReference(path: "README.md") + + // When + let model = try await XcodeGraph.FileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) - // Then - XCTAssertPrinterOutputContains("README.md is not a directory - folder reference paths need to point to directories") - XCTAssertEqual(model, []) + // Then + XCTAssertPrinterOutputContains("README.md is not a directory - folder reference paths need to point to directories") + XCTAssertEqual(model, []) + } } func test_fileElement_warning_withMissingFolderReference() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - let manifest = ProjectDescription.FileElement.folderReference(path: "Documentation") - - // When - let model = try await XcodeGraph.FileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + let manifest = ProjectDescription.FileElement.folderReference(path: "Documentation") + + // When + let model = try await XcodeGraph.FileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) - // Then - XCTAssertPrinterOutputContains("Documentation does not exist") - XCTAssertEqual(model, []) + // Then + XCTAssertPrinterOutputContains("Documentation does not exist") + XCTAssertEqual(model, []) + } } func test_throws_when_the_glob_is_invalid() async throws { diff --git a/Tests/TuistLoaderTests/Models+ManifestMappers/ResourceFileElementManifestMapperTests.swift b/Tests/TuistLoaderTests/Models+ManifestMappers/ResourceFileElementManifestMapperTests.swift index bb253139a2d..2ce04f924fb 100644 --- a/Tests/TuistLoaderTests/Models+ManifestMappers/ResourceFileElementManifestMapperTests.swift +++ b/Tests/TuistLoaderTests/Models+ManifestMappers/ResourceFileElementManifestMapperTests.swift @@ -1,6 +1,7 @@ import Foundation import Path import ProjectDescription +import ServiceContextModule import TuistCore import TuistSupport import XcodeGraph @@ -11,171 +12,183 @@ import XCTest final class ResourceFileElementManifestMapperTests: TuistUnitTestCase { func test_from_outputs_a_warning_when_the_paths_point_to_directories() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - try await createFiles([ - "Documentation/README.md", - "Documentation/USAGE.md", - ]) - - let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Documentation") - - // When - let model = try await XcodeGraph.ResourceFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem, - includeFiles: { !FileHandler.shared.isFolder($0) } - ) - - // Then - let documentationPath = temporaryPath.appending(component: "Documentation").pathString - XCTAssertPrinterOutputContains( - "'\(documentationPath)' is a directory, try using: '\(documentationPath)/**' to list its files" - ) - XCTAssertEqual(model, []) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + try await createFiles([ + "Documentation/README.md", + "Documentation/USAGE.md", + ]) + + let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Documentation") + + // When + let model = try await XcodeGraph.ResourceFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem, + includeFiles: { !FileHandler.shared.isFolder($0) } + ) + + // Then + let documentationPath = temporaryPath.appending(component: "Documentation").pathString + XCTAssertPrinterOutputContains( + "'\(documentationPath)' is a directory, try using: '\(documentationPath)/**' to list its files" + ) + XCTAssertEqual(model, []) + } } func test_from_outputs_a_warning_when_no_files_found() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) - try await fileSystem.makeDirectory(at: rootDirectory.appending(component: "Resources")) + try await fileSystem.makeDirectory(at: rootDirectory.appending(component: "Resources")) - let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Resources/**") + let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Resources/**") - // When - let model = try await XcodeGraph.ResourceFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) - - // Then - XCTAssertPrinterOutputContains( - "No files found at: \(rootDirectory.appending(components: "Resources", "**"))" - ) - XCTAssertEqual(model, []) + // When + let model = try await XcodeGraph.ResourceFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) + + // Then + XCTAssertPrinterOutputContains( + "No files found at: \(rootDirectory.appending(components: "Resources", "**"))" + ) + XCTAssertEqual(model, []) + } } func test_from_outputs_a_warning_when_no_files_found_in_opaque_directory() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - - let assetsDirectory = rootDirectory.appending(components: "Resources", "Assets.xcassets") - try await fileSystem.makeDirectory(at: assetsDirectory) - - let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Resources/Assets.xcassets/**") - - // When - let model = try await XcodeGraph.ResourceFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) - - // Then - XCTAssertPrinterOutputContains( - "No files found at: \(assetsDirectory.appending(components: "**"))" - ) - XCTAssertEqual(model, []) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + + let assetsDirectory = rootDirectory.appending(components: "Resources", "Assets.xcassets") + try await fileSystem.makeDirectory(at: assetsDirectory) + + let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Resources/Assets.xcassets/**") + + // When + let model = try await XcodeGraph.ResourceFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) + + // Then + XCTAssertPrinterOutputContains( + "No files found at: \(assetsDirectory.appending(components: "**"))" + ) + XCTAssertEqual(model, []) + } } func test_from_when_files_found_in_opaque_directory() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - - let assetsDirectory = rootDirectory.appending(components: "Resources", "Assets.xcassets") - try await fileSystem.makeDirectory(at: assetsDirectory) - try await fileSystem.touch(assetsDirectory.appending(component: "image.png")) - - let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Resources/Assets.xcassets/**") - - // When - let model = try await XcodeGraph.ResourceFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) - - // Then - XCTAssertPrinterOutputNotContains( - "No files found at: \(assetsDirectory.appending(components: "**"))" - ) - XCTAssertEqual( - model, - [ - .file(path: assetsDirectory, tags: [], inclusionCondition: nil), - ] - ) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + + let assetsDirectory = rootDirectory.appending(components: "Resources", "Assets.xcassets") + try await fileSystem.makeDirectory(at: assetsDirectory) + try await fileSystem.touch(assetsDirectory.appending(component: "image.png")) + + let manifest = ProjectDescription.ResourceFileElement.glob(pattern: "Resources/Assets.xcassets/**") + + // When + let model = try await XcodeGraph.ResourceFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) + + // Then + XCTAssertPrinterOutputNotContains( + "No files found at: \(assetsDirectory.appending(components: "**"))" + ) + XCTAssertEqual( + model, + [ + .file(path: assetsDirectory, tags: [], inclusionCondition: nil), + ] + ) + } } func test_from_outputs_a_warning_when_the_folder_reference_is_invalid() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - try await createFiles([ - "README.md", - ]) - - let manifest = ProjectDescription.ResourceFileElement.folderReference(path: "README.md") - - // When - let model = try await XcodeGraph.ResourceFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + try await createFiles([ + "README.md", + ]) + + let manifest = ProjectDescription.ResourceFileElement.folderReference(path: "README.md") + + // When + let model = try await XcodeGraph.ResourceFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) - // Then - XCTAssertPrinterOutputContains("README.md is not a directory - folder reference paths need to point to directories") - XCTAssertEqual(model, []) + // Then + XCTAssertPrinterOutputContains("README.md is not a directory - folder reference paths need to point to directories") + XCTAssertEqual(model, []) + } } func test_resourceFileElement_warning_withMissingFolderReference() async throws { - // Given - let temporaryPath = try temporaryPath() - let rootDirectory = temporaryPath - let generatorPaths = GeneratorPaths( - manifestDirectory: temporaryPath, - rootDirectory: rootDirectory - ) - let manifest = ProjectDescription.ResourceFileElement.folderReference(path: "Documentation") - - // When - let model = try await XcodeGraph.ResourceFileElement.from( - manifest: manifest, - generatorPaths: generatorPaths, - fileSystem: fileSystem - ) + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let rootDirectory = temporaryPath + let generatorPaths = GeneratorPaths( + manifestDirectory: temporaryPath, + rootDirectory: rootDirectory + ) + let manifest = ProjectDescription.ResourceFileElement.folderReference(path: "Documentation") + + // When + let model = try await XcodeGraph.ResourceFileElement.from( + manifest: manifest, + generatorPaths: generatorPaths, + fileSystem: fileSystem + ) - // Then - XCTAssertPrinterOutputContains("Documentation does not exist") - XCTAssertEqual(model, []) + // Then + XCTAssertPrinterOutputContains("Documentation does not exist") + XCTAssertEqual(model, []) + } } func test_throws_when_the_glob_is_invalid() async throws { diff --git a/Tests/TuistMigrationIntegrationTests/Utilities/EmptyBuildSettingsCheckerIntegrationTests.swift b/Tests/TuistMigrationIntegrationTests/Utilities/EmptyBuildSettingsCheckerIntegrationTests.swift index aca92a7c3b6..5e91a512324 100644 --- a/Tests/TuistMigrationIntegrationTests/Utilities/EmptyBuildSettingsCheckerIntegrationTests.swift +++ b/Tests/TuistMigrationIntegrationTests/Utilities/EmptyBuildSettingsCheckerIntegrationTests.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistSupport import XCTest @@ -31,28 +32,34 @@ final class EmptyBuildSettingsCheckerIntegrationTests: TuistTestCase { } func test_check_when_non_empty_target_build_settings() async throws { - // Given - let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) + try await ServiceContext.withTestingDependencies { + // Given + let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) - // Then - await XCTAssertThrowsSpecific(try await subject.check( - xcodeprojPath: xcodeprojPath, - targetName: "iOS" - ), EmptyBuildSettingsCheckerError.nonEmptyBuildSettings(["Debug", "Release"])) - XCTAssertPrinterOutputContains("The build setting 'DYLIB_CURRENT_VERSION' of build configuration 'Debug' is not empty.") + // Then + await XCTAssertThrowsSpecific(try await subject.check( + xcodeprojPath: xcodeprojPath, + targetName: "iOS" + ), EmptyBuildSettingsCheckerError.nonEmptyBuildSettings(["Debug", "Release"])) + XCTAssertPrinterOutputContains( + "The build setting 'DYLIB_CURRENT_VERSION' of build configuration 'Debug' is not empty." + ) + } } func test_check_when_non_empty_project_build_settings() async throws { - // Given - let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) + try await ServiceContext.withTestingDependencies { + // Given + let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) - // Then - await XCTAssertThrowsSpecific(try await subject.check( - xcodeprojPath: xcodeprojPath, - targetName: nil - ), EmptyBuildSettingsCheckerError.nonEmptyBuildSettings(["Debug", "Release"])) - XCTAssertPrinterOutputContains( - "The build setting 'GCC_WARN_UNUSED_VARIABLE' of build configuration 'Debug' is not empty." - ) + // Then + await XCTAssertThrowsSpecific(try await subject.check( + xcodeprojPath: xcodeprojPath, + targetName: nil + ), EmptyBuildSettingsCheckerError.nonEmptyBuildSettings(["Debug", "Release"])) + XCTAssertPrinterOutputContains( + "The build setting 'GCC_WARN_UNUSED_VARIABLE' of build configuration 'Debug' is not empty." + ) + } } } diff --git a/Tests/TuistMigrationIntegrationTests/Utilities/SettingsToXCConfigExtractorIntegrationTests.swift b/Tests/TuistMigrationIntegrationTests/Utilities/SettingsToXCConfigExtractorIntegrationTests.swift index 444eb2eaf80..5d24aeebc77 100644 --- a/Tests/TuistMigrationIntegrationTests/Utilities/SettingsToXCConfigExtractorIntegrationTests.swift +++ b/Tests/TuistMigrationIntegrationTests/Utilities/SettingsToXCConfigExtractorIntegrationTests.swift @@ -1,5 +1,6 @@ import Foundation import Path +import ServiceContextModule import TuistSupport import XCTest @@ -20,120 +21,124 @@ final class SettingsToXCConfigExtractorIntegrationTests: TuistTestCase { } func test_extract_when_target() async throws { - // Given - let temporaryPath = try temporaryPath() - let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) - let xcconfigPath = temporaryPath.appending(component: "iOS.xcconfig") + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) + let xcconfigPath = temporaryPath.appending(component: "iOS.xcconfig") - // When - try await subject.extract( - xcodeprojPath: xcodeprojPath, - targetName: "iOS", - xcconfigPath: xcconfigPath - ) + // When + try await subject.extract( + xcodeprojPath: xcodeprojPath, + targetName: "iOS", + xcconfigPath: xcconfigPath + ) - // Then - let expected = """ - BUILD_LIBRARY_FOR_DISTRIBUTION=YES - CLANG_ENABLE_MODULES=YES - CODE_SIGN_STYLE=Automatic - DEFINES_MODULE=YES - DYLIB_COMPATIBILITY_VERSION=1 - DYLIB_CURRENT_VERSION=1 - DYLIB_INSTALL_NAME_BASE=@rpath - INFOPLIST_FILE=iOS/Info.plist - INSTALL_PATH=$(LOCAL_LIBRARY_DIR)/Frameworks - PRODUCT_BUNDLE_IDENTIFIER=io.tuist.iOS - PRODUCT_NAME=$(TARGET_NAME:c99extidentifier) - SKIP_INSTALL=NO - SWIFT_VERSION=5.0 - TARGETED_DEVICE_FAMILY=1,2 - """ - let content = try FileHandler.shared.readTextFile(xcconfigPath) - XCTAssertTrue(content.contains(expected)) - XCTAssertPrinterOutputContains("Build settings successfully extracted into \(xcconfigPath.pathString)") + // Then + let expected = """ + BUILD_LIBRARY_FOR_DISTRIBUTION=YES + CLANG_ENABLE_MODULES=YES + CODE_SIGN_STYLE=Automatic + DEFINES_MODULE=YES + DYLIB_COMPATIBILITY_VERSION=1 + DYLIB_CURRENT_VERSION=1 + DYLIB_INSTALL_NAME_BASE=@rpath + INFOPLIST_FILE=iOS/Info.plist + INSTALL_PATH=$(LOCAL_LIBRARY_DIR)/Frameworks + PRODUCT_BUNDLE_IDENTIFIER=io.tuist.iOS + PRODUCT_NAME=$(TARGET_NAME:c99extidentifier) + SKIP_INSTALL=NO + SWIFT_VERSION=5.0 + TARGETED_DEVICE_FAMILY=1,2 + """ + let content = try FileHandler.shared.readTextFile(xcconfigPath) + XCTAssertTrue(content.contains(expected)) + XCTAssertPrinterOutputContains("Build settings successfully extracted into \(xcconfigPath.pathString)") + } } func test_extract_when_project() async throws { - // Given - let temporaryPath = try temporaryPath() - let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) - let xcconfigPath = temporaryPath.appending(component: "Project.xcconfig") + try await ServiceContext.withTestingDependencies { + // Given + let temporaryPath = try temporaryPath() + let xcodeprojPath = fixturePath(path: try RelativePath(validating: "Frameworks/Frameworks.xcodeproj")) + let xcconfigPath = temporaryPath.appending(component: "Project.xcconfig") - // When - try await subject.extract( - xcodeprojPath: xcodeprojPath, - targetName: nil, - xcconfigPath: xcconfigPath - ) + // When + try await subject.extract( + xcodeprojPath: xcodeprojPath, + targetName: nil, + xcconfigPath: xcconfigPath + ) - // Then - let expected = """ - ALWAYS_SEARCH_USER_PATHS=NO - CLANG_ANALYZER_NONNULL=YES - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION=YES_AGGRESSIVE - CLANG_CXX_LANGUAGE_STANDARD=gnu++14 - CLANG_CXX_LIBRARY=libc++ - CLANG_ENABLE_MODULES=YES - CLANG_ENABLE_OBJC_ARC=YES - CLANG_ENABLE_OBJC_WEAK=YES - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING=YES - CLANG_WARN_BOOL_CONVERSION=YES - CLANG_WARN_COMMA=YES - CLANG_WARN_CONSTANT_CONVERSION=YES - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS=YES - CLANG_WARN_DIRECT_OBJC_ISA_USAGE=YES_ERROR - CLANG_WARN_DOCUMENTATION_COMMENTS=YES - CLANG_WARN_EMPTY_BODY=YES - CLANG_WARN_ENUM_CONVERSION=YES - CLANG_WARN_INFINITE_RECURSION=YES - CLANG_WARN_INT_CONVERSION=YES - CLANG_WARN_NON_LITERAL_NULL_CONVERSION=YES - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF=YES - CLANG_WARN_OBJC_LITERAL_CONVERSION=YES - CLANG_WARN_OBJC_ROOT_CLASS=YES_ERROR - CLANG_WARN_RANGE_LOOP_ANALYSIS=YES - CLANG_WARN_STRICT_PROTOTYPES=YES - CLANG_WARN_SUSPICIOUS_MOVE=YES - CLANG_WARN_UNGUARDED_AVAILABILITY=YES_AGGRESSIVE - CLANG_WARN_UNREACHABLE_CODE=YES - CLANG_WARN__DUPLICATE_METHOD_MATCH=YES - COPY_PHASE_STRIP=NO - CURRENT_PROJECT_VERSION=1 - ENABLE_STRICT_OBJC_MSGSEND=YES - GCC_C_LANGUAGE_STANDARD=gnu11 - GCC_NO_COMMON_BLOCKS=YES - GCC_WARN_64_TO_32_BIT_CONVERSION=YES - GCC_WARN_ABOUT_RETURN_TYPE=YES_ERROR - GCC_WARN_UNDECLARED_SELECTOR=YES - GCC_WARN_UNINITIALIZED_AUTOS=YES_AGGRESSIVE - GCC_WARN_UNUSED_FUNCTION=YES - GCC_WARN_UNUSED_VARIABLE=YES - IPHONEOS_DEPLOYMENT_TARGET=13.2 - MTL_FAST_MATH=YES - SDKROOT=iphoneos - VERSIONING_SYSTEM=apple-generic - VERSION_INFO_PREFIX= + // Then + let expected = """ + ALWAYS_SEARCH_USER_PATHS=NO + CLANG_ANALYZER_NONNULL=YES + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION=YES_AGGRESSIVE + CLANG_CXX_LANGUAGE_STANDARD=gnu++14 + CLANG_CXX_LIBRARY=libc++ + CLANG_ENABLE_MODULES=YES + CLANG_ENABLE_OBJC_ARC=YES + CLANG_ENABLE_OBJC_WEAK=YES + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING=YES + CLANG_WARN_BOOL_CONVERSION=YES + CLANG_WARN_COMMA=YES + CLANG_WARN_CONSTANT_CONVERSION=YES + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS=YES + CLANG_WARN_DIRECT_OBJC_ISA_USAGE=YES_ERROR + CLANG_WARN_DOCUMENTATION_COMMENTS=YES + CLANG_WARN_EMPTY_BODY=YES + CLANG_WARN_ENUM_CONVERSION=YES + CLANG_WARN_INFINITE_RECURSION=YES + CLANG_WARN_INT_CONVERSION=YES + CLANG_WARN_NON_LITERAL_NULL_CONVERSION=YES + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF=YES + CLANG_WARN_OBJC_LITERAL_CONVERSION=YES + CLANG_WARN_OBJC_ROOT_CLASS=YES_ERROR + CLANG_WARN_RANGE_LOOP_ANALYSIS=YES + CLANG_WARN_STRICT_PROTOTYPES=YES + CLANG_WARN_SUSPICIOUS_MOVE=YES + CLANG_WARN_UNGUARDED_AVAILABILITY=YES_AGGRESSIVE + CLANG_WARN_UNREACHABLE_CODE=YES + CLANG_WARN__DUPLICATE_METHOD_MATCH=YES + COPY_PHASE_STRIP=NO + CURRENT_PROJECT_VERSION=1 + ENABLE_STRICT_OBJC_MSGSEND=YES + GCC_C_LANGUAGE_STANDARD=gnu11 + GCC_NO_COMMON_BLOCKS=YES + GCC_WARN_64_TO_32_BIT_CONVERSION=YES + GCC_WARN_ABOUT_RETURN_TYPE=YES_ERROR + GCC_WARN_UNDECLARED_SELECTOR=YES + GCC_WARN_UNINITIALIZED_AUTOS=YES_AGGRESSIVE + GCC_WARN_UNUSED_FUNCTION=YES + GCC_WARN_UNUSED_VARIABLE=YES + IPHONEOS_DEPLOYMENT_TARGET=13.2 + MTL_FAST_MATH=YES + SDKROOT=iphoneos + VERSIONING_SYSTEM=apple-generic + VERSION_INFO_PREFIX= - DEBUG_INFORMATION_FORMAT[config=Debug]=dwarf - DEBUG_INFORMATION_FORMAT[config=Release]=dwarf-with-dsym - ENABLE_NS_ASSERTIONS[config=Release]=NO - ENABLE_TESTABILITY[config=Debug]=YES - GCC_DYNAMIC_NO_PIC[config=Debug]=NO - GCC_OPTIMIZATION_LEVEL[config=Debug]=0 - GCC_PREPROCESSOR_DEFINITIONS[config=Debug]=DEBUG=1 $(inherited) - MTL_ENABLE_DEBUG_INFO[config=Debug]=INCLUDE_SOURCE - MTL_ENABLE_DEBUG_INFO[config=Release]=NO - ONLY_ACTIVE_ARCH[config=Debug]=YES - SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug]=DEBUG - SWIFT_COMPILATION_MODE[config=Release]=wholemodule - SWIFT_OPTIMIZATION_LEVEL[config=Debug]=-Onone - SWIFT_OPTIMIZATION_LEVEL[config=Release]=-O - VALIDATE_PRODUCT[config=Release]=YES - """ - let content = try FileHandler.shared.readTextFile(xcconfigPath) - XCTAssertTrue(content.contains(expected)) - XCTAssertPrinterOutputContains("Build settings successfully extracted into \(xcconfigPath.pathString)") + DEBUG_INFORMATION_FORMAT[config=Debug]=dwarf + DEBUG_INFORMATION_FORMAT[config=Release]=dwarf-with-dsym + ENABLE_NS_ASSERTIONS[config=Release]=NO + ENABLE_TESTABILITY[config=Debug]=YES + GCC_DYNAMIC_NO_PIC[config=Debug]=NO + GCC_OPTIMIZATION_LEVEL[config=Debug]=0 + GCC_PREPROCESSOR_DEFINITIONS[config=Debug]=DEBUG=1 $(inherited) + MTL_ENABLE_DEBUG_INFO[config=Debug]=INCLUDE_SOURCE + MTL_ENABLE_DEBUG_INFO[config=Release]=NO + ONLY_ACTIVE_ARCH[config=Debug]=YES + SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug]=DEBUG + SWIFT_COMPILATION_MODE[config=Release]=wholemodule + SWIFT_OPTIMIZATION_LEVEL[config=Debug]=-Onone + SWIFT_OPTIMIZATION_LEVEL[config=Release]=-O + VALIDATE_PRODUCT[config=Release]=YES + """ + let content = try FileHandler.shared.readTextFile(xcconfigPath) + XCTAssertTrue(content.contains(expected)) + XCTAssertPrinterOutputContains("Build settings successfully extracted into \(xcconfigPath.pathString)") + } } func test_extract_when_target_is_not_found() async throws { diff --git a/Tests/TuistServerTests/Client/ServerClientOutputWarningsMiddlewareTests.swift b/Tests/TuistServerTests/Client/ServerClientOutputWarningsMiddlewareTests.swift index 8cd72b06376..6c0e6b73746 100644 --- a/Tests/TuistServerTests/Client/ServerClientOutputWarningsMiddlewareTests.swift +++ b/Tests/TuistServerTests/Client/ServerClientOutputWarningsMiddlewareTests.swift @@ -1,8 +1,10 @@ import Foundation import HTTPTypes import OpenAPIRuntime +import ServiceContextModule import TuistSupport import XCTest + @testable import TuistServer @testable import TuistSupportTesting @@ -34,28 +36,30 @@ final class ServerClientOutputWarningsMiddlewareTests: TuistUnitTestCase { } func test_outputsWarnings_whenTheHeaderIsPresent() async throws { - // Given - let url = URL(string: "https://test.tuist.io")! - let warnings = ["foo", "bar"] - let base64edJsonWarnings = (try JSONSerialization.data(withJSONObject: warnings)).base64EncodedString() - let request = HTTPRequest(method: .get, scheme: nil, authority: nil, path: "/") - let response = HTTPResponse( - status: 200, - headerFields: [ - try XCTUnwrap(HTTPField.Name("x-tuist-cloud-warnings")): base64edJsonWarnings, - ] - ) + try await ServiceContext.withTestingDependencies { + // Given + let url = URL(string: "https://test.tuist.io")! + let warnings = ["foo", "bar"] + let base64edJsonWarnings = (try JSONSerialization.data(withJSONObject: warnings)).base64EncodedString() + let request = HTTPRequest(method: .get, scheme: nil, authority: nil, path: "/") + let response = HTTPResponse( + status: 200, + headerFields: [ + try XCTUnwrap(HTTPField.Name("x-tuist-cloud-warnings")): base64edJsonWarnings, + ] + ) - // When - let (gotResponse, _) = try await subject - .intercept(request, body: nil, baseURL: url, operationID: "123") { _, _, _ in - (response, nil) - } + // When + let (gotResponse, _) = try await subject + .intercept(request, body: nil, baseURL: url, operationID: "123") { _, _, _ in + (response, nil) + } - // Then - XCTAssertEqual(gotResponse, response) - for warning in warnings { - XCTAssertStandardOutput(pattern: warning) + // Then + XCTAssertEqual(gotResponse, response) + for warning in warnings { + XCTAssertStandardOutput(pattern: warning) + } } } @@ -73,6 +77,7 @@ final class ServerClientOutputWarningsMiddlewareTests: TuistUnitTestCase { // Then XCTAssertEqual(gotResponse, response) - XCTAssertEqual(TestingLogHandler.collected[.warning, <=], "") + let standardOutput = ServiceContext.current?.testingLogHandler?.collected[.warning, <=] ?? "" + XCTAssertEqual(standardOutput, "") } } diff --git a/Tests/TuistServerTests/Session/ServerSessionControllerTests.swift b/Tests/TuistServerTests/Session/ServerSessionControllerTests.swift index 32d75c6ad6c..f9c06898c54 100644 --- a/Tests/TuistServerTests/Session/ServerSessionControllerTests.swift +++ b/Tests/TuistServerTests/Session/ServerSessionControllerTests.swift @@ -1,6 +1,7 @@ import Foundation import Mockable import Path +import ServiceContextModule import TuistSupport import XCTest @@ -135,49 +136,53 @@ final class ServerSessionControllerTests: TuistUnitTestCase { } func test_logout_deletesLegacyCredentials() async throws { - // Given - let credentials = ServerCredentials( - token: "token", - accessToken: nil, - refreshToken: nil - ) - given(credentialsStore) - .store(credentials: .value(credentials), serverURL: .value(serverURL)) - .willReturn() - try await credentialsStore.store(credentials: credentials, serverURL: serverURL) + try await ServiceContext.withTestingDependencies { + // Given + let credentials = ServerCredentials( + token: "token", + accessToken: nil, + refreshToken: nil + ) + given(credentialsStore) + .store(credentials: .value(credentials), serverURL: .value(serverURL)) + .willReturn() + try await credentialsStore.store(credentials: credentials, serverURL: serverURL) - given(credentialsStore) - .delete(serverURL: .value(serverURL)) - .willReturn() + given(credentialsStore) + .delete(serverURL: .value(serverURL)) + .willReturn() - // When - try await subject.logout(serverURL: serverURL) + // When + try await subject.logout(serverURL: serverURL) - // Then - XCTAssertPrinterOutputContains("Successfully logged out.") + // Then + XCTAssertPrinterOutputContains("Successfully logged out.") + } } func test_logout_deletesCredentials() async throws { - // Given - let credentials = ServerCredentials( - token: nil, - accessToken: "access-token", - refreshToken: "refresh-token" - ) - given(credentialsStore) - .store(credentials: .value(credentials), serverURL: .value(serverURL)) - .willReturn() - try await credentialsStore.store(credentials: credentials, serverURL: serverURL) + try await ServiceContext.withTestingDependencies { + // Given + let credentials = ServerCredentials( + token: nil, + accessToken: "access-token", + refreshToken: "refresh-token" + ) + given(credentialsStore) + .store(credentials: .value(credentials), serverURL: .value(serverURL)) + .willReturn() + try await credentialsStore.store(credentials: credentials, serverURL: serverURL) - given(credentialsStore) - .delete(serverURL: .value(serverURL)) - .willReturn() + given(credentialsStore) + .delete(serverURL: .value(serverURL)) + .willReturn() - // When - try await subject.logout(serverURL: serverURL) + // When + try await subject.logout(serverURL: serverURL) - // Then - XCTAssertPrinterOutputContains("Successfully logged out.") + // Then + XCTAssertPrinterOutputContains("Successfully logged out.") + } } fileprivate func authURL() -> URL { diff --git a/Tests/TuistServerTests/Utilities/ServerAuthenticationControllerTests.swift b/Tests/TuistServerTests/Utilities/ServerAuthenticationControllerTests.swift index 214ba7ca84d..1573fd60f3c 100644 --- a/Tests/TuistServerTests/Utilities/ServerAuthenticationControllerTests.swift +++ b/Tests/TuistServerTests/Utilities/ServerAuthenticationControllerTests.swift @@ -1,5 +1,6 @@ import Foundation import Mockable +import ServiceContextModule import TuistSupport import TuistSupportTesting import XCTest @@ -117,113 +118,121 @@ final class ServerAuthenticationControllerTests: TuistUnitTestCase { } func test_when_deprecated_config_token_is_present_and_is_ci() async throws { - // Given - environment.tuistVariables[ - Constants.EnvironmentVariables.deprecatedToken - ] = "project-token" - given(ciChecker) - .isCI() - .willReturn(true) - - // When - let got = try await subject.authenticationToken(serverURL: .test()) - - // Then - XCTAssertEqual( - got, - .project("project-token") - ) - XCTAssertStandardOutput( - pattern: "Use `TUIST_CONFIG_TOKEN` environment variable instead of `TUIST_CONFIG_CLOUD_TOKEN` to authenticate on the CI" - ) + try await ServiceContext.withTestingDependencies { + // Given + environment.tuistVariables[ + Constants.EnvironmentVariables.deprecatedToken + ] = "project-token" + given(ciChecker) + .isCI() + .willReturn(true) + + // When + let got = try await subject.authenticationToken(serverURL: .test()) + + // Then + XCTAssertEqual( + got, + .project("project-token") + ) + XCTAssertStandardOutput( + pattern: "Use `TUIST_CONFIG_TOKEN` environment variable instead of `TUIST_CONFIG_CLOUD_TOKEN` to authenticate on the CI" + ) + } } func test_when_deprecated_and_current_config_tokens_are_present_and_is_ci() async throws { - // Given - environment.tuistVariables[ - Constants.EnvironmentVariables.deprecatedToken - ] = "deprecated-project-token" - environment.tuistVariables[ - Constants.EnvironmentVariables.token - ] = "project-token" - given(ciChecker) - .isCI() - .willReturn(true) - - // When - let got = try await subject.authenticationToken(serverURL: .test()) - - // Then - XCTAssertEqual( - got, - .project("project-token") - ) - XCTAssertPrinterOutputNotContains( - "Use `TUIST_CONFIG_TOKEN` environment variable instead of `TUIST_CONFIG_CLOUD_TOKEN` to authenticate on the CI" - ) + try await ServiceContext.withTestingDependencies { + // Given + environment.tuistVariables[ + Constants.EnvironmentVariables.deprecatedToken + ] = "deprecated-project-token" + environment.tuistVariables[ + Constants.EnvironmentVariables.token + ] = "project-token" + given(ciChecker) + .isCI() + .willReturn(true) + + // When + let got = try await subject.authenticationToken(serverURL: .test()) + + // Then + XCTAssertEqual( + got, + .project("project-token") + ) + XCTAssertPrinterOutputNotContains( + "Use `TUIST_CONFIG_TOKEN` environment variable instead of `TUIST_CONFIG_CLOUD_TOKEN` to authenticate on the CI" + ) + } } func test_when_credentials_store_returns_legacy_token() async throws { - // Given - given(ciChecker) - .isCI() - .willReturn(false) - - given(credentialsStore) - .read(serverURL: .any) - .willReturn(ServerCredentials(token: "legacy-token", accessToken: nil, refreshToken: nil)) - - // When - let got = try await subject.authenticationToken(serverURL: .test()) - - // Then - XCTAssertEqual( - got, - .user(legacyToken: "legacy-token", accessToken: nil, refreshToken: nil) - ) - XCTAssertStandardOutput( - pattern: "You are using a deprecated user token. Please, reauthenticate by running 'tuist auth login'." - ) + try await ServiceContext.withTestingDependencies { + // Given + given(ciChecker) + .isCI() + .willReturn(false) + + given(credentialsStore) + .read(serverURL: .any) + .willReturn(ServerCredentials(token: "legacy-token", accessToken: nil, refreshToken: nil)) + + // When + let got = try await subject.authenticationToken(serverURL: .test()) + + // Then + XCTAssertEqual( + got, + .user(legacyToken: "legacy-token", accessToken: nil, refreshToken: nil) + ) + XCTAssertStandardOutput( + pattern: "You are using a deprecated user token. Please, reauthenticate by running 'tuist auth login'." + ) + } } func test_when_credentials_store_returns_legacy_token_and_jwt_tokens() async throws { - // Given - given(ciChecker) - .isCI() - .willReturn(false) - - given(credentialsStore) - .read(serverURL: .any) - .willReturn( - .test( - token: "legacy-token", - accessToken: accessToken, - refreshToken: refreshToken + try await ServiceContext.withTestingDependencies { + // Given + given(ciChecker) + .isCI() + .willReturn(false) + + given(credentialsStore) + .read(serverURL: .any) + .willReturn( + .test( + token: "legacy-token", + accessToken: accessToken, + refreshToken: refreshToken + ) ) - ) - - // When - let got = try await subject.authenticationToken(serverURL: .test()) - // Then - // Then - XCTAssertEqual( - got, - .user( - legacyToken: nil, - accessToken: .test( - token: accessToken, - expiryDate: Date(timeIntervalSince1970: 1_720_429_812) - ), - refreshToken: .test( - token: refreshToken, - expiryDate: Date(timeIntervalSince1970: 1_720_429_810) + // When + let got = try await subject.authenticationToken(serverURL: .test()) + + // Then + // Then + XCTAssertEqual( + got, + .user( + legacyToken: nil, + accessToken: .test( + token: accessToken, + expiryDate: Date(timeIntervalSince1970: 1_720_429_812) + ), + refreshToken: .test( + token: refreshToken, + expiryDate: Date(timeIntervalSince1970: 1_720_429_810) + ) ) ) - ) - XCTAssertPrinterOutputNotContains( - "You are using a deprecated user token. Please, reauthenticate by running 'tuist auth login'." - ) + XCTAssertPrinterOutputNotContains( + "You are using a deprecated user token. Please, reauthenticate by running 'tuist auth login'." + ) + } } func test_when_credentials_store_returns_jwt_tokens() async throws { diff --git a/Tests/TuistSupportTests/Errors/ErrorHandlerTests.swift b/Tests/TuistSupportTests/Errors/ErrorHandlerTests.swift index adef0a7a7e2..43759d51f89 100644 --- a/Tests/TuistSupportTests/Errors/ErrorHandlerTests.swift +++ b/Tests/TuistSupportTests/Errors/ErrorHandlerTests.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceContextModule import XCTest @testable import TuistSupport @testable import TuistSupportTesting @@ -22,19 +23,23 @@ final class ErrorHandlerTests: TuistUnitTestCase { super.tearDown() } - func test_fatalError_printsTheDescription_whenPrintableError() { - let error = TestError(type: .abort) - subject.fatal(error: error) - XCTAssertPrinterErrorContains(error.description) + func test_fatalError_printsTheDescription_whenPrintableError() async throws { + try await ServiceContext.withTestingDependencies { + let error = TestError(type: .abort) + subject.fatal(error: error) + XCTAssertPrinterErrorContains(error.description) + } } - func test_fatalError_prints_whenItsSilent() { - let error = TestError(type: .bugSilent) - subject.fatal(error: error) - let expected = """ - An unexpected error happened. We've opened an issue to fix it as soon as possible. - We are sorry for any inconveniences it might have caused. - """ - XCTAssertPrinterErrorContains(expected) + func test_fatalError_prints_whenItsSilent() async throws { + try await ServiceContext.withTestingDependencies { + let error = TestError(type: .bugSilent) + subject.fatal(error: error) + let expected = """ + An unexpected error happened. We've opened an issue to fix it as soon as possible. + We are sorry for any inconveniences it might have caused. + """ + XCTAssertPrinterErrorContains(expected) + } } } diff --git a/Tests/TuistSupportTests/Utils/UserInputReaderTests.swift b/Tests/TuistSupportTests/Utils/UserInputReaderTests.swift index dafc36d1e20..df1262384b1 100644 --- a/Tests/TuistSupportTests/Utils/UserInputReaderTests.swift +++ b/Tests/TuistSupportTests/Utils/UserInputReaderTests.swift @@ -1,3 +1,4 @@ +import ServiceContextModule import TuistSupportTesting import XCTest @testable import TuistSupport @@ -85,31 +86,33 @@ class UserInputReaderTests: TuistUnitTestCase { ) } - func test_read_value_when_multiple_values_provided() throws { - // Given - var fakeReadLine = StringReader(input: "1") - let reader: UserInputReader = .init { _ in - fakeReadLine.readLine() + func test_read_value_when_multiple_values_provided() async throws { + try await ServiceContext.withTestingDependencies { + // Given + var fakeReadLine = StringReader(input: "1") + let reader: UserInputReader = .init { _ in + fakeReadLine.readLine() + } + let valueOne = Value(name: "value-one") + let valueTwo = Value(name: "value-two") + + // When + let got = try reader.readValue( + asking: "Choose value:", + values: [valueOne, valueTwo], + valueDescription: \.name + ) + + // Then + XCTAssertEqual(got, valueTwo) + XCTAssertStandardOutput( + pattern: """ + Choose value: + \t0: value-one + \t1: value-two + """ + ) } - let valueOne = Value(name: "value-one") - let valueTwo = Value(name: "value-two") - - // When - let got = try reader.readValue( - asking: "Choose value:", - values: [valueOne, valueTwo], - valueDescription: \.name - ) - - // Then - XCTAssertEqual(got, valueTwo) - XCTAssertStandardOutput( - pattern: """ - Choose value: - \t0: value-one - \t1: value-two - """ - ) } } diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index c8235950ac9..91f5eab0d5a 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -115,6 +115,7 @@ public enum Module: String, CaseIterable { fileprivate var sharedDependencies: [TargetDependency] { return [ .external(name: "Path"), + .external(name: "ServiceContextModule"), .external(name: "SystemPackage"), ] } @@ -281,6 +282,7 @@ public enum Module: String, CaseIterable { .external(name: "ZIPFoundation"), .external(name: "Difference"), .external(name: "Command"), + .external(name: "LoggingOSLog"), ] case .kit: [ @@ -652,6 +654,7 @@ public enum Module: String, CaseIterable { .external(name: "SwiftToolsSupport"), .external(name: "FileSystem"), .external(name: "Command"), + .external(name: "Logging"), ] case .kit: []