fastlane/lib/fastlane/fast_file.rb in fastlane-2.63.0.beta.20171026010003 vs fastlane/lib/fastlane/fast_file.rb in fastlane-2.63.0.beta.20171027010003

- old
+ new

@@ -223,40 +223,49 @@ end # @param url [String] The git URL to clone the repository from # @param branch [String] The branch to checkout in the repository # @param path [String] The path to the Fastfile - def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile') + # @param verion [String] Version of the required Fastlane version + def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version: nil) UI.user_error!("Please pass a path to the `import_from_git` action") if url.to_s.length == 0 Actions.execute_action('import_from_git') do require 'tmpdir' action_launched('import_from_git') # Checkout the repo repo_name = url.split("/").last + checkout_param = branch Dir.mktmpdir("fl_clone") do |tmp_path| clone_folder = File.join(tmp_path, repo_name) - branch_option = "" branch_option = "--branch #{branch}" if branch != 'HEAD' - clone_command = "GIT_TERMINAL_PROMPT=0 git clone '#{url}' '#{clone_folder}' --depth 1 -n #{branch_option}" - UI.message "Cloning remote git repo..." - Actions.sh(clone_command) + Actions.sh("GIT_TERMINAL_PROMPT=0 git clone '#{url}' '#{clone_folder}' --depth 1 -n #{branch_option}") - Actions.sh("cd '#{clone_folder}' && git checkout #{branch} '#{path}'") + unless version.nil? + git_tags = fetch_remote_tags(folder: clone_folder) + # Separate version from optimistic operator + version_number = version(version_string: version) + operator = operator(version_string: version) + + checkout_param = checkout_param_for_operator(operator: operator, version: version_number, git_tags: git_tags) + end + + Actions.sh("cd '#{clone_folder}' && git checkout #{checkout_param} '#{path}'") + # We also want to check out all the local actions of this fastlane setup containing = path.split(File::SEPARATOR)[0..-2] containing = "." if containing.count == 0 actions_folder = File.join(containing, "actions") begin - Actions.sh("cd '#{clone_folder}' && git checkout #{branch} '#{actions_folder}'") + Actions.sh("cd '#{clone_folder}' && git checkout #{checkout_param} '#{actions_folder}'") rescue # We don't care about a failure here, as local actions are optional end return_value = import(File.join(clone_folder, path)) @@ -264,9 +273,92 @@ action_completed('import_from_git', status: FastlaneCore::ActionCompletionStatus::SUCCESS) return return_value end end + end + + ##################################################### + # @!group Versioning helpers + ##################################################### + + def fetch_remote_tags(folder: nil) + UI.message "Fetching remote git tags..." + Actions.sh("cd '#{folder}' && GIT_TERMINAL_PROMPT=0 git fetch --all --tags -q") + + # Fetch all possible tags + git_tags_string = Actions.sh("cd '#{folder}' && git tag -l") + git_tags = git_tags_string.split("\n") + + # Delete tags that are not a real version number + git_tags.delete_if { |tag| Gem::Version.correct?(tag) != 0 } + + # Sort tags based on their version number + git_tags.sort_by { |tag| Gem::Version.new(tag) } + + return git_tags + end + + def checkout_param_for_operator(operator: nil, version: nil, git_tags: nil) + # ~> should select the latest version withing constraints. + # -> should select a specific version without fallback. + if operator == "~>" + return checkout_param_twiddle_wakka(version: version, git_tags: git_tags) + + elsif operator == "->" || operator.nil? + return checkout_param_specific_version(version: version, git_tags: git_tags) + + else + UI.user_error!("The specified operator \"#{operator}\" in \"#{version}\" is unknown. Please use one of these '~> ->'") + end + end + + def checkout_param_specific_version(version: nil, git_tags: nil) + # Search matching version in array + matching_git_tags = git_tags.select do |tag| + tag == version + end + + UI.user_error!("The specified version \"#{version}\" doesn't exist") if matching_git_tags.count == 0 + return matching_git_tags.last + end + + def checkout_param_twiddle_wakka(version: nil, git_tags: nil) + # Drop last specified digit in version + last_dot_index = version.rindex('.') + version_range = version[0..last_dot_index - 1] + + # Search matching version in array + matching_git_tags = git_tags.select do |tag| + tag.start_with?(version_range) + end + + UI.user_error!("No version found within the \"#{version_range}.*\" range") if matching_git_tags.count == 0 + + return matching_git_tags.last + end + + def operator(version_string: nil) + version_info = version_range_info(version_string: version_string) + + # version_info will have 2 elements if an optimistic operator is specified. + if version_info.count > 1 + + # Optimistic operator is always the first part. e.g.: ["~>", "2.0.0"] + return version_info.first + end + + return nil + end + + def version(version_string: nil) + version_info = version_range_info(version_string: version_string) + return version_info.last + end + + def version_range_info(version_string: nil) + # Separate version from optimistic operator + return version_string.split(" ") end ##################################################### # @!group Overwriting Ruby methods #####################################################