diff --git a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Interceptors/.gitkeep b/Modules/Data/Tests/Resources/.gitkeep similarity index 100% rename from {PROJECT_NAME}/Sources/Data/NetworkAPI/Interceptors/.gitkeep rename to Modules/Data/Tests/Resources/.gitkeep diff --git a/{PROJECT_NAME}Tests/Sources/Dummy/Data/DummyNetworkModel.swift b/Modules/Data/Tests/Sources/Dummies/DummyNetworkModel.swift similarity index 100% rename from {PROJECT_NAME}Tests/Sources/Dummy/Data/DummyNetworkModel.swift rename to Modules/Data/Tests/Sources/Dummies/DummyNetworkModel.swift diff --git a/{PROJECT_NAME}Tests/Sources/Dummy/Data/DummyRequestConfiguration.swift b/Modules/Data/Tests/Sources/Dummies/DummyRequestConfiguration.swift similarity index 88% rename from {PROJECT_NAME}Tests/Sources/Dummy/Data/DummyRequestConfiguration.swift rename to Modules/Data/Tests/Sources/Dummies/DummyRequestConfiguration.swift index 1359b72b..b5a3d920 100644 --- a/{PROJECT_NAME}Tests/Sources/Dummy/Data/DummyRequestConfiguration.swift +++ b/Modules/Data/Tests/Sources/Dummies/DummyRequestConfiguration.swift @@ -4,7 +4,7 @@ import Alamofire -@testable import {PROJECT_NAME} +@testable import Data struct DummyRequestConfiguration: RequestConfiguration { @@ -24,6 +24,6 @@ extension DummyRequestConfiguration: RequestConfigurationStubable { } var path: String { - (try? url.asURL().path).string + (try? url.asURL().path) ?? "" } } diff --git a/{PROJECT_NAME}Tests/Sources/Specs/Data/NetworkAPI/NetworkAPISpec.swift b/Modules/Data/Tests/Sources/Specs/NetworkAPI/NetworkAPISpec.swift similarity index 98% rename from {PROJECT_NAME}Tests/Sources/Specs/Data/NetworkAPI/NetworkAPISpec.swift rename to Modules/Data/Tests/Sources/Specs/NetworkAPI/NetworkAPISpec.swift index 23e388c7..e88f16ca 100644 --- a/{PROJECT_NAME}Tests/Sources/Specs/Data/NetworkAPI/NetworkAPISpec.swift +++ b/Modules/Data/Tests/Sources/Specs/NetworkAPI/NetworkAPISpec.swift @@ -5,7 +5,7 @@ import Nimble import Quick -@testable import {PROJECT_NAME} +@testable import Data final class NetworkAPISpec: AsyncSpec { diff --git a/{PROJECT_NAME}Tests/Sources/Utilities/NetworkStubber.swift b/Modules/Data/Tests/Sources/Utilities/NetworkStubber.swift similarity index 100% rename from {PROJECT_NAME}Tests/Sources/Utilities/NetworkStubber.swift rename to Modules/Data/Tests/Sources/Utilities/NetworkStubber.swift diff --git a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Models/.gitkeep b/Modules/Domain/Tests/Resources/.gitkeep similarity index 100% rename from {PROJECT_NAME}/Sources/Data/NetworkAPI/Models/.gitkeep rename to Modules/Domain/Tests/Resources/.gitkeep diff --git a/Modules/Domain/Tests/Sources/Specs/DummySpec.swift b/Modules/Domain/Tests/Sources/Specs/DummySpec.swift new file mode 100644 index 00000000..5fc7cdc7 --- /dev/null +++ b/Modules/Domain/Tests/Sources/Specs/DummySpec.swift @@ -0,0 +1,23 @@ +// TODO: Remove this file + +import Nimble +import Quick + +@testable import Domain + +final class DummySpec: QuickSpec { + + override class func spec() { + + describe("A Dummy") { + + context("given a dummy message") { + let message = "Hello" + + it("equals Hello") { + expect(message) == "Hello" + } + } + } + } +} diff --git a/Project.swift b/Project.swift index da528d53..c58b5cd2 100644 --- a/Project.swift +++ b/Project.swift @@ -6,15 +6,7 @@ let project = Project.project(name: "{PROJECT_NAME}", bundleId: "${PRODUCT_BUNDL extension Project { static func project(name: String, bundleId: String) -> Project { - var targets: [Target] = [ - .mainTarget(name: name, bundleId: bundleId), - .testsTarget(name: name, bundleId: bundleId), - .kifUITestsTarget(name: name, bundleId: bundleId), - ] - - Module.allCases.forEach { - targets.append(Target.makeFramework(module: $0, bundleId: bundleId)) - } + let targets = Target.makeTargets(name: name, bundleId: bundleId) return Project( name: name, @@ -26,11 +18,7 @@ extension Project { settings: .settings( configurations: BuildConfiguration.allCases.map { $0.createConfiguration(projectName: name) } ), - targets: [ - .mainTarget(name: name, bundleId: bundleId), - .testsTarget(name: name, bundleId: bundleId), - .kifUITestsTarget(name: name, bundleId: bundleId), - ], + targets: targets, schemes: [ .productionScheme(name: name), .stagingScheme(name: name), diff --git a/Tuist/Interfaces/SwiftUI/Project/Podfile b/Tuist/Interfaces/SwiftUI/Project/Podfile index 7f9d0daf..a2fc0e78 100644 --- a/Tuist/Interfaces/SwiftUI/Project/Podfile +++ b/Tuist/Interfaces/SwiftUI/Project/Podfile @@ -46,6 +46,27 @@ target '{PROJECT_NAME}' do end end +def data_dependencies + pod 'Alamofire' + pod 'JSONAPIMapper', :git => 'https://github.com/nimblehq/JSONMapper', :tag => '1.1.1' +end + +target 'Data' do + data_dependencies + + target 'DataTests' do + data_dependencies + testing_pods + end +end + +target 'Domain' do + # Pods for Domain + target 'DomainTests' do + testing_pods + end +end + post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| diff --git a/Tuist/Interfaces/UIKit/Project/Podfile b/Tuist/Interfaces/UIKit/Project/Podfile index 653dc1a4..d81009c3 100644 --- a/Tuist/Interfaces/UIKit/Project/Podfile +++ b/Tuist/Interfaces/UIKit/Project/Podfile @@ -15,10 +15,6 @@ target '{PROJECT_NAME}' do pod 'Kingfisher' pod 'SnapKit' - # Backend - pod 'Alamofire' - pod 'JSONAPIMapper', :git => 'https://github.com/nimblehq/JSONMapper', :tag => '1.1.1' - # Storage pod 'KeychainAccess' @@ -48,6 +44,27 @@ target '{PROJECT_NAME}' do end end +def data_dependencies + pod 'Alamofire' + pod 'JSONAPIMapper', :git => 'https://github.com/nimblehq/JSONMapper', :tag => '1.1.1' +end + +target 'Data' do + data_dependencies + + target 'DataTests' do + data_dependencies + testing_pods + end +end + +target 'Domain' do + # Pods for Domain + target 'DomainTests' do + testing_pods + end +end + post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| diff --git a/Tuist/ProjectDescriptionHelpers/Constant.swift b/Tuist/ProjectDescriptionHelpers/Constant.swift new file mode 100644 index 00000000..1d7de6e2 --- /dev/null +++ b/Tuist/ProjectDescriptionHelpers/Constant.swift @@ -0,0 +1,15 @@ +// +// Constant.swift +// ProjectDescriptionHelpers +// +// Created by Phong on 22/10/2023. +// + +public enum Constant { + + static let plistsPath = "Configurations/Plists" + static let modulesRootPath = "Modules" + static let sourcesPath = "Sources" + static let resourcesPath = "Resources" + static let testsPath = "Tests" +} diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index 06f95023..4c13cb4c 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -7,7 +7,6 @@ import ProjectDescription - public enum Module: CaseIterable { case domain @@ -30,4 +29,39 @@ public enum Module: CaseIterable { return [.target(name: Module.domain.name)] } } + + public var frameworkPath: String { + "\(Constant.modulesRootPath)/\(name)" + } + + public var sources: ProjectDescription.SourceFilesList { + return ["\(frameworkPath)/\(Constant.sourcesPath)/**"] + } + + public var resources: ProjectDescription.ResourceFileElements { + switch self { + case .data, .domain: + return [] + } + } + + public var testsSources: ProjectDescription.SourceFilesList { + ["\(frameworkPath)/\(Constant.testsPath)/**"] + } + + public var testsResources: ProjectDescription.ResourceFileElements { + [ + "\(frameworkPath)/\(Constant.testsPath)/**/.gitkeep", + "\(frameworkPath)/\(Constant.testsPath)/\(Constant.resourcesPath)/**" + ] + } + + + public func getBundleId(mainBundleId: String) -> String { + "\(mainBundleId).\(name)" + } + + public func getTestBundleId(mainBundleId: String) -> String { + "\(mainBundleId).\(name)\(Constant.testsPath)" + } } diff --git a/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift b/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift index 8694c4c9..33440e42 100644 --- a/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift +++ b/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift @@ -5,14 +5,15 @@ extension Scheme { public static func productionScheme(name: String) -> Scheme { let debugConfigName = BuildConfiguration.debugProduction.name let releaseConfigName = BuildConfiguration.releaseProduction.name + + var testModules = Module.allCases.map { TestableTarget("\($0.name)\(Constant.testsPath)") } + testModules.append(contentsOf: ["\(name)Tests", "\(name)KIFUITests"]) + return Scheme( name: name, shared: true, buildAction: .buildAction(targets: ["\(name)"]), - testAction: .targets( - ["\(name)Tests", "\(name)KIFUITests"], - configuration: debugConfigName - ), + testAction: .targets(testModules, configuration: debugConfigName), runAction: .runAction(configuration: debugConfigName), archiveAction: .archiveAction(configuration: releaseConfigName), profileAction: .profileAction(configuration: debugConfigName), @@ -23,14 +24,15 @@ extension Scheme { public static func stagingScheme(name: String) -> Scheme { let debugConfigName = BuildConfiguration.debugStaging.name let releaseConfigName = BuildConfiguration.releaseStaging.name + + var testModules = Module.allCases.map { TestableTarget("\($0.name)\(Constant.testsPath)") } + testModules.append(contentsOf: ["\(name)Tests", "\(name)KIFUITests"]) + return Scheme( name: "\(name) Staging", shared: true, buildAction: .buildAction(targets: ["\(name)"]), - testAction: .targets( - ["\(name)Tests", "\(name)KIFUITests"], - configuration: debugConfigName - ), + testAction: .targets(testModules, configuration: debugConfigName), runAction: .runAction(configuration: debugConfigName), archiveAction: .archiveAction(configuration: releaseConfigName), profileAction: .profileAction(configuration: debugConfigName), @@ -39,8 +41,6 @@ extension Scheme { } public static func kifUITestsScheme(name: String) -> Scheme { - let debugConfigName = BuildConfiguration.debugStaging.name - let releaseConfigName = BuildConfiguration.releaseStaging.name return Scheme( name: "\(name)KIFUITests", shared: false, diff --git a/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift b/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift index ccc1cc9e..58f508bc 100644 --- a/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift +++ b/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift @@ -1,17 +1,32 @@ import ProjectDescription extension Target { - - private static let plistsPath: String = "Configurations/Plists" - - enum Constant { - - static let modulesRootPath: String = "Modules" - static let sourcesPath: String = "Sources" - static let resourcesPath: String = "Resources" + + public static func makeTargets(name: String, bundleId: String) -> [Target] { + var targets: [Target] = [] + + let frameworks = Module.allCases + .flatMap { Target.makeFramework(module: $0, bundleId: bundleId) } + + targets.append(contentsOf: frameworks) + + let mainTargets: [Target] = [ + .mainTarget(name: name, bundleId: bundleId), + .testsTarget(name: name, bundleId: bundleId), + .kifUITestsTarget(name: name, bundleId: bundleId) + ] + + targets.append(contentsOf: mainTargets) + + return targets } - - public static func mainTarget(name: String, bundleId: String) -> Target { +} + +// MARK: - Main Targets + +extension Target { + + fileprivate static func mainTarget(name: String, bundleId: String) -> Target { return Target( name: name, platform: .iOS, @@ -21,7 +36,7 @@ extension Target { targetVersion: "{TARGET_VERSION}", devices: [.iphone] ), - infoPlist: "\(name)/\(plistsPath)/Info.plist", + infoPlist: "\(name)/\(Constant.plistsPath)/Info.plist", sources: ["\(name)/Sources/**"], resources: [ "\(name)/Resources/**", @@ -36,19 +51,19 @@ extension Target { ], dependencies: [ .target(name: Module.data.name), - .target(name: Module.data.name) + .target(name: Module.domain.name) ] ) } - - public static func testsTarget(name: String, bundleId: String) -> Target { + + fileprivate static func testsTarget(name: String, bundleId: String) -> Target { let targetName = "\(name)Tests" return Target( name: targetName, platform: .iOS, product: .unitTests, bundleId: bundleId, - infoPlist: "\(targetName)/\(plistsPath)/Info.plist", + infoPlist: "\(targetName)/\(Constant.plistsPath)/Info.plist", sources: ["\(targetName)/**"], resources: [ "\(targetName)/**/.gitkeep", // To include empty folders @@ -58,15 +73,15 @@ extension Target { dependencies: [.target(name: name)] ) } - - public static func kifUITestsTarget(name: String, bundleId: String) -> Target { + + fileprivate static func kifUITestsTarget(name: String, bundleId: String) -> Target { let targetName = "\(name)KIFUITests" return Target( name: targetName, platform: .iOS, product: .unitTests, bundleId: bundleId, - infoPlist: "\(targetName)/\(plistsPath)/Info.plist", + infoPlist: "\(targetName)/\(Constant.plistsPath)/Info.plist", sources: ["\(targetName)/**"], resources: [ "\(targetName)/**/.gitkeep", // To include empty folders @@ -74,69 +89,36 @@ extension Target { dependencies: [.target(name: name)] ) } - - public static func makeFramework(module: Module, bundleId: String) -> Target { - let frameworkPath = "\(Constant.modulesRootPath)/\(module.name)" - let resourcesElement = ResourceFileElement.glob(pattern: "\(frameworkPath)/\(Constant.resourcesPath)/**") - - return Target( +} + +// MARK: - Dependencies + +extension Target { + + fileprivate static func makeFramework(module: Module, bundleId: String) -> [Target] { + let framework = Target( name: module.name, platform: .iOS, product: .framework, - bundleId: bundleId, - sources: ["\(frameworkPath)/\(Constant.sourcesPath)/**"], - resources: ResourceFileElements(resources: [resourcesElement]), + bundleId: module.getBundleId(mainBundleId: bundleId), + deploymentTarget: .iOS( + targetVersion: "{TARGET_VERSION}", + devices: [.iphone] + ), + sources: module.sources, + resources: module.resources, dependencies: module.dependencies ) + + let testTarget = Target( + name: "\(module.name)\(Constant.testsPath)", + platform: .iOS, + product: .unitTests, + bundleId: module.getTestBundleId(mainBundleId: bundleId), + sources: module.testsSources, + resources: module.testsResources, + dependencies: [.target(name: module.name)] + ) + return [framework, testTarget] } } - -//// MARK: - Domain -// -//extension Target { -// -// public static func domainTarget(bundleId: String) -> Target { -// return Target( -// name: "Domain", -// platform: .iOS, -// product: .staticLibrary, -// bundleId: bundleId -// ) -// } -// -// public static func domainTestsTarget(bundleId: String) -> Target { -// return Target( -// name: "DomainTests", -// platform: .iOS, -// product: .unitTests, -// bundleId: bundleId -// ) -// } -//} -// -// -//// MARK: - Data -// -//extension Target { -// -// public static func domainTarget(bundleId: String) -> Target { -// let name = "Data" -// return Target( -// name: name, -// platform: .iOS, -// product: .staticLibrary, -// bundleId: bundleId, -// sources: ["\(modulesPath)/\(name)/**"] -// ) -// } -// -// public static func domainTestsTarget(bundleId: String) -> Target { -// return Target( -// name: "DataTests", -// platform: .iOS, -// product: .unitTests, -// bundleId: bundleId, -// sources: [""] -// ) -// } -//} diff --git a/fastlane/Fastfile.swift b/fastlane/Fastfile.swift index 35fe6bbf..888d4a57 100644 --- a/fastlane/Fastfile.swift +++ b/fastlane/Fastfile.swift @@ -150,10 +150,6 @@ class Fastfile: LaneFile { desc("Build and Test project") Test.buildAndTest( environment: .staging, - targets: [ - Constant.testTarget, - Constant.kifUITestTarget - ], devices: Constant.devices ) } diff --git a/fastlane/Helpers/Test.swift b/fastlane/Helpers/Test.swift index bb4188d8..3ce377fa 100644 --- a/fastlane/Helpers/Test.swift +++ b/fastlane/Helpers/Test.swift @@ -10,13 +10,13 @@ enum Test { static func buildAndTest( environment: Constant.Environment, - targets: [String], + onlyTesting: [String] = [], devices: [String] ) { scan( scheme: .userDefined(environment.scheme), devices: .userDefined(devices), - onlyTesting: targets, + onlyTesting: onlyTesting, codeCoverage: .userDefined(true), outputDirectory: Constant.testOutputDirectoryPath, xcodebuildFormatter: "Pods/xcbeautify/xcbeautify", diff --git a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIError.swift b/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIError.swift deleted file mode 100644 index 78c72199..00000000 --- a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIError.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// NetworkAPIError.swift -// - -import Foundation - -enum NetworkAPIError: Error { - - case generic - case dataNotFound -} diff --git a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIProtocol.swift b/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIProtocol.swift deleted file mode 100644 index c2ee0030..00000000 --- a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIProtocol.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// NetworkAPIProtocol.swift -// - -import Alamofire - -protocol NetworkAPIProtocol { - - func performRequest( - _ configuration: RequestConfiguration, - for type: T.Type - ) async throws -> T -} - -extension NetworkAPIProtocol { - - func request( - session: Session, - configuration: RequestConfiguration, - decoder: JSONDecoder - ) async throws -> T { - try await session.request( - configuration.url, - method: configuration.method, - parameters: configuration.parameters, - encoding: configuration.encoding, - headers: configuration.headers, - interceptor: configuration.interceptor - ) - .serializingDecodable(T.self) - .value - } -} diff --git a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/RequestConfiguration.swift b/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/RequestConfiguration.swift deleted file mode 100644 index 32ddb9d3..00000000 --- a/{PROJECT_NAME}/Sources/Data/NetworkAPI/Core/RequestConfiguration.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// RequestConfiguration.swift -// - -import Alamofire -import Foundation - -protocol RequestConfiguration { - - var baseURL: String { get } - - var endpoint: String { get } - - var method: HTTPMethod { get } - - var url: URLConvertible { get } - - var parameters: Parameters? { get } - - var encoding: ParameterEncoding { get } - - var headers: HTTPHeaders? { get } - - var interceptor: RequestInterceptor? { get } -} - -extension RequestConfiguration { - - var url: URLConvertible { - let url = URL(string: baseURL)?.appendingPathComponent(endpoint) - return url?.absoluteString ?? "\(baseURL)\(endpoint)" - } - - var parameters: Parameters? { nil } - - var headers: HTTPHeaders? { nil } - - var interceptor: RequestInterceptor? { nil } -} diff --git a/{PROJECT_NAME}/Sources/Data/NetworkAPI/NetworkAPI.swift b/{PROJECT_NAME}/Sources/Data/NetworkAPI/NetworkAPI.swift deleted file mode 100644 index d52c2081..00000000 --- a/{PROJECT_NAME}/Sources/Data/NetworkAPI/NetworkAPI.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// NetworkAPI.swift -// - -import Alamofire - -final class NetworkAPI: NetworkAPIProtocol { - - private let decoder: JSONDecoder - - init(decoder: JSONDecoder = JSONDecoder()) { - self.decoder = decoder - } - - func performRequest( - _ configuration: RequestConfiguration, - for type: T.Type - ) async throws -> T { - try await request( - session: Session(), - configuration: configuration, - decoder: decoder - ) - } -} diff --git a/{PROJECT_NAME}/Sources/Data/NetworkAPI/RequestConfigurations/.gitkeep b/{PROJECT_NAME}/Sources/Data/NetworkAPI/RequestConfigurations/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/{PROJECT_NAME}/Sources/Data/Repositories/.gitkeep b/{PROJECT_NAME}/Sources/Data/Repositories/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/{PROJECT_NAME}/Sources/Domain/Entities/.gitkeep b/{PROJECT_NAME}/Sources/Domain/Entities/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/{PROJECT_NAME}/Sources/Domain/Interfaces/.gitkeep b/{PROJECT_NAME}/Sources/Domain/Interfaces/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/{PROJECT_NAME}/Sources/Domain/UseCases/UseCaseFactoryProtocol.swift b/{PROJECT_NAME}/Sources/Domain/UseCases/UseCaseFactoryProtocol.swift deleted file mode 100644 index 9948f5ba..00000000 --- a/{PROJECT_NAME}/Sources/Domain/UseCases/UseCaseFactoryProtocol.swift +++ /dev/null @@ -1,5 +0,0 @@ -// -// UseCaseFactoryProtocol.swift -// - -protocol UseCaseFactoryProtocol: AnyObject {}