autowow 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,48 +1,48 @@
1
- require 'pastel'
2
-
3
- require_relative '../commands/gem'
4
- require_relative 'vcs'
5
-
6
- module Autowow
7
- module Features
8
- module Gem
9
- include EasyLogging
10
- include Commands::Gem
11
- include Commands::Vcs
12
- include Executor
13
-
14
- def gem_release
15
- pretty_with_output.run(git_status)
16
- start_branch = Vcs.working_branch
17
- logger.error("Not on master.") and return unless start_branch.eql?('master')
18
- pretty.run(push)
19
-
20
- Vcs.on_branch('release') do
21
- pretty.run(pull)
22
- pretty.run(rebase(start_branch))
23
- pretty_with_output.run(release)
24
- end
25
-
26
- pretty_with_output.run(git_status)
27
- end
28
-
29
- def gem_clean
30
- pretty_with_output.run(clean)
31
- end
32
-
33
- def rubocop_parallel_autocorrect
34
- pastel = Pastel.new
35
- result = pretty_with_output.run!(rubocop_parallel)
36
- if result.failed?
37
- filtered = result.out.each_line.select { |line| line.match(%r{(.*):([0-9]*):([0-9]*):}) }
38
- .map{ |line| line.split(':')[0] }
39
- .uniq
40
- .map{ |line| pastel.strip(line) }
41
- pretty_with_output.run(rubocop_autocorrect(filtered)) if filtered.any?
42
- end
43
- end
44
-
45
- include ReflectionUtils::CreateModuleFunctions
46
- end
47
- end
48
- end
1
+ require "pastel"
2
+
3
+ require_relative "../commands/gem"
4
+ require_relative "vcs"
5
+
6
+ module Autowow
7
+ module Features
8
+ module Gem
9
+ include EasyLogging
10
+ include Commands::Gem
11
+ include Commands::Vcs
12
+ include Executor
13
+
14
+ def gem_release
15
+ pretty_with_output.run(git_status)
16
+ start_branch = Vcs.working_branch
17
+ logger.error("Not on master.") and return unless start_branch.eql?("master")
18
+ pretty.run(push)
19
+
20
+ Vcs.on_branch("release") do
21
+ pretty.run(pull)
22
+ pretty.run(rebase(start_branch))
23
+ pretty_with_output.run(release)
24
+ end
25
+
26
+ pretty_with_output.run(git_status)
27
+ end
28
+
29
+ def gem_clean
30
+ pretty_with_output.run(clean)
31
+ end
32
+
33
+ def rubocop_parallel_autocorrect
34
+ pastel = Pastel.new
35
+ result = pretty_with_output.run!(rubocop_parallel)
36
+ if result.failed?
37
+ filtered = result.out.each_line.select { |line| line.match(%r{(.*):([0-9]*):([0-9]*):}) }
38
+ .map { |line| line.split(":")[0] }
39
+ .uniq
40
+ .map { |line| pastel.strip(line) }
41
+ pretty_with_output.run(rubocop_autocorrect(filtered)) if filtered.any?
42
+ end
43
+ end
44
+
45
+ include ReflectionUtils::CreateModuleFunctions
46
+ end
47
+ end
48
+ end
@@ -1,16 +1,16 @@
1
- require_relative '../commands/os'
2
-
3
- module Autowow
4
- module Features
5
- module Os
6
- include Commands::Os
7
- include Executor
8
-
9
- def exists?(cmd)
10
- quiet.run!(which(cmd)).success?
11
- end
12
-
13
- include ReflectionUtils::CreateModuleFunctions
14
- end
15
- end
16
- end
1
+ require_relative "../commands/os"
2
+
3
+ module Autowow
4
+ module Features
5
+ module Os
6
+ include Commands::Os
7
+ include Executor
8
+
9
+ def exists?(cmd)
10
+ quiet.run!(which(cmd)).success?
11
+ end
12
+
13
+ include ReflectionUtils::CreateModuleFunctions
14
+ end
15
+ end
16
+ end
@@ -1,50 +1,50 @@
1
- require_relative '../commands/rbenv'
2
- require_relative '../commands/vcs'
3
-
4
- require_relative 'fs'
5
- require_relative 'vcs'
6
-
7
- module Autowow
8
- module Features
9
- module Rbenv
10
- include EasyLogging
11
- include Commands::Rbenv
12
- include Executor
13
- include StringDecorator
14
-
15
- def ruby_versions
16
- logger.info(used_versions)
17
- end
18
-
19
- def used_versions
20
- rubies = []
21
- Fs.in_place_or_subdirs(Vcs.is_git?) do
22
- result = quiet.run!(version)
23
- rubies.concat(result.out.clean_lines) if result.success?
24
- end
25
- rubies.uniq
26
- end
27
-
28
- def ruby_aliases
29
- ret = {}
30
- result = quiet.run!(aliases)
31
- return ret unless result.success?
32
- result.out.clean_lines.each do |line|
33
- ret[line.split(' => ')[0]] = line.split(' => ')[1]
34
- end
35
- ret
36
- end
37
-
38
- def obsolete_versions
39
- alias_map = ruby_aliases
40
- used_versions_and_aliases = used_versions
41
- used_versions.each do |v|
42
- used_versions_and_aliases.push(alias_map[v]) if alias_map.has_key?(v)
43
- end
44
- quiet.run(installed_versions).out.clean_lines - used_versions_and_aliases
45
- end
46
-
47
- include ReflectionUtils::CreateModuleFunctions
48
- end
49
- end
50
- end
1
+ require_relative "../commands/rbenv"
2
+ require_relative "../commands/vcs"
3
+
4
+ require_relative "fs"
5
+ require_relative "vcs"
6
+
7
+ module Autowow
8
+ module Features
9
+ module Rbenv
10
+ include EasyLogging
11
+ include Commands::Rbenv
12
+ include Executor
13
+ include StringDecorator
14
+
15
+ def ruby_versions
16
+ logger.info(used_versions)
17
+ end
18
+
19
+ def used_versions
20
+ rubies = []
21
+ Fs.in_place_or_subdirs(Vcs.is_git?) do
22
+ result = quiet.run!(version)
23
+ rubies.concat(result.out.clean_lines) if result.success?
24
+ end
25
+ rubies.uniq
26
+ end
27
+
28
+ def ruby_aliases
29
+ ret = {}
30
+ result = quiet.run!(aliases)
31
+ return ret unless result.success?
32
+ result.out.clean_lines.each do |line|
33
+ ret[line.split(" => ")[0]] = line.split(" => ")[1]
34
+ end
35
+ ret
36
+ end
37
+
38
+ def obsolete_versions
39
+ alias_map = ruby_aliases
40
+ used_versions_and_aliases = used_versions
41
+ used_versions.each do |v|
42
+ used_versions_and_aliases.push(alias_map[v]) if alias_map.has_key?(v)
43
+ end
44
+ quiet.run(installed_versions).out.clean_lines - used_versions_and_aliases
45
+ end
46
+
47
+ include ReflectionUtils::CreateModuleFunctions
48
+ end
49
+ end
50
+ end
@@ -1,272 +1,272 @@
1
- require 'uri'
2
- require 'net/https'
3
- require 'net/http'
4
- require 'json'
5
- require 'launchy'
6
-
7
- require_relative '../commands/vcs'
8
- require_relative 'fs'
9
- require_relative 'rbenv'
10
- require_relative 'gem'
11
- require_relative '../time_difference'
12
-
13
- module Autowow
14
- module Features
15
- module Vcs
16
- include EasyLogging
17
- include Commands::Vcs
18
- include Executor
19
- include StringDecorator
20
-
21
- using RefinedTimeDifference
22
-
23
- def self.hi!
24
- logger.error("In a git repository. Try 1 level higher.") && return if is_git?
25
- hi do
26
- logger.info('Removing unused branches...')
27
- clear_branches
28
- logger.info('Adding upstream...')
29
- add_upstream
30
- logger.info('Removing unused gems...')
31
- Gem.gem_clean
32
- end
33
- end
34
-
35
- def self.hi
36
- logger.error("In a git repository. Try 1 level higher.") && return if is_git?
37
- latest_project_info = get_latest_repo_info
38
- logger.info("\nHang on, updating your local projects and remote forks...\n\n")
39
- git_projects.each do |project|
40
- Dir.chdir(project) do
41
- logger.info("\nGetting #{project} in shape...")
42
- yield if block_given?
43
- update_project
44
- end
45
- end
46
- greet(latest_project_info)
47
- end
48
-
49
- def self.open
50
- url = origin_push_url(quiet.run(remotes).out)
51
- logger.info("Opening #{url}")
52
- Launchy.open(url)
53
- end
54
-
55
- def self.add_upstream
56
- logger.error("Not a git repository.") and return unless is_git?
57
- logger.warn("Already has upstream.") and return if has_upstream?
58
- remote_list = pretty_with_output.run(remotes).out
59
-
60
- url = URI.parse(origin_push_url(remote_list))
61
- host = "api.#{url.host}"
62
- path = "/repos#{url.path}"
63
- request = Net::HTTP.new(host, url.port)
64
- request.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
- request.use_ssl = url.scheme == 'https'
66
- logger.info("Fetching repo info from #{host}#{path}\n\n")
67
- response = request.get(path)
68
-
69
- if response.kind_of?(Net::HTTPRedirection)
70
- logger.error('Repository moved / renamed. Update remote or implement redirect handling. :)')
71
- elsif response.kind_of?(Net::HTTPNotFound)
72
- logger.error('Repository not found. Maybe it is private.')
73
- elsif response.kind_of?(Net::HTTPSuccess)
74
- parsed_response = JSON.parse(response.body)
75
- logger.warn('Not a fork.') and return unless parsed_response['fork']
76
- parent_url = parsed_response.dig('parent', 'html_url')
77
- pretty.run(add_remote('upstream', parent_url)) unless parent_url.to_s.empty?
78
- pretty_with_output.run(remotes)
79
- else
80
- logger.error("Github API (#{url.scheme}://#{host}#{path}) could not be reached: #{response.body}")
81
- end
82
- end
83
-
84
- def self.origin_push_url(remotes)
85
- # Order is important: first try to match "url" in "#{url}.git" as non-dot_git matchers would include ".git" in the match
86
- origin_push_url_ssl_dot_git(remotes) or
87
- origin_push_url_ssl(remotes)or
88
- origin_push_url_https_dot_git(remotes) or
89
- origin_push_url_https(remotes)
90
- end
91
-
92
- def self.origin_push_url_https(remotes)
93
- remotes[%r{(?<=origin(\s))http(s?)://[a-zA-Z\-_./]*(?=(\s)\(push\))}]
94
- end
95
-
96
- def self.origin_push_url_https_dot_git(remotes)
97
- remotes[%r{(?<=origin(\s))http(s?)://[a-zA-Z\-_./]*(?=(\.)git(\s)\(push\))}]
98
- end
99
-
100
- def self.origin_push_url_ssl_dot_git(remotes)
101
- url = remotes[%r{(?<=origin(\s)git@)[a-zA-Z\-_./:]*(?=(\.)git(\s)\(push\))}]
102
- "https://#{url.gsub(':', '/')}" if url
103
- end
104
-
105
- def self.origin_push_url_ssl(remotes)
106
- url = remotes[%r{(?<=origin(\s)git@)[a-zA-Z\-_./:]*(?=(\s)\(push\))}]
107
- "https://#{url.gsub(':', '/')}" if url
108
- end
109
-
110
- def self.clear_branches
111
- pretty_with_output.run(branch)
112
- branch_removed = false
113
-
114
- (branches - ['master', working_branch]).each do |branch|
115
- if branch_pushed(branch)
116
- pretty.run(branch_force_delete(branch))
117
- branch_removed = true
118
- end
119
- end
120
-
121
- pretty_with_output.run(branch) if branch_removed
122
- end
123
-
124
- def update_projects
125
- Fs.in_place_or_subdirs(is_git?) do
126
- update_project
127
- end
128
- end
129
-
130
- def update_project
131
- logger.info("Updating #{File.expand_path('.')} ...")
132
- logger.error("Not a git repository.") and return unless is_git?
133
- status = quiet.run(git_status).out
134
- if uncommitted_changes?(status) and working_branch.eql?('master')
135
- logger.warn("Skipped: uncommitted changes on master.") and return
136
- end
137
-
138
- on_branch('master') do
139
- has_upstream? ? pull_upstream : pretty_with_output.run(pull)
140
- end
141
- end
142
-
143
- def pull_upstream
144
- upstream_remote = 'upstream'
145
- remote = 'origin'
146
- branch = 'master'
147
- pretty_with_output.run(fetch(upstream_remote)).out
148
- pretty_with_output.run(merge("#{upstream_remote}/#{branch}")).out
149
- pretty_with_output.run(push(remote, branch))
150
- end
151
-
152
- def has_upstream?
153
- quiet.run(remotes).out.include?('upstream')
154
- end
155
-
156
- def on_branch(branch)
157
- keep_changes do
158
- start_branch = working_branch
159
- switch_needed = !start_branch.eql?(branch)
160
- if switch_needed
161
- result = pretty.run!(checkout(branch))
162
- pretty.run(create(branch)) unless result.success?
163
- end
164
-
165
- begin
166
- yield if block_given?
167
- ensure
168
- pretty.run(checkout(start_branch)) if switch_needed
169
- end
170
- end
171
- end
172
-
173
- def branch_merged
174
- pretty_with_output.run(git_status)
175
- branch = working_branch
176
- logger.error("Nothing to do.") and return if branch.eql?('master')
177
-
178
- keep_changes do
179
- pretty_with_output.run(checkout('master'))
180
- pretty_with_output.run(pull)
181
- end
182
- pretty_with_output.run(branch_force_delete(branch))
183
-
184
- pretty_with_output.run(git_status)
185
- end
186
-
187
- def working_branch
188
- quiet.run(current_branch).out.strip
189
- end
190
-
191
- def branch_pushed(branch)
192
- quiet.run(changes_not_on_remote(branch)).out.empty?
193
- end
194
-
195
- def greet(latest_project_info = nil)
196
- logger.info("\nGood morning!\n\n")
197
- if is_git?
198
- logger.error('Inside repo, cannot show report about all repos.')
199
- else
200
- latest_project_info ||= get_latest_repo_info
201
- logger.info(latest_project_info)
202
- check_projects_older_than(1, :months)
203
- end
204
- obsolete_rubies = Rbenv.obsolete_versions
205
- if obsolete_rubies.any?
206
- logger.info("\nThe following Ruby versions are not used by any projects, maybe consider removing them?")
207
- obsolete_rubies.each do |ruby_verion|
208
- logger.info(" #{ruby_verion}")
209
- end
210
- end
211
- end
212
-
213
- def check_projects_older_than(quantity, unit)
214
- old_projects = Fs.older_than(git_projects, quantity, unit)
215
- deprecated_projects = old_projects.reject do |project|
216
- Dir.chdir(project) { branches.reject{ |branch| branch_pushed(branch) }.any? }
217
- end
218
-
219
- 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?
220
- deprecated_projects.each do |project|
221
- time_diff = TimeDifference.between(File.mtime(project), Time.now).humanize_higher_than(:weeks).downcase
222
- logger.info(" #{File.basename(project)} (#{time_diff})")
223
- end
224
- end
225
-
226
- def get_latest_repo_info
227
- latest = latest_repo
228
- time_diff = TimeDifference.between(File.mtime(latest), Time.now).humanize_higher_than(:days).downcase
229
- time_diff_text = time_diff.empty? ? 'recently' : "#{time_diff} ago"
230
- "It looks like you were working on #{File.basename(latest)} #{time_diff_text}.\n\n"
231
- end
232
-
233
- def latest_repo
234
- Fs.latest(git_projects)
235
- end
236
-
237
- def branches
238
- quiet.run(branch_list).out.clean_lines.map { |line| line[%r{(?<=refs/heads/)(.*)}] }
239
- end
240
-
241
- def uncommitted_changes?(status)
242
- !(status.include?('nothing to commit, working tree clean') or status.include?('nothing added to commit but untracked files present'))
243
- end
244
-
245
- def keep_changes
246
- status = quiet.run(git_status).out
247
- pop_stash = uncommitted_changes?(status)
248
- quiet.run(stash) if pop_stash
249
- begin
250
- yield if block_given?
251
- ensure
252
- quiet.run(stash_pop) if pop_stash
253
- end
254
- end
255
-
256
- def is_git?
257
- status = quiet.run!(git_status)
258
- Fs.git_folder_present && status.success? && !status.out.include?('Initial commit')
259
- end
260
-
261
- def git_projects
262
- Fs.ls_dirs.select do |dir|
263
- Dir.chdir(dir) do
264
- is_git?
265
- end
266
- end
267
- end
268
-
269
- include ReflectionUtils::CreateModuleFunctions
270
- end
271
- end
272
- end
1
+ require "uri"
2
+ require "net/https"
3
+ require "net/http"
4
+ require "json"
5
+ require "launchy"
6
+
7
+ require_relative "../commands/vcs"
8
+ require_relative "fs"
9
+ require_relative "rbenv"
10
+ require_relative "gem"
11
+ require_relative "../time_difference"
12
+
13
+ module Autowow
14
+ module Features
15
+ module Vcs
16
+ include EasyLogging
17
+ include Commands::Vcs
18
+ include Executor
19
+ include StringDecorator
20
+
21
+ using RefinedTimeDifference
22
+
23
+ def self.hi!
24
+ logger.error("In a git repository. Try 1 level higher.") && return if is_git?
25
+ hi do
26
+ logger.info("Removing unused branches...")
27
+ clear_branches
28
+ logger.info("Adding upstream...")
29
+ add_upstream
30
+ logger.info("Removing unused gems...")
31
+ Gem.gem_clean
32
+ end
33
+ end
34
+
35
+ def self.hi
36
+ logger.error("In a git repository. Try 1 level higher.") && return if is_git?
37
+ latest_project_info = get_latest_repo_info
38
+ logger.info("\nHang on, updating your local projects and remote forks...\n\n")
39
+ git_projects.each do |project|
40
+ Dir.chdir(project) do
41
+ logger.info("\nGetting #{project} in shape...")
42
+ yield if block_given?
43
+ update_project
44
+ end
45
+ end
46
+ greet(latest_project_info)
47
+ end
48
+
49
+ def self.open
50
+ url = origin_push_url(quiet.run(remotes).out)
51
+ logger.info("Opening #{url}")
52
+ Launchy.open(url)
53
+ end
54
+
55
+ def self.add_upstream
56
+ logger.error("Not a git repository.") and return unless is_git?
57
+ logger.warn("Already has upstream.") and return if has_upstream?
58
+ remote_list = pretty_with_output.run(remotes).out
59
+
60
+ url = URI.parse(origin_push_url(remote_list))
61
+ host = "api.#{url.host}"
62
+ path = "/repos#{url.path}"
63
+ request = Net::HTTP.new(host, url.port)
64
+ request.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
+ request.use_ssl = url.scheme == "https"
66
+ logger.info("Fetching repo info from #{host}#{path}\n\n")
67
+ response = request.get(path)
68
+
69
+ if response.kind_of?(Net::HTTPRedirection)
70
+ logger.error("Repository moved / renamed. Update remote or implement redirect handling. :)")
71
+ elsif response.kind_of?(Net::HTTPNotFound)
72
+ logger.error("Repository not found. Maybe it is private.")
73
+ elsif response.kind_of?(Net::HTTPSuccess)
74
+ parsed_response = JSON.parse(response.body)
75
+ logger.warn("Not a fork.") and return unless parsed_response["fork"]
76
+ parent_url = parsed_response.dig("parent", "html_url")
77
+ pretty.run(add_remote("upstream", parent_url)) unless parent_url.to_s.empty?
78
+ pretty_with_output.run(remotes)
79
+ else
80
+ logger.error("Github API (#{url.scheme}://#{host}#{path}) could not be reached: #{response.body}")
81
+ end
82
+ end
83
+
84
+ def self.origin_push_url(remotes)
85
+ # Order is important: first try to match "url" in "#{url}.git" as non-dot_git matchers would include ".git" in the match
86
+ origin_push_url_ssl_dot_git(remotes) or
87
+ origin_push_url_ssl(remotes) or
88
+ origin_push_url_https_dot_git(remotes) or
89
+ origin_push_url_https(remotes)
90
+ end
91
+
92
+ def self.origin_push_url_https(remotes)
93
+ remotes[%r{(?<=origin(\s))http(s?)://[a-zA-Z\-_./]*(?=(\s)\(push\))}]
94
+ end
95
+
96
+ def self.origin_push_url_https_dot_git(remotes)
97
+ remotes[%r{(?<=origin(\s))http(s?)://[a-zA-Z\-_./]*(?=(\.)git(\s)\(push\))}]
98
+ end
99
+
100
+ def self.origin_push_url_ssl_dot_git(remotes)
101
+ url = remotes[%r{(?<=origin(\s)git@)[a-zA-Z\-_./:]*(?=(\.)git(\s)\(push\))}]
102
+ "https://#{url.gsub(':', '/')}" if url
103
+ end
104
+
105
+ def self.origin_push_url_ssl(remotes)
106
+ url = remotes[%r{(?<=origin(\s)git@)[a-zA-Z\-_./:]*(?=(\s)\(push\))}]
107
+ "https://#{url.gsub(':', '/')}" if url
108
+ end
109
+
110
+ def self.clear_branches
111
+ pretty_with_output.run(branch)
112
+ branch_removed = false
113
+
114
+ (branches - ["master", working_branch]).each do |branch|
115
+ if branch_pushed(branch)
116
+ pretty.run(branch_force_delete(branch))
117
+ branch_removed = true
118
+ end
119
+ end
120
+
121
+ pretty_with_output.run(branch) if branch_removed
122
+ end
123
+
124
+ def update_projects
125
+ Fs.in_place_or_subdirs(is_git?) do
126
+ update_project
127
+ end
128
+ end
129
+
130
+ def update_project
131
+ logger.info("Updating #{File.expand_path('.')} ...")
132
+ logger.error("Not a git repository.") and return unless is_git?
133
+ status = quiet.run(git_status).out
134
+ if uncommitted_changes?(status) && working_branch.eql?("master")
135
+ logger.warn("Skipped: uncommitted changes on master.") and return
136
+ end
137
+
138
+ on_branch("master") do
139
+ has_upstream? ? pull_upstream : pretty_with_output.run(pull)
140
+ end
141
+ end
142
+
143
+ def pull_upstream
144
+ upstream_remote = "upstream"
145
+ remote = "origin"
146
+ branch = "master"
147
+ pretty_with_output.run(fetch(upstream_remote)).out
148
+ pretty_with_output.run(merge("#{upstream_remote}/#{branch}")).out
149
+ pretty_with_output.run(push(remote, branch))
150
+ end
151
+
152
+ def has_upstream?
153
+ quiet.run(remotes).out.include?("upstream")
154
+ end
155
+
156
+ def on_branch(branch)
157
+ keep_changes do
158
+ start_branch = working_branch
159
+ switch_needed = !start_branch.eql?(branch)
160
+ if switch_needed
161
+ result = pretty.run!(checkout(branch))
162
+ pretty.run(create(branch)) unless result.success?
163
+ end
164
+
165
+ begin
166
+ yield if block_given?
167
+ ensure
168
+ pretty.run(checkout(start_branch)) if switch_needed
169
+ end
170
+ end
171
+ end
172
+
173
+ def branch_merged
174
+ pretty_with_output.run(git_status)
175
+ branch = working_branch
176
+ logger.error("Nothing to do.") and return if branch.eql?("master")
177
+
178
+ keep_changes do
179
+ pretty_with_output.run(checkout("master"))
180
+ pretty_with_output.run(pull)
181
+ end
182
+ pretty_with_output.run(branch_force_delete(branch))
183
+
184
+ pretty_with_output.run(git_status)
185
+ end
186
+
187
+ def working_branch
188
+ quiet.run(current_branch).out.strip
189
+ end
190
+
191
+ def branch_pushed(branch)
192
+ quiet.run(changes_not_on_remote(branch)).out.empty?
193
+ end
194
+
195
+ def greet(latest_project_info = nil)
196
+ logger.info("\nGood morning!\n\n")
197
+ if is_git?
198
+ logger.error("Inside repo, cannot show report about all repos.")
199
+ else
200
+ latest_project_info ||= get_latest_repo_info
201
+ logger.info(latest_project_info)
202
+ check_projects_older_than(1, :months)
203
+ end
204
+ obsolete_rubies = Rbenv.obsolete_versions
205
+ if obsolete_rubies.any?
206
+ logger.info("\nThe following Ruby versions are not used by any projects, maybe consider removing them?")
207
+ obsolete_rubies.each do |ruby_verion|
208
+ logger.info(" #{ruby_verion}")
209
+ end
210
+ end
211
+ end
212
+
213
+ def check_projects_older_than(quantity, unit)
214
+ old_projects = Fs.older_than(git_projects, quantity, unit)
215
+ deprecated_projects = old_projects.reject do |project|
216
+ Dir.chdir(project) { branches.reject { |branch| branch_pushed(branch) }.any? }
217
+ end
218
+
219
+ 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?
220
+ deprecated_projects.each do |project|
221
+ time_diff = TimeDifference.between(File.mtime(project), Time.now).humanize_higher_than(:weeks).downcase
222
+ logger.info(" #{File.basename(project)} (#{time_diff})")
223
+ end
224
+ end
225
+
226
+ def get_latest_repo_info
227
+ latest = latest_repo
228
+ time_diff = TimeDifference.between(File.mtime(latest), Time.now).humanize_higher_than(:days).downcase
229
+ time_diff_text = time_diff.empty? ? "recently" : "#{time_diff} ago"
230
+ "It looks like you were working on #{File.basename(latest)} #{time_diff_text}.\n\n"
231
+ end
232
+
233
+ def latest_repo
234
+ Fs.latest(git_projects)
235
+ end
236
+
237
+ def branches
238
+ quiet.run(branch_list).out.clean_lines.map { |line| line[%r{(?<=refs/heads/)(.*)}] }
239
+ end
240
+
241
+ def uncommitted_changes?(status)
242
+ !(status.include?("nothing to commit, working tree clean") or status.include?("nothing added to commit but untracked files present"))
243
+ end
244
+
245
+ def keep_changes
246
+ status = quiet.run(git_status).out
247
+ pop_stash = uncommitted_changes?(status)
248
+ quiet.run(stash) if pop_stash
249
+ begin
250
+ yield if block_given?
251
+ ensure
252
+ quiet.run(stash_pop) if pop_stash
253
+ end
254
+ end
255
+
256
+ def is_git?
257
+ status = quiet.run!(git_status)
258
+ Fs.git_folder_present && status.success? && !status.out.include?("Initial commit")
259
+ end
260
+
261
+ def git_projects
262
+ Fs.ls_dirs.select do |dir|
263
+ Dir.chdir(dir) do
264
+ is_git?
265
+ end
266
+ end
267
+ end
268
+
269
+ include ReflectionUtils::CreateModuleFunctions
270
+ end
271
+ end
272
+ end