diff --git a/lib/gitlab.rb b/lib/gitlab.rb index b87ba9538..79fb048df 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -4,7 +4,8 @@ require 'gitlab/objectified_hash' require 'gitlab/configuration' require 'gitlab/error' -require 'gitlab/page_links' +require 'gitlab/headers/page_links' +require 'gitlab/headers/total' require 'gitlab/paginated_response' require 'gitlab/file_response' require 'gitlab/request' diff --git a/lib/gitlab/headers/page_links.rb b/lib/gitlab/headers/page_links.rb new file mode 100644 index 000000000..8ba92c957 --- /dev/null +++ b/lib/gitlab/headers/page_links.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Gitlab + module Headers + # Parses link header. + # + # @private + class PageLinks + HEADER_LINK = 'Link' + DELIM_LINKS = ',' + LINK_REGEX = /<([^>]+)>; rel="([^"]+)"/.freeze + METAS = %w[last next first prev].freeze + + attr_accessor(*METAS) + + def initialize(headers) + link_header = headers[HEADER_LINK] + + extract_links(link_header) if link_header && link_header =~ /(next|first|last|prev)/ + end + + private + + def extract_links(header) + header.split(DELIM_LINKS).each do |link| + LINK_REGEX.match(link.strip) do |match| + url = match[1] + meta = match[2] + next if !url || !meta || METAS.index(meta).nil? + + send("#{meta}=", url) + end + end + end + end + end +end diff --git a/lib/gitlab/headers/total.rb b/lib/gitlab/headers/total.rb new file mode 100644 index 000000000..4abe84bb4 --- /dev/null +++ b/lib/gitlab/headers/total.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Gitlab + module Headers + # Parses total header. + # + # @private + class Total + HEADER_TOTAL = 'x-total' + TOTAL_REGEX = /^\d+$/.freeze + + attr_accessor :total + + def initialize(headers) + header_total = headers[HEADER_TOTAL] + + extract_total(header_total) if header_total + end + + private + + def extract_total(header_total) + TOTAL_REGEX.match(header_total.strip) do |match| + @total = match[0] + end + end + end + end +end diff --git a/lib/gitlab/page_links.rb b/lib/gitlab/page_links.rb deleted file mode 100644 index 034983c67..000000000 --- a/lib/gitlab/page_links.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - # Parses link header. - # - # @private - class PageLinks - HEADER_LINK = 'Link' - DELIM_LINKS = ',' - LINK_REGEX = /<([^>]+)>; rel="([^"]+)"/.freeze - METAS = %w[last next first prev].freeze - - attr_accessor(*METAS) - - def initialize(headers) - link_header = headers[HEADER_LINK] - - extract_links(link_header) if link_header && link_header =~ /(next|first|last|prev)/ - end - - private - - def extract_links(header) - header.split(DELIM_LINKS).each do |link| - LINK_REGEX.match(link.strip) do |match| - url = match[1] - meta = match[2] - next if !url || !meta || METAS.index(meta).nil? - - send("#{meta}=", url) - end - end - end - end -end diff --git a/lib/gitlab/paginated_response.rb b/lib/gitlab/paginated_response.rb index 90513e2dc..4dbbcf4fa 100644 --- a/lib/gitlab/paginated_response.rb +++ b/lib/gitlab/paginated_response.rb @@ -30,7 +30,8 @@ def respond_to_missing?(method_name, include_private = false) end def parse_headers!(headers) - @links = PageLinks.new headers + @links = Headers::PageLinks.new headers + @total = Headers::Total.new headers end def each_page @@ -58,6 +59,10 @@ def paginate_with_limit(limit, &block) lazy_paginate.take(limit).each(&block) end + def total + @total.total + end + def last_page? !(@links.nil? || @links.last.nil?) end diff --git a/spec/gitlab/page_links_spec.rb b/spec/gitlab/headers/page_links_spec.rb similarity index 95% rename from spec/gitlab/page_links_spec.rb rename to spec/gitlab/headers/page_links_spec.rb index 6bf4a62db..cb1b6ee3d 100644 --- a/spec/gitlab/page_links_spec.rb +++ b/spec/gitlab/headers/page_links_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::PageLinks do +RSpec.describe Gitlab::Headers::PageLinks do before do @page_links = described_class.new('Link' => '; rel="first", ; rel="last", ; rel="prev", ; rel="next"') end diff --git a/spec/gitlab/headers/total_spec.rb b/spec/gitlab/headers/total_spec.rb new file mode 100644 index 000000000..a2616bee6 --- /dev/null +++ b/spec/gitlab/headers/total_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Headers::Total do + before do + @total = described_class.new('x-total' => ' 8 ') + end + + describe '.extract_total' do + it 'extracts total header appropriately' do + expect(@total.total).to eql('8') + end + end +end diff --git a/spec/gitlab/paginated_response_spec.rb b/spec/gitlab/paginated_response_spec.rb index 4cae308e5..aaa761fe1 100644 --- a/spec/gitlab/paginated_response_spec.rb +++ b/spec/gitlab/paginated_response_spec.rb @@ -8,7 +8,7 @@ @paginated_response = described_class.new array end - it 'responds to *_page and has_*_page methods' do + it 'responds to total, *_page and has_*_page methods' do expect(@paginated_response).to respond_to :first_page expect(@paginated_response).to respond_to :last_page expect(@paginated_response).to respond_to :next_page @@ -17,11 +17,12 @@ expect(@paginated_response).to respond_to :has_last_page? expect(@paginated_response).to respond_to :has_next_page? expect(@paginated_response).to respond_to :has_prev_page? + expect(@paginated_response).to respond_to :total end describe '.parse_headers!' do it 'parses headers' do - @paginated_response.parse_headers!('Link' => '; rel="first", ; rel="last"') + @paginated_response.parse_headers!('Link' => '; rel="first", ; rel="last"', 'x-total' => '8') client = @paginated_response.client = double('client') first_page_response = double('first_page_response') last_page_response = double('last_page_response') @@ -36,6 +37,7 @@ expect(@paginated_response.last_page).to be last_page_response expect(@paginated_response.next_page).to be_nil expect(@paginated_response.prev_page).to be_nil + expect(@paginated_response.total).to eq('8') end context 'when the Link header endpoint does not match the configured endpoint' do