diff --git a/.github/workflows/automatic_pull_request_review.yml b/.github/project_workflows/automatic_pull_request_review.yml similarity index 100% rename from .github/workflows/automatic_pull_request_review.yml rename to .github/project_workflows/automatic_pull_request_review.yml diff --git a/.github/workflows/deploy_app_store.yml b/.github/project_workflows/deploy_app_store.yml similarity index 100% rename from .github/workflows/deploy_app_store.yml rename to .github/project_workflows/deploy_app_store.yml diff --git a/.github/workflows/deploy_production_firebase.yml b/.github/project_workflows/deploy_production_firebase.yml similarity index 100% rename from .github/workflows/deploy_production_firebase.yml rename to .github/project_workflows/deploy_production_firebase.yml diff --git a/.github/workflows/deploy_staging_firebase.yml b/.github/project_workflows/deploy_staging_firebase.yml similarity index 100% rename from .github/workflows/deploy_staging_firebase.yml rename to .github/project_workflows/deploy_staging_firebase.yml diff --git a/.github/workflows/draft_a_new_release.yml b/.github/project_workflows/draft_a_new_release.yml similarity index 100% rename from .github/workflows/draft_a_new_release.yml rename to .github/project_workflows/draft_a_new_release.yml diff --git a/.github/project_workflows/publish_docs_to_wiki.yml b/.github/project_workflows/publish_docs_to_wiki.yml new file mode 100644 index 00000000..dc71b021 --- /dev/null +++ b/.github/project_workflows/publish_docs_to_wiki.yml @@ -0,0 +1,19 @@ +name: Publish docs to Wiki + +on: + push: + paths: + - .github/wiki/** + branches: + - main + - master + +jobs: + publish_docs_to_wiki: + name: Publish Wiki + uses: nimblehq/github-actions-workflows/.github/workflows/publish_wiki.yml@0.1.0 + with: + USER_NAME: team-nimblehq + USER_EMAIL: dev@nimblehq.co + secrets: + USER_TOKEN: ${{ secrets.NIMBLE_DEV_TOKEN }} diff --git a/.github/wiki/Deliverable-Configurations.md b/.github/wiki/Deliverable-Configurations.md index 1568bc23..74aac6d0 100644 --- a/.github/wiki/Deliverable-Configurations.md +++ b/.github/wiki/Deliverable-Configurations.md @@ -6,7 +6,7 @@ The file [DeliverableConstants.rb](https://github.com/nimblehq/ios-templates/blo ## Use the template -1. Running the `make.sh` script will ask if the developer wants to configure the `DeliverableConstants` file. +1. Running the `iOSTemplateMaker` script will ask if the developer wants to configure the `DeliverableConstants` file. 2. When confirming with the prompt, the template will launch Xcode to modify the `DeliverableConstants` file. ## Configure later diff --git a/.github/wiki/Getting-Started.md b/.github/wiki/Getting-Started.md index 0d2af9ad..a6f6ea48 100644 --- a/.github/wiki/Getting-Started.md +++ b/.github/wiki/Getting-Started.md @@ -9,5 +9,21 @@ 2. Clone your repository 3. Setup the project by running the following command in your terminal: ```bash - sh make.sh --bundle-id [BUNDLE_ID_PRODUCTION] --bundle-id-staging [BUNDLE_ID_STAGING] --project-name [PROJECT_NAME] + swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make ``` + +## Options + +Options are optional and will be prompted if not provided. Example is provided in (brackets). + +- `--bundle-id-production`: The application's bundle id for production variant. (co.nimblehq.project) +- `--bundle-id-staging`: The application's bundle id for staging variant. (co.nimblehq.project.staging) +- `--project-name`: The name of the project. (Project) +- `--minimum-version`: The minimum version of the iOS application. (14.0) +- `--interface`: The user interface. (UIKit or SwiftUI) + +### Example + +``` +swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make --bundle-id-production co.nimblehq.ios.templates --bundle-id-staging co.nimblehq.ios.templates.staging --project-name TemplateApp --interface SwiftUI +``` diff --git a/.github/wiki/Selecting-User-Interface.md b/.github/wiki/Selecting-User-Interface.md index 80482ea7..3d07a4a3 100644 --- a/.github/wiki/Selecting-User-Interface.md +++ b/.github/wiki/Selecting-User-Interface.md @@ -7,5 +7,5 @@ Current the template supports setup with two user interfaces: To select a user interface when creating a project pass the argument `--interface [SwiftUI or UIKit]` with the `make` script. ```bash - sh make.sh --bundle-id [BUNDLE_ID_PRODUCTION] --bundle-id-staging [BUNDLE_ID_STAGING] --project-name [PROJECT_NAME] --interface SwiftUI + swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make --interface SwiftUI ``` diff --git a/.github/workflows/test_swiftui_install_script.yml b/.github/workflows/test_swiftui_install_script.yml index 7002abae..bded91e1 100644 --- a/.github/workflows/test_swiftui_install_script.yml +++ b/.github/workflows/test_swiftui_install_script.yml @@ -19,7 +19,7 @@ jobs: run: bundle install - name: Start Install Script for SwiftUI Template App - run: sh make.sh --bundle-id co.nimblehq.template --bundle-id-staging co.nimblehq.template.staging --project-name TemplateApp --interface SwiftUI + run: swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make --bundle-id-production co.nimblehq.ios.templates --bundle-id-staging co.nimblehq.ios.templates.staging --project-name TemplateApp --interface SwiftUI - name: Build and Test run: bundle exec fastlane buildAndTest diff --git a/.github/workflows/test_uikit_install_script.yml b/.github/workflows/test_uikit_install_script.yml index d5cc86e9..3f4d0a60 100644 --- a/.github/workflows/test_uikit_install_script.yml +++ b/.github/workflows/test_uikit_install_script.yml @@ -19,7 +19,7 @@ jobs: run: bundle install - name: Start Install Script for UIKit Template App - run: sh make.sh --bundle-id co.nimblehq.template --bundle-id-staging co.nimblehq.template.staging --project-name TemplateApp --interface UIKit + run: swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make --bundle-id-production co.nimblehq.ios.templates --bundle-id-staging co.nimblehq.ios.templates.staging --project-name TemplateApp --interface UIKit - name: Build and Test run: bundle exec fastlane buildAndTest diff --git a/.github/workflows/test_upload_build_to_firebase.yml b/.github/workflows/test_upload_build_to_firebase.yml index 5f8d2655..8b0becfc 100644 --- a/.github/workflows/test_upload_build_to_firebase.yml +++ b/.github/workflows/test_upload_build_to_firebase.yml @@ -47,10 +47,10 @@ jobs: ${{ runner.os }}-pods- - name: Start Install Script for Template App - run: sh make.sh --bundle-id co.nimblehq.ios.templates --bundle-id-staging co.nimblehq.ios.templates.staging --project-name TemplateApp --interface UIKit + run: swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make --bundle-id-production co.nimblehq.ios.templates --bundle-id-staging co.nimblehq.ios.templates.staging --project-name TemplateApp --interface UIKit - name: Start Setup Script for Template App Firebase Upload - run: cat Scripts/Swift/SetUpTestFirebase.swift Scripts/Swift/Extensions/FileManager+Utils.swift | swift - + run: swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make-test-firebase env: MATCH_REPO: ${{ secrets.MATCH_REPO }} STAGING_FIREBASE_APP_ID: ${{ secrets.STAGING_FIREBASE_APP_ID }} diff --git a/.github/workflows/test_upload_build_to_test_flight.yml b/.github/workflows/test_upload_build_to_test_flight.yml index 28baf490..9d68acba 100644 --- a/.github/workflows/test_upload_build_to_test_flight.yml +++ b/.github/workflows/test_upload_build_to_test_flight.yml @@ -44,10 +44,10 @@ jobs: ${{ runner.os }}-pods- - name: Start Install Script for Template App - run: sh make.sh --bundle-id co.nimblehq.ios.templates --bundle-id-staging co.nimblehq.ios.templates.staging --project-name TemplateApp --interface UIKit + run: swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make --bundle-id-production co.nimblehq.ios.templates --bundle-id-staging co.nimblehq.ios.templates.staging --project-name TemplateApp --interface UIKit - name: Start Setup Script for Template App TestFlight Upload - run: cat Scripts/Swift/SetUpTestTestFlight.swift Scripts/Swift/Extensions/FileManager+Utils.swift | swift - + run: swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make-test-test-flight env: MATCH_REPO: ${{ secrets.MATCH_REPO }} API_KEY_ID: ${{ secrets.API_KEY_ID }} diff --git a/.gitignore b/.gitignore index d64a8594..f641b291 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,4 @@ dependencies/ # Environment .env +Scripts/Swift/iOSTemplateMaker/.* diff --git a/README.md b/README.md index 648e5158..86f4b12b 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Our optimized iOS template used in our projects using Xcode Templates 2. Clone your repository 3. Setup the project by running the following command in your terminal: ```bash - sh make.sh --bundle-id [BUNDLE_ID_PRODUCTION] --bundle-id-staging [BUNDLE_ID_STAGING] --project-name [PROJECT_NAME] + swift run --package-path Scripts/Swift/iOSTemplateMaker iOSTemplateMaker make ``` ## Full Documentation @@ -53,4 +53,4 @@ We love open source and do our part in sharing our work with the community! See [our other projects][community] or [hire our team][hire] to help build your product. [community]: https://github.com/nimblehq -[hire]: https://nimblehq.co/ \ No newline at end of file +[hire]: https://nimblehq.co/ diff --git a/Scripts/Swift/SetUpTestFirebase.swift b/Scripts/Swift/SetUpTestFirebase.swift deleted file mode 100644 index f7b36fbb..00000000 --- a/Scripts/Swift/SetUpTestFirebase.swift +++ /dev/null @@ -1,16 +0,0 @@ -let teamIdPlaceholder = "<#teamId#>" -let stagingFirebaseAppIdPlaceholder = "<#stagingFirebaseAppId#>" -let firebaseTesterGroupsPlaceholder = "<#group1#>, <#group2#>" -let matchRepoPlaceholder = "git@github.com:{organization}/{repo}.git" - -let envMatchRepo = ProcessInfo.processInfo.environment["MATCH_REPO"] ?? "" -let envStagingFirebaseAppId = ProcessInfo.processInfo.environment["STAGING_FIREBASE_APP_ID"] ?? "" -let envTeamId = ProcessInfo.processInfo.environment["TEAM_ID"] ?? "" -let firebaseTesterGroup = "nimble" - -let fileManager = FileManager.default - -fileManager.replaceAllOccurrences(of: teamIdPlaceholder, to: envTeamId) -fileManager.replaceAllOccurrences(of: stagingFirebaseAppIdPlaceholder, to: envStagingFirebaseAppId) -fileManager.replaceAllOccurrences(of: firebaseTesterGroupsPlaceholder, to: firebaseTesterGroup) -fileManager.replaceAllOccurrences(of: matchRepoPlaceholder, to: envMatchRepo) diff --git a/Scripts/Swift/SetUpTestTestFlight.swift b/Scripts/Swift/SetUpTestTestFlight.swift deleted file mode 100644 index 950c4952..00000000 --- a/Scripts/Swift/SetUpTestTestFlight.swift +++ /dev/null @@ -1,16 +0,0 @@ -let teamIdPlaceholder = "<#teamId#>" -let apiKeyIdPlaceholder = "<#API_KEY_ID#>" -let issuerIdPlaceholder = "<#ISSUER_ID#>" -let matchRepoPlaceholder = "git@github.com:{organization}/{repo}.git" - -let envMatchRepo = ProcessInfo.processInfo.environment["MATCH_REPO"] ?? "" -let envApiKey = ProcessInfo.processInfo.environment["API_KEY_ID"] ?? "" -let envIssuerId = ProcessInfo.processInfo.environment["ISSUER_ID"] ?? "" -let envTeamId = ProcessInfo.processInfo.environment["TEAM_ID"] ?? "" - -let fileManager = FileManager.default - -fileManager.replaceAllOccurrences(of: teamIdPlaceholder, to: envTeamId) -fileManager.replaceAllOccurrences(of: apiKeyIdPlaceholder, to: envApiKey) -fileManager.replaceAllOccurrences(of: issuerIdPlaceholder, to: envIssuerId) -fileManager.replaceAllOccurrences(of: matchRepoPlaceholder, to: envMatchRepo) diff --git a/Scripts/Swift/iOSTemplateMaker/Package.resolved b/Scripts/Swift/iOSTemplateMaker/Package.resolved new file mode 100644 index 00000000..d429d392 --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", + "version" : "1.2.3" + } + } + ], + "version" : 2 +} diff --git a/Scripts/Swift/iOSTemplateMaker/Package.swift b/Scripts/Swift/iOSTemplateMaker/Package.swift new file mode 100644 index 00000000..46e6dd43 --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version: 5.7.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "iOSTemplateMaker", + products: [ + .executable( + name: "iOSTemplateMaker", + targets: ["iOSTemplateMaker"] + ), + ], + dependencies: [ + .package( + url: "https://github.com/apple/swift-argument-parser.git", + from: "1.0.0" + ), + ], + targets: [ + .executableTarget( + name: "iOSTemplateMaker", + dependencies: [ + .product(name: "ArgumentParser", package: "swift-argument-parser") + ] + ), + ] +) diff --git a/Scripts/Swift/Extensions/FileManager+Utils.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/FileManager+Utils.swift similarity index 82% rename from Scripts/Swift/Extensions/FileManager+Utils.swift rename to Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/FileManager+Utils.swift index 6fd75e11..77b3979a 100644 --- a/Scripts/Swift/Extensions/FileManager+Utils.swift +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/FileManager+Utils.swift @@ -46,13 +46,18 @@ extension FileManager { } } - func createFile(name: String, at directory: String) { + func createDirectory(path: String) { let currentDirectory = currentDirectoryPath do { - try createDirectory(atPath: "\(currentDirectory)/\(directory)", withIntermediateDirectories: true, attributes: nil) + try createDirectory(atPath: "\(currentDirectory)/\(path)", withIntermediateDirectories: true, attributes: nil) } catch { print("Error \(error)") } + } + + func createFile(name: String, at directory: String) { + let currentDirectory = currentDirectoryPath + createDirectory(path: directory) createFile(atPath: "\(currentDirectory)\(directory)\(name)", contents: nil) } @@ -66,7 +71,9 @@ extension FileManager { } func replaceAllOccurrences(of original: String, to replacing: String) { - let files = try? allFiles(in: currentDirectoryPath) + let swiftScriptBuildDirectory = "Scripts/Swift/iOSTemplateMaker/.build".lowercased() + let pngImage = ".png" + let files = try? allFiles(in: currentDirectoryPath, skips: [swiftScriptBuildDirectory, pngImage]) guard let files else { return print("Cannot find any files in current directory") } for file in files { do { @@ -79,7 +86,7 @@ extension FileManager { } } - private func allFiles(in directory: String) throws -> [URL] { + private func allFiles(in directory: String, skips: [String] = []) throws -> [URL] { let url = URL(fileURLWithPath: directory) var files = [URL]() if let enumerator = enumerator( @@ -90,6 +97,7 @@ extension FileManager { let hiddenFolderRegex = "\(directory.replacingOccurrences(of: "/", with: "\\/"))\\/\\..*\\/" for case let fileURL as URL in enumerator { guard !(fileURL.relativePath ~= hiddenFolderRegex) else { continue } + guard !(skips.contains(where: { fileURL.relativePath.lowercased().contains($0) })) else { continue } let fileAttributes = try? fileURL.resourceValues(forKeys:[.isRegularFileKey]) guard fileAttributes?.isRegularFile ?? false else { continue } files.append(fileURL) diff --git a/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/Optional+Utils.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/Optional+Utils.swift new file mode 100644 index 00000000..40610fbe --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/Optional+Utils.swift @@ -0,0 +1,18 @@ +import Foundation + +extension Optional { + + func unwrappedOr(_ defaultValue: Wrapped) -> Wrapped { + switch self { + case .none: + return defaultValue + case let .some(value): + return value + } + } +} + +extension Optional where Wrapped == String { + + var string: String { unwrappedOr("") } +} diff --git a/Scripts/Swift/Extensions/String+Utils.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/String+Utils.swift similarity index 83% rename from Scripts/Swift/Extensions/String+Utils.swift rename to Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/String+Utils.swift index 76ccddaf..527a0b9f 100644 --- a/Scripts/Swift/Extensions/String+Utils.swift +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/String+Utils.swift @@ -1,5 +1,8 @@ +import Foundation + extension String { + /// Match string with regex expression static func ~= (lhs: String, rhs: String) -> Bool { guard let regex = try? NSRegularExpression(pattern: rhs) else { return false } let range = NSRange(location: 0, length: lhs.utf16.count) diff --git a/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Helpers/EnvironmentValue.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Helpers/EnvironmentValue.swift new file mode 100644 index 00000000..295b69c8 --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Helpers/EnvironmentValue.swift @@ -0,0 +1,15 @@ +// +// EnvironmentValue.swift +// +// +// Created by Bliss on 30/8/23. +// + +import Foundation + +enum EnvironmentValue { + + static func value(for key: String) -> String? { + ProcessInfo.processInfo.environment[key] + } +} diff --git a/Scripts/Swift/Helpers/SafeShell.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Helpers/SafeShell.swift similarity index 100% rename from Scripts/Swift/Helpers/SafeShell.swift rename to Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Helpers/SafeShell.swift diff --git a/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Models/EnvironmentKey.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Models/EnvironmentKey.swift new file mode 100644 index 00000000..8fc4fa20 --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Models/EnvironmentKey.swift @@ -0,0 +1,23 @@ +// +// EnvironmentKey.swift +// +// +// Created by Bliss on 30/8/23. +// + +enum EnvironmentKey: String { + + case matchRepo = "MATCH_REPO" + case stagingFirebaseAppId = "STAGING_FIREBASE_APP_ID" + case teamId = "TEAM_ID" + case apiKey = "API_KEY_ID" + case issuerId = "ISSUER_ID" + case isCI = "CI" +} + +extension EnvironmentValue { + + static func value(for key: EnvironmentKey) -> String? { + Self.value(for: key.rawValue) + } +} diff --git a/Scripts/Swift/SetUpCICDService.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpCICDService.swift similarity index 80% rename from Scripts/Swift/SetUpCICDService.swift rename to Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpCICDService.swift index b94d97d4..06436a46 100644 --- a/Scripts/Swift/SetUpCICDService.swift +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpCICDService.swift @@ -1,3 +1,5 @@ +import Foundation + struct SetUpCICDService { enum CICDService { @@ -26,7 +28,7 @@ struct SetUpCICDService { var service: CICDService? = nil while service == nil { print("Which CI/CD service do you use (Can be edited later) [(g)ithub/(b)itrise/(c)odemagic/(l)ater]: ") - service = CICDService(readLine() ?? "") + service = CICDService(readLine().string) } switch service { @@ -34,6 +36,10 @@ struct SetUpCICDService { print("Setting template for Github Actions") fileManager.removeItems(in: "bitrise.yml") fileManager.removeItems(in: "codemagic.yaml") + fileManager.removeItems(in: ".github/workflows") + fileManager.createDirectory(path: ".github/workflows") + fileManager.moveFiles(in: ".github/project_workflows", to: ".github/workflows") + fileManager.removeItems(in: ".github/project_workflows") case .bitrise: print("Setting template for Bitrise") fileManager.removeItems(in: "codemagic.yaml") diff --git a/Scripts/Swift/SetUpDeliveryConstants.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpDeliveryConstants.swift similarity index 100% rename from Scripts/Swift/SetUpDeliveryConstants.swift rename to Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpDeliveryConstants.swift diff --git a/Scripts/Swift/SetUpInterface.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift similarity index 82% rename from Scripts/Swift/SetUpInterface.swift rename to Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift index f34d42b8..9024ea87 100644 --- a/Scripts/Swift/SetUpInterface.swift +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift @@ -1,3 +1,5 @@ +import Foundation + struct SetUpInterface { enum Interface { @@ -5,12 +7,13 @@ struct SetUpInterface { case swiftUI, uiKit init?(_ name: String) { - switch name.lowercased() { - case "s", "swiftui": + let name = name.lowercased() + if name == "s" || name == "swiftui" { self = .swiftUI - case "u", "uikit": + } else if name == "u" || name == "uikit" { self = .uiKit - default: return nil + } else { + return nil } } @@ -40,7 +43,7 @@ struct SetUpInterface { let folderName = interface.folderName fileManager.moveFiles(in: "tuist/Interfaces/\(folderName)/Project", to: "") - fileManager.moveFiles(in: "tuist/Interfaces/\(folderName)/Sources", to: "TemplateApp/Sources") + fileManager.moveFiles(in: "tuist/Interfaces/\(folderName)/Sources", to: "\(projectName)/Sources") fileManager.removeItems(in: "tuist/Interfaces") } } diff --git a/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpTestFirebase.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpTestFirebase.swift new file mode 100644 index 00000000..5f23b513 --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpTestFirebase.swift @@ -0,0 +1,23 @@ +import Foundation + +struct SetUpTestFirebase { + + private let teamIdPlaceholder = "<#teamId#>" + private let stagingFirebaseAppIdPlaceholder = "<#stagingFirebaseAppId#>" + private let firebaseTesterGroupsPlaceholder = "<#group1#>, <#group2#>" + private let matchRepoPlaceholder = "git@github.com:{organization}/{repo}.git" + + private let firebaseTesterGroup = "nimble" + private let fileManager = FileManager.default + + let matchRepo: String + let stagingFirebaseAppId: String + let teamId: String + + func perform() { + fileManager.replaceAllOccurrences(of: teamIdPlaceholder, to: teamId) + fileManager.replaceAllOccurrences(of: stagingFirebaseAppIdPlaceholder, to: stagingFirebaseAppId) + fileManager.replaceAllOccurrences(of: firebaseTesterGroupsPlaceholder, to: firebaseTesterGroup) + fileManager.replaceAllOccurrences(of: matchRepoPlaceholder, to: matchRepo) + } +} diff --git a/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpTestTestFlight.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpTestTestFlight.swift new file mode 100644 index 00000000..5dd58752 --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpTestTestFlight.swift @@ -0,0 +1,23 @@ +import Foundation + +struct SetUpTestTestFlight { + + private let teamIdPlaceholder = "<#teamId#>" + private let apiKeyIdPlaceholder = "<#API_KEY_ID#>" + private let issuerIdPlaceholder = "<#ISSUER_ID#>" + private let matchRepoPlaceholder = "git@github.com:{organization}/{repo}.git" + + private let fileManager = FileManager.default + + let matchRepo: String + let apiKey: String + let issuerId: String + let teamId: String + + func perform() { + fileManager.replaceAllOccurrences(of: teamIdPlaceholder, to: teamId) + fileManager.replaceAllOccurrences(of: apiKeyIdPlaceholder, to: apiKey) + fileManager.replaceAllOccurrences(of: issuerIdPlaceholder, to: issuerId) + fileManager.replaceAllOccurrences(of: matchRepoPlaceholder, to: matchRepo) + } +} diff --git a/Scripts/Swift/SetUpiOSProject.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift similarity index 85% rename from Scripts/Swift/SetUpiOSProject.swift rename to Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift index 9ad2ac5f..412b7a1b 100644 --- a/Scripts/Swift/SetUpiOSProject.swift +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift @@ -1,4 +1,4 @@ -#!/usr/bin/swift +import Foundation class SetUpIOSProject { @@ -14,7 +14,21 @@ class SetUpIOSProject { private var minimumVersion = "" private var interface: SetUpInterface.Interface? private var projectNameNoSpace: String { projectName.trimmingCharacters(in: .whitespacesAndNewlines) } - private var isCI = !(ProcessInfo.processInfo.environment["CI"] ?? "").isEmpty + private var isCI = !((EnvironmentValue.value(for: .isCI)).string).isEmpty + + init( + bundleIdProduction: String = "", + bundleIdStaging: String = "", + projectName: String = "", + minimumVersion: String = "", + interface: String = "" + ) { + self.bundleIdProduction = bundleIdProduction + self.bundleIdStaging = bundleIdStaging + self.projectName = projectName + self.minimumVersion = minimumVersion + self.interface = .init(interface) + } func perform() { readArguments() @@ -34,42 +48,30 @@ class SetUpIOSProject { } private func readArguments() { - // TODO: Should be replaced with ArgumentParser instead of command line - for (index, argument) in CommandLine.arguments.enumerated() { - switch index { - case 1: bundleIdProduction = argument - case 2: bundleIdStaging = argument - case 3: projectName = argument - case 4: minimumVersion = argument - case 5: interface = .init(argument) - default: break - } - } - if isCI { minimumVersion = "14.0" } while bundleIdProduction.isEmpty || !checkPackageName(bundleIdProduction) { print("BUNDLE ID PRODUCTION (i.e. com.example.project):") - bundleIdProduction = readLine() ?? "" + bundleIdProduction = readLine().string } while bundleIdStaging.isEmpty || !checkPackageName(bundleIdStaging) { print("BUNDLE ID STAGING (i.e. com.example.project.staging):") - bundleIdStaging = readLine() ?? "" + bundleIdStaging = readLine().string } while projectName.isEmpty { print("PROJECT NAME (i.e. NewProject):") - projectName = readLine() ?? "" + projectName = readLine().string } while minimumVersion.isEmpty || !checkVersion(minimumVersion) { print("iOS Minimum Version (i.e. 14.0):") - let version = readLine() ?? "" + let version = readLine().string minimumVersion = !version.isEmpty ? version : "14.0" } while interface == nil { print("Interface [(S)wiftUI or (U)IKit]:") - interface = SetUpInterface.Interface(readLine() ?? "") + interface = SetUpInterface.Interface(readLine().string) } } @@ -149,8 +151,8 @@ class SetUpIOSProject { fileManager.removeItems(in: "Workspace.swift") print("Remove script files and git/index") - fileManager.removeItems(in: "make.sh") - fileManager.removeItems(in: ".github/workflows/test_install_script.yml") + fileManager.removeItems(in: ".github/workflows/test_uikit_install_script.yml") + fileManager.removeItems(in: ".github/workflows/test_swiftui_install_script.yml") fileManager.removeItems(in: ".git/index") try safeShell("git reset") } @@ -159,8 +161,6 @@ class SetUpIOSProject { if !isCI { SetUpCICDService().perform() SetUpDeliveryConstants().perform() - fileManager.removeItems(in: "fastlane/Tests") - fileManager.removeItems(in: "set_up_test_testflight.sh") fileManager.removeItems(in: "Scripts") } print("✅ Completed") @@ -191,5 +191,3 @@ class SetUpIOSProject { return valid } } - -SetUpIOSProject().perform() diff --git a/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/iOSTemplateMaker.swift b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/iOSTemplateMaker.swift new file mode 100644 index 00000000..ea1b341d --- /dev/null +++ b/Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/iOSTemplateMaker.swift @@ -0,0 +1,78 @@ +import ArgumentParser +import Foundation + +@main +struct iOSTemplateMaker: ParsableCommand { + + static let configuration: CommandConfiguration = CommandConfiguration( + abstract: "Set up an iOS Project", + subcommands: [Make.self, MakeTestFirebase.self, MakeTestTestFlight.self], + defaultSubcommand: Make.self + ) +} + +extension iOSTemplateMaker { + + struct Make: ParsableCommand { + + @Option(help: "The production id (i.e. com.example.package)") + var bundleIdProduction: String? + @Option(help: "The staging id (i.e. com.example.package.staging)") + var bundleIdStaging: String? + @Option(help: "The project name (i.e. MyApp)") + var projectName: String? + @Option(help: "The minimum iOS version (14.0)") + var minimumVersion: String? + @Option(help: "The user interface framework (SwiftUI or UIKit)") + var interface: String? + + mutating func run() { + SetUpIOSProject( + bundleIdProduction: bundleIdProduction.string, + bundleIdStaging: bundleIdStaging.string, + projectName: projectName.string, + minimumVersion: minimumVersion.string, + interface: interface.string + ).perform() + } + } +} + +extension iOSTemplateMaker { + + struct MakeTestFirebase: ParsableCommand { + + mutating func run() { + let envMatchRepo = EnvironmentValue.value(for: .matchRepo).string + let envStagingFirebaseAppId = EnvironmentValue.value(for: .stagingFirebaseAppId).string + let envTeamId = EnvironmentValue.value(for: .teamId).string + + SetUpTestFirebase( + matchRepo: envMatchRepo, + stagingFirebaseAppId: envStagingFirebaseAppId, + teamId: envTeamId + ).perform() + } + } +} + + +extension iOSTemplateMaker { + + struct MakeTestTestFlight: ParsableCommand { + + mutating func run() { + let envMatchRepo = EnvironmentValue.value(for: .matchRepo).string + let envApiKey = EnvironmentValue.value(for: .apiKey).string + let envIssuerId = EnvironmentValue.value(for: .issuerId).string + let envTeamId = EnvironmentValue.value(for: .teamId).string + + SetUpTestTestFlight( + matchRepo: envMatchRepo, + apiKey: envApiKey, + issuerId: envIssuerId, + teamId: envTeamId + ).perform() + } + } +} diff --git a/Scripts/Swift/iOSTemplateMaker/Tests/iOSTemplateMakerTests/.gitkeep b/Scripts/Swift/iOSTemplateMaker/Tests/iOSTemplateMakerTests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/make.sh b/make.sh deleted file mode 100644 index 61a83ee0..00000000 --- a/make.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/sh -set -e - -# Script inspired by https://gist.github.com/szeidner/613fe4652fc86f083cefa21879d5522b - -readonly PROGNAME=$(basename $0) -readonly WORKING_DIR=$(cd -P -- "$(dirname -- "$0")" && pwd -P) - -die() { - echo "$PROGNAME: $*" >&2 - exit 1 -} - -usage() { - if [ "$*" != "" ] ; then - echo "Error: $*" - fi - - cat << EOF -Usage: $PROGNAME --bundle-id [BUNDLE_ID_PRODUCTION] --bundle-id-staging [BUNDLE_ID_STAGING] --project-name [PROJECT_NAME] --minimum-version [MINIMUM_VERSION] --interface [INTERFACE] -Set up an iOS app from tuist template. -Options: --h, --help display this usage message and exit --b, --bundle-id [BUNDLE_ID_PRODUCTION] the production id (i.e. com.example.package) --s, --bundle-id-staging [BUNDLE_ID_STAGING] the staging id (i.e. com.example.package.staging) --n, --project-name [PROJECT_NAME] the project name (i.e. MyApp) --m, --minimum-version [MINIMUM_VERSION] the minimum version of the project (i.e. 14.0) --i, --interface [INTERFACE] the user interface frameword (SwiftUI or UIKit) -EOF - exit 1 -} - -bundle_id_production="" -bundle_id_staging="" -project_name="" -minimum_version="" -interface="" - -while [ $# -gt 0 ] ; do - case "$1" in - -h|--help) - usage - ;; - -b|--bundle-id) - bundle_id_production="$2" - shift - ;; - -s|--bundle-id-staging) - bundle_id_staging="$2" - shift - ;; - -n|--project-name) - project_name="$2" - shift - ;; - -m|--minimum-version) - minimum_version="$2" - shift - ;; - -i|--interface) - interface="$2" - shift - ;; - -*) - usage "Unknown option '$1'" - ;; - *) - usage "Too many arguments" - ;; - esac - shift -done - -cat Scripts/Swift/SetUpiOSProject.swift Scripts/Swift/SetUpCICDService.swift Scripts/Swift/SetUpDeliveryConstants.swift Scripts/Swift/SetUpInterface.swift Scripts/Swift/Extensions/FileManager+Utils.swift Scripts/Swift/Extensions/String+Utils.swift Scripts/Swift/Helpers/SafeShell.swift > t.swift && swift t.swift $bundle_id_production $bundle_id_staging $project_name "$minimum_version" $interface && rm -rf 't.swift'