class Blufin::Git

Constants

DETACHED_HEAD_REGEX
HISTORY_TYPES

Public Class Methods

add(path, add = '.', verbose: true) click to toggle source

Runs $ git add . @return void

# File lib/core/git.rb, line 186
def self.add(path, add = '.', verbose: true)
    raise RuntimeError, "Path not found: #{path}" unless path.nil? || Blufin::Files::path_exists(path)
    path = Blufin::Strings::strip_newline(`pwd`) if path.nil?
    run("git add #{add}", path, verbose: verbose)
end
branch_exists(path, branch, run_git_fetch: false) click to toggle source

Checks if current branch exists. @return bool

# File lib/core/git.rb, line 168
def self.branch_exists(path, branch, run_git_fetch: false)
    exists(path, branch, 'branch', run_git_fetch)
end
checkout(project_id, branch: nil, tag: nil, commit: nil, is_ec2: false) click to toggle source

Checks out a project and returns the path to it. branch_tag_or_commit can be a branch, commit or tag. Returns current branch/tag/commit (if local) – in case you want to revert after. @return string |

# File lib/core/git.rb, line 36
def self.checkout(project_id, branch: nil, tag: nil, commit: nil, is_ec2: false)
    begin
        project      = Blufin::Projects::get_project_by_id(project_id, true)
        repo_path    = Blufin::Projects::get_project_path(project_id, is_ec2: is_ec2)
        repo_data    = project[Blufin::Projects::REPOSITORY]
        type, btc    = resolve_type_btc(branch, tag, commit)
        errors       = nil
        current_head = nil
        if repo_data.has_key?(Blufin::Projects::LOCAL) && !is_ec2
            # Make sure branch/tag/commit exists.
            raise "#{Blufin::Terminal::format_highlight(type.capitalize)} not found: #{Blufin::Terminal::format_invalid(btc)}" unless Blufin::Git::exists(repo_path, btc, type, false)
            # Get current branch (need to reset to this locally after script has run).
            current_head = Blufin::Git::get_current_branch(repo_path)
        else
            # If path already exists, do some checks...
            if Blufin::Files::path_exists(repo_path)
                res  = Blufin::Terminal::execute("git remote -v | tail -n 1 | awk '{print $2}'", repo_path, capture: true, verbose: false, display_error: false)
                wipe = false
                res  = res[0]
                if res.nil? || Blufin::Strings::strip_newline(res) == ''
                    wipe = true
                else
                    repo_expected = Blufin::Projects::get_project_repo_name(project_id)
                    repo_actual   = extract_repo_name(res)
                    wipe          = true if repo_expected != repo_actual
                end
                # Wipe /tmp folder ONLY if something weird is going on... I put the /tmp regex just in case :)
                `rm -rf #{repo_path}/` if wipe && repo_path =~ /^\/tmp\/[A-Za-z0-9\.]+/
            end
            # Checkout repo (if not exists).
            unless Blufin::Files::path_exists(repo_path)
                clone_cmd = "git clone #{project[Blufin::Projects::REPOSITORY][Blufin::Projects::REMOTE]} #{repo_path}"
                unless Blufin::Terminal::execute_proc(clone_cmd, Proc.new {
                    res    = Blufin::Terminal::execute("#{clone_cmd} &>/dev/null", '/tmp', capture: true, verbose: false, display_error: false)
                    errors = res[1].split("\n")
                    res[1] =~ /^Cloning\s*into\s*('|").+/
                })
                    raise RuntimeError, "Failed to checkout #{type}: #{Blufin::Terminal::format_invalid(btc)}"
                end
            end
            # At this point we should have the repo checked out. Throw an error if we don't.
            raise RuntimeError, "Path not found: #{repo_path}" unless Blufin::Files::path_exists(repo_path)
        end
        # Checkout branch/tag/commit.
        unless Blufin::Terminal::execute_proc("git checkout #{btc}", Proc.new {
            res       = Blufin::Terminal::execute("git checkout #{btc} &>/dev/null", repo_path, capture: true, verbose: false, display_error: false)
            errors    = res[1].split("\n")
            last_line = errors[errors.length - 1].strip
            last_line =~ /^HEAD\s*is\s*now\s*at\s*.+/i || last_line =~ /^Already\s*on\s*('|")#{btc}('|")$/ || last_line =~ /^Switched\s*to(\s*a\s*new)?\s*branch\s*('|")#{btc}('|")$/
        })
            raise RuntimeError, "Failed to checkout #{type}: #{Blufin::Terminal::format_invalid(btc)}"
        end
        current_head
    rescue => e
        if is_ec2
            err_output = nil
            err_output = " - #{errors.is_a?(Array) ? errors.join(', ') : errors.to_s}" unless errors.nil? || errors.strip == ''
            raise RuntimeError, Blufin::Strings::strip_ansi_colors("#{e.message}#{err_output}")
        else
            Blufin::Terminal::error(e.message, errors)
        end
    end
end
commit_exists(path, commit, run_git_fetch: false) click to toggle source

Checks if commit exists. @return bool

# File lib/core/git.rb, line 180
def self.commit_exists(path, commit, run_git_fetch: false)
    exists(path, commit, 'commit', run_git_fetch)
end
extract_repo_name(string) click to toggle source

Attempts to convert something like git@github.com:alb3rtuk/blufin-archetypes.git into -> blufin-archetypes. @return string

# File lib/core/git.rb, line 194
def self.extract_repo_name(string)
    raise RuntimeError, "Expected String, instead got: #{string.class}" unless string.is_a?(String)
    repo_name = Blufin::Strings::strip_newline(string).split('/')
    repo_name[repo_name.length - 1].gsub(/\.git$/i, '')
end
get_current_branch(path = nil, verbose: false) click to toggle source

Gets current branch for a repository. @return String -> (IE: “master”)

# File lib/core/git.rb, line 102
def self.get_current_branch(path = nil, verbose: false)
    raise RuntimeError, "Path not found: #{path}" unless path.nil? || Blufin::Files::path_exists(path)
    path = Blufin::Strings::strip_newline(`pwd`) if path.nil?
    key  = File.expand_path(path)
    return @@branch_current_cache[key] if @@branch_current_cache.has_key?(key)
    res                         = run("git branch | grep \\*", path, text: 'Getting Branch', verbose: verbose)
    branch                      = Blufin::Strings::strip_newline(res).gsub(/^\*\s?/, '')
    branch                      = branch.strip.gsub(DETACHED_HEAD_REGEX, '').gsub(/\)$/, '') if branch =~ DETACHED_HEAD_REGEX
    @@branch_current_cache[key] = branch
    @@branch_current_cache[key]
