hubstats 0.4.4 → 0.5.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 +5 -13
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.markdown +5 -0
- data/README.md +64 -22
- data/app/assets/javascripts/hubstats/pull_requests.js +5 -0
- data/app/assets/javascripts/hubstats/select2.js +46 -3
- data/app/assets/javascripts/hubstats/users.js +8 -0
- data/app/assets/stylesheets/hubstats/application.css +5 -1
- data/app/controllers/hubstats/pull_requests_controller.rb +2 -3
- data/app/controllers/hubstats/repos_controller.rb +7 -12
- data/app/controllers/hubstats/teams_controller.rb +62 -0
- data/app/controllers/hubstats/users_controller.rb +9 -8
- data/app/models/hubstats/comment.rb +1 -0
- data/app/models/hubstats/pull_request.rb +40 -8
- data/app/models/hubstats/repo.rb +1 -1
- data/app/models/hubstats/team.rb +159 -0
- data/app/models/hubstats/user.rb +10 -1
- data/app/views/hubstats/deploys/show.html.erb +1 -4
- data/app/views/hubstats/partials/_comment-condensed.html.erb +1 -0
- data/app/views/hubstats/partials/_comment.html.erb +1 -0
- data/app/views/hubstats/partials/_footer.html.erb +3 -0
- data/app/views/hubstats/partials/_header.html.erb +5 -3
- data/app/views/hubstats/partials/_team.html.erb +40 -0
- data/app/views/hubstats/partials/_user-condensed.html.erb +6 -5
- data/app/views/hubstats/partials/_user.html.erb +2 -1
- data/app/views/hubstats/pull_requests/index.html.erb +4 -0
- data/app/views/hubstats/repos/dashboard.html.erb +0 -1
- data/app/views/hubstats/repos/show.html.erb +1 -1
- data/app/views/hubstats/tables/_comments-condensed.html.erb +1 -1
- data/app/views/hubstats/tables/_comments.html.erb +1 -1
- data/app/views/hubstats/tables/_deploys.html.erb +1 -1
- data/app/views/hubstats/tables/_grouped_deploys.html.erb +1 -1
- data/app/views/hubstats/tables/_grouped_pulls.html.erb +1 -1
- data/app/views/hubstats/tables/_pulls-condensed.html.erb +1 -1
- data/app/views/hubstats/tables/_pulls.html.erb +1 -1
- data/app/views/hubstats/tables/_repos-condensed.html.erb +1 -1
- data/app/views/hubstats/tables/_repos.html.erb +2 -2
- data/app/views/hubstats/tables/_teams.html.erb +28 -0
- data/app/views/hubstats/tables/_users-condensed.html.erb +1 -1
- data/app/views/hubstats/tables/_users.html.erb +2 -2
- data/app/views/hubstats/teams/index.html.erb +10 -0
- data/app/views/hubstats/teams/show.html.erb +28 -0
- data/app/views/hubstats/users/show.html.erb +2 -2
- data/config/routes.rb +4 -3
- data/db/migrate/20150706204910_create_hubstats_teams.rb +8 -0
- data/db/migrate/20150706205049_create_hubstats_teams_users.rb +8 -0
- data/db/migrate/20150713185013_add_team_id_to_prs.rb +5 -0
- data/hubstats.gemspec +2 -1
- data/lib/generators/hubstats/octokit.example.yml +3 -1
- data/lib/hubstats/events_handler.rb +20 -0
- data/lib/hubstats/github_api.rb +71 -15
- data/lib/hubstats/version.rb +1 -1
- data/lib/tasks/hubstats_tasks.rake +19 -0
- data/lib/tasks/populate_task.rake +35 -2
- data/spec/controllers/hubstats/repos_controller_spec.rb +1 -0
- data/spec/controllers/hubstats/teams_controller_spec.rb +39 -0
- data/spec/controllers/hubstats/users_controller_spec.rb +2 -0
- data/spec/factories/pull_requests.rb +1 -1
- data/spec/factories/teams.rb +24 -0
- data/spec/factories/users.rb +0 -1
- data/spec/lib/hubstats/events_handler_spec.rb +37 -7
- data/spec/lib/hubstats/github_api_spec.rb +55 -2
- data/spec/lib/hubstats_spec.rb +7 -1
- data/spec/models/hubstats/pull_request_spec.rb +34 -0
- data/spec/models/hubstats/team_spec.rb +23 -0
- data/spec/models/hubstats/user_spec.rb +26 -0
- data/test/dummy/config/initializers/octokit_patch.rb +3 -0
- data/test/dummy/db/schema.rb +51 -40
- metadata +62 -29
@@ -1,6 +1,6 @@
|
|
1
1
|
<div class="row single-user">
|
2
2
|
|
3
|
-
<!-- Show the avatar of the githuber user and the user's username -->
|
3
|
+
<!-- Show the avatar of the githuber user and the user's username with a link to their github page -->
|
4
4
|
<div class="user-image col-lg-1 col-md-1 col-sm-1" >
|
5
5
|
<img src= <%= user.avatar_url%> alt= <%= user.login %> >
|
6
6
|
</div>
|
@@ -8,6 +8,7 @@
|
|
8
8
|
<h4>
|
9
9
|
<%= link_to user.login, user_path(user) %>
|
10
10
|
</h4>
|
11
|
+
updated <%= distance_of_time_in_words(DateTime.now,user.updated_at) %> ago
|
11
12
|
<br>
|
12
13
|
<h4>
|
13
14
|
<a class="subtle" href=<%= user.html_url %> >
|
@@ -15,7 +15,6 @@
|
|
15
15
|
<!-- Show all of the repositories with their individual stats -->
|
16
16
|
<div class="row">
|
17
17
|
<div class="col col-lg-12">
|
18
|
-
<h3> Repositories </h3>
|
19
18
|
<%= render 'hubstats/tables/repos' %>
|
20
19
|
<div class="text-center">
|
21
20
|
<%= will_paginate @repo, renderer: BootstrapPagination::Rails %>
|
@@ -19,7 +19,7 @@
|
|
19
19
|
|
20
20
|
<!-- Show all of the merged pull requests in a "condensed" view -->
|
21
21
|
<div class="col col-lg-6">
|
22
|
-
<h3> Pull Requests</h3>
|
22
|
+
<h3> Merged Pull Requests</h3>
|
23
23
|
<%= render 'hubstats/tables/pulls-condensed'%>
|
24
24
|
<% if @pull_count > 20 %>
|
25
25
|
<p class="pull-right"><%= link_to "View All", pulls_path(:repos => @repo.id) %></p>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<a class="header desc" id="deploys"> Deployments <span class="octicon"></span> </a>
|
10
10
|
</div>
|
11
11
|
<div class="col-lg-2 col-md-2 col-sm-2">
|
12
|
-
<a class="header desc" id="pulls"> Pull Requests <span class="octicon"></span> </a>
|
12
|
+
<a class="header desc" id="pulls"> Merged Pull Requests <span class="octicon"></span> </a>
|
13
13
|
</div>
|
14
14
|
<div class="col-lg-2 col-md-2 col-sm-2">
|
15
15
|
<a class="header desc" id="comments"> Comments <span class="octicon"></span></a>
|
@@ -24,6 +24,6 @@
|
|
24
24
|
<%= render partial: 'hubstats/partials/repo', collection: @repos, as: :repo %>
|
25
25
|
</div>
|
26
26
|
<% else %>
|
27
|
-
<p> No
|
27
|
+
<p> No repository information available </p>
|
28
28
|
<% end %>
|
29
29
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<!-- Either say there are no teams to show, or show all of the stat titles along with the stats/teams -->
|
2
|
+
<% if @teams.length > 0 %>
|
3
|
+
<div class="teams">
|
4
|
+
<div class="row single-user header">
|
5
|
+
<div class="col-lg-2 col-md-2 col-sm-2">
|
6
|
+
<a class="header desc" id="name"> Team Name <span class="octicon"></span> </a>
|
7
|
+
</div>
|
8
|
+
<div class="col-lg-2 col-md-2 col-sm-2">
|
9
|
+
<a class="header desc" id="usercount"> Users <span class="octicon"></span> </a>
|
10
|
+
</div>
|
11
|
+
<div class="col-lg-2 col-md-2 col-sm-2">
|
12
|
+
<a class="header desc" id="pulls"> Merged Pull Requests <span class="octicon"></span> </a>
|
13
|
+
</div>
|
14
|
+
<div class="col-lg-2 col-md-2 col-sm-2">
|
15
|
+
<a class="header desc" id="comments"> Comments <span class="octicon"></span></a>
|
16
|
+
</div>
|
17
|
+
<div class="col-lg-2 col-md-2 col-sm-2">
|
18
|
+
<a class="header desc" id="repocount"> Repositories <span class="octicon"></span></a>
|
19
|
+
</div>
|
20
|
+
<div class="col-lg-2 col-md-2 col-sm-2">
|
21
|
+
<a class="header desc" id="netadditions"> Net Additions <span class="octicon"></span></a>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<%= render partial: 'hubstats/partials/team', collection: @teams, as: :team %>
|
25
|
+
</div>
|
26
|
+
<% else %>
|
27
|
+
<p> No team information available </p>
|
28
|
+
<% end %>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<a class="header desc" id="deploys"> Deployments <span class="octicon"></span> </a>
|
10
10
|
</div>
|
11
11
|
<div class="col-lg-2 col-md-2 col-sm-2">
|
12
|
-
<a class="header desc" id="pulls"> Pull Requests <span class="octicon"></span> </a>
|
12
|
+
<a class="header desc" id="pulls"> Merged Pull Requests <span class="octicon"></span> </a>
|
13
13
|
</div>
|
14
14
|
<div class="col-lg-2 col-md-2 col-sm-2">
|
15
15
|
<a class="header desc" id="comments"> Comments <span class="octicon"></span></a>
|
@@ -21,5 +21,5 @@
|
|
21
21
|
<%= render partial: 'hubstats/partials/user', collection: @users, as: :user %>
|
22
22
|
</div>
|
23
23
|
<% else %>
|
24
|
-
<p> No
|
24
|
+
<p> No user information available</p>
|
25
25
|
<% end %>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<div class="container" id="team">
|
2
|
+
<div class="row">
|
3
|
+
|
4
|
+
<!-- Title with the team's name -->
|
5
|
+
<h1 class="title text-center"><%= @team.name %></a> </h1>
|
6
|
+
|
7
|
+
<!-- Show all of the stats about the team -->
|
8
|
+
<%= render 'hubstats/partials/quick_stats' %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="row">
|
12
|
+
|
13
|
+
<!-- Show all of this team's merged pull requests in a "condensed" view -->
|
14
|
+
<div class="col-lg-6 col-md-5 col-sm-5 col-xs-5">
|
15
|
+
<h3> Merged Pull Requests</h3>
|
16
|
+
<%= render 'hubstats/tables/pulls-condensed' %>
|
17
|
+
<% if @pull_count > 20 %>
|
18
|
+
<p class="pull-right"><%= link_to "View All", pulls_path(:teams => @team.id) %></p>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<!-- Show all of this team's users in a "condensed" view -->
|
23
|
+
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
24
|
+
<h3> Active Users </h3>
|
25
|
+
<%= render 'hubstats/tables/users-condensed' %>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="container" id="
|
1
|
+
<div class="container" id="user">
|
2
2
|
<div class="row">
|
3
3
|
|
4
4
|
<!-- Title with the user's GitHub username -->
|
@@ -12,7 +12,7 @@
|
|
12
12
|
|
13
13
|
<!-- Show all of this user's merged pull requests in a "condensed" view -->
|
14
14
|
<div class="col-lg-6 col-md-5 col-sm-5 col-xs-5">
|
15
|
-
<h3> Pull Requests</h3>
|
15
|
+
<h3> Merged Pull Requests</h3>
|
16
16
|
<%= render 'hubstats/tables/pulls-condensed' %>
|
17
17
|
<% if @pull_count > 20 %>
|
18
18
|
<p class="pull-right"><%= link_to "View All", pulls_path(:users => @user.id) %></p>
|
data/config/routes.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# Draw all of the routes that will be used in Hubstats
|
2
2
|
Hubstats::Engine.routes.draw do
|
3
|
-
root to: "pull_requests#index" # sets default root to be the pulls page
|
4
3
|
post "/handler" => "events#handler", :as => :handler
|
5
|
-
|
6
|
-
get "/metrics" => "repos#dashboard", :as => :metrics # routes to list of repos and stats
|
4
|
+
root to: "pull_requests#index" # sets default root to be the pulls page
|
7
5
|
get "/pulls" => "pull_requests#index", :as => :pulls # routes to list of pulls
|
6
|
+
resources :deploys, :only => [:create, :index, :show] # routes to index, show, and to create method
|
7
|
+
resources :teams, :only => [:index, :show]
|
8
8
|
get "/users" => "users#index", :as => :users # routes to list of users
|
9
9
|
get "/user/:id" => "users#show", :as => :user # routes to specific user's contributions
|
10
|
+
get "/metrics" => "repos#dashboard", :as => :metrics # routes to list of repos and stats
|
10
11
|
get "/repos" => "repos#index", :as => :repos # route is for the repo filter on the pull request and deploys page
|
11
12
|
get "/:repo" => "repos#show", :as => :repo # routes to specific repo's stats
|
12
13
|
scope "/:repo", :as => :repo do
|
data/hubstats.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
18
|
|
19
19
|
s.add_dependency "rails", "~> 3.2.18"
|
20
|
-
s.add_dependency "octokit", "~>
|
20
|
+
s.add_dependency "octokit", "~> 4.0"
|
21
21
|
s.add_dependency "will_paginate-bootstrap"
|
22
22
|
s.add_dependency "select2-rails", "3.5.9"
|
23
23
|
s.add_dependency "bootstrap-datepicker-rails", "~> 1.4.0"
|
@@ -26,4 +26,5 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_development_dependency "shoulda-matchers", "~> 2.6"
|
27
27
|
s.add_development_dependency "factory_girl_rails", "~> 4.4"
|
28
28
|
s.add_development_dependency "faker", "~> 1.3"
|
29
|
+
s.add_development_dependency "test-unit", "~> 3.0"
|
29
30
|
end
|
@@ -3,9 +3,11 @@ github_auth: # Must include either access_token || (client_id && client_secret)
|
|
3
3
|
# client_id: <CLIENT ID>
|
4
4
|
# client_secret: <CLIENT SECRET>
|
5
5
|
|
6
|
-
github_config: # Must include
|
6
|
+
github_config: # Must include org_name. The repo_list, team_list, and ignore_users_list are optional.
|
7
7
|
# org_name: <ORGANIZATION NAME>
|
8
|
+
# team_list: [<ARRAY OF TEAMS>]
|
8
9
|
# repo_list: [<ARRAY OF REPOS>]
|
10
|
+
# ignore_users_list: [<ARRAY OF USERS' LOGINS TO IGNORE>]
|
9
11
|
|
10
12
|
webhook_secret: #<40 CHARACTER ACCESS TOKEN >
|
11
13
|
webhook_endpoint: #<url of webhook endpoint>
|
@@ -17,6 +17,8 @@ module Hubstats
|
|
17
17
|
pull_processor(payload)
|
18
18
|
when "pull_request_review_comment", "PullRequestReviewCommentEvent"
|
19
19
|
comment_processor(payload, "PullRequest")
|
20
|
+
when "membership", "MembershipEvent"
|
21
|
+
team_processor(payload)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -47,6 +49,24 @@ module Hubstats
|
|
47
49
|
Hubstats::Comment.create_or_update(comment.with_indifferent_access)
|
48
50
|
end
|
49
51
|
|
52
|
+
# Public - Gets the information for the new team and updates it
|
53
|
+
#
|
54
|
+
# payload - the information that we will use to get the data off of
|
55
|
+
#
|
56
|
+
# Returns - nothing, but updates or makes the team
|
57
|
+
def team_processor(payload)
|
58
|
+
team = payload[:team]
|
59
|
+
team[:action] = payload[:action]
|
60
|
+
team[:current_user] = payload[:member]
|
61
|
+
team_list = Hubstats.config.github_config["team_list"] || []
|
62
|
+
if team_list.include? team[:name]
|
63
|
+
Hubstats::Team.create_or_update(team.with_indifferent_access)
|
64
|
+
hubstats_team = Hubstats::Team.where(name: team[:name]).first
|
65
|
+
hubstats_user = Hubstats::User.create_or_update(team[:current_user])
|
66
|
+
Hubstats::Team.update_users_in_team(hubstats_team, hubstats_user, team[:action])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
50
70
|
# Public - Grabs the PR number off of any of the various places it can be
|
51
71
|
#
|
52
72
|
# payload - the thing that we will use to try to attain the PR number
|
data/lib/hubstats/github_api.rb
CHANGED
@@ -52,18 +52,22 @@ module Hubstats
|
|
52
52
|
#
|
53
53
|
# Returns - an array of github repo objects
|
54
54
|
def self.get_repos
|
55
|
-
if Hubstats.config.github_config.has_key?("org_name")
|
56
|
-
|
57
|
-
|
55
|
+
if Hubstats.config.github_config.has_key?("org_name") == false
|
56
|
+
raise RuntimeError, "COULD NOT COMPLETE RAKE TASK! Organization name in .octokit.yml is required, but was not found."
|
57
|
+
end
|
58
|
+
|
59
|
+
if Hubstats.config.github_config.has_key?("repo_list")
|
58
60
|
repos = []
|
59
61
|
Hubstats.config.github_config["repo_list"].each do |repo|
|
60
62
|
repos << client.repository(repo)
|
61
63
|
end
|
64
|
+
elsif Hubstats.config.github_config.has_key?("org_name")
|
65
|
+
repos = client.organization_repositories(Hubstats.config.github_config["org_name"])
|
62
66
|
end
|
63
67
|
repos
|
64
68
|
end
|
65
69
|
|
66
|
-
# Public - Gets extra information on pull requests, e.g size, additions ...
|
70
|
+
# Public - Gets extra information on pull requests, e.g. size, additions ...
|
67
71
|
#
|
68
72
|
# Returns - nothing
|
69
73
|
def self.update_pulls
|
@@ -71,9 +75,9 @@ module Hubstats
|
|
71
75
|
begin
|
72
76
|
while Hubstats::PullRequest.where(deletions: nil).where(additions: nil).count > 0
|
73
77
|
client = Hubstats::GithubAPI.client
|
74
|
-
|
78
|
+
pull_requests = Hubstats::PullRequest.where(deletions: nil).where(additions: nil).limit(grab_size)
|
75
79
|
|
76
|
-
|
80
|
+
pull_requests.each do |pull|
|
77
81
|
repo = Hubstats::Repo.where(id: pull.repo_id).first
|
78
82
|
pr = client.pull_request(repo.full_name, pull.number)
|
79
83
|
Hubstats::PullRequest.create_or_update(HubHelper.pull_setup(pr))
|
@@ -87,6 +91,37 @@ module Hubstats
|
|
87
91
|
end
|
88
92
|
end
|
89
93
|
|
94
|
+
# Public - Gets information on teams, e.g. name
|
95
|
+
#
|
96
|
+
# Returns - nothing
|
97
|
+
def self.update_teams
|
98
|
+
grab_size = 250
|
99
|
+
begin
|
100
|
+
client = Hubstats::GithubAPI.client
|
101
|
+
all_teams_in_org = client.organization_teams(Hubstats.config.github_config["org_name"])
|
102
|
+
team_list = Hubstats.config.github_config["team_list"] || []
|
103
|
+
|
104
|
+
all_teams_in_org.each do |team|
|
105
|
+
if team_list.include? team[:name]
|
106
|
+
puts "Making a team"
|
107
|
+
Hubstats::Team.create_or_update(team)
|
108
|
+
users = client.team_members(team[:id])
|
109
|
+
users.each do |user|
|
110
|
+
hubstats_team = Hubstats::Team.where(name: team[:name]).first
|
111
|
+
hubstats_user = Hubstats::User.create_or_update(user)
|
112
|
+
puts "Adding a user to a team"
|
113
|
+
Hubstats::Team.update_users_in_team(hubstats_team, hubstats_user, "added")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
wait_limit(grab_size,client.rate_limit)
|
118
|
+
puts "All teams are up to date"
|
119
|
+
rescue Faraday::ConnectionFailed
|
120
|
+
puts "Connection Timeout, restarting team updating"
|
121
|
+
update_teams
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
90
125
|
# Public - Makes a new webhook from a repository
|
91
126
|
#
|
92
127
|
# repo - the repository that is attempting to have a hook made with
|
@@ -103,14 +138,7 @@ module Hubstats
|
|
103
138
|
:secret => Hubstats.config.webhook_secret
|
104
139
|
},
|
105
140
|
{
|
106
|
-
:events => [
|
107
|
-
'pull_request',
|
108
|
-
'pull_request_review_comment',
|
109
|
-
'commit_comment',
|
110
|
-
'issues',
|
111
|
-
'issue_comment',
|
112
|
-
'member'
|
113
|
-
],
|
141
|
+
:events => ['pull_request', 'pull_request_review_comment', 'commit_comment', 'issues', 'issue_comment'],
|
114
142
|
:active => true
|
115
143
|
}
|
116
144
|
)
|
@@ -122,6 +150,34 @@ module Hubstats
|
|
122
150
|
end
|
123
151
|
end
|
124
152
|
|
153
|
+
# Public - Makes a new webhook from an organization
|
154
|
+
#
|
155
|
+
# org_name - the name of the organization that is attempting to have a hook made with
|
156
|
+
#
|
157
|
+
# Returns - the hook and a message (or just a message and no hook)
|
158
|
+
def self.create_org_hook(org_name)
|
159
|
+
begin
|
160
|
+
client.create_hook(
|
161
|
+
org_name,
|
162
|
+
'web',
|
163
|
+
{
|
164
|
+
:url => Hubstats.config.webhook_endpoint,
|
165
|
+
:content_type => 'json',
|
166
|
+
:secret => Hubstats.config.webhook_secret
|
167
|
+
},
|
168
|
+
{
|
169
|
+
:events => ['membership'],
|
170
|
+
:active => true
|
171
|
+
}
|
172
|
+
)
|
173
|
+
puts "Hook on #{org_name} successfully created"
|
174
|
+
rescue Octokit::UnprocessableEntity
|
175
|
+
puts "Hook on #{org_name} already existed"
|
176
|
+
rescue Octokit::NotFound
|
177
|
+
puts "You don't have sufficient privileges to add an event hook to #{org_name}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
125
181
|
# Public - Delete webhook from github repository
|
126
182
|
#
|
127
183
|
# repo - a repo github object
|
@@ -133,7 +189,7 @@ module Hubstats
|
|
133
189
|
client.hooks(repo.full_name).each do |hook|
|
134
190
|
if hook[:config][:url] == old_endpoint
|
135
191
|
Hubstats::GithubAPI.client.remove_hook(repo.full_name, hook[:id])
|
136
|
-
puts "
|
192
|
+
puts "Successfully deleted hook with id #{hook[:id]} and url #{hook[:config][:url]} from #{repo.full_name}"
|
137
193
|
end
|
138
194
|
end
|
139
195
|
rescue Octokit::NotFound
|