fastlane 2.129.0 → 2.134.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +66 -66
  3. data/cert/lib/cert/module.rb +2 -0
  4. data/cert/lib/cert/options.rb +6 -0
  5. data/cert/lib/cert/runner.rb +17 -11
  6. data/fastlane/lib/fastlane.rb +4 -1
  7. data/fastlane/lib/fastlane/actions/.download_dsyms.rb.swp +0 -0
  8. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  9. data/fastlane/lib/fastlane/actions/actions_helper.rb +4 -0
  10. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +11 -3
  11. data/fastlane/lib/fastlane/actions/carthage.rb +11 -3
  12. data/fastlane/lib/fastlane/actions/cocoapods.rb +24 -2
  13. data/fastlane/lib/fastlane/actions/copy_artifacts.rb +1 -1
  14. data/fastlane/lib/fastlane/actions/danger.rb +7 -0
  15. data/fastlane/lib/fastlane/actions/deploygate.rb +1 -1
  16. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +23 -4
  17. data/fastlane/lib/fastlane/actions/download_dsyms.rb +59 -10
  18. data/fastlane/lib/fastlane/actions/ensure_env_vars.rb +58 -0
  19. data/fastlane/lib/fastlane/actions/get_version_number.rb +12 -3
  20. data/fastlane/lib/fastlane/actions/gradle.rb +11 -1
  21. data/fastlane/lib/fastlane/actions/onesignal.rb +59 -29
  22. data/fastlane/lib/fastlane/actions/pod_push.rb +10 -1
  23. data/fastlane/lib/fastlane/actions/register_devices.rb +38 -22
  24. data/fastlane/lib/fastlane/actions/resign.rb +2 -2
  25. data/fastlane/lib/fastlane/actions/slather.rb +1 -0
  26. data/fastlane/lib/fastlane/actions/sonar.rb +16 -0
  27. data/fastlane/lib/fastlane/actions/testfairy.rb +1 -1
  28. data/fastlane/lib/fastlane/actions/update_fastlane.rb +9 -49
  29. data/fastlane/lib/fastlane/actions/update_keychain_access_groups.rb +94 -0
  30. data/fastlane/lib/fastlane/commands_generator.rb +16 -0
  31. data/fastlane/lib/fastlane/environment_printer.rb +7 -1
  32. data/fastlane/lib/fastlane/fast_file.rb +10 -4
  33. data/fastlane/lib/fastlane/helper/crashlytics_helper.rb +1 -1
  34. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +2 -0
  35. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +3 -0
  36. data/fastlane/lib/fastlane/setup/setup_android.rb +1 -1
  37. data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +122 -34
  38. data/fastlane/lib/fastlane/swift_fastlane_function.rb +72 -3
  39. data/fastlane/lib/fastlane/swift_runner_upgrader.rb +4 -0
  40. data/fastlane/lib/fastlane/version.rb +1 -1
  41. data/fastlane/swift/Actions.swift +15 -0
  42. data/fastlane/swift/Deliverfile.swift +1 -1
  43. data/fastlane/swift/DeliverfileProtocol.swift +121 -1
  44. data/fastlane/swift/Fastlane.swift +3925 -30
  45. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +9 -0
  46. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  47. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  48. data/fastlane/swift/Gymfile.swift +1 -1
  49. data/fastlane/swift/GymfileProtocol.swift +91 -9
  50. data/fastlane/swift/Matchfile.swift +1 -1
  51. data/fastlane/swift/MatchfileProtocol.swift +65 -1
  52. data/fastlane/swift/Plugins.swift +15 -0
  53. data/fastlane/swift/Precheckfile.swift +1 -1
  54. data/fastlane/swift/PrecheckfileProtocol.swift +15 -2
  55. data/fastlane/swift/Scanfile.swift +1 -1
  56. data/fastlane/swift/ScanfileProtocol.swift +109 -1
  57. data/fastlane/swift/Screengrabfile.swift +1 -1
  58. data/fastlane/swift/ScreengrabfileProtocol.swift +39 -2
  59. data/fastlane/swift/Snapshotfile.swift +1 -1
  60. data/fastlane/swift/SnapshotfileProtocol.swift +71 -1
  61. data/fastlane/swift/upgrade_manifest.json +1 -1
  62. data/fastlane_core/lib/fastlane_core/command_executor.rb +1 -1
  63. data/fastlane_core/lib/fastlane_core/device_manager.rb +1 -1
  64. data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
  65. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +1 -3
  66. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +3 -2
  67. data/frameit/lib/frameit/screenshot.rb +4 -0
  68. data/gym/lib/gym/generators/build_command_generator.rb +5 -1
  69. data/gym/lib/gym/options.rb +16 -16
  70. data/gym/lib/gym/runner.rb +33 -5
  71. data/match/lib/match/generator.rb +1 -0
  72. data/match/lib/match/importer.rb +2 -2
  73. data/match/lib/match/module.rb +2 -0
  74. data/match/lib/match/nuke.rb +5 -5
  75. data/match/lib/match/options.rb +17 -0
  76. data/match/lib/match/runner.rb +10 -6
  77. data/match/lib/match/storage/git_storage.rb +8 -2
  78. data/match/lib/match/storage/google_cloud_storage.rb +85 -33
  79. data/produce/lib/produce/service.rb +7 -1
  80. data/scan/lib/scan/error_handler.rb +9 -4
  81. data/scan/lib/scan/runner.rb +1 -1
  82. data/sigh/lib/sigh/download_all.rb +48 -8
  83. data/sigh/lib/sigh/runner.rb +13 -5
  84. data/snapshot/lib/snapshot/commands_generator.rb +2 -2
  85. data/snapshot/lib/snapshot/options.rb +5 -0
  86. data/snapshot/lib/snapshot/reports_generator.rb +3 -0
  87. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
  88. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb +1 -1
  89. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +16 -1
  90. data/snapshot/lib/snapshot/update.rb +4 -2
  91. data/spaceship/lib/spaceship/client.rb +3 -3
  92. data/spaceship/lib/spaceship/connect_api/models/app.rb +6 -6
  93. data/spaceship/lib/spaceship/connect_api/models/build.rb +3 -3
  94. data/spaceship/lib/spaceship/connect_api/models/build_delivery.rb +1 -1
  95. data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +1 -1
  96. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +1 -1
  97. data/spaceship/lib/spaceship/connect_api/models/device.rb +1 -1
  98. data/spaceship/lib/spaceship/connect_api/models/profile.rb +1 -1
  99. data/spaceship/lib/spaceship/portal/.certificate.rb.swp +0 -0
  100. data/spaceship/lib/spaceship/portal/provisioning_profile.rb +1 -1
  101. data/spaceship/lib/spaceship/tunes/app_version.rb +4 -0
  102. data/spaceship/lib/spaceship/tunes/application.rb +4 -0
  103. data/spaceship/lib/spaceship/tunes/availability.rb +40 -8
  104. data/spaceship/lib/spaceship/tunes/b2b_organization.rb +50 -0
  105. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +10 -2
  106. data/spaceship/lib/spaceship/tunes/tunes_client.rb +26 -1
  107. metadata +55 -46