end
get_latest_commit_hash(path, verbose: false) click to toggle source

Gets latest commit hash for a repository. @return String -> (IE: “5b7559e5952eacb5251a9baf81dd964fe1ef57f5”)

# File lib/core/git.rb, line 116
def self.get_latest_commit_hash(path, verbose: false)
    raise RuntimeError, "Path not found: #{path}" unless Blufin::Files::path_exists(path)
    key = File.expand_path(path)
    return @@commit_cache[key] if @@commit_cache.has_key?(key)
    res                 = run('git rev-parse HEAD', path, text: 'Getting HEAD Commit', verbose: verbose)
    @@commit_cache[key] = Blufin::Strings::strip_newline(res)
    @@commit_cache[key]
end
get_uncommitted_files(path, run_git_add: true, verbose: false, formatted: false, spacer: nil) click to toggle source

Gets a list of uncommitted files for a repository. Returns an empty Array if branch is clean. @return Array -> (IE: [“file-1.txt”,“file-2.txt”] or [])

# File lib/core/git.rb, line 128
def self.get_uncommitted_files(path, run_git_add: true, verbose: false, formatted: false, spacer: nil)
    raise RuntimeError, "Path not found: #{path}" unless Blufin::Files::path_exists(path)
    raise RuntimeError, "Expected String, instead got: #{spacer.class}" unless spacer.is_a?(String) || spacer.nil?
    raise RuntimeError, 'Cannot pass spacer if formatted: is false.' if !formatted && !spacer.nil?
    key = "#{File.expand_path(path)}-#{formatted}-#{spacer}"
    return @@uncommitted_files_cache[key] if @@uncommitted_files_cache.has_key?(key)
    renamed  = []
    modified = []
    deleted  = []
    moved    = []
    new      = []
    run('git add .', path, verbose: verbose) if run_git_add
    git_status = run('git status', path, verbose: verbose)
    git_status = git_status.split("\n")
    git_status.each do |line|
        renamed << line.split('renamed:')[1].strip if line =~ /renamed:/i
        modified << line.split('modified:')[1].strip if line =~ /modified:/i
        deleted << line.split('deleted:')[1].strip if line =~ /deleted:/i
        moved << line.split('moved:')[1].strip if line =~ /moved:/i
        new << line.split('new file:')[1].strip if line =~ /new file:/i
    end
    if formatted
        files  = []
        spacer = '' if spacer.nil?
        new.each { |file| files << "#{spacer}\x1B[38;5;246m#{'New: '.rjust(10, ' ')}\x1B[38;5;48m#{file}\x1B[0m" } if new.any?
        modified.each { |file| files << "#{spacer}\x1B[38;5;246m#{'Modified: '.rjust(10, ' ')}\x1B[38;5;34m#{file}\x1B[0m" } if modified.any?
        renamed.each { |file| files << "#{spacer}\x1B[38;5;246m#{'Renamed: '.rjust(10, ' ')}\x1B[38;5;34m#{file}\x1B[0m" } if renamed.any?
        deleted.each { |file| files << "#{spacer}\x1B[38;5;246m#{'Deleted: '.rjust(10, ' ')}\x1B[38;5;124m#{file}\x1B[0m" } if deleted.any?
        moved.each { |file| files << "#{spacer}\x1B[38;5;246m#{'Moved: '.rjust(10, ' ')}\x1B[38;5;238m#{file}\x1B[0m" } if moved.any?
    else
        files = renamed + modified + deleted + moved + new
        files.sort!
    end
    files.uniq!
    @@uncommitted_files_cache[key] = files
    @@uncommitted_files_cache[key]
