From 620d014aefd23030ed6ae043e223ccc5dc52fc8a Mon Sep 17 00:00:00 2001
From: "Z.J. van de Weg" <zegerjan@gitlab.com>
Date: Thu, 2 Jun 2016 18:20:08 +0200
Subject: [PATCH] Implement backend gitlab ci dropdown

This commit builds on the groundwork in
ee008e300b1ec0abcc90e6a30816ec0754cea0dd, which refactored the backend
so the same code could be used for new dropdowns. In this commit its
used for templates for the `.gitlab-ci.yml` files.
---
 app/helpers/blob_helper.rb             | 14 +++++--
 lib/api/templates.rb                   |  3 +-
 lib/gitlab/template/base_template.rb   | 35 ++++++++++------
 lib/gitlab/template/gitignore.rb       |  5 +--
 lib/gitlab/template/gitlab_ci_yml.rb   | 22 +++++++++++
 lib/tasks/gitlab/update_templates.rake | 55 +++++++++++---------------
 spec/requests/api/gitignores_spec.rb   | 29 --------------
 spec/requests/api/templates_spec.rb    | 43 ++++++++++++++++++++
 8 files changed, 126 insertions(+), 80 deletions(-)
 create mode 100644 lib/gitlab/template/gitlab_ci_yml.rb
 delete mode 100644 spec/requests/api/gitignores_spec.rb
 create mode 100644 spec/requests/api/templates_spec.rb

diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 2d42cce95ce..b30a01614be 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -186,10 +186,16 @@ module BlobHelper
   end
 
   def gitignore_names
-    return @gitignore_names if defined?(@gitignore_names)
+    @gitignore_names ||=
+      Gitlab::Template::Gitignore.categories.keys.map do |k|
+        [k, Gitlab::Template::Gitignore.by_category(k).map { |t| { name: t.name } }]
+      end.to_h
+  end
 
-    @gitignore_names = Gitlab::Template::Gitignore.categories.map do |k, _|
-      [k, Gitlab::Template::Gitignore.by_category(k)]
-    end.to_h
+  def gitlab_ci_ymls
+    @gitlab_ci_ymls ||=
+      Gitlab::Template::GitlabCIYml.categories.keys.map do |k|
+        [k, Gitlab::Template::GitlabCIYml.by_category(k).map { |t| { name: t.name } }]
+      end.to_h
   end
 end
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index 4c770c0b9dd..9f5f10a5088 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -1,7 +1,8 @@
 module API
   class Templates < Grape::API
     TEMPLATE_TYPES = {
-      gitignores:     Gitlab::Template::Gitignore
+      gitignores:     Gitlab::Template::Gitignore,
+      gitlab_ci_ymls: Gitlab::Template::GitlabCIYml
     }.freeze
 
     TEMPLATE_TYPES.each do |template, klass|
diff --git a/lib/gitlab/template/base_template.rb b/lib/gitlab/template/base_template.rb
index e1cdfc8f5f6..652a496b57b 100644
--- a/lib/gitlab/template/base_template.rb
+++ b/lib/gitlab/template/base_template.rb
@@ -13,40 +13,53 @@ module Gitlab
         File.read(@path)
       end
 
+      def categories
+        raise NotImplementedError
+      end
+
+      def extension
+        raise NotImplementedError
+      end
+
+      def base_dir
+        raise NotImplementedError
+      end
+
       class << self
         def all
-          self.category_directories.flat_map do |dir|
-            templates_for_folder(dir)
-          end
+          self.categories.keys.flat_map { |cat| by_category(cat) }
         end
 
         def find(key)
           file_name = "#{key}#{self.extension}"
 
           directory = select_directory(file_name)
-          directory ? new(File.join(directory, file_name)) : nil
+          directory ? new(File.join(category_directory(directory), file_name)) : nil
         end
 
         def by_category(category)
-          templates_for_folder(categories[category])
+          templates_for_directory(category_directory(category))
         end
 
-        def category_directories
-          self.categories.values.map { |subdir| File.join(base_dir, subdir)}
+        def category_directory(category)
+          File.join(base_dir, categories[category])
         end
 
         private
 
         def select_directory(file_name)