@@ -16,7 +16,7 @@ module Fastlane
16
16
  # If any of the paths include "*", we assume that we are referring to the Unix entries
17
17
  # e.g /tmp/fastlane/* refers to all the files in /tmp/fastlane
18
18
  # We use Dir.glob to expand all those paths, this would create an array of arrays though, so flatten
19
- artifacts = artifacts_to_search.map { |f| f.include?("*") ? Dir.glob(f) : f }.flatten
19
+ artifacts = artifacts_to_search.flat_map { |f| f.include?("*") ? Dir.glob(f) : f }
20
20
 
21
21
  UI.verbose("Copying artifacts #{artifacts.join(', ')} to #{target_path}")
22
22
  UI.verbose(params[:keep_original] ? "Keeping original files" : "Not keeping original files")
@@ -18,6 +18,7 @@ module Fastlane
18
18
  cmd << "--dangerfile=#{dangerfile}" if dangerfile
19
19
  cmd << "--fail-on-errors=true" if params[:fail_on_errors]
20
20
  cmd << "--new-comment" if params[:new_comment]
21
+ cmd << "--remove-previous-comments" if params[:remove_previous_comments]
21
22
  cmd << "--base=#{base}" if base
22
23
  cmd << "--head=#{head}" if head
23
24
  cmd << "pr #{pr}" if pr
@@ -78,6 +79,12 @@ module Fastlane
78
79
  is_string: false,
79
80
  optional: true,
80
81
  default_value: false),
