fastlane 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c339ea21edfc2acca2f46b9a751d03795647c3f6
4
- data.tar.gz: 9c35a144521c7f03f7a9c7fe5441026ed9882d59
3
+ metadata.gz: beef52022ff1b725c056cb6d6b76940e08a80e47
4
+ data.tar.gz: 7d3ae10b2bd5e238fb9476d14ea3133f53c3fb04
5
5
  SHA512:
6
- metadata.gz: cc15fe2094ff6748d3c9f9ba7fc029b60eb7faafe91b9f7c407a749232fed51ab25a852f6b69b746ae4b0b3cd296cc260aa9b4e291385a09c530369978a05beb
7
- data.tar.gz: 4849594603cd554346c5ddc54d97a1365903df26f1a14507719ecd2434ae780c79515a7c8c88c5d0392f5bfffac7da8694bc63487d3abb972bbdd965499fcd06
6
+ metadata.gz: 0cd216d8caabb4f7cbfe99e0d9adf6bba9269fd75f0561939c4f7e0675c9b6bc156f9ec54de1533f3f2d1ef2f17567721799654ffbe2af178dd4e4fb7f086b59
7
+ data.tar.gz: f882d73eb82fc32a530ae6538060c3c9895fe5b222fcbab700253a8dd9e1f1145ade69dc74b0b11453dffc4942640669e520b9fefd4b2ab98d977b163e71dbd8
@@ -24,6 +24,12 @@ module Fastlane
24
24
  "A short description with <= 80 characters of what this action does"
25
25
  end
26
26
 
27
+ def self.details
28
+ # Optional:
29
+ # this is your change to provide a more detailed description of this action
30
+ "You can use this action to do cool things..."
31
+ end
32
+
27
33
  def self.available_options
28
34
  # Define all options your action supports.
29
35
 
data/lib/fastlane.rb CHANGED
@@ -5,6 +5,7 @@ require 'fastlane/fast_file'
5
5
  require 'fastlane/dependency_checker'
6
6
  require 'fastlane/runner'
7
7
  require 'fastlane/setup'
8
+ require 'fastlane/lane'
8
9
  require 'fastlane/fastlane_folder'
9
10
  require 'fastlane/junit_generator'
10
11
  require 'fastlane/lane_manager'
@@ -8,10 +8,7 @@ module Fastlane
8
8
  ENVIRONMENT = :ENVIRONMENT
9
9
  end
10
10
 
11
- def self.executed_actions
12
- @executed_actions ||= []
13
- end
14
-
11
+ # Helper Methods
15
12
  def self.git_author
16
13
  s = `git log --name-status HEAD^..HEAD`
17
14
  s = s.match(/Author:.*<(.*)>/)[1]
@@ -27,6 +24,18 @@ module Fastlane
27
24
  nil
28
25
  end
29
26
 
27
+ # Returns the current git branch - can be replaced using the environment variable `GIT_BRANCH`
28
+ def self.git_branch
29
+ return ENV['GIT_BRANCH'] if ENV['GIT_BRANCH'].to_s.length > 0 # set by Jenkins
30
+ s = `git rev-parse --abbrev-ref HEAD`
31
+ return s.to_s.strip if s.to_s.length > 0
32
+ nil
33
+ end
34
+
35
+
36
+ def self.executed_actions
37
+ @executed_actions ||= []
38
+ end
30
39
 
31
40
  # The shared hash can be accessed by any action and contains information like the screenshots path or beta URL
32
41
  def self.lane_context
@@ -109,14 +118,6 @@ module Fastlane
109
118
  Encoding.default_internal = previous_encoding.last
110
119
  end
111
120
 
112
- # Returns the current git branch - can be replaced using the environment variable `GIT_BRANCH`
113
- def self.git_branch
114
- return ENV['GIT_BRANCH'] if ENV['GIT_BRANCH'].to_s.length > 0 # set by Jenkins
115
- s = `git rev-parse --abbrev-ref HEAD`
116
- return s.to_s.strip if s.to_s.length > 0
117
- nil
118
- end
119
-
120
121
  # returns a list of official integrations
121
122
  def self.get_all_official_actions
122
123
  Dir[File.expand_path '*.rb', File.dirname(__FILE__)].collect do |file|
@@ -7,9 +7,8 @@ module Fastlane
7
7
  class EnsureGitBranchAction < Action
8
8
  def self.run(params)
9
9
  branch = params[:branch]
10
-
11
10
  if Actions.git_branch != branch
12
- raise "Git is not on the `#{branch}` branch! Please ensure the repo is checked out to the correct branch.".red
11
+ raise "Git is not on the `#{branch}` branch, but on `#{Actions.git_branch}`! Please ensure the repo is checked out to the correct branch.".red
13
12
  else
14
13
  Helper.log.info "Git branch is `#{branch}`, all good! 💪".green
15
14
  end