-          category_directories.find { |dir| File.exist?(File.join(dir, file_name)) }
+          categories.keys.find do |category|
+            File.exist?(File.join(category_directory(category), file_name))
+          end
         end
 
-        def templates_for_folder(dir)
-          Dir.glob("#{dir.to_s}/*#{self.extension}").select { |f| f =~ filter_regex }.map { |f| new(f) }
+        def templates_for_directory(dir)
+          dir << '/' unless dir.end_with?('/')
+          Dir.glob(File.join(dir, "*#{self.extension}")).select { |f| f =~ filter_regex }.map { |f| new(f) }
         end
 
         def filter_regex
-          /#{Regexp.escape(extension)}\z/
+          @filter_reges ||= /#{Regexp.escape(extension)}\z/
         end
       end
     end
diff --git a/lib/gitlab/template/gitignore.rb b/lib/gitlab/template/gitignore.rb
index 73fb3b18c4d..964fbfd4de3 100644
--- a/lib/gitlab/template/gitignore.rb
+++ b/lib/gitlab/template/gitignore.rb
@@ -1,7 +1,6 @@
 module Gitlab
   module Template
     class Gitignore < BaseTemplate
-
       class << self
         def extension
           '.gitignore'
@@ -9,8 +8,8 @@ module Gitlab
 
         def categories
           {
-            Languages:  '',
-            Global:     'Global'
+            "Languages" => '',
+            "Global"    => 'Global'
           }
         end
 
diff --git a/lib/gitlab/template/gitlab_ci_yml.rb b/lib/gitlab/template/gitlab_ci_yml.rb
new file mode 100644
index 00000000000..20377499ac9
--- /dev/null
+++ b/lib/gitlab/template/gitlab_ci_yml.rb
@@ -0,0 +1,22 @@
+module Gitlab
+  module Template
+    class GitlabCIYml < BaseTemplate
+      class << self
+        def extension
+          '.gitlab-ci.yml'
+        end
+
+        def categories
+          {
+            "General" => '',
+            "Pages"   =>'Pages'
+          }
+        end
+
+        def base_dir
+          Rails.root.join('vendor/gitlab-ci-yml')
+        end
+      end
+    end
+  end
+end
diff --git a/lib/tasks/gitlab/update_templates.rake b/lib/tasks/gitlab/update_templates.rake
index 36ffad8aae9..90b1a64ed5a 100644
--- a/lib/tasks/gitlab/update_templates.rake
+++ b/lib/tasks/gitlab/update_templates.rake
@@ -1,35 +1,34 @@
 namespace :gitlab do
   desc "GitLab | Update templates"
   task :update_templates do
-    update("gitignore")
-    update("gitlab-ci-yml")
+    TEMPLATE_DATA.each { |template| update(template) }
   end
 
-  def update(directory)
-    unless clone_repository(directory)
-      puts "Cloning the #{directory} templates failed".red
+  def update(template)
+    sub_dir = template.repo_url.match(/([a-z-]+)\.git\z/)[1]
+    dir = File.join(vendor_directory, sub_dir)
+
+    unless clone_repository(template.repo_url, dir)
+      puts "Cloning the #{sub_dir} templates failed".red
       return
     end
 
-    remove_unneeded_files(directory)
+    remove_unneeded_files(dir, template.cleanup_regex)
     puts "Done".green
   end
 
-  def clone_repository(directory)
-    dir = File.join(vendor_directory, directory)
-    FileUtils.rm_rf(dir) if Dir.exist?(dir)
-    FileUtils.cd vendor_directory
+  def clone_repository(url, directory)
+    FileUtils.rm_rf(directory) if Dir.exist?(directory)
 
-    system("git clone --depth=1 --branch=master #{TEMPLATE_DATA[directory]}")
+    system("git clone #{url} --depth=1 --branch=master #{directory}")
   end
 
   # Retain only certain files:
   # - The LICENSE, because we have to
-  # - The sub dir global
-  # - The gitignores themself
+  # - The sub dirs so we can organise the file by category
+  # - The templates themself
   # - Dir.entires returns also the entries '.' and '..'
