Class: Ninny::Git
Overview
rubocop:disable Metrics/ClassLength
Constant Summary collapse
- NO_BRANCH =
'(no branch)'
- DEFAULT_DIRTY_MESSAGE =
'Your Git index is not clean. Commit, stash, or otherwise clean' \ ' up the index before continuing.'
- DIRTY_CONFIRM_MESSAGE =
'Your Git index is not clean. Do you want to continue?'
- DEPLOYABLE_PREFIX =
branch prefixes
'deployable'
- STAGING_PREFIX =
'staging'
- QAREADY_PREFIX =
'qaready'
- CheckoutFailed =
Exceptions
Class.new(StandardError)
- NotOnBranch =
Class.new(StandardError)
- NoBranchOfType =
Class.new(StandardError)
- DirtyIndex =
Class.new(StandardError)
Instance Attribute Summary collapse
-
#git ⇒ Object
readonly
Returns the value of attribute git.
Instance Method Summary collapse
-
#alert_dirty_index(message) ⇒ Object
Public: Display the message and show the git status.
-
#branches_for(prefix) ⇒ Object
Public: List of branches starting with the given string.
-
#check_out(branch, do_after_pull = true) ⇒ Object
Public: Check out the given branch name.
-
#clean? ⇒ Boolean
Public: Whether the Git index is clean (has no uncommited changes).
- #command(*args) ⇒ Object
- #current_branch ⇒ Object
- #current_branch_name ⇒ Object
-
#delete_branch(branch_name) ⇒ Object
Public: Delete the given branch.
-
#if_clean(message = DEFAULT_DIRTY_MESSAGE) ⇒ Object
Public: Perform the block if the Git index is clean.
-
#initialize ⇒ Git
constructor
A new instance of Git.
-
#latest_branch_for(prefix) ⇒ Object
Public: Most recent branch starting with the given string.
- #merge(branch_name) ⇒ Object
-
#new_branch(new_branch_name, source_branch_name) ⇒ Object
Public: Create a new branch from the given source.
- #prompt(**options) ⇒ Object
-
#pull ⇒ Object
Public: Pull the latest changes for the checked-out branch.
-
#push ⇒ Object
Public: Push the current branch to GitHub.
-
#remote_branches ⇒ Object
Public: The list of branches on GitHub.
-
#track_current_branch(do_after_pull = true) ⇒ Object
Public: Track remote branch matching current branch.
Constructor Details
#initialize ⇒ Git
Returns a new instance of Git.
21 22 23 |
# File 'lib/ninny/git.rb', line 21 def initialize @git = ::Git.open(Dir.pwd) end |
Instance Attribute Details
#git ⇒ Object (readonly)
Returns the value of attribute git.
19 20 21 |
# File 'lib/ninny/git.rb', line 19 def git @git end |
Instance Method Details
#alert_dirty_index(message) ⇒ Object
Public: Display the message and show the git status
163 164 165 166 167 168 169 |
# File 'lib/ninny/git.rb', line 163 def alert_dirty_index() prompt.say ' ' prompt.say prompt.say ' ' prompt.say command('status') raise DirtyIndex end |
#branches_for(prefix) ⇒ Object
Public: List of branches starting with the given string
prefix - String to match branch names against
Returns an Array of Branches containing the branch name
129 130 131 132 133 |
# File 'lib/ninny/git.rb', line 129 def branches_for(prefix) remote_branches.select do |branch| branch.name =~ /^#{prefix}/ end end |
#check_out(branch, do_after_pull = true) ⇒ Object
Public: Check out the given branch name
branch_name - The name of the branch to check out do_after_pull - Should a pull be done after checkout?
67 68 69 70 71 72 |
# File 'lib/ninny/git.rb', line 67 def check_out(branch, do_after_pull = true) `git fetch --prune &> /dev/null` git.checkout(branch) pull if do_after_pull raise CheckoutFailed, "Failed to check out '#{branch}'" unless current_branch.name == branch.name end |
#clean? ⇒ Boolean
Public: Whether the Git index is clean (has no uncommited changes)
Returns a Boolean
148 149 150 |
# File 'lib/ninny/git.rb', line 148 def clean? command('status', '--short').empty? end |
#command(*args) ⇒ Object
25 26 27 |
# File 'lib/ninny/git.rb', line 25 def command(*args) git.lib.send(:command, *args) end |
#current_branch ⇒ Object
29 30 31 |
# File 'lib/ninny/git.rb', line 29 def current_branch git.branch(current_branch_name) end |
#current_branch_name ⇒ Object
33 34 35 36 37 |
# File 'lib/ninny/git.rb', line 33 def current_branch_name raise NotOnBranch, 'Not currently checked out to a particular branch' if git.current_branch == NO_BRANCH git.current_branch end |
#delete_branch(branch_name) ⇒ Object
Public: Delete the given branch
branch_name - The name of the branch to delete
106 107 108 109 110 111 112 113 114 |
# File 'lib/ninny/git.rb', line 106 def delete_branch(branch_name) branch = branch_name.is_a?(::Git::Branch) ? branch_name : git.branch(branch_name) git.push('origin', ":#{branch}") branch.delete rescue ::Git::GitExecuteError => e if e..include?(':error: branch') && e..include?(' not found.') puts 'Could not delete local branch, but the remote branch was deleted.' end end |
#if_clean(message = DEFAULT_DIRTY_MESSAGE) ⇒ Object
Public: Perform the block if the Git index is clean
153 154 155 156 157 158 159 160 |
# File 'lib/ninny/git.rb', line 153 def if_clean( = DEFAULT_DIRTY_MESSAGE) if clean? || prompt.yes?(DIRTY_CONFIRM_MESSAGE) yield else alert_dirty_index exit 1 end end |
#latest_branch_for(prefix) ⇒ Object
Public: Most recent branch starting with the given string
prefix - String to match branch names against
Returns an Array of Branches containing the branch name
140 141 142 143 |
# File 'lib/ninny/git.rb', line 140 def latest_branch_for(prefix) # I don't really see why the first part would break, and the second would work, but you never know branches_for(prefix).last || Ninny.git.branches_for(prefix).last || raise(NoBranchOfType, "No #{prefix} branch") end |
#merge(branch_name) ⇒ Object
39 40 41 42 43 44 45 46 47 |
# File 'lib/ninny/git.rb', line 39 def merge(branch_name) if_clean do `git fetch --prune &> /dev/null` command('merge', '--no-ff', "origin/#{branch_name}") raise MergeFailed unless clean? push end end |
#new_branch(new_branch_name, source_branch_name) ⇒ Object
Public: Create a new branch from the given source
new_branch_name - The name of the branch to create source_branch_name - The name of the branch to branch from
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/ninny/git.rb', line 86 def new_branch(new_branch_name, source_branch_name) `git fetch --prune &> /dev/null` remote_branches = command('branch', '--remote') if remote_branches.include?("origin/#{new_branch_name}") ask_to_recreate_branch(new_branch_name, source_branch_name) else create_branch(new_branch_name, source_branch_name) end rescue ::Git::GitExecuteError => e if e..include?(':fatal: A branch named') && e..include?(' already exists') puts "The local branch #{new_branch_name} already exists." \ ' Please delete it manually and then run this command again.' exit 1 end end |
#prompt(**options) ⇒ Object
171 172 173 174 |
# File 'lib/ninny/git.rb', line 171 def prompt(**) require 'tty-prompt' TTY::Prompt.new(*) end |
#pull ⇒ Object
Public: Pull the latest changes for the checked-out branch
57 58 59 60 61 |
# File 'lib/ninny/git.rb', line 57 def pull if_clean do command('pull') end end |
#push ⇒ Object
Public: Push the current branch to GitHub
50 51 52 53 54 |
# File 'lib/ninny/git.rb', line 50 def push if_clean do git.push('origin', current_branch_name) end end |
#remote_branches ⇒ Object
Public: The list of branches on GitHub
Returns an Array of Strings containing the branch names
119 120 121 122 |
# File 'lib/ninny/git.rb', line 119 def remote_branches `git fetch --prune &> /dev/null` git.branches.remote.map { |branch| git.branch(branch.name) }.sort_by(&:name) end |
#track_current_branch(do_after_pull = true) ⇒ Object
Public: Track remote branch matching current branch
do_after_pull - Should a pull be done after tracking?
77 78 79 80 |
# File 'lib/ninny/git.rb', line 77 def track_current_branch(do_after_pull = true) command('branch', '-u', "origin/#{current_branch_name}") pull if do_after_pull end |