@@ -0,0 +1,112 @@
1
+ module Fastlane
2
+ module Actions
3
+ module SharedValues
4
+ GET_GITHUB_RELEASE_INFO = :GET_GITHUB_RELEASE_INFO
5
+ end
6
+
7
+ class GetGithubReleaseAction < Action
8
+ def self.run(params)
9
+ Helper.log.info "Verifying release on GitHub (#{params[:url]}: #{params[:version]})"
10
+ require 'excon'
11
+ result = JSON.parse(Excon.get("https://api.github.com/repos/#{params[:url]}/releases").body)
12
+ result.each do |current|
13
+ if current['tag_name'] == params[:version]
14
+ # Found it
15
+ if current['body'].to_s.length > 0
16
+ Actions.lane_context[SharedValues::GET_GITHUB_RELEASE_INFO] = current
17
+ Helper.log.info "Version is already live on GitHub.com 🚁"
18
+ return current
19
+ else
20
+ raise "No release notes found for #{params[:version]}"
21
+ end
22
+ end
23
+ end
24
+
25
+ Helper.log.error "Couldn't find GitHub release #{params[:version]}".yellow
26
+ return nil
27
+ end
28
+
29
+ #####################################################
30
+ # @!group Documentation
31
+ #####################################################
32
+
33
+ def self.description
34
+ "This will verify if a given release version is avialable on GitHub"
35
+ end
36
+
37
+ def self.details
38
+ sample = '
39
+ {"url"=>"https://api.github.com/repos/KrauseFx/fastlane/releases/1537713",
40
+ "assets_url"=>"https://api.github.com/repos/KrauseFx/fastlane/releases/1537713/assets",
41
+ "upload_url"=>"https://uploads.github.com/repos/KrauseFx/fastlane/releases/1537713/assets{?name}",
42
+ "html_url"=>"https://github.com/KrauseFx/fastlane/releases/tag/1.8.0",
43
+ "id"=>1537713,
44
+ "tag_name"=>"1.8.0",
45
+ "target_commitish"=>"master",
46
+ "name"=>"1.8.0 Switch Lanes & Pass Parameters",
47
+ "draft"=>false,
48
+ "author"=>
49
+ {"login"=>"KrauseFx",
50
+ "id"=>869950,
51
+ "avatar_url"=>"https://avatars.githubusercontent.com/u/869950?v=3",
52
+ "gravatar_id"=>"",
53
+ "url"=>"https://api.github.com/users/KrauseFx",
54
+ "html_url"=>"https://github.com/KrauseFx",
55
+ "followers_url"=>"https://api.github.com/users/KrauseFx/followers",
56
+ "following_url"=>"https://api.github.com/users/KrauseFx/following{/other_user}",
57
+ "gists_url"=>"https://api.github.com/users/KrauseFx/gists{/gist_id}",
58
+ "starred_url"=>"https://api.github.com/users/KrauseFx/starred{/owner}{/repo}",
59
+ "subscriptions_url"=>"https://api.github.com/users/KrauseFx/subscriptions",
60
+ "organizations_url"=>"https://api.github.com/users/KrauseFx/orgs",
61
+ "repos_url"=>"https://api.github.com/users/KrauseFx/repos",
62
+ "events_url"=>"https://api.github.com/users/KrauseFx/events{/privacy}",
63
+ "received_events_url"=>"https://api.github.com/users/KrauseFx/received_events",
64
+ "type"=>"User",
65
+ "site_admin"=>false},
66
+ "prerelease"=>false,
67
+ "created_at"=>"2015-07-14T23:33:01Z",
68
+ "published_at"=>"2015-07-14T23:44:10Z",
69
+ "assets"=>[],
70
+ "tarball_url"=>"https://api.github.com/repos/KrauseFx/fastlane/tarball/1.8.0",
71
+ "zipball_url"=>"https://api.github.com/repos/KrauseFx/fastlane/zipball/1.8.0",
72
+ "body"=>
73
+ "This is one of the biggest updates of `fastlane` yet"
74
+ }'
75
+
76
+ [
77
+ "This will return all information about a release. For example:",
78
+ sample
79
+ ].join("\n")
80
+ end
81
+
82
+ def self.output
83
+ [
84
+ ['GET_GITHUB_RELEASE_INFO', 'Contains all the information about this release']
85
+ ]
86
+ end
87
+
88
+ def self.available_options
89
+ [
90
+ FastlaneCore::ConfigItem.new(key: :url,
91
+ env_name: "FL_GET_GITHUB_RELEASE_URL",
92
+ description: "The path to your repo, e.g. 'KrauseFx/fastlane'",
93
+ verify_block: Proc.new do |value|
94
+ raise "Please only pass the path, e.g. 'KrauseFx/fastlane'".red if value.include?"github.com"
95
+ raise "Please only pass the path, e.g. 'KrauseFx/fastlane'".red if value.split('/').count != 2
96
+ end),
97
+ FastlaneCore::ConfigItem.new(key: :version,
98
+ env_name: "FL_GET_GITHUB_RELEASE_VERSION",
99
+ description: "The version tag of the release to check")
100
+ ]
101
+ end
102
+
103
+ def self.authors
104
+ ["KrauseFx"]
105
+ end
106
+
107
+ def self.is_supported?(platform)
108
+ true
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,41 @@
1
+ module Fastlane
2
+ module Actions
3
+ module SharedValues
4
+
5
+ end
6
+
7
+ class GitBranchAction < Action
8
+ def self.run(params)
9
+ ENV['GIT_BRANCH'] or `git symbolic-ref HEAD --short 2>/dev/null`.strip
10
+ end
11
+
12
+ #####################################################
13
+ # @!group Documentation
14
+ #####################################################
15
+
16
+ def self.description
17
+ "Returns the name of the current git branch"
18
+ end
19
+
20
+ def self.details
21
+ "If no branch could be found, this action will return nil"
22
+ end
23
+
24
+ def self.available_options
25
+ []
26
+ end
27
+
28
+ def self.output
29
+ []
30
+ end
31
+
32
+ def self.authors
33
+ ["KrauseFx"]
34
+ end
35
+
36
+ def self.is_supported?(platform)
37
+ true
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ module Fastlane
2
+ module Actions
3
+ class PromptAction < Action
4
+ def self.run(params)
5
+ params[:text] += " (y/n)" if params[:boolean]
6
+ Helper.log.info params[:text]
7
+
8
+ user_input = params[:ci_input] if Helper.is_ci?
9
+ user_input ||= STDIN.gets.chomp.strip
10
+
11
+ user_input = (user_input.downcase == 'y') if params[:boolean]
12
+
13
+ return user_input
14
+ end
15
+
16
+ #####################################################
17
+ # @!group Documentation
18
+ #####################################################
19
+
20
+ def self.description
21
+ "Ask the user for a value or for confirmation"
22
+ end
23
+
24
+ def self.details
25
+ [
26
+ "You can use `prompt` to ask the user for a value or to just let the user confirm the next step",
27
+ "When this is executed on a CI service, the passed `ci_input` value will be returned"
28
+ ].join("\n")
29
+ end
30
+
31
+ def self.available_options
32
+ [
33
+ FastlaneCore::ConfigItem.new(key: :text,
34
+ description: "The text that will be displayed to the user"),
35
+ FastlaneCore::ConfigItem.new(key: :ci_input,
36
+ description: "The default text that will be used when being executed on a CI service",
37
+ default_value: ''),
38
+ FastlaneCore::ConfigItem.new(key: :boolean,
39
+ description: "Is that a boolean question (yes/no)? This will add (y/n) at the end",
40
+ default_value: false,
41
+ is_string: false)
42
+ ]
43
+ end
44
+
45
+ def self.output
46
+ []
47
+ end
48
+
49
+ def self.authors
50
+ ["KrauseFx"]
51
+ end
52
+
53
+ def self.is_supported?(platform)
54
+ true
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,25 @@
1
+ module Fastlane
2
+ module Actions
3
+ class PutsAction < Action
4
+ def self.run(params)
5
+ Helper.log.info params.join(' ')
6
+ end
7
+
8
+ #####################################################
9
+ # @!group Documentation
10
+ #####################################################
11
+
12
+ def self.description
13
+ "Prints out the given text"
14
+ end
15
+
16
+ def self.authors
17
+ ["KrauseFx"]
18
+ end
19
+
20
+ def self.is_supported?(platform)
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -82,6 +82,11 @@ module Fastlane
82
82
  description: "Remove some of the default payloads. More information about the available payloads on GitHub",
