Class: FastlaneFlutterFlavor::YamlSpecLoader
- Inherits:
-
Object
- Object
- FastlaneFlutterFlavor::YamlSpecLoader
- Defined in:
- lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb
Constant Summary collapse
- STANDARD_BUILD_TYPES =
%w[debug release profile].freeze
Instance Method Summary collapse
-
#check_removed_firebase_fields(spec) ⇒ Object
Raises UI.user_error! if firebase_app_id or build_target are present in any iOS firebase block.
- #empty_defaults_for(platform) ⇒ Object
- #empty_flavor_for(platform) ⇒ Object
- #enabled? ⇒ Boolean
-
#get_api_key_path(platform, flavor_name) ⇒ String?
The API key path (platform-level credential for uploading to the store).
-
#get_apple_id(platform, flavor_name) ⇒ String?
The Apple ID (numeric) for the flavor from App Store stores config.
-
#get_auth_client_id(platform, flavor_name, build_config) ⇒ Object
For Google Sign-In (annai_auth).
- #get_auth_reversed_client_id(platform, flavor_name, build_config) ⇒ Object
-
#get_cloudflare_config(platform, flavor_name) ⇒ Hash
Returns the resolved Cloudflare config for a web flavor as a Hash with keys: project_name, account_id, branch, mode — cascaded flavor → default → hardcoded fallback.
-
#get_dart_defines_flags(platform, flavor_name, build_type = 'release') ⇒ Object
Merges common + compile-scoped dart_defines (compile wins on collision, per REQ-DDEF-00015) into individual --dart-define=KEY=VALUE flags for
flutter build. -
#get_display_name(platform, flavor_name) ⇒ String?
The merged app name.
-
#get_effective_id(platform, flavor_name, build_type) ⇒ Object
For AdMob (annai_ads) Returns the full app ID for a specific build type, applying build_types.id_suffix.
-
#get_effective_name(platform, flavor_name, build_type) ⇒ Object
Returns the full display name for a specific build type, applying build_types.name_suffix.
-
#get_export_option_file(platform, flavor_name) ⇒ String?
The export options plist path (inside default.credentials.app_store).
-
#get_firebase_project_id(platform, flavor_name, build_config) ⇒ String?
The Firebase Project ID.
-
#get_flavor_name(platform, flavor_name) ⇒ String?
The flavor name (just for consistency with other getters).
- #get_gms_ads_id(platform, flavor_name) ⇒ Object
-
#get_main_file(platform, flavor_name) ⇒ String?
The path to the main Dart file.
-
#get_package_id(platform, flavor_name, build_type = 'release') ⇒ String?
The merged package ID (bundle ID or application ID) for the given build type.
-
#get_platform_flavors(platform) ⇒ Hash
Retrieves the hash of all defined flavors for a given platform.
-
#get_priority(platform, flavor_name) ⇒ String?
The Google Play update priority for the flavor.
-
#get_service_account(platform, flavor_name, build_config) ⇒ String?
Returns the resolved service_account path for the given platform/flavor/build_config, cascading through the core's full 4-level resolution: flavor.build_types.firebase.service_account (most specific) flavor.firebase.service_account default.build_types.firebase.service_account default.firebase.service_account (least specific) Corrected via ADR-008/REQ-CDEL-00060 — the pre-delegation implementation only checked the first and third levels, silently skipping the flavor-top-level and default-top-level fallbacks.
-
#get_team_id(platform, flavor_name) ⇒ String?
The Apple Team ID for the flavor (flavor-level credentials override, falls back to default).
-
#get_version_code(platform, flavor_name) ⇒ String?
The path to the version_code.
-
#get_version_name(platform, flavor_name) ⇒ String?
The merged version name.
-
#initialize(root_folder, file_path) ⇒ YamlSpecLoader
constructor
Initialize the loader with the project root folder context and load the spec file.
-
#load_file ⇒ AnnFlavorCore::AnnSpec?
Loads and parses annspec.yaml via the shared core (ADR-008) — the single source of truth for parsing, cascade merging, and resolution.
-
#platform_flavor_and_defaults(platform, flavor_name) ⇒ Object
Returns the [flavor, defaults] structs for a platform, or nil if the platform/flavor cannot be resolved.
- #platform_for(spec, platform) ⇒ Object
-
#resolve(platform, flavor_name, build_type) ⇒ Object
Resolves a flavor against a build type via the core resolver.
Constructor Details
#initialize(root_folder, file_path) ⇒ YamlSpecLoader
Initialize the loader with the project root folder context and load the spec file.
13 14 15 16 17 18 19 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 13 def initialize(root_folder, file_path) @root_folder = root_folder @file_path = file_path # The file path, potentially overridden by ENV outside this class # Load the file content immediately and store it @spec = load_file end |
Instance Method Details
#check_removed_firebase_fields(spec) ⇒ Object
Raises UI.user_error! if firebase_app_id or build_target are present in any iOS firebase block. Both fields were removed — they are derived automatically now. The core's model has no fields for them at all, so this reads the raw YAML directly (a narrow, deliberate exception to delegation — it is a migration guard, not spec parsing/merging/resolution, per ADR-008).
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 48 def check_removed_firebase_fields(spec) full_path = File.(@file_path, @root_folder) raw = YAML.safe_load(File.read(full_path), aliases: true) || {} ios_app = raw.dig('app', 'ios') return unless ios_app.is_a?(Hash) sections = {} sections['ios.default'] = ios_app.dig('default') || {} flavors = ios_app.dig('flavor') || {} flavors.each do |flavor_key, flavor_data| sections["ios.flavor.#{flavor_key}"] = flavor_data || {} end sections.each do |section_path, section_data| build_types = section_data.dig('build_types') || {} build_types.each do |bt_key, bt_data| next unless bt_data.is_a?(Hash) firebase_block = bt_data.dig('firebase') || {} next unless firebase_block.is_a?(Hash) if firebase_block.key?('firebase_app_id') Fastlane::UI.user_error!( "[#{section_path}/#{bt_key}] `firebase_app_id` is no longer supported in annspec.yaml. " \ "Remove it — GOOGLE_APP_ID is now read from the generated firebase_options dart file." ) end if firebase_block.key?('build_target') Fastlane::UI.user_error!( "[#{section_path}/#{bt_key}] `build_target` is no longer supported in annspec.yaml. " \ "Remove it — the Xcode build target is derived automatically as " \ "'#{bt_key.to_s.capitalize}-#{section_path.split('.').last}'." ) end end end end |
#empty_defaults_for(platform) ⇒ Object
142 143 144 145 146 147 148 149 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 142 def empty_defaults_for(platform) case platform.to_s when 'android' then AnnFlavorCore::AndroidDefault.defaults when 'ios' then AnnFlavorCore::IosDefault.defaults when 'web' then AnnFlavorCore::WebDefault.defaults when 'windows' then AnnFlavorCore::WindowsDefault.defaults end end |
#empty_flavor_for(platform) ⇒ Object
133 134 135 136 137 138 139 140 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 133 def empty_flavor_for(platform) case platform.to_s when 'android' then AnnFlavorCore::AndroidFlavor.defaults when 'ios' then AnnFlavorCore::IosFlavor.defaults when 'web' then AnnFlavorCore::WebFlavor.defaults when 'windows' then AnnFlavorCore::WindowsFlavor.defaults end end |
#enabled? ⇒ Boolean
87 88 89 90 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 87 def enabled? return false unless @spec @spec.enabled != false end |
#get_api_key_path(platform, flavor_name) ⇒ String?
Returns The API key path (platform-level credential for uploading to the store).
224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 224 def get_api_key_path(platform, flavor_name) return nil unless @spec platform_data = platform_for(@spec, platform) return nil unless platform_data case platform.to_s when 'android' platform_data.default&.credentials&.google_play&.api_key when 'ios' platform_data.default&.credentials&.app_store&.api_key end end |
#get_apple_id(platform, flavor_name) ⇒ String?
Returns The Apple ID (numeric) for the flavor from App Store stores config.
216 217 218 219 220 221 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 216 def get_apple_id(platform, flavor_name) pair = platform_flavor_and_defaults(platform, flavor_name) return nil unless pair flavor, = pair flavor&.stores&.app_store&.apple_id end |
#get_auth_client_id(platform, flavor_name, build_config) ⇒ Object
For Google Sign-In (annai_auth)
323 324 325 326 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 323 def get_auth_client_id(platform, flavor_name, build_config) resolved = resolve(platform, flavor_name, build_config) resolved&.effective_auth&.client_id end |
#get_auth_reversed_client_id(platform, flavor_name, build_config) ⇒ Object
328 329 330 331 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 328 def get_auth_reversed_client_id(platform, flavor_name, build_config) resolved = resolve(platform, flavor_name, build_config) resolved&.effective_auth&.reversed_client_id end |
#get_cloudflare_config(platform, flavor_name) ⇒ Hash
Returns the resolved Cloudflare config for a web flavor as a Hash with keys: project_name, account_id, branch, mode — cascaded flavor → default → hardcoded fallback.
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 306 def get_cloudflare_config(platform, flavor_name) return {} unless @spec return {} unless platform.to_s == 'web' resolved = resolve(platform, flavor_name, 'release') cf = resolved&.effective_cloudflare return {} unless cf { 'project_name' => cf.project_name, 'account_id' => cf.account_id, 'branch' => cf.branch, 'mode' => cf.mode, } end |
#get_dart_defines_flags(platform, flavor_name, build_type = 'release') ⇒ Object
Merges common + compile-scoped dart_defines (compile wins on collision,
per REQ-DDEF-00015) into individual --dart-define=KEY=VALUE flags for
flutter build. Returns [] when there's nothing to emit. Returned as
separate array elements (not a single joined string) so callers can pass
them straight through to Fastlane::Actions.sh's argv-array form without
each flag being treated as one combined shell argument.
REQ-DDEF-00040's default-only scoping decision applies here too:
resolve folds flavor-level overrides in via the core's 4-level cascade,
so a flavor with its own dart_defines still resolves correctly per call —
unlike the (now-removed) generated-Fastfile-lane version, which could
only represent default-level dart_defines since it was a single static
lane shared across every flavor.
346 347 348 349 350 351 352 353 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 346 def get_dart_defines_flags(platform, flavor_name, build_type = 'release') resolved = resolve(platform, flavor_name, build_type) defines = resolved&.effective_dart_defines return [] unless defines merged = (defines.common || {}).merge(defines.compile || {}) merged.map { |k, v| "--dart-define=#{k}=#{v}" } end |
#get_display_name(platform, flavor_name) ⇒ String?
Returns The merged app name.
183 184 185 186 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 183 def get_display_name(platform, flavor_name) resolved = resolve(platform, flavor_name, 'release') resolved&.effective_name end |
#get_effective_id(platform, flavor_name, build_type) ⇒ Object
For AdMob (annai_ads) Returns the full app ID for a specific build type, applying build_types.id_suffix.
287 288 289 290 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 287 def get_effective_id(platform, flavor_name, build_type) resolved = resolve(platform, flavor_name, build_type) resolved&.effective_id end |
#get_effective_name(platform, flavor_name, build_type) ⇒ Object
Returns the full display name for a specific build type, applying build_types.name_suffix.
293 294 295 296 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 293 def get_effective_name(platform, flavor_name, build_type) resolved = resolve(platform, flavor_name, build_type) resolved&.effective_name end |
#get_export_option_file(platform, flavor_name) ⇒ String?
Returns The export options plist path (inside default.credentials.app_store).
239 240 241 242 243 244 245 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 239 def get_export_option_file(platform, flavor_name) return nil unless @spec return nil unless platform.to_s == 'ios' ios = @spec.app&.ios ios&.default&.credentials&.app_store&. end |
#get_firebase_project_id(platform, flavor_name, build_config) ⇒ String?
Returns The Firebase Project ID.
262 263 264 265 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 262 def get_firebase_project_id(platform, flavor_name, build_config) resolved = resolve(platform, flavor_name, build_config) resolved&.effective_firebase&.project_id end |
#get_flavor_name(platform, flavor_name) ⇒ String?
Returns The flavor name (just for consistency with other getters).
167 168 169 170 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 167 def get_flavor_name(platform, flavor_name) pair = platform_flavor_and_defaults(platform, flavor_name) pair ? flavor_name.to_s : nil end |
#get_gms_ads_id(platform, flavor_name) ⇒ Object
298 299 300 301 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 298 def get_gms_ads_id(platform, flavor_name) resolved = resolve(platform, flavor_name, 'release') resolved&.effective_gms_ads_id end |
#get_main_file(platform, flavor_name) ⇒ String?
Returns The path to the main Dart file.
202 203 204 205 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 202 def get_main_file(platform, flavor_name) resolved = resolve(platform, flavor_name, 'release') resolved&.effective_main_file end |
#get_package_id(platform, flavor_name, build_type = 'release') ⇒ String?
Returns The merged package ID (bundle ID or application ID) for the given build type. Was previously hardcoded to 'release' regardless of the caller's actual build — corrected via plan-030 Phase 6 / REQ-CDEL-00070 (PodspecBridge#bundle_id now threads its real @build_type through instead of relying on this default).
177 178 179 180 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 177 def get_package_id(platform, flavor_name, build_type = 'release') resolved = resolve(platform, flavor_name, build_type) resolved&.effective_id end |
#get_platform_flavors(platform) ⇒ Hash
Retrieves the hash of all defined flavors for a given platform.
158 159 160 161 162 163 164 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 158 def get_platform_flavors(platform) return {} unless @spec && enabled? platform_data = platform_for(@spec, platform) return {} if platform_data.nil? platform_data.flavors end |
#get_priority(platform, flavor_name) ⇒ String?
Returns The Google Play update priority for the flavor.
208 209 210 211 212 213 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 208 def get_priority(platform, flavor_name) pair = platform_flavor_and_defaults(platform, flavor_name) return nil unless pair flavor, = pair flavor&.stores&.google_play&.priority end |
#get_service_account(platform, flavor_name, build_config) ⇒ String?
Returns the resolved service_account path for the given platform/flavor/build_config, cascading through the core's full 4-level resolution:
flavor.build_types[bt].firebase.service_account (most specific)
flavor.firebase.service_account
default.build_types[bt].firebase.service_account
default.firebase.service_account (least specific)
Corrected via ADR-008/REQ-CDEL-00060 — the pre-delegation implementation only checked the first and third levels, silently skipping the flavor-top-level and default-top-level fallbacks.
277 278 279 280 281 282 283 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 277 def get_service_account(platform, flavor_name, build_config) resolved = resolve(platform, flavor_name, build_config) path = resolved&.effective_firebase&.service_account return nil if path.nil? || path.empty? File.(path, @root_folder) end |
#get_team_id(platform, flavor_name) ⇒ String?
Returns The Apple Team ID for the flavor (flavor-level credentials override, falls back to default).
248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 248 def get_team_id(platform, flavor_name) return nil unless @spec return nil unless platform.to_s == 'ios' ios = @spec.app&.ios return nil unless ios flavor_team_id = ios.flavors[flavor_name.to_s]&.credentials&.signing&.team_id return flavor_team_id if flavor_team_id && !flavor_team_id.empty? ios.default&.credentials&.signing&.team_id end |
#get_version_code(platform, flavor_name) ⇒ String?
Returns The path to the version_code.
195 196 197 198 199 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 195 def get_version_code(platform, flavor_name) resolved = resolve(platform, flavor_name, 'release') return nil unless resolved resolved.effective_version_code.to_i.to_s end |
#get_version_name(platform, flavor_name) ⇒ String?
Returns The merged version name.
189 190 191 192 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 189 def get_version_name(platform, flavor_name) resolved = resolve(platform, flavor_name, 'release') resolved&.effective_version_name end |
#load_file ⇒ AnnFlavorCore::AnnSpec?
Loads and parses annspec.yaml via the shared core (ADR-008) — the single source of truth for parsing, cascade merging, and resolution.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 24 def load_file begin # Ensure the file path is resolved relative to the project root full_path = File.(@file_path, @root_folder) Fastlane::UI.verbose("Reading Annai spec from: #{full_path}") spec = AnnFlavorCore::Parser.parse_file(full_path) check_removed_firebase_fields(spec) return spec rescue Fastlane::Shell::ShellError => e raise e rescue => e # Use @file_path for reporting the error path Fastlane::UI.error("Failed to load or parse annai spec YAML file at #{@file_path}: #{e.}") return nil end end |
#platform_flavor_and_defaults(platform, flavor_name) ⇒ Object
Returns the [flavor, defaults] structs for a platform, or nil if the platform/flavor cannot be resolved.
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 94 def platform_flavor_and_defaults(platform, flavor_name) return nil unless @spec && enabled? platform_data = platform_for(@spec, platform) return nil if platform_data.nil? flavor = platform_data.flavors[flavor_name.to_s] return nil if flavor.nil? && platform_data.default.nil? [flavor, platform_data.default] end |
#platform_for(spec, platform) ⇒ Object
106 107 108 109 110 111 112 113 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 106 def platform_for(spec, platform) case platform.to_s when 'android' then spec.app&.android when 'ios' then spec.app&.ios when 'web' then spec.app&.web when 'windows' then spec.app&.windows end end |
#resolve(platform, flavor_name, build_type) ⇒ Object
Resolves a flavor against a build type via the core resolver. Returns nil when the platform/flavor cannot be resolved.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/utils_spec_loader.rb', line 117 def resolve(platform, flavor_name, build_type) pair = platform_flavor_and_defaults(platform, flavor_name) return nil if pair.nil? flavor, defaults = pair flavor ||= empty_flavor_for(platform) defaults ||= empty_defaults_for(platform) case platform.to_s when 'android' then AnnFlavorCore::Resolver.resolve_android_flavor(flavor, defaults, build_type.to_s) when 'ios' then AnnFlavorCore::Resolver.resolve_ios_flavor(flavor, defaults, build_type.to_s) when 'web' then AnnFlavorCore::Resolver.resolve_web_flavor(flavor, defaults, build_type.to_s) when 'windows' then AnnFlavorCore::Resolver.resolve_windows_flavor(flavor, defaults, build_type.to_s) end end |