repofetch 0.4.4 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +9 -7
- data/Gemfile.lock +15 -12
- data/README.md +1 -1
- data/RELEASE_NOTES +4 -4
- data/lib/repofetch/VERSION +1 -0
- data/lib/repofetch/bitbucketcloud/stats.rb +64 -0
- data/lib/repofetch/bitbucketcloud.rb +14 -63
- data/lib/repofetch/cli.rb +24 -11
- data/lib/repofetch/github.rb +8 -9
- data/lib/repofetch/gitlab.rb +11 -11
- data/lib/repofetch/plugin.rb +180 -0
- data/lib/repofetch/stat.rb +60 -0
- data/lib/repofetch/timespan_stat.rb +16 -0
- data/lib/repofetch/util.rb +34 -3
- data/lib/repofetch/version.rb +5 -0
- data/lib/repofetch.rb +48 -199
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bfe2278b9a089681497c499e15573b0ccc6ad56aec6562a520f3a1e004bd8a2
|
4
|
+
data.tar.gz: abcf48633cf56efb233e9a9543a8b0e1a647b9c8209f9cd332b75fc13745972d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f9827c43998f71189b3e80a7e824a12b79ec941e83a756631aac8eafe51791674cb354452efc5265a022202c7d6134d34523bfb589d8236bf67fb0262949066
|
7
|
+
data.tar.gz: 70faf36fa9c88ab85ea7a0ae31b2b68f6b85159d02a48f0bad2e1a3d4b8bfa2071cefe449c64531b631b97b083229837068173b6af10f3db0a1a7ab799fb3718
|
data/CONTRIBUTING.md
CHANGED
@@ -62,14 +62,15 @@ The following requirements assume you are *not* manually implementing a plugin's
|
|
62
62
|
`to_s` method, and you are inheriting from `Repofetch::Plugin`.
|
63
63
|
|
64
64
|
- `ascii` should return a string for the ASCII art
|
65
|
-
- `header` should return the header text that will be above the `---` separator on the right side.
|
65
|
+
- `header` should return the header text or an array of header text that will be above the `---` separator on the right side.
|
66
66
|
- `stats` should return an array of values that implement `to_s`. These will be
|
67
67
|
the stats displayed to the right of the ASCII art. You can use`Repofetch::Stat` and
|
68
68
|
`Repofetch::TimespanStat` to create a pretty stat.
|
69
69
|
|
70
|
-
|
70
|
+
### Optional Plugin Instance Methods
|
71
71
|
|
72
72
|
- `theme` can return an instance of `Repofetch::Theme` to use a different color scheme.
|
73
|
+
- `primary_color` will set the color for the header and stat labels.
|
73
74
|
|
74
75
|
### Authoring ASCII Art
|
75
76
|
|
@@ -113,15 +114,16 @@ class MyCoolPlugin < Repofetch::Plugin
|
|
113
114
|
end
|
114
115
|
|
115
116
|
def header
|
116
|
-
# NOTE:
|
117
|
-
|
117
|
+
# NOTE: The inherited header_joiner method will make the final header "My Plugin @ Me"
|
118
|
+
# You can override this method to use a different joiner, or override formatted_header
|
119
|
+
# for more control.
|
120
|
+
['My Plugin', 'Me']
|
118
121
|
end
|
119
122
|
|
120
123
|
def stats
|
121
|
-
# if theme is not passed, the stat will not be styled
|
122
124
|
[
|
123
|
-
Repofetch::Stat.new('git repo detected', @detected_from_git, emoji: '📂'
|
124
|
-
Repofetch::Stat.new('args passed', @arg_count
|
125
|
+
Repofetch::Stat.new('git repo detected', @detected_from_git, emoji: '📂'),
|
126
|
+
Repofetch::Stat.new('args passed', @arg_count)
|
125
127
|
]
|
126
128
|
end
|
127
129
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
repofetch (0.
|
4
|
+
repofetch (0.5.1)
|
5
5
|
actionview (~> 7.0, >= 7.0.4)
|
6
6
|
dotenv (~> 2.8)
|
7
7
|
faraday-retry (~> 2.0)
|
@@ -12,13 +12,13 @@ PATH
|
|
12
12
|
GEM
|
13
13
|
remote: https://rubygems.org/
|
14
14
|
specs:
|
15
|
-
actionview (7.0.4)
|
16
|
-
activesupport (= 7.0.4)
|
15
|
+
actionview (7.0.4.1)
|
16
|
+
activesupport (= 7.0.4.1)
|
17
17
|
builder (~> 3.1)
|
18
18
|
erubi (~> 1.4)
|
19
19
|
rails-dom-testing (~> 2.0)
|
20
20
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
21
|
-
activesupport (7.0.4)
|
21
|
+
activesupport (7.0.4.1)
|
22
22
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
23
23
|
i18n (>= 1.6, < 2)
|
24
24
|
minitest (>= 5.1)
|
@@ -35,7 +35,7 @@ GEM
|
|
35
35
|
docile (1.4.0)
|
36
36
|
dotenv (2.8.1)
|
37
37
|
erubi (1.12.0)
|
38
|
-
faraday (2.7.
|
38
|
+
faraday (2.7.4)
|
39
39
|
faraday-net_http (>= 2.0, < 3.1)
|
40
40
|
ruby2_keywords (>= 0.0.4)
|
41
41
|
faraday-net_http (3.0.2)
|
@@ -58,7 +58,7 @@ GEM
|
|
58
58
|
faraday (>= 1, < 3)
|
59
59
|
sawyer (~> 0.9)
|
60
60
|
os (1.1.4)
|
61
|
-
overcommit (0.
|
61
|
+
overcommit (0.60.0)
|
62
62
|
childprocess (>= 0.6.3, < 5)
|
63
63
|
iniparse (~> 1.4)
|
64
64
|
rexml (~> 3.2)
|
@@ -70,12 +70,12 @@ GEM
|
|
70
70
|
rails-dom-testing (2.0.3)
|
71
71
|
activesupport (>= 4.2.0)
|
72
72
|
nokogiri (>= 1.6)
|
73
|
-
rails-html-sanitizer (1.
|
73
|
+
rails-html-sanitizer (1.5.0)
|
74
74
|
loofah (~> 2.19, >= 2.19.1)
|
75
75
|
rainbow (3.1.1)
|
76
76
|
rake (13.0.6)
|
77
77
|
rchardet (1.8.0)
|
78
|
-
regexp_parser (2.6.
|
78
|
+
regexp_parser (2.6.2)
|
79
79
|
rexml (3.2.5)
|
80
80
|
rspec (3.12.0)
|
81
81
|
rspec-core (~> 3.12.0)
|
@@ -86,14 +86,14 @@ GEM
|
|
86
86
|
rspec-expectations (3.12.2)
|
87
87
|
diff-lcs (>= 1.2.0, < 2.0)
|
88
88
|
rspec-support (~> 3.12.0)
|
89
|
-
rspec-mocks (3.12.
|
89
|
+
rspec-mocks (3.12.3)
|
90
90
|
diff-lcs (>= 1.2.0, < 2.0)
|
91
91
|
rspec-support (~> 3.12.0)
|
92
92
|
rspec-snapshot (2.0.1)
|
93
93
|
awesome_print (> 1.0.0)
|
94
94
|
rspec (> 3.0.0)
|
95
95
|
rspec-support (3.12.0)
|
96
|
-
rubocop (1.
|
96
|
+
rubocop (1.44.0)
|
97
97
|
json (~> 2.3)
|
98
98
|
parallel (~> 1.10)
|
99
99
|
parser (>= 3.2.0.0)
|
@@ -105,10 +105,13 @@ GEM
|
|
105
105
|
unicode-display_width (>= 2.4.0, < 3.0)
|
106
106
|
rubocop-ast (1.24.1)
|
107
107
|
parser (>= 3.1.1.0)
|
108
|
+
rubocop-capybara (2.17.0)
|
109
|
+
rubocop (~> 1.41)
|
108
110
|
rubocop-rake (0.6.0)
|
109
111
|
rubocop (~> 1.0)
|
110
|
-
rubocop-rspec (2.
|
112
|
+
rubocop-rspec (2.18.1)
|
111
113
|
rubocop (~> 1.33)
|
114
|
+
rubocop-capybara (~> 2.17)
|
112
115
|
ruby-progressbar (1.11.0)
|
113
116
|
ruby2_keywords (0.0.5)
|
114
117
|
sawyer (0.9.2)
|
@@ -149,4 +152,4 @@ DEPENDENCIES
|
|
149
152
|
yard (~> 0.9.28)
|
150
153
|
|
151
154
|
BUNDLED WITH
|
152
|
-
2.4.
|
155
|
+
2.4.5
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[![GitHub contributors (via allcontributors.org)](https://img.shields.io/github/all-contributors/spenserblack/repofetch)](./CREDITS.md)
|
5
5
|
![CI](https://github.com/spenserblack/repofetch/workflows/CI/badge.svg)
|
6
6
|
[![CodeQL](https://github.com/spenserblack/repofetch/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/spenserblack/repofetch/actions/workflows/github-code-scanning/codeql)
|
7
|
-
[![codecov](https://codecov.io/gh/spenserblack/repofetch/branch/
|
7
|
+
[![codecov](https://codecov.io/gh/spenserblack/repofetch/branch/main/graph/badge.svg?token=3572AEWQAY)](https://codecov.io/gh/spenserblack/repofetch)
|
8
8
|
|
9
9
|
Fetch details about your remote repository.
|
10
10
|
|
data/RELEASE_NOTES
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
|
1
|
+
Next
|
2
2
|
|
3
|
-
##
|
3
|
+
## Added
|
4
4
|
|
5
|
-
-
|
6
|
-
|
5
|
+
- `-v`/`--version` to print the version from the CLI
|
6
|
+
- `Repofetch::VERSION` to get the version as a library
|
@@ -0,0 +1 @@
|
|
1
|
+
0.5.1
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'repofetch'
|
4
|
+
|
5
|
+
class Repofetch
|
6
|
+
class BitbucketCloud < Repofetch::Plugin
|
7
|
+
# Methods to get Bitbucket Cloud stats.
|
8
|
+
module Stats
|
9
|
+
protected
|
10
|
+
|
11
|
+
def repo_data
|
12
|
+
@repo_data ||= agent.call(:get, "repositories/#{@repo_identifier}").data
|
13
|
+
end
|
14
|
+
|
15
|
+
def clone_urls
|
16
|
+
@clone_urls ||= repo_data['links']['clone'].to_h { |clone| [clone['name'].to_sym, clone['href']] }
|
17
|
+
end
|
18
|
+
|
19
|
+
def http_clone_url
|
20
|
+
Repofetch::Stat.new('HTTP(S)', clone_urls[:https], emoji: '🌐')
|
21
|
+
end
|
22
|
+
|
23
|
+
def ssh_clone_url
|
24
|
+
Repofetch::Stat.new('SSH', clone_urls[:ssh], emoji: '🔑')
|
25
|
+
end
|
26
|
+
|
27
|
+
def watchers
|
28
|
+
@watcher_data ||= agent.call(:get, "repositories/#{@repo_identifier}/watchers").data
|
29
|
+
Repofetch::Stat.new('subscribers', @watcher_data['size'], emoji: '👀')
|
30
|
+
end
|
31
|
+
|
32
|
+
def forks
|
33
|
+
@fork_data ||= agent.call(:get, "repositories/#{@repo_identifier}/forks").data
|
34
|
+
Repofetch::Stat.new('forks', @fork_data['size'], emoji: '🔱')
|
35
|
+
end
|
36
|
+
|
37
|
+
def created
|
38
|
+
Repofetch::TimespanStat.new('created', repo_data['created_on'], emoji: '🐣')
|
39
|
+
end
|
40
|
+
|
41
|
+
def updated
|
42
|
+
Repofetch::TimespanStat.new('updated', repo_data['updated_on'], emoji: '📤')
|
43
|
+
end
|
44
|
+
|
45
|
+
def size
|
46
|
+
# NOTE: Size is in bytes
|
47
|
+
# TODO: Move this somewhere else instead of using a copy-paste
|
48
|
+
byte_size = number_to_human_size(repo_data['size'] || 0, precision: 2, significant: false,
|
49
|
+
strip_insignificant_zeros: false)
|
50
|
+
Repofetch::Stat.new('size', byte_size, emoji: '💽')
|
51
|
+
end
|
52
|
+
|
53
|
+
def issues
|
54
|
+
@issue_data ||= agent.call(:get, "repositories/#{@repo_identifier}/issues").data
|
55
|
+
Repofetch::Stat.new('issues', @issue_data['size'], emoji: '❗')
|
56
|
+
end
|
57
|
+
|
58
|
+
def pull_requests
|
59
|
+
@pull_request_data ||= agent.call(:get, "repositories/#{@repo_identifier}/pullrequests").data
|
60
|
+
Repofetch::Stat.new('pull requests', @pull_request_data['size'], emoji: '🔀')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -2,14 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'action_view'
|
4
4
|
require 'optparse'
|
5
|
-
require 'repofetch'
|
5
|
+
require 'repofetch/bitbucketcloud/stats'
|
6
6
|
require 'repofetch/exceptions'
|
7
|
+
require 'repofetch/plugin'
|
8
|
+
require 'repofetch/util'
|
7
9
|
require 'sawyer'
|
8
10
|
|
9
11
|
class Repofetch
|
10
12
|
# Adds support for Bitbucket repositories.
|
11
13
|
class BitbucketCloud < Repofetch::Plugin
|
12
14
|
include ActionView::Helpers::NumberHelper
|
15
|
+
include Repofetch::BitbucketCloud::Stats
|
16
|
+
include Repofetch::Util
|
17
|
+
extend Repofetch::Util
|
13
18
|
|
14
19
|
HTTP_REMOTE_REGEX = %r{https?://bitbucket\.org/(?<owner>[\w._-]+)/(?<repo>[\w._-]+)}.freeze
|
15
20
|
SSH_REMOTE_REGEX = %r{git@bitbucket\.org:(?<owner>[\w._-]+)/(?<repo>[\w._-]+)}.freeze
|
@@ -24,13 +29,15 @@ class Repofetch
|
|
24
29
|
end
|
25
30
|
|
26
31
|
def header
|
27
|
-
"#{repo_data['owner']['display_name']}/#{repo_data['name']}
|
32
|
+
["#{repo_data['owner']['display_name']}/#{repo_data['name']}", 'Bitbucket']
|
28
33
|
end
|
29
34
|
|
30
|
-
def
|
31
|
-
|
35
|
+
def primary_color
|
36
|
+
:blue
|
37
|
+
end
|
32
38
|
|
33
|
-
|
39
|
+
def stats
|
40
|
+
[http_clone_url, ssh_clone_url, watchers, forks, created, updated, size, issues, pull_requests]
|
34
41
|
end
|
35
42
|
|
36
43
|
def ascii
|
@@ -49,8 +56,7 @@ class Repofetch
|
|
49
56
|
|
50
57
|
# Detects that the repository is a Bitbucket repository.
|
51
58
|
def self.matches_repo?(git)
|
52
|
-
|
53
|
-
matches_remote?(default_remote&.url)
|
59
|
+
matches_remote?(default_remote_url(git))
|
54
60
|
end
|
55
61
|
|
56
62
|
# Detects that the remote URL is for a Bitbucket Cloud repository.
|
@@ -60,8 +66,7 @@ class Repofetch
|
|
60
66
|
|
61
67
|
# Gets the owner and repository from a GitHub local repository.
|
62
68
|
def self.repo_identifiers(git)
|
63
|
-
|
64
|
-
remote_identifiers(default_remote&.url)
|
69
|
+
remote_identifiers(default_remote_url(git))
|
65
70
|
end
|
66
71
|
|
67
72
|
# Gets the owner and repository from a GitHub remote URL.
|
@@ -98,60 +103,6 @@ class Repofetch
|
|
98
103
|
|
99
104
|
new(args[0])
|
100
105
|
end
|
101
|
-
|
102
|
-
protected
|
103
|
-
|
104
|
-
def repo_data
|
105
|
-
@repo_data ||= agent.call(:get, "repositories/#{@repo_identifier}").data
|
106
|
-
end
|
107
|
-
|
108
|
-
def clone_urls
|
109
|
-
@clone_urls ||= repo_data['links']['clone'].to_h { |clone| [clone['name'].to_sym, clone['href']] }
|
110
|
-
end
|
111
|
-
|
112
|
-
def http_clone_url
|
113
|
-
Repofetch::Stat.new('HTTP(S)', clone_urls[:https], emoji: '🌐')
|
114
|
-
end
|
115
|
-
|
116
|
-
def ssh_clone_url
|
117
|
-
Repofetch::Stat.new('SSH', clone_urls[:ssh], emoji: '🔑')
|
118
|
-
end
|
119
|
-
|
120
|
-
def watchers
|
121
|
-
@watcher_data ||= agent.call(:get, "repositories/#{@repo_identifier}/watchers").data
|
122
|
-
Repofetch::Stat.new('subscribers', @watcher_data['size'], emoji: '👀')
|
123
|
-
end
|
124
|
-
|
125
|
-
def forks
|
126
|
-
@fork_data ||= agent.call(:get, "repositories/#{@repo_identifier}/forks").data
|
127
|
-
Repofetch::Stat.new('forks', @fork_data['size'], emoji: '🔱')
|
128
|
-
end
|
129
|
-
|
130
|
-
def created
|
131
|
-
Repofetch::TimespanStat.new('created', repo_data['created_on'], emoji: '🐣')
|
132
|
-
end
|
133
|
-
|
134
|
-
def updated
|
135
|
-
Repofetch::TimespanStat.new('updated', repo_data['updated_on'], emoji: '📤')
|
136
|
-
end
|
137
|
-
|
138
|
-
def size
|
139
|
-
# NOTE: Size is in bytes
|
140
|
-
# TODO: Move this somewhere else instead of using a copy-paste
|
141
|
-
byte_size = number_to_human_size(repo_data['size'] || 0, precision: 2, significant: false,
|
142
|
-
strip_insignificant_zeros: false)
|
143
|
-
Repofetch::Stat.new('size', byte_size, emoji: '💽')
|
144
|
-
end
|
145
|
-
|
146
|
-
def issues
|
147
|
-
@issue_data ||= agent.call(:get, "repositories/#{@repo_identifier}/issues").data
|
148
|
-
Repofetch::Stat.new('issues', @issue_data['size'], emoji: '❗')
|
149
|
-
end
|
150
|
-
|
151
|
-
def pull_requests
|
152
|
-
@pull_request_data ||= agent.call(:get, "repositories/#{@repo_identifier}/pullrequests").data
|
153
|
-
Repofetch::Stat.new('pull requests', @pull_request_data['size'], emoji: '🔀')
|
154
|
-
end
|
155
106
|
end
|
156
107
|
end
|
157
108
|
|
data/lib/repofetch/cli.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'git'
|
4
3
|
require 'optparse'
|
5
4
|
require 'repofetch'
|
6
5
|
require 'repofetch/config'
|
7
6
|
require 'repofetch/exceptions'
|
7
|
+
require 'repofetch/version'
|
8
8
|
|
9
9
|
class Repofetch
|
10
10
|
# Command line interface for repofetch.
|
@@ -28,15 +28,9 @@ class Repofetch
|
|
28
28
|
load_plugins
|
29
29
|
define_options.parse!(@args)
|
30
30
|
|
31
|
-
|
32
|
-
plugin = new_plugin
|
33
|
-
rescue Repofetch::PluginUsageError => e
|
34
|
-
warn e
|
35
|
-
return 1
|
36
|
-
end
|
31
|
+
return @exit unless @exit.nil?
|
37
32
|
|
38
|
-
|
39
|
-
0
|
33
|
+
start_plugin
|
40
34
|
end
|
41
35
|
|
42
36
|
def define_options
|
@@ -46,6 +40,7 @@ class Repofetch
|
|
46
40
|
add_repository_options(opts)
|
47
41
|
add_plugin_options(opts)
|
48
42
|
add_options_notes(opts)
|
43
|
+
add_version_option(opts)
|
49
44
|
end
|
50
45
|
end
|
51
46
|
|
@@ -56,12 +51,18 @@ class Repofetch
|
|
56
51
|
def new_plugin
|
57
52
|
return @plugin.from_args(@args) unless @plugin.nil?
|
58
53
|
|
59
|
-
|
60
|
-
Repofetch.get_plugin(git, @args)
|
54
|
+
Repofetch.get_plugin(@repository_path, @args)
|
61
55
|
end
|
62
56
|
|
63
57
|
private
|
64
58
|
|
59
|
+
def add_version_option(opts)
|
60
|
+
opts.on('-v', '--version', 'Print the version number and exit.') do
|
61
|
+
puts "repofetch #{Repofetch::VERSION}"
|
62
|
+
@exit = 0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
65
66
|
def add_repository_options(opts)
|
66
67
|
opts.on('-r', '--repository', '-p', '--path PATH',
|
67
68
|
'Use the provided path. Defaults to the current directory.') do |path|
|
@@ -93,5 +94,17 @@ class Repofetch
|
|
93
94
|
def available_plugins
|
94
95
|
Repofetch.plugins.to_h { |plugin| [plugin.name, plugin] }
|
95
96
|
end
|
97
|
+
|
98
|
+
def start_plugin
|
99
|
+
begin
|
100
|
+
plugin = new_plugin
|
101
|
+
rescue Repofetch::PluginUsageError => e
|
102
|
+
warn e
|
103
|
+
return 1
|
104
|
+
end
|
105
|
+
|
106
|
+
puts plugin
|
107
|
+
0
|
108
|
+
end
|
96
109
|
end
|
97
110
|
end
|
data/lib/repofetch/github.rb
CHANGED
@@ -3,13 +3,16 @@
|
|
3
3
|
require 'action_view'
|
4
4
|
require 'octokit'
|
5
5
|
require 'optparse'
|
6
|
-
require 'repofetch'
|
7
6
|
require 'repofetch/exceptions'
|
7
|
+
require 'repofetch/plugin'
|
8
|
+
require 'repofetch/util'
|
8
9
|
|
9
10
|
class Repofetch
|
10
11
|
# Adds support for GitHub repositories.
|
11
12
|
class Github < Repofetch::Plugin
|
12
13
|
include ActionView::Helpers::NumberHelper
|
14
|
+
include Repofetch::Util
|
15
|
+
extend Repofetch::Util
|
13
16
|
|
14
17
|
HTTP_REMOTE_REGEX = %r{https?://github\.com/(?<owner>[\w.-]+)/(?<repository>[\w.-]+)}.freeze
|
15
18
|
SSH_REMOTE_REGEX = %r{git@github\.com:(?<owner>[\w.-]+)/(?<repository>[\w.-]+)}.freeze
|
@@ -31,15 +34,12 @@ class Repofetch
|
|
31
34
|
end
|
32
35
|
|
33
36
|
def stats
|
34
|
-
|
35
|
-
pull_requests]
|
36
|
-
stats.each { |stat| stat.style_label!(:bold) }
|
37
|
+
[http_clone_url, ssh_clone_url, stargazers, subscribers, forks, created, updated, size, issues, pull_requests]
|
37
38
|
end
|
38
39
|
|
39
40
|
# Detects that the repository is a GitHub repository.
|
40
41
|
def self.matches_repo?(git)
|
41
|
-
|
42
|
-
matches_remote?(default_remote&.url)
|
42
|
+
matches_remote?(default_remote_url(git))
|
43
43
|
end
|
44
44
|
|
45
45
|
# Detects that the remote URL is for a GitHub repository.
|
@@ -49,8 +49,7 @@ class Repofetch
|
|
49
49
|
|
50
50
|
# Gets the owner and repository from a GitHub local repository.
|
51
51
|
def self.repo_identifiers(git)
|
52
|
-
|
53
|
-
remote_identifiers(default_remote&.url)
|
52
|
+
remote_identifiers(default_remote_url(git))
|
54
53
|
end
|
55
54
|
|
56
55
|
# Gets the owner and repository from a GitHub remote URL.
|
@@ -93,7 +92,7 @@ class Repofetch
|
|
93
92
|
end
|
94
93
|
|
95
94
|
def header
|
96
|
-
"#{
|
95
|
+
["#{owner}/#{repository}", 'GitHub']
|
97
96
|
end
|
98
97
|
|
99
98
|
def ascii
|
data/lib/repofetch/gitlab.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'cgi'
|
4
|
-
require 'repofetch'
|
5
4
|
require 'repofetch/exceptions'
|
5
|
+
require 'repofetch/plugin'
|
6
|
+
require 'repofetch/util'
|
6
7
|
require 'sawyer'
|
7
8
|
|
8
9
|
class Repofetch
|
9
10
|
# Adds support for GitLab repositories.
|
10
11
|
class Gitlab < Repofetch::Plugin
|
12
|
+
include Repofetch::Util
|
13
|
+
extend Repofetch::Util
|
14
|
+
|
11
15
|
HTTP_REMOTE_REGEX = %r{https?://gitlab\.com/(?<path>[\w.-][\w.\-/]+)}.freeze
|
12
16
|
SSH_REMOTE_REGEX = %r{git@gitlab\.com:(?<path>[\w.-][\w.\-/]+)}.freeze
|
13
17
|
ASCII = File.read(File.expand_path('gitlab/ASCII', __dir__))
|
@@ -22,11 +26,11 @@ class Repofetch
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def header
|
25
|
-
|
29
|
+
[repo_data['name_with_namespace'], 'GitLab']
|
26
30
|
end
|
27
31
|
|
28
|
-
def
|
29
|
-
|
32
|
+
def primary_color
|
33
|
+
:red
|
30
34
|
end
|
31
35
|
|
32
36
|
def stats
|
@@ -35,7 +39,7 @@ class Repofetch
|
|
35
39
|
# NOTE: Stats that require authentication
|
36
40
|
stats << open_issues unless token.nil?
|
37
41
|
|
38
|
-
stats
|
42
|
+
stats
|
39
43
|
end
|
40
44
|
|
41
45
|
def ascii
|
@@ -87,9 +91,7 @@ class Repofetch
|
|
87
91
|
|
88
92
|
# Gets the path (+owner/subproject/repo+) of the repository.
|
89
93
|
def self.repo_identifier(git)
|
90
|
-
|
91
|
-
url = default_remote&.url
|
92
|
-
remote_identifier(url)
|
94
|
+
remote_identifier(default_remote_url(git))
|
93
95
|
end
|
94
96
|
|
95
97
|
# Gets the path (+owner/subproject/repo+) of the repository.
|
@@ -105,9 +107,7 @@ class Repofetch
|
|
105
107
|
|
106
108
|
# Detects that the repository is a GitHub repository.
|
107
109
|
def self.matches_repo?(git)
|
108
|
-
|
109
|
-
url = default_remote&.url
|
110
|
-
matches_remote?(url)
|
110
|
+
matches_remote?(default_remote_url(git))
|
111
111
|
end
|
112
112
|
|
113
113
|
# Detects that the remote URL is for a GitHub repository.
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'repofetch'
|
4
|
+
require 'repofetch/util'
|
5
|
+
require 'repofetch/stat'
|
6
|
+
|
7
|
+
class Repofetch
|
8
|
+
# @abstract Subclass to create a plugin.
|
9
|
+
class Plugin
|
10
|
+
include Repofetch::Util
|
11
|
+
|
12
|
+
# Plugin intializer arguments should come from the +from_git+ or +from_args+
|
13
|
+
# class methods.
|
14
|
+
def initialize(*) end
|
15
|
+
|
16
|
+
# Registers this plugin class for repofetch.
|
17
|
+
def self.register
|
18
|
+
Repofetch.register_plugin(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Tries to replace another plugin. An example use case might be if this plugin
|
22
|
+
# extends another registered plugin.
|
23
|
+
#
|
24
|
+
# @param [Plugin] old The plugin to replace
|
25
|
+
def self.replace_or_register(old)
|
26
|
+
Repofetch.replace_or_register_plugin(old, self)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @abstract Detects that this plugin should be used. Should be overridden by subclasses.
|
30
|
+
#
|
31
|
+
# An example implementation is checking if +Repofetch.default_remote_url+ matches
|
32
|
+
# a regular expression.
|
33
|
+
#
|
34
|
+
# @param [Git::Base] _git The Git repository object
|
35
|
+
def self.matches_repo?(_git)
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
# @abstract Detects that this plugin should be used. Should be overridden by subclasses.
|
40
|
+
#
|
41
|
+
# This is intended to be more generic than +matches_repo?+, and support any path.
|
42
|
+
#
|
43
|
+
# An example implementation is checking if an expected file exists in this path.
|
44
|
+
# @param [String] _path The path to check
|
45
|
+
def self.matches_path?(_path)
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
# @abstract This should use a git instance and call +Plugin.new+.
|
50
|
+
#
|
51
|
+
# @param [Git::Base] _git The Git repository object to use when calling +Plugin.new+.
|
52
|
+
# @param [Array] _args The arguments to process.
|
53
|
+
#
|
54
|
+
# @return [Plugin]
|
55
|
+
def self.from_git(_git, _args)
|
56
|
+
raise NoMethodError, 'from_git must be overridden by the plugin subclass'
|
57
|
+
end
|
58
|
+
|
59
|
+
# @abstract This should use a path and call +Plugin.new+.
|
60
|
+
#
|
61
|
+
# @param [String] _path The path to use when calling +Plugin.new+.
|
62
|
+
# @param [Array] _args The arguments to process.
|
63
|
+
#
|
64
|
+
# @return [Plugin]
|
65
|
+
def self.from_path(_path, _args)
|
66
|
+
raise NoMethodError, 'from_path must be overridden by the plugin subclass'
|
67
|
+
end
|
68
|
+
|
69
|
+
# @abstract This will receive an array of strings (e.g. +ARGV+) and call +Plugin.new+.
|
70
|
+
#
|
71
|
+
# @param [Array] _args The arguments to process.
|
72
|
+
#
|
73
|
+
# @return [Plugin]
|
74
|
+
def self.from_args(_args)
|
75
|
+
raise NoMethodError, 'from_args must be overridden by the plugin subclass'
|
76
|
+
end
|
77
|
+
|
78
|
+
# Gets the plugin's theme. Override to use a theme besides the default.
|
79
|
+
def theme
|
80
|
+
Repofetch::DEFAULT_THEME
|
81
|
+
end
|
82
|
+
|
83
|
+
# @abstract The ASCII to be printed alongside the stats.
|
84
|
+
#
|
85
|
+
# This should be overridden by the plugin subclass.
|
86
|
+
# Should be within the bounds 40x20 (width x height).
|
87
|
+
def ascii
|
88
|
+
raise NoMethodError, 'ascii must be overridden by the plugin subclass'
|
89
|
+
end
|
90
|
+
|
91
|
+
# @abstract The header to show for the plugin.
|
92
|
+
#
|
93
|
+
# This should be overridden by the plugin subclass.
|
94
|
+
#
|
95
|
+
# If an array is returned, it will be joined by +header_joiner+.
|
96
|
+
#
|
97
|
+
# @return [String, Array<String>]
|
98
|
+
def header
|
99
|
+
raise NoMethodError, 'header must be overridden by the plugin subclass'
|
100
|
+
end
|
101
|
+
|
102
|
+
# A string to join header text.
|
103
|
+
#
|
104
|
+
# Override to use a different string.
|
105
|
+
# @return [String]
|
106
|
+
def header_joiner
|
107
|
+
' @ '
|
108
|
+
end
|
109
|
+
|
110
|
+
# Creates the separator that appears underneath the header
|
111
|
+
def separator
|
112
|
+
return '-' * header.length unless header.is_a?(Array)
|
113
|
+
|
114
|
+
header_length = header.map(&:length).sum + ((header.length - 1) * header_joiner.length)
|
115
|
+
|
116
|
+
'-' * header_length
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_s
|
120
|
+
zipped_lines.map do |ascii_line, stat_line|
|
121
|
+
cleaned_ascii = remove_format_params(ascii_line)
|
122
|
+
styled_ascii = (ascii_line % theme.to_h) + theme.style(:reset)
|
123
|
+
aligned_stat_line = "#{' ' * (MAX_ASCII_WIDTH + 5)}#{stat_line}"
|
124
|
+
"#{styled_ascii}#{aligned_stat_line.slice(cleaned_ascii.length..)}\n"
|
125
|
+
end.join
|
126
|
+
end
|
127
|
+
|
128
|
+
# @abstract An array of stats that will be displayed to the right of the ASCII art.
|
129
|
+
#
|
130
|
+
# @return [Array<Stat>]
|
131
|
+
def stats
|
132
|
+
[]
|
133
|
+
end
|
134
|
+
|
135
|
+
# The primary color to use for the header and stats.
|
136
|
+
#
|
137
|
+
# Override to use a different color from the theme.
|
138
|
+
# @see Repofetch::Theme
|
139
|
+
#
|
140
|
+
# @return [Symbol]
|
141
|
+
def primary_color
|
142
|
+
:default
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns the header, formatted with the primary color and bold, and joined with the header joiner.
|
146
|
+
#
|
147
|
+
# @return [String]
|
148
|
+
def formatted_header
|
149
|
+
(header.is_a?(Array) ? header : [header]).map { |h| apply_styles(h, :bold, primary_color) }.join(header_joiner)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Makes an array of stat lines, including the header and separator.
|
153
|
+
def stat_lines
|
154
|
+
styled_stats = stats.map do |stat|
|
155
|
+
next stat unless stat.is_a?(Repofetch::Stat)
|
156
|
+
|
157
|
+
stat.style_label(:bold, primary_color).format(theme)
|
158
|
+
end
|
159
|
+
[formatted_header, separator, *styled_stats]
|
160
|
+
end
|
161
|
+
|
162
|
+
# Zips ASCII lines with stat lines.
|
163
|
+
#
|
164
|
+
# If there are more of one than the other, than the zip will be padded with empty strings.
|
165
|
+
def zipped_lines
|
166
|
+
ascii_lines = ascii.lines.map(&:chomp)
|
167
|
+
if ascii_lines.length > stat_lines.length
|
168
|
+
ascii_lines.zip(stat_lines)
|
169
|
+
else
|
170
|
+
stat_lines.zip(ascii_lines).map(&:reverse)
|
171
|
+
end.map { |ascii, stat| [ascii.to_s, stat.to_s] }
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
def apply_styles(str, *styles)
|
177
|
+
styles.inject(str) { |style, s| theme.format(s, style) }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Repofetch
|
4
|
+
# Base class for stats.
|
5
|
+
class Stat
|
6
|
+
attr_reader :label, :value, :emoji
|
7
|
+
attr_writer :theme
|
8
|
+
|
9
|
+
# Creates a stat
|
10
|
+
#
|
11
|
+
# @param [String] label The label of the stat
|
12
|
+
# @param value The value of the stat
|
13
|
+
# @param [String] emoji An optional emoji for the stat
|
14
|
+
def initialize(label, value, emoji: nil)
|
15
|
+
@label = label
|
16
|
+
@value = value
|
17
|
+
@emoji = emoji
|
18
|
+
@label_styles = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def format(theme = nil)
|
22
|
+
return to_s if theme.nil?
|
23
|
+
|
24
|
+
emoji = @emoji
|
25
|
+
emoji = nil unless Repofetch.config.nil? || Repofetch.config.emojis?
|
26
|
+
styled_label = @label_styles.inject(@label) { |label, style| theme.format(style, label) }
|
27
|
+
"#{emoji}#{styled_label}: #{format_value}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Formats the value of the stat
|
31
|
+
#
|
32
|
+
# Simply calls +to_s+, but can be overridden by subclasses.
|
33
|
+
def format_value
|
34
|
+
@value.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
emoji = @emoji
|
39
|
+
emoji = nil unless Repofetch.config.nil? || Repofetch.config.emojis?
|
40
|
+
"#{emoji}#{@label}: #{@value}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Adds one or more styles for the label
|
44
|
+
#
|
45
|
+
# @param [Symbol] style The theme's style to add
|
46
|
+
# @param [Symbol] styles Additional styles to add
|
47
|
+
def style_label!(style, *styles)
|
48
|
+
@label_styles << style
|
49
|
+
@label_styles.concat(styles)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Adds one or more styles for the label, returning a new stat
|
53
|
+
#
|
54
|
+
# @param [Symbol] style The theme's style to add
|
55
|
+
# @return [Stat] A new stat with the style added
|
56
|
+
def style_label(style, *styles)
|
57
|
+
dup.tap { |stat| stat.style_label!(style, *styles) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'repofetch/stat'
|
4
|
+
|
5
|
+
class Repofetch
|
6
|
+
# Timespan stat for "x units ago" stats.
|
7
|
+
class TimespanStat < Stat
|
8
|
+
include ActionView::Helpers::DateHelper
|
9
|
+
|
10
|
+
# Formats the value as "x units ago".
|
11
|
+
def format_value(now = nil)
|
12
|
+
now = Time.now if now.nil?
|
13
|
+
"#{distance_of_time_in_words(@value, now)} ago"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/repofetch/util.rb
CHANGED
@@ -2,10 +2,41 @@
|
|
2
2
|
|
3
3
|
class Repofetch
|
4
4
|
# Provides uncategorized utilities.
|
5
|
-
|
6
|
-
#
|
7
|
-
def
|
5
|
+
module Util
|
6
|
+
# Converts a format string into a plain string (e.g. +"%{green}OK"+ -> +"OK"+)
|
7
|
+
def remove_format_params(str)
|
8
8
|
str.gsub(/%{[\w\d]+?}/, '')
|
9
9
|
end
|
10
|
+
|
11
|
+
# Removes ANSI escape sequences from +str+.
|
12
|
+
def clean_ansi(str)
|
13
|
+
str.gsub("\e", '').gsub(/\[\d+(;\d+)*m/, '')
|
14
|
+
end
|
15
|
+
|
16
|
+
# Gets the name of the default remote to use.
|
17
|
+
#
|
18
|
+
# Will try to pick "origin", but if that is not found then it will
|
19
|
+
# pick the first one found, or nil if there aren't any available.
|
20
|
+
#
|
21
|
+
# @param [Git::Base] git The repository instance.
|
22
|
+
#
|
23
|
+
# @return [Git::Remote]
|
24
|
+
def default_remote(git)
|
25
|
+
remotes = git.remotes
|
26
|
+
found_remote = remotes.find { |remote| remote.name == 'origin' }
|
27
|
+
found_remote = remotes[0] if found_remote.nil?
|
28
|
+
found_remote
|
29
|
+
end
|
30
|
+
|
31
|
+
# Just wrapper around +default_remote+ since this is likely the most common
|
32
|
+
# use case (and it's easier than referencing the +Git::Remote+ docs to ensure
|
33
|
+
# correct usage in each plugin).
|
34
|
+
#
|
35
|
+
# @param [Git::Base] git The repository instance.
|
36
|
+
#
|
37
|
+
# @return [String]
|
38
|
+
def default_remote_url(git)
|
39
|
+
default_remote(git)&.url
|
40
|
+
end
|
10
41
|
end
|
11
42
|
end
|
data/lib/repofetch.rb
CHANGED
@@ -5,8 +5,12 @@ require 'git'
|
|
5
5
|
require 'repofetch/config'
|
6
6
|
require 'repofetch/env'
|
7
7
|
require 'repofetch/exceptions'
|
8
|
+
require 'repofetch/plugin'
|
9
|
+
require 'repofetch/stat'
|
10
|
+
require 'repofetch/timespan_stat'
|
8
11
|
require 'repofetch/theme'
|
9
12
|
require 'repofetch/util'
|
13
|
+
require 'repofetch/version'
|
10
14
|
|
11
15
|
# Main class for repofetch
|
12
16
|
class Repofetch
|
@@ -56,230 +60,75 @@ class Repofetch
|
|
56
60
|
# Raises a +Repofetch::NoPluginsError+ if no plugins are found.
|
57
61
|
# Raises a +Repofetch::TooManyPluginsError+ if more than one plugin is found.
|
58
62
|
#
|
59
|
-
# @param [
|
63
|
+
# @param [String] path The path to check.
|
60
64
|
# @param [Array<String>] args The arguments passed to the program.
|
61
65
|
#
|
62
66
|
# @raise [NoPluginsError] If no plugins were selected.
|
63
67
|
# @raise [TooManyPluginsError] If more than one plugin was selected.
|
64
68
|
#
|
65
69
|
# @return [Plugin] A plugin to use.
|
66
|
-
def self.get_plugin(
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
raise NoPluginsError if available_plugins.empty?
|
70
|
+
def self.get_plugin(path, args)
|
71
|
+
path_plugin = get_plugin_for_path(path)
|
72
|
+
repo_plugin = get_plugin_for_repo(path)
|
73
|
+
|
74
|
+
raise TooManyPluginsError if path_plugin && repo_plugin
|
75
|
+
|
76
|
+
raise NoPluginsError if path_plugin.nil? && repo_plugin.nil?
|
74
77
|
|
75
|
-
|
78
|
+
return path_plugin.from_path(path, args) unless path_plugin.nil?
|
76
79
|
|
77
|
-
|
80
|
+
git = Git.open(path)
|
81
|
+
repo_plugin.from_git(git, args)
|
78
82
|
end
|
79
83
|
|
80
|
-
# Gets the
|
84
|
+
# Gets the plugins that matches the given path.
|
81
85
|
#
|
82
|
-
#
|
83
|
-
# pick the first one found, or nil if there aren't any available.
|
86
|
+
# @param [String] path The path to check.
|
84
87
|
#
|
85
|
-
# @
|
86
|
-
|
87
|
-
|
88
|
-
def self.default_remote(git)
|
89
|
-
remotes = git.remotes
|
90
|
-
found_remote = remotes.find { |remote| remote.name == 'origin' }
|
91
|
-
found_remote = remotes[0] if found_remote.nil?
|
92
|
-
found_remote
|
88
|
+
# @return [Array<Plugin>] The plugins that match the path.
|
89
|
+
def self.get_plugins_for_path(path)
|
90
|
+
@plugins.filter { |plugin_class| plugin_class.matches_path?(path) }
|
93
91
|
end
|
94
92
|
|
95
|
-
#
|
96
|
-
# use case (and it's easier than referencing the +Git::Remote+ docs to ensure
|
97
|
-
# correct usage in each plugin).
|
93
|
+
# Gets a single plugin that matches the given path.
|
98
94
|
#
|
99
|
-
# @param [String] path The path to
|
95
|
+
# @param [String] path The path to check.
|
100
96
|
#
|
101
|
-
# @return [
|
102
|
-
def self.
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
# @abstract Subclass to create a plugin.
|
107
|
-
class Plugin
|
108
|
-
# Plugin intializer arguments should come from the +from_git+ or +from_args+
|
109
|
-
# class methods.
|
110
|
-
def initialize(*) end
|
111
|
-
|
112
|
-
# Registers this plugin class for repofetch.
|
113
|
-
def self.register
|
114
|
-
Repofetch.register_plugin(self)
|
115
|
-
end
|
116
|
-
|
117
|
-
# Tries to replace another plugin. An example use case might be if this plugin
|
118
|
-
# extends another registered plugin.
|
119
|
-
#
|
120
|
-
# @param [Plugin] old The plugin to replace
|
121
|
-
def self.replace_or_register(old)
|
122
|
-
Repofetch.replace_or_register_plugin(old, self)
|
123
|
-
end
|
124
|
-
|
125
|
-
# @abstract Detects that this plugin should be used. Should be overridden by subclasses.
|
126
|
-
#
|
127
|
-
# An example implementation is checking if +Repofetch.default_remote_url+ matches
|
128
|
-
# a regular expression.
|
129
|
-
#
|
130
|
-
# @param [Git::Base] _git The Git repository object
|
131
|
-
def self.matches_repo?(_git)
|
132
|
-
raise NoMethodError, 'matches_repo? must be overridden by the plugin subclass'
|
133
|
-
end
|
97
|
+
# @return [Plugin, nil] The plugin that matches the path.
|
98
|
+
def self.get_plugin_for_path(path)
|
99
|
+
plugins = get_plugins_for_path(path)
|
134
100
|
|
135
|
-
|
136
|
-
#
|
137
|
-
# @param [Git::Base] _git The Git repository object to use when calling +Plugin.new+.
|
138
|
-
# @param [Array] _args The arguments to process.
|
139
|
-
#
|
140
|
-
# @return [Plugin]
|
141
|
-
def self.from_git(_git, _args)
|
142
|
-
raise NoMethodError, 'from_git must be overridden by the plugin subclass'
|
143
|
-
end
|
144
|
-
|
145
|
-
# @abstract This will receive an array of strings (e.g. +ARGV+) and call +Plugin.new+.
|
146
|
-
#
|
147
|
-
# @param [Array] _args The arguments to process.
|
148
|
-
#
|
149
|
-
# @return [Plugin]
|
150
|
-
def self.from_args(_args)
|
151
|
-
raise NoMethodError, 'from_args must be overridden by the plugin subclass'
|
152
|
-
end
|
153
|
-
|
154
|
-
# Gets the plugin's theme. Override to use a theme besides the default.
|
155
|
-
def theme
|
156
|
-
Repofetch::DEFAULT_THEME
|
157
|
-
end
|
158
|
-
|
159
|
-
# @abstract The ASCII to be printed alongside the stats.
|
160
|
-
#
|
161
|
-
# This should be overridden by the plugin subclass.
|
162
|
-
# Should be within the bounds 40x20 (width x height).
|
163
|
-
def ascii
|
164
|
-
raise NoMethodError, 'ascii must be overridden by the plugin subclass'
|
165
|
-
end
|
166
|
-
|
167
|
-
# @abstract The header to show for the plugin.
|
168
|
-
#
|
169
|
-
# This should be overridden by the plugin subclass.
|
170
|
-
# For example, "foo/bar @ GitHub".
|
171
|
-
def header
|
172
|
-
raise NoMethodError, 'header must be overridden by the plugin subclass'
|
173
|
-
end
|
101
|
+
raise TooManyPluginsError if plugins.length > 1
|
174
102
|
|
175
|
-
|
176
|
-
def separator
|
177
|
-
'-' * Repofetch::Util.clean_s(header).length
|
178
|
-
end
|
179
|
-
|
180
|
-
def to_s
|
181
|
-
zipped_lines.map do |ascii_line, stat_line|
|
182
|
-
cleaned_ascii = Repofetch::Util.clean_s(ascii_line)
|
183
|
-
styled_ascii = (ascii_line % theme.to_h) + theme.style(:reset)
|
184
|
-
aligned_stat_line = "#{' ' * (MAX_ASCII_WIDTH + 5)}#{stat_line}"
|
185
|
-
"#{styled_ascii}#{aligned_stat_line.slice(cleaned_ascii.length..)}\n"
|
186
|
-
end.join
|
187
|
-
end
|
188
|
-
|
189
|
-
# @abstract An array of stats that will be displayed to the right of the ASCII art.
|
190
|
-
#
|
191
|
-
# @return [Array<Stat>]
|
192
|
-
def stats
|
193
|
-
[]
|
194
|
-
end
|
195
|
-
|
196
|
-
# Adds +theme+ to the stats, mutating those stats.
|
197
|
-
#
|
198
|
-
# @return [Array<Stat>]
|
199
|
-
def theme_stats!
|
200
|
-
stats.each do |stat|
|
201
|
-
stat.theme = theme if stat.respond_to?(:theme=)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
# Makes an array of stat lines, including the header and separator.
|
206
|
-
#
|
207
|
-
# Mutates +stats+ to add the +theme+.
|
208
|
-
def stat_lines!
|
209
|
-
[header, separator, *theme_stats!.map(&:to_s)]
|
210
|
-
end
|
211
|
-
|
212
|
-
# Zips ASCII lines with stat lines.
|
213
|
-
#
|
214
|
-
# If there are more of one than the other, than the zip will be padded with empty strings.
|
215
|
-
def zipped_lines
|
216
|
-
ascii_lines = ascii.lines.map(&:chomp)
|
217
|
-
stat_lines = stat_lines!
|
218
|
-
if ascii_lines.length > stat_lines.length
|
219
|
-
ascii_lines.zip(stat_lines)
|
220
|
-
else
|
221
|
-
stat_lines.zip(ascii_lines).map(&:reverse)
|
222
|
-
end.map { |ascii, stat| [ascii.to_s, stat.to_s] }
|
223
|
-
end
|
103
|
+
plugins[0]
|
224
104
|
end
|
225
105
|
|
226
|
-
#
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
def initialize(label, value, emoji: nil)
|
237
|
-
@label = label
|
238
|
-
@value = value
|
239
|
-
@emoji = emoji
|
240
|
-
@label_styles = []
|
241
|
-
end
|
242
|
-
|
243
|
-
def to_s
|
244
|
-
emoji = @emoji
|
245
|
-
emoji = nil unless Repofetch.config.nil? || Repofetch.config.emojis?
|
246
|
-
"#{emoji}#{format_label}: #{format_value}"
|
247
|
-
end
|
248
|
-
|
249
|
-
# Adds a style for the label
|
250
|
-
#
|
251
|
-
# @param [Symbol] style The theme's style to add
|
252
|
-
def style_label!(style)
|
253
|
-
@label_styles << style
|
254
|
-
end
|
255
|
-
|
256
|
-
# Formats the label, including styles.
|
257
|
-
#
|
258
|
-
# @return [String]
|
259
|
-
def format_label
|
260
|
-
return @label if @theme.nil?
|
261
|
-
|
262
|
-
@label_styles.inject(@label) { |label, style| @theme.format(style, label) }
|
106
|
+
# Gets the plugins that matches the given repository.
|
107
|
+
#
|
108
|
+
# @param [String] path The repository to check.
|
109
|
+
#
|
110
|
+
# @return [Array<Plugin>] The plugins that match the repository.
|
111
|
+
def self.get_plugins_for_repo(path)
|
112
|
+
begin
|
113
|
+
git = Git.open(path)
|
114
|
+
rescue ArgumentError
|
115
|
+
return []
|
263
116
|
end
|
264
117
|
|
265
|
-
|
266
|
-
#
|
267
|
-
# This simply converts the value to a string, but can be overridden but
|
268
|
-
# subclasses to affect +to_s+.
|
269
|
-
def format_value
|
270
|
-
@value.to_s
|
271
|
-
end
|
118
|
+
@plugins.filter { |plugin_class| plugin_class.matches_repo?(git) }
|
272
119
|
end
|
273
120
|
|
274
|
-
#
|
275
|
-
|
276
|
-
|
121
|
+
# Gets a single plugin that matches the given repository.
|
122
|
+
#
|
123
|
+
# @param [String] path The repository to check.
|
124
|
+
#
|
125
|
+
# @return [Plugin, nil] The plugin that matches the repository.
|
126
|
+
def self.get_plugin_for_repo(path)
|
127
|
+
plugins = get_plugins_for_repo(path)
|
277
128
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
"#{distance_of_time_in_words(@value, now)} ago"
|
282
|
-
end
|
129
|
+
raise TooManyPluginsError if plugins.length > 1
|
130
|
+
|
131
|
+
plugins[0]
|
283
132
|
end
|
284
133
|
|
285
134
|
def self.clear_plugins
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: repofetch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Spenser Black
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-01-
|
11
|
+
date: 2023-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionview
|
@@ -296,8 +296,10 @@ files:
|
|
296
296
|
- exe/repofetch
|
297
297
|
- lib/repofetch.rb
|
298
298
|
- lib/repofetch/DEFAULT_CONFIG
|
299
|
+
- lib/repofetch/VERSION
|
299
300
|
- lib/repofetch/bitbucketcloud.rb
|
300
301
|
- lib/repofetch/bitbucketcloud/ASCII
|
302
|
+
- lib/repofetch/bitbucketcloud/stats.rb
|
301
303
|
- lib/repofetch/cli.rb
|
302
304
|
- lib/repofetch/config.rb
|
303
305
|
- lib/repofetch/env.rb
|
@@ -306,8 +308,12 @@ files:
|
|
306
308
|
- lib/repofetch/github/ASCII
|
307
309
|
- lib/repofetch/gitlab.rb
|
308
310
|
- lib/repofetch/gitlab/ASCII
|
311
|
+
- lib/repofetch/plugin.rb
|
312
|
+
- lib/repofetch/stat.rb
|
309
313
|
- lib/repofetch/theme.rb
|
314
|
+
- lib/repofetch/timespan_stat.rb
|
310
315
|
- lib/repofetch/util.rb
|
316
|
+
- lib/repofetch/version.rb
|
311
317
|
homepage: https://github.com/spenserblack/repofetch
|
312
318
|
licenses:
|
313
319
|
- MIT
|