83
83
  optional: true,
84
84
  is_string: false),
85
+ FastlaneCore::ConfigItem.new(key: :attachment_properties,
86
+ env_name: "FL_SLACK_ATTACHMENT_PROPERTIES",
87
+ description: "Merge additional properties in the slack attachment, see https://api.slack.com/docs/attachments",
88
+ default_value: {},
89
+ is_string: false),
85
90
  FastlaneCore::ConfigItem.new(key: :success,
86
91
  env_name: "FL_SLACK_SUCCESS",
87
92
  description: "Was this build successful? (true/false)",
@@ -128,7 +133,7 @@ module Fastlane
128
133
  # test_result
129
134
  if should_add_payload[:test_result]
130
135
  slack_attachment[:fields] << {
131
- title: 'Test Result',
136
+ title: 'Result',
132
137
  value: (options[:success] ? 'Success' : 'Error'),
133
138
  short: true
134
139
  }
@@ -165,7 +170,16 @@ module Fastlane
165
170
  }
166
171
  end
167
172
 
168
- slack_attachment
173
+ # merge additional properties
174
+ deep_merge(slack_attachment, options[:attachment_properties])
175
+ end
176
+
177
+ # Adapted from http://stackoverflow.com/a/30225093/158525
178
+ def self.deep_merge(a, b)
179
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ?
180
+ v1.merge(v2, &merger) : Array === v1 && Array === v2 ?
181
+ v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
182
+ a.merge(b, &merger)
169
183
  end
170
184
  end
171
185
  end
@@ -11,17 +11,17 @@ module Fastlane
11
11
 
12
12
  output << "# Available Actions"
13
13
 
14
- all_keys = ff.runner.description_blocks.keys.reject(&:nil?)
14
+ all_keys = ff.runner.lanes.keys.reject(&:nil?)
15
15
  all_keys.unshift(nil) # because we want root elements on top. always! They have key nil
16
16
 
17
17
  all_keys.each do |platform|
18
18
  output << "## #{formatted_platform(platform)}" if platform
19
19
 
20
- value = ff.runner.description_blocks[platform]
20
+ value = ff.runner.lanes[platform]
21
21
 
22
22
  if value
