hubdate 0.0.01

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'hubdate.rb'))
6
+
7
+ options = {}
8
+
9
+ opt_parser = OptionParser.new do |opt|
10
+ opt.banner = "Usage: rd COMMAND [OPTIONS]"
11
+ opt.separator ""
12
+ opt.separator "Commands"
13
+ opt.separator " init: initialize a new rudoo file architecture"
14
+ opt.separator ""
15
+ opt.separator "Options"
16
+
17
+ opt.on("-u", "--username USERNAME", "username of the github account you would like to monitor") do |username|
18
+ options[:username] = username
19
+ end
20
+
21
+ opt.on("-p", "--password PASSWORD", "password for the github account you would like to monitor") do |password|
22
+ options[:password] = password
23
+ end
24
+
25
+ opt.on("-t", "--time TIME", "time you would like to wait between polls (Minimum of 70s)") do |time|
26
+ options[:time] = time
27
+ end
28
+ end
29
+
30
+ opt_parser.parse!
31
+
32
+ username = options[:username] || nil
33
+ password = options[:password] || nil
34
+ time = options[:time] || 70
35
+
36
+ if username.nil?
37
+ puts "A username must be specified!"
38
+ elsif password.nil?
39
+ puts "A password must be specified!"
40
+ else
41
+ begin
42
+ run(username, password, time.to_i)
43
+ rescue
44
+ puts "Invalid credentials!"
45
+ end
46
+ end
47
+
48
+
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Tommy Schaefer"]
6
+ gem.email = ["me@tommyschaefer.net"]
7
+ gem.description = %q{A ruby program that polls github for updates and sends them to notification center.}
8
+ gem.summary = %q{Hubdate is a console executed program that polls github for updates (notifications, stars, and watchers). Any new updates will be sent to notification center.}
9
+ gem.homepage = "https://github.com/tommyschaefer/hubdate"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "hubdate"
15
+ gem.version = Hubdate::VERSION
16
+ gem.add_dependency "terminal-notifier"
17
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :person_token: ! '@'
3
+ :tag_token: ^
4
+ :project_token: ! '*'
@@ -0,0 +1,14 @@
1
+ ---
2
+ !binary "MDQxMDIz": !ruby/object:Rudoo::Task
3
+ todo: Upload initial commit
4
+ priority: 0
5
+ !binary "ODgxNDMw": !ruby/object:Rudoo::Task
6
+ todo: Add executable
7
+ priority: 0
8
+ !binary "MWRhMzM0": !ruby/object:Rudoo::Task
9
+ todo: Fix bug that occurs when creating files for the first time and move execution
10
+ into executable :done
11
+ priority: 0
12
+ !binary "NmJmODEx": !ruby/object:Rudoo::Task
13
+ todo: Gemify program :wkng
14
+ priority: 0
@@ -0,0 +1,36 @@
1
+ require "rubygems"
2
+ require "terminal-notifier"
3
+
4
+ require 'json'
5
+ require 'yaml'
6
+ require 'net/http'
7
+ require 'net/https'
8
+ require 'fileutils'
9
+
10
+ require File.expand_path(File.join(File.dirname(__FILE__), "hubdate", "base"))
11
+ require File.expand_path(File.join(File.dirname(__FILE__), "hubdate", "user"))
12
+ require File.expand_path(File.join(File.dirname(__FILE__), "hubdate", "repository"))
13
+ require File.expand_path(File.join(File.dirname(__FILE__), "hubdate", "notification"))
14
+ require File.expand_path(File.join(File.dirname(__FILE__), "hubdate", "connection"))
15
+ require File.expand_path(File.join(File.dirname(__FILE__), "hubdate", "storage"))
16
+ require File.expand_path(File.join(File.dirname(__FILE__), "hubdate", "checker"))
17
+
18
+ def run(user, password, time)
19
+ if !Storage.dir_initialized?(File.join(Dir.home, ".hubdate"))
20
+ Storage.generate_files
21
+ else
22
+ Storage.generate_follow if !Storage.file_initialized?(File.join(Dir.home, ".hubdate", "followers.yaml"))
23
+ Storage.generate_star if !Storage.file_initialized?(File.join(Dir.home, ".hubdate", "stargazers.yaml"))
24
+ Storage.generate_watch if !Storage.file_initialized?(File.join(Dir.home, ".hubdate", "watchers.yaml"))
25
+ end
26
+
27
+ connection = Github::Connection.new({:user => user, :pass => password})
28
+
29
+ loop do
30
+ Checker.check_notifications(connection)
31
+ Checker.check_followers(connection)
32
+ Checker.check_watchers(:stargazer, connection)
33
+ Checker.check_watchers(:watcher, connection)
34
+ sleep time
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ class Github
2
+ module Base
3
+ attr_reader :response, :connection
4
+
5
+ # Initialize module by gathering JSON hash and connection
6
+ def initialize(responseHash, conn = Github::Connection.new)
7
+ @connection = conn
8
+ @response = responseHash
9
+ end
10
+
11
+ # If method doesnt exist, check if the id is a response key and if so return the value
12
+ def method_missing(id, *args)
13
+ unless @response && @response.keys.include?(id.id2name)
14
+ raise NoMethodError.new("Undefined method #{id.id2name} for #{self}: #{self.class}.")
15
+ end
16
+
17
+ @response[id.id2name]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,78 @@
1
+ class Checker
2
+ def self.check_notifications(connection)
3
+ notifications = Github::User.fetch(connection).notifications.reverse
4
+
5
+ notifications.each do |notif|
6
+ TerminalNotifier.notify("#{notif.message}", :title => "#{notif.reason[0] = notif.reason[0].capitalize; notif.reason}: #{notif.type}")
7
+ end
8
+ end
9
+
10
+ def self.check_watchers(type, connection)
11
+ watchers_file = File.join(Dir.home, ".hubdate", "stargazers.yaml") if type == :stargazer
12
+ watchers_file = File.join(Dir.home, ".hubdate", "watchers.yaml") if type == :watcher
13
+
14
+ watchers = Github::User.fetch(connection).watchers(type)
15
+
16
+ begin
17
+ file_watchers = YAML.load_file(watchers_file)
18
+ rescue
19
+ Storage.write_file(watchers, watchers_file)
20
+ end
21
+
22
+ if file_watchers != watchers
23
+ new_gazers = {}
24
+
25
+ watchers.each do |repo, gazers|
26
+ begin
27
+ added = (gazers - file_watchers[repo])
28
+ rescue
29
+ added = []
30
+ end
31
+
32
+ new_gazers[repo] = added
33
+ end
34
+
35
+ new_gazers.each do |repo, logins|
36
+ if logins != []
37
+ case type
38
+ when :stargazer
39
+ action = "Starred"
40
+ message_action = "starred"
41
+ when :watcher
42
+ action = "Now Being Watched"
43
+ message_action = "now watching"
44
+ end
45
+ TerminalNotifier.notify("", :title => "Repository #{action}!", :subtitle => "#{logins.join(", ")} #{message_action} your repository \"#{repo}\"!")
46
+ end
47
+ end
48
+
49
+ Storage.write_file(watchers, watchers_file)
50
+ end
51
+ end
52
+
53
+ def self.check_followers(connection)
54
+ followers_file = File.join(Dir.home, ".hubdate", "followers.yaml")
55
+
56
+ followers = Github::User.fetch(connection).followers.map {|follower| follower.login}
57
+
58
+ begin
59
+ file_followers = YAML.load_file(followers_file)
60
+ rescue
61
+ Storage.write_file(followers, followers_file)
62
+ end
63
+
64
+ if file_followers != followers
65
+ begin
66
+ added = (followers - file_followers)
67
+ rescue
68
+ added = []
69
+ end
70
+
71
+ added.each do |login|
72
+ TerminalNotifier.notify("", :title => 'New Follower!', :subtitle => "#{login} is now following you!")
73
+ end
74
+
75
+ Storage.write_file(followers, followers_file)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,96 @@
1
+ class Github
2
+ class Connection
3
+ attr_accessor :user # Allows us to call for the connections user later
4
+ attr_reader :pass, :token
5
+
6
+ # Check for argument errors and format credentials
7
+ def initialize(args={})
8
+ raise ArgumentError.new("Github::Connection does not take any arguments of type #{args.class}.") unless args.is_a?(Hash)
9
+
10
+ args.keys.each do |key|
11
+ raise ArgumentError.new("Unknown option '#{key}'.") unless [:user, :pass, :token].include? key
12
+ end
13
+
14
+ if args.keys.include?(:user) || args.keys.include?(:pass)
15
+ unless args.keys.include?(:user) && args.keys.include?(:pass)
16
+ raise ArgumentError.new("When using basic authentication, both :user and :pass are required.")
17
+ end
18
+ end
19
+
20
+ if args.keys.include?(:token)
21
+ if args.keys.include?(:user) || args.keys.include?(:pass)
22
+ raise ArgumentError.new("Both OAuth parameters and basic authenctication parameters have been previded.")
23
+ end
24
+ end
25
+
26
+ @user = args[:user]
27
+ @pass = args[:pass]
28
+ @token = args[:token]
29
+
30
+ @server = "api.github.com"
31
+
32
+ if !@token.nil?
33
+ @creds = {:token => @token}
34
+ elsif !@user.nil?
35
+ @creds = {:user => @user, :pass => @pass}
36
+ elsif @token.nil? && @user.nil?
37
+ @creds = {}
38
+ end
39
+ end
40
+
41
+ # Check is user is authenticated
42
+ def authenticated?
43
+ if (user && pass) || token
44
+ true
45
+ else
46
+ false
47
+ end
48
+ end
49
+
50
+ # Send HTTP Get request
51
+ def get(path, params = {}, creds = @creds, server = @server)
52
+ path = linkPath(path, params) if params != {}
53
+ path = linkPath(path, params, creds[:token]) if params != {} && creds.keys.include?(:token)
54
+
55
+ http = Net::HTTP.new(server, 443)
56
+ req = Net::HTTP::Get.new(path)
57
+ http.use_ssl = true
58
+ req.basic_auth creds[:user], creds[:pass] if creds.keys.include?(:user)
59
+ response = http.request(req)
60
+ return JSON.parse(response.body)
61
+ end
62
+
63
+ def post(path, params={}, creds = @creds, server = @server)
64
+ path = linkPath(path, params, creds[:token]) if params != {} && creds.keys.include?(:token)
65
+
66
+ http = Net::HTTP.new(server, 443)
67
+ req = Net::HTTP::Post.new(path)
68
+ http.use_ssl = true
69
+ req.body = params.to_json
70
+ req.basic_auth creds[:user], creds[:pass] if creds.keys.include?(:user)
71
+ response = http.request(req)
72
+ return JSON.parse(response.body)
73
+ end
74
+
75
+ def edit
76
+ end
77
+
78
+ def delete
79
+ end
80
+
81
+ private
82
+
83
+ # Method used to link multiple parameters with a base path
84
+ def linkPath(path, params, token = nil)
85
+ param1 = params.shift
86
+ paramString = "?#{param1[0].to_s}=#{param1[1]}"
87
+
88
+ params.each do |name, value|
89
+ paramString += "&&#{name.to_s}=#{value}"
90
+ end
91
+
92
+ paramString += "&&#{token}" unless token.nil?
93
+ paramString = path + paramString
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,33 @@
1
+ class Github
2
+ class Notification
3
+ include Github::Base
4
+
5
+ # Generate JSON hash and create new Github::Repository object through Github::Base
6
+ def self.fetch(conn = Github::Connection.new)
7
+ raise ArgumentError.new("You must be authenticated to retrieve this information!") if !connection.authenticated?
8
+
9
+ responseHash = conn.get("/notifications")
10
+ new(responseHash, conn)
11
+ end
12
+
13
+ def message
14
+ subject["title"]
15
+ end
16
+
17
+ def type
18
+ subject["type"]
19
+ end
20
+
21
+ # Do some argument checking and then return an array of repository objects
22
+ def self.list(params = {}, conn = Github::Connection.new)
23
+ conn = params if params.class == Github::Connection
24
+ params = {} if params.class == Github::Connection
25
+
26
+ notifications = conn.get("/notifications", params)
27
+
28
+ notifications.map do |notification|
29
+ new(notification, conn)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ class Github
2
+ class Repository
3
+ include Github::Base
4
+
5
+ # Generate JSON hash and create new Github::Repository object through Github::Base
6
+ def self.fetch(user, name, conn = Github::Connection.new)
7
+ raise ArgumentError.new("Username must be provided. Call user.repo(*) for an authenticated user's repository.") if user.nil?
8
+ raise ArgumentError.new("Repository name must be provided.") if name.nil?
9
+
10
+ responseHash = conn.get("/repos/#{user}/#{name}")
11
+ new(responseHash, conn)
12
+ end
13
+
14
+ # Do some argument checking and then return an array of repository objects
15
+ def self.list(login, account_type, params = {}, conn = Github::Connection.new)
16
+ conn = params if params.class == Github::Connection
17
+ params = {} if params.class == Github::Connection
18
+
19
+ case account_type
20
+ when "User"
21
+ baseUrl = "users"
22
+ when "Organization"
23
+ baseUrl = "orgs"
24
+ else
25
+ raise ArgumentError.new("Unknown account type: #{account_type}.")
26
+ end
27
+
28
+ repositories = conn.get("/#{baseUrl}/#{login}/repos", params)
29
+
30
+ repositories.map do |repo|
31
+ new(repo, conn)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,61 @@
1
+ class Storage
2
+ def self.write_file(contents, destination)
3
+ File.open(destination, "w") do |file|
4
+ file << contents.to_yaml
5
+ end
6
+ end
7
+
8
+ def self.clear_files(dir)
9
+ raise StandardError.new("Unable to delete folder.") unless FileUtils.rm_rf(dir)
10
+ end
11
+
12
+ def self.make_file(dir, file)
13
+ f = File.new(File.join(dir, file), "w+")
14
+
15
+ raise StandardError.new("Unable to make file.") unless f
16
+
17
+ f.close
18
+ end
19
+
20
+ def self.make_folder(dir)
21
+ folder = FileUtils.mkdir(dir)
22
+
23
+ raise StandardError.new("Unable to create directory.") unless folder
24
+ end
25
+
26
+ def self.dir_initialized?(dir)
27
+ if File.directory?(dir)
28
+ return true
29
+ else
30
+ return false
31
+ end
32
+ end
33
+
34
+ def self.file_initialized?(file)
35
+ if File.exists?(file)
36
+ return true
37
+ else
38
+ return false
39
+ end
40
+ end
41
+
42
+ def self.generate_follow
43
+ Storage.make_file(File.join(Dir.home, ".hubdate") , "followers.yaml")
44
+ end
45
+
46
+ def self.generate_star
47
+ Storage.make_file(File.join(Dir.home, ".hubdate"), "stargazers.yaml")
48
+ end
49
+
50
+ def self.generate_watch
51
+ Storage.make_file(File.join(Dir.home, ".hubdate"), "watchers.yaml")
52
+ end
53
+
54
+ def self.generate_files
55
+ Storage.make_folder(File.join(Dir.home, ".hubdate"))
56
+
57
+ self.generate_follow
58
+ self.generate_star
59
+ self.generate_watch
60
+ end
61
+ end
@@ -0,0 +1,70 @@
1
+ class Github
2
+ class User
3
+ include Github::Base
4
+
5
+ # Generate JSON hash and create new Github::User object through Github::Base
6
+ def self.fetch(user = nil, conn = Github::Connection.new)
7
+ conn = user if user.class == Github::Connection
8
+ user = nil if user.class == Github::Connection
9
+ if user.nil?
10
+ raise ArgumentError.new("Authenticated request required when making calls on logged in user.") unless conn.authenticated?
11
+ responseHash = conn.get("/user")
12
+ else
13
+ responseHash = conn.get("/users/#{user}")
14
+ end
15
+
16
+ new(responseHash, conn)
17
+ end
18
+
19
+ # Define ID because its reserved by ruby
20
+ def id
21
+ @response['id']
22
+ end
23
+
24
+ # Define type because its reserved by ruby
25
+ def type
26
+ @response['type']
27
+ end
28
+
29
+ # Return a Github::User object for each follower
30
+ def followers
31
+ result = connection.get("/users/#{login}/followers")
32
+
33
+ result.map do |follower|
34
+ self.class.new(follower, connection)
35
+ end
36
+ end
37
+
38
+ def notifications(params = {})
39
+ Github::Notification.list(params, connection)
40
+ end
41
+
42
+ def repos(params = {})
43
+ Github::Repository.list(login, type, params, connection)
44
+ end
45
+
46
+ def watchers(type)
47
+
48
+ case type
49
+ when :stargazer
50
+ type = "stargazers"
51
+ when :watcher
52
+ type = "subscribers"
53
+ else
54
+ raise StandardError.new("Watcher type must be either :stargazer or :watcher!")
55
+ end
56
+
57
+ stargazers_hash = {}
58
+ repos = self.repos.map {|repo| repo.name}
59
+
60
+ repos.each do |repo|
61
+ stargazers = connection.get("/repos/#{login}/#{repo}/#{type}")
62
+ stargazers_array = stargazers.map {|gazer| gazer["login"]}
63
+
64
+ stargazers_hash[repo.to_s] = stargazers_array
65
+ end
66
+
67
+ return stargazers_hash
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module Hubdate
2
+ VERSION = "0.0.01"
3
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hubdate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.01
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tommy Schaefer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: terminal-notifier
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: A ruby program that polls github for updates and sends them to notification
31
+ center.
32
+ email:
33
+ - me@tommyschaefer.net
34
+ executables:
35
+ - hubdate
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - bin/hubdate
40
+ - hubdate.gemspec
41
+ - lib/.rudoo/config.yml
42
+ - lib/.rudoo/list.yml
43
+ - lib/hubdate.rb
44
+ - lib/hubdate/base.rb
45
+ - lib/hubdate/checker.rb
46
+ - lib/hubdate/connection.rb
47
+ - lib/hubdate/notification.rb
48
+ - lib/hubdate/repository.rb
49
+ - lib/hubdate/storage.rb
50
+ - lib/hubdate/user.rb
51
+ - lib/version.rb
52
+ homepage: https://github.com/tommyschaefer/hubdate
53
+ licenses: []
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 1.8.24
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Hubdate is a console executed program that polls github for updates (notifications,
76
+ stars, and watchers). Any new updates will be sent to notification center.
77
+ test_files: []