Class: Geet::Utils::GitClient
- Inherits:
-
Object
- Object
- Geet::Utils::GitClient
- Includes:
- Helpers::OsHelper
- Defined in:
- lib/geet/utils/git_client.rb
Overview
Represents the git program interface; used for performing git operations.
Constant Summary collapse
- UPSTREAM_NAME =
'upstream'- REMOTE_URL_REGEX =
Simplified, but good enough, pattern.
Relevant matches:
1: protocol + suffix 2: domain 3: domain<>path separator 4: path (repo, project) 5: suffix %r{ \A (https://|git@) (.+?) ([/:]) (.+/.+?) (\.git)? \Z }x
- UPSTREAM_BRANCH_REGEX =
%r{\A[^/]+/([^/]+)\Z}- CLEAN_TREE_MESSAGE_REGEX =
/^nothing to commit, working tree clean$/
Instance Method Summary collapse
- #add_remote(name, url) ⇒ Object
-
#checkout(branch) ⇒ Object
OPERATION APIS.
-
#cherry(limit) ⇒ Object
Return the commit shas between HEAD and
limit, excluding the already applied commits (which start with-). - #current_branch ⇒ Object
-
#delete_branch(branch) ⇒ Object
Unforced deletion.
-
#fetch ⇒ Object
Performs pruning.
-
#initialize(location: nil) ⇒ GitClient
constructor
A new instance of GitClient.
- #owner ⇒ Object
-
#path(upstream: false) ⇒ Object
Example:
donaldduck/geet. - #provider_domain ⇒ Object
-
#push(upstream_branch: nil) ⇒ Object
upstream_branch: create an upstream branch.
- #rebase ⇒ Object
-
#remote(name: nil) ⇒ Object
Returns the URL of the remote with the given name.
-
#remote_components(name: nil) ⇒ Object
Return the components of the remote, according to REMOTE_URL_REGEX; doesn’t include the full match.
-
#remote_defined?(name) ⇒ Boolean
Doesn’t sanity check for the remote url format; this action is for querying purposes, any any action that needs to work with the remote, uses #remote.
-
#show_description(object) ⇒ Object
Show the description (“<subject>nn<body>”) for the given git object.
-
#upstream_branch ⇒ Object
Not to be confused with
upstreamrepository!. -
#upstream_branch_gone? ⇒ Boolean
TODO: May be merged with :upstream_branch, although it would require designing how a gone remote branch is expressed.
- #working_tree_clean? ⇒ Boolean
Methods included from Helpers::OsHelper
#execute_command, #open_file_with_default_application
Constructor Details
#initialize(location: nil) ⇒ GitClient
Returns a new instance of GitClient.
40 41 42 |
# File 'lib/geet/utils/git_client.rb', line 40 def initialize(location: nil) @location = location end |
Instance Method Details
#add_remote(name, url) ⇒ Object
217 218 219 |
# File 'lib/geet/utils/git_client.rb', line 217 def add_remote(name, url) execute_git_command("remote add #{name.shellescape} #{url}") end |
#checkout(branch) ⇒ Object
OPERATION APIS
189 190 191 |
# File 'lib/geet/utils/git_client.rb', line 189 def checkout(branch) execute_git_command("checkout #{branch.shellescape}") end |
#cherry(limit) ⇒ Object
Return the commit shas between HEAD and limit, excluding the already applied commits (which start with -)
51 52 53 54 55 |
# File 'lib/geet/utils/git_client.rb', line 51 def cherry(limit) raw_commits = execute_git_command("cherry #{limit.shellescape}") raw_commits.split("\n").grep(/^\+/).map { |line| line[3..-1] } end |
#current_branch ⇒ Object
57 58 59 60 61 62 63 |
# File 'lib/geet/utils/git_client.rb', line 57 def current_branch branch = execute_git_command("rev-parse --abbrev-ref HEAD") raise "Couldn't find current branch" if branch == 'HEAD' branch end |
#delete_branch(branch) ⇒ Object
Unforced deletion.
195 196 197 |
# File 'lib/geet/utils/git_client.rb', line 195 def delete_branch(branch) execute_git_command("branch --delete #{branch.shellescape}") end |
#fetch ⇒ Object
Performs pruning.
213 214 215 |
# File 'lib/geet/utils/git_client.rb', line 213 def fetch execute_git_command("fetch --prune") end |
#owner ⇒ Object
140 141 142 |
# File 'lib/geet/utils/git_client.rb', line 140 def owner path.split('/')[0] end |
#path(upstream: false) ⇒ Object
Example: donaldduck/geet
134 135 136 137 138 |
# File 'lib/geet/utils/git_client.rb', line 134 def path(upstream: false) remote_name_option = upstream ? {name: UPSTREAM_NAME} : {} remote(**remote_name_option)[REMOTE_URL_REGEX, 4] end |
#provider_domain ⇒ Object
144 145 146 147 148 149 150 151 152 |
# File 'lib/geet/utils/git_client.rb', line 144 def provider_domain # We assume that it's not possible to have origin and upstream on different providers. domain = remote()[REMOTE_URL_REGEX, 2] raise "Can't identify domain in the provider domain string: #{domain}" if domain !~ /\w+\.\w+/ domain end |
#push(upstream_branch: nil) ⇒ Object
upstream_branch: create an upstream branch.
205 206 207 208 209 |
# File 'lib/geet/utils/git_client.rb', line 205 def push(upstream_branch: nil) upstream_branch_option = "-u origin #{upstream_branch.shellescape}" if upstream_branch execute_git_command("push #{upstream_branch_option}") end |
#rebase ⇒ Object
199 200 201 |
# File 'lib/geet/utils/git_client.rb', line 199 def rebase execute_git_command("rebase") end |
#remote(name: nil) ⇒ Object
Returns the URL of the remote with the given name. Sanity checks are performed.
The result is in the format ‘[email protected]:donaldduck/geet.git`
options
:name: remote name; if unspecified, the default remote is used.
162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/geet/utils/git_client.rb', line 162 def remote(name: nil) remote_url = execute_git_command("ls-remote --get-url #{name}") if !remote_defined?(name) raise "Remote #{name.inspect} not found!" elsif remote_url !~ REMOTE_URL_REGEX raise "Unexpected remote reference format: #{remote_url.inspect}" end remote_url end |
#remote_components(name: nil) ⇒ Object
Return the components of the remote, according to REMOTE_URL_REGEX; doesn’t include the full match.
128 129 130 |
# File 'lib/geet/utils/git_client.rb', line 128 def remote_components(name: nil) remote.match(REMOTE_URL_REGEX)[1..] end |
#remote_defined?(name) ⇒ Boolean
Doesn’t sanity check for the remote url format; this action is for querying purposes, any any action that needs to work with the remote, uses #remote.
177 178 179 180 181 182 183 |
# File 'lib/geet/utils/git_client.rb', line 177 def remote_defined?(name) remote_url = execute_git_command("ls-remote --get-url #{name}") # If the remote is not defined, `git ls-remote` will return the passed value. # remote_url != name end |
#show_description(object) ⇒ Object
Show the description (“<subject>nn<body>”) for the given git object.
117 118 119 |
# File 'lib/geet/utils/git_client.rb', line 117 def show_description(object) execute_git_command("show --quiet --format='%s\n\n%b' #{object.shellescape}") end |
#upstream_branch ⇒ Object
Not to be confused with upstream repository!
This API doesn’t reveal if the remote branch is gone.
return: nil, if the upstream branch is not configured.
71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/geet/utils/git_client.rb', line 71 def upstream_branch head_symbolic_ref = execute_git_command("symbolic-ref -q HEAD") raw_upstream_branch = execute_git_command("for-each-ref --format='%(upstream:short)' #{head_symbolic_ref.shellescape}").strip if raw_upstream_branch != '' raw_upstream_branch[UPSTREAM_BRANCH_REGEX, 1] || raise("Unexpected upstream format: #{raw_upstream_branch}") else nil end end |
#upstream_branch_gone? ⇒ Boolean
TODO: May be merged with :upstream_branch, although it would require designing how a gone remote branch is expressed.
Sample command output:
## add_milestone_closing...origin/add_milestone_closing [gone]
M spec/integration/merge_pr_spec.rb
91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/geet/utils/git_client.rb', line 91 def upstream_branch_gone? git_command = "status -b --porcelain" status_output = execute_git_command(git_command) # Simplified branch naming pattern. The exact one (see https://stackoverflow.com/a/3651867) # is not worth implementing. # if status_output =~ %r(^## .+\.\.\..+?( \[gone\])?$) !!$LAST_MATCH_INFO[1] else raise "Unexpected git command #{git_command.inspect} output: #{status_output}" end end |
#working_tree_clean? ⇒ Boolean
105 106 107 108 109 |
# File 'lib/geet/utils/git_client.rb', line 105 def working_tree_clean? = execute_git_command("status") !!( =~ CLEAN_TREE_MESSAGE_REGEX) end |