Class: Autowow::Vcs
- Inherits:
-
Object
- Object
- Autowow::Vcs
- Includes:
- EasyLogging, StringDecorator
- Defined in:
- lib/autowow/vcs.rb
Class Method Summary collapse
- .add_remote(name, url) ⇒ Object
- .add_upstream ⇒ Object
- .branch ⇒ Object
- .branch_force_delete(branch) ⇒ Object
- .branch_merged ⇒ Object
- .branch_pushed(branch) ⇒ Object
- .branches ⇒ Object
- .check_projects_older_than(quantity, unit) ⇒ Object
- .checkout(existing_branch) ⇒ Object
- .clear_branches ⇒ Object
- .create(branch) ⇒ Object
- .current_branch ⇒ Object
- .get_latest_project_info ⇒ Object
- .git_projects ⇒ Object
- .has_upstream?(remotes) ⇒ Boolean
- .hi ⇒ Object
- .hi! ⇒ Object
- .is_git?(start_status) ⇒ Boolean
- .keep_changes ⇒ Object
- .latest_repo ⇒ Object
- .on_branch(branch) ⇒ Object
- .open ⇒ Object
- .origin_push_url(remotes) ⇒ Object
- .origin_push_url_https(remotes) ⇒ Object
- .origin_push_url_https_dot_git(remotes) ⇒ Object
- .origin_push_url_ssl(remotes) ⇒ Object
- .origin_push_url_ssl_dot_git(remotes) ⇒ Object
- .pull ⇒ Object
- .pull_upstream ⇒ Object
- .push ⇒ Object
- .rebase(branch) ⇒ Object
- .remotes ⇒ Object
- .stash ⇒ Object
- .stash_pop ⇒ Object
- .status ⇒ Object
- .status_dry ⇒ Object
- .uncommitted_changes?(start_status) ⇒ Boolean
- .update_project ⇒ Object
- .update_projects ⇒ Object
Class Method Details
.add_remote(name, url) ⇒ Object
243 244 245 |
# File 'lib/autowow/vcs.rb', line 243 def self.add_remote(name, url) Command.run('git', 'remote', 'add', name, url) end |
.add_upstream ⇒ Object
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 |
# File 'lib/autowow/vcs.rb', line 65 def self.add_upstream start_status = status_dry logger.error("Not a git repository.") and return unless is_git?(start_status) remote_list = remotes.stdout logger.warn("Already has upstream.") and return if has_upstream?(remote_list) logger.info(remote_list) url = URI.parse(origin_push_url(remote_list)) host = "api.#{url.host}" path = "/repos#{url.path}" request = Net::HTTP.new(host, url.port) request.verify_mode = OpenSSL::SSL::VERIFY_NONE request.use_ssl = url.scheme == 'https' response = request.get(path) if response.kind_of?(Net::HTTPRedirection) logger.error('Repository moved / renamed. Update remote or implement redirect handling. :)') elsif response.kind_of?(Net::HTTPNotFound) logger.error('Repository not found. Maybe it is private.') elsif response.kind_of?(Net::HTTPSuccess) parsed_response = JSON.parse(response.body) logger.warn('Not a fork.') and return unless parsed_response['fork'] parent_url = parsed_response.dig('parent', 'html_url') add_remote('upstream', parent_url) unless parent_url.to_s.empty? logger.info(remotes.stdout) else logger.error("Github API (#{url.scheme}://#{host}#{path}) could not be reached: #{response.body}") end end |
.branch ⇒ Object
189 190 191 |
# File 'lib/autowow/vcs.rb', line 189 def self.branch Command.run('git', 'branch') end |
.branch_force_delete(branch) ⇒ Object
197 198 199 |
# File 'lib/autowow/vcs.rb', line 197 def self.branch_force_delete(branch) Command.run('git', 'branch', '-D', branch) end |
.branch_merged ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/autowow/vcs.rb', line 21 def self.branch_merged start_status = status logger.info(start_status) working_branch = current_branch logger.error("Nothing to do.") and return if working_branch.eql?('master') keep_changes do checkout('master') pull end branch_force_delete(working_branch) logger.info(status) end |
.branch_pushed(branch) ⇒ Object
278 279 280 |
# File 'lib/autowow/vcs.rb', line 278 def self.branch_pushed(branch) Command.run_dry('git', 'log', branch, '--not', '--remotes').stdout.empty? end |
.branches ⇒ Object
282 283 284 285 |
# File 'lib/autowow/vcs.rb', line 282 def self.branches branches = Command.run_dry('git', 'for-each-ref', "--format='%(refname)'", 'refs/heads/').stdout branches.each_line.map { |line| line.strip[%r{(?<='refs/heads/)(.*)(?=')}] } end |
.check_projects_older_than(quantity, unit) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/autowow/vcs.rb', line 139 def self.check_projects_older_than(quantity, unit) old_projects = Fs.older_than(git_projects, quantity, unit) deprecated_projects = old_projects.reject do |project| Dir.chdir(project) { branches.reject{ |branch| branch_pushed(branch) }.any? } end logger.info("The following projects have not been touched for more than #{quantity} #{unit} and all changes have been pushed, maybe consider removing them?") unless deprecated_projects.empty? deprecated_projects.each do |project| time_diff = TimeDifference.between(File.mtime(project), Time.now).humanize_higher_than(:weeks).downcase logger.info(" #{File.basename(project)} (#{time_diff})") end end |
.checkout(existing_branch) ⇒ Object
170 171 172 |
# File 'lib/autowow/vcs.rb', line 170 def self.checkout(existing_branch) Command.run('git', 'checkout', existing_branch) end |
.clear_branches ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/autowow/vcs.rb', line 53 def self.clear_branches logger.info(branch.stdout) working_branch = current_branch master_branch = 'master' (branches - [master_branch, working_branch]).each do |branch| branch_force_delete(branch) if branch_pushed(branch) end logger.info(branch.stdout) end |
.create(branch) ⇒ Object
174 175 176 177 |
# File 'lib/autowow/vcs.rb', line 174 def self.create(branch) Command.run('git', 'checkout', '-b', branch) Command.run('git', 'push', '--set-upstream', 'origin', branch) end |
.current_branch ⇒ Object
156 157 158 |
# File 'lib/autowow/vcs.rb', line 156 def self.current_branch Command.run_dry('git', 'symbolic-ref', '--short', 'HEAD').stdout end |
.get_latest_project_info ⇒ Object
128 129 130 131 132 133 |
# File 'lib/autowow/vcs.rb', line 128 def self.get_latest_project_info latest = latest_repo time_diff = TimeDifference.between(File.mtime(latest), Time.now).humanize_higher_than(:days).downcase time_diff_text = time_diff.empty? ? 'recently' : "#{time_diff} ago" "It looks like you were working on #{File.basename(latest)} #{time_diff_text}.\n\n" end |
.git_projects ⇒ Object
270 271 272 273 274 275 276 |
# File 'lib/autowow/vcs.rb', line 270 def self.git_projects Fs.ls_dirs.select do |dir| Dir.chdir(dir) do is_git?(status_dry) end end end |
.has_upstream?(remotes) ⇒ Boolean
205 206 207 |
# File 'lib/autowow/vcs.rb', line 205 def self.has_upstream?(remotes) remotes.include?('upstream') end |
.hi ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/autowow/vcs.rb', line 95 def self.hi logger.error("In a git repository. Try 1 level higher.") && return if is_git?(status_dry) latest_project_info = get_latest_project_info logger.info("\nHang on, updating your local projects and remote forks...\n\n") git_projects.each do |project| Dir.chdir(project) do logger.info("\nGetting #{project} in shape...") yield if block_given? update_project end end logger.info("\nGood morning!\n\n") logger.info(latest_project_info) check_projects_older_than(1, :months) logger.info("\nThe following Ruby versions are not used by any projects, maybe consider removing them?\n #{Ruby.obsolete_versions.join("\n ")}") end |
.hi! ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/autowow/vcs.rb', line 112 def self.hi! logger.error("In a git repository. Try 1 level higher.") && return if is_git?(status_dry) hi do logger.info('Removing unused branches...') clear_branches logger.info('Adding upstream...') add_upstream logger.info('Removing unused gems...') logger.info(Gem.clean.stdout) end end |
.is_git?(start_status) ⇒ Boolean
213 214 215 |
# File 'lib/autowow/vcs.rb', line 213 def self.is_git?(start_status) !start_status.include?('Not a git repository') end |
.keep_changes ⇒ Object
262 263 264 265 266 267 268 |
# File 'lib/autowow/vcs.rb', line 262 def self.keep_changes status = status_dry pop_stash = uncommitted_changes?(status) stash if pop_stash yield stash_pop if pop_stash end |
.latest_repo ⇒ Object
135 136 137 |
# File 'lib/autowow/vcs.rb', line 135 def self.latest_repo Fs.latest(git_projects) end |
.on_branch(branch) ⇒ Object
247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/autowow/vcs.rb', line 247 def self.on_branch(branch) keep_changes do working_branch = current_branch switch_needed = !working_branch.eql?(branch) if switch_needed result = checkout(branch) create(branch) if result.stderr.eql?("error: pathspec '#{branch}' did not match any file(s) known to git.") end yield checkout(working_branch) if switch_needed end end |
.open ⇒ Object
124 125 126 |
# File 'lib/autowow/vcs.rb', line 124 def self.open Launchy.open(origin_push_url(remotes.stdout)) end |
.origin_push_url(remotes) ⇒ Object
217 218 219 220 221 222 223 |
# File 'lib/autowow/vcs.rb', line 217 def self.origin_push_url(remotes) # Order is important: first try to match "url" in "#{url}.git" as non-dot_git matchers would include ".git" in the match origin_push_url_ssl_dot_git(remotes) or origin_push_url_ssl(remotes)or origin_push_url_https_dot_git(remotes) or origin_push_url_https(remotes) end |
.origin_push_url_https(remotes) ⇒ Object
225 226 227 |
# File 'lib/autowow/vcs.rb', line 225 def self.origin_push_url_https(remotes) remotes[%r{(?<=origin(\s))http(s?)://[a-zA-Z\-_./]*(?=(\s)\(push\))}] end |
.origin_push_url_https_dot_git(remotes) ⇒ Object
229 230 231 |
# File 'lib/autowow/vcs.rb', line 229 def self.origin_push_url_https_dot_git(remotes) remotes[%r{(?<=origin(\s))http(s?)://[a-zA-Z\-_./]*(?=(\.)git(\s)\(push\))}] end |
.origin_push_url_ssl(remotes) ⇒ Object
238 239 240 241 |
# File 'lib/autowow/vcs.rb', line 238 def self.origin_push_url_ssl(remotes) url = remotes[%r{(?<=origin(\s)git@)[a-zA-Z\-_./:]*(?=(\s)\(push\))}] "https://#{url.gsub(':', '/')}" if url end |
.origin_push_url_ssl_dot_git(remotes) ⇒ Object
233 234 235 236 |
# File 'lib/autowow/vcs.rb', line 233 def self.origin_push_url_ssl_dot_git(remotes) url = remotes[%r{(?<=origin(\s)git@)[a-zA-Z\-_./:]*(?=(\.)git(\s)\(push\))}] "https://#{url.gsub(':', '/')}" if url end |
.pull ⇒ Object
179 180 181 |
# File 'lib/autowow/vcs.rb', line 179 def self.pull Command.run('git', 'pull') end |
.pull_upstream ⇒ Object
183 184 185 186 187 |
# File 'lib/autowow/vcs.rb', line 183 def self.pull_upstream Command.run('git', 'fetch', 'upstream') Command.run('git', 'merge', 'upstream/master') Command.run('git', 'push', 'origin', 'master') end |
.push ⇒ Object
287 288 289 |
# File 'lib/autowow/vcs.rb', line 287 def self.push Command.run('git', 'push') end |
.rebase(branch) ⇒ Object
291 292 293 |
# File 'lib/autowow/vcs.rb', line 291 def self.rebase(branch) Command.run('git', 'rebase', branch) end |
.remotes ⇒ Object
201 202 203 |
# File 'lib/autowow/vcs.rb', line 201 def self.remotes Command.run_dry('git', 'remote', '-v') end |
.stash ⇒ Object
152 153 154 |
# File 'lib/autowow/vcs.rb', line 152 def self.stash Command.run('git', 'stash').output_does_not_match?(%r{No local changes to save}) end |
.stash_pop ⇒ Object
193 194 195 |
# File 'lib/autowow/vcs.rb', line 193 def self.stash_pop Command.run('git', 'stash', 'pop') end |
.status ⇒ Object
160 161 162 163 |
# File 'lib/autowow/vcs.rb', line 160 def self.status status = Command.run('git', 'status') status.stdout + status.stderr end |
.status_dry ⇒ Object
165 166 167 168 |
# File 'lib/autowow/vcs.rb', line 165 def self.status_dry status = Command.run_dry('git', 'status') status.stdout + status.stderr end |
.uncommitted_changes?(start_status) ⇒ Boolean
209 210 211 |
# File 'lib/autowow/vcs.rb', line 209 def self.uncommitted_changes?(start_status) !(start_status.include?('nothing to commit, working tree clean') or start_status.include?('nothing added to commit but untracked files present')) end |
.update_project ⇒ Object
42 43 44 45 46 47 48 49 50 51 |
# File 'lib/autowow/vcs.rb', line 42 def self.update_project start_status = status_dry return unless is_git?(start_status) logger.info("Updating #{File.expand_path('.')} ...") logger.warn("Skipped: uncommitted changes on master.") and return if uncommitted_changes?(start_status) and current_branch.eql?('master') on_branch('master') do has_upstream?(remotes.stdout) ? pull_upstream : pull end end |
.update_projects ⇒ Object
36 37 38 39 40 |
# File 'lib/autowow/vcs.rb', line 36 def self.update_projects Fs.in_place_or_subdirs(is_git?(status_dry)) do update_project end end |