82
+ FastlaneCore::ConfigItem.new(key: :remove_previous_comments,
83
+ env_name: "FL_DANGER_REMOVE_PREVIOUS_COMMENT",
84
+ description: "Makes Danger remove all previous comment and create a new one in the end of the list",
85
+ is_string: false,
86
+ optional: true,
87
+ default_value: false),
81
88
  FastlaneCore::ConfigItem.new(key: :base,
82
89
  env_name: "FL_DANGER_BASE",
83
90
  description: "A branch/tag/commit to use as the base of the diff. [master|dev|stable]",
@@ -33,7 +33,7 @@ module Fastlane
33
33
  options[:disable_notify] = 'yes' if options[:disable_notify]
34
34
 
35
35
  connection.post("/api/users/#{user_name}/apps", options)
36
- rescue Faraday::Error::TimeoutError
36
+ rescue Faraday::TimeoutError
37
37
  UI.crash!("Timed out while uploading build. Check https://deploygate.com/ to see if the upload was completed.")
38
38
  end
39
39
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  A new approach to iOS code signing: Share one code signing identity across your development team to simplify your codesigning setup and prevent code signing issues.
8
8
 
9
- _match_ is the implementation of the [https://codesigning.guide concept](https://codesigning.guide). _match_ creates all required certificates & provisioning profiles and stores them in a separate git repository. Every team member with access to the repo can use those credentials for code signing. _match_ also automatically repairs broken and expired credentials. It's the easiest way to share signing credentials across teams
9
+ _match_ is the implementation of the [codesigning.guide concept](https://codesigning.guide). _match_ creates all required certificates & provisioning profiles and stores them in a separate git repository. Every team member with access to the repo can use those credentials for code signing. _match_ also automatically repairs broken and expired credentials. It's the easiest way to share signing credentials across teams
10
10
 
11
11
  [More information on how to get started with codesigning](https://docs.fastlane.tools/codesigning/getting-started/)
12
12
 
@@ -79,7 +79,7 @@ You'll be asked if you want to store your code signing identities inside a **Git
79
79
 
80
80
  Use Git Storage to store all code signing identities in a private git repo, owned and operated by you. The files will be encrypted using OpenSSL.
81
81
 
82
- First, enter the URL to your private (!) Git repo (You can create one for free on e.g. [GitHub](https://github.com/new) or [BitBucket](https://bitbucket.org/repo/create)). The URL you enter can be either a `https://` or a `git` URL. (If your machine is currently using SSH to authenticate with GitHub, you'll want to use a `git` URL, otherwise you may see an authentication error when you attempt to use match.) `fastlane match init` won't read or modify your certificates or profiles yet, and also won't validate your git URL.
82
+ First, enter the URL to your private (!) Git repo (You can create one for free on e.g. [GitHub](https://github.com/new) or [BitBucket](https://bitbucket.org/repo/create)). The URL you enter can be either a `https://` or a `git` URL. `fastlane match init` won't read or modify your certificates or profiles yet, and also won't validate your git URL.
83
83
 
84
84
  This will create a `Matchfile` in your current directory (or in your `./fastlane/` folder).
85
85
 
@@ -92,6 +92,25 @@ app_identifier("tools.fastlane.app")
92
92
  username("user@fastlane.tools")
93
93
  ```
94
94
 
95
+ ##### Git Storage on GitHub
96
+
97
+ If your machine is currently using SSH to authenticate with GitHub, you'll want to use a `git` URL, otherwise, you may see an authentication error when you attempt to use match. Alternatively, you can set a basic authorization for _match_:
98
+
99
+ Using parameter:
100
+
101
+ ```
102
+ math(git_basic_authorization: '<YOUR KEY>')
103
+ ```
104
+
105
+ Using environment variable:
106
+
107
+ ```
108
+ ENV['MATCH_GIT_BASIC_AUTHORIZATION'] = '<YOUR KEY>'
109
+ match
110
+ ```
111
+
112
+ You can find more information about GitHub basic authentication and personal token generation here: [https://developer.github.com/v3/auth/#basic-authentication](https://developer.github.com/v3/auth/#basic-authentication)
113
+
95
114
  #### Google Cloud Storage
96
115
 
97
116
  Use [Google Cloud Storage](https://cloud.google.com/storage/) for a fully hosted solution for your code signing identities. Certificates are stored on Google Cloud, encrypted using Google managed keys. Everything will be stored on your Google account, inside a storage bucket you provide. You can also directly access the files using the web console.
@@ -119,7 +138,7 @@ match(git_branch: "team2", username: "user@team2.com")
119
138
 
120
139
  #### Google Cloud Storage
121
140
 
122
- If you use Google Cloud Storage, you don't need to do anything manually. Just use Google Cloud Storage, and the top level folder will be the team ID.
141
+ If you use Google Cloud Storage, you don't need to do anything manually for multiple teams. Just use Google Cloud Storage, and the top level folder will be the team ID.
123
142
 
124
143
  ### Run
125
144
 
@@ -214,7 +233,7 @@ There are two cases for reading and writing certificates stored in a Google Clou
214
233
  1. Continuous integration jobs. These will authenticate to your Google Cloud project via a service account, and use a `gc_keys.json` file as credentials.
215
234
  1. Developers on a local workstation. In this case, you should choose whether everyone on your team will create their own `gc_keys.json` file, or whether you want to manage access to the bucket directly using your developers' Google accounts.
216
235
 
217
- When running `fastlane match init` the first time, the setup process will give you the option to create your `gc_keys.json` file. This file contains the auth credentials needed to access your Google Cloud storage bucket. Make sure to keep that file secret and never add it to version control. We recommend adding `gc_keys.json` to your `.gitignore`
236
+ When running `fastlane match init` the first time, the setup process will give you the option to create your `gc_keys.json` file. This file contains the authentication credentials needed to access your Google Cloud storage bucket. Make sure to keep that file secret and never add it to version control. We recommend adding `gc_keys.json` to your `.gitignore`
218
237
 
219
238
  ##### Managing developer access via keys
220
239
  If you want to manage developer access to your certificates via authentication keys, every developer should create their own `gc_keys.json` and add the file to all their work machines. This will give the admin full control over who has read/write access to the given Storage bucket. At the same time it allows your team to revoke a single key if a file gets compromised.
@@ -25,6 +25,8 @@ module Fastlane
25
25
  build_number = params[:build_number]
26
26
  platform = params[:platform]
27
27
  output_directory = params[:output_directory]
28
+ wait_for_dsym_processing = params[:wait_for_dsym_processing]
29
+ wait_timeout = params[:wait_timeout]
28
30
  min_version = Gem::Version.new(params[:min_version]) if params[:min_version]
29
31
 
30
32
  # Set version if it is latest
@@ -44,6 +46,20 @@ module Fastlane
44
46
  version = latest_candidate_build.train_version
45
47
  build_number = latest_candidate_build.build_version
46
48
  end
49
+ elsif version == 'live'
50
+ UI.message("Looking for live version...")
51
+ live_version = app.live_version(platform: platform)
52
+
53
+ UI.user_error!("Could not find live version for your app, please try setting 'latest' or a specific version") if live_version.nil?
54
+
55
+ # No need to search for candidates, because released App Store version should only have one build
56
+ version = live_version.version
57
+ build_number = live_version.build_version
58
+ end
59
+
60
+ # Remove leading zeros from version string (eg. 1.02 -> 1.2)
61
+ if version
62
+ version = version.split(".").map(&:to_i).join(".")
47
63
  end
48
64
 
49
65
  # Make sure output_directory has a slash on the end
@@ -85,14 +101,32 @@ module Fastlane
85
101
  next
86
102
  end
87
103
 
88
- begin
89
- UI.verbose("Build_version: #{build.build_version} matches #{build_number}, grabbing dsym_url") if build_number
90
-
91
- build_details = app.tunes_build_details(train: train.version_string, build_number: build.build_version, platform: platform)
92
- download_url = build_details.dsym_url
93
- UI.verbose("dsym_url: #{download_url}")
94
- rescue Spaceship::TunesClient::ITunesConnectError => ex
95
- UI.error("Error accessing dSYM file for build\n\n#{build}\n\nException: #{ex}")
104
+ UI.verbose("Build_version: #{build.build_version} matches #{build_number}, grabbing dsym_url") if build_number
105
+
106
+ start = Time.now
107
+ download_url = nil
108
+
109
+ loop do
110
+ begin
111
+ build_details = app.tunes_build_details(train: train.version_string, build_number: build.build_version, platform: platform)
112
+ download_url = build_details.dsym_url
113
+ UI.verbose("dsym_url: #{download_url}")
114
+ rescue Spaceship::TunesClient::ITunesConnectError => ex
115
+ UI.error("Error accessing dSYM file for build\n\n#{build}\n\nException: #{ex}")
116
+ end
117
+
118
+ unless download_url
119
+ if !wait_for_dsym_processing || (Time.now - start) > wait_timeout
120
+ # In some cases, AppStoreConnect does not process the dSYMs, thus no error should be thrown.
121
+ UI.message("Could not find any dSYM for #{build.build_version} (#{train.version_string})")
122
+ else
123
+ UI.message("Waiting for dSYM file to appear...")
124
+ sleep(30)
125
+ next
126
+ end
127
+ end
128
+
129
+ break
96
130
  end
97
131
 
98
132
  if download_url
@@ -212,7 +246,7 @@ module Fastlane
212
246
  FastlaneCore::ConfigItem.new(key: :version,
213
247
  short_option: "-v",
214
248
  env_name: "DOWNLOAD_DSYMS_VERSION",
215
- description: "The app version for dSYMs you wish to download, pass in 'latest' to download only the latest build's dSYMs",
249
+ description: "The app version for dSYMs you wish to download, pass in 'latest' to download only the latest build's dSYMs or 'live' to download only the live verion dSYMs",
216
250
  optional: true),
217
251
  FastlaneCore::ConfigItem.new(key: :build_number,
218
252
  short_option: "-b",
@@ -228,7 +262,21 @@ module Fastlane
228
262
  short_option: "-s",
229
263
  env_name: "DOWNLOAD_DSYMS_OUTPUT_DIRECTORY",
230
264
  description: "Where to save the download dSYMs, defaults to the current path",
231
- optional: true)
265
+ optional: true),
266
+ FastlaneCore::ConfigItem.new(key: :wait_for_dsym_processing,
267
+ short_option: "-w",
268
+ env_name: "DOWNLOAD_DSYMS_WAIT_FOR_DSYM_PROCESSING",
269
+ description: "Wait for dSYMs to process",
270
+ optional: true,
271
+ default_value: false,
272
+ type: Boolean),
273
+ FastlaneCore::ConfigItem.new(key: :wait_timeout,
274
+ short_option: "-t",
275
+ env_name: "DOWNLOAD_DSYMS_WAIT_TIMEOUT",
276
+ description: "Number of seconds to wait for dSYMs to process",
277
+ optional: true,
278
+ default_value: 300,
279
+ type: Integer)
232
280
  ]
233
281
  end
234
282
 
@@ -254,6 +302,7 @@ module Fastlane
254
302
  [
255
303
  'download_dsyms',
256
304
  'download_dsyms(version: "1.0.0", build_number: "345")',
305
+ 'download_dsyms(version: "live")',
257
306
  'download_dsyms(min_version: "1.2.3")'
258
307
  ]
259
308
  end
@@ -0,0 +1,58 @@
1
+ module Fastlane
2
+ module Actions
3
+ class EnsureEnvVarsAction < Action
4
+ def self.run(params)
5
+ variables = params[:env_vars]
6
+
7
+ variables.each do |variable|
8
+ next unless ENV[variable].to_s.strip.empty?
9
+
10
+ UI.user_error!("Missing environment variable '#{variable}'")
11
+ end
12
+
13
+ is_one = variables.length == 1
14
+
15
+ UI.success("Environment variable#{is_one ? '' : 's'} '#{variables.join('\', \'')}' #{is_one ? 'is' : 'are'} set!")
16
+ end
17
+
18
+ def self.description
19
+ 'Raises an exception if the specified env vars are not set'
20
+ end
21
+
22
+ def self.details
23
+ 'This action will check if some environment variables are set.'
24
+ end
25
+
26
+ def self.available_options
27
+ [
28
+ FastlaneCore::ConfigItem.new(key: :env_vars,
29
+ description: 'The environment variables names that should be checked',
30
+ type: Array,
31
+ verify_block: proc do |value|
32
+ UI.user_error!('Specify at least one environment variable name') if value.empty?
33
+ end)
34
+ ]
35
+ end
36
+
37
+ def self.authors
38
+ ['revolter']
39
+ end
40
+
41
+ def self.example_code
42
+ [
43
+ 'ensure_env_vars(
44
+ env_vars: [\'GITHUB_USER_NAME\', \'GITHUB_API_TOKEN\']
45
+ )'
46
+ ]
47
+ end
48
+
49
+ def self.category
50
+ :misc
51
+ end
52
+
53
+ def self.is_supported?(platform)
54
+ true
55
+ end
56
+ end
57
+ end
58
+ end
@@ -18,9 +18,18 @@ module Fastlane
18
18
  plist_file = get_plist!(folder, target, configuration)
19
19
  version_number = get_version_number_from_plist!(plist_file)
20
20
 
21
- # Get from build settings if needed (ex: $(MARKETING_VERSION) is default in Xcode 11)
21
+ # Get from build settings (or project settings) if needed (ex: $(MARKETING_VERSION) is default in Xcode 11)
22
22
  if version_number =~ /\$\(([\w\-]+)\)/
23
- version_number = get_version_number_from_build_settings!(target, $1, configuration)
23
+ version_number = get_version_number_from_build_settings!(target, $1, configuration) || get_version_number_from_build_settings!(project, $1, configuration)
24
+
25
+ # ${MARKETING_VERSION} also works
26
+ elsif version_number =~ /\$\{([\w\-]+)\}/
27
+ version_number = get_version_number_from_build_settings!(target, $1, configuration) || get_version_number_from_build_settings!(project, $1, configuration)
28
+ end
29
+
30
+ # Error out if version_number is not set
31
+ if version_number.nil?
32
+ UI.user_error!("Unable to find Xcode build setting: #{$1}")
24
33
  end
25
34
 
26
35
  # Store the number in the shared hash
@@ -78,7 +87,7 @@ module Fastlane
78
87
  end
79
88
  end
80
89
 
81
- UI.user_error!("Unable to find Xcode build setting: #{variable}")
90
+ return nil
82
91
  end
83
92
 
84
93
  def self.get_plist!(folder, target, configuration = nil)
@@ -8,6 +8,8 @@ module Fastlane
8
8
  GRADLE_ALL_APK_OUTPUT_PATHS = :GRADLE_ALL_APK_OUTPUT_PATHS
9
9
  GRADLE_AAB_OUTPUT_PATH = :GRADLE_AAB_OUTPUT_PATH
10
10
  GRADLE_ALL_AAB_OUTPUT_PATHS = :GRADLE_ALL_AAB_OUTPUT_PATHS
11
+ GRADLE_OUTPUT_JSON_OUTPUT_PATH = :GRADLE_OUTPUT_JSON_OUTPUT_PATH
12
+ GRADLE_ALL_OUTPUT_JSON_OUTPUT_PATHS = :GRADLE_ALL_OUTPUT_JSON_OUTPUT_PATHS
11
13
  GRADLE_FLAVOR = :GRADLE_FLAVOR
12
14
  GRADLE_BUILD_TYPE = :GRADLE_BUILD_TYPE
13
15
  end
@@ -60,6 +62,7 @@ module Fastlane
60
62
 
61
63
  apk_search_path = File.join(project_dir, '**', 'build', 'outputs', 'apk', '**', '*.apk')
62
64
  aab_search_path = File.join(project_dir, '**', 'build', 'outputs', 'bundle', '**', '*.aab')
65
+ output_json_search_path = File.join(project_dir, '**', 'build', 'outputs', 'apk', '**', 'output.json')
63
66
 
64
67
  # Our apk/aab is now built, but there might actually be multiple ones that were built if a flavor was not specified in a multi-flavor project (e.g. `assembleRelease`)
65
68
  # However, we're not interested in unaligned apk's...
@@ -67,18 +70,23 @@ module Fastlane
67
70
  new_apks = new_apks.map { |path| File.expand_path(path) }
68
71
  new_aabs = Dir[aab_search_path]
69
72
  new_aabs = new_aabs.map { |path| File.expand_path(path) }
73
+ new_output_jsons = Dir[output_json_search_path]
74
+ new_output_jsons = new_output_jsons.map { |path| File.expand_path(path) }
70
75
 
71
76
  # We expose all of these new apks and aabs
72
77
  Actions.lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS] = new_apks
73
78
  Actions.lane_context[SharedValues::GRADLE_ALL_AAB_OUTPUT_PATHS] = new_aabs
79
+ Actions.lane_context[SharedValues::GRADLE_ALL_OUTPUT_JSON_OUTPUT_PATHS] = new_output_jsons
74
80
 
75
81
  # We also take the most recent apk and aab to return as SharedValues::GRADLE_APK_OUTPUT_PATH and SharedValues::GRADLE_AAB_OUTPUT_PATH
76
82
  # This is the one that will be relevant for most projects that just build a single build variant (flavor + build type combo).
77
83
  # In multi build variants this value is undefined
78
84
  last_apk_path = new_apks.sort_by(&File.method(:mtime)).last
79
85
  last_aab_path = new_aabs.sort_by(&File.method(:mtime)).last
86
+ last_output_json_path = new_output_jsons.sort_by(&File.method(:mtime)).last
80
87
  Actions.lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH] = File.expand_path(last_apk_path) if last_apk_path
81
88
  Actions.lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH] = File.expand_path(last_aab_path) if last_aab_path
89
+ Actions.lane_context[SharedValues::GRADLE_OUTPUT_JSON_OUTPUT_PATH] = File.expand_path(last_output_json_path) if last_output_json_path
82
90
 
83
91
  # Give a helpful message in case there were no new apks or aabs. Remember we're only running this code when assembling, in which case we certainly expect there to be an apk or aab
84
92
  UI.message('Couldn\'t find any new signed apk files...') if new_apks.empty? && new_aabs.empty?
@@ -165,7 +173,9 @@ module Fastlane
165
173
  ['GRADLE_FLAVOR', 'The flavor, e.g. `MyFlavor`'],
166
174
  ['GRADLE_BUILD_TYPE', 'The build type, e.g. `Release`'],
167
175
  ['GRADLE_AAB_OUTPUT_PATH', 'The path to the most recent Android app bundle'],
168
- ['GRADLE_ALL_AAB_OUTPUT_PATHS', 'The paths to the most recent Android app bundles']
176
+ ['GRADLE_ALL_AAB_OUTPUT_PATHS', 'The paths to the most recent Android app bundles'],
177
+ ['GRADLE_OUTPUT_JSON_OUTPUT_PATH', 'The path to the most recent output.json file'],
178
+ ['GRADLE_ALL_OUTPUT_JSON_OUTPUT_PATHS', 'The path to the newly generated output.json files']
169
179
  ]
170
180
  end
171
181
 
@@ -11,15 +11,26 @@ module Fastlane
11
11
  require 'uri'
12
12
  require 'base64'
13
13
 
14
- UI.message("Parameter App name: #{params[:app_name]}")
14
+ app_id = params[:app_id].to_s.strip
15
15
  auth_token = params[:auth_token]
16
- app_name = params[:app_name]
16
+ app_name = params[:app_name].to_s
17
17
  apns_p12_password = params[:apns_p12_password]
18
18
  android_token = params[:android_token]
19
19
  android_gcm_sender_id = params[:android_gcm_sender_id]
20
20
 
21
+ has_app_id = !app_id.empty?
22
+ has_app_name = !app_name.empty?
23
+
24
+ is_update = has_app_id
25
+
26
+ UI.user_error!('Please specify the `app_id` or the `app_name` parameters!') if !has_app_id && !has_app_name
27
+
28
+ UI.message("Parameter App ID: #{app_id}") if has_app_id
29
+ UI.message("Parameter App name: #{app_name}") if has_app_name
30
+
21
31
  payload = {}
22
- payload['name'] = app_name
32
+
33
+ payload['name'] = app_name if has_app_name
23
34
 
24
35
  unless params[:apns_p12].nil?
25
36
  data = File.read(params[:apns_p12])
@@ -33,61 +44,70 @@ module Fastlane
33
44
  payload["gcm_key"] = android_token unless android_token.nil?
34
45
  payload["android_gcm_sender_id"] = android_gcm_sender_id unless android_gcm_sender_id.nil?
35
46
 
36
- # here's the actual lifting - POST to OneSignal
47
+ # here's the actual lifting - POST or PUT to OneSignal
37
48
 
38
49
  json_headers = { 'Content-Type' => 'application/json', 'Authorization' => "Basic #{auth_token}" }
39
- uri = URI.parse('https://onesignal.com/api/v1/apps')
50
+ url = +'https://onesignal.com/api/v1/apps'
51
+ url << '/' + app_id if is_update
52
+ uri = URI.parse(url)
40
53
  http = Net::HTTP.new(uri.host, uri.port)
41
54
  http.use_ssl = true
42
- response = http.post(uri.path, payload.to_json, json_headers)
55
+
56
+ if is_update
57
+ response = http.put(uri.path, payload.to_json, json_headers)
58
+ else
59
+ response = http.post(uri.path, payload.to_json, json_headers)
60
+ end
61
+
43
62
  response_body = JSON.parse(response.body)
44
63
 
45
64
  Actions.lane_context[SharedValues::ONE_SIGNAL_APP_ID] = response_body["id"]
46
65
  Actions.lane_context[SharedValues::ONE_SIGNAL_APP_AUTH_KEY] = response_body["basic_auth_key"]
47
66
 
48
- check_response_code(response)
67
+ check_response_code(response, is_update)
49
68
  end
50
69
 
51
- def self.check_response_code(response)
70
+ def self.check_response_code(response, is_update)
52
71
  case response.code.to_i
53
72
  when 200, 204
54
- puts("Successfully created new OneSignal app".green)
73
+ UI.success("Successfully #{is_update ? 'updated' : 'created new'} OneSignal app")
55
74
  else
56
75
  UI.user_error!("Unexpected #{response.code} with response: #{response.body}")
57
76
  end
58
77
  end
59
78
 
60
79
  def self.description
61
- "Create a new [OneSignal](https://onesignal.com/) application"
80
+ "Create or update a new [OneSignal](https://onesignal.com/) application"
62
81
  end
63
82
 
64
83
  def self.details
65
- "You can use this action to automatically create a OneSignal application. You can also upload a `.p12` with password, a GCM key, or both."
84
+ "You can use this action to automatically create or update a OneSignal application. You can also upload a `.p12` with password, a GCM key, or both."
66
85
  end
67
86
 
68
87
  def self.available_options
69
88
  [
70
- FastlaneCore::ConfigItem.new(key: :auth_token,
71
- env_name: "ONE_SIGNAL_AUTH_KEY",
72
- sensitive: true,
73
- description: "OneSignal Authorization Key",
74
- verify_block: proc do |value|
75
- unless value.to_s.length > 0
76
- UI.error("Please add 'ENV[\"ONE_SIGNAL_AUTH_KEY\"] = \"your token\"' to your Fastfile's `before_all` section.")
77
- UI.user_error!("No ONE_SIGNAL_AUTH_KEY given.")
78
- end
79
- end),
89
+ FastlaneCore::ConfigItem.new(key: :app_id,
90
+ env_name: "ONE_SIGNAL_APP_ID",
91
+ sensitive: true,
92
+ description: "OneSignal App ID. Setting this updates an existing app",
93
+ optional: true),
80
94
 
81
- FastlaneCore::ConfigItem.new(key: :app_name,
82
- env_name: "ONE_SIGNAL_APP_NAME",
83
- description: "OneSignal App Name",
95
+ FastlaneCore::ConfigItem.new(key: :auth_token,
96
+ env_name: "ONE_SIGNAL_AUTH_KEY",
97
+ sensitive: true,
98
+ description: "OneSignal Authorization Key",
84
99
  verify_block: proc do |value|
85
- unless value.to_s.length > 0
86
- UI.error("Please add 'ENV[\"ONE_SIGNAL_APP_NAME\"] = \"Your app name\"' to your Fastfile's `before_all` section.")
87
- UI.user_error!("No ONE_SIGNAL_APP_NAME given.")
100
+ if value.to_s.empty?
101
+ UI.error("Please add 'ENV[\"ONE_SIGNAL_AUTH_KEY\"] = \"your token\"' to your Fastfile's `before_all` section.")
102
+ UI.user_error!("No ONE_SIGNAL_AUTH_KEY given.")
88
103
  end
89
104
  end),
90
105
 
106
+ FastlaneCore::ConfigItem.new(key: :app_name,
107
+ env_name: "ONE_SIGNAL_APP_NAME",
108
+ description: "OneSignal App Name. This is required when creating an app (in other words, when `:app_id` is not set, and optional when updating an app",
109
+ optional: true),
110
+
91
111
  FastlaneCore::ConfigItem.new(key: :android_token,
92
112
  env_name: "ANDROID_TOKEN",
93
113
  description: "ANDROID GCM KEY",
@@ -121,8 +141,8 @@ module Fastlane
121
141
 
122
142
  def self.output
123
143
  [
124
- ['ONE_SIGNAL_APP_ID', 'The OneSignal app ID of the newly created app'],
125
- ['ONE_SIGNAL_APP_AUTH_KEY', 'The auth token for the newly created OneSignal app']
144
+ ['ONE_SIGNAL_APP_ID', 'The app ID of the newly created or updated app'],
145
+ ['ONE_SIGNAL_APP_AUTH_KEY', 'The auth token for the newly created or updated app']
126
146
  ]
127
147
  end
128
148
 
@@ -144,6 +164,16 @@ module Fastlane
144
164
  apns_p12: "Path to Apple .p12 file (optional)",
145
165
  apns_p12_password: "Password for .p12 file (optional)",
146
166
  apns_env: "production/sandbox (defaults to production)"
167
+ )',
168
+ 'onesignal(
169
+ app_id: "Your OneSignal App ID",
170
+ auth_token: "Your OneSignal Auth Token",
171
+ app_name: "New Name for OneSignal App",
172
+ android_token: "Your Android GCM key (optional)",
173
+ android_gcm_sender_id: "Your Android GCM Sender ID (optional)",
174
+ apns_p12: "Path to Apple .p12 file (optional)",
175
+ apns_p12_password: "Password for .p12 file (optional)",
176
+ apns_env: "production/sandbox (defaults to production)"
147
177
  )'
148
178
  ]
149
179
  end