hubdate 0.0.01

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.
@@ -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: []