23
- value.each do |lane, description|
24
- output << render(platform, lane, description)
23
+ value.each do |lane_name, lane|
24
+ output << render(platform, lane_name, lane.description.join("\n\n"))
25
25
  end
26
26
 
27
27
  output << ""
@@ -1,7 +1,12 @@
1
1
  module Fastlane
2
2
  class FastFile
3
+ # Stores all relevant information from the currently running process
3
4
  attr_accessor :runner
4
5
 
6
+ # the platform in which we're currently in when parsing the Fastfile
7
+ # This is used to identify the platform in which the lane is in
8
+ attr_accessor :current_platform
9
+
5
10
  SharedValues = Fastlane::Actions::SharedValues
6
11
 
7
12
  # @return The runner which can be executed to trigger the given actions
@@ -34,10 +39,10 @@ module Fastlane
34
39
  def lane(lane_name, &block)
35
40
  raise "You have to pass a block using 'do' for lane '#{lane_name}'. Make sure you read the docs on GitHub.".red unless block
36
41
 
37
- desc = desc_collection.join("\n\n")
38
- platform = @current_platform
39
-
40
- @runner.set_block(lane_name, platform, block, desc)
42
+ self.runner.add_lane(Lane.new(platform: self.current_platform,
43
+ block: block,
44
+ description: desc_collection,
45
+ name: lane_name))
41
46
 
42
47
  @desc_collection = nil # reset the collected description again for the next lane
43
48
  end
@@ -46,11 +51,11 @@ module Fastlane
46
51
  def platform(platform_name, &block)
47
52
  SupportedPlatforms.verify!platform_name
48
53
 
49
- @current_platform = platform_name
54
+ self.current_platform = platform_name
50
55
 
51
56
  block.call
52
57
 
53
- @current_platform = nil
58
+ self.current_platform = nil
54
59
  end
55
60
 
56
61
  # Is executed before each test run
@@ -68,61 +73,6 @@ module Fastlane
68
73
  @runner.set_error(@current_platform, block)
69
74
  end
70
75
 
71
- def try_switch_to_lane(new_lane, parameters)
72
- current_platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
73
- block = @runner.blocks.fetch(current_platform, {}).fetch(new_lane, nil)
74
- platform_nil = (block == nil) # used for the output
75
- block ||= @runner.blocks.fetch(nil, {}).fetch(new_lane, nil) # fallback to general lane for multiple platforms
76
- if block
77
- pretty = [new_lane]
78
- pretty = [current_platform, new_lane] unless platform_nil
79
- Helper.log.info "Cruising over to lane '#{pretty.join(' ')}' 🚖".green
80
- collector.did_launch_action(:lane_switch)
81
- result = block.call(parameters.first || {}) # to always pass a hash
82
- original_lane = Actions.lane_context[Actions::SharedValues::LANE_NAME]
83
- Helper.log.info "Cruising back to lane '#{original_lane}' 🚘".green
84
- return result
85
- else
86
- # No action and no lane, raising an exception now
87
- raise "Could not find action or lane '#{new_lane}'. Check out the README for more details: https://github.com/KrauseFx/fastlane".red
88
- end
89
- end
90
-
91
- def execute_action(method_sym, class_ref, arguments)
92
- collector.did_launch_action(method_sym)
93
-
94
- step_name = class_ref.step_text rescue nil
95
- step_name = method_sym.to_s unless step_name
96
-
97
- verify_supported_os(method_sym, class_ref)
98
-
99
- Helper.log_alert("Step: " + step_name)
100
-
101
- begin
102
- Dir.chdir('..') do # go up from the fastlane folder, to the project folder
103
- Actions.execute_action(method_sym) do
104
- # arguments is an array by default, containing an hash with the actual parameters
105
- # Since we usually just need the passed hash, we'll just use the first object if there is only one
106
- if arguments.count == 0
107
- arguments = ConfigurationHelper.parse(class_ref, {}) # no parameters => empty hash
108
- elsif arguments.count == 1 and arguments.first.kind_of?Hash
109
- arguments = ConfigurationHelper.parse(class_ref, arguments.first) # Correct configuration passed
110
- elsif not class_ref.available_options
111
- # This action does not use the new action format
112
- # Just passing the arguments to this method
113
- else
114
- raise "You have to pass the options for '#{method_sym}' in a different way. Please check out the current documentation on GitHub!".red
115
- end
116
-
117
- class_ref.run(arguments)
118
- end
119
- end
120
- rescue => ex
121
- collector.did_raise_error(method_sym)
122
- raise ex
123
- end
124
- end
125
-
126
76
  # Is used to look if the method is implemented as an action
127
77
  def method_missing(method_sym, *arguments, &_block)
128
78
  # First, check if there is a predefined method in the actions folder
@@ -132,14 +82,14 @@ module Fastlane
132
82
  class_ref = Fastlane::Actions.const_get(class_name)
133
83
  if class_ref && class_ref.respond_to?(:run)
134
84
  # Action is available, now execute it
135
- return execute_action(method_sym, class_ref, arguments)
85
+ return self.runner.execute_action(method_sym, class_ref, arguments)
136
86
  else
137
87
  raise "Action '#{method_sym}' of class '#{class_name}' was found, but has no `run` method.".red
