├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── gem-compare.gemspec ├── lib ├── rubygems │ ├── commands │ │ └── compare_command.rb │ ├── comparator.rb │ └── comparator │ │ ├── base.rb │ │ ├── dependency_comparator.rb │ │ ├── dir_utils.rb │ │ ├── file_list_comparator.rb │ │ ├── gemfile_comparator.rb │ │ ├── monitor.rb │ │ ├── report.rb │ │ ├── report │ │ └── entry.rb │ │ ├── spec_comparator.rb │ │ ├── utils.rb │ │ └── version.rb └── rubygems_plugin.rb └── test ├── gemfiles ├── lorem-0.0.1.gem ├── lorem-0.0.1 │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── lib │ │ ├── lorem.rb │ │ └── lorem │ │ │ └── version.rb │ └── lorem.gemspec ├── lorem-0.0.2.gem ├── lorem-0.0.2 │ ├── CHANGELOG.md │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── lib │ │ ├── lorem.rb │ │ └── lorem │ │ │ └── version.rb │ └── lorem.gemspec ├── lorem-0.0.3.gem ├── lorem-0.0.3 │ ├── CHANGELOG.md │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── bin │ │ └── lorem │ ├── lib │ │ ├── lorem.rb │ │ └── lorem │ │ │ ├── utils.rb │ │ │ └── version.rb │ └── lorem.gemspec ├── lorem-0.0.4.gem └── lorem-0.0.4 │ ├── .CHANGELOG.md.swp │ ├── CHANGELOG.md │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── bin │ └── lorem │ ├── lib │ ├── lorem.rb │ └── lorem │ │ ├── utils.rb │ │ └── version.rb │ └── lorem.gemspec ├── rubygems ├── comparator │ ├── test_dependency_comparator.rb │ ├── test_dir_utils.rb │ ├── test_file_list_comparator.rb │ ├── test_gemfile_comparator.rb │ ├── test_monitor.rb │ ├── test_report.rb │ ├── test_spec_comparator.rb │ └── test_utils.rb └── test_gem_commands_compare_command.rb └── test_helper.rb /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | pull_request: 8 | paths-ignore: 9 | - '**.md' 10 | workflow_dispatch: 11 | 12 | # GitHub Actions notes 13 | # - outcome in step name so we can see it without having to expand logs 14 | # - every step must define a `uses` or `run` key 15 | 16 | jobs: 17 | test: 18 | name: >- 19 | ${{ matrix.os }} ${{ matrix.ruby }} 20 | env: 21 | TESTOPTS: -v 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | os: [ubuntu-20.04] 26 | ruby: ['3.0', '3.1'] 27 | include: 28 | - { os: ubuntu-20.04 , ruby: ruby-head } 29 | - { os: ubuntu-20.04 , ruby: jruby, allow-failure: true } 30 | - { os: ubuntu-20.04 , ruby: jruby-head } 31 | - { os: ubuntu-20.04 , ruby: truffleruby } 32 | - { os: ubuntu-20.04 , ruby: truffleruby-head, allow-failure: true } 33 | runs-on: ${{ matrix.os }} 34 | steps: 35 | - uses: actions/checkout@v3 36 | - uses: ruby/setup-ruby@v1 37 | continue-on-error: ${{ matrix.allow-failure || false }} 38 | id: bundle 39 | with: 40 | ruby-version: ${{ matrix.ruby }} 41 | bundler-cache: true 42 | - name: "setup-ruby and bundle install outcome: ${{ steps.bundle.outcome }}" 43 | run: echo "" 44 | - run: bundle exec rake 45 | continue-on-error: ${{ matrix.allow-failure || false }} 46 | id: test 47 | - name: "bundle exec rake outcome: ${{ steps.test.outcome }}" 48 | run: echo "" 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | *.gem 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://www.rubygems.org" 2 | 3 | gemspec 4 | 5 | group :development do 6 | gem 'rake' 7 | gem 'rdoc' 8 | gem 'minitest' 9 | end 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Josef Strzibny. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | 'Software'), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gem-compare 2 | 3 | gem-compare is a RubyGems plugin that compares different versions of the specified gem. It can help you to track changes in metadata through the time, see how dependencies were evolving and spot important changes in gem's files such as shebang or permissions modifications. 4 | 5 | This is especially handy for: 6 | 7 | - checking what goes into to a next gem release 8 | - tracking dependencies and license changes before upgrades 9 | - spotting anything suspicious and unusual 10 | 11 | ## Installation 12 | 13 | You can install `gem-compare` as a gem from RubyGems.org: 14 | 15 | ```bash 16 | $ gem install gem-compare 17 | ``` 18 | 19 | ## Usage 20 | 21 | By default, `gem-compare` compares specified versions of the given gem and includes only changes in the final report. If it's supposed to compare file lists or Gemfiles it will need to download the gems, otherwise it just downloads the specs. If you want to keep the downloaded `.gem` files, use `-k` (as 'keep') option. If you want to see the full report use `-a` (as 'all') switch: 22 | 23 | ```bash 24 | $ gem compare rails 3.0.0 4.0.0 -k 25 | Compared versions: ["3.0.0", "4.0.0"] 26 | DIFFERENT date: 27 | 3.0.0: 2010-08-29 00:00:00 UTC 28 | 4.0.0: 2013-06-25 00:00:00 UTC 29 | DIFFERENT executables: 30 | 3.0.0: ["rails"] 31 | 4.0.0: [] 32 | DIFFERENT has_rdoc: 33 | 3.0.0: true 34 | 4.0.0: 35 | DIFFERENT license: 36 | 3.0.0: 37 | 4.0.0: MIT 38 | DIFFERENT licenses: 39 | 3.0.0: [] 40 | 4.0.0: ["MIT"] 41 | DIFFERENT required_ruby_version: 42 | 3.0.0: >= 1.8.7 43 | 4.0.0: >= 1.9.3 44 | DIFFERENT required_rubygems_version: 45 | 3.0.0: >= 1.3.6 46 | 4.0.0: >= 1.8.11 47 | DIFFERENT rubygems_version: 48 | 3.0.0: 1.3.7 49 | 4.0.0: 2.0.2 50 | DIFFERENT version: 51 | 3.0.0: 3.0.0 52 | 4.0.0: 4.0.0 53 | DIFFERENT files: 54 | 3.0.0->4.0.0: 55 | * Deleted: 56 | bin/rails 57 | * Added: 58 | README.md 59 | guides/assets/images/belongs_to.png 60 | guides/assets/images/book_icon.gif 61 | (...) 62 | ``` 63 | 64 | You can also specify what you are interested in by using -p (as 'param') option: 65 | 66 | ```bash 67 | $ gem compare activesupport 4.0.0 4.1.0 -p 'runtime_dependency' 68 | Compared versions: ["4.0.0", "4.1.0"] 69 | DIFFERENT runtime dependencies: 70 | 4.0.0->4.1.0: 71 | * Deleted: 72 | multi_json ["~> 1.3"] (runtime) 73 | * Added: 74 | json [">= 1.7.7", "~> 1.7"] (runtime) 75 | * Updated: 76 | i18n from: [">= 0.6.4", "~> 0.6"] to: [">= 0.6.9", "~> 0.6"] 77 | tzinfo from: ["~> 0.3.37"] to: ["~> 1.1"] 78 | minitest from: ["~> 4.2"] to: ["~> 5.1"] 79 | ``` 80 | There are also shortcuts for favourite options. Use `--runtime` for runtime dependencies, `--gemfiles` for comparing Gemfiles or `--files` for comparing file lists: 81 | 82 | ```bash 83 | $ gem compare rails 2.0.1 3.0.0 -k --files 84 | Compared versions: ["2.0.1", "3.0.0"] 85 | DIFFERENT files: 86 | 2.0.1->3.0.0: 87 | * Deleted: 88 | bin 89 | builtin 90 | CHANGELOG 91 | configs 92 | dispatches 93 | doc 94 | environments 95 | fresh_rakefile 96 | helpers 97 | html 98 | lib 99 | MIT-LICENSE 100 | (...) 101 | * Changed: 102 | bin/rails 7/17 103 | (!) New permissions: 100644 -> 100755 104 | (!) File is now executable! 105 | (!) Shebang probably added: #!/usr/bin/env ruby 106 | ``` 107 | 108 | If you would like to see all development dependencies for `prawn` since `0.1` version, let *gem-compare* expand the versions for you (`>=0.0` won't work as RubyGems asks for the latest spec only): 109 | 110 | ```bash 111 | $ gem compare prawn '>=0.1' -k -a --development 112 | Compared versions: ["0.1.0", "0.1.1", "0.1.2", "0.2.0", "0.2.1", "0.2.2", "0.2.3", "0.3.0", "0.4.0", "0.4.1", "0.5.0.1", "0.5.1", "0.6.1", "0.6.2", "0.6.3", "0.7.1", "0.7.2", "0.8.4", "0.11.1", "0.12.0", "0.13.0", "0.13.1", "0.13.2", "0.14.0", "0.15.0", "1.0.0", "1.1.0"] 113 | DIFFERENT development dependencies: 114 | 0.12.0->0.13.0: 115 | * Added: 116 | pdf-inspector ["~> 1.1.0"] (development) 117 | coderay ["~> 1.0.7"] (development) 118 | rdoc [">= 0"] (development) 119 | 0.13.2->0.14.0: 120 | * Deleted: 121 | rdoc [">= 0"] (development) 122 | * Added: 123 | yard [">= 0"] (development) 124 | rspec [">= 0"] (development) 125 | mocha [">= 0"] (development) 126 | rake [">= 0"] (development) 127 | 0.14.0->0.15.0: 128 | * Added: 129 | simplecov [">= 0"] (development) 130 | pdf-reader ["~> 1.2"] (development) 131 | 1.0.0->1.1.0: 132 | * Added: 133 | prawn-manual_builder [">= 0.1.1"] (development) 134 | rubocop ["= 0.20.1"] (development) 135 | * Updated: 136 | rspec from: [">= 0"] to: ["= 2.14.1"] 137 | ``` 138 | 139 | #### Platforms 140 | 141 | *gem-compare* supports querying different gem platforms via standard `--platform` option. To compare 142 | nokogiri gem on different platform run: 143 | 144 | ```bash 145 | $ gem compare nokogiri 1.5.6 1.6.1 -ak --platform java # for JRuby 146 | $ gem compare nokogiri 1.5.6 1.6.1 -ak --platform x86-mingw32 # on Windows 147 | ``` 148 | 149 | #### Gems from different source server 150 | 151 | If you run your own gem source server, you can override the RubyGems.org default with 152 | `--sources SOURCE1,SOURCE2` option. 153 | 154 | 155 | ### Supported options 156 | 157 | To see all possible options run: 158 | 159 | ```bash 160 | $ gem compare --help 161 | ``` 162 | 163 | ## Requirements 164 | 165 | Currently tested against RubyGems 3.x. Use the `0.0.7` release for RubyGems 2.x. 166 | 167 | 168 | ## Copyright 169 | 170 | Made by [Josef Strzibny](https://strzibny.name). 171 | 172 | Released under the MIT license. Feel free to contribute! 173 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rdoc/task' 3 | 4 | Rake::RDocTask.new do |rd| 5 | rd.main = 'README.md' 6 | rd.rdoc_files.include('README.md', 'lib/**/*.rb') 7 | end 8 | 9 | Rake::TestTask.new('test') do |t| 10 | t.libs << 'test' 11 | t.pattern = 'test/**/test*.rb' 12 | t.verbose = true 13 | end 14 | 15 | task :default => [:test] 16 | -------------------------------------------------------------------------------- /gem-compare.gemspec: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib')) 2 | require 'rubygems/comparator/version' 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'gem-compare' 6 | s.version = Gem::Comparator::VERSION 7 | s.platform = Gem::Platform::RUBY 8 | s.summary = 'RubyGems plugin for comparing gem versions' 9 | s.description = <<-EOF 10 | gem-compare is a RubyGems plugin that helps to compare versions of the given gem. 11 | It searches for differences in metadata as well as in files. 12 | EOF 13 | s.homepage = 'http://github.com/fedora-ruby/gem-compare' 14 | s.licenses = ['MIT'] 15 | s.author = 'Josef Stribny' 16 | s.email = 'strzibny@strzibny.name' 17 | s.files = Dir['README.md', 'LICENSE', 'Rakefile', 'test/gemfiles/**/*', 18 | 'lib/**/*.rb', 'lib/**/**/*.rb', 'test/**/test*.rb'] 19 | s.required_ruby_version = '>= 3.0.0' 20 | s.required_rubygems_version = '>= 3.0.0' 21 | s.add_runtime_dependency 'json' 22 | s.add_runtime_dependency 'diffy' 23 | s.add_runtime_dependency 'rainbow' 24 | s.add_runtime_dependency 'gemnasium-parser' 25 | end 26 | -------------------------------------------------------------------------------- /lib/rubygems/commands/compare_command.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems/command' 2 | require 'rubygems/version_option' 3 | require 'rubygems/comparator' 4 | 5 | class Gem::Commands::CompareCommand < Gem::Command 6 | include Gem::VersionOption 7 | 8 | def initialize 9 | super 'compare', 'Compare gem\'s versions and generate a report of changes', 10 | :output => Dir.pwd 11 | 12 | add_option('-a', '--all', 'Show every comparison') do 13 | options[:log_all] = true 14 | end 15 | 16 | add_option('-k', '--keep-all', 'Keep downloaded and extracted gem files') do 17 | options[:keep_all] = true 18 | end 19 | 20 | add_option('-n', '--no-color', 'Do not colorize output') do 21 | options[:no_color] = true 22 | end 23 | 24 | # Speficy the platform using --platform=PLATFORM 25 | add_platform_option 26 | 27 | add_option('-pPARAM', '--param PARAM', 'Compare only a given gemspec parameter (like "version")') do |param, options| 28 | options[:param] = param 29 | end 30 | 31 | add_option('-r', '--runtime', 'Compare only runtime dependencies') do 32 | options[:param] = 'runtime_dependency' 33 | end 34 | 35 | add_option('-d', '--development', 'Compare only development dependencies') do 36 | options[:param] = 'development_dependency' 37 | end 38 | 39 | add_option('-f', '--files', 'Compare only files for runtime') do 40 | options[:param] = 'files' 41 | end 42 | 43 | add_option('-F', '--diff', 'Diff file contents') do 44 | options[:diff] = true 45 | options[:param] = 'files' 46 | end 47 | 48 | add_option('-g', '--gemfiles', 'Compare only Gemfiles') do 49 | options[:param] = 'gemfiles' 50 | end 51 | 52 | add_option('-b', '--brief', 'Include only important changes in the report') do 53 | options[:log_all] = false 54 | options[:brief] = true 55 | end 56 | 57 | add_option('-sSOURCES', '--sources SOURCES', 'Use different source URIs for gems (separated by comma)') do |sources, options| 58 | options[:sources] = sources.split ',' 59 | end 60 | 61 | end 62 | 63 | def arguments # :nodoc: 64 | args = <<-EOF 65 | GEMNAME gem name 66 | VERSION [VERSION ...] list of versions to compare 67 | EOF 68 | return args.gsub(/^\s+/, '') 69 | end 70 | 71 | def description # :nodoc: 72 | desc = <<-EOF 73 | gem-compare is a RubyGems plugin that compares versions of the given gem. 74 | It searches for differences in metadata as well as in files. 75 | EOF 76 | return desc.gsub(/^\s+/, '') 77 | end 78 | 79 | def usage # :nodoc: 80 | "#{program_name} GEMNAME VERSION [VERSION ...]" 81 | end 82 | 83 | def execute 84 | gem_name = options[:args].shift 85 | versions = options[:args] 86 | 87 | # No gem specified 88 | unless gem_name 89 | raise Gem::CommandLineError, 90 | "Please specify a gem (e.g. gem compare foo VERSION [VERSION ...])" 91 | end 92 | 93 | # No versions specified 94 | if versions.empty? 95 | raise Gem::CommandLineError, 96 | "Please specify versions you want to compare (e.g. gem compare foo 0.1.0 0.2.0)" 97 | end 98 | 99 | comparator = Gem::Comparator.new(options) 100 | comparator.compare_versions(gem_name, versions) 101 | comparator.print_results 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /lib/rubygems/comparator.rb: -------------------------------------------------------------------------------- 1 | require 'tmpdir' 2 | require 'rbconfig' 3 | require 'rainbow' 4 | require 'uri' 5 | require 'json' 6 | require 'rubygems/package' 7 | require 'rubygems/dependency' 8 | require 'rubygems/spec_fetcher' 9 | require 'rubygems/remote_fetcher' 10 | require 'rubygems/comparator/version' 11 | require 'rubygems/comparator/utils' 12 | require 'rubygems/comparator/report' 13 | require 'rubygems/comparator/spec_comparator' 14 | require 'rubygems/comparator/file_list_comparator' 15 | require 'rubygems/comparator/dependency_comparator' 16 | require 'rubygems/comparator/gemfile_comparator' 17 | 18 | ## 19 | # Gem::Comparator compares different version of the given 20 | # gem. It can compare spec values as well as file lists or 21 | # Gemfiles 22 | 23 | class Gem::Comparator 24 | include Gem::Comparator::Utils 25 | attr_accessor :options, :report 26 | 27 | ## 28 | # Set the working dir and process options 29 | # 30 | # Creates temporal directory if the gem files shouldn't be kept 31 | 32 | def initialize(options) 33 | info "gem-compare in #{VERSION}" 34 | 35 | unless options[:keep_all] 36 | options[:output] = Dir.mktmpdir 37 | end 38 | 39 | if options[:param] && !param_exists?(options[:param]) 40 | error 'Invalid parameter.' 41 | end 42 | 43 | if options[:no_color] 44 | Rainbow.enabled = false 45 | end 46 | 47 | # Let's override platforms with the latest one if 48 | # a platform has been specified via --platform 49 | if options[:added_platform] 50 | Gem.platforms = [Gem.platforms.last] 51 | options[:platform] = Gem.platforms.last.to_s 52 | info "Overriding platform to: #{options[:platform]}" 53 | end 54 | 55 | @options = options 56 | 57 | # Results from the comparison 58 | @report = Gem::Comparator::Report.new 59 | end 60 | 61 | ## 62 | # Compare versions 63 | # 64 | # Compares file lists, requirements, other meta data 65 | 66 | def compare_versions(gem_name, versions) 67 | # Expand versions (<=, >=, ~>) and sort them 68 | compared_versions = expand_versions(gem_name, versions) 69 | 70 | if versions.include?('_') && (compared_versions.size == 1) 71 | error 'Latest upstream version matches the version given. Nothing to compare.' 72 | elsif versions.include?('_') && (compared_versions.size == (versions.size - 1)) 73 | warn 'Latest upstream version matches one of the versions given.' 74 | elsif compared_versions.size == 1 75 | error 'Only one version specified. Specify at lease two versions.' 76 | end 77 | 78 | # This should match the final versions that has been compared 79 | @compared_versions = compared_versions 80 | 81 | compared_versions.each do |version| 82 | download_gems? ? 83 | get_package(gem_name, version) : 84 | get_specification(gem_name, version) 85 | end 86 | 87 | @report.set_header "Compared versions: #{@compared_versions}" 88 | 89 | comparators = [SpecComparator, 90 | FileListComparator, 91 | DependencyComparator, 92 | GemfileComparator] 93 | 94 | # Use different gem sources if specified 95 | with_sources @options[:sources] do 96 | comparators.each do |c| 97 | comparator = c.new 98 | cmp = (comparator.compares == :packages) ? gem_packages.values : gem_specs.values 99 | @report = comparator.compare(cmp, @report, @options) 100 | end 101 | end 102 | 103 | # Clean up 104 | FileUtils.rm_rf options[:output] unless options[:keep_all] 105 | end 106 | 107 | def print_results 108 | info 'Printing results...' 109 | @report.print 110 | end 111 | 112 | private 113 | 114 | def with_sources(sources, &block) 115 | if sources 116 | override_sources sources do 117 | yield 118 | end 119 | else 120 | yield 121 | end 122 | end 123 | 124 | def override_sources(new_sources, &block) 125 | original_sources = Gem.sources.clone 126 | old_sources = Gem.sources.to_a 127 | old_sources.each do |source_uri| 128 | Gem.sources.delete source_uri 129 | end 130 | new_sources.each do |source_uri| 131 | source = Gem::Source.new source_uri 132 | source.load_specs :released 133 | Gem.sources << source 134 | end 135 | Gem.configuration.write 136 | yield 137 | rescue URI::Error, ArgumentError 138 | error 'Given URI is not valid.' 139 | rescue Gem::RemoteFetcher::FetchError => e 140 | error "Fetching the gem from the given URI failed with the " + 141 | "following error:\n #{e.message}" 142 | ensure 143 | original_sources.each do |source_uri| 144 | source = Gem::Source.new source_uri 145 | source.load_specs :released 146 | Gem.sources << source 147 | end 148 | Gem.configuration.write 149 | end 150 | 151 | ## 152 | # If there is an unexpanded version in +versions+ such 153 | # as '>= 4.0.0' or '~>1.0.0', find all existing 154 | # +gem_name+ versions that match the criteria 155 | # 156 | # Return list of expanded versions 157 | 158 | def expand_versions(gem_name, versions) 159 | info "Expanding versions #{versions}..." 160 | expanded = [] 161 | versions.each do |version| 162 | version = latest_gem_version(gem_name) if version == '_' 163 | if version =~ VERSION_REGEX 164 | expanded << version 165 | next 166 | end 167 | op, v = (version.scan(/(>=|<=|~>|!=|>|<|=)\s*(.*)/)).flatten 168 | # Supported operator and version? 169 | if OPERATORS.include?(op) && v =~ VERSION_REGEX 170 | dep = Gem::Dependency.new gem_name, version 171 | specs_and_sources, _errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep 172 | specs_and_sources.each do |s| 173 | expanded << s[0].version 174 | end 175 | else 176 | warn "Unsupported version specification: #{version}, skipping." 177 | end 178 | end 179 | 180 | versions = expanded.uniq.map do |v| 181 | Gem::Version.new v 182 | end.sort.map(&:to_s) 183 | 184 | error 'No versions found.' if versions.size == 0 185 | 186 | info "Expanded versions: #{versions}" 187 | versions 188 | end 189 | 190 | def remote_gem_versions(gem_name) 191 | body_str = URI.open("https://rubygems.org/api/v1/versions/#{gem_name}.json").read 192 | json = JSON.parse(body_str) 193 | gems = json.collect { |version| version['number'] } 194 | info "Upstream versions: #{gems}" 195 | gems 196 | # "This rubygem could not be found." 197 | rescue JSON::ParserError 198 | error "Gem #{gem_name} does not exist." 199 | exit 1 200 | end 201 | 202 | def latest_gem_version(gem_name) 203 | remote_gem_versions(gem_name).map{ |v| Gem::Version.new v }.max.to_s 204 | end 205 | 206 | def gem_file_name(gem_name, version) 207 | if @options[:platform] 208 | "#{gem_name}-#{version}-#{@options[:platform]}.gem" 209 | else 210 | "#{gem_name}-#{version}.gem" 211 | end 212 | end 213 | 214 | def get_package(gem_name, version) 215 | gem_file = gem_file_name(gem_name, version) 216 | return gem_packages["#{gem_file}"] if gem_packages["#{gem_file}"] 217 | 218 | find_downloaded_gem(gem_file) 219 | return gem_packages["#{gem_file}"] if gem_packages["#{gem_file}"] 220 | 221 | download_package(gem_name, version) 222 | end 223 | 224 | def download_package(gem_name, version) 225 | spec, source = get_specification(gem_name, version) 226 | gem_file = gem_file_name(gem_name, spec.version.to_s) 227 | 228 | Dir.chdir @options[:output] do 229 | source.download spec 230 | end 231 | 232 | package = Gem::Package.new File.join(@options[:output], gem_file) 233 | use_package(package) 234 | info "#{gem_file} downloaded." 235 | 236 | package 237 | end 238 | 239 | def get_specification(gem_name, version) 240 | gem_file = gem_file_name(gem_name, version) 241 | return gem_specs["#{gem_file}"] if gem_specs["#{gem_file}"] 242 | 243 | find_downloaded_gem(gem_file) 244 | return gem_specs["#{gem_file}"] if gem_specs["#{gem_file}"] 245 | 246 | download_specification(gem_name, version) 247 | end 248 | 249 | def download_specification(gem_name, version) 250 | dep = Gem::Dependency.new gem_name, version 251 | specs_and_sources, _errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep 252 | spec, source = specs_and_sources.max_by { |s,| s.version } 253 | error "Gem #{gem_name} in #{version} doesn't exist." if spec.nil? 254 | 255 | fix_comparing_version(version, spec.version.to_s) 256 | gem_file = gem_file_name(gem_name, spec.version.to_s) 257 | 258 | gem_specs["#{gem_file}"] = spec 259 | 260 | [spec, source] 261 | end 262 | 263 | ## 264 | # Ensure the right version is referenced 265 | 266 | def fix_comparing_version(version, spec_version) 267 | if spec_version != version 268 | @compared_versions.each do |v| 269 | if v == version 270 | @compared_versions[@compared_versions.index(version)] = spec_version 271 | return 272 | end 273 | end 274 | end 275 | end 276 | 277 | def find_downloaded_gem(gem_file) 278 | if File.exist? File.join(@options[:output], gem_file) 279 | info "#{gem_file} exists, using already downloaded file." 280 | package = Gem::Package.new File.join(@options[:output], gem_file) 281 | use_package(package) 282 | [package, package.spec] 283 | else 284 | [nil, nil] 285 | end 286 | end 287 | 288 | def use_package(package) 289 | gem_file = gem_file_name(package.spec.name, package.spec.version) 290 | gem_packages["#{gem_file}"] = package 291 | gem_specs["#{gem_file}"] = package.spec 292 | end 293 | 294 | def download_gems? 295 | return true if @options[:keep_all] 296 | @options[:param] ? !param_available_in_marshal?(@options[:param]) : true 297 | end 298 | 299 | def gem_packages 300 | @gem_packages ||= {} 301 | end 302 | 303 | def gem_specs 304 | @gem_specs ||= {} 305 | end 306 | 307 | end 308 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/base.rb: -------------------------------------------------------------------------------- 1 | require 'rainbow' 2 | require 'rubygems/comparator/utils' 3 | require 'rubygems/comparator/report' 4 | 5 | class Gem::Comparator 6 | class Base 7 | include Gem::Comparator::Utils 8 | include Gem::Comparator::Report::Signs 9 | 10 | attr_accessor :compares 11 | 12 | ## 13 | # Compare Gem::Specification objects by default 14 | # 15 | # To override create your own initialize method and 16 | # set expect(:packages) to expect Gem::Package objects. 17 | 18 | def initialize 19 | expect(:specs) 20 | end 21 | 22 | private 23 | 24 | def expect(what) 25 | @compares = what 26 | end 27 | 28 | def extract_gem(package, target_dir) 29 | gem_file = File.basename(package.spec.full_name, '.gem') 30 | gem_dir = File.join(target_dir, gem_file) 31 | 32 | if Dir.exist? gem_dir 33 | info "Unpacked gem version exists, using #{gem_dir}." 34 | return gem_dir 35 | end 36 | 37 | info "Unpacking gem '#{package.spec.full_name}' in " + gem_dir 38 | package.extract_files gem_dir 39 | gem_dir 40 | end 41 | 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/dependency_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems/comparator/base' 2 | 3 | class Gem::Comparator 4 | 5 | ## 6 | # Gem::Comparator::DependencyComparator can 7 | # compare dependencies between gem's versions 8 | # based on the given Gem::Specification objects 9 | 10 | class DependencyComparator < Gem::Comparator::Base 11 | 12 | ## 13 | # Compare dependencies in given +specs+ and 14 | # write the changes to the +report+ 15 | # 16 | # If +options[:param]+ is set, it compares only 17 | # those dependencies 18 | 19 | def compare(specs, report, options = {}) 20 | info 'Checking dependencies...' 21 | 22 | filter_params(DEPENDENCY_PARAMS, options[:param]).each do |param| 23 | all_same = true 24 | type = param.gsub('_dependency', '').to_sym 25 | specs.each_with_index do |s, index| 26 | next if index == 0 27 | 28 | prev_deps = specs[index-1].dependencies.select { |d| d.type == type } 29 | curr_deps = specs[index].dependencies.select { |d| d.type == type } 30 | added, deleted, updated = resolve_dependencies(prev_deps, curr_deps) 31 | 32 | if (!deleted.empty? || !added.empty? || !updated.empty?) 33 | all_same = false 34 | end 35 | 36 | ver = "#{specs[index-1].version}->#{specs[index].version}" 37 | 38 | report[param][ver].section do 39 | set_header "#{Rainbow(specs[index-1].version).cyan}->#{Rainbow(s.version).cyan}:" 40 | 41 | nest('deleted').section do 42 | set_header '* Deleted:' 43 | puts deleted.map { |x| "#{x.name} #{x.requirements_list} (#{x.type})" } unless deleted.empty? 44 | end 45 | 46 | nest('added').section do 47 | set_header '* Added:' 48 | puts added.map { |x| "#{x.name} #{x.requirements_list} (#{x.type})" } unless added.empty? 49 | end 50 | 51 | nest('updated').section do 52 | set_header '* Updated:' 53 | puts updated unless updated.empty? 54 | end 55 | end 56 | end 57 | if all_same && options[:log_all] 58 | report[param].set_header "#{same} #{type} dependencies:" if options[:log_all] 59 | deps = specs[0].dependencies.select{ |d| d.type == type }.map{ |d| "#{d.name}: #{d.requirements_list}" } 60 | deps = '[]' if deps.empty? 61 | report[param] << deps 62 | elsif !all_same 63 | report[param].set_header "#{different} #{type} dependencies:" 64 | end 65 | end 66 | 67 | report 68 | end 69 | 70 | private 71 | 72 | ## 73 | # Find dependencies between +prev_deps+ and +curr_deps+ 74 | # 75 | # Return [added, deleted, updated] deps 76 | 77 | def resolve_dependencies(prev_deps, curr_deps) 78 | added = curr_deps - prev_deps 79 | deleted = prev_deps - curr_deps 80 | split_dependencies(added, deleted) 81 | end 82 | 83 | ## 84 | # Find updated dependencies between +added+ and 85 | # +deleted+ deps and move them out to +updated+. 86 | # 87 | # Return [added, deleted, updated] deps 88 | 89 | def split_dependencies(added, deleted) 90 | updated = [] 91 | added.dup.each do |ad| 92 | deleted.dup.each do |dd| 93 | if ad.name == dd.name 94 | unless ad.requirements_list == dd.requirements_list 95 | updated << "#{ad.name} " + 96 | "from: #{dd.requirements_list} " + 97 | "to: #{ad.requirements_list}" 98 | end 99 | added.delete ad 100 | deleted.delete dd 101 | end 102 | end 103 | end 104 | [added, deleted, updated] 105 | end 106 | 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/dir_utils.rb: -------------------------------------------------------------------------------- 1 | require 'pathname' 2 | 3 | class Gem::Comparator 4 | module DirUtils 5 | SHEBANG_REGEX = /\A#!.*/ 6 | 7 | attr_accessor :files_first_line 8 | 9 | def self.file_first_line(file) 10 | File.open(file){ |f| f.readline }.gsub(/(.*)\n/, '\1') 11 | rescue 12 | end 13 | 14 | def self.file_has_shebang?(file) 15 | file_first_line(file) =~ SHEBANG_REGEX 16 | end 17 | 18 | def self.files_same_first_line?(file1, file2) 19 | file_first_line(file1) == file_first_line(file2) 20 | end 21 | 22 | def self.gem_bin_file?(file) 23 | file =~ /(\A|.*\/)bin\/.*/ 24 | end 25 | 26 | ## 27 | # Returns a unique list of directories and top level files 28 | # out of an array of files 29 | 30 | def self.dirs_of_files(file_list) 31 | dirs_of_files = [] 32 | file_list.each do |file| 33 | unless Pathname.new(file).dirname.to_s == '.' 34 | dirs_of_files << "#{Pathname.new(file).dirname.to_s}/" 35 | else 36 | dirs_of_files << file 37 | end 38 | end 39 | dirs_of_files.uniq 40 | end 41 | 42 | def self.remove_subdirs(dirs) 43 | dirs.dup.sort_by(&:length).reverse.each do |dir| 44 | dirs.delete_if{ |d| d =~ /#{dir}\/.+/ } 45 | end 46 | dirs 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/file_list_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'diffy' 2 | require 'rubygems/comparator/base' 3 | require 'rubygems/comparator/dir_utils' 4 | require 'rubygems/comparator/monitor' 5 | 6 | class Gem::Comparator 7 | 8 | ## 9 | # Gem::Comparator::FileListComparator can 10 | # compare file lists from gem's specs 11 | # based on the given Gem::Package objects 12 | # 13 | # To compare the files it needs to extract 14 | # gem packages to +options[:output]+ 15 | 16 | class FileListComparator < Gem::Comparator::Base 17 | 18 | def initialize(ignore_group_writable=true) 19 | expect(:packages) 20 | 21 | # We need diff 22 | begin 23 | IO.popen('diff --version') 24 | rescue Exception 25 | error('Calling `diff` command failed. Do you have it installed?') 26 | end 27 | 28 | @ignore_group_writable = ignore_group_writable 29 | end 30 | 31 | ## 32 | # Compare file lists for gem's Gem::Package objects 33 | # in +packages+ and writes the changes to the +report+ 34 | # 35 | # If +options[:param]+ is set, it compares only 36 | # that file list 37 | 38 | def compare(packages, report, options = {}) 39 | info 'Checking file lists...' 40 | 41 | @packages = packages 42 | 43 | # Check file lists from older versions to newer 44 | filter_params(SPEC_FILES_PARAMS, options[:param]).each do |param| 45 | all_same = true 46 | 47 | packages.each_with_index do |pkg, index| 48 | unpacked_gem_dirs[packages[index].spec.version] = extract_gem(pkg, options[:output]) 49 | next if index == 0 50 | 51 | # File lists as arrays 52 | previous = value_from_spec(param, packages[index-1].spec) 53 | current = value_from_spec(param, pkg.spec) 54 | next unless (previous && current) 55 | 56 | vers = "#{packages[index-1].spec.version}->#{packages[index].spec.version}" 57 | 58 | deleted = previous - current 59 | added = current - previous 60 | same = current - added 61 | 62 | if options[:brief] 63 | deleted, dirs_added = dir_changed(previous, current) 64 | end 65 | 66 | report[param].set_header "#{different} #{param}:" 67 | 68 | report[param][vers].section do 69 | set_header "#{Rainbow(packages[index-1].spec.version).cyan}->" + 70 | "#{Rainbow(packages[index].spec.version).cyan}:" 71 | nest('deleted').section do 72 | set_header '* Deleted:' 73 | puts deleted unless deleted.empty? 74 | end 75 | 76 | nest('added').section do 77 | set_header '* Added:' 78 | puts dirs_added if options[:brief] 79 | end 80 | end 81 | # Add information about permissions, shebangs etc. 82 | report = check_added_files(param, vers, index, added, report, options[:brief], options[:diff]) 83 | 84 | report[param][vers]['changed'].set_header '* Changed:' 85 | report = check_same_files(param, vers, index, same, report, options[:brief], options[:diff]) 86 | same_files = report[param][vers]['changed'].messages.empty? 87 | all_same = false unless same_files 88 | 89 | if previous == current && same_files && !all_same 90 | report[param][vers] << "#{Rainbow(packages[index-1].spec.version).cyan}->" + \ 91 | "#{Rainbow(packages[index].spec.version).cyan}: No change" 92 | end 93 | 94 | end 95 | 96 | if all_same && options[:log_all] 97 | report[param].set_header "#{same} #{param}:" 98 | value = value_from_spec(param, @packages[0].spec) 99 | value = '[]' if value.empty? 100 | report[param] << value 101 | end 102 | end 103 | report 104 | end 105 | 106 | private 107 | 108 | ## 109 | # Access @unpacked_gem_dirs hash that stores 110 | # paths to the unpacked gem dirs 111 | # 112 | # Keys of the hash are gem's versions 113 | 114 | def unpacked_gem_dirs 115 | @unpacked_gem_dirs ||= {} 116 | end 117 | 118 | ## 119 | # This returns [deleted, added] directories between 120 | # +previous+ and +current+ file lists 121 | # 122 | # For top level (.) it compares files themselves 123 | 124 | def dir_changed(previous, current) 125 | prev_dirs = DirUtils.dirs_of_files(previous) 126 | curr_dirs = DirUtils.dirs_of_files(current) 127 | deleted = DirUtils.remove_subdirs(prev_dirs - curr_dirs) 128 | added = DirUtils.remove_subdirs(curr_dirs - prev_dirs) 129 | [deleted, added] 130 | end 131 | 132 | def check_added_files(param, vers, index, files, report, brief_mode, diff_mode) 133 | files.each do |file| 134 | added_file = File.join(unpacked_gem_dirs[@packages[index].spec.version], file) 135 | 136 | line_changes = if diff_mode 137 | Monitor.files_diff(nil, added_file) 138 | else 139 | Monitor.lines_changed(nil, added_file) 140 | end 141 | 142 | changes = Monitor.new_file_permissions(added_file, @ignore_group_writable), 143 | Monitor.new_file_executability(added_file), 144 | Monitor.new_file_shebang(added_file) 145 | 146 | if(!changes.join.empty? || (!brief_mode && !line_changes.empty?)) 147 | if diff_mode 148 | report[param][vers]['added'][file].set_header file 149 | report[param][vers]['added'][file] << line_changes.split("\n") 150 | else 151 | report[param][vers]['added'] << "#{file} #{line_changes}" 152 | end 153 | end 154 | 155 | changes.each do |change| 156 | report[param][vers]['added'] << change unless change.empty? 157 | end 158 | end 159 | report 160 | end 161 | 162 | def check_same_files(param, vers, index, files, report, brief_mode, diff_mode) 163 | files.each do |file| 164 | prev_file = File.join(unpacked_gem_dirs[@packages[index-1].spec.version], file) 165 | curr_file = File.join(unpacked_gem_dirs[@packages[index].spec.version], file) 166 | 167 | next unless check_files([prev_file, curr_file]) 168 | 169 | line_changes = if diff_mode 170 | Monitor.files_diff(prev_file, curr_file) 171 | else 172 | Monitor.lines_changed(prev_file, curr_file) 173 | end 174 | 175 | changes = Monitor.files_permissions_changes(prev_file, curr_file, @ignore_group_writable), 176 | Monitor.files_executability_changes(prev_file, curr_file), 177 | Monitor.files_shebang_changes(prev_file, curr_file) 178 | 179 | if(!changes.join.empty? || (!brief_mode && !line_changes.empty?)) 180 | if diff_mode 181 | report[param][vers]['changed'][file].set_header file 182 | report[param][vers]['changed'][file] << line_changes.split("\n") 183 | else 184 | report[param][vers]['changed'] << "#{file} #{line_changes}" 185 | end 186 | end 187 | 188 | changes.each do |change| 189 | report[param][vers]['changed'] << change unless change.empty? 190 | end 191 | end 192 | report 193 | end 194 | 195 | ## 196 | # Check that files exist 197 | 198 | def check_files(files) 199 | files.each do |file| 200 | unless File.exist? file 201 | warn "#{file} mentioned in spec does not exist " + 202 | "in the gem package, skipping check" 203 | return false 204 | end 205 | end 206 | true 207 | end 208 | 209 | end 210 | end 211 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/gemfile_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'gemnasium/parser' 2 | require 'rubygems/comparator/base' 3 | 4 | class Gem::Comparator 5 | 6 | ## 7 | # Gem::Comparator::GemfileComparator can 8 | # compare dependencies between gem's Gemfiles 9 | # based on the given Gem::Package objects 10 | # 11 | # To compare Gemfiles it needs to extract 12 | # gem packages to +options[:output]+ 13 | 14 | class GemfileComparator < Gem::Comparator::Base 15 | 16 | def initialize 17 | expect(:packages) 18 | end 19 | 20 | ## 21 | # Compare Gemfiles using gem's +packages+ 22 | # and write the changes to the +report+ 23 | 24 | def compare(packages, report, options = {}) 25 | info 'Checking Gemfiles for dependencies...' 26 | return report if options[:param] && options[:param] != 'gemfiles' 27 | 28 | @packages = packages 29 | all_same = true 30 | 31 | # Check Gemfiles from older versions to newer 32 | packages.each_with_index do |pkg, index| 33 | unpacked_gem_dirs[@packages[index].spec.version] = extract_gem(pkg, options[:output]) 34 | next if index == 0 35 | 36 | prev_gemfile = File.join(unpacked_gem_dirs[@packages[index-1].spec.version], 'Gemfile') 37 | curr_gemfile = File.join(unpacked_gem_dirs[@packages[index].spec.version], 'Gemfile') 38 | 39 | vers = "#{@packages[index-1].spec.version}->#{@packages[index].spec.version}" 40 | report['gemfiles'][vers].set_header "#{Rainbow(packages[index-1].spec.version).cyan}->" + 41 | "#{Rainbow(packages[index].spec.version).cyan}:" 42 | 43 | added, deleted, updated = compare_gemfiles(prev_gemfile, curr_gemfile) 44 | 45 | report['gemfiles'][vers]['added'].section do 46 | set_header '* Added:' 47 | puts added.map { |x| "#{x.name} #{x.requirements_list} (#{x.type})" } unless added.empty? 48 | end 49 | report['gemfiles'][vers]['deleted'].section do 50 | set_header '* Deleted' 51 | puts deleted.map { |x| "#{x.name} #{x.requirements_list} (#{x.type})" } unless deleted.empty? 52 | end 53 | report['gemfiles'][vers]['updated'].section do 54 | set_header '* Updated' 55 | puts updated unless updated.empty? 56 | end 57 | all_same = false if !added.empty? || !deleted.empty? 58 | end 59 | if all_same && options[:log_all] 60 | report['gemfiles'].set_header "#{same} Gemfiles:" 61 | gemfile = File.join(unpacked_gem_dirs[@packages[1].spec.version], 'Gemfile') 62 | if File.exist? gemfile 63 | deps = gemfile_deps(gemfile) 64 | deps = '[]' if deps.empty? 65 | report['gemfiles'] << deps 66 | else 67 | report['gemfiles'] << 'No Gemfiles' 68 | end 69 | elsif !all_same 70 | report['gemfiles'].set_header "#{different} Gemfile dependencies" 71 | end 72 | 73 | report 74 | end 75 | 76 | private 77 | 78 | ## 79 | # Access @unpacked_gem_dirs hash that stores 80 | # paths to the unpacked gem dirs 81 | # 82 | # Keys of the hash are gem's versions 83 | 84 | def unpacked_gem_dirs 85 | @unpacked_gem_dirs ||= {} 86 | end 87 | 88 | ## 89 | # Compare two Gemfiles for dependencies 90 | # 91 | # Return [added, deleted, updated] deps 92 | 93 | def compare_gemfiles(prev_gemfile, curr_gemfile) 94 | prev_deps = gemfile_deps(prev_gemfile) 95 | curr_deps = gemfile_deps(curr_gemfile) 96 | added = curr_deps - prev_deps 97 | deleted = prev_deps - curr_deps 98 | 99 | split_dependencies(added, deleted) 100 | end 101 | 102 | ## 103 | # Get the Gemfile dependencies from +gemfile+ 104 | 105 | def gemfile_deps(gemfile) 106 | if File.exist?(gemfile) 107 | parse_gemfile(gemfile).dependencies 108 | else 109 | [] 110 | end 111 | end 112 | 113 | ## 114 | # Parse +gemfile+ using Gemnasium::Parser 115 | # 116 | # Return Gemnasium::Parser::Gemfile 117 | 118 | def parse_gemfile(gemfile) 119 | Gemnasium::Parser.gemfile File.open(gemfile).read 120 | end 121 | 122 | ## 123 | # Find updated dependencies between +added+ and 124 | # +deleted+ deps and move them out to +updated+. 125 | # 126 | # Return [added, deleted, updated] deps 127 | 128 | def split_dependencies(added, deleted) 129 | updated = [] 130 | added.dup.each do |ad| 131 | deleted.dup.each do |dd| 132 | if ad.name == dd.name && ad.type == dd.type 133 | unless ad.requirements_list == dd.requirements_list 134 | updated << "#{ad.name} " + 135 | "from: #{dd.requirements_list} " + 136 | "to: #{ad.requirements_list}" 137 | end 138 | added.delete ad 139 | deleted.delete dd 140 | end 141 | end 142 | end 143 | [added, deleted, updated] 144 | end 145 | 146 | end 147 | end 148 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/monitor.rb: -------------------------------------------------------------------------------- 1 | require 'diffy' 2 | require 'rubygems/comparator/base' 3 | require 'rubygems/comparator/dir_utils' 4 | 5 | class Gem::Comparator 6 | module Monitor 7 | 8 | def self.lines_changed(prev_file, curr_file) 9 | line = compact_files_diff(prev_file, curr_file) 10 | return '' if line.empty? 11 | plus = "+#{line.count('+')}" 12 | minus = "-#{line.count('-')}" 13 | "#{Rainbow(plus).green}/#{Rainbow(minus).red}" 14 | end 15 | 16 | def self.compact_files_diff(prev_file, curr_file) 17 | prev_file = prev_file.nil? ? Tempfile.new.path : prev_file 18 | changes = '' 19 | Diffy::Diff.new( 20 | prev_file, curr_file, :source => 'files', :context => 0 21 | ).each do |line| 22 | case line 23 | when /^\+/ then changes << Rainbow('+').green 24 | when /^-/ then changes << Rainbow('-').red 25 | end 26 | end 27 | changes 28 | end 29 | 30 | def self.files_diff(prev_file, curr_file) 31 | prev_file = prev_file.nil? ? Tempfile.new.path : prev_file 32 | changes = '' 33 | Diffy::Diff.new( 34 | prev_file, curr_file, :source => 'files', :context => 0, :include_diff_info => true 35 | ).each do |line| 36 | case line 37 | when /^\+/ then changes << Rainbow(line).green 38 | when /^-/ then changes << Rainbow(line).red 39 | else changes << line 40 | end 41 | end 42 | changes 43 | end 44 | 45 | def self.files_permissions_changes(prev_file, curr_file, ignore_group_writable=false) 46 | prev_permissions = File.stat(prev_file).mode 47 | curr_permissions = File.stat(curr_file).mode 48 | 49 | diff = prev_permissions ^ curr_permissions 50 | diff ^= 020 if diff != 0 && ignore_group_writable 51 | 52 | if diff != 0 53 | " (!) New permissions: " + 54 | "#{format_permissions(prev_permissions)} -> #{format_permissions(curr_permissions)}" 55 | else 56 | '' 57 | end 58 | end 59 | 60 | def self.new_file_permissions(file, ignore_group_writable=false) 61 | file_permissions = File.stat(file).mode 62 | 63 | expected_permissions = if DirUtils.gem_bin_file?(file) 64 | 0100755 65 | else 66 | 0100644 67 | end 68 | 69 | permissions_to_compare = if ignore_group_writable && file_permissions != expected_permissions 70 | file_permissions ^ 020 71 | else 72 | file_permissions 73 | end 74 | 75 | unless permissions_to_compare == expected_permissions 76 | return " (!) Unexpected permissions: #{format_permissions(file_permissions)}" 77 | end 78 | '' 79 | end 80 | 81 | def self.files_executability_changes(prev_file, curr_file) 82 | prev_executable = File.stat(prev_file).executable? 83 | curr_executable = File.stat(curr_file).executable? 84 | 85 | if !prev_executable && curr_executable 86 | " (!) File is now executable!" 87 | elsif prev_executable && !curr_executable 88 | " (!) File is no longer executable!" 89 | else 90 | '' 91 | end 92 | end 93 | 94 | def self.new_file_executability(file) 95 | file_executable = File.stat(file).executable? 96 | 97 | if file_executable && !DirUtils.gem_bin_file?(file) 98 | " (!) File is executable" 99 | elsif !file_executable && DirUtils.gem_bin_file?(file) 100 | " (!) File is not executable" 101 | else 102 | '' 103 | end 104 | end 105 | 106 | def self.files_shebang_changes(prev_file, curr_file) 107 | return '' if DirUtils.files_same_first_line?(prev_file, curr_file) 108 | 109 | prev_has_shebang = DirUtils.file_has_shebang? prev_file 110 | curr_has_shebang = DirUtils.file_has_shebang? curr_file 111 | 112 | if prev_has_shebang && !curr_has_shebang 113 | " (!) Shebang probably lost: #{DirUtils.file_first_line(prev_file)}" 114 | elsif !prev_has_shebang && curr_has_shebang 115 | " (!) Shebang probably added: #{DirUtils.file_first_line(curr_file)}" 116 | elsif prev_has_shebang && curr_has_shebang 117 | " (!) Shebang probably changed: " + 118 | "#{first_lines[prev_file]} -> #{DirUtils.file_first_line(curr_file)}" 119 | else 120 | '' 121 | end 122 | end 123 | 124 | def self.new_file_shebang(file) 125 | file_has_shebang = DirUtils.file_has_shebang? file 126 | 127 | if file_has_shebang 128 | " (!) Shebang found: #{DirUtils.file_first_line(file)}" 129 | else 130 | '' 131 | end 132 | end 133 | 134 | def self.format_permissions(permissions) 135 | sprintf("%o", permissions) 136 | end 137 | end 138 | end 139 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/report.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems/comparator/report/entry' 2 | 3 | class Gem::Comparator 4 | 5 | ## 6 | # Gem::Comparator::Report can nest sections and print only those that 7 | # contain some messages. 8 | # 9 | # Usage: 10 | # report = Gem::Comparator::Report.new 11 | # report['section1'] << "Message 1" 12 | # report['section1']['subsection1'].set_header 'Message 2 Header' 13 | # report['section1']['subsection1'] << "Message 2" if false 14 | # report['section1'].section 15 | # nest('subsection2').section 16 | # puts "Message 3" 17 | # end 18 | # end 19 | # report.print 20 | # 21 | # This won't print Message 2 nor its header saving a lot of if/else. 22 | 23 | class Report 24 | 25 | module Signs 26 | def same 27 | Rainbow('SAME').green.bright 28 | end 29 | 30 | def different 31 | Rainbow('DIFFERENT').red.bright 32 | end 33 | end 34 | 35 | def self.new(name = 'main') 36 | Gem::Comparator::Report::NestedSection.new(name) 37 | end 38 | 39 | class NestedSection 40 | include Report::Signs 41 | include Gem::UserInteraction 42 | 43 | DEFAULT_INDENT = ' ' 44 | 45 | attr_reader :header, :messages, :parent_section, :level 46 | attr_accessor :name, :sections 47 | 48 | def initialize(name, parent_section = nil) 49 | @name = name 50 | @header = Entry.new 51 | @messages = [] 52 | @sections = [] 53 | @level = 0 54 | 55 | set_parent parent_section if parent_section 56 | end 57 | 58 | def section(&block) 59 | instance_eval(&block) 60 | end 61 | 62 | def set_header(message) 63 | @header = Entry.new(message) 64 | end 65 | 66 | def puts(message) 67 | case message 68 | when String, Array 69 | @messages << Entry.new(message) unless message.empty? 70 | else 71 | @messages << Entry.new(message) unless message 72 | end 73 | end 74 | alias_method :<<, :puts 75 | 76 | def nest(name) 77 | @sections.each do |s| 78 | return s if s.name == name 79 | end 80 | NestedSection.new(name, self) 81 | end 82 | alias_method :[], :nest 83 | 84 | def print 85 | all_messages.each { |m| m.print } 86 | end 87 | 88 | def all_messages 89 | indent = DEFAULT_INDENT*@level 90 | 91 | if @header.empty? 92 | @messages.map do |m| 93 | m.set_indent!(indent) 94 | end + nested_messages 95 | else 96 | nested = @messages.map do |m| 97 | m.set_indent!(indent * 2) 98 | end + nested_messages 99 | return [] if nested.empty? 100 | 101 | @header.set_indent!(indent) 102 | nested.unshift(@header) 103 | end 104 | end 105 | 106 | def lines(line_num) 107 | all_messages[line_num]&.data 108 | end 109 | 110 | def nested_messages 111 | nested_messages = [] 112 | @sections.each do |section| 113 | section.all_messages.each do |m| 114 | nested_messages << m 115 | end 116 | end 117 | nested_messages 118 | end 119 | 120 | private 121 | 122 | def set_parent(parent) 123 | parent.sections << self 124 | @level = parent.level + 1 125 | end 126 | 127 | end 128 | end 129 | end 130 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/report/entry.rb: -------------------------------------------------------------------------------- 1 | class Gem::Comparator 2 | class Report 3 | class Entry 4 | include Gem::UserInteraction 5 | 6 | attr_accessor :data, :indent 7 | 8 | def initialize(data = '', indent = '') 9 | @data = data 10 | @indent = indent 11 | end 12 | 13 | def set_indent!(indent) 14 | @indent = indent 15 | self 16 | end 17 | 18 | def empty? 19 | case @data 20 | when String, Array 21 | @data.empty? 22 | end 23 | end 24 | 25 | def print 26 | printed = case @data 27 | when String 28 | "#{@indent}#{@data}" 29 | when Array 30 | @indent + @data.join("\n#{@indent}") 31 | else 32 | "#{@indent}#{@data}" 33 | end 34 | say printed 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/spec_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems/comparator/base' 2 | 3 | class Gem::Comparator 4 | 5 | ## 6 | # Gem::Comparator::SpecComparator can 7 | # compare values from the gem verions specs 8 | 9 | class SpecComparator < Gem::Comparator::Base 10 | 11 | ## 12 | # Compare common fields in spec 13 | 14 | def compare(specs, report, options = {}) 15 | info 'Checking spec parameters...' 16 | p = options[:param] 17 | b = options[:brief] 18 | 19 | filter_params(SPEC_PARAMS, p, b).each do |param| 20 | values = values_from_specs(param, specs) 21 | 22 | if same_values?(values) && options[:log_all] 23 | v = value(values[0]) 24 | report[param].section do 25 | set_header "#{self.same} #{param}:" 26 | puts v 27 | end 28 | elsif !same_values?(values) 29 | report[param].set_header "#{different} #{param}:" 30 | values.each_with_index do |value, index| 31 | report[param] << \ 32 | "#{Rainbow(specs[index].version).cyan}: #{value}" 33 | end 34 | end 35 | end 36 | report 37 | end 38 | 39 | private 40 | 41 | def value(value) 42 | case value 43 | when Gem::Requirement 44 | unless value.requirements.empty? 45 | r = value.requirements[0] 46 | "#{r[0]} #{r[1].version} " 47 | else 48 | '[]' 49 | end 50 | when Gem::Platform 51 | value.to_s 52 | when String 53 | return value unless value.empty? 54 | '' 55 | else 56 | value.inspect 57 | end 58 | end 59 | 60 | def same_values?(values) 61 | values.count(values[0]) == values.size 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/utils.rb: -------------------------------------------------------------------------------- 1 | require 'rainbow' 2 | require 'rubygems' 3 | require 'rubygems/user_interaction' 4 | 5 | class Gem::Comparator 6 | module Utils 7 | include Gem::UserInteraction 8 | 9 | SPACE = ' ' 10 | DEFAULT_INDENT = SPACE*7 11 | OPERATORS = ['=', '!=', '>', '<', '>=', '<=', '~>'] 12 | VERSION_REGEX = /\A(\d+\.){0,}\d+(\.[a-zA-Z]+\.{0,1}\d{0,1}){0,1}\z/ 13 | SPEC_PARAMS = %w[ author 14 | authors 15 | bindir 16 | cert_chain 17 | date 18 | description 19 | email 20 | executables 21 | extensions 22 | homepage 23 | license 24 | licenses 25 | metadata 26 | name 27 | platform 28 | post_install_message 29 | rdoc_options 30 | require_paths 31 | required_ruby_version 32 | required_rubygems_version 33 | requirements 34 | rubygems_version 35 | signing_key 36 | summary 37 | version ] 38 | SPEC_FILES_PARAMS = %w[ files 39 | test_files 40 | extra_rdoc_files ] 41 | DEPENDENCY_PARAMS = %w[ runtime_dependency 42 | development_dependency ] 43 | GEMFILE_PARAMS = %w[ gemfiles ] 44 | 45 | # Duplicates or obvious changes 46 | FILTER_WHEN_BRIEF = %w[ author 47 | date 48 | license 49 | platform 50 | rubygems_version 51 | version ] 52 | 53 | # Not present in marshal file containing the specs 54 | NOT_IN_MARSHAL = %w[ cert_chain 55 | executables 56 | extensions 57 | extra_rdoc_files 58 | files 59 | license 60 | licenses 61 | metadata 62 | post_install_message 63 | rdoc_options 64 | requirements 65 | signing_key 66 | test_files ] 67 | 68 | private 69 | 70 | def param_exists?(param) 71 | (SPEC_PARAMS.include? param) || 72 | (SPEC_FILES_PARAMS.include? param) || 73 | (DEPENDENCY_PARAMS.include? param) || 74 | (GEMFILE_PARAMS.include? param) 75 | end 76 | 77 | def param_available_in_marshal?(param) 78 | param_exists?(param) && !NOT_IN_MARSHAL.include?(param) 79 | end 80 | 81 | def filter_params(params, param, brief_mode = false) 82 | if param 83 | if params.include? param 84 | return [param] 85 | else 86 | return [] 87 | end 88 | end 89 | if brief_mode 90 | filter_for_brief_mode(params) 91 | else 92 | params 93 | end 94 | end 95 | 96 | def filter_for_brief_mode(params) 97 | params.delete_if{ |p| FILTER_WHEN_BRIEF.include?(p) } 98 | end 99 | 100 | def values_from_specs(param, specs) 101 | values = [] 102 | specs.each do |s| 103 | val = value_from_spec(param, s) 104 | values << val if val 105 | end 106 | values 107 | end 108 | 109 | def value_from_spec(param, spec) 110 | if spec.respond_to? :"#{param}" 111 | spec.send(:"#{param}") 112 | else 113 | warn "#{spec.full_name} does not respond to " + 114 | "#{param}, skipping check" 115 | nil 116 | end 117 | end 118 | 119 | def info(msg) 120 | say msg if Gem.configuration.really_verbose 121 | end 122 | 123 | def warn(msg) 124 | say Rainbow("WARNING: #{msg}").red 125 | end 126 | 127 | def error(msg) 128 | say Rainbow("ERROR: #{msg}").red 129 | exit 1 130 | end 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /lib/rubygems/comparator/version.rb: -------------------------------------------------------------------------------- 1 | class Gem::Comparator 2 | VERSION = '1.2.1' 3 | end 4 | -------------------------------------------------------------------------------- /lib/rubygems_plugin.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems/command_manager' 2 | Gem::CommandManager.instance.register_command :compare 3 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fedora-ruby/gem-compare/6b221bcf37b30a9dda05d0a2d7d677bee52ef097/test/gemfiles/lorem-0.0.1.gem -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in lorem.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Josef Stribny 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1/README.md: -------------------------------------------------------------------------------- 1 | # Lorem 2 | 3 | TODO: Write a gem description 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | gem 'lorem' 10 | 11 | And then execute: 12 | 13 | $ bundle 14 | 15 | Or install it yourself as: 16 | 17 | $ gem install lorem 18 | 19 | ## Usage 20 | 21 | TODO: Write usage instructions here 22 | 23 | ## Contributing 24 | 25 | 1. Fork it ( https://github.com/[my-github-username]/lorem/fork ) 26 | 2. Create your feature branch (`git checkout -b my-new-feature`) 27 | 3. Commit your changes (`git commit -am 'Add some feature'`) 28 | 4. Push to the branch (`git push origin my-new-feature`) 29 | 5. Create a new Pull Request 30 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1/lib/lorem.rb: -------------------------------------------------------------------------------- 1 | require "lorem/version" 2 | 3 | module Lorem 4 | def hello_world 5 | puts 'Hello World' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1/lib/lorem/version.rb: -------------------------------------------------------------------------------- 1 | module Lorem 2 | VERSION = "0.0.1" 3 | end 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.1/lorem.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'lorem/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "lorem" 8 | spec.version = Lorem::VERSION 9 | spec.authors = ["Josef Stribny"] 10 | spec.email = ["jstribny@redhat.com"] 11 | spec.summary = "lorem is a gem for testing gem-compare" 12 | spec.description = "lorem changes a lot so we can test gem-compare a lot" 13 | spec.homepage = "" 14 | spec.license = "MIT" 15 | 16 | spec.files = ["lorem.gemspec", "Gemfile", "Rakefile", "LICENSE.txt", "README.md"] + 17 | Dir.glob("lib/**/*") 18 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.6" 23 | spec.add_development_dependency "rake" 24 | end 25 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fedora-ruby/gem-compare/6b221bcf37b30a9dda05d0a2d7d677bee52ef097/test/gemfiles/lorem-0.0.2.gem -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | lorem 0.0.2 2 | =========== 3 | 4 | - add changelog file 5 | - change license to GPLv2 6 | - add new method to lib/lorem.rb 7 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in lorem.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Josef Stribny 2 | 3 | You can use this library under GPLv2 conditions. 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/README.md: -------------------------------------------------------------------------------- 1 | # Lorem 2 | 3 | TODO: Write a gem description 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | gem 'lorem' 10 | 11 | And then execute: 12 | 13 | $ bundle 14 | 15 | Or install it yourself as: 16 | 17 | $ gem install lorem 18 | 19 | ## Usage 20 | 21 | TODO: Write usage instructions here 22 | 23 | ## Contributing 24 | 25 | 1. Fork it ( https://github.com/[my-github-username]/lorem/fork ) 26 | 2. Create your feature branch (`git checkout -b my-new-feature`) 27 | 3. Commit your changes (`git commit -am 'Add some feature'`) 28 | 4. Push to the branch (`git push origin my-new-feature`) 29 | 5. Create a new Pull Request 30 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/lib/lorem.rb: -------------------------------------------------------------------------------- 1 | require "lorem/version" 2 | 3 | module Lorem 4 | def hello_world 5 | puts 'Hello World' 6 | end 7 | 8 | def new_method 9 | raise 'needs to be implemented' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/lib/lorem/version.rb: -------------------------------------------------------------------------------- 1 | module Lorem 2 | VERSION = "0.0.2" 3 | end 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.2/lorem.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'lorem/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "lorem" 8 | spec.version = Lorem::VERSION 9 | spec.authors = ["Josef Stribny"] 10 | spec.email = ["jstribny@redhat.com"] 11 | spec.summary = "lorem is a gem for testing gem-compare" 12 | spec.description = "lorem changes a lot so we can test gem-compare a lot" 13 | spec.homepage = "" 14 | spec.license = "GPLv2" 15 | 16 | spec.files = ["lorem.gemspec", "CHANGELOG.md", "Gemfile", "Rakefile", "LICENSE.txt", "README.md"] + 17 | Dir.glob("lib/**/*") 18 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.6" 23 | spec.add_development_dependency "rake" 24 | end 25 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fedora-ruby/gem-compare/6b221bcf37b30a9dda05d0a2d7d677bee52ef097/test/gemfiles/lorem-0.0.3.gem -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | lorem 0.0.3 2 | =========== 3 | 4 | - add homepage 5 | - add some lib files 6 | - add an executable file 7 | - change dependencies in gemspec and Gemfile 8 | 9 | lorem 0.0.2 10 | =========== 11 | 12 | - add changelog file 13 | - change license to GPLv2 14 | - add new method to lib/lorem.rb 15 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in lorem.gemspec 4 | gemspec 5 | 6 | gem 'minitest' 7 | gem 'appraisal' 8 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Josef Stribny 2 | 3 | You can use this library under GPLv2 conditions. 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/README.md: -------------------------------------------------------------------------------- 1 | # Lorem 2 | 3 | TODO: Write a gem description 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | gem 'lorem' 10 | 11 | And then execute: 12 | 13 | $ bundle 14 | 15 | Or install it yourself as: 16 | 17 | $ gem install lorem 18 | 19 | ## Usage 20 | 21 | TODO: Write usage instructions here 22 | 23 | ## Contributing 24 | 25 | 1. Fork it ( https://github.com/[my-github-username]/lorem/fork ) 26 | 2. Create your feature branch (`git checkout -b my-new-feature`) 27 | 3. Commit your changes (`git commit -am 'Add some feature'`) 28 | 4. Push to the branch (`git push origin my-new-feature`) 29 | 5. Create a new Pull Request 30 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/bin/lorem: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | puts 'Lorem Executable!' 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/lib/lorem.rb: -------------------------------------------------------------------------------- 1 | require "lorem/version" 2 | 3 | module Lorem 4 | def hello_world 5 | puts 'Hello World' 6 | end 7 | 8 | def new_method 9 | raise 'needs to be implemented' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/lib/lorem/utils.rb: -------------------------------------------------------------------------------- 1 | def check_something 2 | 3 | end 4 | 5 | def make_something 6 | 7 | end 8 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/lib/lorem/version.rb: -------------------------------------------------------------------------------- 1 | module Lorem 2 | VERSION = "0.0.3" 3 | end 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.3/lorem.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'lorem/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "lorem" 8 | spec.version = Lorem::VERSION 9 | spec.authors = ["Josef Stribny"] 10 | spec.email = ["jstribny@redhat.com"] 11 | spec.summary = "lorem is a gem for testing gem-compare" 12 | spec.description = "lorem changes a lot so we can test gem-compare a lot" 13 | spec.homepage = "http://lorem.lorem" 14 | spec.license = "GPLv2" 15 | 16 | spec.files = ["lorem.gemspec", "bin/lorem", "CHANGELOG.md", "Gemfile", "Rakefile", "LICENSE.txt", "README.md"] + 17 | Dir.glob("lib/**/*") 18 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_dependency "rails", ">= 4.0.0" 23 | spec.add_development_dependency "bundler", "~> 1.0" 24 | spec.add_development_dependency "rake", ">= 10.0.0" 25 | end 26 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fedora-ruby/gem-compare/6b221bcf37b30a9dda05d0a2d7d677bee52ef097/test/gemfiles/lorem-0.0.4.gem -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/.CHANGELOG.md.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fedora-ruby/gem-compare/6b221bcf37b30a9dda05d0a2d7d677bee52ef097/test/gemfiles/lorem-0.0.4/.CHANGELOG.md.swp -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | lorem 0.0.4 2 | =========== 3 | 4 | - change summary and description 5 | - make bin/lorem really executable 6 | - bump dependencies 7 | 8 | lorem 0.0.3 9 | =========== 10 | 11 | - add homepage 12 | - add some lib files 13 | - add an executable file 14 | - change dependencies in gemspec and Gemfile 15 | 16 | lorem 0.0.2 17 | =========== 18 | 19 | - add changelog file 20 | - change license to GPLv2 21 | - add new method to lib/lorem.rb 22 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in lorem.gemspec 4 | gemspec 5 | 6 | gem 'minitest', '5.0.0' 7 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Josef Stribny 2 | 3 | You can use this library under GPLv2 conditions. 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/README.md: -------------------------------------------------------------------------------- 1 | # Lorem 2 | 3 | TODO: Write a gem description 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | gem 'lorem' 10 | 11 | And then execute: 12 | 13 | $ bundle 14 | 15 | Or install it yourself as: 16 | 17 | $ gem install lorem 18 | 19 | ## Usage 20 | 21 | TODO: Write usage instructions here 22 | 23 | ## Contributing 24 | 25 | 1. Fork it ( https://github.com/[my-github-username]/lorem/fork ) 26 | 2. Create your feature branch (`git checkout -b my-new-feature`) 27 | 3. Commit your changes (`git commit -am 'Add some feature'`) 28 | 4. Push to the branch (`git push origin my-new-feature`) 29 | 5. Create a new Pull Request 30 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/bin/lorem: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | puts 'Lorem Executable!' 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/lib/lorem.rb: -------------------------------------------------------------------------------- 1 | require "lorem/version" 2 | 3 | module Lorem 4 | def hello_world 5 | puts 'Hello World' 6 | end 7 | 8 | def new_method 9 | raise 'needs to be implemented' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/lib/lorem/utils.rb: -------------------------------------------------------------------------------- 1 | def check_something 2 | 3 | end 4 | 5 | def make_something 6 | 7 | end 8 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/lib/lorem/version.rb: -------------------------------------------------------------------------------- 1 | module Lorem 2 | VERSION = "0.0.4" 3 | end 4 | -------------------------------------------------------------------------------- /test/gemfiles/lorem-0.0.4/lorem.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'lorem/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "lorem" 8 | spec.version = Lorem::VERSION 9 | spec.authors = ["Josef Stribny"] 10 | spec.email = ["jstribny@redhat.com"] 11 | spec.summary = "lorem is a gem for testing gem-compare plugin" 12 | spec.description = "lorem changes a lot so we can test gem-compare plugin a lot" 13 | spec.homepage = "http://lorem.lorem" 14 | spec.license = "GPLv2" 15 | 16 | spec.files = ["lorem.gemspec", "bin/lorem", "CHANGELOG.md", "Gemfile", "Rakefile", "LICENSE.txt", "README.md"] + 17 | Dir.glob("lib/**/*") 18 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_dependency "rails", ">= 4.1.0" 23 | spec.add_development_dependency "bundler", "~> 1.1" 24 | spec.add_development_dependency "rake", ">= 10.0.0" 25 | end 26 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_dependency_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TestDependencyComparator < TestGemComparator 4 | 5 | def test_runtime_dependencies_comparison 6 | assert_equal 'DIFFERENT runtime dependencies:', @report['runtime_dependency'].header.data 7 | assert_equal 'DIFFERENT runtime dependencies:', @report['runtime_dependency'].lines(0) 8 | assert_equal '0.0.2->0.0.3:', @report['runtime_dependency']['0.0.2->0.0.3'].header.data 9 | assert_equal '0.0.2->0.0.3:', @report['runtime_dependency'].lines(1) 10 | assert_equal '* Added:', @report['runtime_dependency']['0.0.2->0.0.3']['added'].lines(0) 11 | assert_equal [], @report['runtime_dependency']['0.0.2->0.0.3']['deleted'].messages 12 | assert_equal [], @report['runtime_dependency']['0.0.2->0.0.3']['updated'].messages 13 | assert_equal ['rails [">= 4.0.0"] (runtime)'], @report['runtime_dependency']['0.0.2->0.0.3']['added'].lines(1) 14 | assert_equal '0.0.3->0.0.4:', @report['runtime_dependency']['0.0.3->0.0.4'].header.data 15 | assert_equal '0.0.3->0.0.4:', @report['runtime_dependency'].lines(4) 16 | assert_equal [], @report['runtime_dependency']['0.0.3->0.0.4']['added'].messages 17 | assert_equal [], @report['runtime_dependency']['0.0.3->0.0.4']['deleted'].messages 18 | assert_equal ['rails from: [">= 4.0.0"] to: [">= 4.1.0"]'], @report['runtime_dependency']['0.0.3->0.0.4']['updated'].lines(1) 19 | end 20 | 21 | def test_development_dependencies_comparison 22 | assert_equal [], @report['development_dependency']['0.0.1->0.0.2']['added'].messages 23 | assert_equal [], @report['development_dependency']['0.0.1->0.0.2']['deleted'].messages 24 | assert_equal [], @report['development_dependency']['0.0.1->0.0.2']['updated'].messages 25 | assert_equal [], @report['development_dependency']['0.0.2->0.0.3']['added'].messages 26 | assert_equal [], @report['development_dependency']['0.0.2->0.0.3']['deleted'].messages 27 | assert_equal 'bundler from: ["~> 1.6"] to: ["~> 1.0"]', @report['development_dependency']['0.0.2->0.0.3']['updated'].lines(1)[0] 28 | assert_equal 'rake from: [">= 0"] to: [">= 10.0.0"]', @report['development_dependency']['0.0.2->0.0.3']['updated'].lines(1)[1] 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_dir_utils.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TestDirUtils < TestGemModule 4 | 5 | def test_file_first_line 6 | file1 = File.join(@v001, 'lib/lorem.rb') 7 | file2 = File.join(@v002, 'bin/lorem') 8 | file3 = File.join(@v003, 'bin/lorem') 9 | assert_equal 'require "lorem/version"', Gem::Comparator::DirUtils.file_first_line(file1) 10 | assert_nil Gem::Comparator::DirUtils.file_first_line(file2) 11 | assert_equal '#!/usr/bin/ruby', Gem::Comparator::DirUtils.file_first_line(file3) 12 | end 13 | 14 | def test_file_has_shebang? 15 | file1 = File.join(@v003, 'lib/lorem.rb') 16 | file2 = File.join(@v004, 'bin/lorem') 17 | assert_nil Gem::Comparator::DirUtils.file_has_shebang?(file1) 18 | assert_equal 0, Gem::Comparator::DirUtils.file_has_shebang?(file2) 19 | end 20 | 21 | def test_files_same_first_line? 22 | file1 = File.join(@v001, 'lib/lorem.rb') 23 | file2 = File.join(@v002, 'lib/lorem.rb') 24 | file3 = File.join(@v003, 'bin/lorem') 25 | assert_equal true, Gem::Comparator::DirUtils.files_same_first_line?(file1, file2) 26 | assert_equal false, Gem::Comparator::DirUtils.files_same_first_line?(file1, file3) 27 | end 28 | 29 | def test_gem_bin_file 30 | file1 = File.join(@v001, 'lib/lorem.rb') 31 | file2 = File.join(@v004, 'bin/lorem') 32 | assert_nil Gem::Comparator::DirUtils.gem_bin_file?(file1) 33 | assert_equal 0, Gem::Comparator::DirUtils.gem_bin_file?(file2) 34 | end 35 | 36 | def test_dirs_of_files 37 | files = ['Rakefile', '/dir1/file1', '/dir2/file2'] 38 | assert_equal ["Rakefile", "/dir1/", "/dir2/"], Gem::Comparator::DirUtils.dirs_of_files(files) 39 | end 40 | 41 | def test_remove_subdirs 42 | dirs = ['/dir1/dir2/dir3', '/dir1/dir2', '/dir', 'Gemfile'] 43 | assert_equal ["/dir1/dir2", "/dir", "Gemfile"], Gem::Comparator::DirUtils.remove_subdirs(dirs) 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_file_list_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TestFileListComparator < TestGemComparator 4 | 5 | def test_files_comparison 6 | assert_equal 'DIFFERENT files:', @report['files'].header.data 7 | assert_equal '0.0.1->0.0.2:', @report['files'].lines(1) 8 | assert_equal "CHANGELOG.md +6/-0", @report['files']['0.0.1->0.0.2']['added'].lines(1) 9 | assert_equal [], @report['files']['0.0.1->0.0.2']['deleted'].messages 10 | assert_equal [], @report['files']['0.0.1->0.0.2']['updated'].messages 11 | assert_equal "bin/lorem +3/-0", @report['files']['0.0.2->0.0.3']['added'].lines(1) 12 | assert_equal "(!) Unexpected permissions: 100664", @report['files']['0.0.2->0.0.3']['added'].lines(2).strip 13 | assert_equal "(!) File is not executable", @report['files']['0.0.2->0.0.3']['added'].lines(3).strip 14 | assert_equal "(!) Shebang found: #!/usr/bin/ruby", @report['files']['0.0.2->0.0.3']['added'].lines(4).strip 15 | assert_equal "lib/lorem/utils.rb +7/-0", @report['files']['0.0.2->0.0.3']['added'].lines(5).strip 16 | assert_nil @report['files']['0.0.2->0.0.3']['added'].lines(6) 17 | assert_equal [], @report['files']['0.0.2->0.0.3']['deleted'].messages 18 | assert_equal [], @report['files']['0.0.2->0.0.3']['updated'].messages 19 | assert_equal [], @report['files']['0.0.3->0.0.4']['added'].messages 20 | assert_equal [], @report['files']['0.0.3->0.0.4']['deleted'].messages 21 | assert_equal [], @report['files']['0.0.3->0.0.4']['updated'].messages 22 | end 23 | 24 | def test_test_files_comparison 25 | assert_equal 'SAME test_files:', @report['test_files'].header.data 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_gemfile_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TestGemfileComparator < TestGemComparator 4 | 5 | def test_gemfile_comparison 6 | assert_equal '0.0.1->0.0.2:', @report['gemfiles']['0.0.1->0.0.2'].header.data 7 | assert_equal [], @report['gemfiles']['0.0.1->0.0.2'].messages 8 | assert_equal [], @report['gemfiles']['0.0.2->0.0.3'].messages 9 | assert_equal [], @report['gemfiles']['0.0.3->0.0.4']['added'].messages 10 | assert_equal '* Deleted', @report['gemfiles']['0.0.3->0.0.4'].lines(1) 11 | assert_equal ['appraisal [">= 0"] (runtime)'], @report['gemfiles']['0.0.3->0.0.4']['deleted'].lines(1) 12 | assert_equal ['minitest from: [">= 0"] to: ["= 5.0.0"]'], @report['gemfiles']['0.0.3->0.0.4']['updated'].lines(1) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_monitor.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TestMonitor < TestGemModule 4 | 5 | def test_lines_changed 6 | file1 = File.join(@v001, 'lib/lorem.rb') 7 | file2 = File.join(@v002, 'lib/lorem.rb') 8 | assert_equal '+4/-0', Gem::Comparator::Monitor.lines_changed(file1, file2) 9 | end 10 | 11 | def test_compact_files_diff 12 | file1 = File.join(@v001, 'lib/lorem.rb') 13 | file2 = File.join(@v002, 'lib/lorem.rb') 14 | assert_equal '++++', Gem::Comparator::Monitor.compact_files_diff(file1, file2) 15 | end 16 | 17 | def test_files_added_diff 18 | file1 = nil 19 | file2 = File.join(@v003, 'lib/lorem/utils.rb') 20 | diff = Gem::Comparator::Monitor.files_diff(file1, file2) 21 | expected_diff = <<~EOF 22 | @@ -0,0 +1,7 @@ 23 | +def check_something 24 | + 25 | +end 26 | + 27 | +def make_something 28 | + 29 | +end 30 | EOF 31 | assert_equal expected_diff, diff.split(/\n/, 3)[2] 32 | end 33 | 34 | def test_files_diff 35 | file1 = File.join(@v001, 'lib/lorem.rb') 36 | file2 = File.join(@v002, 'lib/lorem.rb') 37 | diff = Gem::Comparator::Monitor.files_diff(file1, file2) 38 | expected_diff = <<~EOF 39 | @@ -6,0 +7,4 @@ 40 | + 41 | + def new_method 42 | + raise 'needs to be implemented' 43 | + end 44 | EOF 45 | assert_equal expected_diff, diff.split(/\n/, 3)[2] 46 | end 47 | 48 | def test_files_permissions_changes 49 | file1 = File.join(@v003, 'bin/lorem') 50 | file2 = File.join(@v004, 'bin/lorem') 51 | assert_equal '(!) New permissions: 100664 -> 100775', Gem::Comparator::Monitor.files_permissions_changes(file1, file2).strip 52 | assert_equal '(!) New permissions: 100664 -> 100775', Gem::Comparator::Monitor.files_permissions_changes(file1, file2, true).strip 53 | end 54 | 55 | def test_files_permissions_changes_no_change 56 | file1 = Tempfile.new 57 | file2 = Tempfile.new 58 | begin 59 | File.chmod(0644, file1) 60 | File.chmod(0644, file2) 61 | assert_equal '', Gem::Comparator::Monitor.files_permissions_changes(file1.path, file2.path) 62 | assert_equal '', Gem::Comparator::Monitor.files_permissions_changes(file1.path, file2.path, true) 63 | ensure 64 | file1.unlink 65 | file2.unlink 66 | end 67 | end 68 | 69 | def test_files_permissions_changes_ignores_group_writable_added 70 | file1 = Tempfile.new 71 | file2 = Tempfile.new 72 | begin 73 | File.chmod(0644, file1) 74 | File.chmod(0664, file2) 75 | assert_equal '', Gem::Comparator::Monitor.files_permissions_changes(file1.path, file2.path, true) 76 | ensure 77 | file1.unlink 78 | file2.unlink 79 | end 80 | end 81 | 82 | def test_files_permissions_changes_ignores_group_writable_other_changes 83 | file1 = Tempfile.new 84 | file2 = Tempfile.new 85 | begin 86 | File.chmod(0644, file1) 87 | File.chmod(0660, file2) 88 | assert_equal ' (!) New permissions: 100644 -> 100660', Gem::Comparator::Monitor.files_permissions_changes(file1.path, file2.path, true) 89 | ensure 90 | file1.unlink 91 | file2.unlink 92 | end 93 | end 94 | 95 | def test_files_permissions_changes_ignores_group_writable_removed 96 | file1 = Tempfile.new 97 | file2 = Tempfile.new 98 | begin 99 | File.chmod(0664, file1) 100 | File.chmod(0644, file2) 101 | assert_equal '', Gem::Comparator::Monitor.files_permissions_changes(file1.path, file2.path, true) 102 | ensure 103 | file1.unlink 104 | file2.unlink 105 | end 106 | end 107 | 108 | def test_new_file_permissions 109 | file1 = File.join(@v004, 'bin/lorem') 110 | file2 = File.join(@v004, 'lib/lorem.rb') 111 | assert_equal '(!) Unexpected permissions: 100775', Gem::Comparator::Monitor.new_file_permissions(file1).strip 112 | assert_equal '(!) Unexpected permissions: 100664', Gem::Comparator::Monitor.new_file_permissions(file2).strip 113 | ignore_group_writable = true 114 | assert_equal '', Gem::Comparator::Monitor.new_file_permissions(file1, ignore_group_writable).strip 115 | assert_equal '', Gem::Comparator::Monitor.new_file_permissions(file2, ignore_group_writable).strip 116 | end 117 | 118 | def test_new_file_permissions_ignore_group_writable_when_not_group_writable 119 | file = Tempfile.new 120 | bin_file = temp_bin_file 121 | begin 122 | File.chmod(0644, file) 123 | assert_equal '', Gem::Comparator::Monitor.new_file_permissions(file.path, true) 124 | 125 | File.chmod(0755, bin_file) 126 | assert_equal '', Gem::Comparator::Monitor.new_file_permissions(bin_file.path, true) 127 | ensure 128 | file.unlink 129 | bin_file.unlink 130 | end 131 | end 132 | 133 | def test_new_file_permissions_ignore_group_writable 134 | file = Tempfile.new 135 | bin_file = temp_bin_file 136 | begin 137 | File.chmod(0664, file) 138 | assert_equal '', Gem::Comparator::Monitor.new_file_permissions(file.path, true) 139 | 140 | File.chmod(0775, bin_file) 141 | assert_equal '', Gem::Comparator::Monitor.new_file_permissions(bin_file.path, true) 142 | ensure 143 | file.unlink 144 | bin_file.unlink 145 | end 146 | end 147 | 148 | def test_new_file_permissions_ignore_group_writable_unreadable 149 | file = Tempfile.new 150 | begin 151 | File.chmod(0660, file) 152 | assert_equal ' (!) Unexpected permissions: 100660', Gem::Comparator::Monitor.new_file_permissions(file.path, true) 153 | ensure 154 | file.unlink 155 | end 156 | end 157 | 158 | def test_files_executability_changes 159 | file1 = File.join(@v003, 'bin/lorem') 160 | file2 = File.join(@v004, 'bin/lorem') 161 | assert_equal '(!) File is now executable!', Gem::Comparator::Monitor.files_executability_changes(file1, file2).strip 162 | end 163 | 164 | def test_new_file_executability 165 | file1 = File.join(@v003, 'bin/lorem') 166 | file2 = File.join(@v004, 'bin/lorem') 167 | assert_equal '(!) File is not executable', Gem::Comparator::Monitor.new_file_executability(file1).strip 168 | assert_equal '', Gem::Comparator::Monitor.new_file_executability(file2).strip 169 | end 170 | 171 | def test_files_shebang_changes 172 | file1 = File.join(@v003, 'bin/lorem') 173 | file2 = File.join(@v004, 'bin/lorem') 174 | assert_equal '', Gem::Comparator::Monitor.files_shebang_changes(file1, file2).strip 175 | end 176 | 177 | def test_new_file_shebang 178 | file1 = File.join(@v003, 'bin/lorem') 179 | assert_equal '(!) Shebang found: #!/usr/bin/ruby', Gem::Comparator::Monitor.new_file_shebang(file1).strip 180 | end 181 | end 182 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_report.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../test_helper' 2 | require 'rubygems/comparator' 3 | 4 | class TestGemComparatorReport < Minitest::Test 5 | def setup 6 | super 7 | @report = Gem::Comparator::Report.new 8 | @report['1'] << '1' 9 | @report['1']['2'] << '2' 10 | @report['1']['unused'].set_header 'Unused' 11 | @report['1.1'].section do 12 | nest('1.1.1').section do 13 | puts [3, 3] 14 | end 15 | puts [] 16 | end 17 | end 18 | 19 | def test_all_messages 20 | assert_equal 2, @report['1'].all_messages.size 21 | assert_equal 1, @report['1.1'].all_messages.size 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_spec_comparator.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TestSpecComparator < TestGemComparator 4 | 5 | def test_name_comparison 6 | assert_equal 'SAME name:', @report['name'].header.data 7 | assert_equal 'SAME name:', @report['name'].lines(0) 8 | end 9 | 10 | def test_version_comparison 11 | assert_equal 'DIFFERENT version:', @report['version'].header.data 12 | assert_equal 'DIFFERENT version:', @report['version'].lines(0) 13 | assert_equal '0.0.1: 0.0.1', @report['version'].lines(1) 14 | assert_equal '0.0.2: 0.0.2', @report['version'].lines(2) 15 | assert_equal '0.0.3: 0.0.3', @report['version'].lines(3) 16 | assert_equal '0.0.4: 0.0.4', @report['version'].lines(4) 17 | end 18 | 19 | def test_licenses_comparison 20 | assert_equal 'DIFFERENT license:', @report['license'].header.data 21 | assert_equal 'DIFFERENT licenses:', @report['licenses'].header.data 22 | assert_equal 'DIFFERENT license:', @report['license'].lines(0) 23 | assert_equal 'DIFFERENT licenses:', @report['licenses'].lines(0) 24 | assert_equal '0.0.1: MIT', @report['license'].lines(1) 25 | assert_equal '0.0.2: GPLv2', @report['license'].lines(2) 26 | assert_equal '0.0.3: GPLv2', @report['license'].lines(3) 27 | assert_equal '0.0.4: GPLv2', @report['license'].lines(4) 28 | assert_equal '0.0.1: ["MIT"]', @report['licenses'].lines(1) 29 | assert_equal '0.0.2: ["GPLv2"]', @report['licenses'].lines(2) 30 | assert_equal '0.0.3: ["GPLv2"]', @report['licenses'].lines(3) 31 | assert_equal '0.0.4: ["GPLv2"]', @report['licenses'].lines(4) 32 | end 33 | 34 | def test_authors_comparison 35 | assert_equal 'SAME author:', @report['author'].header.data 36 | assert_equal 'SAME authors:', @report['authors'].header.data 37 | assert_equal 'SAME author:', @report['author'].lines(0) 38 | assert_equal 'SAME authors:', @report['authors'].lines(0) 39 | end 40 | 41 | def test_email_comparison 42 | assert_equal 'SAME email:', @report['email'].header.data 43 | assert_equal 'SAME email:', @report['email'].lines(0) 44 | end 45 | 46 | def test_summary_comparison 47 | assert_equal 'DIFFERENT summary:', @report['summary'].header.data 48 | assert_equal 'DIFFERENT summary:', @report['summary'].lines(0) 49 | assert_equal '0.0.1: lorem is a gem for testing gem-compare', @report['summary'].lines(1) 50 | assert_equal '0.0.2: lorem is a gem for testing gem-compare', @report['summary'].lines(2) 51 | assert_equal '0.0.3: lorem is a gem for testing gem-compare', @report['summary'].lines(3) 52 | assert_equal '0.0.4: lorem is a gem for testing gem-compare plugin', @report['summary'].lines(4) 53 | end 54 | 55 | def test_description_comparison 56 | assert_equal 'DIFFERENT description:', @report['description'].header.data 57 | assert_equal 'DIFFERENT description:', @report['description'].lines(0) 58 | assert_equal '0.0.1: lorem changes a lot so we can test gem-compare a lot', @report['description'].lines(1) 59 | assert_equal '0.0.2: lorem changes a lot so we can test gem-compare a lot', @report['description'].lines(2) 60 | assert_equal '0.0.3: lorem changes a lot so we can test gem-compare a lot', @report['description'].lines(3) 61 | assert_equal '0.0.4: lorem changes a lot so we can test gem-compare plugin a lot', @report['description'].lines(4) 62 | end 63 | 64 | def test_homepage_comparison 65 | assert_equal 'DIFFERENT homepage:', @report['homepage'].header.data 66 | assert_equal 'DIFFERENT homepage:', @report['homepage'].lines(0) 67 | assert_equal '0.0.1: ', @report['homepage'].lines(1) 68 | assert_equal '0.0.2: ', @report['homepage'].lines(2) 69 | assert_equal '0.0.3: http://lorem.lorem', @report['homepage'].lines(3) 70 | assert_equal '0.0.4: http://lorem.lorem', @report['homepage'].lines(4) 71 | end 72 | 73 | def test_platform_comparison 74 | assert_equal 'SAME platform:', @report['platform'].header.data 75 | assert_equal 'SAME platform:', @report['platform'].lines(0) 76 | end 77 | 78 | def test_require_paths_comparison 79 | assert_equal 'SAME require_paths:', @report['require_paths'].header.data 80 | assert_equal 'SAME require_paths:', @report['require_paths'].lines(0) 81 | end 82 | 83 | def test_bindir_comparison 84 | assert_equal 'SAME bindir:', @report['bindir'].header.data 85 | assert_equal 'SAME bindir:', @report['bindir'].lines(0) 86 | end 87 | 88 | def test_rubygems_version_comparison 89 | assert_equal 'SAME rubygems_version:', @report['rubygems_version'].header.data 90 | assert_equal 'SAME rubygems_version:', @report['rubygems_version'].lines(0) 91 | end 92 | 93 | def test_cert_chain_comparison 94 | assert_equal 'SAME cert_chain:', @report['cert_chain'].header.data 95 | assert_equal 'SAME cert_chain:', @report['cert_chain'].lines(0) 96 | end 97 | 98 | def test_executables_comparison 99 | assert_equal 'DIFFERENT executables:', @report['executables'].header.data 100 | assert_equal 'DIFFERENT executables:', @report['executables'].lines(0) 101 | end 102 | 103 | def test_extensions_comparison 104 | assert_equal 'SAME extensions:', @report['extensions'].header.data 105 | assert_equal 'SAME extensions:', @report['extensions'].lines(0) 106 | end 107 | 108 | def test_metadata_comparison 109 | assert_equal 'SAME metadata:', @report['metadata'].header.data 110 | assert_equal 'SAME metadata:', @report['metadata'].lines(0) 111 | end 112 | 113 | def test_post_install_message_comparison 114 | assert_equal 'SAME post_install_message:', @report['post_install_message'].header.data 115 | assert_equal 'SAME post_install_message:', @report['post_install_message'].lines(0) 116 | end 117 | 118 | def test_rdoc_options_comparison 119 | assert_equal 'SAME rdoc_options:', @report['rdoc_options'].header.data 120 | assert_equal 'SAME rdoc_options:', @report['rdoc_options'].lines(0) 121 | end 122 | 123 | def test_required_ruby_version_comparison 124 | assert_equal 'SAME required_ruby_version:', @report['required_ruby_version'].header.data 125 | assert_equal 'SAME required_ruby_version:', @report['required_ruby_version'].lines(0) 126 | end 127 | 128 | def test_required_rubygems_version_comparison 129 | assert_equal 'SAME required_rubygems_version:', @report['required_rubygems_version'].header.data 130 | assert_equal 'SAME required_rubygems_version:', @report['required_rubygems_version'].lines(0) 131 | end 132 | 133 | def test_requirements_comparison 134 | assert_equal 'SAME requirements:', @report['requirements'].header.data 135 | assert_equal 'SAME requirements:', @report['requirements'].lines(0) 136 | end 137 | 138 | def test_signing_key_comparison 139 | assert_equal 'SAME signing_key:', @report['signing_key'].header.data 140 | assert_equal 'SAME signing_key:', @report['signing_key'].lines(0) 141 | end 142 | 143 | def test_date_comparison 144 | assert_equal 'SAME date:', @report['date'].header.data 145 | assert_equal 'SAME date:', @report['date'].lines(0) 146 | end 147 | 148 | end 149 | -------------------------------------------------------------------------------- /test/rubygems/comparator/test_utils.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../test_helper' 2 | require 'rubygems/comparator' 3 | 4 | class TestGemComparatorUtils < Minitest::Test 5 | def setup 6 | super 7 | # This should pull in Gem::Comparator::Utils 8 | @test_comparator = Class.new(Gem::Comparator::Base).new 9 | end 10 | 11 | def test_param_exist? 12 | params = (Gem::Comparator::Utils::SPEC_PARAMS + 13 | Gem::Comparator::Utils::SPEC_FILES_PARAMS + 14 | Gem::Comparator::Utils::DEPENDENCY_PARAMS + 15 | Gem::Comparator::Utils::GEMFILE_PARAMS) 16 | 17 | params.each do |param| 18 | assert_equal true, @test_comparator.send(:param_exists?, param) 19 | end 20 | 21 | assert_equal false, @test_comparator.send(:param_exists?, 'i_dont_exist') 22 | end 23 | 24 | def test_filter_params 25 | params = Gem::Comparator::Utils::SPEC_PARAMS 26 | assert_equal ['license'], @test_comparator.send(:filter_params, params, 'license') 27 | end 28 | 29 | def test_filter_for_brief_mode 30 | exclude = Gem::Comparator::Utils::FILTER_WHEN_BRIEF + ['not_excluded'] 31 | assert_equal ['not_excluded'], @test_comparator.send(:filter_for_brief_mode, exclude) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/rubygems/test_gem_commands_compare_command.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | require 'rubygems/user_interaction' 3 | require 'rubygems/mock_gem_ui' 4 | require 'rubygems/commands/compare_command' 5 | 6 | class TestGemCommandsCompareCommand < Minitest::Test 7 | include Gem::DefaultUserInteraction 8 | 9 | def setup 10 | super 11 | 12 | @command = Gem::Commands::CompareCommand.new 13 | @ui = Gem::MockGemUi.new 14 | end 15 | 16 | def test_execute_no_gemfile 17 | @command.options[:args] = [] 18 | 19 | e = assert_raises Gem::CommandLineError do 20 | use_ui @ui do 21 | @command.execute 22 | end 23 | end 24 | 25 | assert_match 'Please specify a gem (e.g. gem compare foo VERSION [VERSION ...])', e.message 26 | end 27 | 28 | def test_execute_no_patch 29 | @command.options[:args] = ['my_gem'] 30 | 31 | e = assert_raises Gem::CommandLineError do 32 | use_ui @ui do 33 | @command.execute 34 | end 35 | end 36 | 37 | assert_match 'Please specify versions you want to compare (e.g. gem compare foo 0.1.0 0.2.0)', e.message 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'rubygems/comparator' 3 | 4 | # The tests expects these permissions, which isn't the case if you have 5 | # umask 022 when cloning the repo 6 | def setup_file_permissions 7 | gemfiles_path = File.expand_path('gemfiles', File.dirname(__FILE__)) 8 | File.chmod(0664, File.join(gemfiles_path, 'lorem-0.0.1', 'lib', 'lorem.rb')) 9 | File.chmod(0664, File.join(gemfiles_path, 'lorem-0.0.3', 'bin', 'lorem')) 10 | File.chmod(0664, File.join(gemfiles_path, 'lorem-0.0.4', 'lib', 'lorem.rb')) 11 | File.chmod(0775, File.join(gemfiles_path, 'lorem-0.0.4', 'bin', 'lorem')) 12 | end 13 | 14 | def temp_bin_file 15 | bin_dir = File.join(Dir.mktmpdir, "bin") 16 | Dir.mkdir(bin_dir) 17 | Tempfile.new("", bin_dir) 18 | end 19 | 20 | class TestGemComparator < Minitest::Test 21 | def setup 22 | super 23 | 24 | setup_file_permissions 25 | 26 | options = { keep_all: true, log_all: true, no_color: true, brief_mode: false } 27 | versions = ['0.0.1', '0.0.2', '0.0.3', '0.0.4'] 28 | 29 | @comparator = Gem::Comparator.new(options) 30 | 31 | Dir.chdir(File.expand_path('gemfiles', File.dirname(__FILE__))) do 32 | @comparator.options.merge!({ output: Dir.getwd }) 33 | @comparator.compare_versions('lorem', versions) 34 | end 35 | 36 | @report = @comparator.report 37 | end 38 | end 39 | 40 | class TestGemModule < Minitest::Test 41 | def setup 42 | super 43 | Rainbow.enabled = false 44 | setup_file_permissions 45 | gemfiles_path = File.expand_path('gemfiles', File.dirname(__FILE__)) 46 | @v001 = File.join(gemfiles_path, 'lorem-0.0.1') 47 | @v002 = File.join(gemfiles_path, 'lorem-0.0.2') 48 | @v003 = File.join(gemfiles_path, 'lorem-0.0.3') 49 | @v004 = File.join(gemfiles_path, 'lorem-0.0.4') 50 | end 51 | end 52 | --------------------------------------------------------------------------------