Class: Blufin::Git

Inherits:
Object
  • Object
show all
Defined in:
lib/core/git.rb

Constant Summary collapse

HISTORY_TYPES =
%w(branch tag commit)
DETACHED_HEAD_REGEX =
/\(HEAD\s*detached\s*at\s*/
@@branch_current_cache =
{}
@@btc_exists_cache =
{}
@@commit_cache =
{}
@@uncommitted_files_cache =
{}

Class Method Summary collapse

Class Method Details

.add(path, add = '.', verbose: true) ⇒ Object

Runs $ git add .

Returns:

  • void

Raises:

  • (RuntimeError)


186
187
188
189
190
# 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) ⇒ Object

Checks if current branch exists.

Returns:

  • bool



168
169
170
# 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) ⇒ Object

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.

Returns:

  • string |



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 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) ⇒ Object

Checks if commit exists.

Returns:

  • bool



180
181
182
# 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) ⇒ Object

Attempts to convert something like [email protected]:alb3rtuk/blufin-archetypes.git into -> blufin-archetypes.

Returns:

  • string

Raises:

  • (RuntimeError)


194
195
196
197
198
# 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) ⇒ Object

Gets current branch for a repository.

Returns:

  • String -> (IE: “master”)

Raises:

  • (RuntimeError)


102
103
104
105
106
107
108
109
110
111
112
# 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) ⇒ Object

Gets latest commit hash for a repository.

Returns:

  • String -> (IE: “5b7559e5952eacb5251a9baf81dd964fe1ef57f5”)

Raises:

  • (RuntimeError)


116
117
118
119
120
121
122
123
# 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) ⇒ Object

Gets a list of uncommitted files for a repository. Returns an empty Array if branch is clean.

Returns:

  • Array -> (IE: [“file-1.txt”,“file-2.txt”] or [])

Raises:

  • (RuntimeError)


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# 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) ⇒ Object

Checks if tag exists.

Returns:

  • bool



174
175
176
# 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