end
tag_exists(path, tag, run_git_fetch: false) click to toggle source

Checks if tag exists. @return bool

# File lib/core/git.rb, line 174
def self.tag_exists(path, tag, run_git_fetch: false)
    exists(path, tag, 'tag', run_git_fetch)
end

Private Class Methods

exists(path, btc, type, run_git_fetch) click to toggle source

Common code for 'exists' method(s). @return bool

# File lib/core/git.rb, line 213
def self.exists(path, btc, type, run_git_fetch)
    raise RuntimeError, "Path not found: #{path}" unless path.nil? || Blufin::Files::path_exists(path)
    raise RuntimeError, "Invalid type: #{type}" unless HISTORY_TYPES.include?(type)
    key = "#{File.expand_path(path)}|#{btc}|#{type}|#{run_git_fetch}"
    return @@btc_exists_cache[key] if @@btc_exists_cache.has_key?(key)
    exists = false
    Blufin::Terminal::execute_proc("Checking #{type} exists: #{Blufin::Terminal::format_highlight(btc)} \x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;240m#{File.expand_path(path)}\x1B[0m", Proc.new {
        run('git fetch -p', path, verbose: false) if run_git_fetch
        case type
            when 'branch'
                cmd = "git branch -r | grep #{btc}"
            when 'tag'
                cmd = "git tag | grep #{btc}"
            when 'commit'
                cmd = "git log | grep \"commit #{btc}\""
        else
          raise RuntimeError, "Unhandled type: #{type}"
        end
        res = Blufin::Terminal::execute(cmd, path, capture: true, verbose: false)
        res.each do |line|
            next if line.nil? || line.strip == ''
            case type
                when 'branch'
                    line = line.gsub(/^\*\s?/, '')
                    line = line.gsub(/^\s*origin\//, '')
                when 'commit'
                    line = line.gsub(/^commit\s?/, '')
                when 'tag'
                else
                    raise RuntimeError, "Unrecognized type: #{type}"
            end
            line = Blufin::Strings::strip_newline(line)
            if line =~ /^#{btc}$/
                exists = true
                break
            end
        end
        exists
    })
    @@btc_exists_cache[key] = exists
    @@btc_exists_cache[key]
end
resolve_type_btc(branch, tag, commit) click to toggle source

Convenience method to resolve type and branch/tag/commit name. @return Array

# File lib/core/git.rb, line 258
def self.resolve_type_btc(branch, tag, commit)
    set = 0
    set =+1 unless branch.nil?
    set =+1 unless tag.nil?
    set =+1 unless commit.nil?
    raise RuntimeError, "Must set atleast one of: #{HISTORY_TYPES.join(', ')}" if set == 0
    raise RuntimeError, "Can only set one of: #{HISTORY_TYPES.join(', ')}" if set > 1
    type = 'branch' unless branch.nil?
    type = 'tag' unless tag.nil?
    type = 'commit' unless commit.nil?
    case type
        when 'branch'
            btc = branch
        when 'tag'
            btc = tag
        when 'commit'
            btc = commit
        else
            raise RuntimeError, "Unrecognized type: #{type}"
    end
    raise RuntimeError, "#{type.capitalize} cannot be nil." if btc.nil? || btc.strip == ''
    [type, btc]
end
run(cmd, path, text: nil, verbose: true) click to toggle source

Convenience method to run commands. Throws error if anything fails. Returns only the output, not the error. Does not strip new lines! This must be done 1 level up. @return string

# File lib/core/git.rb, line 205
def self.run(cmd, path, text: nil, verbose: true)
    res = Blufin::Terminal::execute(cmd, path, capture: true, text: text, verbose: verbose)
    Blufin::Terminal::error("Something went wrong: #{Blufin::Terminal::format_invalid(res[1])}") unless res[1].nil?
    res[0]
end