ghtorrent 0.3.1 → 0.4

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.
@@ -1,31 +1,3 @@
1
- # Copyright 2012 Georgios Gousios <gousiosg@gmail.com>
2
- #
3
- # Redistribution and use in source and binary forms, with or
4
- # without modification, are permitted provided that the following
5
- # conditions are met:
6
- #
7
- # 1. Redistributions of source code must retain the above
8
- # copyright notice, this list of conditions and the following
9
- # disclaimer.
10
- #
11
- # 2. Redistributions in binary form must reproduce the above
12
- # copyright notice, this list of conditions and the following
13
- # disclaimer in the documentation and/or other materials
14
- # provided with the distribution.
15
- #
16
- # THIS SOFTWARE IS PROVIDED BY BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
- # AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
- # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20
- # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
- # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
- # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
- # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
- # POSSIBILITY OF SUCH DAMAGE.
28
-
29
1
  require 'net/http'
30
2
  require 'set'
31
3
  require 'open-uri'
@@ -132,6 +104,7 @@ module GHTorrent
132
104
  STDERR.puts "#{url}: #{e.io.status[1]}"
133
105
  return nil
134
106
  else # Server error or HTTP conditions that Github does not report
107
+ STDERR.puts "#{url}"
135
108
  raise e
136
109
  end
137
110
  end
@@ -1,31 +1,3 @@
1
- # Copyright 2012 Georgios Gousios <gousiosg@gmail.com>
2
- #
3
- # Redistribution and use in source and binary forms, with or
4
- # without modification, are permitted provided that the following
5
- # conditions are met:
6
- #
7
- # 1. Redistributions of source code must retain the above
8
- # copyright notice, this list of conditions and the following
9
- # disclaimer.
10
- #
11
- # 2. Redistributions in binary form must reproduce the above
12
- # copyright notice, this list of conditions and the following
13
- # disclaimer in the documentation and/or other materials
14
- # provided with the distribution.
15
- #
16
- # THIS SOFTWARE IS PROVIDED BY BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
- # AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
- # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20
- # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
- # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
- # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
- # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
- # POSSIBILITY OF SUCH DAMAGE.
28
-
29
1
  module GHTorrent
30
2
  class CallStack
31
3
 
@@ -1,31 +1,3 @@
1
- # Copyright 2012 Georgios Gousios <gousiosg@gmail.com>
2
- #
3
- # Redistribution and use in source and binary forms, with or
4
- # without modification, are permitted provided that the following
5
- # conditions are met:
6
- #
7
- # 1. Redistributions of source code must retain the above
8
- # copyright notice, this list of conditions and the following
9
- # disclaimer.
10
- #
11
- # 2. Redistributions in binary form must reproduce the above
12
- # copyright notice, this list of conditions and the following
13
- # disclaimer in the documentation and/or other materials
14
- # provided with the distribution.
15
- #
16
- # THIS SOFTWARE IS PROVIDED BY BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
- # AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
- # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20
- # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
- # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
- # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
- # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
- # POSSIBILITY OF SUCH DAMAGE.
28
-
29
1
  require 'rubygems'
30
2
  require 'trollop'
31
3
  require 'daemons'
@@ -1,31 +1,3 @@
1
- # Copyright 2012 Georgios Gousios <gousiosg@gmail.com>
2
- #
3
- # Redistribution and use in source and binary forms, with or
4
- # without modification, are permitted provided that the following
5
- # conditions are met:
6
- #
7
- # 1. Redistributions of source code must retain the above
8
- # copyright notice, this list of conditions and the following
9
- # disclaimer.
10
- #
11
- # 2. Redistributions in binary form must reproduce the above
12
- # copyright notice, this list of conditions and the following
13
- # disclaimer in the documentation and/or other materials
14
- # provided with the distribution.
15
- #
16
- # THIS SOFTWARE IS PROVIDED BY BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
- # AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18
- # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20
- # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
- # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
- # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
- # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
- # POSSIBILITY OF SUCH DAMAGE.
28
-
29
1
  require 'sequel'
30
2
 
31
3
  module GHTorrent
@@ -65,12 +37,7 @@ module GHTorrent
65
37
  ##
