otr 0.1.0

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.
Files changed (5) hide show
  1. data/LICENSE +28 -0
  2. data/README.rdoc +101 -0
  3. data/bin/otr +48 -0
  4. data/lib/otr.rb +47 -0
  5. metadata +82 -0
data/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ Copyright (c) Stephen McDonald and individual contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of OTR nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
data/README.rdoc ADDED
@@ -0,0 +1,101 @@
1
+ = One True Repo
2
+
3
+ == One feed to rule them all, and in the mashup bind them.
4
+
5
+ _One_ _True_ _Repo_ merges both the {GitHub}[http://github.com] and
6
+ {Bitbucket}[http://bitbucket.org] APIs into a single JSON feed,
7
+ for the purpose of combining numbers of watchers and forks across
8
+ duplicate repositories. It comes as both a {Sinatra}[http://sinatrarb.com]
9
+ app and command-line gem.
10
+
11
+ === Sinatra
12
+
13
+ The Sinatra app is hosted on Heroku at
14
+ {otr.jupo.org}[http://otr.jupo.org]. Add your username to the path to
15
+ get your feed. For example my GitHub and Bitbucket username is
16
+ +stephenmcd+ so my feed is available at {otr.jupo.org/stephenmcd}[
17
+ http://otr.jupo.org/stephenmcd]. If you have different usernames
18
+ between GitHub and Bitbucket, you can use the URL
19
+ {otr.jupo.org/github_username/bitbucket_username
20
+ }[http://otr.jupo.org/github_username/bitbucket_username]
21
+ to provide them separately. Note that feeds are cached for about 24
22
+ hours.
23
+
24
+ === JSON
25
+
26
+ Here's a sample of the JSON provided:
27
+
28
+ [
29
+ {
30
+ "name": "mezzanine",
31
+ "urls": [
32
+ "https://github.com/stephenmcd/mezzanine",
33
+ "https://bitbucket.org/stephenmcd/mezzanine"
34
+ ],
35
+ "watchers": 316,
36
+ "forks": 102,
37
+ "fork": false
38
+ },
39
+ {
40
+ "name": "django-socketio",
41
+ "urls": [
42
+ "https://github.com/stephenmcd/django-socketio",
43
+ "https://bitbucket.org/stephenmcd/django-socketio"
44
+ ],
45
+ "watchers": 112,
46
+ "forks": 11,
47
+ "fork": false
48
+ }
49
+ ]
50
+
51
+ === JSONP
52
+
53
+ You can also append a +callback+ parameter to the Sinatra app's URLs,
54
+ specifying the name of a JavaScript function to call:
55
+
56
+ <script>
57
+ var displayRepos = function(repos) {
58
+ // The repos argument will contain the
59
+ // JSON data for stephenmcd's feed.
60
+ var watchers = 0, forks = 0;
61
+ for (var i = 0; i < repos.length; i++) {
62
+ watchers += repos[i].watchers;
63
+ forks += repos[i].forks;
64
+ }
65
+ alert('Total watchers: ' + watchers + '\nTotal forks: ' + forks);
66
+ }
67
+ </script>
68
+ <script src="http://otr.jupo.org/stephenmcd?callback=displayRepos"></script>
69
+
70
+ === Ruby Gem
71
+
72
+ _One_ _True_ _Repo_ is also an installable gem named +otr+. Install the
73
+ +otr+ gem with the following command:
74
+
75
+ $ gem install otr
76
+
77
+ Once installed, +otr+ can be called from the command-line and will output
78
+ its JSON feed:
79
+
80
+ Usage: otr [options]
81
+
82
+ -u, --username NAME Combined GitHub / Bitbucket username
83
+ -g, --github-username NAME GitHub username if different from
84
+ Bitbucket username (required without -u)
85
+ -b, --bitbucket-username NAME Bitbucket username if different from
86
+ GitHub username (required without -u)
87
+ -h, --help Show this message
88
+ -v, --version Show version
89
+
90
+ You can also use +otr+ in your own Ruby code:
91
+
92
+ require 'rubygems'
93
+ require 'otr'
94
+
95
+ = With a combined username:
96
+ options = {:username => "stephenmcd"}
97
+
98
+ = Or with differing usernames:
99
+ options = {:github_username => "alice", :bitbucket_username => "bob"}
100
+
101
+ json = OTR.get(options).to_json
data/bin/otr ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "optparse"
5
+ require "lib/otr"
6
+
7
+
8
+ options = {}
9
+
10
+ option_parser = OptionParser.new do |opts|
11
+ opts.banner = "\nUsage: otr [options]\n\n"
12
+
13
+ opts.on("-u", "--username NAME", String,
14
+ "Combined GitHub / Bitbucket username") do |v|
15
+ options[:username] = v
16
+ end
17
+
18
+ opts.on("-g", "--github-username NAME", String,
19
+ "GitHub username if different from Bitbucket username (required without -u)") do |v|
20
+ options[:github_username] = v
21
+ end
22
+
23
+ opts.on("-b", "--bitbucket-username NAME", String,
24
+ "Bitbucket username if different from GitHub username (required without -u)") do |v|
25
+ options[:bitbucket_username] = v
26
+ end
27
+
28
+ opts.on("-h", "--help", "Show this message") do
29
+ puts opts
30
+ exit
31
+ end
32
+
33
+ opts.on("-v", "--version", "Show version") do
34
+ puts OTR::VERSION
35
+ exit
36
+ end
37
+ end
38
+
39
+ begin
40
+ option_parser.parse!
41
+ raise OptionParser::ParseError if options.size == 0
42
+ rescue OptionParser::ParseError
43
+ # Display all options if anything goes wrong.
44
+ puts option_parser
45
+ exit
46
+ end
47
+
48
+ puts OTR.get(options).to_json
data/lib/otr.rb ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "json"
5
+ require "rest_client"
6
+
7
+ module OTR
8
+ VERSION = "0.1.0"
9
+
10
+ def self.get_bb(username)
11
+ repos = {}
12
+ url = "https://api.bitbucket.org/1.0/users/#{username}/"
13
+ JSON.parse(RestClient.get(url))["repositories"].map { |repo|
14
+ Thread.new repo do |repo|
15
+ name = repo["slug"]
16
+ url = "https://bitbucket.org/#{username}/#{name}/descendants"
17
+ html = RestClient.get(url)
18
+ repos[name] = {
19
+ "name" => name,
20
+ "watchers" => html.split("followers-count\">")[1].to_i,
21
+ "forks" => html.split("Forks/queues (")[1].to_i,
22
+ "fork" => repo["is_fork"],
23
+ "urls" => ["https://bitbucket.org/#{username}/#{name}"]
24
+ }
25
+ end
26
+ }.each { |thread| thread.join }
27
+ repos
28
+ end
29
+
30
+ def self.get_gh(username)
31
+ url = "http://github.com/api/v1/json/#{username}"
32
+ JSON.parse(RestClient.get(url))["user"]["repositories"]
33
+ end
34
+
35
+ def self.get(options)
36
+ repos = self.get_bb(options[:bitbucket_username] || options[:username])
37
+ self.get_gh(options[:github_username] || options[:username]).each do |repo|
38
+ name = repo["name"]
39
+ repos[name] ||= {"forks" => 0, "watchers" => 0, "urls" => []}
40
+ repos[name]["urls"] << repo["url"]
41
+ %w[watchers forks].each { |k| repos[name][k] += repo[k] }
42
+ %w[fork name].each { |k| repos[name][k] ||= repo[k] }
43
+ end
44
+ repos.values
45
+ end
46
+
47
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: otr
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Stephen McDonald
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-12-31 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rest-client
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Combined GitHub and Bitbucket API.
35
+ email: steve@jupo.org
36
+ executables:
37
+ - otr
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.rdoc
42
+ - LICENSE
43
+ files:
44
+ - LICENSE
45
+ - README.rdoc
46
+ - lib/otr.rb
47
+ - bin/otr
48
+ homepage: http://jupo.org
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.13
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Combined GitHub and Bitbucket API.
81
+ test_files: []
82
+