repofetch 0.4.4 → 0.5.0
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 +14 -11
- data/README.md +1 -1
- data/RELEASE_NOTES +25 -3
- data/lib/repofetch/bitbucketcloud/stats.rb +64 -0
- data/lib/repofetch/bitbucketcloud.rb +14 -63
- data/lib/repofetch/cli.rb +1 -3
- 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.rb +47 -199
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d212500ad7536eede542d6a5c1e8e0f7cd6de302dd6508c6c279896100004b37
|
4
|
+
data.tar.gz: b8a63cc0c47c808f937b27041e508dbec59fee6934d6adaf2e1e4e94cbf73be5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fffca813b8f21cdae1229dc8d506ff1fba2d50db37252b1403d20a327a276991567aa46e78dcd52a999d290951162886e7ad6366b930054d7553cf5516eecf92
|
7
|
+
data.tar.gz: 788d2d7d46db0e2ed455e170ffaa52a5b392cb87815eb09f906a92e0523d51dc81a2d8f279d850757071046ade142a29e3811734b53931ba1f63691d089746c7
|
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.0)
|
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,7 +86,7 @@ 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)
|
@@ -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.4
|
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,28 @@
|
|
1
|
-
|
1
|
+
0.5.0
|
2
|
+
|
3
|
+
## Added
|
4
|
+
|
5
|
+
- `Stat#format(theme)` to create styled stats
|
6
|
+
- `Stat#style_label` to style the label without mutating the original `Stat` instance
|
7
|
+
- `Plugin#matches_path?` and `Plugin#from_path` to allow plugins to initialize from paths, not
|
8
|
+
just git repositories
|
9
|
+
|
10
|
+
## Changed
|
11
|
+
|
12
|
+
- Bitbucket Cloud header to be bold and blue
|
13
|
+
- `Stat#style_label!` to accept one or more styles as parameters
|
14
|
+
- `Plugin#matches_repo?` to return `false` instead of raising an error when it is not overridden
|
2
15
|
|
3
16
|
## Fixed
|
4
17
|
|
5
|
-
-
|
6
|
-
|
18
|
+
- length of separator to match *visual* length of header
|
19
|
+
|
20
|
+
## Potentially Breaking for 3rd-party Plugins
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
|
24
|
+
- `Repofetch::Util` to be a module
|
25
|
+
- `clean_s` to be called `remove_format_params`
|
26
|
+
- Moved `default_remote` and `default_remote_url` to be in `Repofetch::Util`
|
27
|
+
- `Stat#to_s` to return an unstyled value
|
28
|
+
- Header text and stats will now automatically be bold and use the value returned by `Plugin#primary_color`
|
@@ -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,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'git'
|
4
3
|
require 'optparse'
|
5
4
|
require 'repofetch'
|
6
5
|
require 'repofetch/config'
|
@@ -56,8 +55,7 @@ class Repofetch
|
|
56
55
|
def new_plugin
|
57
56
|
return @plugin.from_args(@args) unless @plugin.nil?
|
58
57
|
|
59
|
-
|
60
|
-
Repofetch.get_plugin(git, @args)
|
58
|
+
Repofetch.get_plugin(@repository_path, @args)
|
61
59
|
end
|
62
60
|
|
63
61
|
private
|
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,6 +5,9 @@ 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'
|
10
13
|
|
@@ -56,230 +59,75 @@ class Repofetch
|
|
56
59
|
# Raises a +Repofetch::NoPluginsError+ if no plugins are found.
|
57
60
|
# Raises a +Repofetch::TooManyPluginsError+ if more than one plugin is found.
|
58
61
|
#
|
59
|
-
# @param [
|
62
|
+
# @param [String] path The path to check.
|
60
63
|
# @param [Array<String>] args The arguments passed to the program.
|
61
64
|
#
|
62
65
|
# @raise [NoPluginsError] If no plugins were selected.
|
63
66
|
# @raise [TooManyPluginsError] If more than one plugin was selected.
|
64
67
|
#
|
65
68
|
# @return [Plugin] A plugin to use.
|
66
|
-
def self.get_plugin(
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
raise NoPluginsError if available_plugins.empty?
|
69
|
+
def self.get_plugin(path, args)
|
70
|
+
path_plugin = get_plugin_for_path(path)
|
71
|
+
repo_plugin = get_plugin_for_repo(path)
|
72
|
+
|
73
|
+
raise TooManyPluginsError if path_plugin && repo_plugin
|
74
|
+
|
75
|
+
raise NoPluginsError if path_plugin.nil? && repo_plugin.nil?
|
74
76
|
|
75
|
-
|
77
|
+
return path_plugin.from_path(path, args) unless path_plugin.nil?
|
76
78
|
|
77
|
-
|
79
|
+
git = Git.open(path)
|
80
|
+
repo_plugin.from_git(git, args)
|
78
81
|
end
|
79
82
|
|
80
|
-
# Gets the
|
83
|
+
# Gets the plugins that matches the given path.
|
81
84
|
#
|
82
|
-
#
|
83
|
-
# pick the first one found, or nil if there aren't any available.
|
85
|
+
# @param [String] path The path to check.
|
84
86
|
#
|
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
|
87
|
+
# @return [Array<Plugin>] The plugins that match the path.
|
88
|
+
def self.get_plugins_for_path(path)
|
89
|
+
@plugins.filter { |plugin_class| plugin_class.matches_path?(path) }
|
93
90
|
end
|
94
91
|
|
95
|
-
#
|
96
|
-
# use case (and it's easier than referencing the +Git::Remote+ docs to ensure
|
97
|
-
# correct usage in each plugin).
|
92
|
+
# Gets a single plugin that matches the given path.
|
98
93
|
#
|
99
|
-
# @param [String] path The path to
|
94
|
+
# @param [String] path The path to check.
|
100
95
|
#
|
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
|
96
|
+
# @return [Plugin, nil] The plugin that matches the path.
|
97
|
+
def self.get_plugin_for_path(path)
|
98
|
+
plugins = get_plugins_for_path(path)
|
134
99
|
|
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
|
100
|
+
raise TooManyPluginsError if plugins.length > 1
|
174
101
|
|
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
|
102
|
+
plugins[0]
|
224
103
|
end
|
225
104
|
|
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) }
|
105
|
+
# Gets the plugins that matches the given repository.
|
106
|
+
#
|
107
|
+
# @param [String] path The repository to check.
|
108
|
+
#
|
109
|
+
# @return [Array<Plugin>] The plugins that match the repository.
|
110
|
+
def self.get_plugins_for_repo(path)
|
111
|
+
begin
|
112
|
+
git = Git.open(path)
|
113
|
+
rescue ArgumentError
|
114
|
+
return []
|
263
115
|
end
|
264
116
|
|
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
|
117
|
+
@plugins.filter { |plugin_class| plugin_class.matches_repo?(git) }
|
272
118
|
end
|
273
119
|
|
274
|
-
#
|
275
|
-
|
276
|
-
|
120
|
+
# Gets a single plugin that matches the given repository.
|
121
|
+
#
|
122
|
+
# @param [String] path The repository to check.
|
123
|
+
#
|
124
|
+
# @return [Plugin, nil] The plugin that matches the repository.
|
125
|
+
def self.get_plugin_for_repo(path)
|
126
|
+
plugins = get_plugins_for_repo(path)
|
277
127
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
"#{distance_of_time_in_words(@value, now)} ago"
|
282
|
-
end
|
128
|
+
raise TooManyPluginsError if plugins.length > 1
|
129
|
+
|
130
|
+
plugins[0]
|
283
131
|
end
|
284
132
|
|
285
133
|
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.0
|
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-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionview
|
@@ -298,6 +298,7 @@ files:
|
|
298
298
|
- lib/repofetch/DEFAULT_CONFIG
|
299
299
|
- lib/repofetch/bitbucketcloud.rb
|
300
300
|
- lib/repofetch/bitbucketcloud/ASCII
|
301
|
+
- lib/repofetch/bitbucketcloud/stats.rb
|
301
302
|
- lib/repofetch/cli.rb
|
302
303
|
- lib/repofetch/config.rb
|
303
304
|
- lib/repofetch/env.rb
|
@@ -306,7 +307,10 @@ files:
|
|
306
307
|
- lib/repofetch/github/ASCII
|
307
308
|
- lib/repofetch/gitlab.rb
|
308
309
|
- lib/repofetch/gitlab/ASCII
|
310
|
+
- lib/repofetch/plugin.rb
|
311
|
+
- lib/repofetch/stat.rb
|
309
312
|
- lib/repofetch/theme.rb
|
313
|
+
- lib/repofetch/timespan_stat.rb
|
310
314
|
- lib/repofetch/util.rb
|
311
315
|
homepage: https://github.com/spenserblack/repofetch
|
312
316
|
licenses:
|