From 389380d6ac3feeea23addf6bbca534727aceb080 Mon Sep 17 00:00:00 2001 From: Pietro Caselani Date: Tue, 2 Jul 2019 09:08:07 -0300 Subject: [PATCH 1/5] Create a simple lane to setup certificates --- fastlane/Fastfile | 11 ++++++++--- fastlane/README.md | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 3e1f3c7c..9bf3c8ec 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -9,9 +9,8 @@ platform :ios do secrets_param = branch == 'master' ? '' : 'empty' sh("../scripts/generate_secrets #{secrets_param}", log: false) - sh('cd .. && tuist generate') - - pods + # sh('cd .. && tuist generate') + # pods end desc 'Run bundle exec pod install --repo-update' @@ -19,6 +18,12 @@ platform :ios do cocoapods(podfile: '.', repo_update: false) end + desc 'Setup Certificates' + lane :setup_certs do + match(type: 'development') + match(type: 'appstore') + end + desc 'Run CouchTrackerCore tests' lane :tests do run_tests_for_scheme(scheme: 'TVDBSwiftTests') diff --git a/fastlane/README.md b/fastlane/README.md index c8ff12ce..3405ba76 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -21,6 +21,11 @@ or alternatively using `brew cask install fastlane` fastlane ios pods ``` Run bundle exec pod install --repo-update +### ios setup_certs +``` +fastlane ios setup_certs +``` +Setup Certificates ### ios tests ``` fastlane ios tests From 9e3f06676db5d566363eca60f16214bdcd5c71a9 Mon Sep 17 00:00:00 2001 From: Pietro Caselani Date: Tue, 2 Jul 2019 09:08:32 -0300 Subject: [PATCH 2/5] Adding Sourcery to create enum properties and more --- .sourcery.yml | 5 ++++ Brewfile | 3 +- .../CodeGeneration/EnumPoetry.swift | 5 ++++ .../MovieDetails/MovieDetailsViewState.swift | 2 +- .../Manager/MoviesManagerViewState.swift | 9 +++++- SourceryTemplates/EnumClosures.stencil | 24 +++++++++++++++ SourceryTemplates/EnumProperties.stencil | 26 ++++++++++++++++ SourceryTemplates/EnumTypes.stencil | 30 +++++++++++++++++++ scripts/codegeneration | 13 ++++++++ 9 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 .sourcery.yml create mode 100644 CouchTrackerCore/CodeGeneration/EnumPoetry.swift create mode 100644 SourceryTemplates/EnumClosures.stencil create mode 100644 SourceryTemplates/EnumProperties.stencil create mode 100644 SourceryTemplates/EnumTypes.stencil create mode 100755 scripts/codegeneration diff --git a/.sourcery.yml b/.sourcery.yml new file mode 100644 index 00000000..e04a82c9 --- /dev/null +++ b/.sourcery.yml @@ -0,0 +1,5 @@ +sources: + - CouchTrackerCore +templates: + - SourceryTemplates +output: CouchTrackerCore/CodeGenerated diff --git a/Brewfile b/Brewfile index e478fe3d..b0d175b4 100644 --- a/Brewfile +++ b/Brewfile @@ -1,5 +1,6 @@ tap 'blender/homebrew-tap' -brew 'rome' + +brew 'sourcery' brew 'swiftlint' brew 'sonar-scanner' brew 'tailor' diff --git a/CouchTrackerCore/CodeGeneration/EnumPoetry.swift b/CouchTrackerCore/CodeGeneration/EnumPoetry.swift new file mode 100644 index 00000000..591dec42 --- /dev/null +++ b/CouchTrackerCore/CodeGeneration/EnumPoetry.swift @@ -0,0 +1,5 @@ +public protocol EnumClosures {} + +public protocol EnumProperties {} + +public protocol EnumPoetry: EnumClosures, EnumProperties {} diff --git a/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift b/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift index 6a60926a..af5caa78 100644 --- a/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift +++ b/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift @@ -1,4 +1,4 @@ -public enum MovieDetailsViewState: Hashable { +public enum MovieDetailsViewState: Hashable, EnumPoetry { case loading case showing(movie: MovieEntity) case error(error: Error) diff --git a/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift b/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift index c450490a..77bc605d 100644 --- a/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift +++ b/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift @@ -1,4 +1,11 @@ -public enum MoviesManagerViewState: Hashable { +public enum MoviesManagerViewState: Hashable, EnumPoetry { case loading case showing(pages: [ModulePage], selectedIndex: Int) } + +extension MoviesManagerViewState { + var showing: (pages: [ModulePage], selectedIndex: Int)? { + guard case let .showing(pages, x) = self else { return nil } + return (pages: pages, selectedIndex: x) + } +} diff --git a/SourceryTemplates/EnumClosures.stencil b/SourceryTemplates/EnumClosures.stencil new file mode 100644 index 00000000..16757ab4 --- /dev/null +++ b/SourceryTemplates/EnumClosures.stencil @@ -0,0 +1,24 @@ +{% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} + +{% macro associatedValueTypes associatedValues %}{% for associatedValue in associatedValues %}{% if forloop.first %}{{ associatedValue.typeName }}{% else %}, {{ associatedValue.typeName }}{% endif %}{% endfor %}{% endmacro %} +{% macro associatedValueNames associatedValues %}{% for associatedValue in case.associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} + +// MARK: - EnumClosures + +{% for enum in types.enums where enum.implements.EnumClosures %} +extension {{ enum.name }} { + {% for case in enum.cases %} + {% if case.hasAssociatedValue %} + {{ enum.accessLevel }} func on{{ case.name|capitalize }}(_ fn: ({% call associatedValueTypes case.associatedValues %}) -> Void) { + guard case let .{{ case.name }}({% call associatedValueNames case.associatedValues %}) = self else { return } + fn({% call associatedValueNames case.associatedValues %}) + } + {% else %} + {{ enum.accessLevel }} func on{{ case.name|capitalize }}(_ fn: () -> Void) { + guard case .{{ case.name }} = self else { return } + fn() + } + {% endif %} + {% endfor %} +} +{% endfor %} diff --git a/SourceryTemplates/EnumProperties.stencil b/SourceryTemplates/EnumProperties.stencil new file mode 100644 index 00000000..23e164bf --- /dev/null +++ b/SourceryTemplates/EnumProperties.stencil @@ -0,0 +1,26 @@ +{% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} + +{% macro associatedValueTypes associatedValues %}{% for associatedValue in associatedValues %}{% if forloop.first %}{{ associatedValue.typeName }}{% else %}, {{ associatedValue.typeName }}{% endif %}{% endfor %}{% endmacro %} +{% macro associatedValueNames associatedValues %}{% for associatedValue in case.associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} + +// MARK: - EnumProperties + +{% for enum in types.enums where enum.implements.EnumProperties %} +extension {{ enum.name }} { + {% for case in enum.cases %} + {{ enum.accessLevel }} var is{{ case.name|capitalize }}: Bool { + guard case .{{ case.name }} = self else { return false } + return true + } + {% endfor %} + + {% for case in enum.cases %} + {% if case.hasAssociatedValue %} + {{ enum.accessLevel }} var {{ case.name }}: ({% call associatedValueTypes case.associatedValues %})? { + guard case let .{{ case.name }}({% call associatedValueNames case.associatedValues %}) = self else { return nil } + return ({% call associatedValueNames case.associatedValues %}) + } + {% endif %} + {% endfor %} +} +{% endfor %} diff --git a/SourceryTemplates/EnumTypes.stencil b/SourceryTemplates/EnumTypes.stencil new file mode 100644 index 00000000..130095b2 --- /dev/null +++ b/SourceryTemplates/EnumTypes.stencil @@ -0,0 +1,30 @@ +{% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} + +{% macro associatedValueTypes associatedValues %}{% for associatedValue in associatedValues %}{% if forloop.first %}{{ associatedValue.typeName }}{% else %}, {{ associatedValue.typeName }}{% endif %}{% endfor %}{% endmacro %} +{% macro associatedValueNames associatedValues %}{% for associatedValue in case.associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} + +{% macro associatedTypeAsTuple associatedValues %} +{% if associatedValues.count == 1 %} + {{ associatedValue.typeName }} +{% else %} + {% for associatedValue in associatedValues %} + {% if forloop.first %} + {% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }} + {% else %} + , {% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }} + {% endif %} + {% endfor %} +{% endif %} +{% endmacro %} + +// MARK: - EnumClosures + +{% for enum in types.enums where enum.implements.EnumClosures %} +extension {{ enum.name }} { + {% for case in enum.cases %} + {% if case.hasAssociatedValue %} + // Case: {{ case.name }} ({% call associatedTypeAsTuple case.associatedValues %})? + {% endif %} + {% endfor %} +} +{% endfor %} diff --git a/scripts/codegeneration b/scripts/codegeneration new file mode 100755 index 00000000..8ca92411 --- /dev/null +++ b/scripts/codegeneration @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$(echo "${BASH_SOURCE[0]}" | xargs dirname | xargs -I % sh -c 'cd % && pwd') +PROJECT_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) + +cd "${PROJECT_ROOT}" || exit 1 + +COUCH_TRACKER_CORE_DIR="${PROJECT_ROOT}/CouchTrackerCore" + +TEMPLATES_DIR="${PROJECT_ROOT}/SourceryTemplates" +OUTPUT_DIR="${COUCH_TRACKER_CORE_DIR}/CodeGenerated" + +sourcery --templates ${TEMPLATES_DIR} --output ${OUTPUT_DIR} --sources ${COUCH_TRACKER_CORE_DIR} From 92ac97685455ad2827b483ddd42c5a7fbd430a79 Mon Sep 17 00:00:00 2001 From: Pietro Caselani Date: Tue, 2 Jul 2019 15:44:18 -0300 Subject: [PATCH 3/5] Generating properties and closures for enums --- .../CodeGeneration/EnumClosures.swift | 31 ++++++++++++++ .../CodeGeneration/EnumPoetry.swift | 5 +-- .../CodeGeneration/EnumProperties.swift | 40 +++++++++++++++++++ .../Manager/MoviesManagerViewState.swift | 7 ---- SourceryTemplates/EnumClosures.stencil | 2 - SourceryTemplates/EnumProperties.stencil | 6 +-- SourceryTemplates/EnumTypes.stencil | 30 -------------- 7 files changed, 74 insertions(+), 47 deletions(-) create mode 100644 CouchTrackerCore/CodeGeneration/EnumClosures.swift create mode 100644 CouchTrackerCore/CodeGeneration/EnumProperties.swift delete mode 100644 SourceryTemplates/EnumTypes.stencil diff --git a/CouchTrackerCore/CodeGeneration/EnumClosures.swift b/CouchTrackerCore/CodeGeneration/EnumClosures.swift new file mode 100644 index 00000000..776858b1 --- /dev/null +++ b/CouchTrackerCore/CodeGeneration/EnumClosures.swift @@ -0,0 +1,31 @@ +/* + Given the following enum + + ``` + enum ViewState: EnumClosures { + case start(data: T) + case loading + case completed(count: Int, message: String) +} + ``` + + will generate the following code + + ``` + extension ViewState { + internal func onStart(_ fn: (T) -> Void) { + guard case let .start(data) = self else { return } + fn(data) + } + internal func onLoading(_ fn: () -> Void) { + guard case .loading = self else { return } + fn() + } + internal func onCompleted(_ fn: (Int, String) -> Void) { + guard case let .completed(count, message) = self else { return } + fn(count, message) + } +} + ``` + */ +public protocol EnumClosures {} diff --git a/CouchTrackerCore/CodeGeneration/EnumPoetry.swift b/CouchTrackerCore/CodeGeneration/EnumPoetry.swift index 591dec42..1015b794 100644 --- a/CouchTrackerCore/CodeGeneration/EnumPoetry.swift +++ b/CouchTrackerCore/CodeGeneration/EnumPoetry.swift @@ -1,5 +1,2 @@ -public protocol EnumClosures {} - -public protocol EnumProperties {} - +// See `EnumClosures` and `EnumProperties` public protocol EnumPoetry: EnumClosures, EnumProperties {} diff --git a/CouchTrackerCore/CodeGeneration/EnumProperties.swift b/CouchTrackerCore/CodeGeneration/EnumProperties.swift new file mode 100644 index 00000000..fa435f25 --- /dev/null +++ b/CouchTrackerCore/CodeGeneration/EnumProperties.swift @@ -0,0 +1,40 @@ +/* + Given the following enum + + ``` + enum ViewState: EnumProperties { + case start(T) + case loading + case completed(Int, String) + } + ``` + + will generate the following code + + ``` +extension ViewState { + internal var isStart: Bool { + guard case .start = self else { return false } + return true + } + internal var isLoading: Bool { + guard case .loading = self else { return false } + return true + } + internal var isCompleted: Bool { + guard case .completed = self else { return false } + return true + } + + internal var start: T? { + guard case let .start(data) = self else { return nil } + return (data) + } + internal var completed: (count: Int, message: String)? { + guard case let .completed(count, message) = self else { return nil } + return (count, message) + } +} + ``` + */ +public protocol EnumProperties {} diff --git a/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift b/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift index 77bc605d..c02baedc 100644 --- a/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift +++ b/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift @@ -2,10 +2,3 @@ public enum MoviesManagerViewState: Hashable, EnumPoetry { case loading case showing(pages: [ModulePage], selectedIndex: Int) } - -extension MoviesManagerViewState { - var showing: (pages: [ModulePage], selectedIndex: Int)? { - guard case let .showing(pages, x) = self else { return nil } - return (pages: pages, selectedIndex: x) - } -} diff --git a/SourceryTemplates/EnumClosures.stencil b/SourceryTemplates/EnumClosures.stencil index 16757ab4..2a39141b 100644 --- a/SourceryTemplates/EnumClosures.stencil +++ b/SourceryTemplates/EnumClosures.stencil @@ -1,8 +1,6 @@ {% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} - {% macro associatedValueTypes associatedValues %}{% for associatedValue in associatedValues %}{% if forloop.first %}{{ associatedValue.typeName }}{% else %}, {{ associatedValue.typeName }}{% endif %}{% endfor %}{% endmacro %} {% macro associatedValueNames associatedValues %}{% for associatedValue in case.associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} - // MARK: - EnumClosures {% for enum in types.enums where enum.implements.EnumClosures %} diff --git a/SourceryTemplates/EnumProperties.stencil b/SourceryTemplates/EnumProperties.stencil index 23e164bf..05a97bfa 100644 --- a/SourceryTemplates/EnumProperties.stencil +++ b/SourceryTemplates/EnumProperties.stencil @@ -1,8 +1,7 @@ {% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} - {% macro associatedValueTypes associatedValues %}{% for associatedValue in associatedValues %}{% if forloop.first %}{{ associatedValue.typeName }}{% else %}, {{ associatedValue.typeName }}{% endif %}{% endfor %}{% endmacro %} {% macro associatedValueNames associatedValues %}{% for associatedValue in case.associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} - +{% macro associatedTypeAsTuple associatedValues %}{% if associatedValues.count == 1 %}{{ associatedValues[0].typeName }}{% else %}({% for associatedValue in associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }}{% else %}, {% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }}{% endif %}{% endfor %}){% endif %}{% endmacro %} // MARK: - EnumProperties {% for enum in types.enums where enum.implements.EnumProperties %} @@ -13,10 +12,9 @@ extension {{ enum.name }} { return true } {% endfor %} - {% for case in enum.cases %} {% if case.hasAssociatedValue %} - {{ enum.accessLevel }} var {{ case.name }}: ({% call associatedValueTypes case.associatedValues %})? { + {{ enum.accessLevel }} var {{ case.name }}: {% call associatedTypeAsTuple case.associatedValues %}? { guard case let .{{ case.name }}({% call associatedValueNames case.associatedValues %}) = self else { return nil } return ({% call associatedValueNames case.associatedValues %}) } diff --git a/SourceryTemplates/EnumTypes.stencil b/SourceryTemplates/EnumTypes.stencil deleted file mode 100644 index 130095b2..00000000 --- a/SourceryTemplates/EnumTypes.stencil +++ /dev/null @@ -1,30 +0,0 @@ -{% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} - -{% macro associatedValueTypes associatedValues %}{% for associatedValue in associatedValues %}{% if forloop.first %}{{ associatedValue.typeName }}{% else %}, {{ associatedValue.typeName }}{% endif %}{% endfor %}{% endmacro %} -{% macro associatedValueNames associatedValues %}{% for associatedValue in case.associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} - -{% macro associatedTypeAsTuple associatedValues %} -{% if associatedValues.count == 1 %} - {{ associatedValue.typeName }} -{% else %} - {% for associatedValue in associatedValues %} - {% if forloop.first %} - {% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }} - {% else %} - , {% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }} - {% endif %} - {% endfor %} -{% endif %} -{% endmacro %} - -// MARK: - EnumClosures - -{% for enum in types.enums where enum.implements.EnumClosures %} -extension {{ enum.name }} { - {% for case in enum.cases %} - {% if case.hasAssociatedValue %} - // Case: {{ case.name }} ({% call associatedTypeAsTuple case.associatedValues %})? - {% endif %} - {% endfor %} -} -{% endfor %} From 8a7b152991641283b64b44c7c33b04da37944875 Mon Sep 17 00:00:00 2001 From: Pietro Caselani Date: Tue, 2 Jul 2019 15:45:36 -0300 Subject: [PATCH 4/5] Remove unused code to generate swift code --- scripts/codegeneration | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/scripts/codegeneration b/scripts/codegeneration index 8ca92411..7c9788c0 100755 --- a/scripts/codegeneration +++ b/scripts/codegeneration @@ -1,13 +1,3 @@ #!/usr/bin/env bash -SCRIPT_DIR=$(echo "${BASH_SOURCE[0]}" | xargs dirname | xargs -I % sh -c 'cd % && pwd') -PROJECT_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) - -cd "${PROJECT_ROOT}" || exit 1 - -COUCH_TRACKER_CORE_DIR="${PROJECT_ROOT}/CouchTrackerCore" - -TEMPLATES_DIR="${PROJECT_ROOT}/SourceryTemplates" -OUTPUT_DIR="${COUCH_TRACKER_CORE_DIR}/CodeGenerated" - -sourcery --templates ${TEMPLATES_DIR} --output ${OUTPUT_DIR} --sources ${COUCH_TRACKER_CORE_DIR} +sourcery From df7a0467a4370c38d0921331959b96179f056c74 Mon Sep 17 00:00:00 2001 From: Pietro Caselani Date: Tue, 2 Jul 2019 15:53:53 -0300 Subject: [PATCH 5/5] We need to generate the project and run cocoapods always --- fastlane/Fastfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 9bf3c8ec..146b1dda 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -9,8 +9,8 @@ platform :ios do secrets_param = branch == 'master' ? '' : 'empty' sh("../scripts/generate_secrets #{secrets_param}", log: false) - # sh('cd .. && tuist generate') - # pods + sh('cd .. && tuist generate') + pods end desc 'Run bundle exec pod install --repo-update'