gitmarshal 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/README.md +34 -11
- data/lib/gitmarshal/base_fetcher.rb +5 -6
- data/lib/gitmarshal/cli.rb +100 -70
- data/lib/gitmarshal/github_fetcher.rb +52 -27
- data/lib/gitmarshal/metric_fetcher.rb +2 -2
- data/lib/gitmarshal/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d1136a825070f9c33c0a3288175c2d1df3bc56c861a2c4612d1e91728b54eff
|
4
|
+
data.tar.gz: 27de3ae232d1d9e8694cb3433f3a3f74853a67a1a5b34987ff9995a872e96b53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d223482bd2ff8d5b20d62bb98402f974073ab02ca98f845df36b0dea27ab5d2c8c863d90d61c450b5d21430e3ff3e906006a117056cf26bfd1aabcec0dbd9cab
|
7
|
+
data.tar.gz: 967f16553443e6ba49828f2cbabfb8b267784e3b02279540b8c420fc41be227e7eec5d6a79682b798c5990025df8e24c1d0a135b41aebf900bd0a6d7a327ae6f
|
data/README.md
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
# GitMarshal
|
2
|
-
[](https://opensource.org/licenses/MIT) [](https://codeclimate.com/github/nagstler/gitmarshal/maintainability)
|
2
|
+
[](https://opensource.org/licenses/MIT) [](https://codeclimate.com/github/nagstler/gitmarshal/maintainability) [](https://github.com/nagstler/gitmarshal/actions/workflows/gem-push.yml)
|
3
3
|
|
4
4
|
GitMarshal is a command-line interface (CLI) to extract and display various statistics about GitHub repositories. The metrics it retrieves include the number of commits, pull requests, issues, stars, and contributors.
|
5
5
|
|
6
6
|
Whether you're a developer interested in the activity of a repository or a manager tracking the progress of your project, GitMarshal provides an easy way to fetch this data directly from your command line.
|
7
7
|
|
8
|
-
## Features
|
8
|
+
## :sparkles: Features
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
-
|
10
|
+
:octocat: Fetch and display a summary of your GitHub repositories.
|
11
|
+
|
12
|
+
:bar_chart: Fetch and display detailed metrics for a specific repository, including number of commits, pull requests, issues, stars, and contributors.
|
13
|
+
|
14
|
+
:computer: Easy-to-use command-line interface.
|
15
|
+
|
16
|
+
:wrench: Configurable through environment variables.
|
17
|
+
|
18
|
+
:gem: Available as a Ruby gem for easy installation.
|
15
19
|
|
16
20
|
|
17
21
|
## Table of Contents
|
@@ -61,6 +65,7 @@ export GITHUB_TOKEN=your_github_token_here
|
|
61
65
|
Be sure to replace `your_github_token_here` with the token you generated in the Prerequisites step.
|
62
66
|
|
63
67
|
## Usage
|
68
|
+
|
64
69
|
Once installed and configured, GitMarshal can be used directly from the command-line as follows:
|
65
70
|
|
66
71
|
### List All Repositories
|
@@ -75,13 +80,33 @@ This will provide you with a comprehensive list of your repositories and will sh
|
|
75
80
|
|
76
81
|
### Fetch Metrics for a Specific Repository
|
77
82
|
|
78
|
-
To fetch and display metrics for a specific repository, use:
|
83
|
+
To fetch and display overall metrics for a specific repository, use:
|
79
84
|
|
80
85
|
```bash
|
81
86
|
gitmarshal repo-name
|
82
87
|
```
|
83
88
|
|
84
|
-
Replace `
|
89
|
+
Replace `repo-name` with the name of the repository for which you wish to fetch metrics.
|
90
|
+
|
91
|
+
### Fetch Today's Metrics for a Specific Repository
|
92
|
+
|
93
|
+
To fetch and display metrics for a specific repository for today only, use:
|
94
|
+
|
95
|
+
```bash
|
96
|
+
gitmarshal repo-name --today
|
97
|
+
```
|
98
|
+
|
99
|
+
Replace `repo-name` with the name of the repository for which you wish to fetch today's metrics.
|
100
|
+
|
101
|
+
### Help Command
|
102
|
+
|
103
|
+
If you need help with the commands or if you are unsure about the functionality of GitMarshal, use the help command:
|
104
|
+
|
105
|
+
```bash
|
106
|
+
gitmarshal help
|
107
|
+
```
|
108
|
+
|
109
|
+
This will display a helpful guide on how to use GitMarshal, its options, and commands.
|
85
110
|
|
86
111
|
## Development
|
87
112
|
|
@@ -93,8 +118,6 @@ cd gitmarshal
|
|
93
118
|
bundle install
|
94
119
|
```
|
95
120
|
|
96
|
-
|
97
|
-
|
98
121
|
You can then run the tests with:
|
99
122
|
|
100
123
|
```bash
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "json"
|
2
|
+
require "net/http"
|
3
3
|
|
4
4
|
class BaseFetcher
|
5
5
|
GITHUB_API_BASE_URL = "https://api.github.com"
|
@@ -7,16 +7,15 @@ class BaseFetcher
|
|
7
7
|
protected
|
8
8
|
|
9
9
|
def execute_http_request(req)
|
10
|
-
Net::HTTP.start(req.uri.hostname, req.uri.port, :use_ssl => req.uri.scheme ==
|
10
|
+
Net::HTTP.start(req.uri.hostname, req.uri.port, :use_ssl => req.uri.scheme == "https") do |http|
|
11
11
|
http.request(req)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
def create_request(uri)
|
16
16
|
Net::HTTP::Get.new(uri,
|
17
|
-
|
18
|
-
|
19
|
-
)
|
17
|
+
"Content-Type" => "application/json",
|
18
|
+
"Authorization" => "Bearer #{ENV["GITHUB_TOKEN"]}")
|
20
19
|
end
|
21
20
|
|
22
21
|
def parse_response(response)
|
data/lib/gitmarshal/cli.rb
CHANGED
@@ -1,110 +1,140 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require_relative
|
1
|
+
require "thor"
|
2
|
+
require "terminal-table"
|
3
|
+
require "colorize"
|
4
|
+
require_relative "github_fetcher"
|
5
5
|
|
6
6
|
module GitMarshal
|
7
7
|
class CLI < Thor
|
8
|
-
class_option :help, type: :boolean, aliases:
|
8
|
+
class_option :help, type: :boolean, aliases: "-h", desc: "Display usage information"
|
9
|
+
class_option :today, type: :boolean, aliases: "-t", desc: 'Display today\'s repository metrics instead of overall metrics'
|
9
10
|
|
10
11
|
desc "repos", "Prints a summary of the authenticated user's GitHub repositories"
|
12
|
+
|
11
13
|
def repos
|
12
14
|
begin
|
13
15
|
fetcher = GithubFetcher.new
|
14
16
|
user = fetcher.fetch_user
|
15
17
|
repos = fetcher.fetch_repos
|
16
|
-
|
18
|
+
|
17
19
|
puts "GitHub Repositories for #{user}".colorize(:blue).bold
|
18
|
-
|
20
|
+
|
19
21
|
rows = repos.map do |repo|
|
20
22
|
[
|
21
|
-
repo[
|
22
|
-
repo[
|
23
|
-
repo[
|
24
|
-
repo[
|
23
|
+
repo["name"],
|
24
|
+
repo["issues"],
|
25
|
+
repo["stargazers"],
|
26
|
+
repo["forks"],
|
25
27
|
]
|
26
28
|
end
|
27
|
-
|
29
|
+
|
28
30
|
table = Terminal::Table.new :title => "Repositories".colorize(:green).bold,
|
29
|
-
:headings => [
|
31
|
+
:headings => ["Name", "Issues", "Stargazers", "Forks"].map { |i| i.colorize(:magenta).bold },
|
30
32
|
:rows => rows
|
31
|
-
|
33
|
+
|
32
34
|
table.style = { :border_x => "=", :border_i => "x", :alignment => :center }
|
33
35
|
puts table
|
34
36
|
rescue StandardError => e
|
35
37
|
puts "An error occurred: #{e.message}"
|
36
38
|
end
|
37
39
|
end
|
38
|
-
|
39
40
|
|
40
41
|
def help(*)
|
41
|
-
|
42
|
+
rows = []
|
43
|
+
rows << ["gitmarshal", "List all repositories of the authenticated user"]
|
44
|
+
rows << ["gitmarshal repo-name", "Show the overall metrics of the given repository"]
|
45
|
+
rows << ["gitmarshal repo-name --today", "Show today's metrics of the given repository"]
|
46
|
+
|
47
|
+
table = Terminal::Table.new :rows => rows
|
48
|
+
table.title = "GitMarshal Commands".colorize(:green).bold
|
49
|
+
table.headings = ['Command', 'Description'].map { |i| i.colorize(:magenta).bold }
|
50
|
+
table.style = { :border_x => "=", :border_i => "x", :alignment => :left }
|
51
|
+
puts table
|
42
52
|
end
|
43
53
|
|
44
54
|
private
|
45
55
|
|
46
|
-
def metrics(repo_name)
|
56
|
+
def metrics(repo_name, today_option = false)
|
47
57
|
fetcher = GithubFetcher.new
|
48
58
|
user = fetcher.fetch_user
|
49
|
-
|
50
|
-
repo = fetcher.fetch_repo_metrics(user, repo_name)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
59
|
+
|
60
|
+
repo = today_option ? fetcher.fetch_today_repo_metrics(user, repo_name) : fetcher.fetch_repo_metrics(user, repo_name)
|
61
|
+
|
62
|
+
if today_option
|
63
|
+
rows = prepare_table_rows_for_today(repo)
|
64
|
+
# Display latest commit
|
65
|
+
latest_commit = fetcher.fetch_latest_commit(user, repo_name)
|
66
|
+
if latest_commit
|
67
|
+
rows << ["Latest Commit Date", latest_commit["commit"]["committer"]["date"]]
|
68
|
+
rows << ["Latest Commit Message", wrap_text(latest_commit["commit"]["message"])]
|
69
|
+
end
|
70
|
+
# Display today's metrics in a table
|
71
|
+
display_table("Today's Repository Metrics", rows)
|
72
|
+
else
|
73
|
+
rows = prepare_table_rows(repo)
|
74
|
+
# Display latest commit
|
75
|
+
latest_commit = fetcher.fetch_latest_commit(user, repo_name)
|
76
|
+
if latest_commit
|
77
|
+
rows << ["Latest Commit Date", latest_commit["commit"]["committer"]["date"]]
|
78
|
+
rows << ["Latest Commit Message", wrap_text(latest_commit["commit"]["message"])]
|
79
|
+
end
|
80
|
+
# Display overall metrics in a table
|
81
|
+
display_table("Repository Metrics", rows)
|
66
82
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
[
|
78
|
-
[
|
79
|
-
[
|
80
|
-
[
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def wrap_text(text, max_width = 50)
|
88
|
+
text.gsub(/(.{1,#{max_width}})(\s+|\Z)/, "\\1\n")
|
89
|
+
end
|
90
|
+
|
91
|
+
def prepare_table_rows_for_today(repo)
|
92
|
+
[
|
93
|
+
["Repository Name", repo["name"]],
|
94
|
+
["Total Commits", repo["commits_count"].to_s],
|
95
|
+
["Pull Requests", repo["pull_requests_count"].to_s],
|
96
|
+
["Forks", repo["forks_count"].to_s],
|
97
|
+
["Issues", repo["issues_count"].to_s],
|
98
|
+
["Open Issues", repo["open_issues_count"].to_s],
|
99
|
+
["Closed Issues", repo["closed_issues_count"].to_s],
|
100
|
+
["Open Pull Requests", repo["open_pull_requests_count"].to_s],
|
101
|
+
["Closed Pull Requests", repo["closed_pull_requests_count"].to_s],
|
81
102
|
]
|
82
|
-
|
83
|
-
|
103
|
+
end
|
104
|
+
|
105
|
+
def prepare_table_rows(repo)
|
106
|
+
[
|
107
|
+
["Repository Name", repo["name"]],
|
108
|
+
["Default Branch", repo["default_branch"]],
|
109
|
+
["Last Updated At", repo["last_updated_at"]],
|
110
|
+
["Total Commits", repo["commits_count"].to_s],
|
111
|
+
["Pull Requests", repo["pull_requests_count"].to_s],
|
112
|
+
["Forks", repo["forks_count"].to_s],
|
113
|
+
["Watchers", repo["watchers_count"].to_s],
|
114
|
+
["Issues", repo["issues_count"].to_s],
|
115
|
+
["Open Issues", repo["open_issues_count"].to_s],
|
116
|
+
["Closed Issues", repo["closed_issues_count"].to_s],
|
117
|
+
["Open Pull Requests", repo["open_pull_requests_count"].to_s],
|
118
|
+
["Closed Pull Requests", repo["closed_pull_requests_count"].to_s],
|
119
|
+
["Contributors", repo["contributors_count"].to_s],
|
120
|
+
["Stargazers", repo["stargazers_count"].to_s],
|
121
|
+
]
|
122
|
+
end
|
123
|
+
|
124
|
+
def display_table(title, rows)
|
125
|
+
table = Terminal::Table.new :title => title.colorize(:blue).bold,
|
126
|
+
:headings => ["Metric", "Data"].map { |i| i.colorize(:magenta).bold },
|
127
|
+
:rows => rows
|
128
|
+
|
84
129
|
table.style = { :border_x => "=", :border_i => "x", :alignment => :center }
|
85
|
-
puts table
|
86
130
|
|
87
|
-
|
88
|
-
# today_rows = [
|
89
|
-
# ['Today\'s Total Commits', fetcher.fetch_today_commits_count(user, repo_name)],
|
90
|
-
# ['Today\'s Pull Requests', fetcher.fetch_today_pull_requests_count(user, repo_name)],
|
91
|
-
# ['Today\'s Closed Pull Requests', fetcher.fetch_today_closed_pull_requests_count(user, repo_name)],
|
92
|
-
# ['Today\'s Open Pull Requests', fetcher.fetch_today_open_pull_requests_count(user, repo_name)],
|
93
|
-
# ['Today\'s Issues', fetcher.fetch_today_issues_count(user, repo_name)],
|
94
|
-
# ['Today\'s Closed Issues', fetcher.fetch_today_closed_issues_count(user, repo_name)],
|
95
|
-
# ['Today\'s Open Issues', fetcher.fetch_today_open_issues_count(user, repo_name)]
|
96
|
-
# ]
|
97
|
-
|
98
|
-
# today_table = Terminal::Table.new :title => "Today's Repository Metrics".colorize(:green).bold, :headings => ['Metric', 'Count'].map { |i| i.colorize(:magenta).bold }, :rows => today_rows
|
99
|
-
# today_table.style = { :border_x => "=", :border_i => "x", :alignment => :center }
|
100
|
-
# puts today_table
|
131
|
+
puts table
|
101
132
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
def method_missing(method, *_args, &_block)
|
133
|
+
|
134
|
+
def method_missing(method, *args, &_block)
|
106
135
|
if method =~ /[-a-zA-Z0-9_.]+/
|
107
|
-
|
136
|
+
today_option = args.include?("--today")
|
137
|
+
metrics(method.to_s, today_option)
|
108
138
|
else
|
109
139
|
super
|
110
140
|
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require_relative
|
2
|
-
require
|
1
|
+
require_relative "metric_fetcher"
|
2
|
+
require "octokit"
|
3
3
|
|
4
4
|
class GithubFetcher
|
5
5
|
def initialize
|
6
6
|
Octokit.configure do |config|
|
7
|
-
config.access_token = ENV[
|
7
|
+
config.access_token = ENV["GITHUB_TOKEN"]
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -15,32 +15,51 @@ class GithubFetcher
|
|
15
15
|
def fetch_repos
|
16
16
|
Octokit.repositories.map do |repo|
|
17
17
|
{
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
"name" => repo.name,
|
19
|
+
"issues" => repo.open_issues_count,
|
20
|
+
"stargazers" => repo.stargazers_count,
|
21
|
+
"forks" => repo.forks_count,
|
22
22
|
}
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
def fetch_today_repo_metrics(user, repo_name)
|
27
|
+
{
|
28
|
+
"name" => repo_name,
|
29
|
+
"forks_count" => fetch_today_forks_count(user, repo_name),
|
30
|
+
"open_issues_count" => fetch_today_open_issues_count(user, repo_name),
|
31
|
+
"commits_count" => fetch_today_commits_count(user, repo_name),
|
32
|
+
"pull_requests_count" => fetch_today_pull_requests_count(user, repo_name),
|
33
|
+
"closed_pull_requests_count" => fetch_today_closed_pull_requests_count(user, repo_name),
|
34
|
+
"open_pull_requests_count" => fetch_today_open_pull_requests_count(user, repo_name),
|
35
|
+
"issues_count" => fetch_today_issues_count(user, repo_name),
|
36
|
+
"closed_issues_count" => fetch_today_closed_issues_count(user, repo_name),
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
26
40
|
def fetch_repo_metrics(user, repo_name)
|
27
|
-
|
41
|
+
begin
|
42
|
+
repo = Octokit.repository("#{user}/#{repo_name}")
|
43
|
+
rescue Octokit::NotFound
|
44
|
+
puts "The repository #{user}/#{repo_name} was not found. Please check the repository name and try again."
|
45
|
+
exit
|
46
|
+
end
|
28
47
|
{
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
48
|
+
"name" => repo.name,
|
49
|
+
"description" => repo.description,
|
50
|
+
"default_branch" => repo.default_branch,
|
51
|
+
"last_updated_at" => repo.updated_at,
|
52
|
+
"watchers_count" => repo.watchers_count,
|
53
|
+
"forks_count" => repo.forks_count,
|
54
|
+
"open_issues_count" => repo.open_issues_count,
|
55
|
+
"commits_count" => Octokit.commits("#{user}/#{repo_name}").count,
|
56
|
+
"pull_requests_count" => Octokit.pull_requests("#{user}/#{repo_name}").count,
|
57
|
+
"closed_pull_requests_count" => Octokit.pull_requests("#{user}/#{repo_name}", state: "closed").count,
|
58
|
+
"open_pull_requests_count" => Octokit.pull_requests("#{user}/#{repo_name}", state: "open").count,
|
59
|
+
"issues_count" => Octokit.issues("#{user}/#{repo_name}").count,
|
60
|
+
"closed_issues_count" => Octokit.issues("#{user}/#{repo_name}", state: "closed").count,
|
61
|
+
"stargazers_count" => repo.stargazers_count,
|
62
|
+
"contributors_count" => Octokit.contributors("#{user}/#{repo_name}").count,
|
44
63
|
}
|
45
64
|
end
|
46
65
|
|
@@ -61,13 +80,13 @@ class GithubFetcher
|
|
61
80
|
end
|
62
81
|
|
63
82
|
def fetch_today_closed_pull_requests_count(user, repo_name)
|
64
|
-
Octokit.pull_requests("#{user}/#{repo_name}", state:
|
83
|
+
Octokit.pull_requests("#{user}/#{repo_name}", state: "closed").count do |pr|
|
65
84
|
pr.closed_at.to_date == Date.today
|
66
85
|
end
|
67
86
|
end
|
68
87
|
|
69
88
|
def fetch_today_open_pull_requests_count(user, repo_name)
|
70
|
-
Octokit.pull_requests("#{user}/#{repo_name}", state:
|
89
|
+
Octokit.pull_requests("#{user}/#{repo_name}", state: "open").count do |pr|
|
71
90
|
pr.created_at.to_date == Date.today
|
72
91
|
end
|
73
92
|
end
|
@@ -79,14 +98,20 @@ class GithubFetcher
|
|
79
98
|
end
|
80
99
|
|
81
100
|
def fetch_today_closed_issues_count(user, repo_name)
|
82
|
-
Octokit.issues("#{user}/#{repo_name}", state:
|
101
|
+
Octokit.issues("#{user}/#{repo_name}", state: "closed").count do |issue|
|
83
102
|
issue.closed_at.to_date == Date.today
|
84
103
|
end
|
85
104
|
end
|
86
105
|
|
87
106
|
def fetch_today_open_issues_count(user, repo_name)
|
88
|
-
Octokit.issues("#{user}/#{repo_name}", state:
|
107
|
+
Octokit.issues("#{user}/#{repo_name}", state: "open").count do |issue|
|
89
108
|
issue.created_at.to_date == Date.today
|
90
109
|
end
|
91
110
|
end
|
111
|
+
|
112
|
+
def fetch_today_forks_count(user, repo_name)
|
113
|
+
Octokit.forks("#{user}/#{repo_name}").count do |fork|
|
114
|
+
fork.created_at.to_date == Date.today
|
115
|
+
end
|
116
|
+
end
|
92
117
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative "base_fetcher"
|
2
2
|
|
3
3
|
class MetricFetcher < BaseFetcher
|
4
4
|
def fetch_today_commits_count(owner, repo_name)
|
@@ -43,6 +43,6 @@ class MetricFetcher < BaseFetcher
|
|
43
43
|
response = execute_http_request(req)
|
44
44
|
star_data = parse_response(response)
|
45
45
|
|
46
|
-
star_data[
|
46
|
+
star_data["stargazers_count"]
|
47
47
|
end
|
48
48
|
end
|
data/lib/gitmarshal/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitmarshal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nagendra Dhanakeerthi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-07-
|
11
|
+
date: 2023-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|