github_org_reports 0.0.0 → 0.0.1

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.
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source "http://rubygems.org"
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
 
6
- gem "baza", :path => "/Users/kaspernj/Dev/Ruby/baza"
6
+ gem "baza", ">= 0.0.10", :path => "/Users/kaspernj/Dev/Ruby/baza"
7
7
  gem "json"
8
8
  gem "github_api"
9
9
  gem "string-cases"
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: /Users/kaspernj/Dev/Ruby/baza
3
3
  specs:
4
- baza (0.0.8)
4
+ baza (0.0.10)
5
5
  array_enumerator
6
6
  datet
7
7
  knjrbfw
8
+ string-cases
8
9
  wref
9
10
 
10
11
  GEM
@@ -80,7 +81,7 @@ PLATFORMS
80
81
  ruby
81
82
 
82
83
  DEPENDENCIES
83
- baza!
84
+ baza (>= 0.0.10)!
84
85
  bundler (>= 1.0.0)
85
86
  github_api
86
87
  jeweler (~> 1.8.4)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.0.1
@@ -0,0 +1,84 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "github_org_reports"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["kaspernj"]
12
+ s.date = "2013-05-16"
13
+ s.description = "A gem to generate organization reports based on pull requests and commits."
14
+ s.email = "k@spernj.org"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "github_org_reports.gemspec",
29
+ "include/github_org_reports_dbschema.rb",
30
+ "include/github_org_reports_models.rb",
31
+ "include/github_org_reports_repo.rb",
32
+ "lib/github_org_reports.rb",
33
+ "models/commit.rb",
34
+ "models/commit_organization_link.rb",
35
+ "models/organization.rb",
36
+ "models/pull_request.rb",
37
+ "models/pull_request_organization_link.rb",
38
+ "models/user.rb",
39
+ "spec/github_org_reports_spec.rb",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+ s.homepage = "http://github.com/kaspernj/github_org_reports"
43
+ s.licenses = ["MIT"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = "1.8.23"
46
+ s.summary = "A gem to generate organization reports based on pull requests and commits."
47
+
48
+ if s.respond_to? :specification_version then
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
52
+ s.add_runtime_dependency(%q<baza>, [">= 0.0.10"])
53
+ s.add_runtime_dependency(%q<json>, [">= 0"])
54
+ s.add_runtime_dependency(%q<github_api>, [">= 0"])
55
+ s.add_runtime_dependency(%q<string-cases>, [">= 0"])
56
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
57
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
58
+ s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
59
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
60
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
61
+ else
62
+ s.add_dependency(%q<baza>, [">= 0.0.10"])
63
+ s.add_dependency(%q<json>, [">= 0"])
64
+ s.add_dependency(%q<github_api>, [">= 0"])
65
+ s.add_dependency(%q<string-cases>, [">= 0"])
66
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
67
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
68
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
70
+ s.add_dependency(%q<sqlite3>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<baza>, [">= 0.0.10"])
74
+ s.add_dependency(%q<json>, [">= 0"])
75
+ s.add_dependency(%q<github_api>, [">= 0"])
76
+ s.add_dependency(%q<string-cases>, [">= 0"])
77
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
78
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
79
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
80
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
81
+ s.add_dependency(%q<sqlite3>, [">= 0"])
82
+ end
83
+ end
84
+
@@ -4,6 +4,8 @@ class GithubOrgReports::Dbschema
4
4
  :Commit => {
5
5
  :columns => [
6
6
  {:name => :id, :type => :int, :autoincr => true, :primarykey => true},
7
+ {:name => :repository_name, :type => :varchar},
8
+ {:name => :repository_user, :type => :varchar},
7
9
  {:name => :user_id, :type => :int},
8
10
  {:name => :pull_request_id, :type => :int},
9
11
  {:name => :sha, :type => :varchar},
@@ -12,6 +14,8 @@ class GithubOrgReports::Dbschema
12
14
  {:name => :time, :type => :int}
13
15
  ],
14
16
  :indexes => [
17
+ :repository_name,
18
+ :repository_user,
15
19
  :user_id
16
20
  ]
17
21
  },
@@ -43,15 +47,23 @@ class GithubOrgReports::Dbschema
43
47
  :PullRequest => {
44
48
  :columns => [
45
49
  {:name => :id, :type => :int, :autoincr => true, :primarykey => true},
50
+ {:name => :repository_name, :type => :varchar},
51
+ {:name => :repository_user, :type => :varchar},
46
52
  {:name => :github_id, :type => :int, :renames => [:pull_request_id]},
53
+ {:name => :number, :type => :int},
47
54
  {:name => :user_id, :type => :int},
55
+ {:name => :date, :type => :datetime},
56
+ {:name => :title, :type => :varchar},
48
57
  {:name => :text, :type => :text},
49
58
  {:name => :html, :type => :text},
50
59
  {:name => :time, :type => :int}
51
60
  ],
52
61
  :indexes => [
62
+ :repository_name,
63
+ :repository_user,
53
64
  :github_id,
54
- :user_id
65
+ :user_id,
66
+ :number
55
67
  ]
56
68
  },
57
69
  :PullRequestOrganizationLink => {
@@ -4,4 +4,12 @@ class GithubOrgReports::Repo
4
4
  def initialize(args)
5
5
  @args = args
6
6
  end
7
+
8
+ def name
9
+ return @args[:name]
10
+ end
11
+
12
+ def user
13
+ return @args[:user]
14
+ end
7
15
  end
@@ -11,6 +11,18 @@ class GithubOrgReports
11
11
  return GithubOrgReports.const_get(name)
12
12
  end
13
13
 
14
+ def self.secs_to_time(secs)
15
+ return "0:00" if secs <= 0
16
+
17
+ hours = (secs / 3600).floor
18
+ secs -= hours * 3600
19
+
20
+ mins = (secs / 60).floor
21
+ secs -= mins * 60
22
+
23
+ return "#{hours}:#{sprintf("%02d", mins)}"
24
+ end
25
+
14
26
  def initialize(args = {})
15
27
  @args = args
16
28
  @repos = []
@@ -34,49 +46,93 @@ class GithubOrgReports
34
46
  @repos << repo
35
47
  end
36
48
 
37
- def scan_hash(str)
49
+ def self.scan_hash(str)
38
50
  str.to_s.scan(/!(\{(.+?)\})!/) do |match|
51
+ json_str = match[0]
52
+
53
+
54
+ #Fix missing quotes in 'time' and 'orgs' to make it easier to write.
55
+ json_str.gsub!(/time:\s*([\d+:]+)/, "\"time\": \"\\1\"")
56
+
57
+ if orgs_match = json_str.match(/orgs:\s*\[(.+?)\]/)
58
+ orgs_str = orgs_match[1]
59
+ orgs_str.gsub!(/\s*(^|\s*,\s*)([A-z_\d]+)/, "\\1\"\\2\"")
60
+ json_str.gsub!(orgs_match[0], "\"orgs\": [#{orgs_str}]")
61
+ end
62
+
63
+
64
+ #Parse the JSON and yield it.
39
65
  begin
40
- yield JSON.parse(match[1])
66
+ yield JSON.parse(json_str)
41
67
  rescue JSON::ParserError => e
42
68
  $stderr.puts e.inspect
43
- $stderr.puts e.backtrace
69
+ #$stderr.puts e.backtrace
44
70
  end
45
71
  end
46
72
  end
47
73
 
48
74
  def scan
49
75
  @repos.each do |repo|
50
- gh_args = {}
51
- gh_args[:login] = repo.args[:login] if repo.args[:login]
52
- gh_args[:password] = repo.args[:password] if repo.args[:password]
76
+ @cur_repo = repo
77
+
78
+ gh_args = {
79
+ :user => repo.user,
80
+ :repo => repo.name
81
+ }
82
+ gh_args[:login] = repo.args[:login] unless repo.args[:login].to_s.strip.empty?
83
+ gh_args[:password] = repo.args[:password] unless repo.args[:password].to_s.strip.empty?
53
84
 
54
85
  gh = ::Github.new(gh_args)
55
86
 
56
- commits = gh.repos.commits.all(repo.args[:user], repo.args[:name])
87
+ commits = gh.repos.commits.all(gh_args)
57
88
  commits.each do |commit_data|
58
89
  commit = init_commit_from_data(commit_data)
59
90
  end
60
91
 
61
- prs = gh.pull_requests.list(repo.args[:user], repo.args[:name])
92
+ prs = []
93
+ gh.pull_requests.list(gh_args.merge(:state => "closed")).each do |pr|
94
+ prs << pr
95
+ end
96
+
97
+ gh.pull_requests.list(gh_args.merge(:state => "open")).each do |pr|
98
+ prs << pr
99
+ end
100
+
62
101
  prs.each do |pr_data|
63
102
  text = pr_data.body_text
64
103
 
104
+ name = pr_data.user.login
105
+ raise "Invalid name: '#{name}' (#{pr_data.to_hash})." if !name.is_a?(String)
65
106
  user = @ob.get_or_add(:User, {
66
- :name => pr_data.user
107
+ :name => name
67
108
  })
68
109
 
110
+
111
+ #puts "PullRequest: #{pr_data.to_hash}"
112
+ github_id = pr_data.id.to_i
113
+ raise "Invalid github-ID: '#{github_id}'." if github_id <= 0
114
+
115
+ number = pr_data.number.to_i
116
+ raise "Invalid number: '#{number}'." if number <= 0
117
+
69
118
  pr = @ob.get_or_add(:PullRequest, {
70
- :github_id => pr_data.id
119
+ :repository_user => @cur_repo.user,
120
+ :repository_name => @cur_repo.name,
121
+ :github_id => github_id,
122
+ :number => number
71
123
  })
72
124
 
125
+ #puts "PullRequest: #{pr_data.to_hash}"
126
+
73
127
  pr[:user_id] = user.id
128
+ pr[:title] = pr_data.title
74
129
  pr[:text] = pr_data.body_text
75
130
  pr[:html] = pr_data.body_html
131
+ pr[:date] = Time.parse(pr_data.created_at)
76
132
 
77
133
  pr.scan
78
134
 
79
- commits = gh.pull_requests.commits(:repo => repo.args[:name], :user => repo.args[:user], :number => pr_data.number)
135
+ commits = gh.pull_requests.commits(gh_args.merge(:number => pr_data.number))
80
136
  commits.each do |commit_data|
81
137
  commit = init_commit_from_data(commit_data)
82
138
  commit[:pull_request_id] = pr.id
@@ -88,34 +144,31 @@ class GithubOrgReports
88
144
  def scan_for_time_and_orgs(str)
89
145
  res = {:secs => 0, :orgs => [], :orgs_time => {}}
90
146
 
91
- self.scan_hash(str) do |hash|
147
+ GithubOrgReports.scan_hash(str) do |hash|
92
148
  #Parse time.
93
149
  if hash["time"] and match_time = hash["time"].to_s.match(/^(\d{1,2}):(\d{1,2})$/)
94
150
  secs = 0
95
151
  secs += match_time[1].to_i * 3600
96
152
  secs += match_time[2].to_i * 60
97
153
 
98
- res[:secs] += secs
99
-
100
154
  #Parse organizations.
101
155
  if orgs = hash["orgs"]
102
- orgs = [orgs] if !orgs.is_a?(Hash)
156
+ orgs = [orgs] if !orgs.is_a?(Array)
103
157
  orgs.each do |org_name_short|
104
158
  org_name_short_dc = org_name_short.to_s.downcase
105
159
  next if org_name_short_dc.strip.empty?
106
160
 
107
- org = self.ob.get_or_add(:Organization, {:name_short => org_name_short_dc})
161
+ raise "Invalid short-name: '#{org_name_short_dc}'." unless org_name_short_dc.match(/^[A-z\d+_]+$/)
108
162
 
109
- link = self.ob.get_or_add(:PullRequestOrganizationLink, {
110
- :organization_id => org.id,
111
- :pull_request_id => self.id
112
- })
163
+ org = self.ob.get_or_add(:Organization, {:name_short => org_name_short_dc})
113
164
 
114
165
  res[:orgs] << org unless res[:orgs].include?(org)
115
166
 
116
- res[:orgs_time][org.id] = {:secs => 0} unless res[:orgs].key?(org.id)
117
- res[:orgs_time][org.id][:secs] += match_time
167
+ res[:orgs_time][org.id] = {:secs => 0} unless res[:orgs_time].key?(org.id)
168
+ res[:orgs_time][org.id][:secs] += secs
118
169
  end
170
+ else
171
+ res[:secs] += secs
119
172
  end
120
173
  end
121
174
  end
@@ -126,11 +179,25 @@ class GithubOrgReports
126
179
  private
127
180
 
128
181
  def init_commit_from_data(commit_data)
182
+ sha = commit_data.sha
183
+ raise "Invalid SHA: '#{sha}' (#{commit_data.to_hash})." if sha.to_s.strip.empty?
184
+
129
185
  commit = @ob.get_or_add(:Commit, {
130
- :sha => commit_data.sha
186
+ :repository_user => @cur_repo.user,
187
+ :repository_name => @cur_repo.name,
188
+ :sha => sha
131
189
  })
132
- commit[:text] = commit_data.commit
133
- commit[:date] = commit_data.commit.date
190
+ raise "Commit didnt get added right '#{commit[:sha]}', '#{sha}'." if sha != commit[:sha]
191
+
192
+ text = commit_data.commit.message
193
+ raise "Invalid text: '#{text}' (#{commit_data.to_hash})." if !text.is_a?(String)
194
+ commit[:text] = text
195
+
196
+
197
+ date = Time.parse(commit_data.commit.committer.date)
198
+ raise "Invalid date: '#{date}' (#{commit_data.commit.to_hash})" if !date
199
+
200
+ commit[:date] = date
134
201
 
135
202
  if commit_data.author
136
203
  user = @ob.get_or_add(:User, {
@@ -1,6 +1,9 @@
1
1
  class GithubOrgReports::Models::Commit < Baza::Model
2
2
  has_one :User
3
3
  has_one :PullRequest
4
+ has_many [
5
+ [:CommitOrganizationLink, :commit_id]
6
+ ]
4
7
 
5
8
  def scan
6
9
  hash = ob.data[:github_org_reports].scan_for_time_and_orgs(self[:text])
@@ -10,9 +13,10 @@ class GithubOrgReports::Models::Commit < Baza::Model
10
13
  hash[:orgs].each do |org|
11
14
  link = self.ob.get_or_add(:CommitOrganizationLink, {
12
15
  :organization_id => org.id,
13
- :pull_request_id => self.id,
14
- :time => hash[:orgs_time][org.id]
16
+ :commit_id => self.id
15
17
  })
18
+
19
+ link[:time] = hash[:orgs_time][org.id][:secs]
16
20
  end
17
21
 
18
22
 
@@ -1,3 +1,9 @@
1
1
  class GithubOrgReports::Models::Organization < Baza::Model
2
-
2
+ def name
3
+ name_str = self[:name].to_s.strip
4
+ name_str = self[:name_short].to_s.strip if name_str.empty?
5
+ name_str = "[no name]" if name_str.empty?
6
+
7
+ return name_str
8
+ end
3
9
  end
@@ -1,5 +1,8 @@
1
1
  class GithubOrgReports::Models::PullRequest < Baza::Model
2
- has_many [[:PullRequestOrganizationLink, :pull_request_id]]
2
+ has_many [
3
+ [:PullRequestOrganizationLink, :pull_request_id],
4
+ [:Commit, :pull_request_id]
5
+ ]
3
6
 
4
7
  def scan
5
8
  hash = ob.data[:github_org_reports].scan_for_time_and_orgs(self[:text])
@@ -10,8 +13,9 @@ class GithubOrgReports::Models::PullRequest < Baza::Model
10
13
  link = self.ob.get_or_add(:PullRequestOrganizationLink, {
11
14
  :organization_id => org.id,
12
15
  :pull_request_id => self.id,
13
- :time => hash[:orgs_time][:secs]
14
16
  })
17
+
18
+ link[:time] = hash[:orgs_time][org.id][:secs]
15
19
  end
16
20
 
17
21
 
@@ -22,9 +26,46 @@ class GithubOrgReports::Models::PullRequest < Baza::Model
22
26
  return nil
23
27
  end
24
28
 
25
- def total_time_for_orgs(args)
26
- orgs = {}
29
+ def total_time_for_org(args)
30
+ org = args[:org]
31
+ raise "No ':org' was given." if !org
27
32
 
28
33
 
34
+ #Collect shared time.
35
+ secs = self[:time].to_i
36
+
37
+
38
+ #Collect time for the pull-request-organization-links.
39
+ self.pull_request_organization_links(:organization_id => org.id) do |prol|
40
+ secs += prol[:time].to_i
41
+ end
42
+
43
+
44
+ #Collect time from commits.
45
+ self.commits do |commit|
46
+ secs += commit[:time].to_i
47
+
48
+ commit.commit_organization_links(:organization_id => org.id) do |col|
49
+ secs += col[:time].to_i
50
+ end
51
+ end
52
+
53
+
54
+ return secs
55
+ end
56
+
57
+ def title(args = nil)
58
+ title_str = self[:title].to_s.strip
59
+ title_str = self[:text].to_s.lines.first.to_s.strip if title_str.empty?
60
+ mlength = (args && args[:maxlength]) ? args[:maxlength] : 15
61
+
62
+ if title_str.length > mlength
63
+ title_str = title_str.slice(0, mlength).strip
64
+ title_str << "..."
65
+ end
66
+
67
+ title_str = "[no title]" if title_str.empty?
68
+
69
+ return title_str
29
70
  end
30
71
  end
@@ -22,4 +22,35 @@ describe "GithubOrgReports" do
22
22
  raise e
23
23
  end
24
24
  end
25
+
26
+ it "should be able to parse special json strings" do
27
+ str = "!{time: 00:30, orgs: [knjit, gfish]}!\n"
28
+ str << "!{time: 00:15, orgs: [knjit]}!"
29
+
30
+ db_path = "#{Dir.tmpdir}/github_org_reports.sqlite3"
31
+ db = Baza::Db.new(:type => :sqlite3, :path => db_path, :index_append_table_name => true)
32
+
33
+ login_info = JSON.parse(File.read("#{File.dirname(__FILE__)}/spec_info.txt").to_s.strip)
34
+
35
+ begin
36
+ gor = GithubOrgReports.new(:db => db)
37
+
38
+ res = gor.scan_for_time_and_orgs(str)
39
+
40
+ org_knjit = gor.ob.get_by(:Organization, :name_short => "knjit")
41
+ org_gfish = gor.ob.get_by(:Organization, :name_short => "gfish")
42
+
43
+ res[:orgs_time][org_knjit.id][:secs].should eql(2700)
44
+ res[:orgs_time][org_gfish.id][:secs].should eql(1800)
45
+ rescue => e
46
+ puts e.inspect
47
+ puts e.backtrace
48
+ raise e
49
+ end
50
+ end
51
+
52
+ it "should be able to convert seconds to time strings" do
53
+ GithubOrgReports.secs_to_time(1800).should eql("0:30")
54
+ GithubOrgReports.secs_to_time(2700).should eql("0:45")
55
+ end
25
56
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: github_org_reports
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.0
5
+ version: 0.0.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - kaspernj
@@ -17,7 +17,7 @@ dependencies:
17
17
  requirements:
18
18
  - - ! '>='
19
19
  - !ruby/object:Gem::Version
20
- version: '0'
20
+ version: 0.0.10
21
21
  name: baza
22
22
  type: :runtime
23
23
  prerelease: false
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
- version: '0'
29
+ version: 0.0.10
30
30
  - !ruby/object:Gem::Dependency
31
31
  version_requirements: !ruby/object:Gem::Requirement
32
32
  none: false
@@ -171,6 +171,7 @@ files:
171
171
  - README.rdoc
172
172
  - Rakefile
173
173
  - VERSION
174
+ - github_org_reports.gemspec
174
175
  - include/github_org_reports_dbschema.rb
175
176
  - include/github_org_reports_models.rb
176
177
  - include/github_org_reports_repo.rb
@@ -197,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
197
198
  - !ruby/object:Gem::Version
198
199
  segments:
199
200
  - 0
200
- hash: 2843595140910669046
201
+ hash: 241850806835355267
201
202
  version: '0'
202
203
  required_rubygems_version: !ruby/object:Gem::Requirement
203
204
  none: false