fastlane 2.109.1 → 2.110.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +66 -66
  3. data/deliver/lib/deliver/.options.rb.swp +0 -0
  4. data/fastlane/lib/fastlane/actions/download.rb +1 -0
  5. data/fastlane/lib/fastlane/actions/install_on_device.rb +2 -2
  6. data/fastlane/lib/fastlane/actions/resign.rb +5 -17
  7. data/fastlane/lib/fastlane/helper/adb_helper.rb +1 -1
  8. data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +3 -3
  9. data/fastlane/lib/fastlane/version.rb +1 -1
  10. data/fastlane/swift/Deliverfile.swift +1 -1
  11. data/fastlane/swift/Fastlane.swift +73 -65
  12. data/fastlane/swift/Gymfile.swift +1 -1
  13. data/fastlane/swift/Matchfile.swift +1 -1
  14. data/fastlane/swift/MatchfileProtocol.swift +5 -1
  15. data/fastlane/swift/Precheckfile.swift +1 -1
  16. data/fastlane/swift/Scanfile.swift +1 -1
  17. data/fastlane/swift/ScanfileProtocol.swift +29 -29
  18. data/fastlane/swift/Screengrabfile.swift +1 -1
  19. data/fastlane/swift/Snapshotfile.swift +1 -1
  20. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +18 -16
  21. data/frameit/lib/frameit/options.rb +1 -1
  22. data/match/lib/match.rb +1 -0
  23. data/match/lib/match/change_password.rb +7 -0
  24. data/match/lib/match/commands_generator.rb +15 -2
  25. data/match/lib/match/encryption.rb +3 -0
  26. data/match/lib/match/encryption/openssl.rb +2 -2
  27. data/match/lib/match/migrate.rb +97 -0
  28. data/match/lib/match/module.rb +1 -1
  29. data/match/lib/match/nuke.rb +22 -6
  30. data/match/lib/match/options.rb +19 -1
  31. data/match/lib/match/runner.rb +58 -15
  32. data/match/lib/match/spaceship_ensure.rb +6 -1
  33. data/match/lib/match/storage.rb +4 -0
  34. data/match/lib/match/storage/git_storage.rb +1 -10
  35. data/match/lib/match/storage/google_cloud_storage.rb +227 -0
  36. data/match/lib/match/storage/interface.rb +9 -3
  37. data/scan/lib/scan/options.rb +105 -86
  38. data/spaceship/README.md +20 -42
  39. metadata +38 -17
  40. data/fastlane_core/lib/fastlane_core/configuration/.config_item.rb.swp +0 -0
  41. data/pilot/lib/pilot/.options.rb.swp +0 -0
@@ -18,4 +18,4 @@ class Gymfile: GymfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.109.1
21
+ // Generated with fastlane 2.110.0
@@ -18,4 +18,4 @@ class Matchfile: MatchfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.109.1
21
+ // Generated with fastlane 2.110.0
@@ -21,6 +21,8 @@ protocol MatchfileProtocol: class {
21
21
  var skipDocs: Bool { get }
22
22
  var platform: String { get }
23
23
  var templateName: String? { get }
24
+ var googleCloudBucketName: String? { get }
25
+ var googleCloudKeysFile: String? { get }
24
26
  }
25
27
 