66
38
  # Ensure that a user exists, or fetch its latest state from Github
67
39
  # ==Parameters:
68
- # user::
69
- # The email or login name to lookup the user by
70
- #
71
- # == Returns:
72
- # If the user can be retrieved, it is returned as a Hash. Otherwise,
73
- # the result is nil
40
+ # [user] The email or login name to lookup the user by
74
41
  def get_commit(user, repo, sha)
75
42
 
76
43
  unless sha.match(/[a-f0-9]{40}$/)
@@ -84,14 +51,71 @@ module GHTorrent
84
51
  end
85
52
  end
86
53
 
54
+ ##
55
+ # Add a user as member to a project
56
+ # ==Parameters:
57
+ # [owner] The login of the repository owner
58
+ # [repo] The name of the repository
59
+ # [new_member] The login of the member to add
60
+ # [date_added] The timestamp that the add event took place
61
+ def get_project_member(owner, repo, new_member, date_added)
62
+ transaction do
63
+ ensure_repo(owner, repo)
64
+ ensure_project_member(owner, repo, new_member, date_added)
65
+ end
66
+ end
67
+
68
+ ##
69
+ # Add a commit comment to a commit
70
+ # ==Parameters:
71
+ # [user] The login of the repository owner
72
+ # [repo] The name of the repository
73
+ # [comment_id] The login of the member to add
74
+ # [date_added] The timestamp that the add event took place
75
+ def get_commit_comment(user, repo, comment_id, date_added)
76
+ transaction do
77
+ ensure_repo(user, repo)
78
+ ensure_commit_comment(user, repo, comment_id, date_added)
79
+ end
80
+ end
81
+
82
+ ##
83
+ # Add a watcher to a repository
84
+ # ==Parameters:
85
+ # [owner] The login of the repository owner
86
+ # [repo] The name of the repository
87
+ # [watcher] The login of the member to add
88
+ # [date_added] The timestamp that the add event took place
89
+ def get_watcher(owner, repo, watcher, date_added)
90
+ transaction do
91
+ ensure_repo(owner, repo)
92
+ ensure_watcher(owner, repo, watcher, date_added)
93
+ end
94
+ end
95
+
96
+ ##
97
+ # Add a follower to user
98
+ # ==Parameters:
99
+ # [follower] The login of the repository owner
100
+ # [followed] The name of the repository
101
+ # [date_added] The timestamp that the add event took place
102
+ def get_follower(follower, followed, date_added)
103
+ transaction do
104
+ ensure_user(follower, false, false)
105
+ ensure_user(followed, false, false)
106
+ ensure_user_followers(followed, date_added)
107
+ end
108
+ end
109
+
87
110
  ##
88
111
  # Make sure a commit exists
89
- def ensure_commit(repo, sha, user)
112
+ #
113
+ def ensure_commit(repo, sha, user, comments = true)
90
114
  c = retrieve_commit(repo, sha, user)
91
- store_commit(c, repo, user)
92
- ensure_commit_comments(user, repo, sha)
115
+ stored = store_commit(c, repo, user)
93
116
  ensure_parents(c)
94
- c
117
+ ensure_commit_comments(user, repo, sha) if comments
118
+ stored
95
119
  end
96
120
 
97
121
  ##
@@ -235,6 +259,7 @@ module GHTorrent
235
259
  return u
236
260
  end
237
261
 
262
+
238
263
  ##
239
264
  # Ensure that a user exists, or fetch its latest state from Github
240
265
  # ==Parameters:
@@ -258,19 +283,49 @@ module GHTorrent
258
283
  end
259
284
  end
260
285
 
