otr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+