Method: Fastlane::FastFile#import_from_git

Defined in:
fastlane/lib/fastlane/fast_file.rb

#import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version: nil, dependencies: [], cache_path: nil, git_extra_headers: []) ⇒ Object

Parameters:

  • url (String) (defaults to: nil)

    The git URL to clone the repository from

  • branch (String) (defaults to: 'HEAD')

    The branch to checkout in the repository

  • path (String) (defaults to: 'fastlane/Fastfile')

    The path to the Fastfile

  • version (String, Array) (defaults to: nil)

    Version requirement for repo tags

  • dependencies (Array) (defaults to: [])

    An optional array of additional Fastfiles in the repository

  • cache_path (String) (defaults to: nil)

    An optional path to a directory where the repository should be cloned into

  • git_extra_headers (Array) (defaults to: [])

    An optional array of custom HTTP headers to access the git repo (‘Authorization: Basic <YOUR BASE64 KEY>`, `Cache-Control: no-cache`, etc.)



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'fastlane/lib/fastlane/fast_file.rb', line 282

def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version: nil, dependencies: [], cache_path: nil, git_extra_headers: []) # rubocop:disable Metrics/PerceivedComplexity
  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')

    is_eligible_for_caching = !cache_path.nil?

    UI.message("Eligible for caching") if is_eligible_for_caching

    # Checkout the repo
    repo_name = url.split("/").last
    checkout_param = branch

    import_block = proc do |target_path|
      clone_folder = File.join(target_path, repo_name)

      checkout_dependencies = dependencies.map(&:shellescape).join(" ")

      # If the current call is eligible for caching, we check out all the
      # files and directories. If not, we only check out the specified
      # `path` and `dependencies`.
      checkout_path = is_eligible_for_caching ? "" : "#{path.shellescape} #{checkout_dependencies}"

      if Dir[clone_folder].empty?
        UI.message("Cloning remote git repo...")
        Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
          command = ['git', 'clone', url, clone_folder, '--no-checkout']
          # When using cached clones, we need the entire repository history
          # so we can switch between tags or branches instantly, or else,
          # it would defeat the caching's purpose.
          command += ['--depth', '1'] unless is_eligible_for_caching
          command += ['--branch', branch] unless branch == 'HEAD'
          git_extra_headers.each do |header|
            command += ['--config', "http.extraHeader=#{header}"]
          end
          Actions.sh(*command)
        end
      end

      unless version.nil?
        if is_eligible_for_caching
          checkout_param = find_tag(folder: clone_folder, version: version, remote: false)

          if checkout_param.nil?
            # Update the repo and try again before failing
            UI.message("Updating git repo...")
            Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
              Actions.sh("cd #{clone_folder.shellescape} && git checkout #{branch} && git reset --hard && git pull --all")
            end

            checkout_param = find_tag(folder: clone_folder, version: version, remote: false)
          else
            UI.message("Found tag #{checkout_param}. No git repo update needed.")
          end
        else
          checkout_param = find_tag(folder: clone_folder, version: version, remote: true)
        end

        UI.user_error!("No tag found matching #{version.inspect}") if checkout_param.nil?
      end

      if is_eligible_for_caching
        if version.nil?
          # Update the repo if it's eligible for caching but the version isn't specified
          UI.message("Fetching remote git branches and updating git repo...")
          Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
            command = "cd #{clone_folder.shellescape} && git fetch --all --quiet && git checkout #{checkout_param.shellescape} #{checkout_path} && git reset --hard"
            # Check if checked out "branch" is actually a branch or a tag
            current_branch = Actions.sh("cd #{clone_folder.shellescape} && git rev-parse --abbrev-ref HEAD")
            command << " && git rebase" unless current_branch.strip.eql?("HEAD")
            Actions.sh(command)
          end
        else
          begin
            # https://stackoverflow.com/a/1593574/865175
            current_tag = Actions.sh("cd #{clone_folder.shellescape} && git describe --exact-match --tags HEAD").strip
          rescue
            current_tag = nil
          end

          if current_tag != version
            Actions.sh("cd #{clone_folder.shellescape} && git checkout #{checkout_param.shellescape} #{checkout_path}")
          end
        end
      else
        Actions.sh("cd #{clone_folder.shellescape} && git checkout #{checkout_param.shellescape} #{checkout_path}")
      end

      # Knowing that we check out all the files and directories when the
      # current call is eligible for caching, we don't need to also
      # explicitly check out the "actions" directory.
      unless is_eligible_for_caching
        # 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.shellescape} && git checkout #{checkout_param.shellescape} #{actions_folder.shellescape}")
        rescue
          # We don't care about a failure here, as local actions are optional
        end
      end

      return_value = nil
      if dependencies.any?
        return_value = [import(File.join(clone_folder, path))]
        return_value += dependencies.map { |file_path| import(File.join(clone_folder, file_path)) }
      else
        return_value = import(File.join(clone_folder, path))
      end

      action_completed('import_from_git', status: FastlaneCore::ActionCompletionStatus::SUCCESS)

      return return_value
    end

    if is_eligible_for_caching
      import_block.call(File.expand_path(cache_path))
    else
      Dir.mktmpdir("fl_clone", &import_block)
    end
  end
end