From 38fd30b4df92d8c05eb87c475787b9690f5f17ca Mon Sep 17 00:00:00 2001 From: phongvhd93 Date: Wed, 18 Oct 2023 21:32:37 +0700 Subject: [PATCH 1/5] [#349] Create target --- .../NetworkAPI/Core/NetworkAPIError.swift | 11 +++ .../NetworkAPI/Core/NetworkAPIProtocol.swift | 33 +++++++ .../Core/RequestConfiguration.swift | 39 ++++++++ .../Sources/NetworkAPI/Interceptors/.gitkeep | 0 .../Data/Sources/NetworkAPI/Models/.gitkeep | 0 .../Data/Sources/NetworkAPI/NetworkAPI.swift | 25 ++++++ .../NetworkAPI/RequestConfigurations/.gitkeep | 0 Modules/Data/Sources/Repositories/.gitkeep | 0 Modules/Domain/Sources/Entities/.gitkeep | 0 Modules/Domain/Sources/Interfaces/.gitkeep | 0 .../UseCases/UseCaseFactoryProtocol.swift | 5 ++ Project.swift | 10 +++ Tuist/ProjectDescriptionHelpers/Module.swift | 33 +++++++ .../Target+Initializing.swift | 88 +++++++++++++++++-- 14 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 Modules/Data/Sources/NetworkAPI/Core/NetworkAPIError.swift create mode 100644 Modules/Data/Sources/NetworkAPI/Core/NetworkAPIProtocol.swift create mode 100644 Modules/Data/Sources/NetworkAPI/Core/RequestConfiguration.swift create mode 100644 Modules/Data/Sources/NetworkAPI/Interceptors/.gitkeep create mode 100644 Modules/Data/Sources/NetworkAPI/Models/.gitkeep create mode 100644 Modules/Data/Sources/NetworkAPI/NetworkAPI.swift create mode 100644 Modules/Data/Sources/NetworkAPI/RequestConfigurations/.gitkeep create mode 100644 Modules/Data/Sources/Repositories/.gitkeep create mode 100644 Modules/Domain/Sources/Entities/.gitkeep create mode 100644 Modules/Domain/Sources/Interfaces/.gitkeep create mode 100644 Modules/Domain/Sources/UseCases/UseCaseFactoryProtocol.swift create mode 100644 Tuist/ProjectDescriptionHelpers/Module.swift diff --git a/Modules/Data/Sources/NetworkAPI/Core/NetworkAPIError.swift b/Modules/Data/Sources/NetworkAPI/Core/NetworkAPIError.swift new file mode 100644 index 00000000..78c72199 --- /dev/null +++ b/Modules/Data/Sources/NetworkAPI/Core/NetworkAPIError.swift @@ -0,0 +1,11 @@ +// +// NetworkAPIError.swift +// + +import Foundation + +enum NetworkAPIError: Error { + + case generic + case dataNotFound +} diff --git a/Modules/Data/Sources/NetworkAPI/Core/NetworkAPIProtocol.swift b/Modules/Data/Sources/NetworkAPI/Core/NetworkAPIProtocol.swift new file mode 100644 index 00000000..c2ee0030 --- /dev/null +++ b/Modules/Data/Sources/NetworkAPI/Core/NetworkAPIProtocol.swift @@ -0,0 +1,33 @@ +// +// 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/Modules/Data/Sources/NetworkAPI/Core/RequestConfiguration.swift b/Modules/Data/Sources/NetworkAPI/Core/RequestConfiguration.swift new file mode 100644 index 00000000..32ddb9d3 --- /dev/null +++ b/Modules/Data/Sources/NetworkAPI/Core/RequestConfiguration.swift @@ -0,0 +1,39 @@ +// +// 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/Modules/Data/Sources/NetworkAPI/Interceptors/.gitkeep b/Modules/Data/Sources/NetworkAPI/Interceptors/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Modules/Data/Sources/NetworkAPI/Models/.gitkeep b/Modules/Data/Sources/NetworkAPI/Models/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Modules/Data/Sources/NetworkAPI/NetworkAPI.swift b/Modules/Data/Sources/NetworkAPI/NetworkAPI.swift new file mode 100644 index 00000000..d52c2081 --- /dev/null +++ b/Modules/Data/Sources/NetworkAPI/NetworkAPI.swift @@ -0,0 +1,25 @@ +// +// 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/Modules/Data/Sources/NetworkAPI/RequestConfigurations/.gitkeep b/Modules/Data/Sources/NetworkAPI/RequestConfigurations/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Modules/Data/Sources/Repositories/.gitkeep b/Modules/Data/Sources/Repositories/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Modules/Domain/Sources/Entities/.gitkeep b/Modules/Domain/Sources/Entities/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Modules/Domain/Sources/Interfaces/.gitkeep b/Modules/Domain/Sources/Interfaces/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Modules/Domain/Sources/UseCases/UseCaseFactoryProtocol.swift b/Modules/Domain/Sources/UseCases/UseCaseFactoryProtocol.swift new file mode 100644 index 00000000..9948f5ba --- /dev/null +++ b/Modules/Domain/Sources/UseCases/UseCaseFactoryProtocol.swift @@ -0,0 +1,5 @@ +// +// UseCaseFactoryProtocol.swift +// + +protocol UseCaseFactoryProtocol: AnyObject {} diff --git a/Project.swift b/Project.swift index 92d63a5e..da528d53 100644 --- a/Project.swift +++ b/Project.swift @@ -6,6 +6,16 @@ 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)) + } + return Project( name: name, organizationName: "Nimble", diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift new file mode 100644 index 00000000..06f95023 --- /dev/null +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -0,0 +1,33 @@ +// +// Modules.swift +// ProjectDescriptionHelpers +// +// Created by Phong on 16/10/2023. +// + +import ProjectDescription + + +public enum Module: CaseIterable { + + case domain + case data + + public var name: String { + switch self { + case .domain: + return "Domain" + case .data: + return "Data" + } + } + + public var dependencies: [TargetDependency] { + switch self { + case .domain: + return [] + case .data: + return [.target(name: Module.domain.name)] + } + } +} diff --git a/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift b/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift index 5e2158db..ccc1cc9e 100644 --- a/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift +++ b/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift @@ -1,9 +1,16 @@ 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 mainTarget(name: String, bundleId: String) -> Target { return Target( name: name, @@ -11,7 +18,7 @@ extension Target { product: .app, bundleId: bundleId, deploymentTarget: .iOS( - targetVersion: "{TARGET_VERSION}", + targetVersion: "{TARGET_VERSION}", devices: [.iphone] ), infoPlist: "\(name)/\(plistsPath)/Info.plist", @@ -26,10 +33,14 @@ extension Target { .swiftLintScript(), .swiftFormatLintScript(), .firebaseScript() + ], + dependencies: [ + .target(name: Module.data.name), + .target(name: Module.data.name) ] ) } - + public static func testsTarget(name: String, bundleId: String) -> Target { let targetName = "\(name)Tests" return Target( @@ -47,7 +58,7 @@ extension Target { dependencies: [.target(name: name)] ) } - + public static func kifUITestsTarget(name: String, bundleId: String) -> Target { let targetName = "\(name)KIFUITests" return Target( @@ -59,8 +70,73 @@ extension Target { sources: ["\(targetName)/**"], resources: [ "\(targetName)/**/.gitkeep", // To include empty folders - ], + ], 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( + name: module.name, + platform: .iOS, + product: .framework, + bundleId: bundleId, + sources: ["\(frameworkPath)/\(Constant.sourcesPath)/**"], + resources: ResourceFileElements(resources: [resourcesElement]), + dependencies: module.dependencies + ) + } } + +//// 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: [""] +// ) +// } +//} From 547acd500d71ad4b1d0e398cb91a2c619ab3bf78 Mon Sep 17 00:00:00 2001 From: phongvhd93 Date: Mon, 23 Oct 2023 14:55:52 +0700 Subject: [PATCH 2/5] [#349] Create modules for Domain and Data layer --- .../Data/Tests/Resources}/.gitkeep | 0 .../Sources/Dummies}/DummyNetworkModel.swift | 0 .../Dummies}/DummyRequestConfiguration.swift | 4 +- .../Specs}/NetworkAPI/NetworkAPISpec.swift | 2 +- .../Sources/Utilities/NetworkStubber.swift | 0 .../Domain/Tests/Resources}/.gitkeep | 0 .../Tests/Sources/Specs/DummySpec.swift | 23 +++ Project.swift | 16 +-- Tuist/Interfaces/SwiftUI/Project/Podfile | 21 +++ Tuist/Interfaces/UIKit/Project/Podfile | 25 +++- .../ProjectDescriptionHelpers/Constant.swift | 15 ++ Tuist/ProjectDescriptionHelpers/Module.swift | 36 ++++- .../Scheme+Initializing.swift | 20 +-- .../Target+Initializing.swift | 136 ++++++++---------- fastlane/Fastfile.swift | 4 - fastlane/Helpers/Test.swift | 4 +- .../NetworkAPI/Core/NetworkAPIError.swift | 11 -- .../NetworkAPI/Core/NetworkAPIProtocol.swift | 33 ----- .../Core/RequestConfiguration.swift | 39 ----- .../Sources/Data/NetworkAPI/NetworkAPI.swift | 25 ---- .../NetworkAPI/RequestConfigurations/.gitkeep | 0 .../Sources/Data/Repositories/.gitkeep | 0 .../Sources/Domain/Entities/.gitkeep | 0 .../Sources/Domain/Interfaces/.gitkeep | 0 .../UseCases/UseCaseFactoryProtocol.swift | 5 - 25 files changed, 191 insertions(+), 228 deletions(-) rename {{PROJECT_NAME}/Sources/Data/NetworkAPI/Interceptors => Modules/Data/Tests/Resources}/.gitkeep (100%) rename {{PROJECT_NAME}Tests/Sources/Dummy/Data => Modules/Data/Tests/Sources/Dummies}/DummyNetworkModel.swift (100%) rename {{PROJECT_NAME}Tests/Sources/Dummy/Data => Modules/Data/Tests/Sources/Dummies}/DummyRequestConfiguration.swift (88%) rename {{PROJECT_NAME}Tests/Sources/Specs/Data => Modules/Data/Tests/Sources/Specs}/NetworkAPI/NetworkAPISpec.swift (98%) rename {{PROJECT_NAME}Tests => Modules/Data/Tests}/Sources/Utilities/NetworkStubber.swift (100%) rename {{PROJECT_NAME}/Sources/Data/NetworkAPI/Models => Modules/Domain/Tests/Resources}/.gitkeep (100%) create mode 100644 Modules/Domain/Tests/Sources/Specs/DummySpec.swift create mode 100644 Tuist/ProjectDescriptionHelpers/Constant.swift delete mode 100644 {PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIError.swift delete mode 100644 {PROJECT_NAME}/Sources/Data/NetworkAPI/Core/NetworkAPIProtocol.swift delete mode 100644 {PROJECT_NAME}/Sources/Data/NetworkAPI/Core/RequestConfiguration.swift delete mode 100644 {PROJECT_NAME}/Sources/Data/NetworkAPI/NetworkAPI.swift delete mode 100644 {PROJECT_NAME}/Sources/Data/NetworkAPI/RequestConfigurations/.gitkeep delete mode 100644 {PROJECT_NAME}/Sources/Data/Repositories/.gitkeep delete mode 100644 {PROJECT_NAME}/Sources/Domain/Entities/.gitkeep delete mode 100644 {PROJECT_NAME}/Sources/Domain/Interfaces/.gitkeep delete mode 100644 {PROJECT_NAME}/Sources/Domain/UseCases/UseCaseFactoryProtocol.swift 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 d65996e5..adbb01a0 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 9da86063..5052b7ad 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 {} From 517900eb64632bed20bcad4efac6c81fc941c579 Mon Sep 17 00:00:00 2001 From: phongvhd93 Date: Mon, 6 Nov 2023 20:29:01 +0700 Subject: [PATCH 3/5] [#349] remove unncessary constant --- fastlane/Constants/Constant.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fastlane/Constants/Constant.swift b/fastlane/Constants/Constant.swift index 3e557829..110dde40 100644 --- a/fastlane/Constants/Constant.swift +++ b/fastlane/Constants/Constant.swift @@ -75,11 +75,6 @@ enum Constant { // MARK: - Device static let devices = ["iPhone 12 Pro Max"] - - // MARK: - Test - - static let testTarget: String = "\(projectName)Tests" - static let kifUITestTarget: String = "\(projectName)KIFUITests" } extension Constant { From 4fccd4161edecd54d548478a611df4fc0207cfd7 Mon Sep 17 00:00:00 2001 From: phongvhd93 Date: Wed, 22 Nov 2023 16:27:05 +0700 Subject: [PATCH 4/5] [#349] Rename makeFramework to frameworkTargets --- Tuist/ProjectDescriptionHelpers/Module.swift | 5 +---- Tuist/ProjectDescriptionHelpers/Target+Initializing.swift | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index 4c13cb4c..1d9d6e71 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -39,10 +39,7 @@ public enum Module: CaseIterable { } public var resources: ProjectDescription.ResourceFileElements { - switch self { - case .data, .domain: - return [] - } + [] } public var testsSources: ProjectDescription.SourceFilesList { diff --git a/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift b/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift index 58f508bc..5d974c07 100644 --- a/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift +++ b/Tuist/ProjectDescriptionHelpers/Target+Initializing.swift @@ -6,7 +6,7 @@ extension Target { var targets: [Target] = [] let frameworks = Module.allCases - .flatMap { Target.makeFramework(module: $0, bundleId: bundleId) } + .flatMap { Target.frameworkTargets(module: $0, bundleId: bundleId) } targets.append(contentsOf: frameworks) @@ -95,7 +95,7 @@ extension Target { extension Target { - fileprivate static func makeFramework(module: Module, bundleId: String) -> [Target] { + fileprivate static func frameworkTargets(module: Module, bundleId: String) -> [Target] { let framework = Target( name: module.name, platform: .iOS, From c86637e05151d6ffb3c03df078f57df130df43a6 Mon Sep 17 00:00:00 2001 From: phongvhd93 Date: Mon, 4 Dec 2023 22:44:09 +0700 Subject: [PATCH 5/5] [#349] Improve the duplicated codes --- Tuist/Interfaces/SwiftUI/Project/Podfile | 1 - Tuist/Interfaces/UIKit/Project/Podfile | 2 -- Tuist/ProjectDescriptionHelpers/Module.swift | 2 +- .../Scheme+Initializing.swift | 14 ++++++++------ 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Tuist/Interfaces/SwiftUI/Project/Podfile b/Tuist/Interfaces/SwiftUI/Project/Podfile index a2fc0e78..e39e56c6 100644 --- a/Tuist/Interfaces/SwiftUI/Project/Podfile +++ b/Tuist/Interfaces/SwiftUI/Project/Podfile @@ -61,7 +61,6 @@ target 'Data' do end target 'Domain' do - # Pods for Domain target 'DomainTests' do testing_pods end diff --git a/Tuist/Interfaces/UIKit/Project/Podfile b/Tuist/Interfaces/UIKit/Project/Podfile index d81009c3..bb31ac75 100644 --- a/Tuist/Interfaces/UIKit/Project/Podfile +++ b/Tuist/Interfaces/UIKit/Project/Podfile @@ -51,7 +51,6 @@ end target 'Data' do data_dependencies - target 'DataTests' do data_dependencies testing_pods @@ -59,7 +58,6 @@ target 'Data' do end target 'Domain' do - # Pods for Domain target 'DomainTests' do testing_pods end diff --git a/Tuist/ProjectDescriptionHelpers/Module.swift b/Tuist/ProjectDescriptionHelpers/Module.swift index 1d9d6e71..28a6a00d 100644 --- a/Tuist/ProjectDescriptionHelpers/Module.swift +++ b/Tuist/ProjectDescriptionHelpers/Module.swift @@ -35,7 +35,7 @@ public enum Module: CaseIterable { } public var sources: ProjectDescription.SourceFilesList { - return ["\(frameworkPath)/\(Constant.sourcesPath)/**"] + ["\(frameworkPath)/\(Constant.sourcesPath)/**"] } public var resources: ProjectDescription.ResourceFileElements { diff --git a/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift b/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift index 33440e42..cda644fd 100644 --- a/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift +++ b/Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift @@ -5,9 +5,7 @@ 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"]) + let testModules = testSchemes(name) return Scheme( name: name, @@ -24,9 +22,7 @@ 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"]) + let testModules = testSchemes(name) return Scheme( name: "\(name) Staging", @@ -47,4 +43,10 @@ extension Scheme { hidden: true ) } + + private static func testSchemes(_ name: String) -> [TestableTarget] { + var modules = Module.allCases.map { TestableTarget("\($0.name)\(Constant.testsPath)") } + modules.append(contentsOf: ["\(name)Tests", "\(name)KIFUITests"]) + return modules + } }