diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 2d42cce95cebc9c28f1ffd8603d9baba6ae0ba36..b30a01614be3056b5da65ba8fbb46fe165469919 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 4c770c0b9dd11f1a55163fbac4d35969f49bf601..9f5f10a5088a8b833e37cdcb638ea0f3f72fb311 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 e1cdfc8f5f6267d2da355d5aa1de7dfc631a1bd3..652a496b57b87b946462e7e8e254d7790d9dae6c 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 73fb3b18c4df3c24a0258558cd845edcb20ff808..964fbfd4de330ef82019a615d67be438dcb2eedf 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 0000000000000000000000000000000000000000..20377499ac9339c58cae612db585da3a37dbd4a8
--- /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 36ffad8aae9035b5b8ce20c4b9b8e2d38f41e08e..90b1a64ed5aafbef19a44f126f22035c46f58c01 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 9130312c05735133fc42e01d93f530ccebc9678d..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..0e9a28b1ff61367d67b076e10a04e094eabf20ab
--- /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