From 6b5c72f4a7f8888a3e86d4ea5be336c07cba8194 Mon Sep 17 00:00:00 2001 From: Walter Carvalho Date: Fri, 2 Oct 2015 15:20:20 +0100 Subject: [PATCH] Implement dependency update checking. https://trello.com/c/hK22Q2Bp/3-dependency-update-checker --- .editorconfig | 11 +++ Gemfile | 1 + Gemfile.lock | 10 ++- lib/bumper/update_checker/update_checker.rb | 32 +++++++++ .../file_parsers/ruby_file_parser_spec.rb | 2 +- .../update_checker/update_checker_spec.rb | 63 +++++++++++++++++ .../out_of_date_dependency_response.json | 67 +++++++++++++++++++ .../up_to_date_dependency_response.json | 67 +++++++++++++++++++ spec/spec_helper.rb | 1 + 9 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 .editorconfig create mode 100644 lib/bumper/update_checker/update_checker.rb create mode 100644 spec/bumper/update_checker/update_checker_spec.rb create mode 100644 spec/fixtures/out_of_date_dependency_response.json create mode 100644 spec/fixtures/up_to_date_dependency_response.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..1fab8127f3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# editorconfig.org +root = true + +[*] +indent_size = 2 +translate_tabs_to_spaces = true +indent_style = spaces +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/Gemfile b/Gemfile index 24a76aac65..3b5ad6ed23 100644 --- a/Gemfile +++ b/Gemfile @@ -5,4 +5,5 @@ gem "gemnasium-parser", "~> 0.1.9" group :development do gem "rspec", "~> 3.3.0" gem "rspec-its", "~> 1.2.0", require: "rspec/its" + gem 'webmock' end diff --git a/Gemfile.lock b/Gemfile.lock index 6e4bdc4911..f288b5c803 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,9 @@ GEM remote: https://rubygems.org/ specs: + addressable (2.3.8) + crack (0.4.2) + safe_yaml (~> 1.0.0) diff-lcs (1.2.5) gemnasium-parser (0.1.9) rspec (3.3.0) @@ -19,6 +22,10 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.3.0) rspec-support (3.3.0) + safe_yaml (1.0.4) + webmock (1.21.0) + addressable (>= 2.3.6) + crack (>= 0.3.2) PLATFORMS ruby @@ -27,6 +34,7 @@ DEPENDENCIES gemnasium-parser (~> 0.1.9) rspec (~> 3.3.0) rspec-its (~> 1.2.0) + webmock BUNDLED WITH - 1.10.4 + 1.10.6 diff --git a/lib/bumper/update_checker/update_checker.rb b/lib/bumper/update_checker/update_checker.rb new file mode 100644 index 0000000000..463a357174 --- /dev/null +++ b/lib/bumper/update_checker/update_checker.rb @@ -0,0 +1,32 @@ +# require "gem/version" +require "net/http" +require "json" + +module UpdateChecker + + # checks for dependencies that are out of date + # + # usage: + # UpdateChecker::RubyUpdateChecker.new(initial_dependencies).run + # + # dependencies, Array + # return an Array of dependencies that are out of date + class RubyUpdateChecker + def initialize(dependencies) + @dependencies = dependencies + end + + def run + @dependencies.select do |dependency| + latest_version = get_latest(dependency)["version"] + Gem::Version.new(latest_version) > Gem::Version.new(dependency.version) + end + end + + private + + def get_latest(dependency) + JSON.parse(Net::HTTP.get(URI("https://rubygems.org/api/v1/gems/#{dependency.name}.json"))) + end + end +end diff --git a/spec/bumper/file_parsers/ruby_file_parser_spec.rb b/spec/bumper/file_parsers/ruby_file_parser_spec.rb index 06cf4bbd38..81b1f38752 100644 --- a/spec/bumper/file_parsers/ruby_file_parser_spec.rb +++ b/spec/bumper/file_parsers/ruby_file_parser_spec.rb @@ -3,7 +3,7 @@ require "bumper/file_parsers/ruby_file_parser" RSpec.describe FileParsers::RubyFileParser do - let(:gemfile) { File.read('spec/fixtures/Gemfile') } + let(:gemfile) { File.read("spec/fixtures/Gemfile") } let(:parser) { FileParsers::RubyFileParser.new(gemfile) } subject(:dependencies) { parser.parse } diff --git a/spec/bumper/update_checker/update_checker_spec.rb b/spec/bumper/update_checker/update_checker_spec.rb new file mode 100644 index 0000000000..8df9d4c893 --- /dev/null +++ b/spec/bumper/update_checker/update_checker_spec.rb @@ -0,0 +1,63 @@ +require "spec_helper" +require "bumper/dependency" +require "bumper/update_checker/update_checker" + +RSpec.describe UpdateChecker::RubyUpdateChecker do + let(:outdated_dependency) { + File.read("spec/fixtures/out_of_date_dependency_response.json") + } + + let(:outdated_dependency_json) { + JSON.parse(outdated_dependency) + } + + let(:latest_dependency) { + File.read("spec/fixtures/up_to_date_dependency_response.json") + } + + let(:latest_dependency_json) { + JSON.parse(latest_dependency) + } + + before do + stub_request( + :get, + "https://rubygems.org/api/v1/gems/#{outdated_dependency_json["name"]}.json" + ). + to_return(:status => 200, :body => outdated_dependency, :headers => {}) + + stub_request( + :get, + "https://rubygems.org/api/v1/gems/#{latest_dependency_json["name"]}.json" + ). + to_return(:status => 200, :body => latest_dependency, :headers => {}) + end + + # TODO: tests need mocking + let(:initial_dependencies) do + [ + Dependency.new( + name: latest_dependency_json["name"], + version: latest_dependency_json["version"] + ), + Dependency.new( + name: outdated_dependency_json["name"], + version: "1.2.0" + ) + ] + end + + let(:checker) { UpdateChecker::RubyUpdateChecker.new(initial_dependencies) } + subject(:dependencies) { checker.run } + + its(:length) { is_expected.to eq(1) } + + describe "the first dependency" do + subject { dependencies.first } + + it { is_expected.to be_a(Dependency) } + its(:name) { is_expected.to eq(outdated_dependency_json["name"]) } + its(:version) { is_expected.to eq("1.2.0") } + end + +end diff --git a/spec/fixtures/out_of_date_dependency_response.json b/spec/fixtures/out_of_date_dependency_response.json new file mode 100644 index 0000000000..fa35f444ce --- /dev/null +++ b/spec/fixtures/out_of_date_dependency_response.json @@ -0,0 +1,67 @@ +{ + "name": "outdated", + "downloads": 54431629, + "version": "1.2.3", + "version_downloads": 341108, + "platform": "ruby", + "authors": "David Heinemeier Hansson", + "info": "Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.", + "licenses": [ + "MIT" + ], + "metadata": {}, + "sha": "1c33dd7c280d1c5dc4235509f774d673bac1d3f2e8c53b1353f677e7578ffc5a", + "project_uri": "https://rubygems.org/gems/rails", + "gem_uri": "https://rubygems.org/gems/rails-4.2.4.gem", + "homepage_uri": "http://www.rubyonrails.org", + "wiki_uri": "http://wiki.rubyonrails.org", + "documentation_uri": "http://api.rubyonrails.org", + "mailing_list_uri": "http://groups.google.com/group/rubyonrails-talk", + "source_code_uri": "http://github.com/rails/rails", + "bug_tracker_uri": "http://github.com/rails/rails/issues", + "dependencies": { + "development": [], + "runtime": [ + { + "name": "actionmailer", + "requirements": "= 4.2.4" + }, + { + "name": "actionpack", + "requirements": "= 4.2.4" + }, + { + "name": "actionview", + "requirements": "= 4.2.4" + }, + { + "name": "activejob", + "requirements": "= 4.2.4" + }, + { + "name": "activemodel", + "requirements": "= 4.2.4" + }, + { + "name": "activerecord", + "requirements": "= 4.2.4" + }, + { + "name": "activesupport", + "requirements": "= 4.2.4" + }, + { + "name": "bundler", + "requirements": "< 2.0, >= 1.3.0" + }, + { + "name": "railties", + "requirements": "= 4.2.4" + }, + { + "name": "sprockets-rails", + "requirements": ">= 0" + } + ] + } +} diff --git a/spec/fixtures/up_to_date_dependency_response.json b/spec/fixtures/up_to_date_dependency_response.json new file mode 100644 index 0000000000..6bb035823b --- /dev/null +++ b/spec/fixtures/up_to_date_dependency_response.json @@ -0,0 +1,67 @@ +{ + "name": "latest", + "downloads": 54431629, + "version": "4.2.4", + "version_downloads": 341108, + "platform": "ruby", + "authors": "David Heinemeier Hansson", + "info": "Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.", + "licenses": [ + "MIT" + ], + "metadata": {}, + "sha": "1c33dd7c280d1c5dc4235509f774d673bac1d3f2e8c53b1353f677e7578ffc5a", + "project_uri": "https://rubygems.org/gems/rails", + "gem_uri": "https://rubygems.org/gems/rails-4.2.4.gem", + "homepage_uri": "http://www.rubyonrails.org", + "wiki_uri": "http://wiki.rubyonrails.org", + "documentation_uri": "http://api.rubyonrails.org", + "mailing_list_uri": "http://groups.google.com/group/rubyonrails-talk", + "source_code_uri": "http://github.com/rails/rails", + "bug_tracker_uri": "http://github.com/rails/rails/issues", + "dependencies": { + "development": [], + "runtime": [ + { + "name": "actionmailer", + "requirements": "= 4.2.4" + }, + { + "name": "actionpack", + "requirements": "= 4.2.4" + }, + { + "name": "actionview", + "requirements": "= 4.2.4" + }, + { + "name": "activejob", + "requirements": "= 4.2.4" + }, + { + "name": "activemodel", + "requirements": "= 4.2.4" + }, + { + "name": "activerecord", + "requirements": "= 4.2.4" + }, + { + "name": "activesupport", + "requirements": "= 4.2.4" + }, + { + "name": "bundler", + "requirements": "< 2.0, >= 1.3.0" + }, + { + "name": "railties", + "requirements": "= 4.2.4" + }, + { + "name": "sprockets-rails", + "requirements": ">= 0" + } + ] + } +} diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 59b7da7777..d888b7b0e3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1 +1,2 @@ require "rspec/its" +require "webmock/rspec"