138
88
  end
139
89
  rescue NameError => ex
140
90
  # Action not found
141
91
  # Is there a lane under this name?
142
- return try_switch_to_lane(method_sym, arguments)
92
+ return self.runner.try_switch_to_lane(method_sym, arguments)
143
93
  end
144
94
  end
145
95
 
@@ -147,21 +97,16 @@ module Fastlane
147
97
  # @!group Other things
148
98
  #####################################################
149
99
 
150
- # Speak out loud
151
- def say(value)
152
- # Overwrite this, since there is already a 'say' method defined in the Ruby standard library
153
- value ||= yield
154
- Actions.execute_action('say') do
155
- Fastlane::Actions::SayAction.run([value])
156
- end
100
+ def collector
101
+ runner.collector
157
102
  end
158
103
 
159
104
  # Is the given key a platform block or a lane?
160
105
  def is_platform_block?(key)
161
106
  raise 'No key given'.red unless key
162
107
 
163
- return false if (self.runner.blocks[nil][key.to_sym] rescue false)
164
- return true if self.runner.blocks[key.to_sym].kind_of?Hash
108
+ return false if (self.runner.lanes[nil][key.to_sym] rescue false)
109
+ return true if self.runner.lanes[key.to_sym].kind_of?Hash
165
110
 
166
111
  raise "Could not find '#{key}'. Available lanes: #{self.runner.available_lanes.join(', ')}".red
167
112
  end
@@ -179,34 +124,35 @@ module Fastlane
179
124
  end
180
125
  end
181
126
 
182
- def verify_supported_os(name, class_ref)
183
- if class_ref.respond_to?(:is_supported?)
184
- if Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
185
- # This value is filled in based on the executed platform block. Might be nil when lane is in root of Fastfile
186
- platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
187
-
188
- unless class_ref.is_supported?(platform)
189
- raise "Action '#{name}' doesn't support required operating system '#{platform}'.".red
190
- end
191
- end
192
- end
127
+ def desc(string)
128
+ desc_collection << string
193
129
  end
194
130
 
195
- # Fastfile was finished executing
196
- def did_finish
197
- collector.did_finish
131
+ def desc_collection
132
+ @desc_collection ||= []
198
133
  end
199
134
 
200
- def desc(string)
201
- desc_collection << string
202
- end
135
+ #####################################################
136
+ # @!group Overwriting Ruby methods
137
+ #####################################################
203
138
 
204
- def collector
205
- @collector ||= ActionCollector.new
139
+ # Speak out loud
140
+ def say(value)
141
+ # Overwrite this, since there is already a 'say' method defined in the Ruby standard library
142
+ value ||= yield
143
+ Actions.execute_action('say') do
144
+ collector.did_launch_action(:say)
145
+ Fastlane::Actions::SayAction.run([value])
146
+ end
206
147
  end
207
148
 
208
- def desc_collection
209
- @desc_collection ||= []
149
+ def puts(value)
150
+ # Overwrite this, since there is already a 'puts' method defined in the Ruby standard library
151
+ value ||= yield
152
+ Actions.execute_action('puts') do
153
+ collector.did_launch_action(:pus)
154
+ Fastlane::Actions::PutsAction.run([value])
155
+ end
210
156
  end
211
157
  end
212
158
  end
@@ -4,11 +4,13 @@ module Fastlane
4
4
 
5
5
  # Path to the fastlane folder containing the Fastfile and other configuration files
6
6
  def self.path
7
- return "./#{FOLDER_NAME}/" if File.directory?("./#{FOLDER_NAME}/")
8
- return "./.#{FOLDER_NAME}/" if File.directory?("./.#{FOLDER_NAME}/") # hidden folder
9
- return './' if File.basename(Dir.getwd) == FOLDER_NAME && File.exist?('Fastfile') # inside the folder
10
- return './' if File.basename(Dir.getwd) == ".#{FOLDER_NAME}" && File.exist?('Fastfile') # inside the folder and hidden
11
- nil
7
+ value ||= "./#{FOLDER_NAME}/" if File.directory?("./#{FOLDER_NAME}/")
8
+ value ||= "./.#{FOLDER_NAME}/" if File.directory?("./.#{FOLDER_NAME}/") # hidden folder
9
+ value ||= "./" if File.basename(Dir.getwd) == FOLDER_NAME && File.exist?('Fastfile') # inside the folder
10
+ value ||= "./" if File.basename(Dir.getwd) == ".#{FOLDER_NAME}" && File.exist?('Fastfile') # inside the folder and hidden
11
+
12
+ value = nil if Helper.is_test? # this is required, as the tests would use the ./fastlane folder otherwise
13
+ return value
12
14
  end
13
15
 
14
16
  # Does a fastlane configuration already exist?
