Class: Dev::Git
- Defined in:
- lib/firespring_dev_commands/git.rb,
lib/firespring_dev_commands/git/info.rb
Overview
Class for performing git functions
Defined Under Namespace
Constant Summary collapse
- DEFAULT_MAIN_BRANCH =
The default base branch to use
'master'.freeze
Instance Attribute Summary collapse
-
#info ⇒ Object
Returns the value of attribute info.
-
#main_branch ⇒ Object
Returns the value of attribute main_branch.
-
#original_branches ⇒ Object
Populates and returns a hash containing the original version of branches.
-
#release_branches ⇒ Object
Returns the value of attribute release_branches.
-
#staging_branch ⇒ Object
Returns the value of attribute staging_branch.
Class Method Summary collapse
-
.config {|@config| ... } ⇒ Object
(also: configure)
Instantiates a new top level config object if one hasn’t already been created Yields that config object to any given block Returns the resulting config object.
-
.version ⇒ Object
Returns the version of the git executable running on the system.
Instance Method Summary collapse
-
#add(*paths, dir: default_project_dir, raise_errors: false) ⇒ Object
Add the given paths to git Defaults to the current directory optionally raise errors.
-
#branch_exists?(project_dir, branch_name) ⇒ Boolean
Returns true if the remote branch exists, false otherwise.
-
#branch_name(dir: default_project_dir) ⇒ Object
Returns the branch name associated with the given repository Defaults to the current directory.
-
#changes(dir: default_project_dir) ⇒ Object
Print the changes on the given repo Defaults to the current directory.
-
#changes_slow(dir: default_project_dir) ⇒ Object
Print the changes on the given repo using the ruby built-in method…
-
#check_version ⇒ Object
Checks the min and max version against the current git version if they have been configured.
-
#checkout(branch, dir: default_project_dir, raise_errors: false) ⇒ Object
Checks out the given branch in the given repo Defaults to the current directory optionally raise errors.
-
#checkout_all(branch) ⇒ Object
Checks out the given branch in all repositories with some additional formatting.
-
#clone_repo(dir:, repo_name:, repo_org: nil, branch: nil, depth: nil) ⇒ Object
Clones the repo_name into the dir Optionally specify a repo_org Optionally specify a branch to check out (defaults to the repository default branch).
-
#clone_repos ⇒ Object
Clones all repositories.
- #commit_status(token:, repo_name:, commit_id:, status:, repo_org: nil, options: {}) ⇒ Object
-
#create_branch(branch, dir: default_project_dir, raise_errors: false) ⇒ Object
Create the given branch in the given repo Defaults to the current directory optionally raise errors.
-
#current_branches ⇒ Object
Returns a hash of each project repo and the branch that is currently checked out.
-
#default_project_dir ⇒ Object
Returns the first configured project dire.
-
#indent(string, padding: ' ') ⇒ Object
Split on newlines and add additional padding.
-
#initialize(main_branch: self.class.config.main_branch, staging_branch: self.class.config.staging_branch, info: self.class.config.info) ⇒ Git
constructor
A new instance of Git.
-
#merge(branch, dir: default_project_dir, raise_errors: false) ⇒ Object
Merge the given branch into the given repo Defaults to the current directory optionally raise errors.
-
#merge_all(branch) ⇒ Object
Merge the branch into all repositories.
-
#project_dirs ⇒ Object
Returns all git paths configured in our info.
-
#pull(dir: default_project_dir, raise_errors: false) ⇒ Object
Pull the given repo Defaults to the current directory optionally raise errors.
-
#pull_all ⇒ Object
Pull the latest in all repositories.
-
#push(dir: default_project_dir, raise_errors: false) ⇒ Object
Push the given repo Defaults to the current directory optionally raise errors.
-
#push_all ⇒ Object
Push to remote in all repositories.
-
#repos_with_changes ⇒ Object
Returns the name of any repositories which have changes.
-
#reset(dir: default_project_dir) ⇒ Object
Runs a git reset on the given repo Defaults to the current directory.
-
#reset_all ⇒ Object
Runs a git reset on all given repositories with some additional formatting.
-
#ssh_repo_url(name, org) ⇒ Object
Builds an ssh repo URL using the org and repo name given.
-
#status(dir: default_project_dir) ⇒ Object
Prints the results of the status command Currently running “git status” instead of using the library because it doesn’t do well formatting the output.
-
#status_all ⇒ Object
Prints the status of multiple repository directories and displays the results in a nice format.
Constructor Details
#initialize(main_branch: self.class.config.main_branch, staging_branch: self.class.config.staging_branch, info: self.class.config.info) ⇒ Git
Returns a new instance of Git.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/firespring_dev_commands/git.rb', line 43 def initialize( main_branch: self.class.config.main_branch, staging_branch: self.class.config.staging_branch, info: self.class.config.info ) @main_branch = main_branch raise 'main branch must be configured' if main_branch.to_s.empty? @staging_branch = staging_branch || main_branch @info = Array(info) raise 'git repositories must be configured' if @info.empty? || !@info.all?(Dev::Git::Info) check_version end |
Instance Attribute Details
#info ⇒ Object
Returns the value of attribute info.
41 42 43 |
# File 'lib/firespring_dev_commands/git.rb', line 41 def info @info end |
#main_branch ⇒ Object
Returns the value of attribute main_branch.
41 42 43 |
# File 'lib/firespring_dev_commands/git.rb', line 41 def main_branch @main_branch end |
#original_branches ⇒ Object
Populates and returns a hash containing the original version of branches
78 79 80 |
# File 'lib/firespring_dev_commands/git.rb', line 78 def original_branches @original_branches end |
#release_branches ⇒ Object
Returns the value of attribute release_branches.
41 42 43 |
# File 'lib/firespring_dev_commands/git.rb', line 41 def release_branches @release_branches end |
#staging_branch ⇒ Object
Returns the value of attribute staging_branch.
41 42 43 |
# File 'lib/firespring_dev_commands/git.rb', line 41 def staging_branch @staging_branch end |
Class Method Details
.config {|@config| ... } ⇒ Object Also known as: configure
Instantiates a new top level config object if one hasn’t already been created Yields that config object to any given block Returns the resulting config object
26 27 28 29 30 |
# File 'lib/firespring_dev_commands/git.rb', line 26 def config @config ||= Config.new yield(@config) if block_given? @config end |
.version ⇒ Object
Returns the version of the git executable running on the system
36 37 38 |
# File 'lib/firespring_dev_commands/git.rb', line 36 def version @version ||= ::Git::Lib.new(nil, nil).current_command_version.join('.') end |
Instance Method Details
#add(*paths, dir: default_project_dir, raise_errors: false) ⇒ Object
Add the given paths to git Defaults to the current directory optionally raise errors
269 270 271 272 273 274 275 276 277 278 |
# File 'lib/firespring_dev_commands/git.rb', line 269 def add(*paths, dir: default_project_dir, raise_errors: false) g = ::Git.open(dir) indent g.add(paths) true rescue ::Git::GitExecuteError => e raise e if raise_errors print_errors(e.) false end |
#branch_exists?(project_dir, branch_name) ⇒ Boolean
Returns true if the remote branch exists, false otherwise
105 106 107 |
# File 'lib/firespring_dev_commands/git.rb', line 105 def branch_exists?(project_dir, branch_name) ::Git.ls_remote(project_dir)['remotes']["origin/#{branch_name}"] end |
#branch_name(dir: default_project_dir) ⇒ Object
Returns the branch name associated with the given repository Defaults to the current directory
97 98 99 100 101 102 |
# File 'lib/firespring_dev_commands/git.rb', line 97 def branch_name(dir: default_project_dir) return unless File.exist?(dir) g = ::Git.open(dir) g.current_branch || "HEAD detached at #{g.object('HEAD').sha[0..7]}" end |
#changes(dir: default_project_dir) ⇒ Object
Print the changes on the given repo Defaults to the current directory
145 146 147 148 149 |
# File 'lib/firespring_dev_commands/git.rb', line 145 def changes(dir: default_project_dir) return unless File.exist?(dir) Dir.chdir(dir) { `git status --porcelain | grep -v '^?'` }.split("\n").map(&:strip) end |
#changes_slow(dir: default_project_dir) ⇒ Object
Print the changes on the given repo using the ruby built-in method… which seems REALLY slow compared to the porcelain version Defaults to the current directory
153 154 155 156 157 158 159 160 |
# File 'lib/firespring_dev_commands/git.rb', line 153 def changes_slow(dir: default_project_dir) return unless File.exist?(dir) s = ::Git.open(dir).status s.added.keys.map { |it| " A #{it}" } + s.changed.keys.map { |it| " M #{it}" } + s.deleted.keys.map { |it| " D #{it}" } end |
#check_version ⇒ Object
Checks the min and max version against the current git version if they have been configured
59 60 61 62 63 64 65 |
# File 'lib/firespring_dev_commands/git.rb', line 59 def check_version min_version = self.class.config.min_version raise "requires git version >= #{min_version} (found #{self.class.version})" if min_version && !Dev::Common.new.version_greater_than(min_version, self.class.version) max_version = self.class.config.max_version raise "requires git version < #{max_version} (found #{self.class.version})" if max_version && Dev::Common.new.version_greater_than(max_version, self.class.version) end |
#checkout(branch, dir: default_project_dir, raise_errors: false) ⇒ Object
Checks out the given branch in the given repo Defaults to the current directory optionally raise errors
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/firespring_dev_commands/git.rb', line 208 def checkout(branch, dir: default_project_dir, raise_errors: false) raise 'branch is required' if branch.to_s.strip.empty? return unless File.exist?(dir) # Make sure the original branch hash has been created before we change anything original_branches g = ::Git.open(dir) g.fetch('origin', prune: true) # If the branch we are checking out doesn't exist, check out either the staging branch or the main branch actual_branch = branch unless branch_exists?(dir, branch) actual_branch = [staging_branch, main_branch].uniq.find { |it| branch_exists?(dir, it) } puts "Branch #{branch} not found, checking out #{actual_branch} instead".light_yellow end indent g.checkout(actual_branch) indent g.pull('origin', actual_branch) true rescue ::Git::GitExecuteError => e raise e if raise_errors print_errors(e.) false end |
#checkout_all(branch) ⇒ Object
Checks out the given branch in all repositories with some additional formatting
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/firespring_dev_commands/git.rb', line 188 def checkout_all(branch) @success = true puts puts "Checking out #{branch} in each repo".light_yellow if project_dirs.length > 1 project_dirs.each do |project_dir| next unless File.exist?(project_dir) repo_basename = File.basename(File.realpath(project_dir)) puts Dev::Common.new.center_pad(repo_basename).light_green @success &= checkout(branch, dir: project_dir) puts Dev::Common.new.center_pad.light_green end puts raise "Failed checking out branch #{branch} one or more repositories" unless @success end |
#clone_repo(dir:, repo_name:, repo_org: nil, branch: nil, depth: nil) ⇒ Object
Clones the repo_name into the dir Optionally specify a repo_org Optionally specify a branch to check out (defaults to the repository default branch)
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/firespring_dev_commands/git.rb', line 412 def clone_repo(dir:, repo_name:, repo_org: nil, branch: nil, depth: nil) # TODO: Split out the default of 'firespring' into a configuration variable repo_org = 'firespring' if repo_org.to_s.strip.empty? if Dir.exist?("#{dir}/.git") puts "#{dir} already cloned".light_green return end FileUtils.mkdir_p(dir.to_s) puts "Cloning #{dir} from #{ssh_repo_url(repo_name, repo_org)}".light_yellow opts = {} opts[:branch] = branch unless branch.to_s.strip.empty? opts[:depth] = depth unless depth.to_s.strip.empty? g = ::Git.clone(ssh_repo_url(repo_name, repo_org), dir, opts) g.fetch('origin', prune: true) end |
#clone_repos ⇒ Object
Clones all repositories
405 406 407 |
# File 'lib/firespring_dev_commands/git.rb', line 405 def clone_repos info.each { |it| clone_repo(dir: it.path, repo_name: it.name) } end |
#commit_status(token:, repo_name:, commit_id:, status:, repo_org: nil, options: {}) ⇒ Object
432 433 434 435 436 437 438 439 440 441 442 443 |
# File 'lib/firespring_dev_commands/git.rb', line 432 def commit_status(token:, repo_name:, commit_id:, status:, repo_org: nil, options: {}) # TODO: Split out the default of 'firespring' into a configuration variable repo_org = 'firespring' if repo_org.to_s.strip.empty? repo = "#{repo_org}/#{repo_name}" # Set up the GitHub client client = Octokit::Client.new(access_token: token) # Create the commit status puts "Tagging commit #{commit_id} in #{repo} as #{status} for #{[:context]}" client.create_status(repo, commit_id, status, ) end |
#create_branch(branch, dir: default_project_dir, raise_errors: false) ⇒ Object
Create the given branch in the given repo Defaults to the current directory optionally raise errors
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/firespring_dev_commands/git.rb', line 238 def create_branch(branch, dir: default_project_dir, raise_errors: false) raise 'branch is required' if branch.to_s.strip.empty? raise "refusing to create protected branch '#{branch}'" if %w(master develop).any?(branch.to_s.strip) return unless File.exist?(dir) # Make sure the original branch hash has been created before we change anything original_branches g = ::Git.open(dir) g.fetch('origin', prune: true) puts "Fetching the latest changes for base branch \"#{staging_branch}\"" g.checkout(staging_branch) g.pull('origin', staging_branch) puts "Creating branch #{branch}, pushing to origin, and updating remote tracking" g.branch(branch).checkout g.push('origin', branch) g.config("branch.#{branch}.remote", 'origin') g.config("branch.#{branch}.merge", "refs/heads/#{branch}") puts rescue ::Git::GitExecuteError => e raise e if raise_errors print_errors(e.) false end |
#current_branches ⇒ Object
Returns a hash of each project repo and the branch that is currently checked out
83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/firespring_dev_commands/git.rb', line 83 def current_branches {}.tap do |hsh| project_dirs.each do |project_dir| next unless File.exist?(project_dir) Dir.chdir(project_dir) do hsh[project_dir] = branch_name(dir: project_dir) end end end end |
#default_project_dir ⇒ Object
Returns the first configured project dire
73 74 75 |
# File 'lib/firespring_dev_commands/git.rb', line 73 def default_project_dir project_dirs.first end |
#indent(string, padding: ' ') ⇒ Object
Split on newlines and add additional padding
451 452 453 |
# File 'lib/firespring_dev_commands/git.rb', line 451 def indent(string, padding: ' ') string.to_s.split("\n").each { |line| puts "#{padding}#{line}" } end |
#merge(branch, dir: default_project_dir, raise_errors: false) ⇒ Object
Merge the given branch into the given repo Defaults to the current directory optionally raise errors
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/firespring_dev_commands/git.rb', line 303 def merge(branch, dir: default_project_dir, raise_errors: false) raise 'branch is required' if branch.to_s.strip.empty? return unless File.exist?(dir) # Make sure the original branch hash has been created before we change anything original_branches g = ::Git.open(dir) g.fetch('origin', prune: true) raise 'branch does not exist' unless branch_exists?(dir, branch) # No need to merge into ourself current_branch = branch_name(dir:) return true if current_branch == branch indent "Merging #{branch} into #{current_branch}" indent g.merge(branch) true rescue ::Git::GitExecuteError => e raise e if raise_errors print_errors(e.) false end |
#merge_all(branch) ⇒ Object
Merge the branch into all repositories
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/firespring_dev_commands/git.rb', line 281 def merge_all(branch) @success = true puts puts "Merging #{branch} into each repo".light_yellow if project_dirs.length > 1 project_dirs.each do |project_dir| next unless File.exist?(project_dir) repo_basename = File.basename(File.realpath(project_dir)) puts Dev::Common.new.center_pad(repo_basename).light_green @success &= merge(branch, dir: project_dir) puts Dev::Common.new.center_pad.light_green end puts raise "Failed merging branch #{branch} in one or more repositories" unless @success push_all end |
#project_dirs ⇒ Object
Returns all git paths configured in our info
68 69 70 |
# File 'lib/firespring_dev_commands/git.rb', line 68 def project_dirs @project_dirs ||= @info.map(&:path).sort end |
#pull(dir: default_project_dir, raise_errors: false) ⇒ Object
Pull the given repo Defaults to the current directory optionally raise errors
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/firespring_dev_commands/git.rb', line 349 def pull(dir: default_project_dir, raise_errors: false) return unless File.exist?(dir) g = ::Git.open(dir) g.fetch('origin', prune: true) branch = branch_name(dir:) indent "Pulling branch #{branch} from origin" indent g.pull('origin', branch) true rescue ::Git::GitExecuteError => e raise e if raise_errors print_errors(e.) false end |
#pull_all ⇒ Object
Pull the latest in all repositories
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/firespring_dev_commands/git.rb', line 329 def pull_all @success = true puts puts 'Pulling current branch into each repo'.light_yellow if project_dirs.length > 1 project_dirs.each do |project_dir| next unless File.exist?(project_dir) repo_basename = File.basename(File.realpath(project_dir)) puts Dev::Common.new.center_pad(repo_basename).light_green @success &= pull(dir: project_dir) puts Dev::Common.new.center_pad.light_green end puts raise 'Failed pulling branch in one or more repositories' unless @success end |
#push(dir: default_project_dir, raise_errors: false) ⇒ Object
Push the given repo Defaults to the current directory optionally raise errors
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/firespring_dev_commands/git.rb', line 387 def push(dir: default_project_dir, raise_errors: false) return unless File.exist?(dir) g = ::Git.open(dir) g.fetch('origin', prune: true) branch = branch_name(dir:) indent "Pushing branch #{branch} to origin" indent g.push('origin', branch) true rescue ::Git::GitExecuteError => e raise e if raise_errors print_errors(e.) false end |
#push_all ⇒ Object
Push to remote in all repositories
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/firespring_dev_commands/git.rb', line 367 def push_all @success = true puts puts 'Pushing current branch into each repo'.light_yellow if project_dirs.length > 1 project_dirs.each do |project_dir| next unless File.exist?(project_dir) repo_basename = File.basename(File.realpath(project_dir)) puts Dev::Common.new.center_pad(repo_basename).light_green @success &= push(dir: project_dir) puts Dev::Common.new.center_pad.light_green end puts raise 'Failed pushing branch in one or more repositories' unless @success end |
#repos_with_changes ⇒ Object
Returns the name of any repositories which have changes
139 140 141 |
# File 'lib/firespring_dev_commands/git.rb', line 139 def repos_with_changes info.filter_map { |it| it.name unless changes(dir: it.path).empty? } end |
#reset(dir: default_project_dir) ⇒ Object
Runs a git reset on the given repo Defaults to the current directory
180 181 182 183 184 185 |
# File 'lib/firespring_dev_commands/git.rb', line 180 def reset(dir: default_project_dir) return unless File.exist?(dir) g = ::Git.open(dir) indent g.reset_hard end |
#reset_all ⇒ Object
Runs a git reset on all given repositories with some additional formatting
163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/firespring_dev_commands/git.rb', line 163 def reset_all puts puts 'Resetting each repo'.light_yellow if project_dirs.length > 1 project_dirs.each do |project_dir| next unless File.exist?(project_dir) repo_basename = File.basename(File.realpath(project_dir)) header = "#{repo_basename} (#{original_branches[project_dir]})" puts Dev::Common.new.center_pad(header).light_green reset(dir: project_dir) puts Dev::Common.new.center_pad.light_green end puts end |
#ssh_repo_url(name, org) ⇒ Object
Builds an ssh repo URL using the org and repo name given
446 447 448 |
# File 'lib/firespring_dev_commands/git.rb', line 446 def ssh_repo_url(name, org) "[email protected]:#{org}/#{name}.git" end |
#status(dir: default_project_dir) ⇒ Object
Prints the results of the status command Currently running “git status” instead of using the library because it doesn’t do well formatting the output
130 131 132 133 134 135 136 |
# File 'lib/firespring_dev_commands/git.rb', line 130 def status(dir: default_project_dir) return unless File.exist?(dir) # NOTE: git library doesn't have a good "status" analog. So just run the standard "git" one # splitting and puts'ing to prefix each line with spaces... Dir.chdir(dir) { indent `git status` } end |
#status_all ⇒ Object
Prints the status of multiple repository directories and displays the results in a nice format
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/firespring_dev_commands/git.rb', line 110 def status_all @success = true puts puts 'Getting status in each repo'.light_yellow if project_dirs.length > 1 project_dirs.each do |project_dir| next unless File.exist?(project_dir) repo_basename = File.basename(File.realpath(project_dir)) header = "#{repo_basename} (#{original_branches[project_dir]})" puts Dev::Common.new.center_pad(header).light_green @success &= status(dir: project_dir) puts Dev::Common.new.center_pad.light_green end puts raise 'Failed getting status on one or more repositories' unless @success end |