fastlane-plugin-branch 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 71452d61b439b4f695f7d2098ea5eafba48fd3fe
4
- data.tar.gz: 8ff31c8f5005e6941352e6edffb6dbb8103bf3e4
3
+ metadata.gz: '08822a6026ae8a7f5a990080ddc64e537713d705'
4
+ data.tar.gz: bd5ae339f360d756004bb6e746c46543c0ebf09a
5
5
  SHA512:
6
- metadata.gz: 73026e1c972b2de5c44a504f6c84caf8eebf96546f5de2e8e619c7a346ed0fc695b48aa2d9ac802ffa519bc4b4148d6caa9a2913a568095fa5d1f2a78a3fcba0
7
- data.tar.gz: 1dfad69799475b92c931a24fcc3a9092830f7a0343ee23a2e6184428a88b9f16631eca3758685c000faa112d2316013c05abb256a5b13b512347e51d2cbc88d1
6
+ metadata.gz: 4768a177e965e307358b31fba008a73f1f3b136a81585039372982331521a23c75f9d89d799c68ce44f89bad375d3d822d2d34b8c944f34660d7f581ef231b4d
7
+ data.tar.gz: 2bb0ba13f14c4121aec797867a7b1193cfc30a552bec22fd268ea1e0aba9dad5db35bef92b9c1a15d1bf0f20a15110f363dc96db63d3999c641ce1307ce03e14
data/README.md CHANGED
@@ -34,6 +34,8 @@ for help getting started.
34
34
 
35
35
  ## setup_branch action
36
36
 
37
+ ![Branch plugin](./assets/branch_plugin.gif)
38
+
37
39
  ### Prerequisites
38
40
 