@@ -0,0 +1,33 @@
1
+ module Fastlane
2
+ # Represents a lane
3
+ class Lane
4
+ attr_accessor :platform
5
+
6
+ attr_accessor :name
7
+
8
+ # @return (Array) An array containing the description of this lane
9
+ # Each item of the array is one line
10
+ attr_accessor :description
11
+
12
+ attr_accessor :block
13
+
14
+ def initialize(platform: nil, name: nil, description: nil, block: nil)
15
+ raise "description must be an array" unless description.kind_of?Array
16
+
17
+ self.platform = platform
18
+ self.name = name
19
+ self.description = description
20
+ self.block = block
21
+ end
22
+
23
+ # Execute this lane
24
+ def call(parameters)
25
+ block.call(parameters || {})
26
+ end
27
+
28
+ # @return [String] The lane + name of the lane. If there is no platform, it will only be the lane name
29
+ def pretty_name
30
+ [platform, name].reject(&:nil?).join(' ')
31
+ end
32
+ end
33
+ end
@@ -12,25 +12,21 @@ module Fastlane
12
12
  ff = Fastlane::FastFile.new(path)
13
13
  output = ""
14
14
 
15
- all_keys = ff.runner.description_blocks.keys.reject(&:nil?)
15
+ all_keys = ff.runner.lanes.keys.reject(&:nil?)
16
16
  all_keys.unshift(nil) # because we want root elements on top. always! They have key nil
17
17
 
18
18
  all_keys.each do |platform|
19
- next if (ff.runner.description_blocks[platform] || []).count == 0
19
+ next if (ff.runner.lanes[platform] || []).count == 0
20
20
  plat_text = platform
21
21
  plat_text = "general" if platform.to_s.empty?
22
22
  output += "\n--------- #{plat_text}---------\n".yellow
23
23
 
24
- value = ff.runner.description_blocks[platform]
24
+ value = ff.runner.lanes[platform]
25
25
 
26
26
  if value
27
- value.each do |lane, description|
28
- lane_text = "----- fastlane "
29
- lane_text += platform.to_s + " " if platform
30
- lane_text += lane.to_s + "\n"
31
-
32
- output += lane_text.green
33
- output += description.gsub("\n\n", "\n") + "\n\n" if description.to_s.length > 0
27
+ value.each do |lane_name, lane|
28
+ output += "----- fastlane #{lane.pretty_name}".green
29
+ output += "\n" + lane.description.join("\n") + "\n\n" if lane.description.count > 0
34
30
  end
35
31
  end
36
32
  end
@@ -50,7 +50,7 @@ module Fastlane
50
50
 
51
51
  # All the finishing up that needs to be done
52
52
  def self.finish_fastlane(ff, duration, error)
53
- ff.did_finish
53
+ ff.runner.did_finish
54
54
 
55
55
  # Finished with all the lanes
56
56
  Fastlane::JUnitGenerator.generate(Fastlane::Actions.executed_actions)
@@ -1,48 +1,56 @@
1
1
  module Fastlane
2
2
  class Runner
3
+ # Symbol for the current lane
4
+ attr_accessor :current_lane
3
5
 
4
- # This will take care of executing **one** lane.
6
+ # Symbol for the current platform
7
+ attr_accessor :current_platform
8
+
9
+ # @return [Hash] All the lanes available, first the platform, then the lane
10
+ attr_accessor :lanes
11
+
12
+ def full_lane_name
13
+ [current_platform, current_lane].reject(&:nil?).join(' ')
14
+ end
15
+
16
+ # This will take care of executing **one** lane. That's when the user triggers a lane from the CLI for example
17
+ # This method is **not** executed when switching a lane
5
18
  # @param lane_name The name of the lane to execute
6
19
  # @param platform The name of the platform to execute
7
20
  # @param parameters [Hash] The parameters passed from the command line to the lane
8
21
  def execute(lane, platform = nil, parameters = nil)
9
22
  raise "No lane given" unless lane
10
23
 
11
- ENV["FASTLANE_LANE_NAME"] = lane.to_s
12
- if platform
13
- ENV["FASTLANE_PLATFORM_NAME"] = platform.to_s
14
- else
15
- ENV["FASTLANE_PLATFORM_NAME"] = nil
16
- end
17
-
18
- lane = lane.to_sym
19
- platform = platform.to_sym if platform # might be nil, which is okay => root element
24
+ self.current_lane = lane.to_sym
25
+ self.current_platform = (platform ? platform.to_sym : nil)
20
26
 
21
- Actions.lane_context[Actions::SharedValues::PLATFORM_NAME] = platform # set this in any case: important
27
+ ENV["FASTLANE_LANE_NAME"] = current_lane.to_s
28
+ ENV["FASTLANE_PLATFORM_NAME"] = (current_platform ? current_platform.to_s : nil)
29
+
30
+ Actions.lane_context[Actions::SharedValues::PLATFORM_NAME] = current_platform
31
+ Actions.lane_context[Actions::SharedValues::LANE_NAME] = full_lane_name
22
32
 
23
- full_lane_name = [platform, lane].reject(&:nil?).join(' ')
24
33
  Helper.log.info "Driving the lane '#{full_lane_name}' 🚀".green
25
- Actions.lane_context[Actions::SharedValues::LANE_NAME] = full_lane_name
26
34
 
27
35
  return_val = nil
28
36
 
29
37
  path_to_use = Fastlane::FastlaneFolder.path || Dir.pwd
30
38
  Dir.chdir(path_to_use) do # the file is located in the fastlane folder
31
39
 