-  def remove_unneeded_files(directory)
-    regex = CLEANUP_REGEX[directory]
+  def remove_unneeded_files(directory, regex)
     Dir.foreach(directory) do |file|
       FileUtils.rm_rf(File.join(directory, file)) unless file =~ regex
     end
@@ -37,25 +36,17 @@ namespace :gitlab do
 
   private
 
-  TEMPLATE_DATA = {
-      "gitignore" => "https://github.com/github/gitignore.git",
-      "gitlab-ci-yml" => "https://gitlab.com/gitlab-org/gitlab-ci-yml.git"
-  }.freeze
-
-  CLEANUP_REGEX = {
-    "gitignore" => /(\.{1,2}|LICENSE|Global|\.gitignore)\z/,
-    "gitlab-ci-yml" => /(\.{1,2}|LICENSE|Pages|\.gitignore)\z/
-  }.freeze
+  Template = Struct.new(:repo_url, :cleanup_regex)
+  TEMPLATE_DATA = [Template.new(
+        "https://github.com/github/gitignore.git",
+        /(\.{1,2}|LICENSE|Global|\.gitignore)\z/
+      ),
+      Template.new(
+        "https://gitlab.com/gitlab-org/gitlab-ci-yml.git",
+        /(\.{1,2}|LICENSE|Pages|\.gitignore)\z/
+      )]
 
   def vendor_directory
     Rails.root.join('vendor')
   end
-
-  def gitignore_directory
-    File.join(vendor_directory, 'gitignore')
-  end
-
-  def gitlab_ci_directory
-    File.join(vendor_directory, 'gitlab-ci')
-  end
 end
diff --git a/spec/requests/api/gitignores_spec.rb b/spec/requests/api/gitignores_spec.rb
deleted file mode 100644
index 9130312c057..00000000000
--- a/spec/requests/api/gitignores_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'spec_helper'
-
-describe API::Templates, api: true  do
-  include ApiHelpers
-
-  describe 'Entity Gitignore' do
-    before { get api('/gitignores/Ruby') }
-
-    it { expect(json_response['name']).to eq('Ruby') }
-    it { expect(json_response['content']).to include('*.gem') }
-  end
-
-  describe 'Entity GitignoresList' do
-    before { get api('/gitignores') }
-
-    it { expect(json_response.first['name']).not_to be_nil }
-    it { expect(json_response.first['content']).to be_nil }
-  end
-
-  describe 'GET /gitignores' do
-    it 'returns a list of available license templates' do
-      get api('/gitignores')
-
-      expect(response.status).to eq(200)
-      expect(json_response).to be_an Array
-      expect(json_response.size).to be > 15
-    end
-  end
-end
diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb
new file mode 100644
index 00000000000..0e9a28b1ff6
--- /dev/null
+++ b/spec/requests/api/templates_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe API::Templates, api: true  do
+  include ApiHelpers
+
+  describe 'the Template Entity' do
+    before { get api('/gitignores/Ruby') }
+
+    it { expect(json_response['name']).to eq('Ruby') }
+    it { expect(json_response['content']).to include('*.gem') }
+  end
+
+  describe 'the TemplateList Entity' do
+    before { get api('/gitignores') }
+
+    it { expect(json_response.first['name']).not_to be_nil }
+    it { expect(json_response.first['content']).to be_nil }
+  end
+
+  context 'requesting gitignores' do
+    describe 'GET /gitignores' do
+      it 'returns a list of available gitignore templates' do
+        get api('/gitignores')
+
+        expect(response.status).to eq(200)
+        expect(json_response).to be_an Array
+        expect(json_response.size).to be > 15
+      end
+    end
+  end
+
+  context 'requesting gitlab-ci-ymls' do
+    describe 'GET /gitlab_ci_ymls' do
+      it 'returns a list of available gitlab_ci_ymls' do
+        get api('/gitlab_ci_ymls')
+
+        expect(response.status).to eq(200)
+        expect(json_response).to be_an Array
+        expect(json_response.first['name']).not_to be_nil
+      end
+    end
+  end
+end
-- 
GitLab