From 9b0f57781e8c71eb0e627a63078fedcedfe62bbb Mon Sep 17 00:00:00 2001
From: Kamil Trzcinski <ayufan@ayufan.eu>
Date: Wed, 20 Jan 2016 21:48:22 +0100
Subject: [PATCH] Add method that calculates total size for artifacts subfolder

---
 app/models/ci/build.rb                          |  8 ++++----
 app/views/projects/builds/show.html.haml        |  2 +-
 lib/gitlab/ci/build/artifacts/metadata.rb       |  8 +++++---
 lib/gitlab/ci/build/artifacts/metadata/entry.rb |  7 +++++++
 .../ci/build/artifacts/metadata/entry_spec.rb   | 15 ++++++++++-----
 .../gitlab/ci/build/artifacts/metadata_spec.rb  | 17 +++++++++++++++--
 spec/models/build_spec.rb                       |  8 ++++----
 7 files changed, 46 insertions(+), 19 deletions(-)

diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 16a5b03f591..623edd8bc57 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -346,17 +346,17 @@ module Ci
     end
 
     def artifacts_browse_url
-      if artifacts_browser_supported?
+      if artifacts_metadata?
         browse_namespace_project_build_artifacts_path(project.namespace, project, self)
       end
     end
 
-    def artifacts_browser_supported?
+    def artifacts_metadata?
       artifacts? && artifacts_metadata.exists?
     end
 
-    def artifacts_metadata_entry(path)
-      Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path).to_entry
+    def artifacts_metadata_entry(path, **options)
+      Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path, **options).to_entry
     end
 
     private
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index 2be572d3b10..ba1fdc6f0e7 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -96,7 +96,7 @@
           .center
             .btn-group{ role: :group }
               = link_to "Download", @build.artifacts_download_url, class: 'btn btn-sm btn-primary'
-              - if @build.artifacts_browser_supported?
+              - if @build.artifacts_metadata?
                 = link_to "Browse", @build.artifacts_browse_url, class: 'btn btn-sm btn-primary'
 
       .build-widget
diff --git a/lib/gitlab/ci/build/artifacts/metadata.rb b/lib/gitlab/ci/build/artifacts/metadata.rb
index 1344f5d120b..f2020c82d40 100644
--- a/lib/gitlab/ci/build/artifacts/metadata.rb
+++ b/lib/gitlab/ci/build/artifacts/metadata.rb
@@ -13,8 +13,8 @@ module Gitlab
 
           attr_reader :file, :path, :full_version
 
-          def initialize(file, path)
-            @file, @path = file, path
+          def initialize(file, path, **opts)
+            @file, @path, @opts = file, path, opts
             @full_version = read_version
           end
 
@@ -52,7 +52,9 @@ module Gitlab
 
           def match_entries(gz)
             entries = {}
-            match_pattern = %r{^#{Regexp.escape(@path)}[^/]*/?$}
+
+            child_pattern = '[^/]*/?$' unless @opts[:recursive]
+            match_pattern = /^#{Regexp.escape(@path)}#{child_pattern}/
 
             until gz.eof? do
               begin
diff --git a/lib/gitlab/ci/build/artifacts/metadata/entry.rb b/lib/gitlab/ci/build/artifacts/metadata/entry.rb
index 25b71fc3275..7f4c750b6fd 100644
--- a/lib/gitlab/ci/build/artifacts/metadata/entry.rb
+++ b/lib/gitlab/ci/build/artifacts/metadata/entry.rb
@@ -95,6 +95,13 @@ module Gitlab
           children.empty?
         end
 
+        def total_size
+          descendant_pattern = %r{^#{Regexp.escape(@path)}}
+          entries.sum do |path, entry|
+            (entry[:size] if path =~ descendant_pattern).to_i
+          end
+        end
+
         def to_s
           @path
         end
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
index 41257103ead..acca0b08bab 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
@@ -4,13 +4,13 @@ describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
   let(:entries) do
     { 'path/' => {},
       'path/dir_1/' => {},
-      'path/dir_1/file_1' => {},
-      'path/dir_1/file_b' => {},
+      'path/dir_1/file_1' => { size: 10 },
+      'path/dir_1/file_b' => { size: 10 },
       'path/dir_1/subdir/' => {},
-      'path/dir_1/subdir/subfile' => {},
+      'path/dir_1/subdir/subfile' => { size: 10 },
       'path/second_dir' => {},
-      'path/second_dir/dir_3/file_2' => {},
-      'path/second_dir/dir_3/file_3'=> {},
+      'path/second_dir/dir_3/file_2' => { size: 10 },
+      'path/second_dir/dir_3/file_3'=> { size: 10 },
       'another_directory/'=> {},
       'another_file' => {},
       '/file/with/absolute_path' => {} }
@@ -112,6 +112,11 @@ describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
         subject { |example| path(example).empty? }
         it { is_expected.to be false }
       end
+
+      describe '#total_size' do
+        subject { |example| path(example).total_size }
+        it { is_expected.to eq(30) }
+      end
     end
   end
 
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
index 828eedfa7b0..eea01f91879 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
@@ -1,8 +1,8 @@
 require 'spec_helper'
 
 describe Gitlab::Ci::Build::Artifacts::Metadata do
-  def metadata(path = '')
-    described_class.new(metadata_file_path, path)
+  def metadata(path = '', **opts)
+    described_class.new(metadata_file_path, path, **opts)
   end
 
   let(:metadata_file_path) do
@@ -51,6 +51,19 @@ describe Gitlab::Ci::Build::Artifacts::Metadata do
       end
     end
 
+    describe '#find_entries! recursively for other_artifacts_0.1.2/' do
+      subject { metadata('other_artifacts_0.1.2/', recursive: true).find_entries! }
+
+      it 'matches correct paths' do
+        expect(subject.keys).
+          to contain_exactly 'other_artifacts_0.1.2/',
+                             'other_artifacts_0.1.2/doc_sample.txt',
+                             'other_artifacts_0.1.2/another-subdirectory/',
+                             'other_artifacts_0.1.2/another-subdirectory/empty_directory/',
+                             'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
+      end
+    end
+
     describe '#to_entry' do
       subject { metadata('').to_entry }
       it { is_expected.to be_an_instance_of(Gitlab::Ci::Build::Artifacts::Metadata::Entry) }
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index d12b9e65c82..d30bc7d0554 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -362,12 +362,12 @@ describe Ci::Build, models: true do
     subject { build.artifacts_browse_url }
 
     it "should be nil if artifacts browser is unsupported" do
-      allow(build).to receive(:artifacts_browser_supported?).and_return(false)
+      allow(build).to receive(:artifacts_metadata?).and_return(false)
       is_expected.to be_nil
     end
 
     it 'should not be nil if artifacts browser is supported' do
-      allow(build).to receive(:artifacts_browser_supported?).and_return(true)
+      allow(build).to receive(:artifacts_metadata?).and_return(true)
       is_expected.to_not be_nil
     end
   end
@@ -391,8 +391,8 @@ describe Ci::Build, models: true do
   end
 
 
-  describe :artifacts_browser_supported? do
-    subject { build.artifacts_browser_supported? }
+  describe :artifacts_metadata? do
+    subject { build.artifacts_metadata? }
     context 'artifacts metadata does not exist' do
       it { is_expected.to be_falsy }
     end
-- 
GitLab