hubstats 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 +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
|