32
- unless (blocks[platform][lane] rescue nil)
40
+ unless (lanes[current_platform][current_lane] rescue nil)
33
41
  raise "Could not find lane '#{full_lane_name}'. Available lanes: #{available_lanes.join(', ')}".red
34
42
  end
35
43
 
36
44
  # Call the platform specific before_all block and then the general one
37
- before_all_blocks[platform].call(lane) if (before_all_blocks[platform] and platform != nil)
38
- before_all_blocks[nil].call(lane) if before_all_blocks[nil]
45
+ before_all_blocks[current_platform].call(current_lane) if (before_all_blocks[current_platform] and current_platform)
46
+ before_all_blocks[nil].call(current_lane) if before_all_blocks[nil]
39
47
 
40
- return_val = blocks[platform][lane].call(parameters || {}) # by default no parameters
48
+ return_val = lanes[current_platform][current_lane].call(parameters || {}) # by default no parameters
41
49
 
42
50
  # `after_all` is only called if no exception was raised before
43
51
  # Call the platform specific before_all block and then the general one
44
- after_all_blocks[platform].call(lane) if (after_all_blocks[platform] and platform != nil)
45
- after_all_blocks[nil].call(lane) if (after_all_blocks[nil])
52
+ after_all_blocks[current_platform].call(current_lane) if (after_all_blocks[current_platform] and current_platform)
53
+ after_all_blocks[nil].call(current_lane) if (after_all_blocks[nil])
46
54
  end
47
55
 
48
56
  return return_val
@@ -51,26 +59,126 @@ module Fastlane
51
59
  # Provide error block exception without colour code
