From fc5204a92455bcba557c0e84b54a02f1c3f00b32 Mon Sep 17 00:00:00 2001 From: SeungHyun Hong Date: Fri, 10 Nov 2023 23:39:42 +0900 Subject: [PATCH 1/2] =?UTF-8?q?build:=20Tuist=EB=A5=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=9C=20WeTri=20App=20Project=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iOS/.gitignore | 8 +- iOS/Plugins/IOS/Package.swift | 15 ++++ iOS/Plugins/IOS/Plugin.swift | 3 + .../LocalHelper.swift | 9 ++ .../IOS/Sources/tuist-my-cli/main.swift | 1 + iOS/Projects/App/Project.swift | 31 +++++++ .../App/Resources/LaunchScreen.storyboard | 25 ++++++ iOS/Projects/App/Sources/AppDelegate.swift | 20 +++++ iOS/Projects/App/Sources/SceneDelegate.swift | 22 +++++ iOS/Projects/App/Sources/ViewController.swift | 18 ++++ iOS/Tuist/Config.swift | 3 + .../Project+Templates.swift | 84 +++++++++++++++++++ .../Scripts+Templates.swift | 65 ++++++++++++++ iOS/Workspace.swift | 10 +++ 14 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 iOS/Plugins/IOS/Package.swift create mode 100644 iOS/Plugins/IOS/Plugin.swift create mode 100644 iOS/Plugins/IOS/ProjectDescriptionHelpers/LocalHelper.swift create mode 100644 iOS/Plugins/IOS/Sources/tuist-my-cli/main.swift create mode 100644 iOS/Projects/App/Project.swift create mode 100644 iOS/Projects/App/Resources/LaunchScreen.storyboard create mode 100644 iOS/Projects/App/Sources/AppDelegate.swift create mode 100644 iOS/Projects/App/Sources/SceneDelegate.swift create mode 100644 iOS/Projects/App/Sources/ViewController.swift create mode 100644 iOS/Tuist/Config.swift create mode 100644 iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift create mode 100644 iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift create mode 100644 iOS/Workspace.swift diff --git a/iOS/.gitignore b/iOS/.gitignore index 91a6b573..1afb67d0 100644 --- a/iOS/.gitignore +++ b/iOS/.gitignore @@ -97,6 +97,7 @@ xcuserdata ### Xcode Patch ### *.xcodeproj/* +*.xcworkspace !*.xcodeproj/project.pbxproj !*.xcodeproj/xcshareddata/ !*.xcodeproj/project.xcworkspace/ @@ -104,4 +105,9 @@ xcuserdata /*.gcno **/xcshareddata/WorkspaceSettings.xcsettings -# End of https://www.toptal.com/developers/gitignore/api/swiftpackagemanager,swift,xcode \ No newline at end of file +### Tuist derived files ### +graph.dot +Derived/ + +### Tuist managed dependencies ### +Tuist/Dependencies diff --git a/iOS/Plugins/IOS/Package.swift b/iOS/Plugins/IOS/Package.swift new file mode 100644 index 00000000..c532f25a --- /dev/null +++ b/iOS/Plugins/IOS/Package.swift @@ -0,0 +1,15 @@ +// swift-tools-version: 5.8 + +import PackageDescription + +let package = Package( + name: "MyPlugin", + products: [ + .executable(name: "tuist-my-cli", targets: ["tuist-my-cli"]), + ], + targets: [ + .executableTarget( + name: "tuist-my-cli" + ), + ] +) diff --git a/iOS/Plugins/IOS/Plugin.swift b/iOS/Plugins/IOS/Plugin.swift new file mode 100644 index 00000000..86a1e55b --- /dev/null +++ b/iOS/Plugins/IOS/Plugin.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let plugin = Plugin(name: "MyPlugin") \ No newline at end of file diff --git a/iOS/Plugins/IOS/ProjectDescriptionHelpers/LocalHelper.swift b/iOS/Plugins/IOS/ProjectDescriptionHelpers/LocalHelper.swift new file mode 100644 index 00000000..6f49a442 --- /dev/null +++ b/iOS/Plugins/IOS/ProjectDescriptionHelpers/LocalHelper.swift @@ -0,0 +1,9 @@ +import Foundation + +public struct LocalHelper { + let name: String + + public init(name: String) { + self.name = name + } +} diff --git a/iOS/Plugins/IOS/Sources/tuist-my-cli/main.swift b/iOS/Plugins/IOS/Sources/tuist-my-cli/main.swift new file mode 100644 index 00000000..6f059694 --- /dev/null +++ b/iOS/Plugins/IOS/Sources/tuist-my-cli/main.swift @@ -0,0 +1 @@ +print("Hello, from your Tuist Task") \ No newline at end of file diff --git a/iOS/Projects/App/Project.swift b/iOS/Projects/App/Project.swift new file mode 100644 index 00000000..75c14904 --- /dev/null +++ b/iOS/Projects/App/Project.swift @@ -0,0 +1,31 @@ +// +// Project.swift +// ProjectDescriptionHelpers +// +// Created by 홍승현 on 11/10/23. +// + +import ProjectDescription +import ProjectDescriptionHelpers + +let project = Project.makeModule( + name: "WeTri", + product: .app, + resources: ["Resources/**"], + infoPlist: .extendingDefault( + with: [ + "UILaunchStoryboardName": "LaunchScreen", + "UIApplicationSceneManifest": [ + "UIApplicationSupportsMultipleScenes": false, + "UISceneConfigurations": [ + "UIWindowSceneSessionRoleApplication": [ + [ + "UISceneConfigurationName": "Default Configuration", + "UISceneDelegateClassName": "$(PRODUCT_MODULE_NAME).SceneDelegate" + ] + ] + ] + ] + ] + ) +) diff --git a/iOS/Projects/App/Resources/LaunchScreen.storyboard b/iOS/Projects/App/Resources/LaunchScreen.storyboard new file mode 100644 index 00000000..865e9329 --- /dev/null +++ b/iOS/Projects/App/Resources/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/Projects/App/Sources/AppDelegate.swift b/iOS/Projects/App/Sources/AppDelegate.swift new file mode 100644 index 00000000..c6d93737 --- /dev/null +++ b/iOS/Projects/App/Sources/AppDelegate.swift @@ -0,0 +1,20 @@ +import UIKit + +@main +final class AppDelegate: UIResponder, UIApplicationDelegate { + + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) + -> Bool { + return true + } + + func application( + _ application: UIApplication, + configurationForConnecting connectingSceneSession: UISceneSession, + options: UIScene.ConnectionOptions) + -> UISceneConfiguration { + UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } +} diff --git a/iOS/Projects/App/Sources/SceneDelegate.swift b/iOS/Projects/App/Sources/SceneDelegate.swift new file mode 100644 index 00000000..5ba1962f --- /dev/null +++ b/iOS/Projects/App/Sources/SceneDelegate.swift @@ -0,0 +1,22 @@ +// +// SceneDelegate.swift +// WeTri +// +// Created by 홍승현 on 11/10/23. +// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved. +// + +import UIKit + +final class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + + guard let windowScene = scene as? UIWindowScene else { return } + window = UIWindow(windowScene: windowScene) + window?.rootViewController = ViewController() + window?.makeKeyAndVisible() + } +} diff --git a/iOS/Projects/App/Sources/ViewController.swift b/iOS/Projects/App/Sources/ViewController.swift new file mode 100644 index 00000000..477a02c9 --- /dev/null +++ b/iOS/Projects/App/Sources/ViewController.swift @@ -0,0 +1,18 @@ +// +// ViewController.swift +// WeTri +// +// Created by 홍승현 on 11/10/23. +// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved. +// + +import UIKit + +final class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemBackground + } +} diff --git a/iOS/Tuist/Config.swift b/iOS/Tuist/Config.swift new file mode 100644 index 00000000..ff8e64fa --- /dev/null +++ b/iOS/Tuist/Config.swift @@ -0,0 +1,3 @@ +import ProjectDescription + +let config = Config() diff --git a/iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift b/iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift new file mode 100644 index 00000000..a4bdca3a --- /dev/null +++ b/iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift @@ -0,0 +1,84 @@ +import ProjectDescription + +public extension Project { + static func makeModule( + name: String, + platform: Platform = .iOS, + product: Product, + organizationName: String = "kr.codesquad.boostcamp8", + packages: [Package] = [], + deploymentTarget: DeploymentTarget? = .iOS(targetVersion: "16.0", devices: [.iphone]), + dependencies: [TargetDependency] = [], + sources: SourceFilesList = ["Sources/**"], + resources: ResourceFileElements? = nil, + infoPlist: InfoPlist = .default, + isTestable: Bool = false) + -> Project { + + let settings: Settings = .settings( + base: [:], + configurations: [ + .debug(name: .debug), + .release(name: .release) + ], + defaultSettings: .recommended) + + let appTarget = Target( + name: name, + platform: platform, + product: product, + bundleId: "\(organizationName).\(name)", + deploymentTarget: deploymentTarget, + infoPlist: infoPlist, + sources: sources, + resources: resources, + dependencies: dependencies) + + let schemes: [Scheme] = [.makeScheme(target: .debug, name: name)] + + var targets: [Target] = [appTarget] + + if isTestable { + let testTarget = Target( + name: "\(name)Tests", + platform: platform, + product: .unitTests, + bundleId: "\(organizationName).\(name)Tests", + deploymentTarget: deploymentTarget, + infoPlist: .default, + sources: ["Tests/**"], + dependencies: [.target(name: name)] + ) + + targets.append(testTarget) + } + + return Project( + name: name, + organizationName: organizationName, + packages: packages, + settings: settings, + targets: targets, + schemes: schemes) + } +} + +extension Scheme { + ///Scheme을 만드는 메소드 + static func makeScheme(target: ConfigurationName, name: String) -> Scheme { + return Scheme( + name: name, + shared: true, + buildAction: .buildAction(targets: ["\(name)"]), + testAction: .targets( + ["\(name)Tests"], + configuration: target, + options: .options(coverage: true, codeCoverageTargets: ["\(name)"]) + ), + runAction: .runAction(configuration: target), + archiveAction: .archiveAction(configuration: target), + profileAction: .profileAction(configuration: target), + analyzeAction: .analyzeAction(configuration: target) + ) + } +} diff --git a/iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift b/iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift new file mode 100644 index 00000000..0477e299 --- /dev/null +++ b/iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift @@ -0,0 +1,65 @@ +// +// Scripts+Templates.swift +// ProjectDescriptionHelpers +// +// Created by 홍승현 on 11/10/23. +// + +import Foundation +import ProjectDescription + +private let tuistRootDirectory = ProcessInfo.processInfo.environment["TUIST_ROOT_DIR"] + +private func swiftFormatCommand() -> String { + if let tuistRootDirectory { + return "swiftformat --config \(tuistRootDirectory)/swiftformat ." + } else { + return "swiftformat ." + } +} + + +private func swiftLintCommand() -> String { + if let tuistRootDirectory { + return "swiftlint --config \(tuistRootDirectory)/.swiftlint.yml" + } else { + return "swiftlint" + } +} + + +public extension TargetScript { + static let swiftFormat: Self = .pre( + script: """ + if [ "$CONFIGURATION" == "\(ConfigurationName("WeTri").rawValue)" ]; then + export PATH="$PATH:/opt/homebrew/bin" + if which swiftformat > /dev/null; then + if [ "${ENABLE_PREVIEWS}" = "YES" ]; then + echo "Not running Swift Format for Xcode Previews" + exit 0; + fi + \(swiftFormatCommand()) + else + echo "warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat" + fi + fi + """, + name: "SwiftFormat Run Script", + basedOnDependencyAnalysis: false + ) + + static var swiftLint: Self = .post( + script: """ + if [ "$CONFIGURATION" == "\(ConfigurationName("WeTri").rawValue)" ]; then + export PATH="$PATH:/opt/homebrew/bin" + if which swiftlint > /dev/null; then + \(swiftLintCommand()) + else + echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" + fi + fi + """, + name: "SwiftLint Run Script", + basedOnDependencyAnalysis: false + ) +} diff --git a/iOS/Workspace.swift b/iOS/Workspace.swift new file mode 100644 index 00000000..67a7dc47 --- /dev/null +++ b/iOS/Workspace.swift @@ -0,0 +1,10 @@ +import ProjectDescription +import ProjectDescriptionHelpers + + +let workspace = Workspace( + name: "WeTri", + projects: [ + "Projects/App", + ] +) From 9022e795d5a0688188d1758ae044418fc9234903 Mon Sep 17 00:00:00 2001 From: JongPyoAhn Date: Mon, 13 Nov 2023 16:35:02 +0900 Subject: [PATCH 2/2] =?UTF-8?q?build:=20SwiftLint,=20SwiftFormat=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iOS/.swiftformat | 22 +++++++ iOS/.swiftlint.yml | 62 +++++++++++++++++++ iOS/Projects/App/Project.swift | 10 +-- iOS/Projects/App/Sources/AppDelegate.swift | 19 +++--- iOS/Projects/App/Sources/SceneDelegate.swift | 6 +- iOS/Projects/App/Sources/ViewController.swift | 3 +- .../Project+Templates.swift | 1 + .../Scripts+Templates.swift | 36 +++++------ 8 files changed, 119 insertions(+), 40 deletions(-) create mode 100644 iOS/.swiftformat create mode 100644 iOS/.swiftlint.yml diff --git a/iOS/.swiftformat b/iOS/.swiftformat new file mode 100644 index 00000000..4bb57f0f --- /dev/null +++ b/iOS/.swiftformat @@ -0,0 +1,22 @@ +--swiftversion 5.9 + +# format options + +--indent 2 +--selfrequired +--importgrouping alpha +--enable acronyms +--acronyms "URL, ID, UUID" +--enable blankLineAfterImports +--enable blankLinesAroundMark +--enable blockComments +--enable docComments +--enable isEmpty +--enable markTypes +--enable sortedSwitchCases +--enable wrapEnumCases +--enable wrapSwitchCases + +--disable wrapMultilineStatementBraces +--disable andOperator +--disable redundantReturn diff --git a/iOS/.swiftlint.yml b/iOS/.swiftlint.yml new file mode 100644 index 00000000..0f816928 --- /dev/null +++ b/iOS/.swiftlint.yml @@ -0,0 +1,62 @@ +only_rules: + - colon + - fatal_error_message + - implicitly_unwrapped_optional + - legacy_cggeometry_functions + - legacy_constant + - legacy_constructor + - legacy_nsgeometry_functions + - operator_usage_whitespace + - return_arrow_whitespace + - trailing_newline + - unused_optional_binding + - vertical_whitespace + - void_return + - unowned_variable_capture + - custom_rules + +excluded: + - Carthage + - Pods + - .build + +colon: + apply_to_dictionaries: false + +indentation: 2 + +custom_rules: + no_objcMembers: + name: "@objcMembers" + regex: "@objcMembers" + message: "Explicitly use @objc on each member you want to expose to Objective-C" + severity: error + no_direct_standard_out_logs: + name: "Writing log messages directly to standard out is disallowed" + regex: "(\\bprint|\\bdebugPrint|\\bdump|Swift\\.print|Swift\\.debugPrint|Swift\\.dump)\\s*\\(" + match_kinds: + - identifier + message: "Don't commit `print(…)`, `debugPrint(…)`, or `dump(…)` as they write to standard out in release. Either log to a dedicated logging system or silence this warning in debug-only scenarios explicitly using `// swiftlint:disable:next no_direct_standard_out_logs`" + severity: error + no_file_literal: + name: "#file is disallowed" + regex: "(\\b#file\\b)" + match_kinds: + - identifier + message: "Instead of #file, use #fileID" + severity: error + no_filepath_literal: + name: "#filePath is disallowed" + regex: "(\\b#filePath\\b)" + match_kinds: + - identifier + message: "Instead of #filePath, use #fileID." + severity: error + no_unchecked_sendable: + name: "`@unchecked Sendable` is discouraged." + regex: "@unchecked Sendable" + match_kinds: + - attribute.builtin + - typeidentifier + message: "Instead of using `@unchecked Sendable`, consider a safe alternative like a standard `Sendable` conformance or using `@preconcurrency import`. If you really must use `@unchecked Sendable`, you can add a `// swiftlint:disable:next no_unchecked_sendable` annotation with an explanation for how we know the type is thread-safe, and why we have to use @unchecked Sendable instead of Sendable. More explanation and suggested safe alternatives are available at https://github.com/airbnb/swift#unchecked-sendable." + severity: error diff --git a/iOS/Projects/App/Project.swift b/iOS/Projects/App/Project.swift index 75c14904..c592389d 100644 --- a/iOS/Projects/App/Project.swift +++ b/iOS/Projects/App/Project.swift @@ -21,11 +21,11 @@ let project = Project.makeModule( "UIWindowSceneSessionRoleApplication": [ [ "UISceneConfigurationName": "Default Configuration", - "UISceneDelegateClassName": "$(PRODUCT_MODULE_NAME).SceneDelegate" - ] - ] - ] - ] + "UISceneDelegateClassName": "$(PRODUCT_MODULE_NAME).SceneDelegate", + ], + ], + ], + ], ] ) ) diff --git a/iOS/Projects/App/Sources/AppDelegate.swift b/iOS/Projects/App/Sources/AppDelegate.swift index c6d93737..1ffc70ad 100644 --- a/iOS/Projects/App/Sources/AppDelegate.swift +++ b/iOS/Projects/App/Sources/AppDelegate.swift @@ -2,19 +2,20 @@ import UIKit @main final class AppDelegate: UIResponder, UIApplicationDelegate { - func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) - -> Bool { + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil + ) + -> Bool { return true } - + func application( - _ application: UIApplication, + _: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions) - -> UISceneConfiguration { - UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + options _: UIScene.ConnectionOptions + ) + -> UISceneConfiguration { + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } } diff --git a/iOS/Projects/App/Sources/SceneDelegate.swift b/iOS/Projects/App/Sources/SceneDelegate.swift index 5ba1962f..983518c7 100644 --- a/iOS/Projects/App/Sources/SceneDelegate.swift +++ b/iOS/Projects/App/Sources/SceneDelegate.swift @@ -9,11 +9,9 @@ import UIKit final class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - + + func scene(_ scene: UIScene, willConnectTo _: UISceneSession, options _: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } window = UIWindow(windowScene: windowScene) window?.rootViewController = ViewController() diff --git a/iOS/Projects/App/Sources/ViewController.swift b/iOS/Projects/App/Sources/ViewController.swift index 477a02c9..fae37c15 100644 --- a/iOS/Projects/App/Sources/ViewController.swift +++ b/iOS/Projects/App/Sources/ViewController.swift @@ -9,10 +9,9 @@ import UIKit final class ViewController: UIViewController { - override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = .systemBackground } } diff --git a/iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift b/iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift index a4bdca3a..e7def573 100644 --- a/iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift +++ b/iOS/Tuist/ProjectDescriptionHelpers/Project+Templates.swift @@ -32,6 +32,7 @@ public extension Project { infoPlist: infoPlist, sources: sources, resources: resources, + scripts: [.swiftLint, .swiftFormat], dependencies: dependencies) let schemes: [Scheme] = [.makeScheme(target: .debug, name: name)] diff --git a/iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift b/iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift index 0477e299..2f4036cd 100644 --- a/iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift +++ b/iOS/Tuist/ProjectDescriptionHelpers/Scripts+Templates.swift @@ -31,18 +31,16 @@ private func swiftLintCommand() -> String { public extension TargetScript { static let swiftFormat: Self = .pre( script: """ - if [ "$CONFIGURATION" == "\(ConfigurationName("WeTri").rawValue)" ]; then - export PATH="$PATH:/opt/homebrew/bin" - if which swiftformat > /dev/null; then - if [ "${ENABLE_PREVIEWS}" = "YES" ]; then - echo "Not running Swift Format for Xcode Previews" - exit 0; - fi - \(swiftFormatCommand()) - else - echo "warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat" - fi - fi + export PATH="$PATH:/opt/homebrew/bin" + if which swiftformat > /dev/null; then + if [ "${ENABLE_PREVIEWS}" = "YES" ]; then + echo "Not running Swift Format for Xcode Previews" + exit 0; + fi + \(swiftFormatCommand()) + else + echo "warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat" + fi """, name: "SwiftFormat Run Script", basedOnDependencyAnalysis: false @@ -50,14 +48,12 @@ public extension TargetScript { static var swiftLint: Self = .post( script: """ - if [ "$CONFIGURATION" == "\(ConfigurationName("WeTri").rawValue)" ]; then - export PATH="$PATH:/opt/homebrew/bin" - if which swiftlint > /dev/null; then - \(swiftLintCommand()) - else - echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" - fi - fi + export PATH="$PATH:/opt/homebrew/bin" + if which swiftlint > /dev/null; then + \(swiftLintCommand()) + else + echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" + fi """, name: "SwiftLint Run Script", basedOnDependencyAnalysis: false