lib/slugbuilder/builder.rb in slugbuilder-1.3.0 vs lib/slugbuilder/builder.rb in slugbuilder-2.0.0

- old
+ new

@@ -10,19 +10,21 @@ @base_dir = Slugbuilder.config.base_dir @cache_dir = Shellwords.escape(Slugbuilder.config.cache_dir) @output_dir = Slugbuilder.config.output_dir @buildpacks_dir = File.join(@cache_dir, 'buildpacks') @env_dir = File.join(@base_dir, 'environment') - @repo = repo + repo_matches = parse_git_url(repo) + @repo = "#{repo_matches[:org]}/#{repo_matches[:name]}" + @git_url = normalize_git_url(repo) @git_ref = git_ref - @git_dir = Shellwords.escape(File.join(@base_dir, 'git', repo)) - @build_dir = Shellwords.escape(File.join(@base_dir, repo, git_ref)) + @git_dir = Shellwords.escape(File.join(@base_dir, 'git', @repo)) + @build_dir = Shellwords.escape(File.join(@base_dir, @repo, git_ref)) setup if block_given? - yield(repo: repo, git_ref: git_ref) + yield(repo: @repo, git_ref: git_ref, git_url: @git_url) end end def build(clear_cache: false, env: {}, prebuild: nil, postbuild: nil, slug_name: nil, buildpacks: Slugbuilder.config.buildpacks) @old_env = ENV.to_h @@ -33,11 +35,11 @@ @buildpacks = buildpacks @env = env @slug_file = slug_name ? "#{slug_name}.tgz" : Shellwords.escape("#{@repo.gsub('/', '.')}.#{@git_ref}.#{@git_sha}.tgz") wipe_cache if clear_cache - prebuild.call(repo: @repo, git_ref: @git_ref) if prebuild + prebuild.call(repo: @repo, git_ref: @git_ref, git_url: @git_url) if prebuild with_clean_env do build_and_release end stitle("Setup completed in #{@setup_time} seconds") @@ -51,13 +53,13 @@ compile: @compile_time, slug: @slug_time, output: build_output.join('') } - postbuild.call(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, request_id: @request_id, stats: stats, slug: File.join(@output_dir, @slug_file)) if postbuild + postbuild.call(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, git_url: @git_url, request_id: @request_id, stats: stats, slug: File.join(@output_dir, @slug_file)) if postbuild if block_given? - yield(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, request_id: @request_id, stats: stats, slug: File.join(@output_dir, @slug_file)) + yield(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, git_url: @git_url, request_id: @request_id, stats: stats, slug: File.join(@output_dir, @slug_file)) end return true rescue => e stitle("Failed: #{e}\n#{e.backtrace.join("\n")}") return false @@ -152,44 +154,54 @@ end end def download_repo stitle("Fetching #{@repo}") - rc = run("git clone --quiet git@#{Slugbuilder.config.git_service}:#{@repo}.git #{@git_dir}") + rc = run("git clone --quiet #{@git_url} #{@git_dir}") fail "Failed to download repo: #{@repo}" if rc != 0 end def copy_app # copy dotfiles but not .git, ., or .. files = Dir.glob("#{@git_dir}/**", File::FNM_DOTMATCH).reject { |file| file =~ /\.git|\.$|\.\.$/ } FileUtils.cp_r(files, @build_dir) end def get_buildpack_name(url) - url.match(/.+\/(.+?)\.git$/)[1] + matches = parse_git_url(url) + "#{matches[:org]}__#{matches[:name]}#{matches[:hash]}" end def fetch_buildpacks @buildpacks << Shellwords.escape(@env['BUILDPACK_URL']) if @env.key?('BUILDPACK_URL') fail 'Could not detect buildpack' if @buildpacks.size.zero? existing_buildpacks = Dir.entries(@buildpacks_dir) @buildpacks.each do |buildpack_url| + buildpack_matches = parse_git_url(buildpack_url) buildpack_name = get_buildpack_name(buildpack_url) if !existing_buildpacks.include?(buildpack_name) # download buildpack stitle("Fetching buildpack: #{buildpack_name}") - rc = run("git clone --quiet --depth=1 #{buildpack_url} #{@buildpacks_dir}/#{buildpack_name}") + rc = run("git clone --quiet #{normalize_git_url(buildpack_url)} #{@buildpacks_dir}/#{buildpack_name}") fail "Failed to download buildpack: #{buildpack_name}" if rc != 0 else # fetch latest stitle("Using cached buildpack. Ensuring latest version of buildpack: #{buildpack_name}") Dir.chdir("#{@buildpacks_dir}/#{buildpack_name}") do rc = run('git pull --quiet') fail "Failed to update: #{buildpack_name}" if rc != 0 end end + + # checkout hash + if buildpack_matches[:hash] + Dir.chdir("#{@buildpacks_dir}/#{buildpack_name}") do + rc = run("git fetch --quiet --all && git checkout --quiet #{buildpack_matches[:hash]}") + fail "Failed to fetch and checkout: #{buildpack_matches[:hash]}" if rc != 0 + end + end end @buildpacks end @@ -247,9 +259,32 @@ end def slug_size @slug_size = File.size(File.join(@output_dir, @slug_file)) / 1024 / 1024 stitle("Slug size is #{@slug_size} Megabytes.") + end + + def parse_git_url(url) + regex = %r{ + ^ + .*? + (?:(?<host>[^\/@]+)(\/|:))? + (?<org>[^\/:]+) + \/ + (?<name>[^\/#\.]+) + (?:\.git(?:\#(?<hash>.+))?)? + $ + }x + url.match(regex) + end + + def normalize_git_url(url) + matches = parse_git_url(url) + if Slugbuilder.config.protocol == 'ssh' + "git@#{matches[:host] || Slugbuilder.config.git_service}:#{matches[:org]}/#{matches[:name]}.git" + else + "https://#{matches[:host] || Slugbuilder.config.git_service}/#{matches[:org]}/#{matches[:name]}.git" + end end def print_workers workers = {} if File.exists?("#{@build_dir}/Procfile")