From 096ca0d7e91eba9d64061a3b04141b9f78c467e7 Mon Sep 17 00:00:00 2001 From: Arthur Alves Date: Thu, 19 Oct 2023 15:00:17 +0200 Subject: [PATCH 1/3] Release 1.2.0 (#232) * FIX: Github Marketplace action not picking up the latest release automatically [#189] * FIX: Calling variants setup on M1 mac uses M1 unsupported gems in Gemfile [#208] * FIX: Variants setup on M1 mac does not automatically link variants.xcconfig to xcodeproject [#209] * FIX: Some signing configurations not automatically set in Xcode 14 [#214] * REFACTOR: Signing configuration is updated not only during `setup` but also during `switch` [#215] * REFACTOR: Items in `variants.xcconfig` should be sorted alphabetically [#219] * FEATURE: Ability to add a `postSwitch` command/script, both globally or variant specific [#221] * FEATURE: Add ability to override app name per variant [#216] * FEATURE: Expose configuration keys as static variables in swift [#125] --------- Signed-off-by: dependabot[bot] Co-authored-by: romanhu-bb <93975733+romanhu-bb@users.noreply.github.com> Co-authored-by: Aksay Pudukudi Kandhadai (BB) Co-authored-by: Divine Dube Co-authored-by: Nour Sandid Co-authored-by: noursandidb <92526468+noursandidb@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Gabriel Minucci Co-authored-by: Alex Kuziaev --- .github/ISSUE_TEMPLATE/bug.md | 36 +- .github/ISSUE_TEMPLATE/config.yml | 5 + .github/workflows/secrets.yml | 11 +- Dangerfile.swift | 21 +- Gemfile.lock | 11 +- Sources/Variants/main.swift | 2 +- .../Custom Types/Project/iOSProject.swift | 17 +- .../VariantsCore/Factory/ProjectFactory.swift | 3 +- ...actory.swift => VariantsFileFactory.swift} | 50 +- .../Factory/iOS/XCConfigFactory.swift | 85 +++- .../Factory/iOS/XcodeProjFactory.swift | 68 ++- Sources/VariantsCore/Helpers/Constants.swift | 4 + Sources/VariantsCore/Helpers/SpecHelper.swift | 2 + .../Schemas/iOS/iOSConfiguration.swift | 8 +- .../VariantsCore/Schemas/iOS/iOSSigning.swift | 2 + .../VariantsCore/Schemas/iOS/iOSTarget.swift | 2 + .../VariantsCore/Schemas/iOS/iOSVariant.swift | 47 +- Templates/ios/Variants.swift.template.gyb | 15 +- Templates/ios/_fastlane/Gemfile | 8 +- Templates/ios/_fastlane/Gemfile.lock | 330 +++++++------ Templates/ios/_fastlane/fastlane/SwiftLint | 5 +- .../fastlane/parameters/project_params.rb | 3 +- .../FastlaneParametersFactoryTests.swift | 12 +- .../Mocks/MockXCcodeConfigFactory.swift | 2 + ...alid_incomplete_signing_configuration.yml} | 5 + .../Resources/ios/invalid_missing_ios.yml | 49 ++ Tests/VariantsCoreTests/SpecHelperTests.swift | 21 +- Tests/VariantsCoreTests/UserInputTests.swift | 46 ++ ...s.swift => VariantsFileFactoryTests.swift} | 14 +- .../XcodeProjFactoryTests.swift | 9 +- Tests/VariantsCoreTests/YamlParserTests.swift | 38 +- Tests/VariantsCoreTests/iOSProjectTests.swift | 59 ++- Tests/VariantsCoreTests/iOSSigningTests.swift | 110 +++++ Tests/VariantsCoreTests/iOSVariantTests.swift | 253 +++++++--- Tests/VariantsTests/InitCommandTests.swift | 2 + Variants.xcodeproj/project.pbxproj | 24 +- docs/ENVIRONMENT_VARIABLES.md | 33 +- docs/GITHUB_ACTION.md | 2 +- docs/USAGE.md | 12 + docs/ios/POST_SWITCH_SCRIPT.md | 70 +++ samples/ios/VariantsSample/.gitignore | 8 - samples/ios/VariantsSample/Podfile | 18 - samples/ios/VariantsSample/Podfile.lock | 3 - samples/ios/VariantsSample/Pods/Manifest.lock | 3 - ...ntsSample-VariantsSampleUITests-Info.plist | 26 -- ...ntsSampleUITests-acknowledgements.markdown | 3 - ...riantsSampleUITests-acknowledgements.plist | 29 -- ...riantsSample-VariantsSampleUITests-dummy.m | 5 - ...ntsSample-VariantsSampleUITests-umbrella.h | 16 - ...ample-VariantsSampleUITests.debug.xcconfig | 8 - ...antsSample-VariantsSampleUITests.modulemap | 6 - ...ple-VariantsSampleUITests.release.xcconfig | 8 - .../Pods-VariantsSample-Info.plist | 26 -- ...s-VariantsSample-acknowledgements.markdown | 3 - ...Pods-VariantsSample-acknowledgements.plist | 29 -- .../Pods-VariantsSample-dummy.m | 5 - .../Pods-VariantsSample-umbrella.h | 16 - .../Pods-VariantsSample.debug.xcconfig | 8 - .../Pods-VariantsSample.modulemap | 6 - .../Pods-VariantsSample.release.xcconfig | 8 - .../Pods-VariantsSampleTests-Info.plist | 26 -- ...iantsSampleTests-acknowledgements.markdown | 3 - ...VariantsSampleTests-acknowledgements.plist | 29 -- .../Pods-VariantsSampleTests-dummy.m | 5 - .../Pods-VariantsSampleTests-umbrella.h | 16 - .../Pods-VariantsSampleTests.debug.xcconfig | 8 - .../Pods-VariantsSampleTests.modulemap | 6 - .../Pods-VariantsSampleTests.release.xcconfig | 8 - samples/ios/VariantsSample/README.md | 21 - .../contents.xcworkspacedata | 10 - .../VariantsSample/AppDelegate.swift | 33 -- .../AppIcon.appiconset/Contents.json | 98 ---- .../VariantsSample/VariantsSample/Info.plist | 66 --- .../VariantsSample/SceneDelegate.swift | 14 - .../VariantsSampleTests/Info.plist | 22 - .../VariantsSampleTests.swift | 36 -- .../VariantsSampleUITests/Info.plist | 22 - .../VariantsSampleUITests.swift | 47 -- samples/ios/VariantsTestApp/Gemfile | 11 + samples/ios/VariantsTestApp/Gemfile.lock | 317 +++++++++++++ .../VariantsTestApp.xcodeproj/project.pbxproj | 435 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../VariantsTestApp/AppDelegate.swift | 37 ++ .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 14 + .../AppIcon.appiconset/VariantsBlue.png | Bin 0 -> 11879 bytes .../AppIconYellow.appiconset/Contents.json | 14 + .../VariantsYellow.png | Bin 0 -> 11251 bytes .../Assets.xcassets/Contents.json | 0 .../Base.lproj/LaunchScreen.storyboard | 0 .../Base.lproj/Main.storyboard | 0 .../VariantsTestApp/Info.plist | 39 ++ .../VariantsTestApp/SceneDelegate.swift | 52 +++ .../VariantsTestApp/Variants/Variants.swift | 27 ++ .../Variants/variants.xcconfig | 7 + .../VariantsTestApp}/ViewController.swift | 6 +- .../ios/VariantsTestApp/coherent-swift.yml | 4 + .../ios/VariantsTestApp/fastlane/AppCenter | 28 ++ samples/ios/VariantsTestApp/fastlane/Appfile | 6 + samples/ios/VariantsTestApp/fastlane/Appstore | 40 ++ .../ios/VariantsTestApp/fastlane/BadgyLane | 28 ++ .../ios/VariantsTestApp/fastlane/Cocoapods | 16 + samples/ios/VariantsTestApp/fastlane/Cohesion | 11 + samples/ios/VariantsTestApp/fastlane/Coverage | 15 + .../ios/VariantsTestApp/fastlane/Deliverfile | 54 +++ .../ios/VariantsTestApp/fastlane/Dependencies | 35 ++ samples/ios/VariantsTestApp/fastlane/Deploy | 91 ++++ samples/ios/VariantsTestApp/fastlane/Fastfile | 75 +++ samples/ios/VariantsTestApp/fastlane/Lizard | 20 + samples/ios/VariantsTestApp/fastlane/Match | 42 ++ .../ios/VariantsTestApp/fastlane/Matchfile | 5 + .../ios/VariantsTestApp/fastlane/Pluginfile | 4 + samples/ios/VariantsTestApp/fastlane/Slack | 37 ++ samples/ios/VariantsTestApp/fastlane/Sonar | 15 + .../ios/VariantsTestApp/fastlane/SwiftLint | 24 + .../ios/VariantsTestApp/fastlane/TestFlight | 38 ++ samples/ios/VariantsTestApp/fastlane/Tests | 41 ++ .../fastlane/parameters/appcenter_params.rb | 5 + .../fastlane/parameters/appstore_params.rb | 4 + .../fastlane/parameters/lizard_params.rb | 5 + .../fastlane/parameters/match_params.rb | 17 + .../fastlane/parameters/project_params.rb | 13 + .../fastlane/parameters/uitest_params.rb | 5 + .../fastlane/parameters/variants_params.rb | 5 + samples/ios/VariantsTestApp/swiftlint.yml | 13 + samples/ios/VariantsTestApp/variants.yml | 87 ++++ 127 files changed, 2862 insertions(+), 1087 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml rename Sources/VariantsCore/Factory/iOS/{SecretsFactory.swift => VariantsFileFactory.swift} (68%) rename Tests/VariantsCoreTests/Resources/ios/{invalid_missing_signing_configuration.yml => invalid_incomplete_signing_configuration.yml} (92%) create mode 100644 Tests/VariantsCoreTests/Resources/ios/invalid_missing_ios.yml create mode 100644 Tests/VariantsCoreTests/UserInputTests.swift rename Tests/VariantsCoreTests/{SecretsFactoryTests.swift => VariantsFileFactoryTests.swift} (82%) create mode 100644 Tests/VariantsCoreTests/iOSSigningTests.swift create mode 100644 docs/ios/POST_SWITCH_SCRIPT.md delete mode 100644 samples/ios/VariantsSample/.gitignore delete mode 100644 samples/ios/VariantsSample/Podfile delete mode 100644 samples/ios/VariantsSample/Podfile.lock delete mode 100644 samples/ios/VariantsSample/Pods/Manifest.lock delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-Info.plist delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.markdown delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.plist delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-dummy.m delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-umbrella.h delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.debug.xcconfig delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.modulemap delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.release.xcconfig delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-Info.plist delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.markdown delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.plist delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-dummy.m delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-umbrella.h delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.debug.xcconfig delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.modulemap delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.release.xcconfig delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-Info.plist delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.markdown delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.plist delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-dummy.m delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-umbrella.h delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.debug.xcconfig delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.modulemap delete mode 100644 samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.release.xcconfig delete mode 100644 samples/ios/VariantsSample/README.md delete mode 100644 samples/ios/VariantsSample/VariantsSample.xcworkspace/contents.xcworkspacedata delete mode 100644 samples/ios/VariantsSample/VariantsSample/AppDelegate.swift delete mode 100644 samples/ios/VariantsSample/VariantsSample/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 samples/ios/VariantsSample/VariantsSample/Info.plist delete mode 100644 samples/ios/VariantsSample/VariantsSample/SceneDelegate.swift delete mode 100644 samples/ios/VariantsSample/VariantsSampleTests/Info.plist delete mode 100644 samples/ios/VariantsSample/VariantsSampleTests/VariantsSampleTests.swift delete mode 100644 samples/ios/VariantsSample/VariantsSampleUITests/Info.plist delete mode 100644 samples/ios/VariantsSample/VariantsSampleUITests/VariantsSampleUITests.swift create mode 100644 samples/ios/VariantsTestApp/Gemfile create mode 100644 samples/ios/VariantsTestApp/Gemfile.lock create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.pbxproj create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename samples/ios/{VariantsSample/VariantsSample.xcworkspace => VariantsTestApp/VariantsTestApp.xcodeproj/project.xcworkspace}/xcshareddata/IDEWorkspaceChecks.plist (100%) create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/AppDelegate.swift rename samples/ios/{VariantsSample/VariantsSample => VariantsTestApp/VariantsTestApp}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIcon.appiconset/VariantsBlue.png create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIconYellow.appiconset/Contents.json create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIconYellow.appiconset/VariantsYellow.png rename samples/ios/{VariantsSample/VariantsSample => VariantsTestApp/VariantsTestApp}/Assets.xcassets/Contents.json (100%) rename samples/ios/{VariantsSample/VariantsSample => VariantsTestApp/VariantsTestApp}/Base.lproj/LaunchScreen.storyboard (100%) rename samples/ios/{VariantsSample/VariantsSample => VariantsTestApp/VariantsTestApp}/Base.lproj/Main.storyboard (100%) create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/Info.plist create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/SceneDelegate.swift create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/Variants/Variants.swift create mode 100644 samples/ios/VariantsTestApp/VariantsTestApp/Variants/variants.xcconfig rename samples/ios/{VariantsSample/VariantsSample => VariantsTestApp/VariantsTestApp}/ViewController.swift (74%) create mode 100644 samples/ios/VariantsTestApp/coherent-swift.yml create mode 100644 samples/ios/VariantsTestApp/fastlane/AppCenter create mode 100644 samples/ios/VariantsTestApp/fastlane/Appfile create mode 100644 samples/ios/VariantsTestApp/fastlane/Appstore create mode 100644 samples/ios/VariantsTestApp/fastlane/BadgyLane create mode 100644 samples/ios/VariantsTestApp/fastlane/Cocoapods create mode 100644 samples/ios/VariantsTestApp/fastlane/Cohesion create mode 100644 samples/ios/VariantsTestApp/fastlane/Coverage create mode 100644 samples/ios/VariantsTestApp/fastlane/Deliverfile create mode 100644 samples/ios/VariantsTestApp/fastlane/Dependencies create mode 100644 samples/ios/VariantsTestApp/fastlane/Deploy create mode 100644 samples/ios/VariantsTestApp/fastlane/Fastfile create mode 100644 samples/ios/VariantsTestApp/fastlane/Lizard create mode 100644 samples/ios/VariantsTestApp/fastlane/Match create mode 100644 samples/ios/VariantsTestApp/fastlane/Matchfile create mode 100644 samples/ios/VariantsTestApp/fastlane/Pluginfile create mode 100644 samples/ios/VariantsTestApp/fastlane/Slack create mode 100644 samples/ios/VariantsTestApp/fastlane/Sonar create mode 100644 samples/ios/VariantsTestApp/fastlane/SwiftLint create mode 100644 samples/ios/VariantsTestApp/fastlane/TestFlight create mode 100644 samples/ios/VariantsTestApp/fastlane/Tests create mode 100644 samples/ios/VariantsTestApp/fastlane/parameters/appcenter_params.rb create mode 100644 samples/ios/VariantsTestApp/fastlane/parameters/appstore_params.rb create mode 100644 samples/ios/VariantsTestApp/fastlane/parameters/lizard_params.rb create mode 100644 samples/ios/VariantsTestApp/fastlane/parameters/match_params.rb create mode 100644 samples/ios/VariantsTestApp/fastlane/parameters/project_params.rb create mode 100644 samples/ios/VariantsTestApp/fastlane/parameters/uitest_params.rb create mode 100644 samples/ios/VariantsTestApp/fastlane/parameters/variants_params.rb create mode 100644 samples/ios/VariantsTestApp/swiftlint.yml create mode 100644 samples/ios/VariantsTestApp/variants.yml diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 1c7acc3c..960b50c7 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -1,18 +1,34 @@ --- -name: Bug -about: Issue a bug -title: Bug: -labels: bug +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'bug' assignees: '' --- -## Basic information +### Environment ### +**Variants:** + - Way of installation: [e.g. Homebrew, Make, SPM] + - Version [e.g. 1.1.13] -Variants version: -macOS version: -Swift version: +**Your machine:** + - OS: [e.g. MacOS, Windows] + - Processor [e.g. Intel, Apple Silicon] -## Bug/Issue +**Project's platform:** + - Platform: [e.g. iOS, Android] -Describe the bug you've encountered here. +### Describe the bug ### + A clear and concise description of what the bug is. + +**Steps to reproduce** +1. Go to '...' +2. Execute command '....' +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Logs** +If applicable, add error logs. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..0b39d226 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Slack Variants channel + url: https://backbase.slack.com/archives/s-variants/ + about: Please ask your questions here. diff --git a/.github/workflows/secrets.yml b/.github/workflows/secrets.yml index 8305932f..1ef7b7bb 100644 --- a/.github/workflows/secrets.yml +++ b/.github/workflows/secrets.yml @@ -6,14 +6,17 @@ jobs: gitleaks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: wget + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Fetch .rules.toml uses: wei/wget@v1 with: args: -O .rules.toml https://raw.githubusercontent.com/fnxpt/gitleaks-action/rules/.rules.toml - - name: gitleaks-action + - name: Gitleaks uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE}} + GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} GITLEAKS_CONFIG: .rules.toml diff --git a/Dangerfile.swift b/Dangerfile.swift index 68eba2ac..aa50c369 100644 --- a/Dangerfile.swift +++ b/Dangerfile.swift @@ -31,13 +31,20 @@ var bigPRThreshold = 500 let swiftFilesWithoutCopyright = changedFiles.filter { $0.fileType == .swift - && !danger.utils.readFile($0).contains( - """ - // - // Variants - // - // Copyright (c) Backbase B.V. - https://www.backbase.com - """) + && ( + !danger.utils.readFile($0).contains( + """ + // + // Variants + """ + ) + + || !danger.utils.readFile($0).contains( + """ + // Copyright (c) Backbase B.V. - https://www.backbase.com + """ + ) + ) } if swiftFilesWithoutCopyright.count > 0 { diff --git a/Gemfile.lock b/Gemfile.lock index 60b0e10d..ab351f32 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,7 +3,7 @@ GEM specs: CFPropertyList (3.0.5) rexml - activesupport (7.0.4) + activesupport (7.0.4.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -12,15 +12,17 @@ GEM claide (1.1.0) clamp (1.3.2) colored2 (3.1.2) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.0) i18n (1.12.0) concurrent-ruby (~> 1.0) - minitest (5.16.3) + minitest (5.17.0) nanaimo (0.3.0) nokogiri (1.13.8-arm64-darwin) racc (~> 1.4) nokogiri (1.13.8-x86_64-darwin) racc (~> 1.4) + nokogiri (1.13.8-x86_64-linux) + racc (~> 1.4) racc (1.6.0) rexml (3.2.5) slather (2.7.2) @@ -29,7 +31,7 @@ GEM clamp (~> 1.3) nokogiri (~> 1.12) xcodeproj (~> 1.21) - tzinfo (2.0.5) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) @@ -42,6 +44,7 @@ GEM PLATFORMS arm64-darwin-21 x86_64-darwin-21 + x86_64-linux DEPENDENCIES nokogiri (>= 1.13.2) diff --git a/Sources/Variants/main.swift b/Sources/Variants/main.swift index 61a249fc..84ca8396 100644 --- a/Sources/Variants/main.swift +++ b/Sources/Variants/main.swift @@ -12,7 +12,7 @@ struct Variants: ParsableCommand { static var configuration = CommandConfiguration( commandName: "variants", abstract: "A command-line tool to setup deployment variants and working CI/CD setup", - version: "1.1.3", + version: "1.2.0", subcommands: [ Initializer.self, Setup.self, diff --git a/Sources/VariantsCore/Custom Types/Project/iOSProject.swift b/Sources/VariantsCore/Custom Types/Project/iOSProject.swift index f1692bd5..e529f7ca 100644 --- a/Sources/VariantsCore/Custom Types/Project/iOSProject.swift +++ b/Sources/VariantsCore/Custom Types/Project/iOSProject.swift @@ -48,6 +48,10 @@ class iOSProject: Project { } catch { throw RuntimeError("Unable to switch variants - Check your YAML spec") } + + if let postSwitchScript = desiredVariant.postSwitchScript { + try self.runPostSwitchScript(postSwitchScript) + } } override func list(spec: String) throws -> [Variant] { @@ -60,11 +64,7 @@ class iOSProject: Project { // MARK: - Private - private func loadConfiguration(_ path: String?) throws -> iOSConfiguration? { - guard let path = path else { - throw ValidationError("Error: Use '-s' to specify the configuration file") - } - + private func loadConfiguration(_ path: String) throws -> iOSConfiguration? { let configurationPath = Path(path) guard !configurationPath.isDirectory else { throw ValidationError("Error: \(configurationPath) is a directory path") @@ -109,6 +109,11 @@ class iOSProject: Project { try parametersFactory.createMatchFile(using: variant, target: namedTarget.value) } } + + private func runPostSwitchScript(_ script: String) throws { + guard let outputString = try Bash("bash", arguments: "-c", script).capture() else { return } + Logger.shared.logInfo(item: outputString) + } private func createVariants(with configuration: iOSConfiguration, spec: String) throws { try configuration.targets @@ -233,3 +238,5 @@ class iOSProject: Project { private let configFactory: XCFactory private let parametersFactory: ParametersFactory } + +// swiftlint:enable type_name diff --git a/Sources/VariantsCore/Factory/ProjectFactory.swift b/Sources/VariantsCore/Factory/ProjectFactory.swift index a5c22a53..9b0a2847 100644 --- a/Sources/VariantsCore/Factory/ProjectFactory.swift +++ b/Sources/VariantsCore/Factory/ProjectFactory.swift @@ -18,7 +18,8 @@ struct ProjectFactory { templatePath: Path("/ios/variants-template.yml"), userInputSource: interactiveShell, userInput: { readLine() } - ) + ), + configFactory: XCConfigFactory(logger: logger) ) case .android: return AndroidProject( diff --git a/Sources/VariantsCore/Factory/iOS/SecretsFactory.swift b/Sources/VariantsCore/Factory/iOS/VariantsFileFactory.swift similarity index 68% rename from Sources/VariantsCore/Factory/iOS/SecretsFactory.swift rename to Sources/VariantsCore/Factory/iOS/VariantsFileFactory.swift index e608c8fc..75ec6b28 100644 --- a/Sources/VariantsCore/Factory/iOS/SecretsFactory.swift +++ b/Sources/VariantsCore/Factory/iOS/VariantsFileFactory.swift @@ -9,46 +9,44 @@ import Foundation import PathKit import Stencil -class SecretsFactory { +class VariantsFileFactory { init(logger: Logger = Logger(verbose: false)) { self.logger = logger } - /// Updates `Variants.swift` with `Variants.Secrets` containing - /// encrypted static variables + /// Updates `Variants.swift` with `Variants.Secrets` containing encrypted static variables + /// and `Variants.ConfigurationValueKey` as keys for custom configuration values /// - Parameters: /// - configFilePath: Path to XCConfig file /// - variant: Chosen variant, as seen in `variants.yml` - func updateSecrets(with configFilePath: Path, variant: iOSVariant) { + func updateVariantsFile(with configFilePath: Path, variant: iOSVariant) { do { let path = try TemplateDirectory().path guard let variantsGybTemplatePath = try? path.safeJoin(path: Path("ios/")) else { return } + let secrets = variant.custom?.secrets() ?? [] + let configurationValues = variant.custom?.configurationValues() ?? [] + let context = [ + "secrets": secrets, + "configurationValues": configurationValues + ] as [String: Any] - if let secrets = variant.custom?.envVars() { - let context = [ - "secrets": secrets - ] as [String: Any] - - let environment = Environment(loader: FileSystemLoader(paths: [variantsGybTemplatePath.absolute()])) - let rendered = try environment.renderTemplate(name: StaticPath.Template.variantsSwiftGybFileName, - context: context) - - // Replace multiple empty lines by one only - let lines = rendered.split(whereSeparator: \.isNewline) - let content = lines.joined(separator: "\n") - - try write(Data(content.utf8), using: configFilePath.parent().absolute()) - - let variantsGybFile = try configFilePath.parent().absolute() - .safeJoin(path: Path(StaticPath.Xcode.variantsGybFileName)) - try variantsGybFile.delete() - } + let environment = Environment(loader: FileSystemLoader(paths: [variantsGybTemplatePath.absolute()])) + let rendered = try environment.renderTemplate(name: StaticPath.Template.variantsSwiftGybFileName, + context: context) + // Replace multiple empty lines by one only + let lines = rendered.split(whereSeparator: \.isNewline) + let content = lines.joined(separator: "\n") + + try write(Data(content.utf8), using: configFilePath.parent().absolute()) + let variantsGybFile = try configFilePath.parent().absolute() + .safeJoin(path: Path(StaticPath.Xcode.variantsGybFileName)) + try variantsGybFile.delete() } catch { let variantsFile = try? configFilePath.parent().absolute() .safeJoin(path: Path(StaticPath.Xcode.variantsFileName)) logger.logWarning(item: """ - Something went wrong while generating 'Variants.Secrets' in '\(variantsFile ?? "Variants.swift")' + Something went wrong while generating '\(variantsFile ?? "Variants.swift")' """) dump(error) } @@ -96,7 +94,7 @@ class SecretsFactory { } fileprivate extension Sequence where Iterator.Element == CustomProperty { - func envVars() -> [CustomProperty] { + func secrets() -> [CustomProperty] { return self .filter({ $0.destination == .project && $0.isEnvironmentVariable }) .map { (property) -> CustomProperty in @@ -106,7 +104,7 @@ fileprivate extension Sequence where Iterator.Element == CustomProperty { } } - func literal() -> [CustomProperty] { + func configurationValues() -> [CustomProperty] { return self .filter({ $0.destination == .project && !$0.isEnvironmentVariable }) } diff --git a/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift b/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift index e950853f..1e4968c3 100644 --- a/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift +++ b/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift @@ -23,8 +23,8 @@ protocol XCFactory { } class XCConfigFactory: XCFactory { - init(logLevel: Bool = false) { - logger = Logger(verbose: logLevel) + init(logger: Logger = Logger(verbose: false)) { + self.logger = logger } func write(_ stringContent: String, toFile file: Path, force: Bool) -> (Bool, Path?) { @@ -58,7 +58,6 @@ class XCConfigFactory: XCFactory { try encodedJSONString.write(toFile: file.absolute().description, atomically: true, encoding: .utf8) return (true, file) - } catch { return (false, nil) } @@ -76,7 +75,6 @@ class XCConfigFactory: XCFactory { throw RuntimeError("Attempting to create \(xcconfigFileName) - Path to Xcode Project not found") } let xcodeProjPath = Path(xcodeProj) - let configString = target.value.source.config logger.logInfo("Checking if \(xcconfigFileName) exists", item: "") @@ -93,30 +91,33 @@ class XCConfigFactory: XCFactory { _ = write("", toFile: xcodeConfigPath, force: true) logger.logInfo("Created file: ", item: "'\(xcconfigFileName)' at \(xcodeConfigPath.parent().abbreviate().description)") - - populateConfig(with: target.value, configFile: xcodeConfigPath, variant: variant) - + populateConfig(with: target, configFile: xcodeConfigPath, variant: variant) + /* * If template files should be added to Xcode Project */ if addToXcodeProj ?? false { addToXcode(xcodeConfigPath, toProject: xcodeProjPath, sourceRoot: configPath, target: target, variant: variant) } - + + /* + * Adjust signing configuration in project.pbxproj + */ + updateSigningConfig(for: variant, inTarget: target, projectPath: xcodeProjPath) + /* * INFO.plist */ let infoPath = target.value.source.info let infoPlistPath = Path("\(configPath)/\(infoPath)") - updateInfoPlist(with: target.value, configFile: infoPlistPath, variant: variant) /* * Add custom properties whose values should be read from environment variables * to `Variants.Secret` as encrypted secrets. */ - let secretsFactory = SecretsFactory(logger: logger) - secretsFactory.updateSecrets(with: xcodeConfigPath, variant: variant) + let variantsFileFactory = VariantsFileFactory(logger: logger) + variantsFileFactory.updateVariantsFile(with: xcodeConfigPath, variant: variant) } // MARK: - Private methods @@ -127,7 +128,6 @@ class XCConfigFactory: XCFactory { target: NamedTarget, variant: iOSVariant) { let variantsFile = Path("\(xcConfigFile.parent().absolute().description)/Variants.swift") - do { let path = try TemplateDirectory().path try Bash("cp", arguments: @@ -138,18 +138,11 @@ class XCConfigFactory: XCFactory { let xcodeFactory = XcodeProjFactory() xcodeFactory.add([xcConfigFile, variantsFile], toProject: projectPath, sourceRoot: sourceRoot, target: target) - var mainTargetSettings = [ + let mainTargetSettings = [ "PRODUCT_BUNDLE_IDENTIFIER": "$(V_BUNDLE_ID)", "PRODUCT_NAME": "$(V_APP_NAME)", "ASSETCATALOG_COMPILER_APPICON_NAME": "$(V_APP_ICON)" ] - - if - variant.signing?.matchURL != nil, - variant.signing?.exportMethod != nil { - mainTargetSettings["PROVISIONING_PROFILE_SPECIFIER"] = "$(V_MATCH_PROFILE)" - } - xcodeFactory.modify(mainTargetSettings, in: projectPath, target: target.value) xcodeFactory.modify( @@ -159,15 +152,15 @@ class XCConfigFactory: XCFactory { in: projectPath, target: target.value, asTestSettings: true) - } catch { logger.logError("❌ ", item: "Failed to add Variants.swift to Xcode Project") } } - - private func populateConfig(with target: iOSTarget, configFile: Path, variant: iOSVariant) { + + private func populateConfig(with target: NamedTarget, configFile: Path, variant: iOSVariant) { logger.logInfo("Populating: ", item: "'\(configFile.lastComponent)'") - variant.getDefaultValues(for: target).forEach { (key, value) in + importPodsIfNeeded(target: target, configFile: configFile) + variant.getDefaultValues(for: target.value).forEach { (key, value) in let stringContent = "\(key) = \(value)" logger.logDebug("Item: ", item: stringContent, indentationLevel: 1, color: .purple) @@ -177,9 +170,50 @@ class XCConfigFactory: XCFactory { } } } + + private func updateSigningConfig( + for variant: iOSVariant, + inTarget target: NamedTarget, + projectPath: Path + ) { + guard + let exportMethod = variant.signing?.exportMethod, + let teamName = variant.signing?.teamName, + let teamID = variant.signing?.teamID, + !teamID.isEmpty, + !teamName.isEmpty + else { return } + + let xcodeFactory = XcodeProjFactory() + var certType = "Development" + if exportMethod == .appstore || exportMethod == .enterprise { + certType = "Distribution" + } + let mainTargetSettings = [ + "PROVISIONING_PROFILE_SPECIFIER": "$(V_MATCH_PROFILE)", + "CODE_SIGN_STYLE": "Manual", + "CODE_SIGN_IDENTITY": "Apple \(certType): \(teamName) (\(teamID))" + ] + xcodeFactory.modify(mainTargetSettings, in: projectPath, target: target.value) + } + + private func importPodsIfNeeded(target: NamedTarget, configFile: Path) { + guard StaticPath.Pod.podFileFile.exists else { return } + // this regex finds a folder that starts with Pods and ends with the target key, with a ".release.xcconfig" extension. + let podConfigFileRegex: String = "./Pods/Target Support Files/Pods.*-\(target.key)/.*\\.release\\.xcconfig" + guard let podsConfigFile: String = try? Bash("find | head -n 1", arguments: ".", "-regex", podConfigFileRegex).capture(), + !podsConfigFile.isEmpty else { + logger.logError("❌ ", item: "Failed to import Pods config in .xcconfig, Pod config file not found") + return + } + let includeStatement = "#include \"\(podsConfigFile)\"" + let (success, _) = write(includeStatement, toFile: configFile, force: false) + if !success { + logger.logError("❌ ", item: "Failed to add item to .xcconfig") + } + } private func updateInfoPlist(with target: iOSTarget, configFile: Path, variant: iOSVariant) { - let configFilePath = configFile.absolute().description do { // TODO: Add plutil as separate command? @@ -187,6 +221,7 @@ class XCConfigFactory: XCFactory { Bash("plutil", arguments: "-replace", "CFBundleVersion", "-string", "$(V_VERSION_NUMBER)", configFilePath), Bash("plutil", arguments: "-replace", "CFBundleShortVersionString", "-string", "$(V_VERSION_NAME)", configFilePath), Bash("plutil", arguments: "-replace", "CFBundleName", "-string", "$(V_APP_NAME)", configFilePath), + Bash("plutil", arguments: "-replace", "CFBundleDisplayName", "-string", "$(V_APP_NAME)", configFilePath), Bash("plutil", arguments: "-replace", "CFBundleExecutable", "-string", "$(V_APP_NAME)", configFilePath), Bash("plutil", arguments: "-replace", "CFBundleIdentifier", "-string", "$(V_BUNDLE_ID)", configFilePath) ] diff --git a/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift b/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift index 4a391770..9dcf19d4 100644 --- a/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift +++ b/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift @@ -5,6 +5,8 @@ // Created by Arthur Alves // +// swiftlint:disable file_length + import Foundation import XcodeProj import PathKit @@ -110,16 +112,20 @@ struct XcodeProjFactory { func add(_ files: [Path], toProject projectPath: Path, sourceRoot: Path, target: NamedTarget) { do { let project = try XcodeProj(path: projectPath) - - let variantsGroup = try varientsGroup(for: projectPath, sourceRoot: sourceRoot, target: target) - - try files.forEach { file in - try write(to: file, projectPath: projectPath, variantsGroup: variantsGroup, sourceRoot: sourceRoot, target: target) + let variantsGroup = try createVarientsGroup(for: project, path: projectPath, sourceRoot: sourceRoot, target: target) + for file in files { + try add( + file: file, + to: project, + path: projectPath, + variantsGroup: variantsGroup, + sourceRoot: sourceRoot, + target: target + ) } try project.write(path: projectPath) } catch { - dump(error) - logger.logFatal("❌ ", item: "Unable to add files to Xcode project '\(projectPath)'") + logger.logFatal("❌ ", item: "Unable to add files to Xcode project '\(projectPath)', error: '\(error.localizedDescription)'") } } @@ -190,32 +196,46 @@ struct XcodeProjFactory { private extension XcodeProjFactory { - private func varientsGroup(for projectPath: Path, sourceRoot: Path, target: NamedTarget) throws -> PBXGroup?{ - let variantsGroupPath = Path("\(projectPath)/Variants") - let project = try XcodeProj(path: projectPath) - + private func createVarientsGroup( + for project: XcodeProj, + path: Path, + sourceRoot: Path, + target: NamedTarget + ) throws -> PBXGroup? { + let variantsGroupPath = Path("\(path)/Variants") let rootGroup = project.pbxproj.groups.first(where: { $0.path == sourceRoot.lastComponent }) try rootGroup?.addGroup(named: variantsGroupPath.lastComponent) let variantsGroup = rootGroup?.group(named: variantsGroupPath.lastComponent) return variantsGroup } - private func write(to file: Path, projectPath: Path, variantsGroup: PBXGroup?, sourceRoot: Path, target: NamedTarget) throws { - let project = try XcodeProj(path: projectPath) + // swiftlint:disable function_parameter_count + private func add( + file: Path, + to project: XcodeProj, + path: Path, + variantsGroup: PBXGroup?, + sourceRoot: Path, + target: NamedTarget + ) throws { guard let pbxTarget = project.pbxproj.targets(named: target.key).first else { logger.logFatal("❌ ", item: "Could not add files to Xcode project - Target '\(target.key)' not found.") return } - - let fileRef = try variantsGroup?.addFile(at: file, - sourceTree: .group, - sourceRoot: sourceRoot, - validatePresence: true) - let fileElement = PBXFileElement(sourceTree: .group, - path: file.description, - name: file.lastComponent) + let fileRef = try variantsGroup?.addFile( + at: file, + sourceTree: .group, + sourceRoot: sourceRoot, + validatePresence: true + ) + + let fileElement = PBXFileElement( + sourceTree: .group, + path: file.description, + name: file.lastComponent + ) let buildFile = PBXBuildFile(file: fileElement) let sourceBuildPhase = try pbxTarget.sourcesBuildPhase() sourceBuildPhase?.files?.append(buildFile) @@ -223,9 +243,11 @@ private extension XcodeProjFactory { /* * If .xcconfig, set baseConfigurationReference to it */ - if file.lastComponent.contains(".xcconfig"), let fileReference = fileRef { - changeBaseConfig(fileReference, in: project, path: projectPath, + if file.extension == "xcconfig", let fileReference = fileRef { + changeBaseConfig(fileReference, in: project, path: path, target: target, autoSave: true) } } + // swiftlint:enable function_parameter_count } +// swiftlint:enable file_length diff --git a/Sources/VariantsCore/Helpers/Constants.swift b/Sources/VariantsCore/Helpers/Constants.swift index 6ff3840f..baf93062 100644 --- a/Sources/VariantsCore/Helpers/Constants.swift +++ b/Sources/VariantsCore/Helpers/Constants.swift @@ -30,6 +30,10 @@ struct StaticPath { static let variantsFileName = "Variants.swift" } + struct Pod { + static let podFileFile = Path("Podfile") + } + struct Template { static let variantsScriptFileName = "variants-template.gradle" static let fastlaneParametersFileName = "variants_params_template.rb" diff --git a/Sources/VariantsCore/Helpers/SpecHelper.swift b/Sources/VariantsCore/Helpers/SpecHelper.swift index 9cdd41d3..80e9b642 100644 --- a/Sources/VariantsCore/Helpers/SpecHelper.swift +++ b/Sources/VariantsCore/Helpers/SpecHelper.swift @@ -155,3 +155,5 @@ class iOSSpecHelper: SpecHelper { // MARK: - Android class AndroidSpecHelper: SpecHelper {} + +// swiftlint:enable type_name diff --git a/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift b/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift index 682334f5..99f35a60 100644 --- a/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift +++ b/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift @@ -18,6 +18,8 @@ public struct iOSConfiguration: Codable { let targets: [String: iOSTarget] let variants: [iOSVariant] let custom: [CustomProperty]? + + private let postSwitchScript: String? private let signing: iOSSigning? var pbxproj: String { @@ -31,11 +33,15 @@ public struct iOSConfiguration: Codable { self.targets = try container.decode([String: iOSTarget].self, forKey: .targets) self.custom = try? container.decode([CustomProperty].self, forKey: .custom) + let globalPostSwitchScript = try container.decodeIfPresent(String.self, forKey: .postSwitchScript) let globalSigning = try container.decodeIfPresent(iOSSigning.self, forKey: .signing) let variantsDict = try container.decode([String: UnnamediOSVariant].self, forKey: .variants) + self.postSwitchScript = globalPostSwitchScript self.signing = globalSigning self.variants = try variantsDict - .map { try iOSVariant(from: $1, name: $0, globalSigning: globalSigning) } + .map { try iOSVariant(from: $1, name: $0, globalSigning: globalSigning, globalPostSwitchScript: globalPostSwitchScript) } } } + +// swiftlint:enable type_name diff --git a/Sources/VariantsCore/Schemas/iOS/iOSSigning.swift b/Sources/VariantsCore/Schemas/iOS/iOSSigning.swift index ee68e89a..a11d516d 100644 --- a/Sources/VariantsCore/Schemas/iOS/iOSSigning.swift +++ b/Sources/VariantsCore/Schemas/iOS/iOSSigning.swift @@ -92,3 +92,5 @@ extension iOSSigning { return signing } } + +// swiftlint:enable type_name diff --git a/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift b/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift index a7f48367..2e1bd843 100644 --- a/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift +++ b/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift @@ -32,3 +32,5 @@ public struct iOSSource: Codable { let info: String let config: String } + +// swiftlint:enable type_name diff --git a/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift b/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift index 21d07129..1bf1d1c4 100644 --- a/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift +++ b/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift @@ -14,9 +14,12 @@ public struct iOSVariant: Variant { let versionName: String let versionNumber: Int let appIcon: String? + let appName: String? let storeDestination: Destination let signing: iOSSigning? let custom: [CustomProperty]? + let postSwitchScript: String? + private let bundleNamingOption: BundleNamingOption public var title: String { name } @@ -35,17 +38,21 @@ public struct iOSVariant: Variant { } init( - name: String, versionName: String, versionNumber: Int, appIcon: String?, storeDestination: String?, - custom: [CustomProperty]?, idSuffix: String?, bundleID: String?, variantSigning: iOSSigning?, globalSigning: iOSSigning?) + name: String, versionName: String, versionNumber: Int, appIcon: String?, appName: String?, storeDestination: String?, + custom: [CustomProperty]?, idSuffix: String?, bundleID: String?, variantSigning: iOSSigning?, globalSigning: iOSSigning?, + globalPostSwitchScript: String?, variantPostSwitchScript: String?) throws { self.name = name self.versionName = versionName self.versionNumber = versionNumber self.appIcon = appIcon + self.appName = appName self.storeDestination = try Self.parseDestination(name: name, destination: storeDestination) ?? .appStore self.signing = try Self.parseSigning(name: name, variantSigning: variantSigning, globalSigning: globalSigning) self.custom = custom self.bundleNamingOption = try Self.parseBundleConfiguration(name: name, idSuffix: idSuffix, bundleID: bundleID) + self.postSwitchScript = Self.parsePostSwitchScript(globalScript: globalPostSwitchScript, + variantScript: variantPostSwitchScript) } func makeBundleID(for target: iOSTarget) -> String { @@ -59,9 +66,9 @@ public struct iOSVariant: Variant { } } - func getDefaultValues(for target: iOSTarget) -> [String: String] { + func getDefaultValues(for target: iOSTarget) -> [(key: String, value: String)] { var customDictionary: [String: String] = [ - "V_APP_NAME": target.name + configName, + "V_APP_NAME": appName ?? target.name + configName, "V_BUNDLE_ID": makeBundleID(for: target), "V_VERSION_NAME": versionName, "V_VERSION_NUMBER": String(versionNumber), @@ -76,7 +83,7 @@ public struct iOSVariant: Variant { .filter { $0.destination == .project && !$0.isEnvironmentVariable } .forEach { customDictionary[$0.name] = $0.value } - return customDictionary + return customDictionary.sorted(by: {$0.key < $1.key}) } private static func parseDestination(name: String, destination: String?) throws -> Destination? { @@ -101,11 +108,24 @@ public struct iOSVariant: Variant { } else if let globalSigning = globalSigning { return try globalSigning ~ nil } else { - throw RuntimeError( + Logger.shared.logWarning(item: """ Variant "\(name)" doesn't contain a 'signing' configuration. \ Create a global 'signing' configuration or make sure all variants have this property. """) + return nil + } + } + + private static func parsePostSwitchScript(globalScript: String?, variantScript: String?) -> String? { + if let globalScript = globalScript, let variantScript = variantScript { + return "\(globalScript) && \(variantScript)" + } else if let globalScript = globalScript { + return globalScript + } else if let variantScript = variantScript { + return variantScript + } else { + return nil } } @@ -148,21 +168,25 @@ struct UnnamediOSVariant: Codable { let versionName: String let versionNumber: Int let appIcon: String? + let appName: String? let idSuffix: String? let bundleID: String? let signing: iOSSigning? let custom: [CustomProperty]? let storeDestination: String? + let postSwitchScript: String? enum CodingKeys: String, CodingKey { case versionName = "version_name" case versionNumber = "version_number" case appIcon = "app_icon" + case appName = "app_name" case idSuffix = "id_suffix" case bundleID = "bundle_id" case signing case custom case storeDestination = "store_destination" + case postSwitchScript } } @@ -172,26 +196,33 @@ extension UnnamediOSVariant { versionName = try values.decodeOrReadFromEnv(String.self, forKey: .versionName) versionNumber = try values.decodeOrReadFromEnv(Int.self, forKey: .versionNumber) appIcon = try values.decodeIfPresentOrReadFromEnv(String.self, forKey: .appIcon) + appName = try values.decodeIfPresentOrReadFromEnv(String.self, forKey: .appName) idSuffix = try values.decodeIfPresentOrReadFromEnv(String.self, forKey: .idSuffix) bundleID = try values.decodeIfPresentOrReadFromEnv(String.self, forKey: .bundleID) signing = try values.decodeIfPresent(iOSSigning.self, forKey: .signing) custom = try values.decodeIfPresent([CustomProperty].self, forKey: .custom) storeDestination = try values.decodeIfPresentOrReadFromEnv(String.self, forKey: .storeDestination) + postSwitchScript = try values.decodeIfPresent(String.self, forKey: .postSwitchScript) } } extension iOSVariant { - init(from unnamediOSVariant: UnnamediOSVariant, name: String, globalSigning: iOSSigning?) throws { + init(from unnamediOSVariant: UnnamediOSVariant, name: String, globalSigning: iOSSigning?, globalPostSwitchScript: String?) throws { try self.init( name: name, versionName: unnamediOSVariant.versionName, versionNumber: unnamediOSVariant.versionNumber, appIcon: unnamediOSVariant.appIcon, + appName: unnamediOSVariant.appName, storeDestination: unnamediOSVariant.storeDestination, custom: unnamediOSVariant.custom, idSuffix: unnamediOSVariant.idSuffix, bundleID: unnamediOSVariant.bundleID, variantSigning: unnamediOSVariant.signing, - globalSigning: globalSigning) + globalSigning: globalSigning, + globalPostSwitchScript: globalPostSwitchScript, + variantPostSwitchScript: unnamediOSVariant.postSwitchScript) } } + +// swiftlint:enable type_name diff --git a/Templates/ios/Variants.swift.template.gyb b/Templates/ios/Variants.swift.template.gyb index 4cee6892..c7d01afc 100644 --- a/Templates/ios/Variants.swift.template.gyb +++ b/Templates/ios/Variants.swift.template.gyb @@ -25,9 +25,22 @@ public struct Variants { } return infoDictionary }() + {% if configurationValues %} + // MARK: - ConfigurationValueKey + /// Custom configuration values coming from variants.yml as enum cases + public enum ConfigurationValueKey: String { {% for confValue in configurationValues %} + case {{ confValue.name }} {% endfor %} + } + + static func configurationValue(for key: ConfigurationValueKey) -> Any? { + return Self.configuration[key.rawValue] + } + {% endif %} + {% if secrets %} - // Encrypted secrets coming from variants.yml as environment variables + // MARK: - Secrets + /// Encrypted secrets coming from variants.yml as environment variables public struct Secrets { diff --git a/Templates/ios/_fastlane/Gemfile b/Templates/ios/_fastlane/Gemfile index d186052b..96c7cc57 100644 --- a/Templates/ios/_fastlane/Gemfile +++ b/Templates/ios/_fastlane/Gemfile @@ -1,11 +1,11 @@ source 'https://rubygems.org' - -gem 'cocoapods', '1.9.0' +​ +gem 'cocoapods', '1.11.3' gem 'cocoapods-art' gem 'fastlane' gem 'slather' gem 'json', '2.3.0' -gem 'nokogiri', '1.11.0' - +gem 'nokogiri', '1.13.5' +​ plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/Templates/ios/_fastlane/Gemfile.lock b/Templates/ios/_fastlane/Gemfile.lock index e6007e00..1498b1fa 100644 --- a/Templates/ios/_fastlane/Gemfile.lock +++ b/Templates/ios/_fastlane/Gemfile.lock @@ -1,130 +1,155 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.2) - activesupport (4.2.11.1) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) - algoliasearch (1.27.1) + CFPropertyList (3.0.6) + rexml + activesupport (6.1.7.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) + artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.1.0) - aws-partitions (1.297.0) - aws-sdk-core (3.94.0) + aws-eventstream (1.2.0) + aws-partitions (1.711.0) + aws-sdk-core (3.170.0) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.239.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.62.0) + aws-sdk-core (~> 3, >= 3.165.0) aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.30.0) - aws-sdk-core (~> 3, >= 3.71.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.61.2) - aws-sdk-core (~> 3, >= 3.83.0) + aws-sdk-s3 (1.119.1) + aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.1) - aws-sigv4 (1.1.1) - aws-eventstream (~> 1.0, >= 1.0.2) - babosa (1.0.3) - claide (1.0.3) - clamp (1.3.1) - cocoapods (1.9.0) - activesupport (>= 4.0.2, < 5) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.2) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + clamp (1.3.2) + cocoapods (1.11.3) + addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.9.0) + cocoapods-core (= 1.11.3) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.2.2, < 2.0) + cocoapods-downloader (>= 1.4.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-stats (>= 1.0.0, < 2.0) cocoapods-trunk (>= 1.4.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) fourflusher (>= 2.3.0, < 3.0) gh_inspector (~> 1.0) - molinillo (~> 0.6.6) + molinillo (~> 0.8.0) nap (~> 1.0) - ruby-macho (~> 1.4) - xcodeproj (>= 1.14.0, < 2.0) - cocoapods-art (1.0.4) - cocoapods-core (1.9.0) - activesupport (>= 4.0.2, < 6) + ruby-macho (>= 1.0, < 3.0) + xcodeproj (>= 1.21.0, < 2.0) + cocoapods-art (1.1.0) + cocoapods-core (1.11.3) + activesupport (>= 5.0, < 7) + addressable (~> 2.8) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) fuzzy_match (~> 2.0.4) nap (~> 1.0) netrc (~> 0.11) + public_suffix (~> 4.0) typhoeus (~> 1.0) - cocoapods-deintegrate (1.0.4) - cocoapods-downloader (1.3.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (1.6.3) cocoapods-plugins (1.0.0) nap - cocoapods-search (1.0.0) - cocoapods-stats (1.1.0) - cocoapods-trunk (1.4.1) + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) nap (>= 0.8, < 2.0) netrc (~> 0.11) - cocoapods-try (1.1.0) - coderay (1.1.2) + cocoapods-try (1.2.0) + coderay (1.1.3) colored (1.2) colored2 (3.1.2) - commander-fastlane (4.4.6) - highline (~> 1.7.2) - concurrent-ruby (1.1.6) - declarative (0.0.10) - declarative-option (0.1.0) - digest-crc (0.5.1) + commander (4.6.0) + highline (~> 2.0.0) + concurrent-ruby (1.2.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.5) - emoji_regex (1.0.1) + dotenv (2.8.1) + emoji_regex (3.2.3) escape (0.0.4) - ethon (0.12.0) - ffi (>= 1.3.0) - excon (0.73.0) - faraday (0.17.3) - multipart-post (>= 1.2, < 3) - faraday-cookie_jar (0.0.6) - faraday (>= 0.7.4) + ethon (0.16.0) + ffi (>= 1.15.0) + excon (0.99.0) + faraday (1.10.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) http-cookie (~> 1.0.0) - faraday_middleware (0.13.1) - faraday (>= 0.7.4, < 1.0) - fastimage (2.1.7) - fastlane (2.145.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.211.0) CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.3, < 3.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) - babosa (>= 1.0.2, < 2.0.0) + babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) colored - commander-fastlane (>= 4.4.6, < 5.0.0) + commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) - emoji_regex (>= 0.1, < 2.0) + emoji_regex (>= 0.1, < 4.0) excon (>= 0.71.0, < 1.0.0) - faraday (~> 0.17) + faraday (~> 1.0) faraday-cookie_jar (~> 0.0.6) - faraday_middleware (~> 0.13.1) + faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) gh_inspector (>= 1.1.2, < 2.0.0) - google-api-client (>= 0.29.2, < 0.37.0) - google-cloud-storage (>= 1.15.0, < 2.0.0) - highline (>= 1.7.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) json (< 3.0.0) - jwt (~> 2.1.0) + jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) - multi_xml (~> 0.5) multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) - public_suffix (~> 2.0.0) - rubyzip (>= 1.3.0, < 2.0.0) + rubyzip (>= 2.0.0, < 3.0.0) security (= 0.1.3) simctl (~> 1.6.3) - slack-notifier (>= 2.0.0, < 3.0.0) terminal-notifier (>= 2.0.0, < 3.0.0) terminal-table (>= 1.4.5, < 2.0.0) tty-screen (>= 0.6.3, < 1.0.0) @@ -133,136 +158,151 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-appcenter (1.8.0) - fastlane-plugin-lizard (1.3.1) + fastlane-plugin-appcenter (2.0.0) + fastlane-plugin-lizard (1.3.3) bundler fastlane pry fastlane-plugin-xcconfig (2.0.0) fastlane-plugin-xchtmlreport (0.1.1) - ffi (1.12.2) + ffi (1.15.5) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-api-client (0.36.4) + google-apis-androidpublisher_v3 (0.34.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-core (0.11.0) addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.9) - httpclient (>= 2.8.1, < 3.0) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) mini_mime (~> 1.0) representable (~> 3.0) - retriable (>= 2.0, < 4.0) - signet (~> 0.12) - google-cloud-core (1.5.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.16.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-playcustomapp_v1 (0.12.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) + google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) - google-cloud-env (1.3.1) - faraday (>= 0.17.3, < 2.0) - google-cloud-errors (1.0.0) - google-cloud-storage (1.26.0) - addressable (~> 2.5) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.3.0) + google-cloud-storage (1.44.0) + addressable (~> 2.8) digest-crc (~> 0.4) - google-api-client (~> 0.33) - google-cloud-core (~> 1.2) - googleauth (~> 0.9) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (0.12.0) - faraday (>= 0.17.3, < 2.0) + googleauth (1.3.0) + faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) - signet (~> 0.14) - highline (1.7.10) - http-cookie (1.0.3) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - i18n (0.9.5) + i18n (1.12.0) concurrent-ruby (~> 1.0) - jmespath (1.4.0) + jmespath (1.6.2) json (2.3.0) - jwt (2.1.0) + jwt (2.7.0) memoist (0.16.2) method_source (1.0.0) - mini_magick (4.10.1) - mini_mime (1.0.2) - mini_portile2 (2.5.0) - minitest (5.14.0) - molinillo (0.6.6) - multi_json (1.14.1) - multi_xml (0.6.0) + mini_magick (4.12.0) + mini_mime (1.1.2) + mini_portile2 (2.8.1) + minitest (5.17.0) + molinillo (0.8.0) + multi_json (1.15.0) multipart-post (2.0.0) - nanaimo (0.2.6) + nanaimo (0.3.0) nap (1.1.0) - naturally (2.2.0) + naturally (2.2.1) netrc (0.11.0) - nokogiri (1.11.0) - mini_portile2 (~> 2.5.0) + nokogiri (1.13.5) + mini_portile2 (~> 2.8.0) racc (~> 1.4) - os (1.1.0) - plist (3.5.0) - pry (0.13.0) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - public_suffix (2.0.5) - racc (1.5.2) - representable (3.0.4) + public_suffix (4.0.7) + racc (1.6.2) + rake (13.0.6) + representable (3.2.0) declarative (< 0.1.0) - declarative-option (< 0.2.0) + trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) + rexml (3.2.5) rouge (2.0.7) - ruby-macho (1.4.0) - rubyzip (1.3.0) + ruby-macho (2.5.1) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) security (0.1.3) - signet (0.14.0) - addressable (~> 2.3) - faraday (>= 0.17.3, < 2.0) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.8) + simctl (1.6.10) CFPropertyList naturally - slack-notifier (2.3.2) - slather (2.4.7) + slather (2.7.2) CFPropertyList (>= 2.2, < 4) - activesupport (>= 4.0.2, < 5) + activesupport clamp (~> 1.3) - nokogiri (~> 1.8) - xcodeproj (~> 1.7) + nokogiri (~> 1.12) + xcodeproj (~> 1.21) terminal-notifier (2.0.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - thread_safe (0.3.6) + trailblazer-option (0.1.2) tty-cursor (0.7.1) - tty-screen (0.7.1) + tty-screen (0.8.1) tty-spinner (0.9.3) tty-cursor (~> 0.7) - typhoeus (1.3.1) + typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.7) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.7) - unicode-display_width (1.7.0) + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.16.0) + xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.2.6) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) xcpretty (0.3.0) rouge (~> 2.0.7) - xcpretty-travis-formatter (1.0.0) + xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) - + zeitwerk (2.6.7) +​ PLATFORMS ruby - +​ DEPENDENCIES - cocoapods (= 1.9.0) + cocoapods (= 1.11.3) cocoapods-art fastlane fastlane-plugin-appcenter @@ -270,8 +310,8 @@ DEPENDENCIES fastlane-plugin-xcconfig fastlane-plugin-xchtmlreport json (= 2.3.0) - nokogiri (= 1.11.0) + nokogiri (= 1.13.5) slather - +​ BUNDLED WITH 2.1.4 diff --git a/Templates/ios/_fastlane/fastlane/SwiftLint b/Templates/ios/_fastlane/fastlane/SwiftLint index 1b00b04b..d82907f8 100644 --- a/Templates/ios/_fastlane/fastlane/SwiftLint +++ b/Templates/ios/_fastlane/fastlane/SwiftLint @@ -1,6 +1,7 @@ require File.expand_path('parameters/project_params.rb', __dir__) SWIFTLINT_PATH = PROJECT_PARAMS[:SWIFTLINT_PATH] +SWIFTLINT_CONFIG = PROJECT_PARAMS[:SWIFTLINT_CONFIG] REPORTS_FOLDER = PROJECT_PARAMS[:REPORTS_FOLDER] # --- SwiftLint @@ -11,9 +12,9 @@ lane :run_swiftlint do |options| executable = sh "which swiftlint|tr -d '\n'" puts "Found 'swiftlint' at: "+executable defaults = { - config_file: SWIFTLINT_PATH, + config_file: SWIFTLINT_CONFIG, executable: executable, - path: "../#{APP_SCHEME}/**/*", + path: SWIFTLINT_PATH, output_file: "#{REPORTS_FOLDER}/swiftlint.result" }.freeze diff --git a/Templates/ios/_fastlane/fastlane/parameters/project_params.rb b/Templates/ios/_fastlane/fastlane/parameters/project_params.rb index 5c0a0c7e..5ba11af6 100644 --- a/Templates/ios/_fastlane/fastlane/parameters/project_params.rb +++ b/Templates/ios/_fastlane/fastlane/parameters/project_params.rb @@ -6,7 +6,8 @@ COHERENT_SPEC: '../coherent-swift.yml', VARIANTS_SPEC: '../variants.yml', - SWIFTLINT_PATH: 'swiftlint.yml', + SWIFTLINT_CONFIG: 'swiftlint.yml', + SWIFTLINT_PATH: 'Sources', DERIVED_DATA_PATH: '.derivedData', REPORTS_FOLDER: './reports', TEST_DEVICES: ['iPhone 11'] diff --git a/Tests/VariantsCoreTests/FastlaneParametersFactoryTests.swift b/Tests/VariantsCoreTests/FastlaneParametersFactoryTests.swift index 12c4a060..e7a39087 100644 --- a/Tests/VariantsCoreTests/FastlaneParametersFactoryTests.swift +++ b/Tests/VariantsCoreTests/FastlaneParametersFactoryTests.swift @@ -111,7 +111,7 @@ class FastlaneParametersFactoryTests: XCTestCase { XCTAssertNoThrow(try factory.write(Data(correctOutput.utf8), using: path)) XCTAssertEqual(try path.read(), correctOutput) } - + func testFileWrite_appendingStore() { let expectedOutput = """ @@ -130,12 +130,15 @@ class FastlaneParametersFactoryTests: XCTestCase { versionName: "2.3.4", versionNumber: 99, appIcon: nil, + appName: nil, storeDestination: "testFlight", custom: nil, idSuffix: "sample", bundleID: nil, variantSigning: nil, - globalSigning: iOSSigning(teamName: "", teamID: "", exportMethod: .appstore, matchURL: "")) + globalSigning: iOSSigning(teamName: "", teamID: "", exportMethod: .appstore, matchURL: ""), + globalPostSwitchScript: "echo global", + variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } @@ -172,7 +175,7 @@ class FastlaneParametersFactoryTests: XCTestCase { XCTFail("'Try' should not throw - "+error.localizedDescription) } } - + private func context(for parameters: [CustomProperty]) -> [String: Any] { let fastlaneParameters = parameters.literal() let fastlaneEnvVars = parameters.envVars() @@ -185,7 +188,6 @@ class FastlaneParametersFactoryTests: XCTestCase { return context } } -// swiftlint:enable function_body_length fileprivate extension Sequence where Iterator.Element == CustomProperty { func envVars() -> [CustomProperty] { @@ -203,3 +205,5 @@ fileprivate extension Sequence where Iterator.Element == CustomProperty { .filter({ $0.destination == .fastlane && !$0.isEnvironmentVariable }) } } + +// swiftlint:enable function_body_length diff --git a/Tests/VariantsCoreTests/Mocks/MockXCcodeConfigFactory.swift b/Tests/VariantsCoreTests/Mocks/MockXCcodeConfigFactory.swift index 50e1c792..6a12306c 100644 --- a/Tests/VariantsCoreTests/Mocks/MockXCcodeConfigFactory.swift +++ b/Tests/VariantsCoreTests/Mocks/MockXCcodeConfigFactory.swift @@ -48,3 +48,5 @@ class MockXCcodeConfigFactory: XCFactory { var xcconfigFileName: String = "variants.xcconfig" var logger: Logger } + +// swiftlint:enable colon diff --git a/Tests/VariantsCoreTests/Resources/ios/invalid_missing_signing_configuration.yml b/Tests/VariantsCoreTests/Resources/ios/invalid_incomplete_signing_configuration.yml similarity index 92% rename from Tests/VariantsCoreTests/Resources/ios/invalid_missing_signing_configuration.yml rename to Tests/VariantsCoreTests/Resources/ios/invalid_incomplete_signing_configuration.yml index 9b689166..38d2a9f5 100644 --- a/Tests/VariantsCoreTests/Resources/ios/invalid_missing_signing_configuration.yml +++ b/Tests/VariantsCoreTests/Resources/ios/invalid_incomplete_signing_configuration.yml @@ -56,3 +56,8 @@ ios: - name: SAMPLE_GLOBAL value: GLOBAL Value iOS destination: project + + signing: + match_url: "git@github.com:sample/sample-match-repo.git" + team_name: "Backbase B.V." + team_id: "ABC247DXU9" diff --git a/Tests/VariantsCoreTests/Resources/ios/invalid_missing_ios.yml b/Tests/VariantsCoreTests/Resources/ios/invalid_missing_ios.yml new file mode 100644 index 00000000..dd62b852 --- /dev/null +++ b/Tests/VariantsCoreTests/Resources/ios/invalid_missing_ios.yml @@ -0,0 +1,49 @@ +# +# Auto generated by Variants +# + +android: + path: . + app_name: FrankBank + app_identifier: com.backbase.frank + variants: + default: + version_name: 0.0.1 + version_code: 1 + task_build: bundleProdRelease + task_unittest: testProdReleaseUnitTest + task_uitest: connectedProdReleaseAndroidTest + store_destination: PlayStore + custom: + - name: SAMPLE_PROJECT + value: Sample Project Default Config + destination: project + test: + id_suffix: dev + version_name: 0.0.1 + version_code: 1 + task_build: assembleDevelop + task_unittest: testDevDebugUnitTest + task_uitest: connectedDevDebugAndroidTest + store_destination: AppCenter + custom: + - name: SAMPLE_FASTLANE + value: Sample Fastlane Config + destination: fastlane + - name: SAMPLE_PROJECT + value: Sample Project Config + destination: project + + # ---------------------------------------------------------------------- + # custom: - Not required. + # + # Same as variant's `custom`, but this will be processed regardless of + # the chosen variant. + # + # Uncomment section below if necessary. + # ---------------------------------------------------------------------- + + custom: + - name: SAMPLE_GLOBAL + value: GLOBAL Value Android + destination: project diff --git a/Tests/VariantsCoreTests/SpecHelperTests.swift b/Tests/VariantsCoreTests/SpecHelperTests.swift index 17b15fb0..ebbe309c 100644 --- a/Tests/VariantsCoreTests/SpecHelperTests.swift +++ b/Tests/VariantsCoreTests/SpecHelperTests.swift @@ -58,6 +58,24 @@ class SpecHelperTests: XCTestCase { } } + func testGenerateSpec_notExistingPath() { + let basePath = Path("idontexist") + let specHelper = iOSSpecHelper( + logger: Logger.shared, + templatePath: incorrectTemplatePath, + userInputSource: interactiveShell, + userInput: { "yes" } + ) + + XCTAssertThrowsError( + try specHelper.generate(from: basePath), + "Attempt to use a not existing path" + ) { error in + XCTAssertTrue(error is RuntimeError) + XCTAssertEqual((error as? RuntimeError)?.description, "❌ Couldn't find template path") + } + } + func testGenerateSpec_correctPath() { if let basePath = basePath() { let variantsPath = Path("./variants.yml") @@ -85,6 +103,7 @@ class SpecHelperTests: XCTestCase { static var allTests = [ ("testGenerateSpec_basePathShouldNotBeNil", testGenerateSpec_basePathShouldNotBeNil), ("testGenerateSpec_incorrectPath", testGenerateSpec_incorrectPath), - ("testGenerateSpec_correctPath", testGenerateSpec_correctPath) + ("testGenerateSpec_correctPath", testGenerateSpec_correctPath), + ("testGenerateSpec_notExistingPath", testGenerateSpec_notExistingPath) ] } diff --git a/Tests/VariantsCoreTests/UserInputTests.swift b/Tests/VariantsCoreTests/UserInputTests.swift new file mode 100644 index 00000000..bb443d71 --- /dev/null +++ b/Tests/VariantsCoreTests/UserInputTests.swift @@ -0,0 +1,46 @@ +// +// Variants +// +// Copyright (c) Backbase B.V. - https://www.backbase.com +// Created by Roman Huti +// + +import XCTest +@testable import VariantsCore + +final class UserInputTests: XCTestCase { + + private var sut = interactiveShell + + func testInteractiveShellInputValidYes() { + XCTAssertTrue(sut.doesUserGrantPermissionToOverrideSpec({ "yes" })) + XCTAssertTrue(sut.doesUserGrantPermissionToOverrideSpec({ "YeS" })) + XCTAssertTrue(sut.doesUserGrantPermissionToOverrideSpec({ "Y" })) + XCTAssertTrue(sut.doesUserGrantPermissionToOverrideSpec({ "y" })) + } + + func testInteractiveShellInputValidNo() { + XCTAssertFalse(sut.doesUserGrantPermissionToOverrideSpec({ "no" })) + XCTAssertFalse(sut.doesUserGrantPermissionToOverrideSpec({ "N" })) + XCTAssertFalse(sut.doesUserGrantPermissionToOverrideSpec({ "nO" })) + XCTAssertFalse(sut.doesUserGrantPermissionToOverrideSpec({ "n" })) + } + + func testInteractiveShellInputOnFailValidationRecursionHappens() { + var executionCounter = 0 + sut = UserInputSource { input -> Bool in + return interactiveShellInput( + input, + with: "'variants.yml' spec already exists! Should we override it?", + suggestion: "[Y]es / [N]o", + validation: { _ -> Bool in + executionCounter += 1 + return executionCounter > 2 + } + ) + } + + XCTAssertFalse(sut.doesUserGrantPermissionToOverrideSpec({ "" })) + XCTAssertEqual(executionCounter, 3) + } +} diff --git a/Tests/VariantsCoreTests/SecretsFactoryTests.swift b/Tests/VariantsCoreTests/VariantsFileFactoryTests.swift similarity index 82% rename from Tests/VariantsCoreTests/SecretsFactoryTests.swift rename to Tests/VariantsCoreTests/VariantsFileFactoryTests.swift index 979caa46..8c368a0f 100644 --- a/Tests/VariantsCoreTests/SecretsFactoryTests.swift +++ b/Tests/VariantsCoreTests/VariantsFileFactoryTests.swift @@ -10,7 +10,7 @@ import PathKit import ArgumentParser @testable import VariantsCore -class SecretsFactoryTests: XCTestCase { +class VariantsFileFactoryTests: XCTestCase { let variantsSwiftContent = """ // // Variants @@ -35,12 +35,16 @@ class SecretsFactoryTests: XCTestCase { versionName: "2.3.4", versionNumber: 99, appIcon: nil, + appName: nil, storeDestination: "testFlight", - custom: [CustomProperty(name: "PROPERTY_A", value: "VALUE_A", destination: .project)], + custom: [CustomProperty(name: "PROPERTY_A", value: "VALUE_A", destination: .project), + CustomProperty(name: "PROPERTY_B", value: "VALUE_B", env: true, destination: .project)], idSuffix: nil, bundleID: nil, variantSigning: nil, - globalSigning: iOSSigning(teamName: "", teamID: "", exportMethod: .appstore, matchURL: "")) + globalSigning: iOSSigning(teamName: "", teamID: "", exportMethod: .appstore, matchURL: ""), + globalPostSwitchScript: "echo global", + variantPostSwitchScript: "echo variant") func testRender_noSecrets() { guard let configFile = Bundle(for: type(of: self)) @@ -50,9 +54,9 @@ class SecretsFactoryTests: XCTestCase { XCTAssertTrue(configPath.exists) // commented, as comparing file content not working properly (need to find better way to test) - let secretsFactory = SecretsFactory() + let variantsFileFactory = VariantsFileFactory() guard let defaultVariant = defaultVariant else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } - secretsFactory.updateSecrets(with: configPath, variant: defaultVariant) + variantsFileFactory.updateVariantsFile(with: configPath, variant: defaultVariant) let variantsFilePath = Bundle(for: type(of: self)).path(forResource: "Resources/ios/Variants", ofType: "swift") XCTAssertNotNil(variantsFilePath) diff --git a/Tests/VariantsCoreTests/XcodeProjFactoryTests.swift b/Tests/VariantsCoreTests/XcodeProjFactoryTests.swift index 8ec83270..123d60d8 100644 --- a/Tests/VariantsCoreTests/XcodeProjFactoryTests.swift +++ b/Tests/VariantsCoreTests/XcodeProjFactoryTests.swift @@ -25,7 +25,7 @@ class XcodeProjFactoryTests: XCTestCase { } func testWriteJson() { - let proj = XCConfigFactory(logLevel: true) + let proj = XCConfigFactory(logger: Logger(verbose: true)) let file = Path("./output.json") let (success, path) = proj.writeJSON("{}", toFile: file) XCTAssertTrue(success) @@ -33,12 +33,13 @@ class XcodeProjFactoryTests: XCTestCase { } func testCreateConfiguration() { - let proj = XCConfigFactory(logLevel: true) + let proj = XCConfigFactory(logger: Logger(verbose: true)) let target = iOSTarget(name: "", app_icon: "", bundleId: "", testTarget: "", source: .init(path: "", info: "", config: "")) - guard let variant = try? iOSVariant(name: target.name, versionName: "", versionNumber: 0, appIcon: nil, + guard let variant = try? iOSVariant(name: target.name, versionName: "", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: nil, custom: nil, idSuffix: "", bundleID: nil, variantSigning: nil, - globalSigning: iOSSigning(teamName: "", teamID: "", exportMethod: .appstore, matchURL: "")) + globalSigning: iOSSigning(teamName: "", teamID: "", exportMethod: .appstore, matchURL: ""), + globalPostSwitchScript: nil, variantPostSwitchScript: nil) else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } diff --git a/Tests/VariantsCoreTests/YamlParserTests.swift b/Tests/VariantsCoreTests/YamlParserTests.swift index 41ea2f97..09626e74 100644 --- a/Tests/VariantsCoreTests/YamlParserTests.swift +++ b/Tests/VariantsCoreTests/YamlParserTests.swift @@ -5,7 +5,6 @@ // Created by Arthur Alves // -// swiftlint:disable function_body_length // swiftlint:disable file_length import XCTest @@ -50,11 +49,12 @@ class YamlParserTests: XCTestCase { } } - func testExtractConfiguration_invalid_iOS_missingSigningConfiguration() { + func testExtractConfiguration_invalid_iOS_incompleteSigningConfiguration() { let expectedUnderlyingError = RuntimeError( """ - Variant "BETA" doesn't contain a 'signing' configuration. \ - Create a global 'signing' configuration or make sure all variants have this property. + Missing: 'signing.export_method' + At least one variant doesn't contain 'signing.export_method' in its configuration. + Create a global 'signing' configuration with 'export_method' or make sure all variants have this property. """ ) @@ -74,7 +74,7 @@ class YamlParserTests: XCTestCase { } } } - + // swiftlint:disable function_body_length func testExtractConfiguration_valid_iOS() { let parser = YamlParser() do { @@ -104,12 +104,21 @@ class YamlParserTests: XCTestCase { iOSTarget(name: "FrankBank", app_icon: "AppIcon", bundleId: "com.backbase.frank.ios", testTarget: "FrankBankTests", source: source) ) - XCTAssertEqual(firstVariantDefaultValues?["V_VERSION_NUMBER"], "1") - XCTAssertEqual(firstVariantDefaultValues?["V_APP_NAME"], "FrankBank") - XCTAssertEqual(firstVariantDefaultValues?["V_BUNDLE_ID"], "com.backbase.frank.ios") - XCTAssertEqual(firstVariantDefaultValues?["V_APP_ICON"], "AppIcon") - XCTAssertEqual(firstVariantDefaultValues?["V_VERSION_NAME"], "0.0.1") - XCTAssertEqual(firstVariantDefaultValues?["SAMPLE_CONFIG"], "Production Value") + XCTAssertEqual(firstVariantDefaultValues?.count, 7) + XCTAssertEqual(firstVariantDefaultValues?[0].key, "SAMPLE_CONFIG") + XCTAssertEqual(firstVariantDefaultValues?[0].value, "Production Value") + XCTAssertEqual(firstVariantDefaultValues?[1].key, "V_APP_ICON") + XCTAssertEqual(firstVariantDefaultValues?[1].value, "AppIcon") + XCTAssertEqual(firstVariantDefaultValues?[2].key, "V_APP_NAME") + XCTAssertEqual(firstVariantDefaultValues?[2].value, "FrankBank") + XCTAssertEqual(firstVariantDefaultValues?[3].key, "V_BUNDLE_ID") + XCTAssertEqual(firstVariantDefaultValues?[3].value, "com.backbase.frank.ios") + XCTAssertEqual(firstVariantDefaultValues?[4].key, "V_MATCH_PROFILE") + XCTAssertEqual(firstVariantDefaultValues?[4].value, "match AppStore com.backbase.frank.ios") + XCTAssertEqual(firstVariantDefaultValues?[5].key, "V_VERSION_NAME") + XCTAssertEqual(firstVariantDefaultValues?[5].value, "0.0.1") + XCTAssertEqual(firstVariantDefaultValues?[6].key, "V_VERSION_NUMBER") + XCTAssertEqual(firstVariantDefaultValues?[6].value, "1") // MARK: - iOS Global Properties @@ -158,7 +167,7 @@ class YamlParserTests: XCTestCase { XCTAssertTrue(((error as? DecodingError) == nil)) } } - + // swiftlint:enable function_body_length func testExtractConfiguration_valid_android() { let parser = YamlParser() do { @@ -272,8 +281,8 @@ class YamlParserTests: XCTestCase { testExtractConfiguration_invalidSpec), ("testExtractConfiguration_invalid_iOS_missingExportMethod", testExtractConfiguration_invalid_iOS_missingExportMethod), - ("testExtractConfiguration_invalid_iOS_missingSigningConfiguration", - testExtractConfiguration_invalid_iOS_missingSigningConfiguration), + ("testExtractConfiguration_invalid_iOS_incompleteSigningConfiguration", + testExtractConfiguration_invalid_iOS_incompleteSigningConfiguration), ("testExtractConfiguration_valid_iOS", testExtractConfiguration_valid_iOS), ("testExtractConfiguration_valid_android", @@ -282,5 +291,4 @@ class YamlParserTests: XCTestCase { testStoreDestination_iOS) ] } -// swiftlint:enable function_body_length // swiftlint:enable file_length diff --git a/Tests/VariantsCoreTests/iOSProjectTests.swift b/Tests/VariantsCoreTests/iOSProjectTests.swift index 107c0c8c..652ec51b 100644 --- a/Tests/VariantsCoreTests/iOSProjectTests.swift +++ b/Tests/VariantsCoreTests/iOSProjectTests.swift @@ -150,6 +150,59 @@ class iOSProjectTests: XCTestCase { XCTAssertEqual(xcFactoryMock.createConfigCache.count, 2) XCTAssertEqual(xcFactoryMock.createConfigCache.last?.variant.name, "STG") } + + func testProject_setup_missingiOSConfiguration() { + let xcFactoryMock = MockXCcodeConfigFactory(logLevel: true) + let parametersFactoryMock = MockFastlaneFactory() + + let project = iOSProject( + specHelper: specHelperMock, + configFactory: xcFactoryMock, + parametersFactory: parametersFactoryMock, + yamlParser: YamlParser() + ) + + guard let specPath = specPath(resourcePath: "Resources/ios/invalid_missing_ios", withType: "yml") else { + return XCTFail("Couldn't find invalid_missing_ios.yml file.") + } + + XCTAssertThrowsError(try project.setup(spec: specPath.string, skipFastlane: true, verbose: true), "") { error in + XCTAssertTrue(error is RuntimeError) + XCTAssertEqual((error as? RuntimeError)?.description, """ + ❌ Unable to load spec '\(specPath.string)' + """) + } + } + + func testProject_setup_fail() { + let xcFactoryMock = MockXCcodeConfigFactory(logLevel: true) + let parametersFactoryMock = MockFastlaneFactory() + + let project = iOSProject( + specHelper: specHelperMock, + configFactory: xcFactoryMock, + parametersFactory: parametersFactoryMock, + yamlParser: YamlParser() + ) + + guard let path = Bundle(for: type(of: self)).resourcePath else { + XCTFail("Resource path directory should be not nil") + return + } + + do { + try project.setup(spec: Path(path).string, skipFastlane: false, verbose: true) + XCTFail("Should not succeed, exception throw is expected") + } catch let error as ValidationError { + XCTAssertEqual(error.description, "Error: \(path) is a directory path") + + XCTAssertEqual(xcFactoryMock.createConfigCache.count, 0) + XCTAssertEqual(parametersFactoryMock.createParametersCache.count, 0) + XCTAssertEqual(parametersFactoryMock.createMatchFileCache.count, 0) + } catch { + XCTFail("Caught unknown error \(error)") + } + } private func specPath(resourcePath: String, withType fileType: String) -> Path? { guard let path = Bundle(for: type(of: self)) @@ -163,6 +216,10 @@ class iOSProjectTests: XCTestCase { ("testProject_initialize", testProject_initialize), ("testProject_setup", testProject_setup), ("testProject_list", testProject_list), - ("testProject_switch", testProject_switch) + ("testProject_switch", testProject_switch), + ("testProject_setup_fail", testProject_setup_fail), + ("testProject_setup_missingiOSConfiguration", testProject_setup_missingiOSConfiguration) ] } + +// swiftlint:enable type_name diff --git a/Tests/VariantsCoreTests/iOSSigningTests.swift b/Tests/VariantsCoreTests/iOSSigningTests.swift new file mode 100644 index 00000000..0812aa15 --- /dev/null +++ b/Tests/VariantsCoreTests/iOSSigningTests.swift @@ -0,0 +1,110 @@ +// +// Variants +// +// Copyright (c) Backbase B.V. - https://www.backbase.com +// Created by Roman Huti +// + +import XCTest +@testable import VariantsCore + +// swiftlint:disable type_name + +final class iOSSigningTests: XCTestCase { + + func testMergeValidSignings() throws { + let signing = iOSSigning(teamName: "team", + teamID: nil, + exportMethod: .appstore, + matchURL: "url") + let signing1 = iOSSigning(teamName: nil, + teamID: "new id", + exportMethod: .development, + matchURL: nil) + + do { + let result = try signing ~ signing1 + XCTAssertEqual(result.teamName, "team") + XCTAssertEqual(result.teamID, "new id") + XCTAssertEqual(result.exportMethod, .appstore) + XCTAssertEqual(result.matchURL, "url") + } catch { + XCTFail("Should not throw exception") + } + } + + func testMergeSigningsNoTeamName() throws { + let signing = iOSSigning(teamName: nil, + teamID: nil, + exportMethod: .appstore, + matchURL: "url") + let signing1 = iOSSigning(teamName: nil, + teamID: "new id", + exportMethod: .development, + matchURL: "new url") + let expectedError = RuntimeError(""" + Missing: 'signing.team_name' + At least one variant doesn't contain 'signing.team_name' in its configuration. + Create a global 'signing' configuration with 'team_name' or make sure all variants have this property. + """) + + do { + _ = try signing ~ signing1 + } catch let error as RuntimeError { + XCTAssertEqual(error, expectedError) + } catch { + XCTFail("Unexpected error") + } + } + + func testMergeSigningsNoTeamId() throws { + let signing = iOSSigning(teamName: nil, + teamID: nil, + exportMethod: .appstore, + matchURL: "url") + let signing1 = iOSSigning(teamName: "Name", + teamID: nil, + exportMethod: .development, + matchURL: "new url") + let expectedError = RuntimeError(""" + Missing: 'signing.team_id' + At least one variant doesn't contain 'signing.team_id' in its configuration. + Create a global 'signing' configuration with 'team_id' or make sure all variants have this property. + """) + + do { + _ = try signing ~ signing1 + } catch let error as RuntimeError { + XCTAssertEqual(error, expectedError) + } catch { + XCTFail("Unexpected error") + } + } + + func testCustomProperties() { + let signing = iOSSigning(teamName: "Name", + teamID: nil, + exportMethod: .enterprise, + matchURL: "url") + + let expected = [CustomProperty(name: "TEAMNAME", value: "NAME", destination: .fastlane), + CustomProperty(name: "EXPORTMETHOD", value: "match InHouse", destination: .fastlane), + CustomProperty(name: "MATCHURL", value: "url", destination: .fastlane)] + + XCTAssertEqual(signing.customProperties(), expected) + } + + func testExportMethodPrefixes() { + let dev: iOSSigning.`Type` = .development, + appstore: iOSSigning.`Type` = .appstore, + enterprise: iOSSigning.`Type` = .enterprise, + adhoc: iOSSigning.`Type` = .adhoc + XCTAssertEqual(dev.prefix, "match Development") + XCTAssertEqual(appstore.prefix, "match AppStore") + XCTAssertEqual(enterprise.prefix, "match InHouse") + XCTAssertEqual(adhoc.prefix, "match AdHoc") + } + +} + +// swiftlint:enable type_name diff --git a/Tests/VariantsCoreTests/iOSVariantTests.swift b/Tests/VariantsCoreTests/iOSVariantTests.swift index 485d95ae..839cedcc 100644 --- a/Tests/VariantsCoreTests/iOSVariantTests.swift +++ b/Tests/VariantsCoreTests/iOSVariantTests.swift @@ -20,11 +20,11 @@ class iOSVariantTests: XCTestCase { // MARK: - Initializer tests func testiOSVariantInitWithUnnamediOSVariant() { let customProperties = [CustomProperty(name: "Name", value: "Value", destination: .project)] - let unnamedVariant = UnnamediOSVariant(versionName: "1.0", versionNumber: 0, appIcon: "app_icon", idSuffix: "beta", bundleID: nil, - signing: validSigning, custom: customProperties, storeDestination: "testflight") + let unnamedVariant = UnnamediOSVariant(versionName: "1.0", versionNumber: 0, appIcon: "app_icon", appName: nil, idSuffix: "beta", bundleID: nil, + signing: validSigning, custom: customProperties, storeDestination: "testflight", postSwitchScript: "echo hello") func makeiOSVariant() throws -> iOSVariant { - try iOSVariant(from: unnamedVariant, name: "beta", globalSigning: nil) + try iOSVariant(from: unnamedVariant, name: "beta", globalSigning: nil, globalPostSwitchScript: nil) } XCTAssertNoThrow(try makeiOSVariant()) @@ -37,13 +37,14 @@ class iOSVariantTests: XCTestCase { XCTAssertEqual(variant.storeDestination, iOSVariant.Destination(rawValue: unnamedVariant.storeDestination!.lowercased())!) XCTAssertEqual(variant.custom, unnamedVariant.custom) XCTAssertEqual(variant.makeBundleID(for: target), "com.Company.ValidName.beta") + XCTAssertEqual(variant.postSwitchScript, "echo hello") } // MARK: - Default property assigning func testInitNilFallbackToDefaultProperties() { func makeiOSVariant() throws -> iOSVariant { - try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: nil, custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: nil, custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") } XCTAssertNoThrow(try makeiOSVariant()) @@ -55,8 +56,8 @@ class iOSVariantTests: XCTestCase { // MARK: - Computed properties func testGetTitle() { let name = "Variant Name" - guard let variant = try? iOSVariant(name: name, versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + guard let variant = try? iOSVariant(name: name, versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } @@ -65,8 +66,8 @@ class iOSVariantTests: XCTestCase { func testGetConfigName() { // Default variant - guard let defaultVariant = try? iOSVariant(name: "default", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + guard let defaultVariant = try? iOSVariant(name: "default", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } @@ -74,8 +75,8 @@ class iOSVariantTests: XCTestCase { // Any variant let name = "Variant Name" - guard let anyVariant = try? iOSVariant(name: name, versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + guard let anyVariant = try? iOSVariant(name: name, versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } @@ -84,8 +85,8 @@ class iOSVariantTests: XCTestCase { func testGetDestinationProperty() { let targetDestination = iOSVariant.Destination.appCenter - guard let variant = try? iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: targetDestination.rawValue, - custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + guard let variant = try? iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: targetDestination.rawValue, + custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } @@ -97,6 +98,55 @@ class iOSVariantTests: XCTestCase { XCTAssertEqual(result.destination, expectedResult.destination) } + // MARK: - Post Switch Script tests + func testInitiOSVariantsWithVariantPostSwitchScript() { + func makeiOSVariant() throws -> iOSVariant { + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: nil, custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: nil, variantPostSwitchScript: "echo variant") + } + + XCTAssertNoThrow(try makeiOSVariant()) + + let variant = try? makeiOSVariant() + XCTAssertEqual(variant?.postSwitchScript, "echo variant") + } + + func testInitiOSVariantsWithGlobalPostSwitchScript() { + func makeiOSVariant() throws -> iOSVariant { + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: nil, custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: nil) + } + + XCTAssertNoThrow(try makeiOSVariant()) + + let variant = try? makeiOSVariant() + XCTAssertEqual(variant?.postSwitchScript, "echo global") + } + + func testInitiOSVariantsWithVariantAndGlobalPostSwitchScript() { + func makeiOSVariant() throws -> iOSVariant { + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: nil, custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") + } + + XCTAssertNoThrow(try makeiOSVariant()) + + let variant = try? makeiOSVariant() + XCTAssertEqual(variant?.postSwitchScript, "echo global && echo variant") + } + + func testInitiOSVariantsWithNoPostSwitchScript() { + func makeiOSVariant() throws -> iOSVariant { + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: nil, custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: nil, variantPostSwitchScript: nil) + } + + XCTAssertNoThrow(try makeiOSVariant()) + + let variant = try? makeiOSVariant() + XCTAssertNil(variant?.postSwitchScript) + } + // MARK: - Bundle ID and ID Suffix tests func testInitiOSVariantWithIDSuffixOrBundleID() { @@ -106,12 +156,15 @@ class iOSVariantTests: XCTestCase { versionName: "1.0.0", versionNumber: 0, appIcon: nil, + appName: nil, storeDestination: "appStore", custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: nil, - globalSigning: validSigning)) + globalSigning: validSigning, + globalPostSwitchScript: "echo global", + variantPostSwitchScript: "echo variant")) // Only Bundle ID XCTAssertNoThrow(try iOSVariant( @@ -119,12 +172,15 @@ class iOSVariantTests: XCTestCase { versionName: "1.0.0", versionNumber: 0, appIcon: nil, + appName: nil, storeDestination: "appStore", custom: nil, idSuffix: nil, bundleID: "com.company.customBundle", variantSigning: nil, - globalSigning: validSigning)) + globalSigning: validSigning, + globalPostSwitchScript: "echo global", + variantPostSwitchScript: "echo variant")) } func testInitWithIDSuffixAndBundleID() { @@ -136,8 +192,8 @@ class iOSVariantTests: XCTestCase { ) func makeiOSVariant() throws -> iOSVariant { - try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: "com.company.customBundle", variantSigning: nil, globalSigning: validSigning) + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: "com.company.customBundle", variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") } XCTAssertThrowsError(try makeiOSVariant(), "ID Suffix and Bundle ID can't be configured at same time in the same variant") { error in @@ -154,8 +210,8 @@ class iOSVariantTests: XCTestCase { ) func makeiOSVariant() throws -> iOSVariant { - try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: nil, bundleID: nil, variantSigning: nil, globalSigning: validSigning) + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: nil, bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") } XCTAssertThrowsError(try makeiOSVariant(), "ID Suffix and Bundle ID can't be configured at same time in the same variant") { error in @@ -165,24 +221,24 @@ class iOSVariantTests: XCTestCase { func testMakeBundleIDForVariant() { // ID Suffix provided - guard let idSuffixVariant = try? iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + guard let idSuffixVariant = try? iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } XCTAssertEqual(idSuffixVariant.makeBundleID(for: target), "com.Company.ValidName.beta") // Bundle ID provided - guard let bundleIDVariant = try? iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: nil, bundleID: "com.Overwritten.BundleID", variantSigning: nil, globalSigning: validSigning) + guard let bundleIDVariant = try? iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: nil, bundleID: "com.Overwritten.BundleID", variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } XCTAssertEqual(bundleIDVariant.makeBundleID(for: target), "com.Overwritten.BundleID") // Default variant - guard let defaultVariant = try? iOSVariant(name: "default", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + guard let defaultVariant = try? iOSVariant(name: "default", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } @@ -198,12 +254,15 @@ class iOSVariantTests: XCTestCase { versionName: "1.0.0", versionNumber: 0, appIcon: nil, + appName: nil, storeDestination: "appStore", custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: validSigning, - globalSigning: validSigning)) + globalSigning: validSigning, + globalPostSwitchScript: "echo global", + variantPostSwitchScript: "echo variant")) // Only variant signing defined XCTAssertNoThrow(try iOSVariant( @@ -211,12 +270,15 @@ class iOSVariantTests: XCTestCase { versionName: "1.0.0", versionNumber: 0, appIcon: nil, + appName: nil, storeDestination: "appStore", custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: validSigning, - globalSigning: nil)) + globalSigning: nil, + globalPostSwitchScript: "echo global", + variantPostSwitchScript: "echo variant")) // Only global signing defined XCTAssertNoThrow(try iOSVariant( @@ -224,96 +286,147 @@ class iOSVariantTests: XCTestCase { versionName: "1.0.0", versionNumber: 0, appIcon: nil, + appName: nil, storeDestination: "appStore", custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: nil, - globalSigning: validSigning)) + globalSigning: validSigning, + globalPostSwitchScript: "echo global", + variantPostSwitchScript: "echo variant")) } func testInitWithoutSigningConfiguration() { - let expectedError = RuntimeError( - """ - Variant "Valid Name" doesn't contain a 'signing' configuration. \ - Create a global 'signing' configuration or make sure all variants have this property. - """ - ) - func makeiOSVariant() throws -> iOSVariant { - try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: nil) - } - - XCTAssertThrowsError(try makeiOSVariant(), "At least one signing needs to be provided") { error in - XCTAssertEqual(error as? RuntimeError, expectedError) + try iOSVariant(name: "Valid Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: nil, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") } + + XCTAssertNoThrow(try makeiOSVariant()) } func testGetDefaultValuesForTargetWithoutSigning() { - let expectedValues = [ + let expectedValues: [String: String] = [ + "V_APP_ICON": "AppIcon", "V_APP_NAME": "Target Name Beta", "V_BUNDLE_ID": "com.Company.ValidName.beta", "V_VERSION_NAME": "1.0.0", - "V_VERSION_NUMBER": "0", - "V_APP_ICON": "AppIcon"] + "V_VERSION_NUMBER": "0" + ] let signing = iOSSigning(teamName: "Signing Team Name", teamID: "AB12345CD", exportMethod: .appstore, matchURL: nil) - guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: signing) + guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: signing, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } - - XCTAssertEqual(variant.getDefaultValues(for: target), expectedValues) + let defaultValues = variant.getDefaultValues(for: target) + XCTAssertEqual(defaultValues.count, expectedValues.count) + defaultValues.forEach({ + XCTAssertEqual($0.value, expectedValues[$0.key]) + }) } - func testGetDefaultValuesForTargetWithSigning() { - let expectedValues = [ + func testGetDefaultValuesForTargetWithCustomAppName() { + let expectedValues: [String: String] = [ + "V_APP_ICON": "AppIcon", + "V_APP_NAME": "App Marketing Name", + "V_BUNDLE_ID": "com.Company.ValidName.beta", + "V_VERSION_NAME": "1.0.0", + "V_VERSION_NUMBER": "0" + ] + let signing = iOSSigning(teamName: "Signing Team Name", teamID: "AB12345CD", exportMethod: .appstore, matchURL: nil) + guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, + appName: "App Marketing Name", storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: signing, globalPostSwitchScript: nil, variantPostSwitchScript: nil) + else { + return XCTFail("Failed to initialize iOSVariant with provided parameters") + } + let defaultValues = variant.getDefaultValues(for: target) + XCTAssertEqual(defaultValues.count, expectedValues.count) + defaultValues.forEach({ + XCTAssertEqual($0.value, expectedValues[$0.key]) + }) + } + + func testGetDefaultValuesForTargetWithoutCustomAppName() { + let expectedValues: [String: String] = [ + "V_APP_ICON": "AppIcon", "V_APP_NAME": "Target Name Beta", "V_BUNDLE_ID": "com.Company.ValidName.beta", "V_VERSION_NAME": "1.0.0", - "V_VERSION_NUMBER": "0", + "V_VERSION_NUMBER": "0" + ] + let signing = iOSSigning(teamName: "Signing Team Name", teamID: "AB12345CD", exportMethod: .appstore, matchURL: nil) + guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, + appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: signing, globalPostSwitchScript: nil, variantPostSwitchScript: nil) + else { + return XCTFail("Failed to initialize iOSVariant with provided parameters") + } + let defaultValues = variant.getDefaultValues(for: target) + XCTAssertEqual(defaultValues.count, expectedValues.count) + defaultValues.forEach({ + XCTAssertEqual($0.value, expectedValues[$0.key]) + }) + } + + func testGetDefaultValuesForTargetWithSigning() { + let expectedValues: [String: String] = [ "V_APP_ICON": "AppIcon", - "V_MATCH_PROFILE": "match AppStore com.Company.ValidName.beta"] - guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", custom: nil, - idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + "V_APP_NAME": "Target Name Beta", + "V_BUNDLE_ID": "com.Company.ValidName.beta", + "V_MATCH_PROFILE": "match AppStore com.Company.ValidName.beta", + "V_VERSION_NAME": "1.0.0", + "V_VERSION_NUMBER": "0" + ] + guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", custom: nil, + idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } - XCTAssertEqual(variant.getDefaultValues(for: target), expectedValues) + let defaultValues = variant.getDefaultValues(for: target) + XCTAssertEqual(defaultValues.count, expectedValues.count) + defaultValues.forEach({ + XCTAssertEqual($0.value, expectedValues[$0.key]) + }) } func testGetDefaultValuesWithTargetAndCustomProperties() { - let expectedValues = [ + let expectedValues: [String: String] = [ + "Custom name": "Custom value", + "V_APP_ICON": "AppIcon", "V_APP_NAME": "Target Name Beta", "V_BUNDLE_ID": "com.Company.ValidName.beta", - "V_VERSION_NAME": "1.0.0", - "V_VERSION_NUMBER": "0", - "V_APP_ICON": "AppIcon", "V_MATCH_PROFILE": "match AppStore com.Company.ValidName.beta", - "Custom name": "Custom value" + "V_VERSION_NAME": "1.0.0", + "V_VERSION_NUMBER": "0" ] let customProperties = [ CustomProperty(name: "Custom name", value: "Custom value", env: false, destination: .project), CustomProperty(name: "Custom name 2", value: "Custom value 2", env: true, destination: .project), CustomProperty(name: "Custom name 3", value: "Custom value 3", env: false, destination: .fastlane)] - guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: "appStore", - custom: customProperties, idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + guard let variant = try? iOSVariant(name: "Beta", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: "appStore", + custom: customProperties, idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") else { return XCTFail("Failed to initialize iOSVariant with provided parameters") } - XCTAssertEqual(variant.getDefaultValues(for: target), expectedValues) - XCTAssertTrue(variant.getDefaultValues(for: target)["Custom name 2"] == nil, "Should not contains this property as it's an environment variable") - XCTAssertTrue(variant.getDefaultValues(for: target)["Custom name 3"] == nil, "Should not contains this property as it's not a project destination property") + let defaultValues = variant.getDefaultValues(for: target) + XCTAssertEqual(defaultValues.count, expectedValues.count) + defaultValues.forEach({ + XCTAssertEqual($0.value, expectedValues[$0.key]) + }) + XCTAssertFalse(defaultValues.contains(where: {$0.key == "Custom name 2"}), "Should not contains this property as it's an environment variable") + XCTAssertFalse(defaultValues.contains(where: {$0.key == "Custom name 3"}), "Should not contains this property as it's not a project destination property") } // MARK: - iOSVariants.Destination tests func testParsingiOSVariantDestintation() { func makeVariant(destination: String?) throws -> iOSVariant { - try iOSVariant(name: "Variant Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, storeDestination: destination, - custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning) + try iOSVariant(name: "Variant Name", versionName: "1.0.0", versionNumber: 0, appIcon: nil, appName: nil, storeDestination: destination, + custom: nil, idSuffix: "beta", bundleID: nil, variantSigning: nil, globalSigning: validSigning, globalPostSwitchScript: "echo global", variantPostSwitchScript: "echo variant") } // Should not throw if valid destination is provided @@ -347,8 +460,14 @@ class iOSVariantTests: XCTestCase { ("testInitWithValidSigningConfiguration", testInitWithValidSigningConfiguration), ("testInitWithoutSigningConfiguration", testInitWithoutSigningConfiguration), ("testGetDefaultValuesForTargetWithoutSigning", testGetDefaultValuesForTargetWithoutSigning), + ("testGetDefaultValuesForTargetWithCustomAppName", testGetDefaultValuesForTargetWithCustomAppName), + ("testGetDefaultValuesForTargetWithoutCustomAppName", testGetDefaultValuesForTargetWithoutCustomAppName), ("testGetDefaultValuesForTargetWithSigning", testGetDefaultValuesForTargetWithSigning), ("testGetDefaultValuesWithTargetAndCustomProperties", testGetDefaultValuesWithTargetAndCustomProperties), ("testParsingiOSVariantDestintation", testParsingiOSVariantDestintation) ] } + +// swiftlint:enable type_body_length +// swiftlint:enable line_length +// swiftlint:enable type_name diff --git a/Tests/VariantsTests/InitCommandTests.swift b/Tests/VariantsTests/InitCommandTests.swift index 6cb404d6..b50a1b60 100644 --- a/Tests/VariantsTests/InitCommandTests.swift +++ b/Tests/VariantsTests/InitCommandTests.swift @@ -65,3 +65,5 @@ final class InitCommandTests: XCTestCase { ("testInit_unknownArgument", testInit_unknownArgument) ] } + +// swiftlint:enable line_length diff --git a/Variants.xcodeproj/project.pbxproj b/Variants.xcodeproj/project.pbxproj index 2641ecce..d83e7a8b 100644 --- a/Variants.xcodeproj/project.pbxproj +++ b/Variants.xcodeproj/project.pbxproj @@ -89,8 +89,8 @@ 8E1BA189254C48FD00DD0204 /* VariantsCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E1B9CCE254AC1E700DD0204 /* VariantsCore.framework */; }; 8E1BA18A254C48FD00DD0204 /* VariantsCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8E1B9CCE254AC1E700DD0204 /* VariantsCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8E6ABB9D25C031AB006A62FE /* UtilsDirectory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6ABB9C25C031AB006A62FE /* UtilsDirectory.swift */; }; - 8E6ABBA425C03639006A62FE /* SecretsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6ABBA325C03639006A62FE /* SecretsFactory.swift */; }; - 8E6ABBB625C03F2C006A62FE /* SecretsFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6ABBAF25C03F05006A62FE /* SecretsFactoryTests.swift */; }; + 8E6ABBA425C03639006A62FE /* VariantsFileFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6ABBA325C03639006A62FE /* VariantsFileFactory.swift */; }; + 8E6ABBB625C03F2C006A62FE /* VariantsFileFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6ABBAF25C03F05006A62FE /* VariantsFileFactoryTests.swift */; }; 8E866A1725D2CCEA00A7EC19 /* UserInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E866A1625D2CCEA00A7EC19 /* UserInput.swift */; }; 8E866B0725D68CA900A7EC19 /* InitCommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E866B0625D68CA900A7EC19 /* InitCommandTests.swift */; }; 8E8A483525514BE00056F79F /* Stencil in Frameworks */ = {isa = PBXBuildFile; productRef = 8E8A483425514BE00056F79F /* Stencil */; }; @@ -107,6 +107,8 @@ BEAA720C255E5C3E00E9D4D9 /* MockXCcodeConfigFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEAA720B255E5C3E00E9D4D9 /* MockXCcodeConfigFactory.swift */; }; BEAA7212255E5C4100E9D4D9 /* MockGradleScriptFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEAA71FF255E5BBB00E9D4D9 /* MockGradleScriptFactory.swift */; }; BEAA7219255E5C6C00E9D4D9 /* MockFastlaneFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEAA7218255E5C6C00E9D4D9 /* MockFastlaneFactory.swift */; }; + C52A0A5429263483007CE315 /* UserInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C52A0A5329263483007CE315 /* UserInputTests.swift */; }; + C52A0A5629266B1C007CE315 /* iOSSigningTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C52A0A5529266B1B007CE315 /* iOSSigningTests.swift */; }; E333DBE9281C36B0000E8D03 /* KeyedDecodingContainerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E333DBE8281C36B0000E8D03 /* KeyedDecodingContainerTests.swift */; }; E39502A9256DB16B00484DCE /* String+WriteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39502A8256DB16B00484DCE /* String+WriteTests.swift */; }; E39502C1256DBFA200484DCE /* ProjectFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39502C0256DBFA200484DCE /* ProjectFactoryTests.swift */; }; @@ -196,8 +198,8 @@ 8E1BA0C1254BFF6400DD0204 /* Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Setup.swift; sourceTree = ""; }; 8E6ABB8D25C01BD8006A62FE /* utils */ = {isa = PBXFileReference; lastKnownFileType = folder; path = utils; sourceTree = ""; }; 8E6ABB9C25C031AB006A62FE /* UtilsDirectory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilsDirectory.swift; sourceTree = ""; }; - 8E6ABBA325C03639006A62FE /* SecretsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SecretsFactory.swift; path = Sources/VariantsCore/Factory/ios/SecretsFactory.swift; sourceTree = SOURCE_ROOT; }; - 8E6ABBAF25C03F05006A62FE /* SecretsFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretsFactoryTests.swift; sourceTree = ""; }; + 8E6ABBA325C03639006A62FE /* VariantsFileFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = VariantsFileFactory.swift; path = Sources/VariantsCore/Factory/ios/VariantsFileFactory.swift; sourceTree = SOURCE_ROOT; }; + 8E6ABBAF25C03F05006A62FE /* VariantsFileFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantsFileFactoryTests.swift; sourceTree = ""; }; 8E866A1625D2CCEA00A7EC19 /* UserInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInput.swift; sourceTree = ""; }; 8E866B0625D68CA900A7EC19 /* InitCommandTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitCommandTests.swift; sourceTree = ""; }; 8E8A483B25514D3A0056F79F /* FastlaneParametersFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FastlaneParametersFactory.swift; sourceTree = ""; }; @@ -214,6 +216,8 @@ BEAA71FF255E5BBB00E9D4D9 /* MockGradleScriptFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGradleScriptFactory.swift; sourceTree = ""; }; BEAA720B255E5C3E00E9D4D9 /* MockXCcodeConfigFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockXCcodeConfigFactory.swift; sourceTree = ""; }; BEAA7218255E5C6C00E9D4D9 /* MockFastlaneFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFastlaneFactory.swift; sourceTree = ""; }; + C52A0A5329263483007CE315 /* UserInputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInputTests.swift; sourceTree = ""; }; + C52A0A5529266B1B007CE315 /* iOSSigningTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSSigningTests.swift; sourceTree = ""; }; E333DBE8281C36B0000E8D03 /* KeyedDecodingContainerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyedDecodingContainerTests.swift; sourceTree = ""; }; E39502A8256DB16B00484DCE /* String+WriteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+WriteTests.swift"; sourceTree = ""; }; E39502C0256DBFA200484DCE /* ProjectFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectFactoryTests.swift; sourceTree = ""; }; @@ -327,13 +331,15 @@ OBJ_67 /* YamlParserTests.swift */, 8E8A4849255165CB0056F79F /* FastlaneParametersFactoryTests.swift */, 8E8A48BE255305C50056F79F /* GradleScriptFactoryTests.swift */, + C52A0A5529266B1B007CE315 /* iOSSigningTests.swift */, 8E8A4908255420FC0056F79F /* PlatformDetectorTests.swift */, + C52A0A5329263483007CE315 /* UserInputTests.swift */, 8E8A490F25543F910056F79F /* SpecHelperTests.swift */, 8EDC54E125554B8C00A9CDFF /* CustomProperty+EnvironmentVarTests.swift */, BEAA71EC255A012900E9D4D9 /* AndroidProjectTests.swift */, 8EDC550B25592F5800A9CDFF /* iOSProjectTests.swift */, 2D99DF052820856A004A36E1 /* iOSVariantTests.swift */, - 8E6ABBAF25C03F05006A62FE /* SecretsFactoryTests.swift */, + 8E6ABBAF25C03F05006A62FE /* VariantsFileFactoryTests.swift */, 8E1B9C0E254AB51300DD0204 /* Resources */, 8E1B9CDD254AC1E700DD0204 /* Info.plist */, E39502A8256DB16B00484DCE /* String+WriteTests.swift */, @@ -451,7 +457,7 @@ children = ( OBJ_38 /* XCConfigFactory.swift */, OBJ_39 /* XcodeProjFactory.swift */, - 8E6ABBA325C03639006A62FE /* SecretsFactory.swift */, + 8E6ABBA325C03639006A62FE /* VariantsFileFactory.swift */, ); path = iOS; sourceTree = ""; @@ -764,7 +770,7 @@ 8E1B9DC8254AC27500DD0204 /* iOSProject.swift in Sources */, 8E866A1725D2CCEA00A7EC19 /* UserInput.swift in Sources */, 8E1B9E67254AC29500DD0204 /* Constants.swift in Sources */, - 8E6ABBA425C03639006A62FE /* SecretsFactory.swift in Sources */, + 8E6ABBA425C03639006A62FE /* VariantsFileFactory.swift in Sources */, 8E1BA0C4254BFF6400DD0204 /* Setup.swift in Sources */, 8E1B9E0A254AC27E00DD0204 /* Data+Write.swift in Sources */, 8E1B9EFE254AC2A900DD0204 /* AndroidVariant.swift in Sources */, @@ -800,6 +806,7 @@ buildActionMask = 2147483647; files = ( E39502C1256DBFA200484DCE /* ProjectFactoryTests.swift in Sources */, + C52A0A5629266B1C007CE315 /* iOSSigningTests.swift in Sources */, E333DBE9281C36B0000E8D03 /* KeyedDecodingContainerTests.swift in Sources */, 8E8A485A255165F60056F79F /* FastlaneParametersFactoryTests.swift in Sources */, 7C460E81281C1E8100BBF15D /* MockProject.swift in Sources */, @@ -813,8 +820,9 @@ 39D6D6002701E0740064BD41 /* StandardOutputStreamTests.swift in Sources */, 39C245AF26F8B198008CF1E0 /* PathSafeJoinTests.swift in Sources */, 397811F626F4BCF800643F91 /* MockLogger.swift in Sources */, + C52A0A5429263483007CE315 /* UserInputTests.swift in Sources */, 8E1B9F3B254AC31A00DD0204 /* YamlParserTests.swift in Sources */, - 8E6ABBB625C03F2C006A62FE /* SecretsFactoryTests.swift in Sources */, + 8E6ABBB625C03F2C006A62FE /* VariantsFileFactoryTests.swift in Sources */, 8EDC54E225554B8C00A9CDFF /* CustomProperty+EnvironmentVarTests.swift in Sources */, BEAA71ED255A012900E9D4D9 /* AndroidProjectTests.swift in Sources */, 8EDC550C25592F5800A9CDFF /* iOSProjectTests.swift in Sources */, diff --git a/docs/ENVIRONMENT_VARIABLES.md b/docs/ENVIRONMENT_VARIABLES.md index 04013837..447c6ce1 100644 --- a/docs/ENVIRONMENT_VARIABLES.md +++ b/docs/ENVIRONMENT_VARIABLES.md @@ -58,15 +58,38 @@ rootProject.ext.C_PROPERTY = System.getenv('FOO') - When platform is iOS, these properties behave in a slightly different way. -Properties whose destination is `project`, for iOS, that are **not** reading from environment variables, will be available in `variants.xcconfig`. +Properties whose destination is `project`, for iOS, that are **not** reading from environment variables, will be available in `variants.xcconfig`. But their names are exposed to the codebase directly in `Variants/Variants.swift`, as keys within a `ConfigurationValueKey` enum -``` -A_PROPERTY = FOO -B_PROPERTY = FOO +```swift +// This entire file is automatically generated. + +public struct Variants { + static let configuration: [String: Any] = { + guard let infoDictionary = Bundle.main.infoDictionary else { + fatalError("Info.plist file not found") + } + return infoDictionary + }() + + // MARK: - ConfigurationValueKey + /// Custom configuration values coming from variants.yml as enum cases + + public enum ConfigurationValueKey: String { + case A_PROPERTY + } + + static func configurationValue(for key: ConfigurationValueKey) -> Any? { + return Self.configuration[key.rawValue] + } + + ... + } ``` -These are used in your Swift code as: +It can be used in your codebase as: ```swift +Variants.configurationValue(for: .A_PROPERTY) +/// or Variants.configuration["A_PROPERTY"] ``` diff --git a/docs/GITHUB_ACTION.md b/docs/GITHUB_ACTION.md index 447ee81e..f0f5ca02 100644 --- a/docs/GITHUB_ACTION.md +++ b/docs/GITHUB_ACTION.md @@ -11,7 +11,7 @@ If Github Actions is your CI and you use the [Github-hosted macOS runner](https: ```yaml - uses: backbase/variants@main with: - version: 1.1.3 + version: 1.2.0 spec: variants.yml platform: ios variant: beta diff --git a/docs/USAGE.md b/docs/USAGE.md index 82d8232a..e249b16b 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -83,10 +83,14 @@ ios: version_name: 0.0.1 version_number: {{ envVars.VERSION_CODE }} store_destination: AppStore + # This is an optional field to override the default app name per variant + app_name: App Marketing Name custom: - name: apiBaseUrl value: https://sample.com/ destination: project + postSwitchScript: |- + echo default Variant Done Switching BETA: id_suffix: beta app_icon: AppIcon.beta @@ -100,6 +104,8 @@ ios: - key: OTHER_SWIFT_FLAGS value: $(inherited) -DBETA destination: project + postSwitchScript: |- + echo global Done Switching ``` ```yaml android: @@ -192,6 +198,12 @@ Configuration through custom properties can bring a lot of value to your variant See our [Custom Property documentation](CUSTOM_PROPERTY.md) for a better understanding and examples. +#### Post Switch Script (iOS) + +Post Switch Script allows you to specify a script or command to run after switching variants. It can be provided globally and for each variant individually. + +For more information check [Using Post Switch Script](ios/POST_SWITCH_SCRIPT.md). + #### Signing configuration Code signing for iOS apps can also be handled through `variants.yml` as long as Fastlane Match is used. diff --git a/docs/ios/POST_SWITCH_SCRIPT.md b/docs/ios/POST_SWITCH_SCRIPT.md new file mode 100644 index 00000000..fa6f33aa --- /dev/null +++ b/docs/ios/POST_SWITCH_SCRIPT.md @@ -0,0 +1,70 @@ +## Using Post Switch Script + +### What is a Post Switch Script? + +Post Switch Script allows you to specify a script or command to run after switching variants. Here's what it does: + +- **Variant-specific Post Switch Script**: You can define a script or command to run after switching to a particular variant. +- **Global Post Switch Script**: You can also define a script or command to run after switching to any variant globally. + +If you specify both a variant-specific and a global postSwitchScripts, the global one will run first, followed by the variant-specific one. + +### How to use it + +The "Post Switch Script" feature is optional for both local and global. In case you don't want to use it you can simply omit the configuration in the `variants.yml` file. + +#### Adding a Post Switch Script to a variant +- In your `variants.yml` file, add a `postSwitchScript` for a specific variant. + +```yaml +variants: + variant_name: + postSwitchScript: ./scripts/post_switch_variant1.sh +``` + +#### Adding a global Post Switch Script +- Add a global `postSwitchScript` to your `variants.yml` file. This script will run after switching to any variant. + +```yaml +postSwitchScript: ./scripts/post_switch_variant1.sh +``` + +### Script vs. Command + +The name "postSwitchScript" implies that you are providing a script to be run. However, in practice, you can also provide direct commands or the path to an executable bash file. + +- **Direct Commands**: You can specify commands directly in the postSwitchScript field. + +Single-line script: + +```yaml +variants: + variant_name: + postSwitchScript: echo "Hello, Variant 1" +``` + +Multi-line script: + +```yaml +variants: + variant_name: + postSwitchScript: >- + echo "My first multi-command" && + echo "My second mulit-command" +``` + +- **Executable Bash File**: You can provide the path to an executable bash file. + +```yaml +variants: + variant_name: + postSwitchScript: my_post_switch_script.sh +``` + +### Additional Notes + +- **Direct Execution of Files**: You can execute files by writing their path directly in the `postSwitchScript` field. +- **Multiple Commands**: If you want to execute multiple commands in the script, separate them using `&&` (for sequential execution) or `||` (for conditional execution) at the end of each line. +- **Multi-Line Commands**: According to YAML specification, starting with `|-` is useful if you have multi-line commands or want to start a command on a new line for readability. Additionally, you might use `>-` instead of `|-` to strip the last `\n`. + +That's it! You are now ready to make the most of the "Post Switch Script" feature for your configuration needs. diff --git a/samples/ios/VariantsSample/.gitignore b/samples/ios/VariantsSample/.gitignore deleted file mode 100644 index 29decfa0..00000000 --- a/samples/ios/VariantsSample/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -fastlane/ -variants.yml - -Gemfile -Gemfile.lock -VariantsSample/Variants/ -coherent-swift.yml -swiftlint.yml diff --git a/samples/ios/VariantsSample/Podfile b/samples/ios/VariantsSample/Podfile deleted file mode 100644 index 208837c2..00000000 --- a/samples/ios/VariantsSample/Podfile +++ /dev/null @@ -1,18 +0,0 @@ -platform :ios, '14.0' - -target 'VariantsSample' do - # Comment the next line if you don't want to use dynamic frameworks - use_frameworks! - - # Pods for VariantsSample - - target 'VariantsSampleTests' do - inherit! :search_paths - # Pods for testing - end - - target 'VariantsSampleUITests' do - # Pods for testing - end - -end diff --git a/samples/ios/VariantsSample/Podfile.lock b/samples/ios/VariantsSample/Podfile.lock deleted file mode 100644 index 44ec48af..00000000 --- a/samples/ios/VariantsSample/Podfile.lock +++ /dev/null @@ -1,3 +0,0 @@ -PODFILE CHECKSUM: 9700f4e294b82bbb721dd49924655eb9e5cdb50a - -COCOAPODS: 1.10.0.rc.1 diff --git a/samples/ios/VariantsSample/Pods/Manifest.lock b/samples/ios/VariantsSample/Pods/Manifest.lock deleted file mode 100644 index 44ec48af..00000000 --- a/samples/ios/VariantsSample/Pods/Manifest.lock +++ /dev/null @@ -1,3 +0,0 @@ -PODFILE CHECKSUM: 9700f4e294b82bbb721dd49924655eb9e5cdb50a - -COCOAPODS: 1.10.0.rc.1 diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-Info.plist b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-Info.plist deleted file mode 100644 index 2243fe6e..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - ${PRODUCT_BUNDLE_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0.0 - CFBundleSignature - ???? - CFBundleVersion - ${CURRENT_PROJECT_VERSION} - NSPrincipalClass - - - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.markdown b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.markdown deleted file mode 100644 index 102af753..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.markdown +++ /dev/null @@ -1,3 +0,0 @@ -# Acknowledgements -This application makes use of the following third party libraries: -Generated by CocoaPods - https://cocoapods.org diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.plist b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.plist deleted file mode 100644 index 7acbad1e..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-acknowledgements.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - PreferenceSpecifiers - - - FooterText - This application makes use of the following third party libraries: - Title - Acknowledgements - Type - PSGroupSpecifier - - - FooterText - Generated by CocoaPods - https://cocoapods.org - Title - - Type - PSGroupSpecifier - - - StringsTable - Acknowledgements - Title - Acknowledgements - - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-dummy.m b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-dummy.m deleted file mode 100644 index 973762af..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-dummy.m +++ /dev/null @@ -1,5 +0,0 @@ -#import -@interface PodsDummy_Pods_VariantsSample_VariantsSampleUITests : NSObject -@end -@implementation PodsDummy_Pods_VariantsSample_VariantsSampleUITests -@end diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-umbrella.h b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-umbrella.h deleted file mode 100644 index 87fa5fd7..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests-umbrella.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __OBJC__ -#import -#else -#ifndef FOUNDATION_EXPORT -#if defined(__cplusplus) -#define FOUNDATION_EXPORT extern "C" -#else -#define FOUNDATION_EXPORT extern -#endif -#endif -#endif - - -FOUNDATION_EXPORT double Pods_VariantsSample_VariantsSampleUITestsVersionNumber; -FOUNDATION_EXPORT const unsigned char Pods_VariantsSample_VariantsSampleUITestsVersionString[]; - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.debug.xcconfig b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.debug.xcconfig deleted file mode 100644 index 26f2c773..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.debug.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -PODS_BUILD_DIR = ${BUILD_DIR} -PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -PODS_PODFILE_DIR_PATH = ${SRCROOT}/. -PODS_ROOT = ${SRCROOT}/Pods -PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates -USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.modulemap b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.modulemap deleted file mode 100644 index b0a6ac69..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -framework module Pods_VariantsSample_VariantsSampleUITests { - umbrella header "Pods-VariantsSample-VariantsSampleUITests-umbrella.h" - - export * - module * { export * } -} diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.release.xcconfig b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.release.xcconfig deleted file mode 100644 index 26f2c773..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample-VariantsSampleUITests/Pods-VariantsSample-VariantsSampleUITests.release.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -PODS_BUILD_DIR = ${BUILD_DIR} -PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -PODS_PODFILE_DIR_PATH = ${SRCROOT}/. -PODS_ROOT = ${SRCROOT}/Pods -PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates -USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-Info.plist b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-Info.plist deleted file mode 100644 index 2243fe6e..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - ${PRODUCT_BUNDLE_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0.0 - CFBundleSignature - ???? - CFBundleVersion - ${CURRENT_PROJECT_VERSION} - NSPrincipalClass - - - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.markdown b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.markdown deleted file mode 100644 index 102af753..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.markdown +++ /dev/null @@ -1,3 +0,0 @@ -# Acknowledgements -This application makes use of the following third party libraries: -Generated by CocoaPods - https://cocoapods.org diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.plist b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.plist deleted file mode 100644 index 7acbad1e..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-acknowledgements.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - PreferenceSpecifiers - - - FooterText - This application makes use of the following third party libraries: - Title - Acknowledgements - Type - PSGroupSpecifier - - - FooterText - Generated by CocoaPods - https://cocoapods.org - Title - - Type - PSGroupSpecifier - - - StringsTable - Acknowledgements - Title - Acknowledgements - - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-dummy.m b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-dummy.m deleted file mode 100644 index 6e328025..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-dummy.m +++ /dev/null @@ -1,5 +0,0 @@ -#import -@interface PodsDummy_Pods_VariantsSample : NSObject -@end -@implementation PodsDummy_Pods_VariantsSample -@end diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-umbrella.h b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-umbrella.h deleted file mode 100644 index c703fc56..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample-umbrella.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __OBJC__ -#import -#else -#ifndef FOUNDATION_EXPORT -#if defined(__cplusplus) -#define FOUNDATION_EXPORT extern "C" -#else -#define FOUNDATION_EXPORT extern -#endif -#endif -#endif - - -FOUNDATION_EXPORT double Pods_VariantsSampleVersionNumber; -FOUNDATION_EXPORT const unsigned char Pods_VariantsSampleVersionString[]; - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.debug.xcconfig b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.debug.xcconfig deleted file mode 100644 index 26f2c773..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.debug.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -PODS_BUILD_DIR = ${BUILD_DIR} -PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -PODS_PODFILE_DIR_PATH = ${SRCROOT}/. -PODS_ROOT = ${SRCROOT}/Pods -PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates -USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.modulemap b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.modulemap deleted file mode 100644 index 1fdb66f3..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -framework module Pods_VariantsSample { - umbrella header "Pods-VariantsSample-umbrella.h" - - export * - module * { export * } -} diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.release.xcconfig b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.release.xcconfig deleted file mode 100644 index 26f2c773..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSample/Pods-VariantsSample.release.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -PODS_BUILD_DIR = ${BUILD_DIR} -PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -PODS_PODFILE_DIR_PATH = ${SRCROOT}/. -PODS_ROOT = ${SRCROOT}/Pods -PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates -USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-Info.plist b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-Info.plist deleted file mode 100644 index 2243fe6e..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - ${PRODUCT_BUNDLE_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0.0 - CFBundleSignature - ???? - CFBundleVersion - ${CURRENT_PROJECT_VERSION} - NSPrincipalClass - - - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.markdown b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.markdown deleted file mode 100644 index 102af753..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.markdown +++ /dev/null @@ -1,3 +0,0 @@ -# Acknowledgements -This application makes use of the following third party libraries: -Generated by CocoaPods - https://cocoapods.org diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.plist b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.plist deleted file mode 100644 index 7acbad1e..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-acknowledgements.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - PreferenceSpecifiers - - - FooterText - This application makes use of the following third party libraries: - Title - Acknowledgements - Type - PSGroupSpecifier - - - FooterText - Generated by CocoaPods - https://cocoapods.org - Title - - Type - PSGroupSpecifier - - - StringsTable - Acknowledgements - Title - Acknowledgements - - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-dummy.m b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-dummy.m deleted file mode 100644 index ce98aa76..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-dummy.m +++ /dev/null @@ -1,5 +0,0 @@ -#import -@interface PodsDummy_Pods_VariantsSampleTests : NSObject -@end -@implementation PodsDummy_Pods_VariantsSampleTests -@end diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-umbrella.h b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-umbrella.h deleted file mode 100644 index 486f63c2..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests-umbrella.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __OBJC__ -#import -#else -#ifndef FOUNDATION_EXPORT -#if defined(__cplusplus) -#define FOUNDATION_EXPORT extern "C" -#else -#define FOUNDATION_EXPORT extern -#endif -#endif -#endif - - -FOUNDATION_EXPORT double Pods_VariantsSampleTestsVersionNumber; -FOUNDATION_EXPORT const unsigned char Pods_VariantsSampleTestsVersionString[]; - diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.debug.xcconfig b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.debug.xcconfig deleted file mode 100644 index 26f2c773..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.debug.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -PODS_BUILD_DIR = ${BUILD_DIR} -PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -PODS_PODFILE_DIR_PATH = ${SRCROOT}/. -PODS_ROOT = ${SRCROOT}/Pods -PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates -USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.modulemap b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.modulemap deleted file mode 100644 index f02de623..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -framework module Pods_VariantsSampleTests { - umbrella header "Pods-VariantsSampleTests-umbrella.h" - - export * - module * { export * } -} diff --git a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.release.xcconfig b/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.release.xcconfig deleted file mode 100644 index 26f2c773..00000000 --- a/samples/ios/VariantsSample/Pods/Target Support Files/Pods-VariantsSampleTests/Pods-VariantsSampleTests.release.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -PODS_BUILD_DIR = ${BUILD_DIR} -PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -PODS_PODFILE_DIR_PATH = ${SRCROOT}/. -PODS_ROOT = ${SRCROOT}/Pods -PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates -USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/samples/ios/VariantsSample/README.md b/samples/ios/VariantsSample/README.md deleted file mode 100644 index 112bd741..00000000 --- a/samples/ios/VariantsSample/README.md +++ /dev/null @@ -1,21 +0,0 @@ -## iOS Sample Project - -### Version Control - -The project is checked into git so it can be used while testing and developing `variants` features. However future changes have been suppressed using the following commands: - -``` -find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd && git ls-files -z ${pwd} | xargs -0 git update-index --skip-worktree" \; -``` - -This can be undone by executing the following in this directory: - -``` -find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd && git ls-files -z ${pwd} | xargs -0 git update-index --no-skip-worktree" \; -``` - -More information can be found at these Stackoverflow answers: - -* https://stackoverflow.com/a/39776107/7264964 -* https://stackoverflow.com/a/55860969/7264964 - diff --git a/samples/ios/VariantsSample/VariantsSample.xcworkspace/contents.xcworkspacedata b/samples/ios/VariantsSample/VariantsSample.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index ea9f5af9..00000000 --- a/samples/ios/VariantsSample/VariantsSample.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/samples/ios/VariantsSample/VariantsSample/AppDelegate.swift b/samples/ios/VariantsSample/VariantsSample/AppDelegate.swift deleted file mode 100644 index af18e887..00000000 --- a/samples/ios/VariantsSample/VariantsSample/AppDelegate.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// AppDelegate.swift -// VariantsSample -// -// Created by Paolo Di Lorenzo on 10/28/20. -// - -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - // Override point for customization after application launch. - return true - } - - // MARK: UISceneSession Lifecycle - - func application( - _ application: UIApplication, - configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions - ) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - -} diff --git a/samples/ios/VariantsSample/VariantsSample/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/ios/VariantsSample/VariantsSample/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9221b9bb..00000000 --- a/samples/ios/VariantsSample/VariantsSample/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/samples/ios/VariantsSample/VariantsSample/Info.plist b/samples/ios/VariantsSample/VariantsSample/Info.plist deleted file mode 100644 index 5b531f7b..00000000 --- a/samples/ios/VariantsSample/VariantsSample/Info.plist +++ /dev/null @@ -1,66 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - UIApplicationSupportsIndirectInputEvents - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/samples/ios/VariantsSample/VariantsSample/SceneDelegate.swift b/samples/ios/VariantsSample/VariantsSample/SceneDelegate.swift deleted file mode 100644 index c820472d..00000000 --- a/samples/ios/VariantsSample/VariantsSample/SceneDelegate.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// SceneDelegate.swift -// VariantsSample -// -// Created by Paolo Di Lorenzo on 10/28/20. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - -} diff --git a/samples/ios/VariantsSample/VariantsSampleTests/Info.plist b/samples/ios/VariantsSample/VariantsSampleTests/Info.plist deleted file mode 100644 index 64d65ca4..00000000 --- a/samples/ios/VariantsSample/VariantsSampleTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/samples/ios/VariantsSample/VariantsSampleTests/VariantsSampleTests.swift b/samples/ios/VariantsSample/VariantsSampleTests/VariantsSampleTests.swift deleted file mode 100644 index f67a65c9..00000000 --- a/samples/ios/VariantsSample/VariantsSampleTests/VariantsSampleTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// VariantsSampleTests.swift -// VariantsSampleTests -// -// Created by Paolo Di Lorenzo on 10/28/20. -// - -import XCTest -@testable import VariantsSample - -class VariantsSampleTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation - // of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation - // of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests - // produce the correct results. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/samples/ios/VariantsSample/VariantsSampleUITests/Info.plist b/samples/ios/VariantsSample/VariantsSampleUITests/Info.plist deleted file mode 100644 index 64d65ca4..00000000 --- a/samples/ios/VariantsSample/VariantsSampleUITests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/samples/ios/VariantsSample/VariantsSampleUITests/VariantsSampleUITests.swift b/samples/ios/VariantsSample/VariantsSampleUITests/VariantsSampleUITests.swift deleted file mode 100644 index 56f678ce..00000000 --- a/samples/ios/VariantsSample/VariantsSampleUITests/VariantsSampleUITests.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// VariantsSampleUITests.swift -// VariantsSampleUITests -// -// Created by Paolo Di Lorenzo on 10/28/20. -// - -import XCTest - -class VariantsSampleUITests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation - // of each test method in the class. - - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - - // In UI tests it’s important to set the initial state - such as - // interface orientation - required for your tests before they run. - // The setUp method is a good place to do this. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation - // of each test method in the class. - } - - func testExample() throws { - // UI tests must launch the application that they test. - let app = XCUIApplication() - app.launch() - - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce - // the correct results. - } - - func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { - // This measures how long it takes to launch your application. - measure(metrics: [XCTApplicationLaunchMetric()]) { - XCUIApplication().launch() - } - } - } -} diff --git a/samples/ios/VariantsTestApp/Gemfile b/samples/ios/VariantsTestApp/Gemfile new file mode 100644 index 00000000..b05da1af --- /dev/null +++ b/samples/ios/VariantsTestApp/Gemfile @@ -0,0 +1,11 @@ +source 'https://rubygems.org' + +gem 'cocoapods', '1.11.3' +gem 'cocoapods-art' +gem 'fastlane' +gem 'slather' +gem 'json', '2.3.0' +gem 'nokogiri', '1.13.5' + +plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') +eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/samples/ios/VariantsTestApp/Gemfile.lock b/samples/ios/VariantsTestApp/Gemfile.lock new file mode 100644 index 00000000..51c7c9af --- /dev/null +++ b/samples/ios/VariantsTestApp/Gemfile.lock @@ -0,0 +1,317 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.6) + rexml + activesupport (6.1.7.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.711.0) + aws-sdk-core (3.170.0) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.62.0) + aws-sdk-core (~> 3, >= 3.165.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.119.1) + aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.2) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + clamp (1.3.2) + cocoapods (1.11.3) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.11.3) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 1.4.0, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 1.0, < 3.0) + xcodeproj (>= 1.21.0, < 2.0) + cocoapods-art (1.1.0) + cocoapods-core (1.11.3) + activesupport (>= 5.0, < 7) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (1.6.3) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + coderay (1.1.3) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + concurrent-ruby (1.2.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.8.1) + emoji_regex (3.2.3) + escape (0.0.4) + ethon (0.16.0) + ffi (>= 1.15.0) + excon (0.99.0) + faraday (1.10.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.211.0) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-appcenter (2.0.0) + fastlane-plugin-lizard (1.3.3) + bundler + fastlane + pry + fastlane-plugin-xcconfig (2.0.0) + fastlane-plugin-xchtmlreport (0.1.1) + ffi (1.15.5) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.34.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-core (0.11.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.16.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-playcustomapp_v1 (0.12.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.3.0) + google-cloud-storage (1.44.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.3.0) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + jmespath (1.6.2) + json (2.3.0) + jwt (2.7.0) + memoist (0.16.2) + method_source (1.0.0) + mini_magick (4.12.0) + mini_mime (1.1.2) + mini_portile2 (2.8.1) + minitest (5.17.0) + molinillo (0.8.0) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + nap (1.1.0) + naturally (2.2.1) + netrc (0.11.0) + nokogiri (1.13.5) + mini_portile2 (~> 2.8.0) + racc (~> 1.4) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + public_suffix (4.0.7) + racc (1.6.2) + rake (13.0.6) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + ruby-macho (2.5.1) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.3) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.10) + CFPropertyList + naturally + slather (2.7.2) + CFPropertyList (>= 2.2, < 4) + activesupport + clamp (~> 1.3) + nokogiri (~> 1.12) + xcodeproj (~> 1.21) + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + typhoeus (1.4.0) + ethon (>= 0.9.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.8.1) + word_wrap (1.0.0) + xcodeproj (1.22.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + zeitwerk (2.6.7) + +PLATFORMS + ruby + +DEPENDENCIES + cocoapods (= 1.11.3) + cocoapods-art + fastlane + fastlane-plugin-appcenter + fastlane-plugin-lizard + fastlane-plugin-xcconfig + fastlane-plugin-xchtmlreport + json (= 2.3.0) + nokogiri (= 1.13.5) + slather + +BUNDLED WITH + 2.1.4 diff --git a/samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.pbxproj b/samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.pbxproj new file mode 100644 index 00000000..16ca4ca0 --- /dev/null +++ b/samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.pbxproj @@ -0,0 +1,435 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 8E00D0E729967BD4009F995B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E00D0E629967BD4009F995B /* AppDelegate.swift */; }; + 8E00D0E929967BD4009F995B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E00D0E829967BD4009F995B /* SceneDelegate.swift */; }; + 8E00D0EB29967BD4009F995B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E00D0EA29967BD4009F995B /* ViewController.swift */; }; + 8E00D0EE29967BD4009F995B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8E00D0EC29967BD4009F995B /* Main.storyboard */; }; + 8E00D0F029967BD5009F995B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8E00D0EF29967BD5009F995B /* Assets.xcassets */; }; + 8E00D0F329967BD5009F995B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8E00D0F129967BD5009F995B /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 78DBE119A2B49BE740D07F6E /* variants.xcconfig */ = {isa = PBXFileReference; explicitFileType = text.xcconfig; lastKnownFileType = text.xcconfig; name = variants.xcconfig; path = variants.xcconfig; sourceTree = ""; }; + 8E00D0E329967BD4009F995B /* VariantsTestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VariantsTestApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8E00D0E629967BD4009F995B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 8E00D0E829967BD4009F995B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 8E00D0EA29967BD4009F995B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 8E00D0ED29967BD4009F995B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 8E00D0EF29967BD5009F995B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 8E00D0F229967BD5009F995B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 8E00D0F429967BD5009F995B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B512AE731F1EAB7155E4C339 /* Variants.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; lastKnownFileType = sourcecode.swift; name = Variants.swift; path = Variants.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8E00D0E029967BD4009F995B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 230F48C564AB3C5C82B10FD8 /* Variants */ = { + isa = PBXGroup; + children = ( + ); + name = Variants; + path = Variants; + sourceTree = ""; + }; + 3C00DF7AC3E9535AC87DE841 /* Variants */ = { + isa = PBXGroup; + children = ( + 78DBE119A2B49BE740D07F6E /* variants.xcconfig */, + B512AE731F1EAB7155E4C339 /* Variants.swift */, + ); + name = Variants; + path = Variants; + sourceTree = ""; + }; + 59718C9FC2D37D0BF4D2A70C /* Variants */ = { + isa = PBXGroup; + children = ( + ); + name = Variants; + path = Variants; + sourceTree = ""; + }; + 7811E91440F5CC74E43491D4 /* Variants */ = { + isa = PBXGroup; + children = ( + ); + name = Variants; + path = Variants; + sourceTree = ""; + }; + 8E00D0DA29967BD4009F995B = { + isa = PBXGroup; + children = ( + 8E00D0E529967BD4009F995B /* VariantsTestApp */, + 8E00D0E429967BD4009F995B /* Products */, + ); + sourceTree = ""; + }; + 8E00D0E429967BD4009F995B /* Products */ = { + isa = PBXGroup; + children = ( + 8E00D0E329967BD4009F995B /* VariantsTestApp.app */, + ); + name = Products; + sourceTree = ""; + }; + 8E00D0E529967BD4009F995B /* VariantsTestApp */ = { + isa = PBXGroup; + children = ( + 8E00D0E629967BD4009F995B /* AppDelegate.swift */, + 8E00D0E829967BD4009F995B /* SceneDelegate.swift */, + 8E00D0EA29967BD4009F995B /* ViewController.swift */, + 8E00D0EC29967BD4009F995B /* Main.storyboard */, + 8E00D0EF29967BD5009F995B /* Assets.xcassets */, + 8E00D0F129967BD5009F995B /* LaunchScreen.storyboard */, + 8E00D0F429967BD5009F995B /* Info.plist */, + 3C00DF7AC3E9535AC87DE841 /* Variants */, + EAFEB4948D49564FD23C7C18 /* Variants */, + 230F48C564AB3C5C82B10FD8 /* Variants */, + DF977394A4BABFEBDD9E1123 /* Variants */, + D0217B79AF9976E6B68D08EE /* Variants */, + 7811E91440F5CC74E43491D4 /* Variants */, + 59718C9FC2D37D0BF4D2A70C /* Variants */, + ); + path = VariantsTestApp; + sourceTree = ""; + }; + D0217B79AF9976E6B68D08EE /* Variants */ = { + isa = PBXGroup; + children = ( + ); + name = Variants; + path = Variants; + sourceTree = ""; + }; + DF977394A4BABFEBDD9E1123 /* Variants */ = { + isa = PBXGroup; + children = ( + ); + name = Variants; + path = Variants; + sourceTree = ""; + }; + EAFEB4948D49564FD23C7C18 /* Variants */ = { + isa = PBXGroup; + children = ( + ); + name = Variants; + path = Variants; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8E00D0E229967BD4009F995B /* VariantsTestApp */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8E00D0F729967BD5009F995B /* Build configuration list for PBXNativeTarget "VariantsTestApp" */; + buildPhases = ( + 8E00D0DF29967BD4009F995B /* Sources */, + 8E00D0E029967BD4009F995B /* Frameworks */, + 8E00D0E129967BD4009F995B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = VariantsTestApp; + productName = VariantsTestApp; + productReference = 8E00D0E329967BD4009F995B /* VariantsTestApp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8E00D0DB29967BD4009F995B /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1410; + LastUpgradeCheck = 1410; + TargetAttributes = { + 8E00D0E229967BD4009F995B = { + CreatedOnToolsVersion = 14.1; + }; + }; + }; + buildConfigurationList = 8E00D0DE29967BD4009F995B /* Build configuration list for PBXProject "VariantsTestApp" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8E00D0DA29967BD4009F995B; + productRefGroup = 8E00D0E429967BD4009F995B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8E00D0E229967BD4009F995B /* VariantsTestApp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8E00D0E129967BD4009F995B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E00D0F329967BD5009F995B /* LaunchScreen.storyboard in Resources */, + 8E00D0F029967BD5009F995B /* Assets.xcassets in Resources */, + 8E00D0EE29967BD4009F995B /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8E00D0DF29967BD4009F995B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E00D0EB29967BD4009F995B /* ViewController.swift in Sources */, + 8E00D0E729967BD4009F995B /* AppDelegate.swift in Sources */, + 8E00D0E929967BD4009F995B /* SceneDelegate.swift in Sources */, + "TEMP_BB6F0DB5-B674-40C8-99E9-2E703E5B30CC" /* (null) in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 8E00D0EC29967BD4009F995B /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 8E00D0ED29967BD4009F995B /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 8E00D0F129967BD5009F995B /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 8E00D0F229967BD5009F995B /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 8E00D0F529967BD5009F995B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8E00D0F629967BD5009F995B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8E00D0F829967BD5009F995B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 78DBE119A2B49BE740D07F6E /* variants.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "$(V_APP_ICON)"; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = R22WT7DX79; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = VariantsTestApp/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "$(V_BUNDLE_ID)"; + PRODUCT_NAME = "$(V_APP_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "$(V_MATCH_PROFILE)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8E00D0F929967BD5009F995B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 78DBE119A2B49BE740D07F6E /* variants.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "$(V_APP_ICON)"; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = R22WT7DX79; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = VariantsTestApp/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "$(V_BUNDLE_ID)"; + PRODUCT_NAME = "$(V_APP_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "$(V_MATCH_PROFILE)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8E00D0DE29967BD4009F995B /* Build configuration list for PBXProject "VariantsTestApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8E00D0F529967BD5009F995B /* Debug */, + 8E00D0F629967BD5009F995B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8E00D0F729967BD5009F995B /* Build configuration list for PBXNativeTarget "VariantsTestApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8E00D0F829967BD5009F995B /* Debug */, + 8E00D0F929967BD5009F995B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8E00D0DB29967BD4009F995B /* Project object */; +} diff --git a/samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/samples/ios/VariantsSample/VariantsSample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from samples/ios/VariantsSample/VariantsSample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to samples/ios/VariantsTestApp/VariantsTestApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/samples/ios/VariantsTestApp/VariantsTestApp/AppDelegate.swift b/samples/ios/VariantsTestApp/VariantsTestApp/AppDelegate.swift new file mode 100644 index 00000000..08aa0f42 --- /dev/null +++ b/samples/ios/VariantsTestApp/VariantsTestApp/AppDelegate.swift @@ -0,0 +1,37 @@ +// +// AppDelegate.swift +// VariantsTestApp +// +// Created by Arthur Alves on 10/02/2023. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, + configurationForConnecting connectingSceneSession: UISceneSession, + options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", + sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, + didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, + // this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } +} diff --git a/samples/ios/VariantsSample/VariantsSample/Assets.xcassets/AccentColor.colorset/Contents.json b/samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from samples/ios/VariantsSample/VariantsSample/Assets.xcassets/AccentColor.colorset/Contents.json rename to samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..f63859a6 --- /dev/null +++ b/samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "VariantsBlue.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIcon.appiconset/VariantsBlue.png b/samples/ios/VariantsTestApp/VariantsTestApp/Assets.xcassets/AppIcon.appiconset/VariantsBlue.png new file mode 100644 index 0000000000000000000000000000000000000000..52018efb84f519b80bfdce5489fecff637d07eba GIT binary patch literal 11879 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 + + + + CFBundleDisplayName + $(V_APP_NAME) + CFBundleExecutable + $(V_APP_NAME) + CFBundleIdentifier + $(V_BUNDLE_ID) + CFBundleName + $(V_APP_NAME) + CFBundleShortVersionString + $(V_VERSION_NAME) + CFBundleVersion + $(V_VERSION_NUMBER) + OTHER_SWIFT_FLAGS + $(OTHER_SWIFT_FLAGS) + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/samples/ios/VariantsTestApp/VariantsTestApp/SceneDelegate.swift b/samples/ios/VariantsTestApp/VariantsTestApp/SceneDelegate.swift new file mode 100644 index 00000000..1ba243a9 --- /dev/null +++ b/samples/ios/VariantsTestApp/VariantsTestApp/SceneDelegate.swift @@ -0,0 +1,52 @@ +// +// SceneDelegate.swift +// VariantsTestApp +// +// Created by Arthur Alves on 10/02/2023. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, + willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new + // (see `application:configurationForConnectingSceneSession` instead). + // guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, + // and store enough scene-specific state information + // to restore the scene back to its current state. + } +} diff --git a/samples/ios/VariantsTestApp/VariantsTestApp/Variants/Variants.swift b/samples/ios/VariantsTestApp/VariantsTestApp/Variants/Variants.swift new file mode 100644 index 00000000..8abb9ab9 --- /dev/null +++ b/samples/ios/VariantsTestApp/VariantsTestApp/Variants/Variants.swift @@ -0,0 +1,27 @@ +// +// Variants +// +// Copyright (c) Backbase B.V. - https://www.backbase.com +// Created by Arthur Alves +// + +import Foundation +public struct Variants { + static let configuration: [String: Any] = { + guard let infoDictionary = Bundle.main.infoDictionary else { + fatalError("Info.plist file not found") + } + return infoDictionary + }() + + // MARK: - ConfigurationValueKey + /// Custom configuration values coming from variants.yml as enum cases + public enum ConfigurationValueKey: String { + + case OTHER_SWIFT_FLAGS + } + static func configurationValue(for key: ConfigurationValueKey) -> Any? { + return Self.configuration[key.rawValue] + } + +} diff --git a/samples/ios/VariantsTestApp/VariantsTestApp/Variants/variants.xcconfig b/samples/ios/VariantsTestApp/VariantsTestApp/Variants/variants.xcconfig new file mode 100644 index 00000000..c0b27b34 --- /dev/null +++ b/samples/ios/VariantsTestApp/VariantsTestApp/Variants/variants.xcconfig @@ -0,0 +1,7 @@ +V_APP_ICON = AppIcon +V_VERSION_NAME = 0.0.1 +V_MATCH_PROFILE = match AppStore com.backbase.VariantsTestApp +OTHER_SWIFT_FLAGS = $(inherited) +V_BUNDLE_ID = com.backbase.VariantsTestApp +V_APP_NAME = VariantsTestApp +V_VERSION_NUMBER = 1 diff --git a/samples/ios/VariantsSample/VariantsSample/ViewController.swift b/samples/ios/VariantsTestApp/VariantsTestApp/ViewController.swift similarity index 74% rename from samples/ios/VariantsSample/VariantsSample/ViewController.swift rename to samples/ios/VariantsTestApp/VariantsTestApp/ViewController.swift index 5fa62c67..e836985f 100644 --- a/samples/ios/VariantsSample/VariantsSample/ViewController.swift +++ b/samples/ios/VariantsTestApp/VariantsTestApp/ViewController.swift @@ -1,17 +1,15 @@ // // ViewController.swift -// VariantsSample +// VariantsTestApp // -// Created by Paolo Di Lorenzo on 10/28/20. +// Created by Arthur Alves on 10/02/2023. // import UIKit class ViewController: UIViewController { - override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } - } diff --git a/samples/ios/VariantsTestApp/coherent-swift.yml b/samples/ios/VariantsTestApp/coherent-swift.yml new file mode 100644 index 00000000..3559aae2 --- /dev/null +++ b/samples/ios/VariantsTestApp/coherent-swift.yml @@ -0,0 +1,4 @@ +source: {{ SOURCE }} +minimum_threshold: 60 +reports_folder: ./coherent-reports/ +ignore_output_result: false diff --git a/samples/ios/VariantsTestApp/fastlane/AppCenter b/samples/ios/VariantsTestApp/fastlane/AppCenter new file mode 100644 index 00000000..3c5c0777 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/AppCenter @@ -0,0 +1,28 @@ +require File.expand_path('parameters/appcenter_params.rb', __dir__) + +# +# Ideally, each variant of your application, found in your 'variants.yml' spec would +# specify it's unique APPCENTER_APP_NAME as a custom parameter with destination +# 'fastlane'. +# +# Otherwise, you can always change the value below to read from an environment variable, +# hardcoded value, or anything really. +# + +APPCENTER_APP_NAME = VARIANTS_PARAMS[:APPCENTER_APP_NAME] + +# --- AppCenter + +desc 'deploy app to AppCenter' +private_lane :appcenter_deploy do |options| + destinations = options[:destinations] || APPCENTER_PARAMS[:APPCENTER_DESTINATION_GROUP] || "Collaborators" + notify = options[:notify] || true + + appcenter_upload( + api_token: APPCENTER_PARAMS[:APPCENTER_API_TOKEN], + owner_name: APPCENTER_PARAMS[:APPCENTER_OWNER_NAME], + app_name: APPCENTER_APP_NAME, + notify_testers: notify, + destinations: destinations + ) +end diff --git a/samples/ios/VariantsTestApp/fastlane/Appfile b/samples/ios/VariantsTestApp/fastlane/Appfile new file mode 100644 index 00000000..18030630 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Appfile @@ -0,0 +1,6 @@ +# app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app +# apple_id("[[APPLE_ID]]") # Your Apple email address + + +# For more information about the Appfile, see: +# https://docs.fastlane.tools/advanced/#appfile diff --git a/samples/ios/VariantsTestApp/fastlane/Appstore b/samples/ios/VariantsTestApp/fastlane/Appstore new file mode 100644 index 00000000..7f60aa97 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Appstore @@ -0,0 +1,40 @@ +require File.expand_path('parameters/appstore_params.rb', __dir__) +require File.expand_path('parameters/project_params.rb', __dir__) + +USERNAME = APPSTORE_PARAMS[:APPSTORE_USERNAME] +APPLE_ID = APPSTORE_PARAMS[:APPSTORE_APPLE_ID] +XCCONFIG_PATH = PROJECT_PARAMS[:XCCONFIG_PATH] + +# --- Appstore + +# +# ATTENTION: +# +# Deploying directly to AppStore +# using `pilot`, `deliver` or their aliases require +# authentication to AppStoreConnect. +# +# In order to have this handled automatically in +# your CI machine, you'll need an Application Specific Password +# +# Find more about it and how to generate yours in: +# https://docs.fastlane.tools/best-practices/continuous-integration/#application-specific-passwords +# + +desc 'deploy app to AppStore' +private_lane :appstore_deploy do |options| + # Retrieve app identifier from config + app_identifier = get_xcconfig_value( + path: XCCONFIG_PATH, + name: 'V_BUNDLE_ID' + ) + + deliver( + submit_for_review: false, + automatic_release: false, + force: true, # Skip HTMl report verification + skip_metadata: true, + skip_screenshots: true, + skip_binary_upload: false + ) +end diff --git a/samples/ios/VariantsTestApp/fastlane/BadgyLane b/samples/ios/VariantsTestApp/fastlane/BadgyLane new file mode 100644 index 00000000..98f7e90a --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/BadgyLane @@ -0,0 +1,28 @@ +# --- Badgy +# +# Adds badge overlay to AppIcon, replacing the entire set +# +# Example: +# fastlane badgy name:'BETA' app_icon:'./Sources/Assets.xcassets/AppIcon.appiconasset' color:'#FFD700' tint-color:'#FFF' +# + +desc 'switch variants' +lane :badgy do |options| + color = options[:color] || '#FFD700' + tintColor = options[:tint_color] || '#8B7500' + appIcon = options[:app_icon] || PROJECT_PARAMS[:APP_ICON_ASSET_PATH] + angle = options[:angle] || '15' + position = options[:position] || 'bottom' + + if options[:name] + name = options[:name] + begin + sh "`which badgy` long #{name} #{appIcon} --position #{position} --angle #{angle} --color '#{color}' --tint-color '#{tintColor}' --replace" + rescue + UI.user_error!("'badgy' not installed or something went wrong") + end + else + puts "Accepted parameters - 'name', 'color', 'tint_color', 'app_icon', 'angle', 'position'" + UI.user_error!("Missing parameter `name` - Badge name as string") + end +end diff --git a/samples/ios/VariantsTestApp/fastlane/Cocoapods b/samples/ios/VariantsTestApp/fastlane/Cocoapods new file mode 100644 index 00000000..0d830498 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Cocoapods @@ -0,0 +1,16 @@ +# --- Cocoapod dependencies + +desc 'Update cocoapods and repo-art automatically if pod install fails' +lane :pods_update do + cocoapods(use_bundle_exec: true, error_callback: lambda { |_result| + # If you use Cocoapods-art + # pod_repo_art_update + cocoapods(use_bundle_exec: true, repo_update: true) + }) +end + +desc 'Update all repo-art repositories' +lane :pod_repo_art_update do + repos = sh 'pod repo-art | egrep \'^[a-zA-Z]\'' + repos.split("\n").each { |repo| sh "pod repo-art update #{repo}" } +end diff --git a/samples/ios/VariantsTestApp/fastlane/Cohesion b/samples/ios/VariantsTestApp/fastlane/Cohesion new file mode 100644 index 00000000..6b3e22fa --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Cohesion @@ -0,0 +1,11 @@ + +COHERENT_SPEC = PROJECT_PARAMS[:COHERENT_SPEC] + +desc 'Measure and report cohesion' +lane :run_cohesion do + begin + sh "`which coherent-swift` report -s #{COHERENT_SPEC}" + rescue + puts "Skipping step - Couldn't find 'coherent-swift' or something went wrong" + end +end diff --git a/samples/ios/VariantsTestApp/fastlane/Coverage b/samples/ios/VariantsTestApp/fastlane/Coverage new file mode 100644 index 00000000..378c7b6a --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Coverage @@ -0,0 +1,15 @@ +# --- Coverage + +desc 'convert coverage .profdata to cobertura xml' +lane :run_coverage do |options| + defaults = { + proj: PROJECT, + workspace: WORKSPACE, + scheme: APP_SCHEME, + cobertura_xml: true, + input_format: "profdata", + build_directory: DERIVED_DATA_PATH, + }.freeze + + slather(defaults.merge(options)) +end diff --git a/samples/ios/VariantsTestApp/fastlane/Deliverfile b/samples/ios/VariantsTestApp/fastlane/Deliverfile new file mode 100644 index 00000000..8812017c --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Deliverfile @@ -0,0 +1,54 @@ +require File.expand_path('parameters/match_params.rb', __dir__) + +CODE_SIGNING_IDENTITY = MATCH_PARAMS[:TEAMNAME] +TEAM_ID = MATCH_PARAMS[:TEAMID] +EXPORT_METHOD = MATCH_PARAMS[:EXPORTMETHOD] + +# This is the example Deliverfile +# +# You can remove those parts you don't need +# +# Everything next to a # is a comment and will be ignored + +######################################## +# App Metadata +######################################## + +apple_id '' + +# This folder has to include one folder for each language +# More information about automatic screenshot upload: +# https://github.com/KrauseFx/deliver#upload-screenshots-to-itunes-connect +screenshots_path "" + +app_icon "" + +title({ + "en-US" => "" +}) + +# This log has to include the changes made for the release. It has been commented out for the purpose of developer interest to choose either from repository or from fastlane. +# changelog({ +# "en-US" => "iPhone 6 (Plus) Support" +# }) + +description({ + 'en-US' => "" +}) + +copyright "" + +app_review_information({ + first_name: "", + last_name: "", + phone_number: "", + email_address: "", + demo_user: "", + demo_password: "", + notes: "" +}) + +primary_category "" +secondary_category "" + +ratings_config_path "" diff --git a/samples/ios/VariantsTestApp/fastlane/Dependencies b/samples/ios/VariantsTestApp/fastlane/Dependencies new file mode 100644 index 00000000..0de18a57 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Dependencies @@ -0,0 +1,35 @@ +homebrewDependencies = { + # Uncomment the following line if you want to measure the `cohesion` of your codebase (enabled in `fastlane/Deploy`, lane `all_but_deploy`) + #"coherent-swift" => "arthurpalves/formulae/coherent-swift", + + # Uncomment the following 2 lines if you want to generate overlays for your app icons (enabled in `fastlane/Deploy`, lane `deploy`) + #"badgy" => "arthurpalves/formulae/badgy", + #"convert" => "imagemagick", + + "swiftlint" => "swiftlint", + "swiftformat" => "swiftformat" +} + +desc 'prepare dependencies' +lane :prepare_dependencies do + homebrewDependencies.each do |key, value| + install_dependency(dependency: {key => value}) + end +end + +private_lane :install_dependency do |options| + if options[:dependency] && options[:dependency].is_a?(Hash) + dependency = options[:dependency] + dependency.each do |key, value| + begin + executable = sh "which #{key}" + puts "Found '#{key}' at: "+executable + rescue + puts "Couldn't find '#{key}', installing it." + sh "brew install #{value}" + end + end + else + puts "'install_dependency' failed - :dependency not found or not a Hash" + end +end diff --git a/samples/ios/VariantsTestApp/fastlane/Deploy b/samples/ios/VariantsTestApp/fastlane/Deploy new file mode 100644 index 00000000..2b3f73b5 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Deploy @@ -0,0 +1,91 @@ +require File.expand_path('parameters/match_params.rb', __dir__) + +CODE_SIGNING_IDENTITY = MATCH_PARAMS[:TEAMNAME] +TEAM_ID = MATCH_PARAMS[:TEAMID] +EXPORT_METHOD = MATCH_PARAMS[:EXPORTMETHOD] + +# --- Well, it doesn't deploy + +# +# Perfect for a PR branch. +# +# Example: +# fastlane run_all_but_deploy + +desc 'runs everything but deploy' +lane :run_all_but_deploy do + run_all_tests + run_coverage + run_swiftlint + # run_cohesion + # run_lizard + # run_sonar +end + +# --- Deploy + +desc 'run deploy' +lane :deploy do |options| + destination = options[:store_destination] || VARIANTS_PARAMS[:STORE_DESTINATION] || 'appcenter' + destination = destination.downcase + + run_all_but_deploy + + # If Match is enabled, uncomment line below + # run_match_signing + + # Change icon on the fly by adding a badge overlay to it + # AppIcon is defined in 'parameters/project_params.rb' + # or specify icon path via parameter 'app_icon' + # + # if options[:variant] + # badge_name = options[:variant] + # badgy(name: badge_name) + # end + + archive + + if destination == 'appcenter' + appcenter_deploy + elsif destination == 'testflight' + testflight_deploy + elsif destination == 'appstore' + appstore_deploy + end + + + # Send a Slack message + # + # The following parameters are necessary: + # - 'channel' (string) + # - 'hook_url' (string) + # - 'interactive_url' (string) - URL you'll click to lead you to AppCenter/AppStore or CI pipeline + # - 'message' (string) - What to inform? + # - 'success' (boolean) - OPTIONAL value, false by default. + # + # send_slack_message +end + +# --- Build and archive + +desc "build and archive" +private_lane :archive do |options| + configuration = options[:configuration] || "Release" + + defaults = { + workspace: WORKSPACE, + configuration: configuration, + scheme: APP_SCHEME, + silent: false, + clean: true, + export_team_id: TEAM_ID, + codesigning_identity: CODE_SIGNING_IDENTITY, + export_options: { + method: EXPORT_METHOD + }, + xcargs: '-allowProvisioningUpdates', + skip_profile_detection: true + }.freeze + + build_ios_app(defaults.merge(options)) +end diff --git a/samples/ios/VariantsTestApp/fastlane/Fastfile b/samples/ios/VariantsTestApp/fastlane/Fastfile new file mode 100644 index 00000000..3e65f61b --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Fastfile @@ -0,0 +1,75 @@ +require File.expand_path('parameters/project_params.rb', __dir__) +require File.expand_path('parameters/variants_params.rb', __dir__) + +DERIVED_DATA_PATH = PROJECT_PARAMS[:DERIVED_DATA_PATH] +REPORTS_FOLDER = PROJECT_PARAMS[:REPORTS_FOLDER] +PROJECT = sh 'ls ..|grep "xcodeproj"|sort -r|head -n 1|tr -d "\n"' +WORKSPACE = sh 'ls ..|grep "xcworkspace"|sort -r|head -n 1|tr -d "\n"' +APP_SCHEME = WORKSPACE.split('.')[0] + +import('AppCenter') +import('BadgyLane') +import('Cohesion') +import('Cocoapods') +import('Coverage') +import('Dependencies') +import('Deploy') +import('Lizard') +import('Match') +import('Sonar') +import('SwiftLint') +import('Tests') +import('TestFlight') +import('Appstore') +import('Deliverfile') + +# --- Before all, prepare + +before_all do |lane, options| + # - Install dependencies if needed + # - Setup CI machine + # - Install/update Cocoapods + prepare + + # - Creates temporary keychain used by :match_signing_config + # see 'fastlane/Match' file + if is_ci? + create_temporary_keychain + end +end + +# --- After all, clean up + +after_all do |lane, options| + # - Removes temporary keychain used by :match_signing_config + # see 'fastlane/Match' file + if is_ci? + remove_keychain + end +end + +# --- Preparation phase + +desc 'prepares the environment' +lane :prepare do |options| + defaults = { + derived_data_path: DERIVED_DATA_PATH + }.freeze + options = defaults.merge(options) + + # Check if CLI dependencies are installed + # Otherwise, install them + if is_ci? + prepare_dependencies + end + + # Temporarily disable update_fastlane due to + # https://github.com/fastlane/fastlane/issues/16127 + # update_fastlane + + # Setup CI machine + setup_jenkins(options) + + # Update/Install Pods + pods_update +end diff --git a/samples/ios/VariantsTestApp/fastlane/Lizard b/samples/ios/VariantsTestApp/fastlane/Lizard new file mode 100644 index 00000000..2caf099c --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Lizard @@ -0,0 +1,20 @@ +require File.expand_path('parameters/lizard_params.rb', __dir__) + +SOURCE = LIZARD_PARAMS[:SOURCE] +EXPORT_TYPE = LIZARD_PARAMS[:EXPORT_TYPE] +FALLBACK_EXECUTABLE = LIZARD_PARAMS[:FALLBACK_EXECUTABLE] + +desc 'run a lizard scan on the project' +lane :run_lizard do |options| + executable = options[:executable] || FALLBACK_EXECUTABLE + + defaults = { + source_folder: SOURCE, + language: 'swift', + export_type: EXPORT_TYPE, + report_file: "#{REPORTS_FOLDER}/lizard-report.xml", + executable: executable + }.freeze + + lizard(defaults.merge(options)) +end diff --git a/samples/ios/VariantsTestApp/fastlane/Match b/samples/ios/VariantsTestApp/fastlane/Match new file mode 100644 index 00000000..f8d3b25c --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Match @@ -0,0 +1,42 @@ +require File.expand_path('parameters/match_params.rb', __dir__) + +MATCH_KEYCHAIN_NAME = MATCH_PARAMS[:MATCH_KEYCHAIN_NAME] +MATCH_KEYCHAIN_PASSWORD = MATCH_PARAMS[:MATCH_KEYCHAIN_PASSWORD] +MATCH_GIT_BASIC_AUTHORIZATION = MATCH_PARAMS[:MATCH_GIT_BASIC_AUTHORIZATION] + +# --- MATCH + +desc 'match signing confifguration' +lane :run_match_signing do + match( + keychain_name: MATCH_KEYCHAIN_NAME, + keychain_password: MATCH_KEYCHAIN_PASSWORD, + git_basic_authorization: MATCH_GIT_BASIC_AUTHORIZATION, + readonly: true, + verbose: true, + skip_docs: true + ) +end + +# --- KEYCHAIN + +desc "create temporary keychain" +private_lane :create_temporary_keychain do + create_keychain( + name: MATCH_KEYCHAIN_NAME, + password: MATCH_KEYCHAIN_PASSWORD, + default_keychain: is_ci, + unlock: true, + timeout: 3600, + lock_when_sleeps: false + ) +end + +desc "delete temporary keychain" +private_lane :remove_keychain do + delete_keychain( + name: MATCH_KEYCHAIN_NAME + ) +end + + diff --git a/samples/ios/VariantsTestApp/fastlane/Matchfile b/samples/ios/VariantsTestApp/fastlane/Matchfile new file mode 100644 index 00000000..c8d2a6ec --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Matchfile @@ -0,0 +1,5 @@ +git_url("git@github.com:sample/match.git") +storage_mode("git") +# appstore, development, adhoc, enterprise +type("appstore") +app_identifier("com.backbase.VariantsTestApp") \ No newline at end of file diff --git a/samples/ios/VariantsTestApp/fastlane/Pluginfile b/samples/ios/VariantsTestApp/fastlane/Pluginfile new file mode 100644 index 00000000..56413394 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Pluginfile @@ -0,0 +1,4 @@ +gem 'fastlane-plugin-appcenter' +gem 'fastlane-plugin-lizard' +gem 'fastlane-plugin-xcconfig' +gem 'fastlane-plugin-xchtmlreport' diff --git a/samples/ios/VariantsTestApp/fastlane/Slack b/samples/ios/VariantsTestApp/fastlane/Slack new file mode 100644 index 00000000..eb9d204b --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Slack @@ -0,0 +1,37 @@ + +# --- Slack + +desc 'send deployment message to a Slack channel' +lane :send_slack_message do |options| + + if options[:channel] + && options[:hook_url] + && options[:interactive_url] + && options[:message] + + channel = options[:channel] + hook_url = options[:hook_url] + interactive_url = options[:interactive_url] + message = options[:message] + success = options[:success] || false + + slack( + slack_url: hook_url, + message: message, + channel: channel, + success: success, + payload: { + "Build Date" => Time.new.to_s, + }, + default_payloads: [:git_branch, :lane, :test_result, :last_git_commit], + attachment_properties: { + fields: [{ + title: "Link", + value: interactive_url, + short: false + }] + } + ) + end +end + diff --git a/samples/ios/VariantsTestApp/fastlane/Sonar b/samples/ios/VariantsTestApp/fastlane/Sonar new file mode 100644 index 00000000..34571257 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Sonar @@ -0,0 +1,15 @@ +# --- Sonar + +desc 'run a sonar scan using the configuration in sonar-project.properties' +lane :sonar_report do |options| + BRANCH_NAME = options[:branch_name] || '' + options.delete :branch + + defaults = { + project_name: "#{APP_SCHEME} #{BRANCH_NAME}".strip, + project_key: "#{APP_SCHEME}:#{BRANCH_NAME}".strip, + project_version: get_version_number(target: APP_SCHEME) + }.freeze + + sonar(defaults.merge(options)) +end diff --git a/samples/ios/VariantsTestApp/fastlane/SwiftLint b/samples/ios/VariantsTestApp/fastlane/SwiftLint new file mode 100644 index 00000000..1b00b04b --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/SwiftLint @@ -0,0 +1,24 @@ +require File.expand_path('parameters/project_params.rb', __dir__) + +SWIFTLINT_PATH = PROJECT_PARAMS[:SWIFTLINT_PATH] +REPORTS_FOLDER = PROJECT_PARAMS[:REPORTS_FOLDER] + +# --- SwiftLint + +desc 'run swiftlint on the entire codebase' +lane :run_swiftlint do |options| + begin + executable = sh "which swiftlint|tr -d '\n'" + puts "Found 'swiftlint' at: "+executable + defaults = { + config_file: SWIFTLINT_PATH, + executable: executable, + path: "../#{APP_SCHEME}/**/*", + output_file: "#{REPORTS_FOLDER}/swiftlint.result" + }.freeze + + swiftlint(defaults.merge(options)) + rescue + puts "Failed running swiftlint" + end +end diff --git a/samples/ios/VariantsTestApp/fastlane/TestFlight b/samples/ios/VariantsTestApp/fastlane/TestFlight new file mode 100644 index 00000000..c6b9022b --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/TestFlight @@ -0,0 +1,38 @@ +require File.expand_path('parameters/appstore_params.rb', __dir__) +require File.expand_path('parameters/project_params.rb', __dir__) + +USERNAME = PROJECT_PARAMS[:APPSTORE_USERNAME] +APPLE_ID = PROJECT_PARAMS[:APPSTORE_APPLE_ID] +XCCONFIG_PATH = PROJECT_PARAMS[:XCCONFIG_PATH] + +# --- TestFlight + +# +# ATTENTION: +# +# Deploying to TestFlight or directly to AppStore +# using `pilot`, `deliver` or their aliases require +# authentication to AppStoreConnect. +# +# In order to have this handled automatically in +# your CI machine, you'll need an Application Specific Password +# +# Find more about it and how to generate yours in: +# https://docs.fastlane.tools/best-practices/continuous-integration/#application-specific-passwords +# + +private_lane :testflight_deploy do |options| + # Retrieve app identifier from config + app_identifier = get_xcconfig_value( + path: XCCONFIG_PATH, + name: 'V_BUNDLE_ID' + ) + + pilot( + username: USERNAME, + app_identifier: app_identifier, + apple_id: APPLE_ID, + skip_submission: true, + skip_waiting_for_build_processing: true + ) +end diff --git a/samples/ios/VariantsTestApp/fastlane/Tests b/samples/ios/VariantsTestApp/fastlane/Tests new file mode 100644 index 00000000..aaff58cb --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/Tests @@ -0,0 +1,41 @@ +require File.expand_path('parameters/uitest_params.rb', __dir__) + +TEST_DEVICES = PROJECT_PARAMS[:TEST_DEVICES] + +UITEST_SCHEME = UITEST_PARAMS[:UITEST_SCHEME] +UITEST_REPORTS_FOLDER = UITEST_PARAMS[:UITEST_REPORTS_FOLDER] +UITEST_DESTINATION = UITEST_PARAMS[:UITEST_DESTINATION] + +# --- Tests + +desc 'run all tests' +lane :run_all_tests do |options| + defaults = { + workspace: WORKSPACE, + scheme: APP_SCHEME, + code_coverage: true, + devices: TEST_DEVICES, + derived_data_path: DERIVED_DATA_PATH, + output_directory: REPORTS_FOLDER + }.freeze + + scan(defaults.merge(options)) +end + +desc 'run only UI tests' +lane :run_ui_tests do |options| + defaults = { + workspace: WORKSPACE, + scheme: UITEST_SCHEME, + output_directory: UITEST_REPORTS_FOLDER, + destination: UITEST_DESTINATION, + clean: true, + max_concurrent_simulators: 1, + disable_concurrent_testing: true, + result_bundle: true, + fail_build: false, + }.freeze + + scan(defaults.merge(options)) + xchtmlreport(result_bundle_path: "#{UITEST_REPORTS_FOLDER}/#{UITEST_SCHEME}.xcresult") +end diff --git a/samples/ios/VariantsTestApp/fastlane/parameters/appcenter_params.rb b/samples/ios/VariantsTestApp/fastlane/parameters/appcenter_params.rb new file mode 100644 index 00000000..1f45c04f --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/parameters/appcenter_params.rb @@ -0,0 +1,5 @@ +APPCENTER_PARAMS = { + APPCENTER_OWNER_NAME: ENV["APPCENTER_OWNER_NAME"], + APPCENTER_API_TOKEN: ENV["APPCENTER_API_TOKEN"], + APPCENTER_DESTINATION_GROUP: ENV["APPCENTER_DESTINATION_GROUP"] +}.freeze diff --git a/samples/ios/VariantsTestApp/fastlane/parameters/appstore_params.rb b/samples/ios/VariantsTestApp/fastlane/parameters/appstore_params.rb new file mode 100644 index 00000000..f07d7ac3 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/parameters/appstore_params.rb @@ -0,0 +1,4 @@ +APPSTORE_PARAMS = { + APPSTORE_APPLE_ID: ENV["APPSTORE_APPLE_ID"], + APPSTORE_USERNAME: ENV["APPSTORE_USERNAME"] +}.freeze diff --git a/samples/ios/VariantsTestApp/fastlane/parameters/lizard_params.rb b/samples/ios/VariantsTestApp/fastlane/parameters/lizard_params.rb new file mode 100644 index 00000000..41c9212f --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/parameters/lizard_params.rb @@ -0,0 +1,5 @@ +LIZARD_PARAMS = { + SOURCE: 'Sources', + EXPORT_TYPE: 'xml', + FALLBACK_EXECUTABLE: '/Users/users/Library/Python/2.7/bin/lizard' +}.freeze diff --git a/samples/ios/VariantsTestApp/fastlane/parameters/match_params.rb b/samples/ios/VariantsTestApp/fastlane/parameters/match_params.rb new file mode 100644 index 00000000..53345d49 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/parameters/match_params.rb @@ -0,0 +1,17 @@ +# Generated by Variants +MATCH_PARAMS = { + MATCH_KEYCHAIN_NAME: ENV['MATCH_KEYCHAIN_NAME'], + MATCH_KEYCHAIN_PASSWORD: ENV['MATCH_KEYCHAIN_PASSWORD'], + + # This is needed if your Match repository is private + MATCH_GIT_BASIC_AUTHORIZATION: ENV['MATCH_GIT_BASIC_AUTHORIZATION'], + + # Match repository password, used to decrypt files + MATCH_PASSWORD: ENV['MATCH_PASSWORD'], + + # Signing properties coming from Variants YAML spec. Do not change manually + TEAMNAME: "Backbase B.V.", + TEAMID: "R22WT7DX79", + EXPORTMETHOD: "appstore", + MATCHURL: "git@github.com:sample/match.git", +}.freeze \ No newline at end of file diff --git a/samples/ios/VariantsTestApp/fastlane/parameters/project_params.rb b/samples/ios/VariantsTestApp/fastlane/parameters/project_params.rb new file mode 100644 index 00000000..5c0a0c7e --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/parameters/project_params.rb @@ -0,0 +1,13 @@ + +PROJECT_PARAMS = { + # MUST CHANGE + APP_ICON_SET_PATH: "../SamplePath/Assets.xcassets/AppIcon.appiconset", + XCCONFIG_PATH: "../SamplePath/Variants/variants.xcconfig", + + COHERENT_SPEC: '../coherent-swift.yml', + VARIANTS_SPEC: '../variants.yml', + SWIFTLINT_PATH: 'swiftlint.yml', + DERIVED_DATA_PATH: '.derivedData', + REPORTS_FOLDER: './reports', + TEST_DEVICES: ['iPhone 11'] +}.freeze diff --git a/samples/ios/VariantsTestApp/fastlane/parameters/uitest_params.rb b/samples/ios/VariantsTestApp/fastlane/parameters/uitest_params.rb new file mode 100644 index 00000000..c8085c02 --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/parameters/uitest_params.rb @@ -0,0 +1,5 @@ +UITEST_PARAMS = { + UITEST_SCHEME: '', + UITEST_REPORTS_FOLDER: './uitest-results', + UITEST_DESTINATION: "platform=iOS Simulator,name=#{ENV["DEVICE"]},OS=#{ENV["OS"]}" +}.freeze diff --git a/samples/ios/VariantsTestApp/fastlane/parameters/variants_params.rb b/samples/ios/VariantsTestApp/fastlane/parameters/variants_params.rb new file mode 100644 index 00000000..85e8f91e --- /dev/null +++ b/samples/ios/VariantsTestApp/fastlane/parameters/variants_params.rb @@ -0,0 +1,5 @@ +# Generated by Variants +VARIANTS_PARAMS = { + SAMPLE_FASTLANE_PROPERTY: "This will be available to fastlane", + STORE_DESTINATION: "appstore", +}.freeze \ No newline at end of file diff --git a/samples/ios/VariantsTestApp/swiftlint.yml b/samples/ios/VariantsTestApp/swiftlint.yml new file mode 100644 index 00000000..b3359722 --- /dev/null +++ b/samples/ios/VariantsTestApp/swiftlint.yml @@ -0,0 +1,13 @@ +disabled_rules: + - large_tuple + - trailing_whitespace + - todo + - opening_brace + - nesting +excluded: + - Pods + - .build +line_length: 140 +file_length: + warning: 200 + error: 250 diff --git a/samples/ios/VariantsTestApp/variants.yml b/samples/ios/VariantsTestApp/variants.yml new file mode 100644 index 00000000..dd2a8319 --- /dev/null +++ b/samples/ios/VariantsTestApp/variants.yml @@ -0,0 +1,87 @@ +# +# Auto generated by Variants +# TODO: Replace placeholders with real values if applicable +# + +ios: + xcodeproj: VariantsTestApp.xcodeproj + targets: + VariantsTestApp: + name: VariantsTestApp + bundle_id: com.backbase.VariantsTestApp + test_target: VariantsTestAppTest + app_icon: AppIcon + source: + path: VariantsTestApp + info: VariantsTestApp/Info.plist + config: VariantsTestApp + variants: + # Default variant is mandatory, do not remove + default: + version_name: 0.0.1 + version_number: 1 + # 'store_destination' can be: AppStore, TestFlight or AppCenter + store_destination: AppStore + + # + # custom: - Not required. + # + # You can have as many custom fields as possible. + # Only strings allowed. + # + # The value of will be written to 1 of 2 possible destinations: + # - project => variants.xcconfig + # - fastlane => fastlane/parameters/variants_params.rb + # + custom: + - name: OTHER_SWIFT_FLAGS + value: $(inherited) + env: false + destination: project + - name: SAMPLE_FASTLANE_PROPERTY + value: This will be available to fastlane + env: false + destination: fastlane + # + # Sample variant, "beta". + # Only `version_name` and `version_number` are mandatory fields + # + BETA: + id_suffix: beta + # If app_icon isn't specified, the value fallbacks to target.app_icon + app_icon: AppIconYellow + version_name: 0.0.1 + version_number: 1 + # 'store_destination' can be: AppStore, TestFlight or AppCenter + store_destination: AppCenter + + custom: + - name: OTHER_SWIFT_FLAGS + value: $(inherited) + env: false + destination: project + - name: SAMPLE_FASTLANE_PROPERTY + value: This will be available to fastlane on Beta variant + env: false + destination: fastlane + + signing: + # 'match_url' isn't mandatory, only if you use Match to sign your app + match_url: "git@github.com:sample/match.git" + team_name: "Backbase B.V." + team_id: "R22WT7DX79" + export_method: "appstore" + + # ---------------------------------------------------------------------- + # custom: - Not required. + # + # Same as variant's `custom`, but this will be processed regardless of + # the chosen variant. + # + # Comment or delete section below if necessary. + # ---------------------------------------------------------------------- + + #custom: + # - name: SAMPLE_PROPERTY + # value: Sample value + # destination: project From 9caf67e44435c3c51ab4752607bdfaccc1d50490 Mon Sep 17 00:00:00 2001 From: Arthur Alves Date: Thu, 26 Oct 2023 13:38:34 +0200 Subject: [PATCH 2/3] Release 1.2.1 (#236) * FIX: Reverting supporting-variants-and-pods-configs-simultaneously, that created a bug which cause the UITests project to import an unneeded pod used by the app project, since the xcconfig is shared between the app and the tests projects (#233) --------- Signed-off-by: dependabot[bot] Co-authored-by: Nour Sandid --- Sources/Variants/main.swift | 2 +- .../Factory/iOS/XCConfigFactory.swift | 17 ----------------- docs/GITHUB_ACTION.md | 2 +- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/Sources/Variants/main.swift b/Sources/Variants/main.swift index 84ca8396..642535b5 100644 --- a/Sources/Variants/main.swift +++ b/Sources/Variants/main.swift @@ -12,7 +12,7 @@ struct Variants: ParsableCommand { static var configuration = CommandConfiguration( commandName: "variants", abstract: "A command-line tool to setup deployment variants and working CI/CD setup", - version: "1.2.0", + version: "1.2.1", subcommands: [ Initializer.self, Setup.self, diff --git a/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift b/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift index 1e4968c3..69d1eeb5 100644 --- a/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift +++ b/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift @@ -159,7 +159,6 @@ class XCConfigFactory: XCFactory { private func populateConfig(with target: NamedTarget, configFile: Path, variant: iOSVariant) { logger.logInfo("Populating: ", item: "'\(configFile.lastComponent)'") - importPodsIfNeeded(target: target, configFile: configFile) variant.getDefaultValues(for: target.value).forEach { (key, value) in let stringContent = "\(key) = \(value)" logger.logDebug("Item: ", item: stringContent, indentationLevel: 1, color: .purple) @@ -197,22 +196,6 @@ class XCConfigFactory: XCFactory { xcodeFactory.modify(mainTargetSettings, in: projectPath, target: target.value) } - private func importPodsIfNeeded(target: NamedTarget, configFile: Path) { - guard StaticPath.Pod.podFileFile.exists else { return } - // this regex finds a folder that starts with Pods and ends with the target key, with a ".release.xcconfig" extension. - let podConfigFileRegex: String = "./Pods/Target Support Files/Pods.*-\(target.key)/.*\\.release\\.xcconfig" - guard let podsConfigFile: String = try? Bash("find | head -n 1", arguments: ".", "-regex", podConfigFileRegex).capture(), - !podsConfigFile.isEmpty else { - logger.logError("❌ ", item: "Failed to import Pods config in .xcconfig, Pod config file not found") - return - } - let includeStatement = "#include \"\(podsConfigFile)\"" - let (success, _) = write(includeStatement, toFile: configFile, force: false) - if !success { - logger.logError("❌ ", item: "Failed to add item to .xcconfig") - } - } - private func updateInfoPlist(with target: iOSTarget, configFile: Path, variant: iOSVariant) { let configFilePath = configFile.absolute().description do { diff --git a/docs/GITHUB_ACTION.md b/docs/GITHUB_ACTION.md index f0f5ca02..1aaf02dc 100644 --- a/docs/GITHUB_ACTION.md +++ b/docs/GITHUB_ACTION.md @@ -11,7 +11,7 @@ If Github Actions is your CI and you use the [Github-hosted macOS runner](https: ```yaml - uses: backbase/variants@main with: - version: 1.2.0 + version: 1.2.1 spec: variants.yml platform: ios variant: beta From 4ffd2305566959a9591389facd8ce416c10aeb1a Mon Sep 17 00:00:00 2001 From: Gabriel Minucci Date: Wed, 19 Feb 2025 13:08:39 +0100 Subject: [PATCH 3/3] chore: fix linting and tests --- .../Custom Types/Project/iOSProject.swift | 5 ----- .../Factory/iOS/XCConfigFactory.swift | 2 +- .../Factory/iOS/XcodeProjFactory.swift | 4 ---- .../Schemas/iOS/iOSConfiguration.swift | 2 -- .../VariantsCore/Schemas/iOS/iOSTarget.swift | 2 -- .../VariantsCore/Schemas/iOS/iOSVariant.swift | 17 +---------------- .../Mocks/MockXCodeConfigFactory.swift | 2 -- 7 files changed, 2 insertions(+), 32 deletions(-) diff --git a/Sources/VariantsCore/Custom Types/Project/iOSProject.swift b/Sources/VariantsCore/Custom Types/Project/iOSProject.swift index c7019183..fc2ecd7f 100644 --- a/Sources/VariantsCore/Custom Types/Project/iOSProject.swift +++ b/Sources/VariantsCore/Custom Types/Project/iOSProject.swift @@ -102,11 +102,6 @@ class iOSProject: Project { try parametersFactory.createMatchFile(for: variant, configuration: configuration) } - private func runPostSwitchScript(_ script: String) throws { - guard let outputString = try Bash("bash", arguments: "-c", script).capture() else { return } - Logger.shared.logInfo(item: outputString) - } - private func runPostSwitchScript(_ script: String) throws { guard let outputString = try Bash("bash", arguments: "-c", script).capture() else { return } Logger.shared.logInfo(item: outputString) diff --git a/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift b/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift index 0b42cffd..99327ae3 100644 --- a/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift +++ b/Sources/VariantsCore/Factory/iOS/XCConfigFactory.swift @@ -174,7 +174,7 @@ class XCConfigFactory: XCFactory { private func populateConfig(for target: iOSTarget, configFile: Path, variant: iOSVariant) { logger.logInfo("Populating: ", item: "'\(configFile.lastComponent)'") - variant.getDefaultValues(for: target.value).forEach { (key, value) in + variant.getDefaultValues(for: target).forEach { (key, value) in let stringContent = "\(key) = \(value)" logger.logDebug("Item: ", item: stringContent, indentationLevel: 1, color: .purple) diff --git a/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift b/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift index 1c4adb60..c29862dd 100644 --- a/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift +++ b/Sources/VariantsCore/Factory/iOS/XcodeProjFactory.swift @@ -5,8 +5,6 @@ // Created by Arthur Alves // -// swiftlint:disable file_length - import Foundation import XcodeProj import PathKit @@ -244,6 +242,4 @@ private extension XcodeProjFactory { break } } - // swiftlint:enable function_parameter_count } -// swiftlint:enable file_length diff --git a/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift b/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift index 9f9cfc94..54442778 100644 --- a/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift +++ b/Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift @@ -57,5 +57,3 @@ public struct iOSConfiguration: Codable { globalSigning: globalSigning, globalPostSwitchScript: globalPostSwitchScript) } } } - -// swiftlint:enable type_name diff --git a/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift b/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift index ce29784d..b1e9ff1e 100644 --- a/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift +++ b/Sources/VariantsCore/Schemas/iOS/iOSTarget.swift @@ -30,5 +30,3 @@ public struct iOSSource: Codable { let info: String let config: String } - -// swiftlint:enable type_name diff --git a/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift b/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift index e7dcebe2..636bf0cb 100644 --- a/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift +++ b/Sources/VariantsCore/Schemas/iOS/iOSVariant.swift @@ -109,12 +109,11 @@ public struct iOSVariant: Variant { } else if let base { return try base ~ nil } else { - Logger.shared.logWarning(item: + throw RuntimeError( """ Variant "\(name)" doesn't contain a 'signing' configuration. \ Create a global 'signing' configuration or make sure all variants have this property. """) - return nil } } @@ -136,18 +135,6 @@ public struct iOSVariant: Variant { } } - private static func parsePostSwitchScript(globalScript: String?, variantScript: String?) -> String? { - if let globalScript = globalScript, let variantScript = variantScript { - return "\(globalScript) && \(variantScript)" - } else if let globalScript = globalScript { - return globalScript - } else if let variantScript = variantScript { - return variantScript - } else { - return nil - } - } - private static func parseBundleConfiguration(name: String, idSuffix: String?, bundleID: String?) throws -> BundleNamingOption { guard name != "default" else { return .fromTarget } @@ -253,5 +240,3 @@ extension iOSVariant { variantPostSwitchScript: unnamediOSVariant.postSwitchScript) } } - -// swiftlint:enable type_name diff --git a/Tests/VariantsCoreTests/Mocks/MockXCodeConfigFactory.swift b/Tests/VariantsCoreTests/Mocks/MockXCodeConfigFactory.swift index 6e343694..b63f47c4 100644 --- a/Tests/VariantsCoreTests/Mocks/MockXCodeConfigFactory.swift +++ b/Tests/VariantsCoreTests/Mocks/MockXCodeConfigFactory.swift @@ -39,5 +39,3 @@ class MockXCodeConfigFactory: XCFactory { var xcconfigFileName: String = "variants.xcconfig" var logger: Logger } - -// swiftlint:enable colon