261
- users.insert(:login => u['login'],
262
- :name => u['name'],
263
- :company => u['company'],
264
- :email => email,
265
- :hireable => boolean(u['hirable']),
266
- :bio => u['bio'],
267
- :location => u['location'],
268
- :type => user_type(u['type']),
269
- :created_at => date(u['created_at']),
270
- :ext_ref_id => u[@ext_uniq])
271
-
272
- info "GHTorrent: New user #{user}"
286
+ if not email.nil?
287
+ # Check whether a user has been added by email before
288
+ byemail = users.first(:email => email)
289
+ unless byemail.nil?
290
+ users.filter(:email => email).update(:login => u['login'],
291
+ :name => u['name'],
292
+ :company => u['company'],
293
+ :hireable => boolean(u['hirable']),
294
+ :bio => u['bio'],
295
+ :location => u['location'],
296
+ :type => user_type(u['type']),
297
+ :created_at => date(u['created_at']),
298
+ :ext_ref_id => u[@ext_uniq]
299
+ )
300
+ info "GHTorrent: Updating user #{user} (email #{email})"
301
+ else
302
+ users.insert(:login => u['login'],
303
+ :name => u['name'],
304
+ :company => u['company'],
305
+ :email => email,
306
+ :hireable => boolean(u['hirable']),
307
+ :bio => u['bio'],
308
+ :location => u['location'],
309
+ :type => user_type(u['type']),
310
+ :created_at => date(u['created_at']),
311
+ :ext_ref_id => u[@ext_uniq])
312
+
313
+ info "GHTorrent: New user #{user}"
314
+ end
315
+ else
316
+ users.insert(:login => u['login'],
317
+ :name => u['name'],
318
+ :company => u['company'],
319
+ :email => email,
320
+ :hireable => boolean(u['hirable']),
321
+ :bio => u['bio'],
322
+ :location => u['location'],
323
+ :type => user_type(u['type']),
324
+ :created_at => date(u['created_at']),
325
+ :ext_ref_id => u[@ext_uniq])
273
326
 
327
+ info "GHTorrent: New user #{user}"
328
+ end
274
329
  users.first(:login => user)
275
330
  else
276
331
  debug "GHTorrent: User #{user} exists"
@@ -285,34 +340,42 @@ module GHTorrent
285
340
  #
286
341
  # ==Parameters:
287
342
  # [user] The user login to find followers by
288
- def ensure_user_followers(user, ts = Time.now)
343
+ def ensure_user_followers(user, date_added = nil)
344
+ followers = @db[:followers]
345
+ userid = @db[:users].first(:login => user)[:id]
289
346
 