26
28
  extension MatchfileProtocol {
@@ -46,8 +48,10 @@ extension MatchfileProtocol {
46
48
  var skipDocs: Bool { return false }
47
49
  var platform: String { return "ios" }
48
50
  var templateName: String? { return nil }
51
+ var googleCloudBucketName: String? { return nil }
52
+ var googleCloudKeysFile: String? { return nil }
49
53
  }
50
54
 
51
55
  // Please don't remove the lines below
52
56
  // They are used to detect outdated files
53
- // FastlaneRunnerAPIVersion [0.9.2]
57
+ // FastlaneRunnerAPIVersion [0.9.3]
@@ -18,4 +18,4 @@ class Precheckfile: PrecheckfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.109.1
21
+ // Generated with fastlane 2.110.0
@@ -18,4 +18,4 @@ class Scanfile: ScanfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.109.1
21
+ // Generated with fastlane 2.110.0
@@ -1,16 +1,21 @@
1
1
  protocol ScanfileProtocol: class {
2
2
  var workspace: String? { get }
3
3
  var project: String? { get }
4
+ var scheme: String? { get }
4
5
  var device: String? { get }
5
- var toolchain: String? { get }
6
6
  var devices: [String]? { get }
7
7
  var skipDetectDevices: Bool { get }
8
- var scheme: String? { get }
8
+ var reinstallApp: Bool { get }
9
+ var appIdentifier: String? { get }
10
+ var onlyTesting: String? { get }
11
+ var skipTesting: String? { get }
12
+ var xctestrun: String? { get }
13
+ var toolchain: String? { get }
9
14
  var clean: Bool { get }
10
15
  var codeCoverage: Bool? { get }
11
16
  var addressSanitizer: Bool? { get }
12
17
  var threadSanitizer: Bool? { get }
13
- var skipBuild: Bool { get }
18
+ var openReport: Bool { get }
14
19
  var outputDirectory: String { get }
15
20
  var outputStyle: String? { get }
16
21
  var outputTypes: String { get }
@@ -20,47 +25,47 @@ protocol ScanfileProtocol: class {
20
25
  var suppressXcodeOutput: String? { get }
21
26
  var formatter: String? { get }
22
27
  var xcprettyArgs: String? { get }
28
+ var derivedDataPath: String? { get }
29
+ var shouldZipBuildProducts: Bool { get }
30
+ var resultBundle: Bool { get }
31
+ var useClangReportName: Bool { get }
23
32
  var maxConcurrentSimulators: Int? { get }
24
33
  var disableConcurrentTesting: Bool { get }
34
+ var skipBuild: Bool { get }
25
35
  var testWithoutBuilding: Bool? { get }
26
36
  var buildForTesting: Bool? { get }
27
- var xctestrun: String? { get }
28
- var derivedDataPath: String? { get }
29
- var shouldZipBuildProducts: Bool { get }
30
- var resultBundle: Bool { get }
31
37
  var sdk: String? { get }
32
- var openReport: Bool { get }
33
38
  var configuration: String? { get }
34
- var destination: String? { get }
35
39
  var xcargs: String? { get }
36
40
  var xcconfig: String? { get }
37
- var onlyTesting: String? { get }
38
- var skipTesting: String? { get }
39
41
  var slackUrl: String? { get }
40
42
  var slackChannel: String? { get }
41
43
  var slackMessage: String? { get }
42
44
  var skipSlack: Bool { get }
43
45
  var slackOnlyOnFailure: Bool { get }
44
- var useClangReportName: Bool { get }
46
+ var destination: String? { get }
45
47
  var customReportFileName: String? { get }
46
- var appIdentifier: String? { get }
47
- var reinstallApp: Bool { get }
48
48
  var failBuild: Bool { get }
49
49
  }
50
50
 
51
51
  extension ScanfileProtocol {
52
52
  var workspace: String? { return nil }
53
53
  var project: String? { return nil }
54
+ var scheme: String? { return nil }
54
55
  var device: String? { return nil }
55
- var toolchain: String? { return nil }
56
56
  var devices: [String]? { return nil }
57
57
  var skipDetectDevices: Bool { return false }
58
- var scheme: String? { return nil }
58
+ var reinstallApp: Bool { return false }
59
+ var appIdentifier: String? { return nil }
60
+ var onlyTesting: String? { return nil }
61
+ var skipTesting: String? { return nil }
62
+ var xctestrun: String? { return nil }
63
+ var toolchain: String? { return nil }
59
64
  var clean: Bool { return false }
60
65
  var codeCoverage: Bool? { return nil }
61
66
  var addressSanitizer: Bool? { return nil }
62
67
  var threadSanitizer: Bool? { return nil }
63
- var skipBuild: Bool { return false }
68
+ var openReport: Bool { return false }
64
69
  var outputDirectory: String { return "./test_output" }
65
70
  var outputStyle: String? { return nil }
66
71
  var outputTypes: String { return "html,junit" }
@@ -70,34 +75,29 @@ extension ScanfileProtocol {
70
75
  var suppressXcodeOutput: String? { return nil }
71
76
  var formatter: String? { return nil }
72
77
  var xcprettyArgs: String? { return nil }
78
+ var derivedDataPath: String? { return nil }
79
+ var shouldZipBuildProducts: Bool { return false }
80
+ var resultBundle: Bool { return false }
81
+ var useClangReportName: Bool { return false }
73
82
  var maxConcurrentSimulators: Int? { return nil }
74
83
  var disableConcurrentTesting: Bool { return false }
84
+ var skipBuild: Bool { return false }
75
85
  var testWithoutBuilding: Bool? { return nil }
76
86
  var buildForTesting: Bool? { return nil }
77
- var xctestrun: String? { return nil }
78
- var derivedDataPath: String? { return nil }
79
- var shouldZipBuildProducts: Bool { return false }
80
- var resultBundle: Bool { return false }
81
87
  var sdk: String? { return nil }
82
- var openReport: Bool { return false }
83
88
  var configuration: String? { return nil }
84
- var destination: String? { return nil }
85
89
  var xcargs: String? { return nil }
86
90
  var xcconfig: String? { return nil }
87
- var onlyTesting: String? { return nil }
88
- var skipTesting: String? { return nil }
89
91
  var slackUrl: String? { return nil }
90
92
  var slackChannel: String? { return nil }
91
93
  var slackMessage: String? { return nil }
92
94
  var skipSlack: Bool { return false }
93
95
  var slackOnlyOnFailure: Bool { return false }
94
- var useClangReportName: Bool { return false }
96
+ var destination: String? { return nil }
95
97
  var customReportFileName: String? { return nil }
96
- var appIdentifier: String? { return nil }
97
- var reinstallApp: Bool { return false }
98
98
  var failBuild: Bool { return true }
99
99
  }
100
100
 
101
101
  // Please don't remove the lines below
102
102
  // They are used to detect outdated files
103
- // FastlaneRunnerAPIVersion [0.9.6]
103
+ // FastlaneRunnerAPIVersion [0.9.7]
@@ -18,4 +18,4 @@ class Screengrabfile: ScreengrabfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.109.1
21
+ // Generated with fastlane 2.110.0
@@ -18,4 +18,4 @@ class Snapshotfile: SnapshotfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.109.1
21
+ // Generated with fastlane 2.110.0
@@ -162,7 +162,7 @@ module FastlaneCore
162
162
  [
163
163
  '"' + Helper.transporter_path + '"',
164
164
  "-m upload",
165
- "-u \"#{username}\"",
165
+ "-u #{username.shellescape}",
166
166
  "-p #{shell_escaped_password(password)}",
167
167
  "-f \"#{source}\"",
168
168
  additional_upload_parameters, # that's here, because the user might overwrite the -t option
@@ -177,7 +177,7 @@ module FastlaneCore
177
177
  [
178
178
  '"' + Helper.transporter_path + '"',
179
179
  "-m lookupMetadata",
180
- "-u \"#{username}\"",
180
+ "-u #{username.shellescape}",
181
181
  "-p #{shell_escaped_password(password)}",
182
182
  "-apple_id #{apple_id}",
183
183
  "-destination '#{destination}'",
@@ -203,21 +203,23 @@ module FastlaneCore
203
203
  private
204
204
 
205
205
  def shell_escaped_password(password)
206
- # because the shell handles passwords with single-quotes incorrectly, use gsub to replace ShellEscape'd single-quotes of this form:
207
- # \'
208
- # with a sequence that wraps the escaped single-quote in double-quotes:
209
- # '"\'"'
210
- # this allows us to properly handle passwords with single-quotes in them
211
- # we use the 'do' version of gsub, because two-param version interprets the replace text as a pattern and does the wrong thing
212
- password = Shellwords.escape(password).gsub("\\'") do
213
- "'\"\\'\"'"
214
- end
215
-
216
- # wrap the fully-escaped password in single quotes, since the transporter expects a escaped password string
217
- # (which must be single-quoted for the shell's benefit [on non-Windows platforms])
218
- password = "'" + password + "'" unless Helper.windows?
206
+ password = password.shellescape
207
+ unless Helper.windows?
208
+ # because the shell handles passwords with single-quotes incorrectly, use `gsub` to replace `shellescape`'d single-quotes of this form:
209
+ # \'
210
+ # with a sequence that wraps the escaped single-quote in double-quotes:
211
+ # '"\'"'
212
+ # this allows us to properly handle passwords with single-quotes in them
213
+ # background: https://stackoverflow.com/questions/1250079/how-to-escape-single-quotes-within-single-quoted-strings/1250098#1250098
214
+ password = password.gsub("\\'") do
215
+ # we use the 'do' version of gsub, because two-param version interprets the replace text as a pattern and does the wrong thing
216
+ "'\"\\'\"'"
217
+ end
219
218
 
220
- password
219
+ # wrap the fully-escaped password in single quotes, since the transporter expects a escaped password string (which must be single-quoted for the shell's benefit)
220
+ password = "'" + password + "'"
221
+ end
222
+ return password
221
223
  end
222
224
  end
223
225
 
@@ -46,7 +46,7 @@ module Frameit
46
46
  default_value: false),
47
47
  FastlaneCore::ConfigItem.new(key: :force_orientation_block,
48
48
  type: :string_callback,
49
- description: "[Advanced] A block to customize your screnshots' device orientation",
49
+ description: "[Advanced] A block to customize your screenshots' device orientation",
50
50
  display_in_shell: false,
51
51
  optional: true,
52
52
  default_value: proc do |filename|
@@ -7,6 +7,7 @@ require_relative 'match/generator'
7
7
  require_relative 'match/setup'
8
8
  require_relative 'match/spaceship_ensure'
9
9
  require_relative 'match/change_password'
10
+ require_relative 'match/migrate'
10
11
  require_relative 'match/storage'
11
12
  require_relative 'match/encryption'
12
13
  require_relative 'match/module'
@@ -7,6 +7,13 @@ module Match
7
7
  # These functions should only be used while in (UI.) interactive mode
8
8
  class ChangePassword
9
9
  def self.update(params: nil)
10
+ if params[:storage_mode] != "git"
11
+ # Only git supports changing the password
12
+ # All other storage options will most likely use more advanced
13
+ # ways to encrypt files
14
+ UI.user_error!("Only git-based match allows you to change your password, current `storage_mode` is #{params[:storage_mode]}")
15
+ end
16
+
10
17
  ensure_ui_interactive
11
18
 
12
19
  to = ChangePassword.ask_password(message: "New passphrase for Git Repo: ", confirm: true)
@@ -1,17 +1,19 @@
1
1
  require 'commander'
2
2
 
3
3
  require 'fastlane_core/configuration/configuration'
4
- require_relative 'module'
5
4
 
6
5
  require_relative 'nuke'
7
6
  require_relative 'change_password'
8
7
  require_relative 'setup'
9
8
  require_relative 'runner'
10
9
  require_relative 'options'
10
+ require_relative 'migrate'
11
11
 
12
12
  require_relative 'storage'
13
13
  require_relative 'encryption'
14
14
 
15
+ require_relative 'module'
16
+
15
17
  HighLine.track_eof = false
16
18
 
17
19
  module Match
@@ -125,11 +127,22 @@ module Match
125
127
  git_url: params[:git_url],
126
128
  working_directory: storage.working_directory
127
129
  })
128
- encryption.decrypt_files
130
+ encryption.decrypt_files if encryption
129
131
  UI.success("Repo is at: '#{storage.working_directory}'")
130
132
  end
131
133
  end
132
134
 
135
+ command :migrate do |c|
136
+ c.syntax = "fastlane match migrate"
137
+ c.description = "Migrate from one storage backend to another one"
138
+
139
+ FastlaneCore::CommanderGenerator.new.generate(Match::Options.available_options, command: c)
140
+
141
+ c.action do |args, options|
142
+ Match::Migrate.new.migrate(args, options)
143
+ end
144
+ end
145
+
133
146
  command "nuke" do |c|
134
147
  # We have this empty command here, since otherwise the normal `match` command will be executed
135
148
  c.syntax = "fastlane match nuke"
@@ -11,6 +11,9 @@ module Match
11
11
  # to keychain_name for the name of the keychain entry
12
12
  params[:keychain_name] = params[:git_url]
13
13
  return Encryption::OpenSSL.configure(params)
14
+ },
15
+ "google_cloud" => lambda { |params|
16
+ return nil
14
17
  }
15
18
  }
16
19
  end
@@ -4,8 +4,8 @@ require 'securerandom'
4
4
  require 'security'
5
5
  require 'shellwords'
6
6
 
7
- require_relative '../module'
8
7
  require_relative '../change_password'
8
+ require_relative '../module'
9
9
 
10
10
  module Match
11
11
  module Encryption
@@ -144,7 +144,7 @@ module Match
144
144
  rescue => error
145
145
  fallback_hash_algorithm = "SHA256"
146
146
  if hash_algorithm != fallback_hash_algorithm
147
- decrypt_specific_file(path, password, fallback_hash_algorithm)
147
+ decrypt_specific_file(path: path, password: password, hash_algorithm: fallback_hash_algorithm)
148
148
  else
149
149
  UI.error(error.to_s)
150
150
  UI.crash!("Error decrypting '#{path}'")
@@ -0,0 +1,97 @@
1
+ require_relative 'options'
2
+ require_relative 'spaceship_ensure'
3
+ require_relative 'encryption'
4
+ require_relative 'storage'
5
+ require_relative 'module'
6
+ require 'fileutils'
7
+
8
+ module Match
9
+ class Migrate
10
+ def migrate(args, options)
11
+ params = FastlaneCore::Configuration.create(Match::Options.available_options, options.__hash__)
12
+ loaded_matchfile = params.load_configuration_file("Matchfile")
13
+
14
+ ensure_parameters_are_valid(params)
15
+
16
+ # We init the Google storage client before the git client
17
+ # to ask for all the missing inputs *before* cloning the git repo
18
+ google_cloud_storage = Storage.for_mode("google_cloud", {
19
+ google_cloud_bucket_name: params[:google_cloud_bucket_name],
20
+ google_cloud_keys_file: params[:google_cloud_keys_file]
21
+ })
22
+
23
+ git_storage = Storage.for_mode("git", {
24
+ git_url: params[:git_url],
25
+ shallow_clone: params[:shallow_clone],
26
+ git_branch: params[:git_branch],
27
+ clone_branch_directly: params[:clone_branch_directly]
28
+ })
29
+ git_storage.download
30
+
31
+ encryption = Encryption.for_storage_mode(params[:storage_mode], {
32
+ git_url: params[:git_url],
33
+ working_directory: git_storage.working_directory
34
+ })
35
+ encryption.decrypt_files if encryption
36
+ UI.success("Decrypted the git repo to '#{git_storage.working_directory}'")
37
+
38
+ google_cloud_storage.download
39
+
40
+ # Note how we always prefix the path in Google Cloud with the Team ID
41
+ # while on Git we recommend using the git branch instead. As there is
42
+ # no concept of branches in Google Cloud Storage (omg thanks), we use
43
+ # the team id properly
44
+ spaceship = SpaceshipEnsure.new(params[:username], params[:team_id], params[:team_name])
45
+ team_id = spaceship.team_id
46
+ UI.message("Detected team ID '#{team_id}' to use for Google Cloud Storage...")
47
+
48
+ files_to_commit = []
49
+ Dir.chdir(git_storage.working_directory) do
50
+ Dir[File.join("**", "*")].each do |current_file|
51
+ next if File.directory?(current_file)
52
+
53
+ to_path = File.join(google_cloud_storage.working_directory, team_id, current_file)
54
+ FileUtils.mkdir_p(File.expand_path("..", to_path))
55
+
56
+ if File.exist?(to_path)
57
+ UI.user_error!("Looks like file already exists on Google Cloud Storage at path '#{to_path}', stopping the migration process. Please make sure the bucket is empty, or at least doesn't contain any files related to the same Team ID")
58
+ end
59
+ FileUtils.cp(current_file, to_path)
60
+
61
+ files_to_commit << to_path
62
+ end
63
+ end
64
+
65
+ google_cloud_storage.save_changes!(files_to_commit: files_to_commit)
66
+
67
+ UI.success("Successfully migrated your code signing certificates and provisioning profiles to Google Cloud Storage")
68
+ UI.success("Make sure to update your configuration to specify the `storage_mode`, as well as the bucket to use.")
69
+ UI.message("")
70
+ if loaded_matchfile
71
+ UI.message("Update your Matchfile at path '#{loaded_matchfile.configfile_path}':")
72
+ UI.message("")
73
+ UI.command_output("\t\tstorage_mode \"google_cloud\"")
74
+ UI.command_output("\t\tgoogle_cloud_bucket_name \"#{google_cloud_storage.bucket_name}\"")
75
+ else
76
+ UI.message("Update your Fastfile `match` call to include")
77
+ UI.message("")
78
+ UI.command_output("\t\tstorage_mode: \"google_cloud\",")
79
+ UI.command_output("\t\tgoogle_cloud_bucket_name: \"#{google_cloud_storage.bucket_name}\",")
80
+ end
81
+ UI.message("")
82
+ UI.success("You can also remove the `git_url`, as well as any other git related configurations from your Fastfile and Matchfile")
83
+ UI.message("")
84
+ UI.input("Please make sure to read the above and confirm with enter")
85
+ end
86
+
87
+ def ensure_parameters_are_valid(params)
88
+ if params[:readonly]
89
+ UI.user_error!("`fastlane match migrate` doesn't work in `readonly` mode")
90
+ end
91
+
92
+ if params[:storage_mode] != "git"
93
+ UI.user_error!("`fastlane match migrate` only allows migration from `git` to `google_cloud` right now, looks like your currently selected `storage_mode` is '#{params[:storage_mode]}'")
94
+ end
95
+ end
96
+ end
97
+ end