gem-miner 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4acfe8bf3640a218566752d209c0ec69dbf0665d
4
+ data.tar.gz: 6fe3c2965609073a8777875ecca05dde2cb61c9f
5
+ SHA512:
6
+ metadata.gz: c50059c70f09a70cbee8d212d22f9e34610a723100a5132fbac7fad70816b7761532c3c82a78556f228bfca5d6575dc10a9c820ff4aa5e98f6bd40c7b2d31b56
7
+ data.tar.gz: 2aa3365629d0780671ad8c4f6743230107e4f03a7ede10c376debb915b517636f7d822975bfc68946896b9eab9aa4563e8a9858bfa8ff90a8614503a38de7eae
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gem-miner.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Reevoo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ # GemMiner
2
+
3
+ [![Build Status](https://travis-ci.org/reevoo/gem-miner.svg?branch=master)](https://travis-ci.org/reevoo/gem-miner)
4
+
5
+ [![Code Climate](https://codeclimate.com/github/reevoo/gem-miner/badges/gpa.svg)](https://codeclimate.com/github/reevoo/gem-miner)
6
+
7
+
8
+
9
+ At [Reevoo](http://reevoo.github.io), we want to get rid of some of our old repositories - they don't do anything and they're confusing new starters. However, we want to make sure that these repositories aren't used by others.
10
+
11
+ GemMiner looks through all of the repositories of a GitHub user and shows where a gem is being used by extracting information from Gemfiles and Gemspecs.
12
+
13
+ This tool is being actively developed; please feel free to contribute or fork for your own purposes!
14
+
15
+ ## Installation
16
+
17
+ This is a tool, so it makes sense to install it globally.
18
+
19
+ ```bash
20
+ gem install 'gem-miner'
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ Execute `gem-miner help` in your favourite shell for information on the wonderful things this application can do.
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/reevoo/gem-miner.
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
7
+ rescue LoadError
8
+ # no rspec available
9
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "gem-miner"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'gem-miner/cli'
5
+
6
+ GemMiner::CLI.start(ARGV)
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gem-miner/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'gem-miner'
8
+ spec.version = GemMiner::VERSION
9
+ spec.authors = ['Reevoo']
10
+ spec.email = ['developers@reevoo.com']
11
+
12
+ spec.summary = %q{Collect Gemfiles and Gemspecs from multiple repositories.}
13
+ spec.homepage = 'https://github.com/reevoo/gem-miner'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = 'exe'
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ # GitHub API Client
22
+ spec.add_dependency 'octokit', '~> 4'
23
+
24
+ # CLI helper. Not at v1 yet...
25
+ spec.add_dependency 'thor'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1'
28
+ spec.add_development_dependency 'rake', '~> 10'
29
+ spec.add_development_dependency 'rspec', '~> 3'
30
+ spec.add_development_dependency 'pry-byebug'
31
+ end
@@ -0,0 +1,4 @@
1
+ require 'gem-miner/version'
2
+ require 'gem-miner/miner'
3
+ # 'gem-miner/cli' is deliberately not included here;
4
+ # cli includes gem-miner, not the other way round.
@@ -0,0 +1,53 @@
1
+ require 'gem-miner'
2
+ require 'thor'
3
+ require 'yaml'
4
+
5
+ module GemMiner
6
+ class CLI < Thor
7
+
8
+ option :token,
9
+ aliases: [:t],
10
+ desc: 'The Github access token to use when querying Github.',
11
+ type: :string
12
+
13
+ option :output,
14
+ aliases: [:o],
15
+ desc: 'The filename to output results to (leave blank for console).',
16
+ type: :string
17
+
18
+ desc 'gems QUERY', 'Collects all gems for projects given by the Github query.'
19
+ long_desc <<-LD
20
+ Collects all gems for projects given by the Github query.
21
+ This is useful for auditing which gems you use across all projects,
22
+ to check whether you can delete any!
23
+
24
+ The following command gets all gems for the organisation 'reevoo':
25
+
26
+ > $ gem-miner gems user:reevoo
27
+
28
+ You probably want to supply an access token to ensure you are not rate-limited
29
+ by Github.
30
+
31
+ This action returns the gems as a hash in YAML format with the gem description as the key
32
+ and the repositories that use the gem as an array of values.
33
+ LD
34
+ def gems(github_search_query)
35
+ output GemMiner::Miner.gems_for(github_search_query, options[:token]).to_yaml
36
+ end
37
+
38
+ private
39
+
40
+ # Output the result of a command to either the terminal or a file,
41
+ # depending on the options given.
42
+ def output(result)
43
+ if options[:output]
44
+ File.write(options[:output], result)
45
+ else
46
+ puts result
47
+ end
48
+
49
+ result
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,38 @@
1
+ require 'base64'
2
+ require 'octokit'
3
+
4
+ module GemMiner
5
+ # A Github client with GemMiner-specific extensions.
6
+ class GithubClient
7
+
8
+ def initialize(github_access_token = nil)
9
+ @internal_client = Octokit::Client.new(
10
+ auto_paginate: true,
11
+ access_token: github_access_token
12
+ )
13
+ end
14
+
15
+ # Gets the files from a code search.
16
+ def files(query)
17
+ @internal_client.search_code(query)['items']
18
+ .map do |item|
19
+ {
20
+ name: name_of(item),
21
+ content: raw_content(item),
22
+ }
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def name_of(item)
29
+ item[:repository][:full_name]
30
+ end
31
+
32
+ def raw_content(item)
33
+ content_request = @internal_client.contents(name_of(item), path: item[:path])
34
+ Base64.decode64 content_request[:content]
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ module GemMiner
2
+
3
+ module Logger
4
+ @@logger = STDOUT
5
+
6
+ def self.logger=(logger)
7
+ @@logger = logger
8
+ end
9
+
10
+ def log(message)
11
+ @@logger.print message if @@logger
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,121 @@
1
+ require 'base64'
2
+ require 'octokit'
3
+
4
+ require 'gem-miner/github_client'
5
+ require 'gem-miner/logger'
6
+
7
+ module GemMiner
8
+ class Miner
9
+ include Logger
10
+
11
+ def self.gems_for(*args)
12
+ new(*args).gems
13
+ end
14
+
15
+ def initialize(github_search_query, github_client = GithubClient.new)
16
+ @github_search_query = github_search_query
17
+ @github_client = github_client
18
+ end
19
+
20
+ # A hash of gems and the repositories they are used in:
21
+ #
22
+ # {
23
+ # "pry '~> 1'" => ['reevoo/flakes', 'reevoo/gem-miner'],
24
+ # ...
25
+ # }
26
+ def gems
27
+ @gems ||= collect_gems!
28
+ end
29
+
30
+ private
31
+
32
+ # Collects gem specifications from Gemfiles and Gemspecs.
33
+ # Returns a hash of gems and the repositories they are used in:
34
+ #
35
+ # {
36
+ # "pry '~> 1'" => ['reevoo/flakes', 'reevoo/gem-miner'],
37
+ # ...
38
+ # }
39
+ def collect_gems!
40
+ gemfiles = parse_gemfiles
41
+ gemspecs = parse_gemspecs
42
+
43
+ gems = merge_hashes(gemfiles, gemspecs)
44
+
45
+ # Invert the PROJECT => [GEMS] hash to a GEM => [PROJECTS] hash
46
+ gems = invert_hash_of_arrays(gems)
47
+
48
+ # Sort it
49
+ gems = gems.sort.to_h
50
+ end
51
+
52
+ # Collects all of the gemfiles for all Reevoo repositories.
53
+ # Returns a dictionary with the gem as the key and an array of repositories as
54
+ # values.
55
+ def parse_gemfiles
56
+ results = search("filename:Gemfile #{@github_search_query}")
57
+
58
+ log "Parsing #{results.count} gemfiles"
59
+ gemfiles = results.reduce({}) do |memo, result|
60
+ # We might have more than one Gemfile in a repository...
61
+ memo[name_of(result)] ||= []
62
+ memo[name_of(result)] += extract_gemfile(result[:content])
63
+ log '.'
64
+ memo
65
+ end
66
+ log "done!\n"
67
+ gemfiles
68
+ end
69
+
70
+ GEM_REGEX = /gem[\s]+([^\n\;]+)/
71
+ def extract_gemfile(gemfile)
72
+ gemfile.gsub(/\"/, '\'').scan(GEM_REGEX).flatten
73
+ end
74
+
75
+ def parse_gemspecs
76
+ results = search("filename:gemspec #{@github_search_query}")
77
+ log "Parsing #{results.count} gemspecs"
78
+ gemspecs = results.reduce({}) do |memo, result|
79
+ # We might have more than one Gemfile in a repository...
80
+ memo[name_of(result)] ||= []
81
+ memo[name_of(result)] += extract_gemspec(result[:content])
82
+ log '.'
83
+ memo
84
+ end
85
+ log "done!\n"
86
+ gemspecs
87
+ end
88
+
89
+ GEMSPEC_REGEX = /dependency[\s]+([^\n\;]+)/
90
+ def extract_gemspec(gemspec)
91
+ gemspec.gsub(/\"/, '\'').scan(GEMSPEC_REGEX).flatten
92
+ end
93
+
94
+ def search(query)
95
+ @github_client.files(query)
96
+ end
97
+
98
+ # Merge two hashes of lists
99
+ #
100
+ # h1 = { a: [1, 2, 3], b: [2, 4] }
101
+ # h2 = { b: [1, 3], c: [1, 2, 3] }
102
+ # merge_hashes(h1, h2) # => { a: [1, 2, 3], b: [1, 2, 3, 4], c: [1, 2, 3] }
103
+ #
104
+ # From http://stackoverflow.com/questions/11171834/merging-ruby-hash-with-array-of-values-into-another-hash-with-array-of-values
105
+ def merge_hashes(hash1, hash2)
106
+ hash1.merge(hash2) { |key, oldval, newval| (oldval | newval) }
107
+ end
108
+
109
+ # Converts a hash of the form A => [Bs] to B => [As]
110
+ def invert_hash_of_arrays(hash)
111
+ hash.reduce({}) do |memo, (key, values)|
112
+ values.each do |v|
113
+ memo[v] ||= []
114
+ memo[v] << key
115
+ end
116
+
117
+ memo
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,3 @@
1
+ module GemMiner
2
+ VERSION = '1.0.0'
3
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gem-miner
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Reevoo
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: octokit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - developers@reevoo.com
100
+ executables:
101
+ - gem-miner
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - bin/console
112
+ - bin/setup
113
+ - exe/gem-miner
114
+ - gem-miner.gemspec
115
+ - lib/gem-miner.rb
116
+ - lib/gem-miner/cli.rb
117
+ - lib/gem-miner/github_client.rb
118
+ - lib/gem-miner/logger.rb
119
+ - lib/gem-miner/miner.rb
120
+ - lib/gem-miner/version.rb
121
+ homepage: https://github.com/reevoo/gem-miner
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.4.5
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Collect Gemfiles and Gemspecs from multiple repositories.
145
+ test_files: []