290
- followers = retrieve_user_followers(user)
291
- followers.each { |f|
347
+ retrieved = retrieve_user_followers(user)
348
+ retrieved.each { |f|
292
349
  follower = f['login']
293
350
  ensure_user(user, false, false)
294
351
  ensure_user(follower, false, false)
295
352
 
296
- userid = @db[:users].select(:id).first(:login => user)[:id]
297
- followerid = @db[:users].select(:id).first(:login => follower)[:id]
298
- followers = @db[:followers]
353
+ followerid = @db[:users].first(:login => follower)[:id]
354
+
299
355
 
300
356
  if followers.first(:user_id => userid, :follower_id => followerid).nil?
301
- @db[:followers].insert(:user_id => userid,
302
- :follower_id => followerid,
303
- :created_at => ts,
304
- :ext_ref_id => f[@ext_uniq]
357
+ added = if date_added.nil? then Time.now else date_added end
358
+ followers.insert(:user_id => userid,
359
+ :follower_id => followerid,
360
+ :created_at => added,
361
+ :ext_ref_id => f[@ext_uniq]
305
362
  )
306
363
  info "GHTorrent: User #{follower} follows #{user}"
307
364
  else
308
- info "User #{follower} already follows #{user}"
365
+ unless date_added.nil?
366
+ followers.filter(:user_id => userid,
367
+ :follower_id => followerid).\
368
+ update(:created_at => date(date_added))
369
+ info "GHTorrent: Updated follower #{follower} -> #{user}"
370
+ end
371
+ debug "GHTorrent: User #{follower} already follows #{user}"
309
372
  end
310
373
  }
311
374
  end
312
375
 
313
376
  ##
314
377
  # Try to retrieve a user by email. Search the DB first, fall back to
315
- # Github API v2 if unsuccessful.
378
+ # Github search API if unsuccessful.
316
379
  #
317
380
  # ==Parameters:
318
381
  # [email] The email to lookup the user by
@@ -330,7 +393,7 @@ module GHTorrent
330
393
  u = retrieve_user_byemail(email, name)
331
394
 
332
395
  if u.nil? or u['user'].nil? or u['user']['login'].nil?
333
- debug "GHTorrent: Cannot find #{email} through API v2 query"
396
+ debug "GHTorrent: Cannot find #{email} through search API query"
334
397
  users.insert(:email => email,
335
398
  :name => name,
336
399
  :login => (0...8).map { 65.+(rand(25)).chr }.join,
@@ -348,7 +411,7 @@ module GHTorrent
348
411
  :location => u['user']['location'],
349
412
  :created_at => date(u['user']['created_at']),
350
413
  :ext_ref_id => u[@ext_uniq])
351
- debug "GHTorrent: Found #{email} through API v2 query"
414
+ debug "GHTorrent: Found #{email} through search API query"
352
415
  users.first(:email => email)
353
416
  end
354
417
  else
@@ -371,7 +434,8 @@ module GHTorrent
371
434
 
372
435
  ensure_user(user, true, true)
373
436
  repos = @db[:projects]
374
- currepo = repos.first(:name => repo)
437
+ curuser = @db[:users].first(:login => user)
438
+ currepo = repos.first(:owner_id => curuser[:id], :name => repo)
375
439
 
376
440
  if currepo.nil?
377
441
  r = retrieve_repo(user, repo)
@@ -385,13 +449,63 @@ module GHTorrent
385
449
 
386
450
  info "GHTorrent: New repo #{repo}"
387
451
  ensure_commits(user, repo)
388
- repos.first(:name => repo)
452
+ ensure_project_members(user, repo)
453
+ ensure_watchers(user, repo)
454
+ repos.first(:owner_id => curuser[:id], :name => repo)
389
455
  else
390
456
  debug "GHTorrent: Repo #{repo} exists"
391
457
  currepo
392
458
  end
393
459
  end
394
460
 
461
+ ##
462
+ # Make sure that a project has all the registered members defined
463
+ def ensure_project_members(user, repo)
464
+ curuser = @db[:users].first(:login => user)
465
+ currepo = @db[:projects].first(:owner_id => curuser[:id], :name => repo)
466
+ project_members = @db[:project_members].filter(:user_id => curuser[:id],
467
+ :repo_id => currepo[:id])
468
+
469
+ retrieve_repo_collaborators(user, repo).reduce([]) do |acc, x|
470
+ if project_members.find { |y| y[:login] == x['login'] }.nil?
471
+ acc << x
472
+ else
473
+ acc
474
+ end
475
+ end.map { |x| ensure_project_member(user, repo, x['login'], nil) }
476
+ end
477
+
478
+ ##
479
+ # Make sure that a project member exists in a project
480
+ def ensure_project_member(owner, repo, new_member, date_added)
481
+ pr_members = @db[:project_members]
482
+ new_user = ensure_user(new_member, false, false)
483
+ owner_id = @db[:users].first(:login => owner)[:id]
484
+ project = @db[:projects].first(:owner_id => owner_id, :name => repo)
485
+
486
+ memb_exist = pr_members.first(:user_id => new_user[:id],
487
+ :repo_id => project[:id])
488
+
489
+ if memb_exist.nil?
490
+ added = if date_added.nil? then Time.now else date_added end
491
+ retrieved = retrieve_repo_collaborator(owner, repo, new_member)
492
+ pr_members.insert(
493
+ :user_id => new_user[:id],
494
+ :repo_id => project[:id],
495
+ :created_at => date(added),
496
+ :ext_ref_id => retrieved[@ext_uniq]
497
+ )
498
+ info "GHTorrent: Added project member #{repo} -> #{new_member}"
499
+ else
500
+ unless date_added.nil?
501
+ pr_members.filter(:user_id => new_user[:id],
502
+ :repo_id => project[:id])\
503
+ .update(:created_at => date(date_added))
504
+ info "GHTorrent: Updating #{repo} -> #{new_member}"
505
+ end
506
+ end
507
+ end
508
+
395
509
  ##
396
510
  # Make sure that the organizations the user participates into exist
397
511
  #
@@ -404,7 +518,7 @@ module GHTorrent
404
518
  end
405
519
 
406
520
  ##
407
- # Make sure that a user belongs to the provided organization
521
+ # Make sure that a user participates to the provided organization
408
522
  #
409
523
  # ==Parameters:
410
524
  # [user] The login name of the user to check the organizations for
@@ -434,7 +548,7 @@ module GHTorrent
434
548
  # Make sure that an organization exists
435
549
  #
436
550
  # ==Parameters:
437
- # [org] The login name of the organization
551
+ # [organization] The login name of the organization
438
552
  #
439
553
  def ensure_org(organization)
440
554
  org = @db[:users].find(:login => organization, :type => 'org')
@@ -447,39 +561,28 @@ module GHTorrent
447
561
  end
448
562
  end
449
563
 
450
-
451
564
  ##
452
565
  # Get all comments for a commit
453
566
  #
454
567
  # ==Parameters:
455
568
  # [user] The login name of the organization
569
+ # [user] The repository containing the commit whose comments will be retrieved
570
+ # [sha] The commit sha to retrieve comments for
456
571
  def ensure_commit_comments(user, repo, sha)
457
- commit_id = @db[:commits].first(:sha => sha)
458
- stored_comments = @db[:commit_comments].find(:commit_id => commit_id)
459
- commit_commets = retrieve_commit_comments(user, repo, sha)
460
- user_id = @db[:users].first(:login => user)[:id]
572
+ commit_id = @db[:commits].first(:sha => sha)[:id]
573
+ stored_comments = @db[:commit_comments].filter(:commit_id => commit_id)
574
+ commit_comments = retrieve_commit_comments(user, repo, sha)
575
+ #user_id = @db[:users].first(:login => user)[:id]
461
576
 
462
- not_saved = commit_commets.reduce([]) do |acc, x|
463
- if stored_comments.find{|y| y[:comment_id] == x['comment_id']}.nil?
577
+ not_saved = commit_comments.reduce([]) do |acc, x|
578
+ if stored_comments.find{|y| y[:comment_id] == x['id']}.nil?
464
579
  acc << x
465
580
  else
466
581
  acc
467
582
  end
468
583
  end
469
584
 
470
- not_saved.each do |c|
471
- @db[:commit_comments].insert(
472
- :commit_id => commit_id,
473
- :user_id => user_id,
474
- :body => c['body'],
475
- :line => c['line'],
476
- :position => c['position'],
477
- :comment_id => c['id'],
478
- :ext_ref_id => c['ext_ref_id'],
479
- :created_at => date(c['created_at'])
480
- )
481
- info "GHTorrent: Added commit comment #{sha} -> #{user}"
482
- end
585
+ not_saved.map{|x| ensure_commit_comment(user, repo, x['id'], nil)}
483
586
  end
484
587
 
485
588
  ##
@@ -487,12 +590,21 @@ module GHTorrent
487
590
  #
488
591
  # ==Parameters:
489
592
  # [user] The login name of the organization
490
- def ensure_commit_comment(user, repo, id)
593
+ # [repo] The repository containing the commit whose comment will be retrieved
594
+ # [id] The comment id to retrieve
595
+ # [created_at] The timestamp that the comment was made.
596
+ def ensure_commit_comment(user, repo, id, created_at)
491
597
  stored_comment = @db[:commit_comments].first(:comment_id => id)
492
598
 
493
599
  if stored_comment.nil?
494
600
  retrieved = retrieve_commit_comment(user, repo, id)
495
- commit = ensure_commit(repo, retrieved['commit_id'], user)
601
+
602
+ if retrieved.nil?
603
+ debug "GHTorrent: Commit comment #{id} deleted"
604
+ return
605
+ end
606
+
607
+ commit = ensure_commit(repo, retrieved['commit_id'], user, comments = false)
496
608
  user = ensure_user(user, false, false)
497
609
  @db[:commit_comments].insert(
498
610
  :commit_id => commit[:id],
@@ -501,17 +613,66 @@ module GHTorrent
501
613
  :line => retrieved['line'],
502
614
  :position => retrieved['position'],
503
615
  :comment_id => retrieved['id'],
504
- :ext_ref_id => retrieved['ext_ref_id'],
616
+ :ext_ref_id => retrieved[@ext_uniq],
505
617
  :created_at => date(retrieved['created_at'])
506
618
  )
619
+ info "GHTorrent: Added commit comment #{commit[:sha]} -> #{user[:login]}"
507
620
  @db[:commit_comments].first(:comment_id => id)
508
- info "GHTorrent: Added commit comment #{commit[:sha]} -> #{user}"
509
621
  else
510
622
  info "GHTorrent: Commit comment #{id} exists"
511
623
  stored_comment
512
624
  end
513
625
  end
514
626
 
627
+ ##
628
+ # Make sure that
629
+ def ensure_watchers(owner, repo)
630
+ curuser = @db[:users].first(:login => owner)
631
+ currepo = @db[:projects].first(:owner_id => curuser[:id],
632
+ :name => repo)
633
+ watchers = @db[:watchers].filter(:user_id => curuser[:id],
634
+ :repo_id => currepo[:id])
635
+
636
+ retrieve_watchers(owner, repo).reduce([]) do |acc, x|
637
+ if watchers.find { |y| y[:login] == x['login'] }.nil?
638
+ acc << x
639
+ else
640
+ acc
641
+ end
642
+ end.map { |x| ensure_watcher(owner, repo, x['login']) }
643
+ end
644
+
645
+ ##
646
+ # Make sure that a project member exists in a project
647
+ def ensure_watcher(owner, repo, watcher, date_added = nil)
648
+ watchers = @db[:watchers]
649
+ new_watcher = ensure_user(watcher, false, false)
650
+ owner_id = @db[:users].first(:login => owner)[:id]
651
+ project = @db[:projects].first(:owner_id => owner_id, :name => repo)
652
+
653
+ memb_exist = watchers.first(:user_id => new_watcher[:id],
654
+ :repo_id => project[:id])
655
+
656
+ if memb_exist.nil?
657
+ added = if date_added.nil? then Time.now else date_added end
658
+ retrieved = retrieve_watcher(owner, repo, watcher)
659
+ watchers.insert(
660
+ :user_id => new_watcher[:id],
661
+ :repo_id => project[:id],
662
+ :created_at => date(added),
663
+ :ext_ref_id => retrieved[@ext_uniq]
664
+ )
665
+ info "GHTorrent: Added watcher #{repo} -> #{watcher}"
666
+ else
667
+ unless date_added.nil?
668
+ watchers.filter(:user_id => new_watcher[:id],
669
+ :repo_id => project[:id])\
670
+ .update(:created_at => date(date_added))
671
+ info "GHTorrent: Updating #{repo} -> #{watcher}"
672
+ end
673
+ end
674
+ end
675
+
515
676
  private
516
677
 
517
678
  # Store a commit contained in a hash. First check whether the commit exists.
@@ -523,7 +684,6 @@ module GHTorrent
523
684
  author = commit_user(c['author'], c['commit']['author'])
524
685
  commiter = commit_user(c['committer'], c['commit']['committer'])
525
686
 
526
-
527
687
  userid = @db[:users].filter(:login => user).first[:id]
528
688
  repoid = @db[:projects].filter(:owner_id => userid,
529
689
  :name => repo).first[:id]
@@ -535,9 +695,11 @@ module GHTorrent
535
695
  :created_at => date(c['commit']['author']['date']),
536
696
  :ext_ref_id => c[@ext_uniq]
537
697
  )
698
+ commits.first(:sha => c['sha'])
538
699
  debug "GHTorrent: New commit #{repo} -> #{c['sha']} "
539
700
  else
540
701
  debug "GHTorrent: Commit #{repo} -> #{c['sha']} exists"
702
+ commit
541
703
  end
542
704
  end
543
705
 
@@ -569,7 +731,11 @@ module GHTorrent
569
731
  # - yyyy-mm-ddThh:mm:ssZ
570
732
  # - yyyy/mm/dd hh:mm:ss {+/-}hhmm
571
733
  def date(arg)
572
- Time.parse(arg)#.to_i
734
+ if arg.class != Time
735
+ Time.parse(arg)#.to_i
736
+ else
737
+ arg
738
+ end
573
739
  end
574
740
 
575
741
  def is_valid_email(email)