39
41
  Before using this action, make sure to set up your app in the [Branch Dashboard](https://dashboard.branch.io). See https://docs.branch.io/pages/dashboard/integrate/ for details. To use the `setup_branch` action, you need:
@@ -48,6 +50,26 @@ Before using this action, make sure to set up your app in the [Branch Dashboard]
48
50
  This action automatically configures Xcode and Android projects that use the Branch SDK
49
51
  for Universal Links, App Links and custom URI handling. It modifies Xcode project settings and entitlements as well as Info.plist and AndroidManifest.xml files.
50
52
 
53
+ For iOS projects, if a Podfile is detected, and the Podfile does not already contain
54
+ the Branch pod, the pod will be added and `pod install` run to add the Branch SDK
55
+ dependency to the project. If no Podfile is present, and a Cartfile is detected without
56
+ the Branch framework, the framework will be added and `carthage update` run to add
57
+ the Branch SDK dependency to the project. If no Podfile or Cartfile is detected, or
58
+ if one exists with the Branch SDK already included, no changes to the project's
59
+ dependencies will be made.
60
+
61
+ The AppDelegate will receive the following changes if a
62
+ Branch import is not found:
63
+
64
+ - Import the Branch SDK (`import Branch` or `#import <Branch/Branch.h>`).
65
+ - Add the Branch `initSession` call to the `application:didFinishLaunchingWithOptions:` method.
66
+ - Add the `application:continueUserActivity:restorationHandler:` method if it does not
67
+ exist.
68
+
69
+ Both Swift and Objective-C are supported. Automatically updating the Podfile and
70
+ the AppDelegate may be suppressed, respectively, using the `:add_sdk` and
71
+ `:patch_source` options (see below for all options).
72
+
51
73
  ```ruby
52
74
  setup_branch(
53
75
  live_key: "key_live_xxxx",
@@ -88,6 +110,11 @@ Available options:
88
110
  |:force|Update project(s) even if Universal Link validation fails|BRANCH_FORCE_UPDATE|boolean|false|
89
111
  |:commit|Set to true to commit changes to Git; set to a string to commit with a custom message|BRANCH_COMMIT_CHANGES|boolean or string|false|
90
112
  |:frameworks|A list of system frameworks to add to the target that uses the Branch SDK (iOS only)|BRANCH_FRAMEWORKS|array|[]|
113
+ |:add_sdk|Set to false to disable automatic integration of the Branch SDK|BRANCH_ADD_SDK|boolean|true|
114
+ |:podfile|Path to a Podfile to update (iOS only)|BRANCH_PODFILE|string||
115
+ |:patch_source|Set to false to disable automatic source-code patching|BRANCH_PATCH_SOURCE|boolean|true|
116
+ |:pod_repo_update|Set to false to disable update of local podspec repo before pod install|BRANCH_POD_REPO_UPDATE|boolean|true|
117
+ |:cartfile|Path to a Cartfile to update (iOS only)|BRANCH_CARTFILE|string||
91
118
 
92
119
  Individually, all parameters are optional, but the following conditions apply:
93
120
 
@@ -96,7 +123,7 @@ Individually, all parameters are optional, but the following conditions apply:
96
123
  - :app_link_subdomain or :domains must be specified.
97
124
 
98
125
  This action also supports an optional Branchfile to specify configuration options.
99
- See the sample Branchfile at the root of this repo.
126
+ See the sample [Branchfile](./fastlane/Branchfile) in the fastlane subdirectory of this repo.
100
127
 
101
128
  ## validate_universal_links action (iOS only)
102
129
 
@@ -9,8 +9,6 @@ module Fastlane
9
9
  # First augment with any defaults from Branchfile, if present
10
10
  params.load_configuration_file("Branchfile")
11
11
 
12
- helper = Helper::BranchHelper
13
-
14
12
  keys = helper.keys_from_params params
15
13
  raise "Must specify :live_key or :test_key." if keys.empty?
16
14
 
@@ -29,6 +27,8 @@ module Fastlane
29
27
  # raises
30
28
  xcodeproj = Xcodeproj::Project.open params[:xcodeproj]
31
29
 
30
+ update_podfile(params) || update_cartfile(params, xcodeproj)
31
+
32
32
  target = params[:target] # may be nil
33
33
 
34
34
  if params[:update_bundle_and_team_ids]
@@ -51,6 +51,8 @@ module Fastlane
51
51
  helper.add_system_frameworks xcodeproj, target, params[:frameworks] unless params[:frameworks].empty?
52
52
 
53
53
  xcodeproj.save
54
+
55
+ patch_source xcodeproj if params[:patch_source]
54
56
  end
55
57
 
56
58
  if params[:android_project_path] || params[:android_manifest_path]
@@ -201,7 +203,35 @@ module Fastlane
201
203
  description: "A list of system frameworks to add to the target that uses the Branch SDK (iOS only)",
202
204
  optional: true,
203
205
  default_value: [],
204
- type: Array)
206
+ type: Array),
207
+ FastlaneCore::ConfigItem.new(key: :add_sdk,
208
+ env_name: "BRANCH_ADD_SDK",
209
+ description: "Set to false to disable automatic integration of the Branch SDK",
210
+ optional: true,
211
+ default_value: true,
212
+ is_string: false),
213
+ FastlaneCore::ConfigItem.new(key: :podfile,
214
+ env_name: "BRANCH_PODFILE",
215
+ description: "Path to a Podfile to update (iOS only)",
216
+ optional: true,
217
+ type: String),
218
+ FastlaneCore::ConfigItem.new(key: :patch_source,
219
+ env_name: "BRANCH_PATCH_SOURCE",
220
+ description: "Set to false to disable automatic source-code patching",
221
+ optional: true,
222
+ default_value: true,
223
+ is_string: false),
224
+ FastlaneCore::ConfigItem.new(key: :pod_repo_update,
225
+ env_name: "BRANCH_POD_REPO_UPDATE",
226
+ description: "Set to false to disable update of local podspec repo before pod install",
227
+ optional: true,
228
+ default_value: true,
229
+ is_string: false),
230
+ FastlaneCore::ConfigItem.new(key: :cartfile,
231
+ env_name: "BRANCH_CARTFILE",
232
+ description: "Path to a Cartfile to update (iOS only)",
233
+ optional: true,
234
+ type: String)
205
235
  ]
206
236
  end
207
237
 
@@ -212,6 +242,74 @@ module Fastlane
212
242
  def self.category
213
243
  :project
214
244
  end
245
+
246
+ class << self
247
+ def update_podfile(params)
248
+ podfile_path = helper.podfile_path_from_params params
249
+ return false if podfile_path.nil?
250
+
251
+ # 1. Patch Podfile. Return if no change (Branch pod already present).
252
+ return false unless helper.patch_podfile podfile_path
253
+
254
+ # 2. pod install
255
+ other_action.cocoapods podfile: podfile_path, repo_update: params[:pod_repo_update]
256
+
257
+ # 3. Add Podfile and Podfile.lock to commit (in case :commit param specified)
258
+ helper.add_change podfile_path
259
+ helper.add_change "#{podfile_path}.lock"
260
+
261
+ # 4. Check if Pods folder is under SCM
262
+ pods_folder_path = File.expand_path "../Pods", podfile_path
263
+ `git ls-files #{pods_folder_path} --error-unmatch > /dev/null 2>&1`
264
+ return true unless $?.exitstatus == 0
265
+
266
+ # 5. If so, add the Pods folder to the commit (in case :commit param specified)
267
+ helper.add_change pods_folder_path
268
+ other_action.git_add path: pods_folder_path if params[:commit]
269
+ true
270
+ end
271
+
272
+ def update_cartfile(params, project)
273
+ cartfile_path = helper.cartfile_path_from_params params
274
+ return false if cartfile_path.nil?
275
+
276
+ # 1. Patch Cartfile. Return if no change (Branch already present).
277
+ return false unless helper.patch_cartfile cartfile_path
278
+
279
+ # 2. carthage update
280
+ other_action.carthage command: "update", project_directory: File.dirname(cartfile_path)
281
+
282
+ # 3. Add Cartfile and Cartfile.resolved to commit (in case :commit param specified)
283
+ helper.add_change cartfile_path
284
+ helper.add_change "#{cartfile_path}.resolved"
285
+
286
+ # 4. Add to target depependencies
287
+ frameworks_group = project['Frameworks']
288
+ branch_framework = frameworks_group.new_file "Carthage/Build/iOS/Branch.framework"
289
+ target = helper.target_from_project project, params[:target]
290
+ target.frameworks_build_phase.add_file_reference branch_framework
291
+
292
+ # 5. TODO: Add to copy-frameworks build phase
293
+
294
+ # 6. Check if Carthage folder is under SCM
295
+ carthage_folder_path = File.expand_path "../Carthage", cartfile_path
296
+ `git ls-files #{carthage_folder_path} --error-unmatch > /dev/null 2>&1`
297
+ return true unless $?.exitstatus == 0
298
+
299
+ # 7. If so, add the Pods folder to the commit (in case :commit param specified)
300
+ helper.add_change carthage_folder_path
301
+ other_action.git_add path: carthage_folder_path if params[:commit]
302
+ true
303
+ end
304
+
305
+ def patch_source(xcodeproj)
306
+ helper.patch_app_delegate_swift(xcodeproj) || helper.patch_app_delegate_objc(xcodeproj)
307
+ end
308
+
309
+ def helper
310
+ Helper::BranchHelper
311
+ end
312
+ end
215
313
  end
216
314
  end
217
315
  end
@@ -81,6 +81,68 @@ module Fastlane
81
81
 
82
82
  domains
83
83
  end
84
+
85
+ def podfile_path_from_params(params)
86
+ # Disable Podfile update if add_sdk: false is present
87
+ return nil unless add_sdk? params
88
+
89
+ # Use the :podfile parameter if present
90
+ if params[:podfile]
91
+ UI.user_error! ":podfile argument must specify a path ending in '/Podfile'" unless params[:podfile] =~ %r{/Podfile$}
92
+ podfile_path = File.expand_path params[:podfile], Bundler.root
93
+ return podfile_path if File.exist? podfile_path
94
+ UI.user_error! "#{podfile_path} not found"
95
+ end
96
+
97
+ xcodeproj_path = xcodeproj_path_from_params(params)
98
+ # Look in the same directory as the project (typical setup)
99
+ podfile_path = File.expand_path "../Podfile", xcodeproj_path
100
+ return podfile_path if File.exist? podfile_path
101
+
102
+ # Scan the repo. If one Podfile found, return it.
103
+ repo_path = Bundler.root
104
+
105
+ all_podfile_paths = Dir[File.expand_path(File.join(repo_path, '**/Podfile'))]
106
+ return nil unless all_podfile_paths.count == 1
107
+ all_podfile_paths.first
108
+ end
109
+
110
+ def cartfile_path_from_params(params)
111
+ # Disable Cartfile update if add_sdk: false is present
112
+ return nil unless add_sdk? params
113
+
114
+ # Use the :cartfile parameter if present
115
+ if params[:cartfile]
116
+ UI.user_error! ":cartfile argument must specify a path ending in '/Cartfile'" unless params[:cartfile] =~ %r{/Cartfile$}
117
+ cartfile_path = File.expand_path params[:cartfile], Bundler.root
118
+ return cartfile_path if File.exist? cartfile_path
119
+ UI.user_error! "#{cartfile_path} not found"
120
+ end
121
+
122
+ xcodeproj_path = xcodeproj_path_from_params(params)
123
+ # Look in the same directory as the project (typical setup)
124
+ cartfile_path = File.expand_path "../Cartfile", xcodeproj_path
125
+ return cartfile_path if File.exist? cartfile_path
126
+
127
+ # Scan the repo. If one Cartfile found, return it.
128
+ repo_path = Bundler.root
129
+
130
+ all_cartfile_paths = Dir[File.expand_path(File.join(repo_path, '**/Cartfile'))]
131
+ return nil unless all_cartfile_paths.count == 1
132
+ all_cartfile_paths.first
133
+ end
134
+
135
+ def add_sdk?(params)
136
+ add_sdk_param = params[:add_sdk]
137
+ return false if add_sdk_param.nil?
138
+
139
+ case add_sdk_param
140
+ when String
141
+ add_sdk_param.casecmp? "true"
142
+ else
143
+ add_sdk_param
144
+ end
145
+ end
84
146
  end
85
147
  end
86
148
  end
@@ -1,3 +1,4 @@
1
+ require "fastlane/plugin/patch"
1
2
  require "plist"
2
3
 
3
4
  module Fastlane
@@ -335,6 +336,162 @@ module Fastlane
335
336
 
336
337
  target.add_system_framework frameworks
337
338
  end
339
+
340
+ def patch_app_delegate_swift(project)
341
+ app_delegate_swift = project.files.find { |f| f.path =~ /AppDelegate.swift$/ }
342
+ return false if app_delegate_swift.nil?
343
+
344
+ app_delegate_swift_path = app_delegate_swift.real_path.to_s
345
+
346
+ app_delegate = File.open(app_delegate_swift_path, &:read)
347
+ return false if app_delegate =~ /import\s+Branch/
348
+
349
+ UI.message "Patching #{app_delegate_swift_path}"
350
+
351
+ Actions::PatchAction.run(
352
+ files: app_delegate_swift_path,
353
+ regexp: /^\s*import .*$/,
354
+ text: "\nimport Branch",
355
+ mode: :prepend,
356
+ offset: 0
357
+ )
358
+
359
+ # TODO: This is Swift 3. Support other versions, esp. 4.
360
+ init_session_text = <<-EOF
361
+ Branch.getInstance().initSession(launchOptions: launchOptions) {
362
+ universalObject, linkProperties, error in
363
+
364
+ // TODO: Route Branch links
365
+ }
366
+ EOF
367
+
368
+ Actions::PatchAction.run(
369
+ files: app_delegate_swift_path,
370
+ regexp: /didFinishLaunchingWithOptions.*\{[^\n]*\n/m,
371
+ text: init_session_text,
372
+ mode: :append,
373
+ offset: 0
374
+ )
375
+
376
+ unless app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
377
+ # Add the application:continueUserActivity:restorationHandler method if it does not exist
378
+ continue_user_activity_text = <<-EOF
379
+
380
+
381
+ func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
382
+ return Branch.getInstance().continue(userActivity)
383
+ }
384
+ EOF
385
+
386
+ Actions::PatchAction.run(
387
+ files: app_delegate_swift_path,
388
+ regexp: /\n\s*\}[^{}]*\Z/m,
389
+ text: continue_user_activity_text,
390
+ mode: :prepend,
391
+ offset: 0
392
+ )
393
+ end
394
+
395
+ add_change app_delegate_swift_path
396
+ true
397
+ end
398
+
399
+ def patch_app_delegate_objc(project)
400
+ app_delegate_objc = project.files.find { |f| f.path =~ /AppDelegate.m$/ }
401
+ return false if app_delegate_objc.nil?
402
+
403
+ app_delegate_objc_path = app_delegate_objc.real_path.to_s
404
+
405
+ app_delegate = File.open(app_delegate_objc_path, &:read)
406
+ return false if app_delegate =~ %r{^\s+#import\s+<Branch/Branch.h>|^\s+@import\s+Branch;}
407
+
408
+ UI.message "Patching #{app_delegate_objc_path}"
409
+
410
+ Actions::PatchAction.run(
411
+ files: app_delegate_objc_path,
412
+ regexp: /^\s+@import|^\s+#import.*$/,
413
+ text: "\n#import <Branch/Branch.h>",
414
+ mode: :prepend,
415
+ offset: 0
416
+ )
417
+
418
+ init_session_text = <<-EOF
419
+ [[Branch getInstance] initSessionWithLaunchOptions:launchOptions
420
+ andRegisterDeepLinkHandlerUsingBranchUniversalObject:^(BranchUniversalObject *universalObject, BranchLinkProperties *linkProperties, NSError *error){
421
+ // TODO: Route Branch links
422
+ }];
423
+ EOF
424
+
425
+ Actions::PatchAction.run(
426
+ files: app_delegate_objc_path,
427
+ regexp: /didFinishLaunchingWithOptions.*\{[^\n]*\n/m,
428
+ text: init_session_text,
429
+ mode: :append,
430
+ offset: 0
431
+ )
432
+
433
+ unless app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
434
+ # Add the application:continueUserActivity:restorationHandler method if it does not exist
435
+ continue_user_activity_text = <<-EOF
436
+
437
+
438
+ - (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler
439
+ {
440
+ return [[Branch getInstance] continueUserActivity:userActivity];
441
+ }
442
+ EOF
443
+
444
+ Actions::PatchAction.run(
445
+ files: app_delegate_objc_path,
446
+ regexp: /\n\s*@end[^@]*\Z/m,
447
+ text: continue_user_activity_text,
448
+ mode: :prepend,
449
+ offset: 0
450
+ )
451
+ end
452
+
453
+ add_change app_delegate_objc_path
454
+ true
455
+ end
456
+
457
+ def patch_podfile(podfile_path)
458
+ podfile = File.open(podfile_path, &:read)
459
+
460
+ # Podfile already contains the Branch pod
461
+ return false if podfile =~ /pod\s+('Branch'|"Branch")/
462
+
463
+ UI.message "Adding pod \"Branch\" to #{podfile_path}"
464
+
465
+ # TODO: Improve this patch. Should work in the majority of cases for now.
466
+ Actions::PatchAction.run(
467
+ files: podfile_path,
468
+ regexp: /^\s*pod\s*/,
469
+ text: "\npod \"Branch\"",
470
+ mode: :prepend,
471
+ offset: 0
472
+ )
473
+
474
+ true
475
+ end
476
+
477
+ def patch_cartfile(cartfile_path)
478
+ cartfile = File.open(cartfile_path, &:read)
479
+
480
+ # Cartfile already contains the Branch framework
481
+ return false if cartfile =~ /git.+Branch/
482
+
483
+ UI.message "Adding \"Branch\" to #{cartfile_path}"
484
+
485
+ Actions::PatchAction.run(
486
+ files: cartfile_path,
487
+ regexp: /\z/,
488
+ text: "git \"https://github.com/BranchMetrics/ios-branch-deep-linking\"\n",
489
+ mode: :append,
490
+ offset: 0
491
+ )
492
+
493
+ true
494
+ end
338
495
  end
339
496
  end
340
497
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Branch
3
- VERSION = "0.3.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-branch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Branch
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-01 00:00:00.000000000 Z
12
+ date: 2017-09-03 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fastlane-plugin-patch
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: plist
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +109,20 @@ dependencies:
95
109
  - - ">="
96
110
  - !ruby/object:Gem::Version
97
111
  version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rspec-simplecov
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
98
126
  - !ruby/object:Gem::Dependency
99
127
  name: rubocop
100
128
  requirement: !ruby/object:Gem::Requirement
@@ -109,6 +137,20 @@ dependencies:
109
137
  - - ">="
110
138
  - !ruby/object:Gem::Version
111
139
  version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: simplecov
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
112
154
  - !ruby/object:Gem::Dependency
113
155
  name: fastlane
114
156
  requirement: !ruby/object:Gem::Requirement