class Blufin::Git
Constants
- DETACHED_HEAD_REGEX
- HISTORY_TYPES
Public Class Methods
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
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
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
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
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
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
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
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
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
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
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
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