diff --git a/lib/gemstash/gem_source/private_source.rb b/lib/gemstash/gem_source/private_source.rb index 025312d0..5195570d 100644 --- a/lib/gemstash/gem_source/private_source.rb +++ b/lib/gemstash/gem_source/private_source.rb @@ -50,6 +50,17 @@ def serve_versions halt 404, "Not yet supported" end + def serve_gem_versions(name) + authorization.protect(self) do + auth.check("fetch") if gemstash_env.config[:protected_fetch] + name.slice! ".json" + gem = fetch_gem(name) + halt 404 unless gem.exist?(:spec) + content_type "application/json;charset=UTF-8" + fetch_gem_versions(name).to_json + end + end + def serve_info(name) halt 403, "Not yet supported" end @@ -118,6 +129,29 @@ def fetch_gem(gem_full_name) halt 403, "That gem has been yanked" unless gem.properties[:indexed] gem end + + def fetch_gem_versions(gem) + results = db[" + SELECT rubygem.name, + version.number, version.platform + FROM rubygems rubygem + JOIN versions version + ON version.rubygem_id = rubygem.id + WHERE rubygem.name = ? + AND version.indexed = ?", gem.to_a, true].to_a + results.group_by {|r| r[:name] }.each do |rows| + requirements = rows.group_by {|r| [r[:number], r[:platform]] } + + value = requirements.map do |(version, platform)| + { + :number => version, + :platform => platform + } + end + + yield(gem, value) + end + end end end end diff --git a/lib/gemstash/gem_source/upstream_source.rb b/lib/gemstash/gem_source/upstream_source.rb index 48f17c9a..7a53f52a 100644 --- a/lib/gemstash/gem_source/upstream_source.rb +++ b/lib/gemstash/gem_source/upstream_source.rb @@ -62,6 +62,10 @@ def serve_versions redirect index_upstream.url("versions", request.query_string) end + def serve_gem_versions(name) + redirect index_upstream.url("api/v1/versions/#{name}", request.query_string) + end + def serve_info(name) redirect index_upstream.url("info/#{name}", request.query_string) end diff --git a/lib/gemstash/web.rb b/lib/gemstash/web.rb index ae2428c8..675d2c9c 100644 --- a/lib/gemstash/web.rb +++ b/lib/gemstash/web.rb @@ -47,6 +47,10 @@ def http_client_for(server_url) @gem_source.serve_dependencies_json end + get "/api/v1/versions/:name" do + @gem_source.serve_gem_versions(params[:name]) + end + post "/api/v1/gems" do @gem_source.serve_add_gem end diff --git a/spec/gemstash/web_spec.rb b/spec/gemstash/web_spec.rb index 26892975..2af0021f 100644 --- a/spec/gemstash/web_spec.rb +++ b/spec/gemstash/web_spec.rb @@ -201,6 +201,63 @@ def for(server_url, timeout = 20) end end + context "GET /api/v1/versions/:name" do + context "from the default upstream" do + let(:current_env) { Gemstash::Env.current } + let(:upstream) { Gemstash::Upstream.new(current_env.config[:rubygems_url]) } + let(:storage) { Gemstash::LocalStorage.for("gem_cache").for(upstream.host_id) } + + it "fetches the gem informations as json" do + result = [{ + "number" => "1.0.0", + "platform" => "ruby" + }] + + get "/api/v1/versions/rack.json", {}, rack_env + expect(last_response).to be_ok + expect(JSON.parse(last_response.body)).to eq(result) + end + + it "can be called multiple times without error" do + get "/api/v1/versions/rack.json", {}, rack_env + get "/api/v1/versions/rack.json", {}, rack_env + end + end + + context "from private gems" do + let(:gem_source) { Gemstash::GemSource::PrivateSource } + let(:storage) { Gemstash::LocalStorage.for("private").for("gems") } + + context "with a missing gem" do + it "halts with 404" do + get "/api/v1/versions/unknown.json", {}, rack_env + expect(last_response).to_not be_ok + expect(last_response.status).to eq(404) + expect(last_response.body).to match(/not found/i) + end + end + + context "with a regular gem" do + before do + gem_id = insert_rubygem "example" + insert_version gem_id, "0.1.0" + storage.resource("example-0.1.0").save({ gem: "Example gem content" }, indexed: true) + end + + it "fetches the gem informations as json" do + result = [{ + "number" => "0.1.0", + "platform" => "ruby" + }] + + get "/api/v1/versions/example.json", {}, rack_env + expect(last_response).to be_ok + expect(JSON.parse(last_response.body)).to eq(result) + end + end + end + end + context "GET /gems/:id" do context "from the default upstream" do let(:current_env) { Gemstash::Env.current }