52
60
  error_ex = ex.exception(ex.message.gsub(/\033\[\d+m/, ''))
53
61
 
54
- error_blocks[platform].call(lane, error_ex) if (error_blocks[platform] and platform != nil)
55
- error_blocks[nil].call(lane, error_ex) if error_blocks[nil]
62
+ error_blocks[current_platform].call(current_lane, error_ex) if (error_blocks[current_platform] and current_platform)
63
+ error_blocks[nil].call(current_lane, error_ex) if error_blocks[nil]
56
64
  end
57
65
  raise ex
58
66
  end
59
67
 
60
68
  # @param filter_platform: Filter, to only show the lanes of a given platform
69
+ # @return an array of lanes (platform lane_name) to print them out to the user
61
70
  def available_lanes(filter_platform = nil)
62
71
  all = []
63
- blocks.each do |platform, lane|
72
+ lanes.each do |platform, platform_lanes|
64
73
  next if (filter_platform and filter_platform.to_s != platform.to_s) # skip actions that don't match
65
74
 
66
- lane.each do |lane_name, block|
75
+ platform_lanes.each do |lane_name, lane|
67
76
  all << [platform, lane_name].reject(&:nil?).join(' ')
68
77
  end
69
78
  end
70
79
  all
71
80
  end
72
81
 
73
- # Called internally
82
+ #
83
+ # All the methods that are usually called on execution
84
+ #
85
+
86
+ def try_switch_to_lane(new_lane, parameters)
87
+ block = lanes.fetch(current_platform, {}).fetch(new_lane, nil)
88
+ block ||= lanes.fetch(nil, {}).fetch(new_lane, nil) # fallback to general lane for multiple platforms
89
+ if block
90
+ original_full = full_lane_name
91
+ original_lane = current_lane
92
+
93
+ raise "Parameters for a lane must always be a hash".red unless (parameters.first || {}).kind_of?Hash
94
+
95
+ pretty = [new_lane]
96
+ pretty = [current_platform, new_lane] if current_platform
97
+ Helper.log.info "Cruising over to lane '#{pretty.join(' ')}' 🚖".green
98
+
99
+ # Actually switch lane now
100
+ current_lane = new_lane
101
+ collector.did_launch_action(:lane_switch)
102
+ result = block.call(parameters.first || {}) # to always pass a hash
103
+ current_lane = original_lane
104
+
105
+ Helper.log.info "Cruising back to lane '#{original_full}' 🚘".green
106
+ return result
107
+ else
108
+ # No action and no lane, raising an exception now
109
+ raise "Could not find action or lane '#{new_lane}'. Check out the README for more details: https://github.com/KrauseFx/fastlane".red
110
+ end
111
+ end
112
+
113
+ def execute_action(method_sym, class_ref, arguments)
114
+ collector.did_launch_action(method_sym)
115
+
116
+ step_name = class_ref.step_text rescue nil
117
+ step_name = method_sym.to_s unless step_name
118
+
119
+ verify_supported_os(method_sym, class_ref)
120
+
121
+ Helper.log_alert("Step: " + step_name)
122
+
123
+ begin
124
+ Dir.chdir('..') do # go up from the fastlane folder, to the project folder
125
+ Actions.execute_action(method_sym) do
126
+ # arguments is an array by default, containing an hash with the actual parameters
127
+ # Since we usually just need the passed hash, we'll just use the first object if there is only one
128
+ if arguments.count == 0
129
+ arguments = ConfigurationHelper.parse(class_ref, {}) # no parameters => empty hash
130
+ elsif arguments.count == 1 and arguments.first.kind_of?Hash
131
+ arguments = ConfigurationHelper.parse(class_ref, arguments.first) # Correct configuration passed
132
+ elsif not class_ref.available_options
133
+ # This action does not use the new action format
134
+ # Just passing the arguments to this method
135
+ else
136
+ raise "You have to pass the options for '#{method_sym}' in a different way. Please check out the current documentation on GitHub!".red
137
+ end
138
+
139
+ class_ref.run(arguments)
140
+ end
141
+ end
142
+ rescue => ex
143
+ collector.did_raise_error(method_sym)
144
+ raise ex
145
+ end
146
+ end
147
+
148
+ def verify_supported_os(name, class_ref)
149
+ if class_ref.respond_to?(:is_supported?)
150
+ if Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
151
+ # This value is filled in based on the executed platform block. Might be nil when lane is in root of Fastfile
152
+ platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
153
+
154
+ unless class_ref.is_supported?(platform)
155
+ raise "Action '#{name}' doesn't support required operating system '#{platform}'.".red
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ def collector
162
+ @collector ||= ActionCollector.new
163
+ end
164
+
165
+ # Fastfile was finished executing
166
+ def did_finish
167
+ collector.did_finish
168
+ end
169
+
170
+ # Called internally to setup the runner object
171
+ #
172
+
173
+ # @param lane [Lane] A lane object
174
+ def add_lane(lane)
175
+ lanes[lane.platform] ||= {}
176
+
177
+ raise "Lane '#{lane.name}' was defined multiple times!".red if lanes[lane.platform][lane.name]
178
+
179
+ lanes[lane.platform][lane.name] = lane
180
+ end
181
+
74
182
  def set_before_all(platform, block)
75
183
  before_all_blocks[platform] = block
76
184
  end
@@ -83,22 +191,8 @@ module Fastlane
83
191
  error_blocks[platform] = block
84
192
  end
85
193
 
86
- # @param lane: The name of the lane
87
- # @param platform: The platform for the given block - might be nil - nil is actually the root of Fastfile with no specific platform
88
- # @param block: The block of the lane
89
- # @param desc: Description of this action
90
- def set_block(lane, platform, block, desc = nil)
91
- blocks[platform] ||= {}
92
- description_blocks[platform] ||= {}
93
-
94
- raise "Lane '#{lane}' was defined multiple times!".red if blocks[platform][lane]
95
-
96
- blocks[platform][lane] = block
97
- description_blocks[platform][lane] = desc
98
- end
99
-
100
- def blocks
101
- @blocks ||= {}
194
+ def lanes
195
+ @lanes ||= {}
102
196
  end
103
197
 
104
198
  def before_all_blocks
@@ -112,9 +206,5 @@ module Fastlane
112
206
  def error_blocks
113
207
  @error_blocks ||= {}
114
208
  end
115
-
116
- def description_blocks
117
- @description_blocks ||= {}
118
- end
119
209
  end
120
210
  end
@@ -1,3 +1,3 @@
1
1
  module Fastlane
2
- VERSION = '1.8.0'
2
+ VERSION = '1.9.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Krause
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-14 00:00:00.000000000 Z
11
+ date: 2015-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -430,6 +430,8 @@ files:
430
430
  - lib/fastlane/actions/fastlane_version.rb
431
431
  - lib/fastlane/actions/frameit.rb
432
432
  - lib/fastlane/actions/gcovr.rb
433
+ - lib/fastlane/actions/get_github_release.rb
434
+ - lib/fastlane/actions/git_branch.rb
433
435
  - lib/fastlane/actions/hg_add_tag.rb
434
436
  - lib/fastlane/actions/hg_commit_version_bump.rb
435
437
  - lib/fastlane/actions/hg_ensure_clean_status.rb
@@ -442,6 +444,7 @@ files:
442
444
  - lib/fastlane/actions/install_carthage.rb
443
445
  - lib/fastlane/actions/install_cocapods.rb
444
446
  - lib/fastlane/actions/ipa.rb
447
+ - lib/fastlane/actions/lane_context.rb
445
448
  - lib/fastlane/actions/lcov.rb
446
449
  - lib/fastlane/actions/mailgun.rb
447
450
  - lib/fastlane/actions/notify.rb
@@ -449,7 +452,9 @@ files:
449
452
  - lib/fastlane/actions/opt_out_usage.rb
450
453
  - lib/fastlane/actions/pem.rb
451
454
  - lib/fastlane/actions/produce.rb
455
+ - lib/fastlane/actions/prompt.rb
452
456
  - lib/fastlane/actions/push_to_git_remote.rb
457
+ - lib/fastlane/actions/puts.rb
453
458
  - lib/fastlane/actions/register_devices.rb
454
459
  - lib/fastlane/actions/reset_git_repo.rb
455
460
  - lib/fastlane/actions/resign.rb
@@ -483,7 +488,7 @@ files:
483
488
  - lib/fastlane/fast_file.rb
484
489
  - lib/fastlane/fastlane_folder.rb
485
490
  - lib/fastlane/junit_generator.rb
486
- - lib/fastlane/lane_context.rb
491
+ - lib/fastlane/lane.rb
487
492
  - lib/fastlane/lane_list.rb
488
493
  - lib/fastlane/lane_manager.rb
489
494
  - lib/fastlane/new_action.rb