# HG changeset patch
# User Balasankar 'Balu' C <balasankar@gitlab.com>
# Date 1647571604 0
#      Fri Mar 18 02:46:44 2022 +0000
# Node ID 6cf620bad9384163c45ed979f6e9972970fcd84d
# Parent  2296db406e195efb692dd70d62c5fda3e78b7a1d
Move specs testing non-chef components to own directory

- Moves Build and Tasks rspecs into the lib directory

Closes https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3217

Signed-off-by: Balasankar "Balu" C <balasankar@gitlab.com>

diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,5 @@
 node_modules
 
 spec/examples.txt
+
+.projections.json
diff --git a/.projections.json.example b/.projections.json.example
new file mode 100644
--- /dev/null
+++ b/.projections.json.example
@@ -0,0 +1,11 @@
+{
+  "lib/*.rb": {
+    "alternate": "spec/lib/{}_spec.rb",
+    "type": "source"
+  },
+  "spec/lib/*_spec.rb": {
+    "alternate": "lib/{}.rb",
+    "type": "test",
+    "dispatch": "bundle exec rspec {file}"
+  }
+}
diff --git a/.rubocop.yml b/.rubocop.yml
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -70,7 +70,7 @@
     - files/**/*
     - docker/**/*
     - lib/gitlab/util.rb
-    - spec/gitlab/util_spec.rb
+    - spec/lib/gitlab/util_spec.rb
 
 Style/MultilineIfModifier:
   Enabled: false
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -68,8 +68,8 @@
     - 'files/gitlab-ctl-commands/upgrade.rb'
     - 'spec/chef/secrets_spec.rb'
     - 'spec/gitlab-ctl-commands/gitlab_ctl_spec.rb'
-    - 'spec/gitlab/build/image_spec.rb'
-    - 'spec/gitlab/tasks/qa_spec.rb'
+    - 'spec/lib/gitlab/build/image_spec.rb'
+    - 'spec/lib/gitlab/tasks/qa_spec.rb'
     - 'spec/support/shared_examples/geo_promotion_command_accepts_option_shared_examples.rb'
     - 'spec/support/shared_examples/gitlab_geo_promotion_commands_shared_examples.rb'
 
diff --git a/spec/gitlab/build/check_spec.rb b/spec/gitlab/build/check_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build/check_spec.rb
+++ /dev/null
@@ -1,171 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build/check'
-
-RSpec.describe Build::Check do
-  before do
-    stub_default_package_version
-  end
-
-  describe 'is_ee?' do
-    describe 'with environment variables' do
-      before do
-        stub_is_ee_version(false)
-      end
-
-      describe 'ee variable' do
-        it 'when ee=true' do
-          stub_is_ee_env(true)
-          expect(described_class.is_ee?).to be_truthy
-        end
-
-        it 'when ee=false' do
-          stub_is_ee(false)
-          expect(described_class.is_ee?).to be_falsy
-        end
-
-        it 'when env variable is not set' do
-          stub_is_ee_version(false)
-          stub_is_auto_deploy(false)
-          expect(described_class.is_ee?).to be_falsy
-        end
-      end
-
-      describe 'GITLAB_VERSION variable' do
-        it 'when GITLAB_VERSION ends with -ee' do
-          stub_env_var('GITLAB_VERSION', 'foo-ee')
-          expect(described_class.is_ee?).to be_truthy
-        end
-
-        it 'when GITLAB_VERSION does not end with -ee' do
-          stub_env_var('GITLAB_VERSION', 'foo')
-          stub_is_auto_deploy(false)
-          expect(described_class.is_ee?).to be_falsy
-        end
-
-        it 'ee variable wins over GITLAB_VERSION variable' do
-          stub_is_ee_env(true)
-          stub_env_var('GITLAB_VERSION', 'foo')
-          expect(described_class.is_ee?).to be_truthy
-        end
-      end
-    end
-
-    describe 'without environment variables' do
-      it 'checks the VERSION file' do
-        stub_is_ee_version(false)
-        stub_env_var('GITLAB_VERSION', 'foo-ee')
-        expect(described_class.is_ee?).to be_truthy
-      end
-
-      it 'GITLAB_VERSION variable wins over the file' do
-        stub_env_var('GITLAB_VERSION', 'foo-ee')
-        expect(described_class.is_ee?).to be_truthy
-      end
-    end
-  end
-
-  describe 'include_ee?' do
-    it 'returns true when is_ee? is true' do
-      allow(described_class).to receive(:is_ee?).and_return(true)
-      expect(described_class.include_ee?).to be_truthy
-    end
-
-    it 'returns false when we are building a ce package' do
-      allow(described_class).to receive(:is_ee?).and_return(false)
-      expect(described_class.include_ee?).to be_falsey
-    end
-  end
-
-  describe 'add tag methods' do
-    describe 'is_nightly?' do
-      it 'returns true if it is a nightly build' do
-        stub_env_var('NIGHTLY', 'true')
-        expect(described_class.is_nightly?).to be_truthy
-      end
-
-      it 'returns false if it is not a nightly build' do
-        expect(described_class.is_nightly?).to be_falsey
-      end
-    end
-
-    describe 'is_latest_tag?' do
-      it 'returns true if it is an rc release' do
-        # This will be the case if latest_tag is eg. 9.3.0+rc6.ce.0
-        # or 9.3.0+ce.0
-        allow(Build::Info).to receive(:latest_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
-        allow(described_class).to receive(:match_tag?).and_return(true)
-        expect(described_class.is_latest_tag?).to be_truthy
-      end
-
-      it 'returns true if it is not an rc release' do
-        allow(Build::Info).to receive(:latest_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
-        allow(described_class).to receive(:match_tag?).and_return(false)
-        expect(described_class.is_latest_tag?).to be_falsey
-      end
-    end
-
-    describe 'is_latest_stable_tag?' do
-      it 'returns true if it is a stable release' do
-        # This will be the case if latest_tag is eg. 9.3.0+ce.0
-        # It will not be the case if the tag is 9.3.0+rc6.ce.0
-        allow(Build::Info).to receive(:latest_stable_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
-        allow(described_class).to receive(:match_tag?).and_return(true)
-        expect(described_class.is_latest_stable_tag?).to be_truthy
-      end
-
-      it 'returns true if it is not a stable release' do
-        allow(Build::Info).to receive(:latest_stable_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
-        allow(described_class).to receive(:match_tag?).and_return(false)
-        expect(described_class.is_latest_stable_tag?).to be_falsey
-      end
-    end
-  end
-
-  describe '.is_patch_release?' do
-    it 'returns true for patch release' do
-      allow(Build::Info).to receive(:semver_version).and_return("10.0.3")
-      expect(described_class.is_patch_release?).to be_truthy
-    end
-
-    it 'returns false for major/minor release' do
-      allow(Build::Info).to receive(:semver_version).and_return("10.0.0")
-      expect(described_class.is_patch_release?).to be_falsey
-    end
-  end
-
-  describe 'is_rc_tag?' do
-    it 'returns true if it looks like an rc tag' do
-      # It will be the case if the tag is 9.3.0+rc6.ce.0
-      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+rc6.ce.0')
-      expect(described_class.is_rc_tag?).to be_truthy
-    end
-    it 'returns false if it does not look like an rc tag' do
-      # This not be the case if tag is eg. 9.3.0+ce.0
-      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+ce.0')
-      expect(described_class.is_rc_tag?).to be_falsey
-    end
-  end
-
-  describe 'is_auto_deploy?' do
-    it 'returns true if it looks like an auto-deploy tag' do
-      # This is the case if the tag is 11.10.12345+5159f2949cb.59c9fa631
-      allow(Build::Info).to receive(:current_git_tag).and_return('11.10.12345+5159f2949cb.59c9fa631')
-      expect(described_class.is_auto_deploy?).to be_truthy
-    end
-
-    it 'returns false if it does not look like an auto-deploy tag' do
-      # This not be the case if ag is eg. 9.3.0+ce.0
-      allow(Gitlab::Util).to receive(:get_env).with('CI_COMMIT_REF_NAME').and_return('a-random-branch')
-
-      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+ce.0')
-      expect(described_class.is_auto_deploy?).to be_falsey
-    end
-  end
-
-  describe 'ci_commit_tag?' do
-    it 'checks for the CI_COMMIT_TAG' do
-      allow(Gitlab::Util).to receive(:get_env).with('CI_COMMIT_TAG').and_return('11.10.12345+5159f2949cb.59c9fa631')
-      expect(described_class.ci_commit_tag?).to be_truthy
-    end
-  end
-end
diff --git a/spec/gitlab/build/facts_spec.rb b/spec/gitlab/build/facts_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build/facts_spec.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build/facts'
-require 'gitlab/build/gitlab_image'
-
-RSpec.describe Build::Facts do
-  before do
-    allow(ENV).to receive(:[]).and_call_original
-  end
-
-  describe '.generate' do
-    it 'calls necessary methods' do
-      expect(described_class).to receive(:generate_tag_files)
-      expect(described_class).to receive(:generate_env_file)
-
-      described_class.generate
-    end
-  end
-
-  describe '.generate_tag_files' do
-    before do
-      allow(Build::Info).to receive(:latest_stable_tag).and_return('14.6.2+ce.0')
-      allow(Build::Info).to receive(:latest_tag).and_return('14.7.0+rc42.ce.0')
-    end
-
-    it 'writes tag details to file' do
-      expect(File).to receive(:write).with('build_facts/latest_stable_tag', '14.6.2+ce.0')
-      expect(File).to receive(:write).with('build_facts/latest_tag', '14.7.0+rc42.ce.0')
-
-      described_class.generate_tag_files
-    end
-  end
-
-  describe '.generate_env_file' do
-    before do
-      allow(described_class).to receive(:common_vars).and_return(%w[TOP_UPSTREAM_SOURCE_PROJECT=gitlab-org/gitlab])
-      allow(described_class).to receive(:qa_trigger_vars).and_return(%w[QA_RELEASE=foobar])
-      allow(described_class).to receive(:version_vars).and_return(%w[GITLAB_VERSION=randombranch])
-    end
-
-    it 'writes environment variables to file' do
-      expect(File).to receive(:write).with('build_facts/env_vars', "TOP_UPSTREAM_SOURCE_PROJECT=gitlab-org/gitlab\nQA_RELEASE=foobar\nGITLAB_VERSION=randombranch")
-
-      described_class.generate_env_file
-    end
-  end
-
-  describe '.common_vars' do
-    before do
-      stub_env_var('TOP_UPSTREAM_SOURCE_PROJECT', 'gitlab-org/gitlab')
-      stub_env_var('TOP_UPSTREAM_SOURCE_REF', 'master')
-      stub_env_var('TOP_UPSTREAM_SOURCE_JOB', '123456')
-      stub_env_var('TOP_UPSTREAM_SOURCE_SHA', 'aq2456fs')
-      stub_env_var('TOP_UPSTREAM_MERGE_REQUEST_PROJECT_ID', '55555')
-      stub_env_var('TOP_UPSTREAM_MERGE_REQUEST_IID', '7689')
-    end
-
-    it 'returns correct variables' do
-      result = %w[
-        TOP_UPSTREAM_SOURCE_PROJECT=gitlab-org/gitlab
-        TOP_UPSTREAM_SOURCE_REF=master
-        TOP_UPSTREAM_SOURCE_JOB=123456
-        TOP_UPSTREAM_SOURCE_SHA=aq2456fs
-        TOP_UPSTREAM_MERGE_REQUEST_PROJECT_ID=55555
-        TOP_UPSTREAM_MERGE_REQUEST_IID=7689
-      ]
-
-      expect(described_class.common_vars).to eq(result)
-    end
-  end
-
-  describe '.qa_trigger_vars' do
-    before do
-      allow(described_class).to receive(:generate_knapsack_report?).and_return('true')
-      allow(Build::GitlabImage).to receive(:gitlab_registry_image_address).and_return('registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:14.6.2-rfbranch.450066356.c97110ad-0')
-
-      stub_env_var('QA_IMAGE', 'gitlab/gitlab-ee-qa:nightly')
-      stub_env_var('QA_TESTS', '')
-      stub_env_var('ALLURE_JOB_NAME', '')
-      stub_env_var('GITLAB_QA_OPTIONS', '')
-    end
-
-    it 'returns correct variables' do
-      result = %w[
-        QA_BRANCH=master
-        QA_RELEASE=registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:14.6.2-rfbranch.450066356.c97110ad-0
-        QA_IMAGE=gitlab/gitlab-ee-qa:nightly
-        QA_TESTS=
-        ALLURE_JOB_NAME=
-        GITLAB_QA_OPTIONS=
-        KNAPSACK_GENERATE_REPORT=true
-      ]
-
-      expect(described_class.qa_trigger_vars).to eq(result)
-    end
-  end
-end
diff --git a/spec/gitlab/build/gitlab_image_spec.rb b/spec/gitlab/build/gitlab_image_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build/gitlab_image_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build/gitlab_image'
-
-RSpec.describe Build::GitlabImage do
-  before do
-    allow(Build::Info).to receive(:package).and_return('gitlab-ce')
-  end
-
-  describe '.dockerhub_image_name' do
-    it 'returns a correct image name' do
-      expect(described_class.dockerhub_image_name).to eq('gitlab/gitlab-ce')
-    end
-  end
-
-  describe '.gitlab_registry_image_name' do
-    it 'returns a correct image name' do
-      expect(described_class.gitlab_registry_image_name).to eq('gitlab-ce')
-    end
-  end
-end
diff --git a/spec/gitlab/build/image_spec.rb b/spec/gitlab/build/image_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build/image_spec.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build/image'
-
-RSpec.describe Build::Image do
-  ComponentImage = Class.new do
-    extend Build::Image
-
-    def self.gitlab_registry_image_name
-      'my-project/my-image'
-    end
-
-    def self.dockerhub_image_name
-      'my-image'
-    end
-  end
-
-  before do
-    allow(ENV).to receive(:[]).and_call_original
-    allow(ENV).to receive(:[]).with('CI_JOB_TOKEN').and_return('1234')
-    allow(ENV).to receive(:[]).with('CI_REGISTRY').and_return('registry.com')
-    allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('registry.com/group/repo')
-    allow(ENV).to receive(:[]).with('DOCKERHUB_USERNAME').and_return('john')
-    allow(ENV).to receive(:[]).with('DOCKERHUB_PASSWORD').and_return('secret')
-    allow(Build::Info).to receive(:docker_tag).and_return('9.0.0')
-  end
-
-  describe '.pull' do
-    it 'creates an image from the local one' do
-      expect(Docker::Image).to receive(:create).with(
-        'fromImage' => "#{ComponentImage.gitlab_registry_image_address}:9.0.0"
-      )
-
-      ComponentImage.pull
-    end
-  end
-
-  describe '.gitlab_registry_image_address' do
-    it 'returns a correct image name' do
-      expect(ComponentImage.gitlab_registry_image_address).to eq('registry.com/group/repo/my-project/my-image')
-    end
-
-    context 'with a tag given' do
-      it 'returns a correct image name' do
-        expect(ComponentImage.gitlab_registry_image_address(tag: 'mytag')).to eq('registry.com/group/repo/my-project/my-image:mytag')
-      end
-    end
-  end
-
-  describe '.tag_and_push_to_gitlab_registry' do
-    it 'calls DockerOperations.authenticate and DockerOperations.tag_and_push' do
-      expect(DockerOperations).to receive(:authenticate).with('gitlab-ci-token', '1234', 'registry.com')
-      expect(DockerOperations).to receive(:tag_and_push).with(
-        ComponentImage.gitlab_registry_image_address,
-        ComponentImage.gitlab_registry_image_address,
-        'latest',
-        'foo'
-      )
-
-      ComponentImage.tag_and_push_to_gitlab_registry('foo')
-    end
-  end
-
-  describe '.tag_and_push_to_dockerhub' do
-    it 'calls DockerOperations.authenticate and DockerOperations.tag_and_push' do
-      expect(DockerOperations).to receive(:authenticate).with('john', 'secret')
-      expect(DockerOperations).to receive(:tag_and_push).with(
-        ComponentImage.gitlab_registry_image_address,
-        ComponentImage.dockerhub_image_name,
-        '9.0.0',
-        'foo'
-      )
-
-      ComponentImage.tag_and_push_to_dockerhub('foo')
-    end
-
-    context 'with a initial_tag given' do
-      it 'calls DockerOperations.authenticate and DockerOperations.tag_and_push' do
-        expect(DockerOperations).to receive(:authenticate).with('john', 'secret')
-        expect(DockerOperations).to receive(:tag_and_push).with(
-          ComponentImage.gitlab_registry_image_address,
-          ComponentImage.dockerhub_image_name,
-          'latest',
-          'foo'
-        )
-
-        ComponentImage.tag_and_push_to_dockerhub('foo', initial_tag: 'latest')
-      end
-    end
-  end
-
-  describe '.write_release_file' do
-    describe 'with triggered build' do
-      let(:release_file) do
-        [
-          "PACKAGECLOUD_REPO=download-package",
-          "RELEASE_VERSION=12.121.12-ce.1",
-          "DOWNLOAD_URL=https://gitlab.com/api/v4/projects/1/jobs/1/artifacts/pkg/ubuntu-focal/gitlab.deb",
-          "TRIGGER_PRIVATE_TOKEN=NOT-PRIVATE-TOKEN\n"
-        ]
-      end
-
-      before do
-        stub_env_var('PACKAGECLOUD_REPO', 'download-package')
-        stub_env_var('TRIGGER_PRIVATE_TOKEN', 'NOT-PRIVATE-TOKEN')
-        stub_env_var('CI_PROJECT_ID', '1')
-        stub_env_var('CI_PIPELINE_ID', '2')
-        allow(Build::Info).to receive(:release_version).and_return('12.121.12-ce.1')
-        allow(Build::Info).to receive(:fetch_artifact_url).with('1', '2').and_return('1')
-      end
-
-      describe 'for CE' do
-        before do
-          allow(Build::Info).to receive(:package).and_return('gitlab-ce')
-        end
-
-        it 'returns build version and iteration with env variable' do
-          release_file_content = release_file.insert(1, 'RELEASE_PACKAGE=gitlab-ce').join("\n")
-
-          expect(ComponentImage.write_release_file).to eq(release_file_content)
-        end
-      end
-
-      describe 'for EE' do
-        before do
-          allow(Build::Info).to receive(:package).and_return('gitlab-ee')
-        end
-
-        it 'returns build version and iteration with env variable' do
-          release_file_content = release_file.insert(1, 'RELEASE_PACKAGE=gitlab-ee').join("\n")
-
-          expect(ComponentImage.write_release_file).to eq(release_file_content)
-        end
-      end
-
-      describe 'with regular build' do
-        let(:s3_download_link) { 'https://downloads-packages.s3.amazonaws.com/ubuntu-focal/gitlab-ee_12.121.12-ce.1_amd64.deb' }
-
-        let(:release_file) do
-          [
-            "RELEASE_VERSION=12.121.12-ce.1",
-            "DOWNLOAD_URL=#{s3_download_link}\n",
-          ]
-        end
-
-        before do
-          stub_env_var('PACKAGECLOUD_REPO', '')
-          stub_env_var('TRIGGER_PRIVATE_TOKEN', '')
-          stub_env_var('CI_PROJECT_ID', '')
-          stub_env_var('CI_PIPELINE_ID', '')
-          allow(Build::Check).to receive(:on_tag?).and_return(true)
-          allow(Build::Info).to receive(:package).and_return('gitlab-ee')
-          allow(ComponentImage).to receive(:release_version).and_return('12.121.12-ce.1')
-        end
-
-        it 'returns build version and iteration with env variable' do
-          release_file_content = release_file.insert(0, 'RELEASE_PACKAGE=gitlab-ee').join("\n")
-
-          expect(ComponentImage.write_release_file).to eq(release_file_content)
-        end
-      end
-    end
-  end
-end
diff --git a/spec/gitlab/build/info_spec.rb b/spec/gitlab/build/info_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build/info_spec.rb
+++ /dev/null
@@ -1,277 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build/info'
-require 'gitlab/build/gitlab_image'
-
-RSpec.describe Build::Info do
-  before do
-    stub_default_package_version
-    stub_env_var('GITLAB_ALTERNATIVE_REPO', nil)
-    stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', nil)
-  end
-
-  describe '.package' do
-    describe 'shows EE' do
-      it 'when ee=true' do
-        stub_is_ee_env(true)
-        expect(described_class.package).to eq('gitlab-ee')
-      end
-
-      it 'when env var is not present, checks VERSION file' do
-        stub_is_ee_version(true)
-        expect(described_class.package).to eq('gitlab-ee')
-      end
-    end
-
-    describe 'shows CE' do
-      it 'by default' do
-        stub_is_ee(false)
-        expect(described_class.package).to eq('gitlab-ce')
-      end
-    end
-  end
-
-  describe '.release_version' do
-    before do
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      allow_any_instance_of(Omnibus::BuildVersion).to receive(:semver).and_return('12.121.12')
-      allow_any_instance_of(Gitlab::BuildIteration).to receive(:build_iteration).and_return('ce.1')
-    end
-
-    it 'returns build version and iteration' do
-      expect(described_class.release_version).to eq('12.121.12-ce.1')
-    end
-
-    it 'defaults to an initial build version when there are no matching tags' do
-      allow(Build::Check).to receive(:on_tag?).and_return(false)
-      allow(Build::Check).to receive(:is_nightly?).and_return(false)
-      allow(Build::Info).to receive(:latest_tag).and_return('')
-      allow(Build::Info).to receive(:commit_sha).and_return('ffffffff')
-      stub_env_var('CI_PIPELINE_ID', '5555')
-
-      expect(described_class.release_version).to eq('0.0.1+rfbranch.5555.ffffffff-ce.1')
-    end
-
-    describe 'with env variables' do
-      it 'returns build version and iteration with env variable' do
-        stub_env_var('USE_S3_CACHE', 'false')
-        stub_env_var('CACHE_AWS_ACCESS_KEY_ID', 'NOT-KEY')
-        stub_env_var('CACHE_AWS_SECRET_ACCESS_KEY', 'NOT-SECRET-KEY')
-        stub_env_var('CACHE_AWS_BUCKET', 'bucket')
-        stub_env_var('CACHE_AWS_S3_REGION', 'moon-west1')
-        stub_env_var('CACHE_AWS_S3_ENDPOINT', 'endpoint')
-        stub_env_var('CACHE_S3_ACCELERATE', 'sure')
-
-        stub_env_var('NIGHTLY', 'true')
-        stub_env_var('CI_PIPELINE_ID', '5555')
-
-        expect(described_class.release_version).to eq('12.121.12-ce.1')
-      end
-    end
-  end
-
-  describe '.docker_tag' do
-    before do
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      allow_any_instance_of(Omnibus::BuildVersion).to receive(:semver).and_return('12.121.12')
-      allow_any_instance_of(Gitlab::BuildIteration).to receive(:build_iteration).and_return('ce.1')
-    end
-
-    it 'returns package version when regular build' do
-      expect(described_class.docker_tag).to eq('12.121.12-ce.1')
-    end
-
-    it 'respects IMAGE_TAG if set' do
-      allow(ENV).to receive(:[]).with('IMAGE_TAG').and_return('foobar')
-      expect(described_class.docker_tag).to eq('foobar')
-    end
-  end
-
-  # Specs for latest_tag and for latest_stable_tag are really useful since we
-  # are stubbing out shell out to git.
-  # However, they are showing what we expect to see.
-  describe '.latest_tag' do
-    describe 'for CE' do
-      before do
-        stub_is_ee(false)
-        allow(described_class).to receive(:`).with("git describe --exact-match 2>/dev/null").and_return('12.121.12+rc7.ce.0')
-        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ce.*' --sort=-v:refname | head -1").and_return('12.121.12+rc7.ce.0')
-      end
-
-      it 'returns the version of correct edition' do
-        expect(described_class.latest_tag).to eq('12.121.12+rc7.ce.0')
-      end
-    end
-
-    describe 'for EE' do
-      before do
-        stub_is_ee(true)
-        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ee.*' --sort=-v:refname | head -1").and_return('12.121.12+rc7.ee.0')
-      end
-
-      it 'returns the version of correct edition' do
-        expect(described_class.latest_tag).to eq('12.121.12+rc7.ee.0')
-      end
-    end
-  end
-
-  describe '.latest_stable_tag' do
-    describe 'for CE' do
-      before do
-        stub_is_ee(nil)
-        allow(described_class).to receive(:`).with("git describe --exact-match 2>/dev/null").and_return('12.121.12+ce.0')
-        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ce.*' --sort=-v:refname | awk '!/rc/' | head -1").and_return('12.121.12+ce.0')
-      end
-
-      it 'returns the version of correct edition' do
-        expect(described_class.latest_stable_tag).to eq('12.121.12+ce.0')
-      end
-    end
-
-    describe 'for EE' do
-      before do
-        stub_is_ee(true)
-        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ee.*' --sort=-v:refname | awk '!/rc/' | head -1").and_return('12.121.12+ee.0')
-      end
-
-      it 'returns the version of correct edition' do
-        expect(described_class.latest_stable_tag).to eq('12.121.12+ee.0')
-      end
-    end
-  end
-
-  describe '.gitlab_version' do
-    describe 'GITLAB_VERSION variable specified' do
-      it 'returns passed value' do
-        allow(ENV).to receive(:[]).with("GITLAB_VERSION").and_return("9.0.0")
-        expect(described_class.gitlab_version).to eq('9.0.0')
-      end
-    end
-
-    describe 'GITLAB_VERSION variable not specified' do
-      it 'returns content of VERSION' do
-        allow(File).to receive(:read).with("VERSION").and_return("8.5.6")
-        expect(described_class.gitlab_version).to eq('8.5.6')
-      end
-    end
-  end
-
-  describe '.previous_version' do
-    it 'detects previous version correctly' do
-      allow(described_class).to receive(:`).with("git describe --exact-match 2>/dev/null").and_return('10.4.0+ee.0')
-      allow(Build::Info).to receive(:`).with(/git -c versionsort/).and_return("10.4.0+ee.0\n10.3.5+ee.0")
-
-      expect(described_class.previous_version).to eq("10.3.5-ee.0")
-    end
-  end
-
-  describe '.gitlab_rails repo' do
-    describe 'with alternative sources channel selected' do
-      before do
-        allow(::Gitlab::Version).to receive(:sources_channel).and_return('alternative')
-      end
-
-      it 'returns public mirror for GitLab CE' do
-        allow(Build::Info).to receive(:package).and_return("gitlab-ce")
-        expect(described_class.gitlab_rails_repo).to eq("https://gitlab.com/gitlab-org/gitlab-foss.git")
-      end
-      it 'returns public mirror for GitLab EE' do
-        allow(Build::Info).to receive(:package).and_return("gitlab-ee")
-        expect(described_class.gitlab_rails_repo).to eq("https://gitlab.com/gitlab-org/gitlab.git")
-      end
-    end
-
-    describe 'with default sources channel' do
-      before do
-        allow(::Gitlab::Version).to receive(:sources_channel).and_return('remote')
-      end
-
-      it 'returns dev repo for GitLab CE' do
-        allow(Build::Info).to receive(:package).and_return("gitlab-ce")
-        expect(described_class.gitlab_rails_repo).to eq("git@dev.gitlab.org:gitlab/gitlabhq.git")
-      end
-      it 'returns dev repo for GitLab EE' do
-        allow(Build::Info).to receive(:package).and_return("gitlab-ee")
-        expect(described_class.gitlab_rails_repo).to eq("git@dev.gitlab.org:gitlab/gitlab-ee.git")
-      end
-    end
-
-    describe 'with security sources channel selected' do
-      before do
-        allow(::Gitlab::Version).to receive(:sources_channel).and_return('security')
-        stub_env_var('CI_JOB_TOKEN', 'CJT')
-      end
-
-      it 'returns security mirror for GitLab CE with attached credential' do
-        allow(Build::Info).to receive(:package).and_return("gitlab-ce")
-        expect(described_class.gitlab_rails_repo).to eq("https://gitlab-ci-token:CJT@gitlab.com/gitlab-org/security/gitlab-foss.git")
-      end
-      it 'returns security mirror for GitLab EE with attached credential' do
-        allow(Build::Info).to receive(:package).and_return("gitlab-ee")
-        expect(described_class.gitlab_rails_repo).to eq("https://gitlab-ci-token:CJT@gitlab.com/gitlab-org/security/gitlab.git")
-      end
-    end
-  end
-
-  describe '.major_minor_version_and_rails_ref' do
-    it 'return minor and major version components plus the rails ref' do
-      allow(ENV).to receive(:[]).with('CI_COMMIT_TAG').and_return('12.0.12345+5159f2949cb.59c9fa631')
-
-      expect(described_class.major_minor_version_and_rails_ref).to eq('12.0-5159f2949cb')
-    end
-
-    it 'raises an error if the commit tag is invalid' do
-      allow(ENV).to receive(:[]).with('CI_COMMIT_TAG').and_return('xyz')
-
-      expect { described_class.major_minor_version_and_rails_ref }.to raise_error(RuntimeError, /Invalid auto-deploy version 'xyz'/)
-    end
-  end
-
-  describe '.deploy_env' do
-    before do
-      allow(ENV).to receive(:[]).with('AUTO_DEPLOY_ENVIRONMENT').and_return('ad')
-      allow(ENV).to receive(:[]).with('PATCH_DEPLOY_ENVIRONMENT').and_return('patch')
-      allow(ENV).to receive(:[]).with('RELEASE_DEPLOY_ENVIRONMENT').and_return('r')
-    end
-
-    context 'on auto-deploy tag' do
-      before do
-        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(true)
-      end
-      it 'returns the auto-deploy environment' do
-        expect(described_class.deploy_env).to eq('ad')
-      end
-    end
-
-    context 'on RC tag' do
-      before do
-        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(false)
-        allow(Build::Check).to receive(:is_rc_tag?).and_return(true)
-      end
-      it 'returns the auto-deploy environment' do
-        expect(described_class.deploy_env).to eq('patch')
-      end
-    end
-
-    context 'on latest tag' do
-      before do
-        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(false)
-        allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
-        allow(Build::Check).to receive(:is_latest_stable_tag?).and_return(true)
-      end
-      it 'returns the auto-deploy environment' do
-        expect(described_class.deploy_env).to eq('r')
-      end
-    end
-
-    context 'when unable to determine the desired env' do
-      before do
-        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(false)
-        allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
-        allow(Build::Check).to receive(:is_latest_stable_tag?).and_return(false)
-      end
-      it 'it returns nil' do
-        expect(described_class.deploy_env).to eq(nil)
-      end
-    end
-  end
-end
diff --git a/spec/gitlab/build/qa_image_spec.rb b/spec/gitlab/build/qa_image_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build/qa_image_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build/qa_image'
-
-RSpec.describe Build::QAImage do
-  before do
-    allow(Build::GitlabImage).to receive(:dockerhub_image_name).and_return('gitlab/gitlab-ce')
-    allow(Build::GitlabImage).to receive(:gitlab_registry_image_name).and_return('gitlab-ce')
-  end
-
-  describe '.dockerhub_image_name' do
-    it 'returns a correct image name' do
-      expect(described_class.dockerhub_image_name).to eq('gitlab/gitlab-ce-qa')
-    end
-  end
-
-  describe '.gitlab_registry_image_name' do
-    it 'returns a correct image name' do
-      expect(described_class.gitlab_registry_image_name).to eq('gitlab-ce-qa')
-    end
-  end
-end
diff --git a/spec/gitlab/build/qa_spec.rb b/spec/gitlab/build/qa_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build/qa_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build/qa'
-
-RSpec.describe Build::QA do
-  before do
-    allow(ENV).to receive(:[]).and_call_original
-    stub_env_var('GITLAB_ALTERNATIVE_REPO', nil)
-    stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', nil)
-  end
-
-  describe '.repo_path' do
-    it 'returns correct location' do
-      expect(described_class.repo_path).to eq("/tmp/gitlab")
-    end
-  end
-
-  describe '.get_gitlab_repo' do
-    it 'returns correct location' do
-      allow(Build::QA).to receive(:clone_gitlab_rails).and_return(true)
-      allow(Build::QA).to receive(:checkout_gitlab_rails).and_return(true)
-
-      expect(described_class.get_gitlab_repo).to eq("/tmp/gitlab")
-    end
-  end
-
-  describe '.clone_gitlab_rails' do
-    it 'calls the git command' do
-      allow(Build::Info).to receive(:package).and_return("gitlab-ee")
-      allow(::Gitlab::Version).to receive(:sources_channel).and_return('remote')
-
-      expect(described_class).to receive(:system).with(*%w[rm -rf /tmp/gitlab])
-      expect(described_class).to receive(:system).with(*%w[git clone git@dev.gitlab.org:gitlab/gitlab-ee.git /tmp/gitlab])
-
-      Build::QA.clone_gitlab_rails
-    end
-  end
-
-  describe '.checkout_gitlab_rails' do
-    it 'calls the git command' do
-      allow(Build::Info).to receive(:package).and_return("gitlab-ee")
-      allow(Build::Info).to receive(:gitlab_version).and_return("9.0.0")
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      stub_is_auto_deploy(false)
-
-      expect(described_class).to receive(:system).with(*%w[git --git-dir=/tmp/gitlab/.git --work-tree=/tmp/gitlab checkout --quiet v9.0.0])
-
-      Build::QA.checkout_gitlab_rails
-    end
-  end
-
-  describe '.get_gitlab_rails_sha' do
-    it 'returns the correct stable tag' do
-      allow(Build::Info).to receive(:gitlab_version).and_return("9.0.0")
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      stub_is_auto_deploy(false)
-
-      expect(Build::QA.get_gitlab_rails_sha).to eq("v9.0.0")
-    end
-
-    it 'returns the correct auto-deploy commit sha' do
-      allow(Build::Info).to receive(:gitlab_version).and_return("bebc7c1e290074863e0d2621b3a4c4c7bdb072ae")
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      stub_is_auto_deploy(true)
-
-      expect(Build::QA.get_gitlab_rails_sha).to eq("bebc7c1e290074863e0d2621b3a4c4c7bdb072ae")
-    end
-  end
-end
diff --git a/spec/gitlab/build_iteration_spec.rb b/spec/gitlab/build_iteration_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build_iteration_spec.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build_iteration'
-
-RSpec.describe Gitlab::BuildIteration do
-  describe :build_iteration do
-    subject { Gitlab::BuildIteration.new(git_describe) }
-
-    context 'with an invalid git_describe' do
-      let(:git_describe) { '1.2.3-foo.3' }
-
-      it 'returns 0' do
-        allow(Build::Check).to receive(:on_tag?).and_return(true)
-        expect(subject.build_iteration).to eq('0')
-      end
-    end
-
-    context 'with a git_describe from master' do
-      let(:git_describe) { '1.2.3+rc1.ce.2-6-ge5626d5' }
-
-      it 'returns rc1.ce.2' do
-        allow(Build::Check).to receive(:on_tag?).and_return(true)
-        expect(subject.build_iteration).to eq('rc1.ce.2')
-      end
-    end
-
-    context 'with a proper git_describe' do
-      let(:git_describe) { '1.2.3+foo.4' }
-
-      it 'returns foo.4' do
-        allow(Build::Check).to receive(:on_tag?).and_return(true)
-        expect(subject.build_iteration).to eq('foo.4')
-      end
-    end
-
-    context 'with a git_describe with new line char' do
-      let(:git_describe) { "1.2.3+foo.4\n" }
-
-      it 'returns foo.4' do
-        allow(Build::Check).to receive(:on_tag?).and_return(true)
-        expect(subject.build_iteration).to eq('foo.4')
-      end
-    end
-
-    context 'with multiple plus signs' do
-      let(:git_describe) { '1.2.3+foo.4+bar' }
-
-      it 'returns everything after the first plus' do
-        allow(Build::Check).to receive(:on_tag?).and_return(true)
-        expect(subject.build_iteration).to eq('foo.4+bar')
-      end
-    end
-
-    context 'with an invalid git tag' do
-      let(:git_describe) { '1.2.3+' }
-
-      it 'returns an empty string' do
-        allow(Build::Check).to receive(:on_tag?).and_return(true)
-        expect(subject.build_iteration).to eq('0')
-      end
-    end
-
-    context 'not on a git tag' do
-      subject { Gitlab::BuildIteration.new }
-
-      it 'returns 0' do
-        allow(Build::Check).to receive(:system).with('git describe --exact-match > /dev/null 2>&1').and_return(false)
-        expect(subject.build_iteration).to eq('0')
-      end
-    end
-  end
-end
diff --git a/spec/gitlab/build_spec.rb b/spec/gitlab/build_spec.rb
deleted file mode 100644
--- a/spec/gitlab/build_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build'
-
-RSpec.describe Build do
-  describe 'cmd' do
-    describe 'by default' do
-      it 'runs build command with log level info' do
-        expect(described_class.cmd('gitlab')).to eq %w[bundle exec omnibus build gitlab --log-level info]
-      end
-    end
-
-    describe 'with different log level' do
-      it 'runs build command with custom log level' do
-        stub_env_var('BUILD_LOG_LEVEL', 'debug')
-        expect(described_class.cmd('gitlab')).to eq %w[bundle exec omnibus build gitlab --log-level debug]
-      end
-    end
-  end
-end
diff --git a/spec/gitlab/deployer_helper_spec.rb b/spec/gitlab/deployer_helper_spec.rb
deleted file mode 100644
--- a/spec/gitlab/deployer_helper_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require 'spec_helper'
-require 'gitlab/build'
-require 'gitlab/deployer_helper'
-
-RSpec.describe DeployerHelper do
-  subject(:service) { described_class.new('some-token', 'some-env', 'some-branch') }
-  describe '#trigger_deploy' do
-    it 'triggers an auto deploy' do
-      response = instance_double('response', body: JSON.dump(web_url: 'http://example.com'), status: 201)
-      allow(Build::Info).to receive(:docker_tag).and_return('some-version')
-      expect(HTTP)
-        .to receive(:post)
-        .with(
-          "https://ops.gitlab.net/api/v4/projects/135/trigger/pipeline",
-          form: {
-            "token" => "some-token",
-            "ref" => "some-branch",
-            "variables[DEPLOY_ENVIRONMENT]" => "some-env",
-            "variables[DEPLOY_VERSION]" => "some-version",
-            "variables[DEPLOY_USER]" => "deployer"
-          }
-        ).and_return(response)
-      expect(service.trigger_deploy).to eq('http://example.com')
-    end
-
-    it 'triggers an auto deploy with retries' do
-      # Set this to zero so there we don't have delays during tests
-      stub_const('DeployerHelper::TRIGGER_RETRY_INTERVAL', 0)
-      response = instance_double('response', body: JSON.dump(web_url: 'http://example.com'), status: 401)
-      allow(Build::Info).to receive(:docker_tag).and_return('some-version')
-      expect(HTTP)
-        .to receive(:post)
-        .with(
-          "https://ops.gitlab.net/api/v4/projects/135/trigger/pipeline",
-          form: {
-            "token" => "some-token",
-            "ref" => "some-branch",
-            "variables[DEPLOY_ENVIRONMENT]" => "some-env",
-            "variables[DEPLOY_VERSION]" => "some-version",
-            "variables[DEPLOY_USER]" => "deployer"
-          }
-        ).and_return(response).exactly(3).times
-      expect { service.trigger_deploy }.to raise_error(RuntimeError, "Unable to trigger pipeline after 3 retries")
-    end
-  end
-end
diff --git a/spec/gitlab/docker_operations_spec.rb b/spec/gitlab/docker_operations_spec.rb
deleted file mode 100644
--- a/spec/gitlab/docker_operations_spec.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-require 'spec_helper'
-require 'gitlab/docker_operations'
-
-RSpec.describe DockerOperations do
-  describe '.set_timeout' do
-    context 'when ENV["DOCKER_TIMEOUT"] is not set' do
-      it 'uses a default timeout value' do
-        expect(Docker).to receive(:options=).with(read_timeout: 1200, write_timeout: 1200)
-
-        described_class.set_timeout
-      end
-    end
-
-    context 'when ENV["DOCKER_TIMEOUT"] is not set' do
-      before do
-        expect(ENV).to receive(:[]).with('DOCKER_TIMEOUT').and_return("42")
-      end
-
-      it 'uses the given timeout value' do
-        expect(Docker).to receive(:options=).with(read_timeout: "42", write_timeout: "42")
-
-        described_class.set_timeout
-      end
-    end
-  end
-
-  describe '.build' do
-    let(:location) { '/tmp/foo' }
-    let(:image) { 'gitlab-ce' }
-    let(:tag) { 'latest' }
-
-    it 'uses a default timeout value' do
-      expect(described_class).to receive(:set_timeout)
-      expect(Docker::Image).to receive(:build_from_dir).with(location, { t: "#{image}:#{tag}", pull: true }).and_yield(JSON.dump(stream: 'Hello!'))
-      expect(described_class).to receive(:puts).with('Hello!')
-
-      described_class.build(location.to_sym, image, tag)
-    end
-  end
-
-  describe '.authenticate' do
-    context 'with no arguments' do
-      it 'calls Docker.authenticate!' do
-        expect(ENV).to receive(:[]).with('DOCKERHUB_USERNAME').and_return('user')
-        expect(ENV).to receive(:[]).with('DOCKERHUB_PASSWORD').and_return('pass')
-        expect(Docker).to receive(:authenticate!).with(username: 'user', password: 'pass', serveraddress: '')
-
-        described_class.authenticate
-      end
-    end
-
-    context 'with arguments' do
-      it 'uses a default timeout value' do
-        expect(Docker).to receive(:authenticate!).with(username: 'john', password: 'secret', serveraddress: 'registry.com')
-
-        described_class.authenticate('john', 'secret', 'registry.com')
-      end
-    end
-  end
-
-  describe '.get' do
-    it 'calls Docker::Image.get' do
-      expect(described_class).to receive(:set_timeout)
-      expect(Docker::Image).to receive(:get).with('namespace:tag')
-
-      described_class.get('namespace', 'tag')
-    end
-  end
-
-  describe '.push' do
-    it 'calls Docker::Image.push' do
-      image = double
-      creds = double
-
-      expect(described_class).to receive(:set_timeout)
-      expect(described_class).to receive(:get).with('namespace', 'tag').and_return(image)
-      expect(Docker).to receive(:creds).and_return(creds)
-      expect(image).to receive(:push).with(creds, repo_tag: 'namespace:tag').and_yield('Hello!')
-      expect(described_class).to receive(:puts).and_return('Hello!')
-
-      described_class.push('namespace', 'tag')
-    end
-  end
-
-  describe '.tag' do
-    it 'calls Docker::Image.tag' do
-      image = double
-
-      expect(described_class).to receive(:set_timeout)
-      expect(described_class).to receive(:get).with('namespace1', 'tag1').and_return(image)
-      expect(image).to receive(:tag).with(repo: 'namespace2', tag: 'tag2', force: true)
-
-      described_class.tag('namespace1', 'namespace2', 'tag1', 'tag2')
-    end
-  end
-
-  describe '.tag_and_push' do
-    it 'delegates to tag_and_push' do
-      expect(described_class).to receive(:tag).with('namespace1', 'namespace2', 'tag1', 'tag2')
-      expect(described_class).to receive(:push).with('namespace2', 'tag2')
-
-      described_class.tag_and_push('namespace1', 'namespace2', 'tag1', 'tag2')
-    end
-  end
-end
diff --git a/spec/gitlab/linker_helper_spec.rb b/spec/gitlab/linker_helper_spec.rb
deleted file mode 100644
--- a/spec/gitlab/linker_helper_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-require 'gitlab/linker_helper'
-
-RSpec.describe LinkerHelper do
-  subject(:service) { described_class }
-  before do
-    allow(IO).to receive(:popen).and_call_original
-    allow(IO).to receive(:popen).with(%w[ldconfig -p]).and_return("1 library found\nlibssl.so (libc6,x86-64) => /lib64/libssl.so")
-  end
-
-  describe "#ldconfig" do
-    it "should should update linker cache" do
-      expect(service).to receive(:system).with("ldconfig")
-
-      service.ldconfig
-    end
-
-    it "should return discovered libraries" do
-      expect(service.ldconfig).to have_key("libssl.so")
-    end
-  end
-end
diff --git a/spec/gitlab/package_repository_spec.rb b/spec/gitlab/package_repository_spec.rb
deleted file mode 100644
--- a/spec/gitlab/package_repository_spec.rb
+++ /dev/null
@@ -1,265 +0,0 @@
-require 'spec_helper'
-require 'gitlab/package_repository'
-require 'gitlab/util'
-
-RSpec.describe PackageRepository do
-  let(:repo) { PackageRepository.new }
-
-  before do
-    allow(ENV).to receive(:[]).and_call_original
-  end
-
-  describe :repository_for_rc do
-    context 'on master' do
-      # Example:
-      # on non stable branch: 8.1.0+rc1.ce.0-1685-gd2a2c51
-      # on tag: 8.12.0+rc1.ee.0
-      before do
-        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.12.0+rc1.ee.0\n")
-      end
-
-      it { expect(repo.repository_for_rc).to eq 'unstable' }
-    end
-
-    context 'on stable branch' do
-      # Example:
-      # on non stable branch: 8.12.8+ce.0-1-gdac92d4
-      # on tag: 8.12.8+ce.0
-      before do
-        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.12.8+ce.0\n")
-      end
-
-      it { expect(repo.repository_for_rc).to eq nil }
-    end
-  end
-
-  describe :target do
-    shared_examples 'with an override repository' do
-      context 'with repository override' do
-        before do
-          set_all_env_variables
-        end
-
-        it 'uses the override repository' do
-          expect(repo.target).to eq('super-stable-1234')
-        end
-      end
-    end
-
-    shared_examples 'with raspberry pi repo' do
-      context 'with raspberry pi repo' do
-        before do
-          set_raspi_env_variable
-        end
-
-        it 'uses the raspberry pi repository' do
-          expect(repo.target).to eq('raspi')
-        end
-      end
-    end
-
-    context 'on non-stable branch' do
-      before do
-        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.1.0+rc1.ce.0-1685-gd2a2c51\n")
-      end
-
-      it 'prints unstable' do
-        expect(repo.target).to eq('unstable')
-      end
-
-      it_behaves_like 'with an override repository'
-      it_behaves_like 'with raspberry pi repo'
-    end
-
-    context 'on a stable branch' do
-      before do
-        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.12.8+ce.0-1-gdac92d4\n")
-      end
-
-      context 'when EE' do
-        before do
-          allow(File).to receive(:read).with('VERSION').and_return("1.2.3-ee\n")
-        end
-
-        it 'prints gitlab-ee' do
-          expect(repo.target).to eq('gitlab-ee')
-        end
-
-        it_behaves_like 'with an override repository'
-        it_behaves_like 'with raspberry pi repo'
-      end
-
-      context 'when CE' do
-        before do
-          stub_is_ee(false)
-          allow(File).to receive(:read).with('VERSION').and_return("1.2.3\n")
-        end
-
-        it 'prints gitlab-ce' do
-          expect(repo.target).to eq('gitlab-ce')
-        end
-
-        it_behaves_like 'with an override repository'
-        it_behaves_like 'with raspberry pi repo'
-      end
-    end
-  end
-
-  describe :validate do
-    context 'with artifacts available' do
-      before do
-        allow(Build::Info).to receive(:package_list).and_return(['pkg/el-6/gitlab-ce.rpm'])
-      end
-
-      it 'in dry run mode prints the checksum commands' do
-        expect { repo.validate(true) }.to output("sha256sum -c pkg/el-6/gitlab-ce.rpm.sha256\n").to_stdout
-      end
-
-      it 'raises an exception when there is a mismatch' do
-        expect(repo).to receive(:verify_checksum).with('pkg/el-6/gitlab-ce.rpm.sha256', true).and_return(false)
-
-        expect { repo.validate(true) }.to raise_error(%r{Aborting, package .* has an invalid checksum!})
-      end
-    end
-
-    context 'with artifacts unavailable' do
-      before do
-        allow(Build::Info).to receive(:package_list).and_return([])
-      end
-
-      it 'prints nothing' do
-        expect { repo.validate(true) }.to output('').to_stdout
-      end
-    end
-  end
-
-  describe :upload do
-    describe 'with staging repository' do
-      context 'when upload user is not specified' do
-        it 'prints a message and aborts' do
-          expect { repo.upload('my-staging-repository', true) }.to output(%r{User for uploading to package server not specified!\n}).to_stdout
-        end
-      end
-
-      context 'with specified upload user' do
-        before do
-          stub_env_var('PACKAGECLOUD_USER', "gitlab")
-        end
-
-        context 'with artifacts available' do
-          before do
-            allow(Build::Info).to receive(:package_list).and_return(['pkg/el-6/gitlab-ce.rpm'])
-          end
-
-          it 'in dry run mode prints the upload commands' do
-            expect { repo.upload('my-staging-repository', true) }.to output(%r{Uploading...\n}).to_stdout
-            expect { repo.upload('my-staging-repository', true) }.to output(%r{bin/package_cloud push gitlab/my-staging-repository/scientific/6 pkg/el-6/gitlab-ce.rpm --url=https://packages.gitlab.com\n}).to_stdout
-            expect { repo.upload('my-staging-repository', true) }.to output(%r{bin/package_cloud push gitlab/my-staging-repository/ol/6 pkg/el-6/gitlab-ce.rpm --url=https://packages.gitlab.com\n}).to_stdout
-            expect { repo.upload('my-staging-repository', true) }.to output(%r{bin/package_cloud push gitlab/my-staging-repository/el/6 pkg/el-6/gitlab-ce.rpm --url=https://packages.gitlab.com\n}).to_stdout
-          end
-        end
-
-        context 'with artifacts unavailable' do
-          before do
-            allow(Dir).to receive(:glob).with("pkg/**/*.{deb,rpm}").and_return([])
-          end
-
-          it 'prints a message and aborts' do
-            expect { repo.upload('my-staging-repository', true) }.to raise_exception(%r{No packages found for upload. Are artifacts available?})
-          end
-        end
-      end
-    end
-
-    describe "with production repository" do
-      context 'with artifacts available' do
-        before do
-          stub_env_var('PACKAGECLOUD_USER', "gitlab")
-          allow(Dir).to receive(:glob).with("pkg/**/*.{deb,rpm}").and_return(['pkg/ubuntu-focal/gitlab.deb'])
-        end
-
-        context 'for stable release' do
-          before do
-            stub_env_var('PACKAGECLOUD_REPO', nil)
-            stub_env_var('RASPBERRY_REPO', nil)
-            allow_any_instance_of(PackageRepository).to receive(:repository_for_rc).and_return(nil)
-          end
-
-          context 'of EE' do
-            before do
-              stub_is_ee(true)
-            end
-
-            it 'in dry run mode prints the upload commands' do
-              expect { repo.upload(nil, true) }.to output(%r{Uploading...\n}).to_stdout
-              expect { repo.upload(nil, true) }.to output(%r{bin/package_cloud push gitlab/gitlab-ee/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
-            end
-          end
-
-          context 'of CE' do
-            before do
-              stub_is_ee(nil)
-            end
-
-            it 'in dry run mode prints the upload commands' do
-              expect { repo.upload(nil, true) }.to output(%r{Uploading...\n}).to_stdout
-              expect { repo.upload(nil, true) }.to output(%r{bin/package_cloud push gitlab/gitlab-ce/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
-            end
-          end
-        end
-
-        context 'for nightly release' do
-          before do
-            set_nightly_env_variable
-            allow_any_instance_of(PackageRepository).to receive(:repository_for_rc).and_return(nil)
-          end
-
-          it 'in dry run mode prints the upload commands' do
-            expect { repo.upload(Gitlab::Util.get_env('STAGING_REPO'), true) }.to output(%r{Uploading...\n}).to_stdout
-            expect { repo.upload(Gitlab::Util.get_env('STAGING_REPO'), true) }.to output(%r{bin/package_cloud push gitlab/nightly-builds/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
-          end
-        end
-
-        context 'for raspbian release' do
-          before do
-            set_raspi_env_variable
-            allow_any_instance_of(PackageRepository).to receive(:repository_for_rc).and_return(nil)
-          end
-
-          it 'in dry run mode prints the upload commands' do
-            expect { repo.upload(nil, true) }.to output(%r{Uploading...\n}).to_stdout
-            expect { repo.upload(nil, true) }.to output(%r{bin/package_cloud push gitlab/raspi/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
-          end
-        end
-      end
-    end
-
-    describe 'when artifacts contain unexpected files' do
-      before do
-        stub_env_var('PACKAGECLOUD_USER', "gitlab")
-        set_all_env_variables
-        allow(Dir).to receive(:glob).with("pkg/**/*.{deb,rpm}").and_return(['pkg/ubuntu-focal/gitlab.deb', 'pkg/ubuntu-focal/testing/gitlab.deb'])
-      end
-
-      it 'raises an exception' do
-        expect { repo.upload(nil, true) }.to raise_exception(%r{Found unexpected contents in the directory:})
-      end
-    end
-  end
-
-  def set_all_env_variables
-    stub_env_var("PACKAGECLOUD_REPO", "super-stable-1234")
-    stub_env_var("RASPBERRY_REPO", "raspi")
-  end
-
-  def set_nightly_env_variable
-    stub_env_var("PACKAGECLOUD_REPO", "")
-    stub_env_var("RASPBERRY_REPO", "")
-    stub_env_var("STAGING_REPO", "nightly-builds")
-  end
-
-  def set_raspi_env_variable
-    stub_env_var("PACKAGECLOUD_REPO", "")
-    stub_env_var("RASPBERRY_REPO", "raspi")
-  end
-end
diff --git a/spec/gitlab/tasks/aws_spec.rb b/spec/gitlab/tasks/aws_spec.rb
deleted file mode 100644
--- a/spec/gitlab/tasks/aws_spec.rb
+++ /dev/null
@@ -1,154 +0,0 @@
-require 'spec_helper'
-
-Struct.new("Image", :image_id, :name, :tags)
-Struct.new("Region", :region_name)
-Struct.new("Response", :images)
-Struct.new("Tag", :key, :value)
-Struct.new("DescribeRegionResult", :regions)
-
-class AwsDummyClass
-  # Dummy class which mimicks AWS::EC2::Client class from aws-sdk and stubs
-  # necessary methods
-
-  def describe_images(parameters)
-    images = if parameters['filters'.to_sym][1][:values] == ["GitLab Community Edition"]
-               [
-                 Struct::Image.new("ami-422", "GitLab Community Edition 8.13.2", [Struct::Tag.new("Version", "8.13.2")])
-               ]
-             else
-               [
-                 Struct::Image.new("ami-322", "GitLab Enterprise Edition 10.5.4", [Struct::Tag.new("Version", "10.5.4")])
-               ]
-             end
-    @response = Struct::Response.new(images)
-  end
-
-  def describe_regions
-    Struct::DescribeRegionResult.new([Struct::Region.new('us-east-1')])
-  end
-
-  def deregister_image(parameters)
-    true
-  end
-end
-
-RSpec.describe 'aws:ami:create', type: :rake do
-  before :all do
-    Rake.application.rake_require 'gitlab/tasks/aws'
-  end
-
-  before do
-    Rake::Task['aws:ami:create'].reenable
-    allow_any_instance_of(Kernel).to receive(:system).and_return(true)
-  end
-
-  describe 'on a regular tag' do
-    before do
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      allow(Build::Check).to receive(:is_auto_deploy?).and_return(false)
-      allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
-      allow(Build::Info).to receive(:deb_package_download_url).and_return('http://example.com')
-    end
-
-    it 'should identify ce category correctly, if specified' do
-      allow(Build::Info).to receive(:edition).and_return('ce')
-      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
-
-      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ce", "http://example.com", ""])
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-
-    it 'should identify ce category correctly if nothing is specified' do
-      allow(Build::Info).to receive(:edition).and_return(nil)
-      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
-
-      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ce", "http://example.com", ""])
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-
-    it 'should identify ee category correctly' do
-      allow(Build::Info).to receive(:edition).and_return('ee')
-      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
-
-      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee", "http://example.com", ""])
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-
-    it 'should identify ce arm64 correctly' do
-      allow(Gitlab::Util).to receive(:get_env).and_call_original
-      allow(Gitlab::Util).to receive(:get_env).with('AWS_ARCHITECTURE').and_return('arm64')
-      allow(Build::Info).to receive(:edition).and_return(nil)
-      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
-
-      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ce-arm64", "http://example.com", ""])
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-
-    it 'should identify ee arm64 correctly' do
-      allow(Gitlab::Util).to receive(:get_env).and_call_original
-      allow(Gitlab::Util).to receive(:get_env).with('AWS_ARCHITECTURE').and_return('arm64')
-      allow(Build::Info).to receive(:edition).and_return('ee')
-      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
-
-      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee-arm64", "http://example.com", ""])
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-
-    it 'should identify ee ultimate category correctly' do
-      allow(Build::Info).to receive(:edition).and_return('ee')
-      allow(Gitlab::Util).to receive(:get_env).and_call_original
-      allow(Gitlab::Util).to receive(:get_env).with("AWS_RELEASE_TYPE").and_return('ultimate')
-      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
-
-      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee-ultimate", "http://example.com", "AWS_ULTIMATE_LICENSE_FILE"])
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-
-    it 'should identify ee premium category correctly' do
-      allow(Build::Info).to receive(:edition).and_return('ee')
-      allow(Gitlab::Util).to receive(:get_env).and_call_original
-      allow(Gitlab::Util).to receive(:get_env).with("AWS_RELEASE_TYPE").and_return('premium')
-      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
-
-      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee-premium", "http://example.com", "AWS_PREMIUM_LICENSE_FILE"])
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-  end
-
-  describe 'on an rc tag' do
-    before do
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      allow(Build::Check).to receive(:is_auto_deploy?).and_return(false)
-      allow(Build::Check).to receive(:is_rc_tag?).and_return(true)
-      allow(Build::Info).to receive(:deb_package_download_url).and_return('http://example.com')
-    end
-
-    it 'does not do anything' do
-      expect(AWSHelper).not_to receive(:new)
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-  end
-
-  describe 'on an auto-deploy tag' do
-    before do
-      allow(Build::Check).to receive(:on_tag?).and_return(true)
-      allow(Build::Check).to receive(:is_auto_deploy?).and_return(true)
-      allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
-      allow(Build::Info).to receive(:deb_package_download_url).and_return('http://example.com')
-    end
-
-    it 'does not do anything' do
-      expect(AWSHelper).not_to receive(:new)
-
-      Rake::Task['aws:ami:create'].invoke
-    end
-  end
-end
diff --git a/spec/gitlab/tasks/docker_tasks_spec.rb b/spec/gitlab/tasks/docker_tasks_spec.rb
deleted file mode 100644
--- a/spec/gitlab/tasks/docker_tasks_spec.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-require 'spec_helper'
-require_relative '../../../lib/gitlab/docker_operations.rb'
-
-RSpec.describe 'docker', type: :rake do
-  before :all do
-    Rake.application.rake_require 'gitlab/tasks/docker_tasks'
-  end
-
-  describe 'docker:build:image' do
-    before do
-      Rake::Task['docker:build:image'].reenable
-      allow(ENV).to receive(:[]).and_call_original
-    end
-
-    it 'calls build command with correct parameters' do
-      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('dev.gitlab.org:5005/gitlab/omnibus-gitlab')
-      allow(Build::Info).to receive(:package).and_return('gitlab-ce')
-      allow(Build::GitlabImage).to receive(:write_release_file).and_return(true)
-      allow(File).to receive(:expand_path).and_return('/tmp/omnibus-gitlab/lib/gitlab/tasks/docker_tasks.rake')
-      allow(DockerOperations).to receive(:build).and_call_original
-
-      expect(DockerOperations).to receive(:build).with("/tmp/omnibus-gitlab/docker", "dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce", "latest")
-      expect(Docker::Image).to receive(:build_from_dir).with("/tmp/omnibus-gitlab/docker", { t: "dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce:latest", pull: true })
-      Rake::Task['docker:build:image'].invoke
-    end
-  end
-
-  describe 'docker:pull:staging' do
-    before do
-      Rake::Task['docker:pull:staging'].reenable
-      allow(ENV).to receive(:[]).and_call_original
-    end
-
-    it 'pulls in correct image' do
-      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('dev.gitlab.org:5005/gitlab/omnibus-gitlab')
-      allow(Build::Info).to receive(:package).and_return('gitlab-ce')
-      allow(Build::Info).to receive(:docker_tag).and_return('9.0.0')
-      allow(DockerOperations).to receive(:authenticate).and_return(true)
-
-      expect(Docker::Image).to receive(:create).with('fromImage' => 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce:9.0.0')
-      Rake::Task['docker:pull:staging'].invoke
-    end
-  end
-
-  describe 'docker:push' do
-    let(:dummy_image) { Docker::Image.new(Docker::Connection.new("test", {}), "id" => "test") }
-    let(:dummy_creds) { { username: "test", password: "test" } }
-
-    before do
-      Rake::Task['docker:push:staging'].reenable
-      Rake::Task['docker:push:stable'].reenable
-      Rake::Task['docker:push:nightly'].reenable
-      Rake::Task['docker:push:rc'].reenable
-      Rake::Task['docker:push:latest'].reenable
-
-      allow(ENV).to receive(:[]).and_call_original
-      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('dev.gitlab.org:5005/gitlab/omnibus-gitlab')
-      allow(Build::Info).to receive(:package).and_return('gitlab-ce')
-      allow(Build::Info).to receive(:docker_tag).and_return('9.0.0')
-      allow(DockerOperations).to receive(:authenticate).and_return(true)
-      allow(Docker::Image).to receive(:get).and_return(dummy_image)
-      allow(Docker).to receive(:creds).and_return(dummy_creds)
-      allow(dummy_image).to receive(:tag).and_return(true)
-    end
-
-    it 'pushes to staging correctly' do
-      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce:9.0.0')
-      Rake::Task['docker:push:staging'].invoke
-    end
-
-    it 'pushes nightly images correctly' do
-      allow(Build::Check).to receive(:is_nightly?).and_return(true)
-
-      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'gitlab/gitlab-ce:nightly')
-      Rake::Task['docker:push:nightly'].invoke
-    end
-
-    it 'pushes latest images correctly' do
-      allow(Build::Check).to receive(:is_latest_stable_tag?).and_return(true)
-
-      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'gitlab/gitlab-ce:latest')
-      Rake::Task['docker:push:latest'].invoke
-    end
-
-    it 'pushes rc images correctly' do
-      allow(Build::Check).to receive(:is_latest_tag?).and_return(true)
-
-      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'gitlab/gitlab-ce:rc')
-      Rake::Task['docker:push:rc'].invoke
-    end
-
-    it 'pushes triggered images correctly' do
-      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('registry.gitlab.com/gitlab-org/omnibus-gitlab')
-      allow(ENV).to receive(:[]).with("IMAGE_TAG").and_return("omnibus-12345")
-      allow(Build::Info).to receive(:docker_tag).and_call_original
-
-      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'registry.gitlab.com/gitlab-org/omnibus-gitlab/gitlab-ce:omnibus-12345')
-      Rake::Task['docker:push:triggered'].invoke
-    end
-  end
-end
-
-RSpec.describe 'docker_operations' do
-  describe 'without docker operations timeout variable' do
-    it 'sets default value as timeout' do
-      DockerOperations.set_timeout
-      expect(Docker.options[:read_timeout]).to eq(1200)
-    end
-  end
-
-  describe 'with docker operations timeout variable specified' do
-    it 'sets provided value as timeout' do
-      allow(ENV).to receive(:[]).and_call_original
-      allow(ENV).to receive(:[]).with('DOCKER_TIMEOUT').and_return("500")
-      DockerOperations.set_timeout
-      expect(Docker.options[:read_timeout]).to eq("500")
-    end
-  end
-end
diff --git a/spec/gitlab/tasks/license_spec.rb b/spec/gitlab/tasks/license_spec.rb
deleted file mode 100644
--- a/spec/gitlab/tasks/license_spec.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-require 'spec_helper'
-
-RSpec.describe 'license:check', type: :rake do
-  let(:f) { double("Mocked file object") }
-
-  before :all do
-    Rake.application.rake_require 'gitlab/tasks/license'
-  end
-
-  before do
-    Rake::Task['license:check'].reenable
-    allow(File).to receive(:exist?).and_return(true)
-    allow(File).to receive(:open).and_call_original
-    allow(File).to receive(:open).with(/pkg.*license-status.json/, "w").and_return(f)
-    allow(f).to receive(:write).and_return(true)
-    allow(f).to receive(:close).and_return(true)
-    allow(Build::Info).to receive(:release_version).and_return("11.5.1+ce.0")
-  end
-
-  it 'detects good licenses correctly' do
-    license_info = '[
-      {
-        "name": "chef-zero",
-        "version": "4.8.0",
-        "license": "Apache-2.0",
-        "dependencies": [
-          {
-            "name": "sample",
-            "version": "1.0.0",
-            "license": "MIT"
-          }
-        ]
-      }
-     ]'
-    allow(File).to receive(:read).and_return(license_info)
-
-    expect { Rake::Task['license:check'].invoke }.to output(/✓.*chef-zero - 4.8.0.*Apache-2.0/).to_stdout
-  end
-
-  it 'detects blacklisted softwares with good licenses correctly' do
-    license_info = '[
-      {
-        "name": "readline",
-        "version": "4.8.0",
-        "license": "Apache-2.0",
-        "dependencies": [
-          {
-            "name": "sample",
-            "version": "1.0.0",
-            "license": "MIT"
-          }
-        ]
-      }
-     ]'
-    allow(File).to receive(:read).and_return(license_info)
-
-    expect { Rake::Task['license:check'].invoke }.to output(/readline.*Blacklisted software/).to_stdout.and raise_error(RuntimeError, "Build Aborted due to license violations")
-  end
-
-  it 'detects bad licenses correctly' do
-    license_info = '[
-      {
-        "name": "foo",
-        "version": "4.8.0",
-        "license": "GPL-3.0",
-        "dependencies": [
-          {
-            "name": "sample",
-            "version": "1.0.0",
-            "license": "GPL-3.0"
-          }
-        ]
-      }
-     ]'
-
-    allow(File).to receive(:read).and_return(license_info)
-    expect { Rake::Task['license:check'].invoke }.to output(/foo.*Unacceptable license/).to_stdout.and raise_error(RuntimeError, "Build Aborted due to license violations")
-  end
-
-  it 'detects whitelisted softwares with bad licenses correctly' do
-    license_info = '[
-      {
-        "name": "git",
-        "version": "4.8.0",
-        "license": "GPL-3.0",
-        "dependencies": [
-          {
-            "name": "sample",
-            "version": "1.0.0",
-            "license": "LGPL"
-          }
-        ]
-      }
-     ]'
-    allow(File).to receive(:read).and_return(license_info)
-
-    expect { Rake::Task['license:check'].invoke }.to output(/git.*Whitelisted software/).to_stdout
-  end
-
-  it 'detects blacklisted softwares with unknown licenses correctly' do
-    license_info = '[
-      {
-        "name": "readline",
-        "version": "4.8.0",
-        "license": "jargon",
-        "dependencies": [
-          {
-            "name": "sample",
-            "version": "1.0.0",
-            "license": "MIT"
-          }
-        ]
-      }
-     ]'
-    allow(File).to receive(:read).and_return(license_info)
-
-    expect { Rake::Task['license:check'].invoke }.to output(/readline.*Blacklisted software/).to_stdout.and raise_error(RuntimeError, "Build Aborted due to license violations")
-  end
-
-  it 'detects whitelisted software with unknown licenses correctly' do
-    license_info = '[
-      {
-        "name": "git",
-        "version": "4.8.0",
-        "license": "jargon",
-        "dependencies": [
-          {
-            "name": "sample",
-            "version": "1.0.0",
-            "license": "MIT"
-          }
-        ]
-      }
-     ]'
-    allow(File).to receive(:read).and_return(license_info)
-    expect { Rake::Task['license:check'].invoke }.to output(/git.*Whitelisted software/).to_stdout
-  end
-
-  it 'should detect if install directory not found' do
-    allow(File).to receive(:read).and_return('install_dir   /opt/gitlab')
-    allow(File).to receive(:exist?).with('/opt/gitlab').and_return(false)
-    expect { Rake::Task['license:check'].invoke }.to raise_error(StandardError, "Unable to retrieve install_dir, thus unable to check /opt/gitlab/dependency_licenses.json")
-  end
-
-  it 'should detect if dependency_license.json file not found' do
-    allow(File).to receive(:read).and_return('install_dir   /opt/gitlab')
-    allow(File).to receive(:exist?).with('/opt/gitlab').and_return(true)
-    allow(File).to receive(:exist?).with('/opt/gitlab/dependency_licenses.json').and_return(false)
-    expect { Rake::Task['license:check'].invoke }.to raise_error(StandardError, "Unable to open /opt/gitlab/dependency_licenses.json")
-  end
-end
diff --git a/spec/gitlab/tasks/qa_spec.rb b/spec/gitlab/tasks/qa_spec.rb
deleted file mode 100644
--- a/spec/gitlab/tasks/qa_spec.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-require 'spec_helper'
-
-RSpec.describe 'qa', type: :rake do
-  let(:gitlab_registry_image_address) { 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce-qa' }
-  let(:gitlab_version) { '10.2.0' }
-  let(:commit_sha) { 'abcd1234' }
-  let(:image_tag) { 'omnibus-12345' }
-  let(:version_manifest) { { "software": { "gitlab-rails": { "locked_version": "123445" } } } }
-
-  before(:all) do
-    Rake.application.rake_require 'gitlab/tasks/qa'
-  end
-
-  describe 'qa:build' do
-    let(:repo_path) { "/tmp/gitlab" }
-    before do
-      Rake::Task['qa:build'].reenable
-
-      allow(Build::QA).to receive(:get_gitlab_repo).and_return(repo_path)
-      allow(Build::QA).to receive(:gitlab_repo).and_return(repo_path)
-      allow(Build::QAImage).to receive(:gitlab_registry_image_address).and_return(gitlab_registry_image_address)
-      allow(JSON).to receive(:parse).and_return(version_manifest)
-    end
-
-    it 'calls build method with correct parameters' do
-      expect(DockerOperations).to receive(:build).with(repo_path, 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce-qa', 'latest', dockerfile: "qa/Dockerfile")
-
-      Rake::Task['qa:build'].invoke
-    end
-  end
-
-  describe 'qa:push' do
-    before do
-      Rake::Task['qa:push:stable'].reenable
-      Rake::Task['qa:push:nightly'].reenable
-      Rake::Task['qa:push:rc'].reenable
-      Rake::Task['qa:push:latest'].reenable
-
-      allow(Build::Info).to receive(:gitlab_version).and_return(gitlab_version)
-    end
-
-    it 'pushes stable images correctly' do
-      expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(gitlab_version)
-      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with(gitlab_version, initial_tag: 'latest')
-
-      Rake::Task['qa:push:stable'].invoke
-    end
-
-    it 'pushes nightly images correctly' do
-      expect(Build::Check).to receive(:is_nightly?).and_return(true)
-
-      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with('nightly', initial_tag: 'latest')
-
-      Rake::Task['qa:push:nightly'].invoke
-    end
-
-    it 'pushes latest images correctly' do
-      expect(Build::Check).to receive(:is_latest_stable_tag?).and_return(true)
-
-      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with('latest', initial_tag: 'latest')
-
-      Rake::Task['qa:push:latest'].invoke
-    end
-
-    it 'pushes rc images correctly' do
-      expect(Build::Check).to receive(:is_latest_tag?).and_return(true)
-
-      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with('rc', initial_tag: 'latest')
-
-      Rake::Task['qa:push:rc'].invoke
-    end
-
-    it 'pushes triggered images correctly' do
-      allow(ENV).to receive(:[]).with('CI').and_return('true')
-      expect(ENV).to receive(:[]).with('IMAGE_TAG').and_return(image_tag)
-
-      expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(image_tag)
-
-      Rake::Task['qa:push:triggered'].invoke
-    end
-
-    describe ':staging' do
-      before do
-        Rake::Task['qa:push:staging'].reenable
-
-        allow(Build::Info).to receive(:gitlab_version).and_return(gitlab_version)
-        allow(Build::Info).to receive(:commit_sha).and_return(commit_sha)
-      end
-
-      it 'pushes staging images correctly' do
-        stub_is_auto_deploy(false)
-        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(gitlab_version)
-        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(commit_sha)
-
-        Rake::Task['qa:push:staging'].invoke
-      end
-
-      it 'pushes staging auto-deploy images correctly' do
-        allow(ENV).to receive(:[]).with('CI').and_return('true')
-        allow(ENV).to receive(:[]).with('CI_COMMIT_TAG').and_return('12.0.12345+5159f2949cb.59c9fa631')
-        allow(Build::Info).to receive(:current_git_tag).and_return('12.0.12345+5159f2949cb.59c9fa631')
-
-        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with('12.0-5159f2949cb')
-        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(commit_sha)
-
-        Rake::Task['qa:push:staging'].invoke
-      end
-    end
-  end
-end
diff --git a/spec/gitlab/util_spec.rb b/spec/gitlab/util_spec.rb
deleted file mode 100644
--- a/spec/gitlab/util_spec.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-require 'spec_helper'
-require 'gitlab/util'
-
-RSpec.describe Gitlab::Util do
-  describe :get_env do
-    it 'strips value of env variable correctly' do
-      allow(ENV).to receive(:[]).with('foo').and_return('  bar  ')
-
-      expect(Gitlab::Util.get_env('foo')).to eq('bar')
-    end
-
-    it 'does not fail if env variable is nil' do
-      allow(ENV).to receive(:[]).with('foo').and_return(nil)
-
-      expect { Gitlab::Util.get_env('foo') }.not_to raise_error
-      expect(Gitlab::Util.get_env('foo')).to eq(nil)
-    end
-  end
-
-  describe :set_env do
-    it 'strips value before setting env variable' do
-      Gitlab::Util.set_env('foo', '  blahblah ')
-      expect(ENV['foo']).to eq('blahblah')
-    end
-
-    it 'does not fail if value is nil' do
-      expect { Gitlab::Util.set_env('foo', nil) }.not_to raise_error
-      expect(ENV['foo']).to eq(nil)
-    end
-  end
-
-  describe :set_env_if_missing do
-    it 'does not override existing value' do
-      allow(ENV).to receive(:[]).with('foo').and_return('lorem')
-
-      Gitlab::Util.set_env_if_missing('foo', 'ipsum')
-      expect(ENV['foo']).to eq('lorem')
-    end
-
-    it 'sets value if env variable is mising' do
-      Gitlab::Util.set_env_if_missing('foo', 'ipsum')
-      expect(ENV['foo']).to eq('ipsum')
-    end
-
-    it 'does not fail if value is nil' do
-      expect { Gitlab::Util.set_env_if_missing('bar', nil) }.not_to raise_error
-      expect(ENV['bar']).to eq(nil)
-    end
-  end
-end
diff --git a/spec/gitlab/version_spec.rb b/spec/gitlab/version_spec.rb
deleted file mode 100644
--- a/spec/gitlab/version_spec.rb
+++ /dev/null
@@ -1,318 +0,0 @@
-require 'spec_helper'
-require 'gitlab/version'
-
-RSpec.describe Gitlab::Version do
-  before do
-    allow(ENV).to receive(:[]).and_call_original
-    stub_env_var('GITLAB_ALTERNATIVE_REPO', nil)
-    stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', nil)
-  end
-
-  describe '.sources_channel' do
-    subject { described_class }
-    using RSpec::Parameterized::TableSyntax
-    where(:alternative_sources, :security_sources, :source_channel) do
-      nil | nil | "alternative"
-      nil | 'true' | "security"
-      nil | 'false' | "alternative"
-      'true' | nil | "alternative"
-      'true' | 'true' | "security"
-      'true' | 'false' | "alternative"
-      'false' | nil | "remote"
-      'false' | 'true' | "security"
-      'false' | 'false' | "remote"
-    end
-
-    with_them do
-      before do
-        stub_env_var('ALTERNATIVE_SOURCES', alternative_sources)
-        stub_env_var('SECURITY_SOURCES', security_sources)
-      end
-
-      context 'when checking the source channel environment variables' do
-        it 'uses the correct source channel' do
-          expect(subject.sources_channel).to eq(source_channel)
-        end
-      end
-    end
-  end
-
-  describe '.fallback_sources_channel' do
-    subject { described_class }
-
-    context 'with ALTERNATIVE_SOURCES=true' do
-      it 'returns "alternative"' do
-        stub_env_var('ALTERNATIVE_SOURCES', 'true')
-
-        expect(subject.fallback_sources_channel).to eq('alternative')
-      end
-    end
-
-    context 'with ALTERNATIVE_SOURCES not set true' do
-      it 'returns "remote"' do
-        stub_env_var('ALTERNATIVE_SOURCES', 'false')
-
-        expect(subject.fallback_sources_channel).to eq('remote')
-      end
-    end
-  end
-
-  describe '.security_channel?' do
-    subject { described_class }
-
-    it 'returns true when sources_channel is set for security' do
-      mock_sources_channel('security')
-
-      expect(subject.security_channel?).to be_truthy
-    end
-
-    it 'returns false when sources_channel is not set for security' do
-      mock_sources_channel
-
-      expect(subject.security_channel?).to be_falsey
-    end
-  end
-
-  describe :remote do
-    subject { Gitlab::Version.new(software) }
-
-    context 'with a valid software name' do
-      let(:software) { 'gitlab-rails-ee' }
-
-      it 'returns a link from custom_sources yml' do
-        mock_sources_channel
-
-        expect(subject.remote).to eq('git@dev.gitlab.org:gitlab/gitlab-ee.git')
-      end
-    end
-
-    context 'with an invalid software name' do
-      let(:software) { 'not a valid software' }
-
-      it 'outputs an empty string' do
-        expect(subject.remote).to eq('')
-      end
-    end
-
-    context 'with default fallback' do
-      let(:software) { 'gitlab-rails-ee' }
-
-      it 'returns "remote" link from custom_sources yml' do
-        mock_sources_channel
-
-        expect(subject.remote).to eq('git@dev.gitlab.org:gitlab/gitlab-ee.git')
-      end
-    end
-
-    context 'with alternative fallback' do
-      let(:software) { 'gitlab-rails-ee' }
-
-      it 'returns "alternative" link from custom_sources yml' do
-        mock_sources_channel('alternative')
-
-        expect(subject.remote).to eq('https://gitlab.com/gitlab-org/gitlab.git')
-      end
-    end
-
-    context 'with alternative env override' do
-      let(:software) { 'gitlab-rails-ee' }
-
-      it 'returns "alternative" link from the environment whenever present' do
-        stub_env_var('GITLAB_ALTERNATIVE_REPO', 'https://gitlab.example.com/gitlab.git')
-
-        expect(subject.remote).to eq('https://gitlab.example.com/gitlab.git')
-      end
-
-      it 'attaches credentials to alternative env links when present' do
-        stub_env_var('GITLAB_ALTERNATIVE_REPO', 'https://gitlab.example.com/gitlab.git')
-        stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', 'APT')
-
-        expect(subject.remote).to eq('https://gitlab-ci-token:APT@gitlab.example.com/gitlab.git')
-      end
-    end
-
-    context 'with security source channel selected' do
-      before do
-        stub_env_var('CI_JOB_TOKEN', 'CJT')
-        mock_sources_channel('security')
-      end
-
-      context 'when security source is defined for the software' do
-        let(:software) { 'gitlab-rails-ee' }
-
-        it 'returns "security" link attached with credential from custom_sources yml' do
-          expect(subject.remote).to eq('https://gitlab-ci-token:CJT@gitlab.com/gitlab-org/security/gitlab.git')
-        end
-
-        context 'when "security" link is in not URI compliant' do
-          before do
-            allow(YAML).to receive(:load_file)
-              .and_return(software => { "security" => "git@dev.gitlab.org:gitlab/gitlab-ee.git" })
-          end
-
-          it 'returns "security" link without attaching credential' do
-            expect(subject.remote).to eq("git@dev.gitlab.org:gitlab/gitlab-ee.git")
-          end
-        end
-      end
-
-      context 'when security source is not defined for the software' do
-        let(:software) { 'prometheus' }
-
-        it 'returns "remote" link from custom_sources yml' do
-          mock_fallback_channel
-
-          expect(subject.remote).to eq('git@dev.gitlab.org:omnibus-mirror/prometheus.git')
-        end
-
-        it 'returns expected link from custom_sources yml when asked for a specific remote' do
-          mock_fallback_channel
-
-          expect(subject.remote('alternative')).to eq('https://gitlab.com/gitlab-org/build/omnibus-mirror/prometheus.git')
-        end
-
-        context 'with alternative fallback' do
-          it 'returns "alternative" link from custom_sources yml' do
-            mock_fallback_channel('alternative')
-
-            expect(subject.remote).to eq('https://gitlab.com/gitlab-org/build/omnibus-mirror/prometheus.git')
-          end
-        end
-      end
-    end
-  end
-
-  describe :print do
-    subject { Gitlab::Version.new(software, version) }
-
-    context 'with a valid software name and version' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { '12.34.567' }
-
-      it 'returns correct version with v appended' do
-        expect(subject.print).to eq('v12.34.567')
-      end
-    end
-
-    context 'with a valid software name and version' do
-      let(:software) { 'gitlab-rails-ee' }
-      let(:version) { '12.34.567-ee' }
-
-      it 'returns correct version with v appended' do
-        expect(subject.print).to eq('v12.34.567-ee')
-      end
-    end
-
-    context 'with a valid software name and no version' do
-      let(:software) { 'ruby' }
-      let(:version) { nil }
-
-      it 'outputs an empty string' do
-        expect(subject.print).to eq(nil)
-      end
-    end
-
-    context 'with a valid software name and a version' do
-      let(:software) { 'ruby' }
-      let(:version) { '2.3.1' }
-
-      it 'adds a v prefix' do
-        expect(subject.print).to eq("v2.3.1")
-      end
-
-      it 'does not add a v prefix if explicitly set' do
-        expect(subject.print(false)).to eq("2.3.1")
-      end
-    end
-
-    context 'with a valid software name and a branch name' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { '9-0-stable' }
-
-      it 'does not add a v prefix' do
-        expect(subject.print).to eq("9-0-stable")
-      end
-    end
-
-    context 'with a valid software name and a branch name' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { 'master' }
-
-      it 'does not add a v prefix' do
-        expect(subject.print).to eq("master")
-      end
-    end
-
-    context 'with a valid software name and an rc tag ' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { '9.1.0-rc1' }
-
-      it 'add a v prefix' do
-        expect(subject.print).to eq("v9.1.0-rc1")
-      end
-    end
-
-    context 'with a valid software name and an rc tag ' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { '9.1.0-rc2-ee' }
-
-      it 'add a v prefix' do
-        expect(subject.print).to eq("v9.1.0-rc2-ee")
-      end
-    end
-
-    context 'with a valid software name and a branch name' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { '9.1.0-fix' }
-
-      it 'does not add a v prefix' do
-        expect(subject.print).to eq("9.1.0-fix")
-      end
-    end
-
-    context 'with a valid software name and a branch name' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { 'fix-9.1.0' }
-
-      it 'does not add a v prefix' do
-        expect(subject.print).to eq("fix-9.1.0")
-      end
-    end
-
-    context 'with a valid software name and a commit sha' do
-      let(:software) { 'gitlab-rails' }
-      let(:version) { '1076385cb57a03fa254be5604f6c6ceb6e39987f' }
-
-      it 'does not add a v prefix' do
-        expect(subject.print).to eq("1076385cb57a03fa254be5604f6c6ceb6e39987f")
-      end
-    end
-  end
-
-  describe :version do
-    subject { Gitlab::Version.new(software) }
-
-    context 'env variable for setting version' do
-      let(:software) { 'gitlab-rails' }
-
-      it 'identifies correct version from env variable' do
-        stub_env_var('GITLAB_VERSION', '5.6.7')
-        allow(File).to receive(:read).and_return("1.2.3")
-        expect(subject.print).to eq("v5.6.7")
-      end
-
-      it 'falls back to VERSION file if env variable not found' do
-        allow(File).to receive(:read).and_return("1.2.3")
-        expect(subject.print).to eq("v1.2.3")
-      end
-    end
-  end
-
-  def mock_sources_channel(channel = 'remote')
-    allow(::Gitlab::Version).to receive(:sources_channel).and_return(channel)
-  end
-
-  def mock_fallback_channel(channel = 'remote')
-    allow(::Gitlab::Version).to receive(:fallback_sources_channel).and_return(channel)
-  end
-end
diff --git a/spec/lib/gitlab/build/check_spec.rb b/spec/lib/gitlab/build/check_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build/check_spec.rb
@@ -0,0 +1,171 @@
+require 'spec_helper'
+require 'gitlab/build/check'
+
+RSpec.describe Build::Check do
+  before do
+    stub_default_package_version
+  end
+
+  describe 'is_ee?' do
+    describe 'with environment variables' do
+      before do
+        stub_is_ee_version(false)
+      end
+
+      describe 'ee variable' do
+        it 'when ee=true' do
+          stub_is_ee_env(true)
+          expect(described_class.is_ee?).to be_truthy
+        end
+
+        it 'when ee=false' do
+          stub_is_ee(false)
+          expect(described_class.is_ee?).to be_falsy
+        end
+
+        it 'when env variable is not set' do
+          stub_is_ee_version(false)
+          stub_is_auto_deploy(false)
+          expect(described_class.is_ee?).to be_falsy
+        end
+      end
+
+      describe 'GITLAB_VERSION variable' do
+        it 'when GITLAB_VERSION ends with -ee' do
+          stub_env_var('GITLAB_VERSION', 'foo-ee')
+          expect(described_class.is_ee?).to be_truthy
+        end
+
+        it 'when GITLAB_VERSION does not end with -ee' do
+          stub_env_var('GITLAB_VERSION', 'foo')
+          stub_is_auto_deploy(false)
+          expect(described_class.is_ee?).to be_falsy
+        end
+
+        it 'ee variable wins over GITLAB_VERSION variable' do
+          stub_is_ee_env(true)
+          stub_env_var('GITLAB_VERSION', 'foo')
+          expect(described_class.is_ee?).to be_truthy
+        end
+      end
+    end
+
+    describe 'without environment variables' do
+      it 'checks the VERSION file' do
+        stub_is_ee_version(false)
+        stub_env_var('GITLAB_VERSION', 'foo-ee')
+        expect(described_class.is_ee?).to be_truthy
+      end
+
+      it 'GITLAB_VERSION variable wins over the file' do
+        stub_env_var('GITLAB_VERSION', 'foo-ee')
+        expect(described_class.is_ee?).to be_truthy
+      end
+    end
+  end
+
+  describe 'include_ee?' do
+    it 'returns true when is_ee? is true' do
+      allow(described_class).to receive(:is_ee?).and_return(true)
+      expect(described_class.include_ee?).to be_truthy
+    end
+
+    it 'returns false when we are building a ce package' do
+      allow(described_class).to receive(:is_ee?).and_return(false)
+      expect(described_class.include_ee?).to be_falsey
+    end
+  end
+
+  describe 'add tag methods' do
+    describe 'is_nightly?' do
+      it 'returns true if it is a nightly build' do
+        stub_env_var('NIGHTLY', 'true')
+        expect(described_class.is_nightly?).to be_truthy
+      end
+
+      it 'returns false if it is not a nightly build' do
+        expect(described_class.is_nightly?).to be_falsey
+      end
+    end
+
+    describe 'is_latest_tag?' do
+      it 'returns true if it is an rc release' do
+        # This will be the case if latest_tag is eg. 9.3.0+rc6.ce.0
+        # or 9.3.0+ce.0
+        allow(Build::Info).to receive(:latest_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
+        allow(described_class).to receive(:match_tag?).and_return(true)
+        expect(described_class.is_latest_tag?).to be_truthy
+      end
+
+      it 'returns true if it is not an rc release' do
+        allow(Build::Info).to receive(:latest_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
+        allow(described_class).to receive(:match_tag?).and_return(false)
+        expect(described_class.is_latest_tag?).to be_falsey
+      end
+    end
+
+    describe 'is_latest_stable_tag?' do
+      it 'returns true if it is a stable release' do
+        # This will be the case if latest_tag is eg. 9.3.0+ce.0
+        # It will not be the case if the tag is 9.3.0+rc6.ce.0
+        allow(Build::Info).to receive(:latest_stable_tag).and_return('9.3.0+ce.0') # This line only is only an example, stubbing is not needed.
+        allow(described_class).to receive(:match_tag?).and_return(true)
+        expect(described_class.is_latest_stable_tag?).to be_truthy
+      end
+
+      it 'returns true if it is not a stable release' do
+        allow(Build::Info).to receive(:latest_stable_tag).and_return('9.3.0+rc6.ce.0') # This line only is only an example, stubbing is not needed.
+        allow(described_class).to receive(:match_tag?).and_return(false)
+        expect(described_class.is_latest_stable_tag?).to be_falsey
+      end
+    end
+  end
+
+  describe '.is_patch_release?' do
+    it 'returns true for patch release' do
+      allow(Build::Info).to receive(:semver_version).and_return("10.0.3")
+      expect(described_class.is_patch_release?).to be_truthy
+    end
+
+    it 'returns false for major/minor release' do
+      allow(Build::Info).to receive(:semver_version).and_return("10.0.0")
+      expect(described_class.is_patch_release?).to be_falsey
+    end
+  end
+
+  describe 'is_rc_tag?' do
+    it 'returns true if it looks like an rc tag' do
+      # It will be the case if the tag is 9.3.0+rc6.ce.0
+      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+rc6.ce.0')
+      expect(described_class.is_rc_tag?).to be_truthy
+    end
+    it 'returns false if it does not look like an rc tag' do
+      # This not be the case if tag is eg. 9.3.0+ce.0
+      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+ce.0')
+      expect(described_class.is_rc_tag?).to be_falsey
+    end
+  end
+
+  describe 'is_auto_deploy?' do
+    it 'returns true if it looks like an auto-deploy tag' do
+      # This is the case if the tag is 11.10.12345+5159f2949cb.59c9fa631
+      allow(Build::Info).to receive(:current_git_tag).and_return('11.10.12345+5159f2949cb.59c9fa631')
+      expect(described_class.is_auto_deploy?).to be_truthy
+    end
+
+    it 'returns false if it does not look like an auto-deploy tag' do
+      # This not be the case if ag is eg. 9.3.0+ce.0
+      allow(Gitlab::Util).to receive(:get_env).with('CI_COMMIT_REF_NAME').and_return('a-random-branch')
+
+      allow(Build::Info).to receive(:current_git_tag).and_return('9.3.0+ce.0')
+      expect(described_class.is_auto_deploy?).to be_falsey
+    end
+  end
+
+  describe 'ci_commit_tag?' do
+    it 'checks for the CI_COMMIT_TAG' do
+      allow(Gitlab::Util).to receive(:get_env).with('CI_COMMIT_TAG').and_return('11.10.12345+5159f2949cb.59c9fa631')
+      expect(described_class.ci_commit_tag?).to be_truthy
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build/facts_spec.rb b/spec/lib/gitlab/build/facts_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build/facts_spec.rb
@@ -0,0 +1,96 @@
+require 'spec_helper'
+require 'gitlab/build/facts'
+require 'gitlab/build/gitlab_image'
+
+RSpec.describe Build::Facts do
+  before do
+    allow(ENV).to receive(:[]).and_call_original
+  end
+
+  describe '.generate' do
+    it 'calls necessary methods' do
+      expect(described_class).to receive(:generate_tag_files)
+      expect(described_class).to receive(:generate_env_file)
+
+      described_class.generate
+    end
+  end
+
+  describe '.generate_tag_files' do
+    before do
+      allow(Build::Info).to receive(:latest_stable_tag).and_return('14.6.2+ce.0')
+      allow(Build::Info).to receive(:latest_tag).and_return('14.7.0+rc42.ce.0')
+    end
+
+    it 'writes tag details to file' do
+      expect(File).to receive(:write).with('build_facts/latest_stable_tag', '14.6.2+ce.0')
+      expect(File).to receive(:write).with('build_facts/latest_tag', '14.7.0+rc42.ce.0')
+
+      described_class.generate_tag_files
+    end
+  end
+
+  describe '.generate_env_file' do
+    before do
+      allow(described_class).to receive(:common_vars).and_return(%w[TOP_UPSTREAM_SOURCE_PROJECT=gitlab-org/gitlab])
+      allow(described_class).to receive(:qa_trigger_vars).and_return(%w[QA_RELEASE=foobar])
+      allow(described_class).to receive(:version_vars).and_return(%w[GITLAB_VERSION=randombranch])
+    end
+
+    it 'writes environment variables to file' do
+      expect(File).to receive(:write).with('build_facts/env_vars', "TOP_UPSTREAM_SOURCE_PROJECT=gitlab-org/gitlab\nQA_RELEASE=foobar\nGITLAB_VERSION=randombranch")
+
+      described_class.generate_env_file
+    end
+  end
+
+  describe '.common_vars' do
+    before do
+      stub_env_var('TOP_UPSTREAM_SOURCE_PROJECT', 'gitlab-org/gitlab')
+      stub_env_var('TOP_UPSTREAM_SOURCE_REF', 'master')
+      stub_env_var('TOP_UPSTREAM_SOURCE_JOB', '123456')
+      stub_env_var('TOP_UPSTREAM_SOURCE_SHA', 'aq2456fs')
+      stub_env_var('TOP_UPSTREAM_MERGE_REQUEST_PROJECT_ID', '55555')
+      stub_env_var('TOP_UPSTREAM_MERGE_REQUEST_IID', '7689')
+    end
+
+    it 'returns correct variables' do
+      result = %w[
+        TOP_UPSTREAM_SOURCE_PROJECT=gitlab-org/gitlab
+        TOP_UPSTREAM_SOURCE_REF=master
+        TOP_UPSTREAM_SOURCE_JOB=123456
+        TOP_UPSTREAM_SOURCE_SHA=aq2456fs
+        TOP_UPSTREAM_MERGE_REQUEST_PROJECT_ID=55555
+        TOP_UPSTREAM_MERGE_REQUEST_IID=7689
+      ]
+
+      expect(described_class.common_vars).to eq(result)
+    end
+  end
+
+  describe '.qa_trigger_vars' do
+    before do
+      allow(described_class).to receive(:generate_knapsack_report?).and_return('true')
+      allow(Build::GitlabImage).to receive(:gitlab_registry_image_address).and_return('registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:14.6.2-rfbranch.450066356.c97110ad-0')
+
+      stub_env_var('QA_IMAGE', 'gitlab/gitlab-ee-qa:nightly')
+      stub_env_var('QA_TESTS', '')
+      stub_env_var('ALLURE_JOB_NAME', '')
+      stub_env_var('GITLAB_QA_OPTIONS', '')
+    end
+
+    it 'returns correct variables' do
+      result = %w[
+        QA_BRANCH=master
+        QA_RELEASE=registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:14.6.2-rfbranch.450066356.c97110ad-0
+        QA_IMAGE=gitlab/gitlab-ee-qa:nightly
+        QA_TESTS=
+        ALLURE_JOB_NAME=
+        GITLAB_QA_OPTIONS=
+        KNAPSACK_GENERATE_REPORT=true
+      ]
+
+      expect(described_class.qa_trigger_vars).to eq(result)
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build/gitlab_image_spec.rb b/spec/lib/gitlab/build/gitlab_image_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build/gitlab_image_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+require 'gitlab/build/gitlab_image'
+
+RSpec.describe Build::GitlabImage do
+  before do
+    allow(Build::Info).to receive(:package).and_return('gitlab-ce')
+  end
+
+  describe '.dockerhub_image_name' do
+    it 'returns a correct image name' do
+      expect(described_class.dockerhub_image_name).to eq('gitlab/gitlab-ce')
+    end
+  end
+
+  describe '.gitlab_registry_image_name' do
+    it 'returns a correct image name' do
+      expect(described_class.gitlab_registry_image_name).to eq('gitlab-ce')
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build/image_spec.rb b/spec/lib/gitlab/build/image_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build/image_spec.rb
@@ -0,0 +1,163 @@
+require 'spec_helper'
+require 'gitlab/build/image'
+
+RSpec.describe Build::Image do
+  ComponentImage = Class.new do
+    extend Build::Image
+
+    def self.gitlab_registry_image_name
+      'my-project/my-image'
+    end
+
+    def self.dockerhub_image_name
+      'my-image'
+    end
+  end
+
+  before do
+    allow(ENV).to receive(:[]).and_call_original
+    allow(ENV).to receive(:[]).with('CI_JOB_TOKEN').and_return('1234')
+    allow(ENV).to receive(:[]).with('CI_REGISTRY').and_return('registry.com')
+    allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('registry.com/group/repo')
+    allow(ENV).to receive(:[]).with('DOCKERHUB_USERNAME').and_return('john')
+    allow(ENV).to receive(:[]).with('DOCKERHUB_PASSWORD').and_return('secret')
+    allow(Build::Info).to receive(:docker_tag).and_return('9.0.0')
+  end
+
+  describe '.pull' do
+    it 'creates an image from the local one' do
+      expect(Docker::Image).to receive(:create).with(
+        'fromImage' => "#{ComponentImage.gitlab_registry_image_address}:9.0.0"
+      )
+
+      ComponentImage.pull
+    end
+  end
+
+  describe '.gitlab_registry_image_address' do
+    it 'returns a correct image name' do
+      expect(ComponentImage.gitlab_registry_image_address).to eq('registry.com/group/repo/my-project/my-image')
+    end
+
+    context 'with a tag given' do
+      it 'returns a correct image name' do
+        expect(ComponentImage.gitlab_registry_image_address(tag: 'mytag')).to eq('registry.com/group/repo/my-project/my-image:mytag')
+      end
+    end
+  end
+
+  describe '.tag_and_push_to_gitlab_registry' do
+    it 'calls DockerOperations.authenticate and DockerOperations.tag_and_push' do
+      expect(DockerOperations).to receive(:authenticate).with('gitlab-ci-token', '1234', 'registry.com')
+      expect(DockerOperations).to receive(:tag_and_push).with(
+        ComponentImage.gitlab_registry_image_address,
+        ComponentImage.gitlab_registry_image_address,
+        'latest',
+        'foo'
+      )
+
+      ComponentImage.tag_and_push_to_gitlab_registry('foo')
+    end
+  end
+
+  describe '.tag_and_push_to_dockerhub' do
+    it 'calls DockerOperations.authenticate and DockerOperations.tag_and_push' do
+      expect(DockerOperations).to receive(:authenticate).with('john', 'secret')
+      expect(DockerOperations).to receive(:tag_and_push).with(
+        ComponentImage.gitlab_registry_image_address,
+        ComponentImage.dockerhub_image_name,
+        '9.0.0',
+        'foo'
+      )
+
+      ComponentImage.tag_and_push_to_dockerhub('foo')
+    end
+
+    context 'with a initial_tag given' do
+      it 'calls DockerOperations.authenticate and DockerOperations.tag_and_push' do
+        expect(DockerOperations).to receive(:authenticate).with('john', 'secret')
+        expect(DockerOperations).to receive(:tag_and_push).with(
+          ComponentImage.gitlab_registry_image_address,
+          ComponentImage.dockerhub_image_name,
+          'latest',
+          'foo'
+        )
+
+        ComponentImage.tag_and_push_to_dockerhub('foo', initial_tag: 'latest')
+      end
+    end
+  end
+
+  describe '.write_release_file' do
+    describe 'with triggered build' do
+      let(:release_file) do
+        [
+          "PACKAGECLOUD_REPO=download-package",
+          "RELEASE_VERSION=12.121.12-ce.1",
+          "DOWNLOAD_URL=https://gitlab.com/api/v4/projects/1/jobs/1/artifacts/pkg/ubuntu-focal/gitlab.deb",
+          "TRIGGER_PRIVATE_TOKEN=NOT-PRIVATE-TOKEN\n"
+        ]
+      end
+
+      before do
+        stub_env_var('PACKAGECLOUD_REPO', 'download-package')
+        stub_env_var('TRIGGER_PRIVATE_TOKEN', 'NOT-PRIVATE-TOKEN')
+        stub_env_var('CI_PROJECT_ID', '1')
+        stub_env_var('CI_PIPELINE_ID', '2')
+        allow(Build::Info).to receive(:release_version).and_return('12.121.12-ce.1')
+        allow(Build::Info).to receive(:fetch_artifact_url).with('1', '2').and_return('1')
+      end
+
+      describe 'for CE' do
+        before do
+          allow(Build::Info).to receive(:package).and_return('gitlab-ce')
+        end
+
+        it 'returns build version and iteration with env variable' do
+          release_file_content = release_file.insert(1, 'RELEASE_PACKAGE=gitlab-ce').join("\n")
+
+          expect(ComponentImage.write_release_file).to eq(release_file_content)
+        end
+      end
+
+      describe 'for EE' do
+        before do
+          allow(Build::Info).to receive(:package).and_return('gitlab-ee')
+        end
+
+        it 'returns build version and iteration with env variable' do
+          release_file_content = release_file.insert(1, 'RELEASE_PACKAGE=gitlab-ee').join("\n")
+
+          expect(ComponentImage.write_release_file).to eq(release_file_content)
+        end
+      end
+
+      describe 'with regular build' do
+        let(:s3_download_link) { 'https://downloads-packages.s3.amazonaws.com/ubuntu-focal/gitlab-ee_12.121.12-ce.1_amd64.deb' }
+
+        let(:release_file) do
+          [
+            "RELEASE_VERSION=12.121.12-ce.1",
+            "DOWNLOAD_URL=#{s3_download_link}\n",
+          ]
+        end
+
+        before do
+          stub_env_var('PACKAGECLOUD_REPO', '')
+          stub_env_var('TRIGGER_PRIVATE_TOKEN', '')
+          stub_env_var('CI_PROJECT_ID', '')
+          stub_env_var('CI_PIPELINE_ID', '')
+          allow(Build::Check).to receive(:on_tag?).and_return(true)
+          allow(Build::Info).to receive(:package).and_return('gitlab-ee')
+          allow(ComponentImage).to receive(:release_version).and_return('12.121.12-ce.1')
+        end
+
+        it 'returns build version and iteration with env variable' do
+          release_file_content = release_file.insert(0, 'RELEASE_PACKAGE=gitlab-ee').join("\n")
+
+          expect(ComponentImage.write_release_file).to eq(release_file_content)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build/info_spec.rb b/spec/lib/gitlab/build/info_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build/info_spec.rb
@@ -0,0 +1,277 @@
+require 'spec_helper'
+require 'gitlab/build/info'
+require 'gitlab/build/gitlab_image'
+
+RSpec.describe Build::Info do
+  before do
+    stub_default_package_version
+    stub_env_var('GITLAB_ALTERNATIVE_REPO', nil)
+    stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', nil)
+  end
+
+  describe '.package' do
+    describe 'shows EE' do
+      it 'when ee=true' do
+        stub_is_ee_env(true)
+        expect(described_class.package).to eq('gitlab-ee')
+      end
+
+      it 'when env var is not present, checks VERSION file' do
+        stub_is_ee_version(true)
+        expect(described_class.package).to eq('gitlab-ee')
+      end
+    end
+
+    describe 'shows CE' do
+      it 'by default' do
+        stub_is_ee(false)
+        expect(described_class.package).to eq('gitlab-ce')
+      end
+    end
+  end
+
+  describe '.release_version' do
+    before do
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      allow_any_instance_of(Omnibus::BuildVersion).to receive(:semver).and_return('12.121.12')
+      allow_any_instance_of(Gitlab::BuildIteration).to receive(:build_iteration).and_return('ce.1')
+    end
+
+    it 'returns build version and iteration' do
+      expect(described_class.release_version).to eq('12.121.12-ce.1')
+    end
+
+    it 'defaults to an initial build version when there are no matching tags' do
+      allow(Build::Check).to receive(:on_tag?).and_return(false)
+      allow(Build::Check).to receive(:is_nightly?).and_return(false)
+      allow(Build::Info).to receive(:latest_tag).and_return('')
+      allow(Build::Info).to receive(:commit_sha).and_return('ffffffff')
+      stub_env_var('CI_PIPELINE_ID', '5555')
+
+      expect(described_class.release_version).to eq('0.0.1+rfbranch.5555.ffffffff-ce.1')
+    end
+
+    describe 'with env variables' do
+      it 'returns build version and iteration with env variable' do
+        stub_env_var('USE_S3_CACHE', 'false')
+        stub_env_var('CACHE_AWS_ACCESS_KEY_ID', 'NOT-KEY')
+        stub_env_var('CACHE_AWS_SECRET_ACCESS_KEY', 'NOT-SECRET-KEY')
+        stub_env_var('CACHE_AWS_BUCKET', 'bucket')
+        stub_env_var('CACHE_AWS_S3_REGION', 'moon-west1')
+        stub_env_var('CACHE_AWS_S3_ENDPOINT', 'endpoint')
+        stub_env_var('CACHE_S3_ACCELERATE', 'sure')
+
+        stub_env_var('NIGHTLY', 'true')
+        stub_env_var('CI_PIPELINE_ID', '5555')
+
+        expect(described_class.release_version).to eq('12.121.12-ce.1')
+      end
+    end
+  end
+
+  describe '.docker_tag' do
+    before do
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      allow_any_instance_of(Omnibus::BuildVersion).to receive(:semver).and_return('12.121.12')
+      allow_any_instance_of(Gitlab::BuildIteration).to receive(:build_iteration).and_return('ce.1')
+    end
+
+    it 'returns package version when regular build' do
+      expect(described_class.docker_tag).to eq('12.121.12-ce.1')
+    end
+
+    it 'respects IMAGE_TAG if set' do
+      allow(ENV).to receive(:[]).with('IMAGE_TAG').and_return('foobar')
+      expect(described_class.docker_tag).to eq('foobar')
+    end
+  end
+
+  # Specs for latest_tag and for latest_stable_tag are really useful since we
+  # are stubbing out shell out to git.
+  # However, they are showing what we expect to see.
+  describe '.latest_tag' do
+    describe 'for CE' do
+      before do
+        stub_is_ee(false)
+        allow(described_class).to receive(:`).with("git describe --exact-match 2>/dev/null").and_return('12.121.12+rc7.ce.0')
+        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ce.*' --sort=-v:refname | head -1").and_return('12.121.12+rc7.ce.0')
+      end
+
+      it 'returns the version of correct edition' do
+        expect(described_class.latest_tag).to eq('12.121.12+rc7.ce.0')
+      end
+    end
+
+    describe 'for EE' do
+      before do
+        stub_is_ee(true)
+        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ee.*' --sort=-v:refname | head -1").and_return('12.121.12+rc7.ee.0')
+      end
+
+      it 'returns the version of correct edition' do
+        expect(described_class.latest_tag).to eq('12.121.12+rc7.ee.0')
+      end
+    end
+  end
+
+  describe '.latest_stable_tag' do
+    describe 'for CE' do
+      before do
+        stub_is_ee(nil)
+        allow(described_class).to receive(:`).with("git describe --exact-match 2>/dev/null").and_return('12.121.12+ce.0')
+        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ce.*' --sort=-v:refname | awk '!/rc/' | head -1").and_return('12.121.12+ce.0')
+      end
+
+      it 'returns the version of correct edition' do
+        expect(described_class.latest_stable_tag).to eq('12.121.12+ce.0')
+      end
+    end
+
+    describe 'for EE' do
+      before do
+        stub_is_ee(true)
+        allow(described_class).to receive(:`).with("git -c versionsort.prereleaseSuffix=rc tag -l '*[+.]ee.*' --sort=-v:refname | awk '!/rc/' | head -1").and_return('12.121.12+ee.0')
+      end
+
+      it 'returns the version of correct edition' do
+        expect(described_class.latest_stable_tag).to eq('12.121.12+ee.0')
+      end
+    end
+  end
+
+  describe '.gitlab_version' do
+    describe 'GITLAB_VERSION variable specified' do
+      it 'returns passed value' do
+        allow(ENV).to receive(:[]).with("GITLAB_VERSION").and_return("9.0.0")
+        expect(described_class.gitlab_version).to eq('9.0.0')
+      end
+    end
+
+    describe 'GITLAB_VERSION variable not specified' do
+      it 'returns content of VERSION' do
+        allow(File).to receive(:read).with("VERSION").and_return("8.5.6")
+        expect(described_class.gitlab_version).to eq('8.5.6')
+      end
+    end
+  end
+
+  describe '.previous_version' do
+    it 'detects previous version correctly' do
+      allow(described_class).to receive(:`).with("git describe --exact-match 2>/dev/null").and_return('10.4.0+ee.0')
+      allow(Build::Info).to receive(:`).with(/git -c versionsort/).and_return("10.4.0+ee.0\n10.3.5+ee.0")
+
+      expect(described_class.previous_version).to eq("10.3.5-ee.0")
+    end
+  end
+
+  describe '.gitlab_rails repo' do
+    describe 'with alternative sources channel selected' do
+      before do
+        allow(::Gitlab::Version).to receive(:sources_channel).and_return('alternative')
+      end
+
+      it 'returns public mirror for GitLab CE' do
+        allow(Build::Info).to receive(:package).and_return("gitlab-ce")
+        expect(described_class.gitlab_rails_repo).to eq("https://gitlab.com/gitlab-org/gitlab-foss.git")
+      end
+      it 'returns public mirror for GitLab EE' do
+        allow(Build::Info).to receive(:package).and_return("gitlab-ee")
+        expect(described_class.gitlab_rails_repo).to eq("https://gitlab.com/gitlab-org/gitlab.git")
+      end
+    end
+
+    describe 'with default sources channel' do
+      before do
+        allow(::Gitlab::Version).to receive(:sources_channel).and_return('remote')
+      end
+
+      it 'returns dev repo for GitLab CE' do
+        allow(Build::Info).to receive(:package).and_return("gitlab-ce")
+        expect(described_class.gitlab_rails_repo).to eq("git@dev.gitlab.org:gitlab/gitlabhq.git")
+      end
+      it 'returns dev repo for GitLab EE' do
+        allow(Build::Info).to receive(:package).and_return("gitlab-ee")
+        expect(described_class.gitlab_rails_repo).to eq("git@dev.gitlab.org:gitlab/gitlab-ee.git")
+      end
+    end
+
+    describe 'with security sources channel selected' do
+      before do
+        allow(::Gitlab::Version).to receive(:sources_channel).and_return('security')
+        stub_env_var('CI_JOB_TOKEN', 'CJT')
+      end
+
+      it 'returns security mirror for GitLab CE with attached credential' do
+        allow(Build::Info).to receive(:package).and_return("gitlab-ce")
+        expect(described_class.gitlab_rails_repo).to eq("https://gitlab-ci-token:CJT@gitlab.com/gitlab-org/security/gitlab-foss.git")
+      end
+      it 'returns security mirror for GitLab EE with attached credential' do
+        allow(Build::Info).to receive(:package).and_return("gitlab-ee")
+        expect(described_class.gitlab_rails_repo).to eq("https://gitlab-ci-token:CJT@gitlab.com/gitlab-org/security/gitlab.git")
+      end
+    end
+  end
+
+  describe '.major_minor_version_and_rails_ref' do
+    it 'return minor and major version components plus the rails ref' do
+      allow(ENV).to receive(:[]).with('CI_COMMIT_TAG').and_return('12.0.12345+5159f2949cb.59c9fa631')
+
+      expect(described_class.major_minor_version_and_rails_ref).to eq('12.0-5159f2949cb')
+    end
+
+    it 'raises an error if the commit tag is invalid' do
+      allow(ENV).to receive(:[]).with('CI_COMMIT_TAG').and_return('xyz')
+
+      expect { described_class.major_minor_version_and_rails_ref }.to raise_error(RuntimeError, /Invalid auto-deploy version 'xyz'/)
+    end
+  end
+
+  describe '.deploy_env' do
+    before do
+      allow(ENV).to receive(:[]).with('AUTO_DEPLOY_ENVIRONMENT').and_return('ad')
+      allow(ENV).to receive(:[]).with('PATCH_DEPLOY_ENVIRONMENT').and_return('patch')
+      allow(ENV).to receive(:[]).with('RELEASE_DEPLOY_ENVIRONMENT').and_return('r')
+    end
+
+    context 'on auto-deploy tag' do
+      before do
+        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(true)
+      end
+      it 'returns the auto-deploy environment' do
+        expect(described_class.deploy_env).to eq('ad')
+      end
+    end
+
+    context 'on RC tag' do
+      before do
+        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(false)
+        allow(Build::Check).to receive(:is_rc_tag?).and_return(true)
+      end
+      it 'returns the auto-deploy environment' do
+        expect(described_class.deploy_env).to eq('patch')
+      end
+    end
+
+    context 'on latest tag' do
+      before do
+        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(false)
+        allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
+        allow(Build::Check).to receive(:is_latest_stable_tag?).and_return(true)
+      end
+      it 'returns the auto-deploy environment' do
+        expect(described_class.deploy_env).to eq('r')
+      end
+    end
+
+    context 'when unable to determine the desired env' do
+      before do
+        allow(Build::Check).to receive(:is_auto_deploy_tag?).and_return(false)
+        allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
+        allow(Build::Check).to receive(:is_latest_stable_tag?).and_return(false)
+      end
+      it 'it returns nil' do
+        expect(described_class.deploy_env).to eq(nil)
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build/qa_image_spec.rb b/spec/lib/gitlab/build/qa_image_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build/qa_image_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+require 'gitlab/build/qa_image'
+
+RSpec.describe Build::QAImage do
+  before do
+    allow(Build::GitlabImage).to receive(:dockerhub_image_name).and_return('gitlab/gitlab-ce')
+    allow(Build::GitlabImage).to receive(:gitlab_registry_image_name).and_return('gitlab-ce')
+  end
+
+  describe '.dockerhub_image_name' do
+    it 'returns a correct image name' do
+      expect(described_class.dockerhub_image_name).to eq('gitlab/gitlab-ce-qa')
+    end
+  end
+
+  describe '.gitlab_registry_image_name' do
+    it 'returns a correct image name' do
+      expect(described_class.gitlab_registry_image_name).to eq('gitlab-ce-qa')
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build/qa_spec.rb b/spec/lib/gitlab/build/qa_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build/qa_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+require 'gitlab/build/qa'
+
+RSpec.describe Build::QA do
+  before do
+    allow(ENV).to receive(:[]).and_call_original
+    stub_env_var('GITLAB_ALTERNATIVE_REPO', nil)
+    stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', nil)
+  end
+
+  describe '.repo_path' do
+    it 'returns correct location' do
+      expect(described_class.repo_path).to eq("/tmp/gitlab")
+    end
+  end
+
+  describe '.get_gitlab_repo' do
+    it 'returns correct location' do
+      allow(Build::QA).to receive(:clone_gitlab_rails).and_return(true)
+      allow(Build::QA).to receive(:checkout_gitlab_rails).and_return(true)
+
+      expect(described_class.get_gitlab_repo).to eq("/tmp/gitlab")
+    end
+  end
+
+  describe '.clone_gitlab_rails' do
+    it 'calls the git command' do
+      allow(Build::Info).to receive(:package).and_return("gitlab-ee")
+      allow(::Gitlab::Version).to receive(:sources_channel).and_return('remote')
+
+      expect(described_class).to receive(:system).with(*%w[rm -rf /tmp/gitlab])
+      expect(described_class).to receive(:system).with(*%w[git clone git@dev.gitlab.org:gitlab/gitlab-ee.git /tmp/gitlab])
+
+      Build::QA.clone_gitlab_rails
+    end
+  end
+
+  describe '.checkout_gitlab_rails' do
+    it 'calls the git command' do
+      allow(Build::Info).to receive(:package).and_return("gitlab-ee")
+      allow(Build::Info).to receive(:gitlab_version).and_return("9.0.0")
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      stub_is_auto_deploy(false)
+
+      expect(described_class).to receive(:system).with(*%w[git --git-dir=/tmp/gitlab/.git --work-tree=/tmp/gitlab checkout --quiet v9.0.0])
+
+      Build::QA.checkout_gitlab_rails
+    end
+  end
+
+  describe '.get_gitlab_rails_sha' do
+    it 'returns the correct stable tag' do
+      allow(Build::Info).to receive(:gitlab_version).and_return("9.0.0")
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      stub_is_auto_deploy(false)
+
+      expect(Build::QA.get_gitlab_rails_sha).to eq("v9.0.0")
+    end
+
+    it 'returns the correct auto-deploy commit sha' do
+      allow(Build::Info).to receive(:gitlab_version).and_return("bebc7c1e290074863e0d2621b3a4c4c7bdb072ae")
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      stub_is_auto_deploy(true)
+
+      expect(Build::QA.get_gitlab_rails_sha).to eq("bebc7c1e290074863e0d2621b3a4c4c7bdb072ae")
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build_iteration_spec.rb b/spec/lib/gitlab/build_iteration_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build_iteration_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+require 'gitlab/build_iteration'
+
+RSpec.describe Gitlab::BuildIteration do
+  describe :build_iteration do
+    subject { Gitlab::BuildIteration.new(git_describe) }
+
+    context 'with an invalid git_describe' do
+      let(:git_describe) { '1.2.3-foo.3' }
+
+      it 'returns 0' do
+        allow(Build::Check).to receive(:on_tag?).and_return(true)
+        expect(subject.build_iteration).to eq('0')
+      end
+    end
+
+    context 'with a git_describe from master' do
+      let(:git_describe) { '1.2.3+rc1.ce.2-6-ge5626d5' }
+
+      it 'returns rc1.ce.2' do
+        allow(Build::Check).to receive(:on_tag?).and_return(true)
+        expect(subject.build_iteration).to eq('rc1.ce.2')
+      end
+    end
+
+    context 'with a proper git_describe' do
+      let(:git_describe) { '1.2.3+foo.4' }
+
+      it 'returns foo.4' do
+        allow(Build::Check).to receive(:on_tag?).and_return(true)
+        expect(subject.build_iteration).to eq('foo.4')
+      end
+    end
+
+    context 'with a git_describe with new line char' do
+      let(:git_describe) { "1.2.3+foo.4\n" }
+
+      it 'returns foo.4' do
+        allow(Build::Check).to receive(:on_tag?).and_return(true)
+        expect(subject.build_iteration).to eq('foo.4')
+      end
+    end
+
+    context 'with multiple plus signs' do
+      let(:git_describe) { '1.2.3+foo.4+bar' }
+
+      it 'returns everything after the first plus' do
+        allow(Build::Check).to receive(:on_tag?).and_return(true)
+        expect(subject.build_iteration).to eq('foo.4+bar')
+      end
+    end
+
+    context 'with an invalid git tag' do
+      let(:git_describe) { '1.2.3+' }
+
+      it 'returns an empty string' do
+        allow(Build::Check).to receive(:on_tag?).and_return(true)
+        expect(subject.build_iteration).to eq('0')
+      end
+    end
+
+    context 'not on a git tag' do
+      subject { Gitlab::BuildIteration.new }
+
+      it 'returns 0' do
+        allow(Build::Check).to receive(:system).with('git describe --exact-match > /dev/null 2>&1').and_return(false)
+        expect(subject.build_iteration).to eq('0')
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/build_spec.rb b/spec/lib/gitlab/build_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/build_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+require 'gitlab/build'
+
+RSpec.describe Build do
+  describe 'cmd' do
+    describe 'by default' do
+      it 'runs build command with log level info' do
+        expect(described_class.cmd('gitlab')).to eq %w[bundle exec omnibus build gitlab --log-level info]
+      end
+    end
+
+    describe 'with different log level' do
+      it 'runs build command with custom log level' do
+        stub_env_var('BUILD_LOG_LEVEL', 'debug')
+        expect(described_class.cmd('gitlab')).to eq %w[bundle exec omnibus build gitlab --log-level debug]
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/deployer_helper_spec.rb b/spec/lib/gitlab/deployer_helper_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/deployer_helper_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+require 'gitlab/build'
+require 'gitlab/deployer_helper'
+
+RSpec.describe DeployerHelper do
+  subject(:service) { described_class.new('some-token', 'some-env', 'some-branch') }
+  describe '#trigger_deploy' do
+    it 'triggers an auto deploy' do
+      response = instance_double('response', body: JSON.dump(web_url: 'http://example.com'), status: 201)
+      allow(Build::Info).to receive(:docker_tag).and_return('some-version')
+      expect(HTTP)
+        .to receive(:post)
+        .with(
+          "https://ops.gitlab.net/api/v4/projects/135/trigger/pipeline",
+          form: {
+            "token" => "some-token",
+            "ref" => "some-branch",
+            "variables[DEPLOY_ENVIRONMENT]" => "some-env",
+            "variables[DEPLOY_VERSION]" => "some-version",
+            "variables[DEPLOY_USER]" => "deployer"
+          }
+        ).and_return(response)
+      expect(service.trigger_deploy).to eq('http://example.com')
+    end
+
+    it 'triggers an auto deploy with retries' do
+      # Set this to zero so there we don't have delays during tests
+      stub_const('DeployerHelper::TRIGGER_RETRY_INTERVAL', 0)
+      response = instance_double('response', body: JSON.dump(web_url: 'http://example.com'), status: 401)
+      allow(Build::Info).to receive(:docker_tag).and_return('some-version')
+      expect(HTTP)
+        .to receive(:post)
+        .with(
+          "https://ops.gitlab.net/api/v4/projects/135/trigger/pipeline",
+          form: {
+            "token" => "some-token",
+            "ref" => "some-branch",
+            "variables[DEPLOY_ENVIRONMENT]" => "some-env",
+            "variables[DEPLOY_VERSION]" => "some-version",
+            "variables[DEPLOY_USER]" => "deployer"
+          }
+        ).and_return(response).exactly(3).times
+      expect { service.trigger_deploy }.to raise_error(RuntimeError, "Unable to trigger pipeline after 3 retries")
+    end
+  end
+end
diff --git a/spec/lib/gitlab/docker_operations_spec.rb b/spec/lib/gitlab/docker_operations_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/docker_operations_spec.rb
@@ -0,0 +1,105 @@
+require 'spec_helper'
+require 'gitlab/docker_operations'
+
+RSpec.describe DockerOperations do
+  describe '.set_timeout' do
+    context 'when ENV["DOCKER_TIMEOUT"] is not set' do
+      it 'uses a default timeout value' do
+        expect(Docker).to receive(:options=).with(read_timeout: 1200, write_timeout: 1200)
+
+        described_class.set_timeout
+      end
+    end
+
+    context 'when ENV["DOCKER_TIMEOUT"] is not set' do
+      before do
+        expect(ENV).to receive(:[]).with('DOCKER_TIMEOUT').and_return("42")
+      end
+
+      it 'uses the given timeout value' do
+        expect(Docker).to receive(:options=).with(read_timeout: "42", write_timeout: "42")
+
+        described_class.set_timeout
+      end
+    end
+  end
+
+  describe '.build' do
+    let(:location) { '/tmp/foo' }
+    let(:image) { 'gitlab-ce' }
+    let(:tag) { 'latest' }
+
+    it 'uses a default timeout value' do
+      expect(described_class).to receive(:set_timeout)
+      expect(Docker::Image).to receive(:build_from_dir).with(location, { t: "#{image}:#{tag}", pull: true }).and_yield(JSON.dump(stream: 'Hello!'))
+      expect(described_class).to receive(:puts).with('Hello!')
+
+      described_class.build(location.to_sym, image, tag)
+    end
+  end
+
+  describe '.authenticate' do
+    context 'with no arguments' do
+      it 'calls Docker.authenticate!' do
+        expect(ENV).to receive(:[]).with('DOCKERHUB_USERNAME').and_return('user')
+        expect(ENV).to receive(:[]).with('DOCKERHUB_PASSWORD').and_return('pass')
+        expect(Docker).to receive(:authenticate!).with(username: 'user', password: 'pass', serveraddress: '')
+
+        described_class.authenticate
+      end
+    end
+
+    context 'with arguments' do
+      it 'uses a default timeout value' do
+        expect(Docker).to receive(:authenticate!).with(username: 'john', password: 'secret', serveraddress: 'registry.com')
+
+        described_class.authenticate('john', 'secret', 'registry.com')
+      end
+    end
+  end
+
+  describe '.get' do
+    it 'calls Docker::Image.get' do
+      expect(described_class).to receive(:set_timeout)
+      expect(Docker::Image).to receive(:get).with('namespace:tag')
+
+      described_class.get('namespace', 'tag')
+    end
+  end
+
+  describe '.push' do
+    it 'calls Docker::Image.push' do
+      image = double
+      creds = double
+
+      expect(described_class).to receive(:set_timeout)
+      expect(described_class).to receive(:get).with('namespace', 'tag').and_return(image)
+      expect(Docker).to receive(:creds).and_return(creds)
+      expect(image).to receive(:push).with(creds, repo_tag: 'namespace:tag').and_yield('Hello!')
+      expect(described_class).to receive(:puts).and_return('Hello!')
+
+      described_class.push('namespace', 'tag')
+    end
+  end
+
+  describe '.tag' do
+    it 'calls Docker::Image.tag' do
+      image = double
+
+      expect(described_class).to receive(:set_timeout)
+      expect(described_class).to receive(:get).with('namespace1', 'tag1').and_return(image)
+      expect(image).to receive(:tag).with(repo: 'namespace2', tag: 'tag2', force: true)
+
+      described_class.tag('namespace1', 'namespace2', 'tag1', 'tag2')
+    end
+  end
+
+  describe '.tag_and_push' do
+    it 'delegates to tag_and_push' do
+      expect(described_class).to receive(:tag).with('namespace1', 'namespace2', 'tag1', 'tag2')
+      expect(described_class).to receive(:push).with('namespace2', 'tag2')
+
+      described_class.tag_and_push('namespace1', 'namespace2', 'tag1', 'tag2')
+    end
+  end
+end
diff --git a/spec/lib/gitlab/linker_helper_spec.rb b/spec/lib/gitlab/linker_helper_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/linker_helper_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+require 'gitlab/linker_helper'
+
+RSpec.describe LinkerHelper do
+  subject(:service) { described_class }
+  before do
+    allow(IO).to receive(:popen).and_call_original
+    allow(IO).to receive(:popen).with(%w[ldconfig -p]).and_return("1 library found\nlibssl.so (libc6,x86-64) => /lib64/libssl.so")
+  end
+
+  describe "#ldconfig" do
+    it "should should update linker cache" do
+      expect(service).to receive(:system).with("ldconfig")
+
+      service.ldconfig
+    end
+
+    it "should return discovered libraries" do
+      expect(service.ldconfig).to have_key("libssl.so")
+    end
+  end
+end
diff --git a/spec/lib/gitlab/package_repository_spec.rb b/spec/lib/gitlab/package_repository_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/package_repository_spec.rb
@@ -0,0 +1,265 @@
+require 'spec_helper'
+require 'gitlab/package_repository'
+require 'gitlab/util'
+
+RSpec.describe PackageRepository do
+  let(:repo) { PackageRepository.new }
+
+  before do
+    allow(ENV).to receive(:[]).and_call_original
+  end
+
+  describe :repository_for_rc do
+    context 'on master' do
+      # Example:
+      # on non stable branch: 8.1.0+rc1.ce.0-1685-gd2a2c51
+      # on tag: 8.12.0+rc1.ee.0
+      before do
+        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.12.0+rc1.ee.0\n")
+      end
+
+      it { expect(repo.repository_for_rc).to eq 'unstable' }
+    end
+
+    context 'on stable branch' do
+      # Example:
+      # on non stable branch: 8.12.8+ce.0-1-gdac92d4
+      # on tag: 8.12.8+ce.0
+      before do
+        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.12.8+ce.0\n")
+      end
+
+      it { expect(repo.repository_for_rc).to eq nil }
+    end
+  end
+
+  describe :target do
+    shared_examples 'with an override repository' do
+      context 'with repository override' do
+        before do
+          set_all_env_variables
+        end
+
+        it 'uses the override repository' do
+          expect(repo.target).to eq('super-stable-1234')
+        end
+      end
+    end
+
+    shared_examples 'with raspberry pi repo' do
+      context 'with raspberry pi repo' do
+        before do
+          set_raspi_env_variable
+        end
+
+        it 'uses the raspberry pi repository' do
+          expect(repo.target).to eq('raspi')
+        end
+      end
+    end
+
+    context 'on non-stable branch' do
+      before do
+        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.1.0+rc1.ce.0-1685-gd2a2c51\n")
+      end
+
+      it 'prints unstable' do
+        expect(repo.target).to eq('unstable')
+      end
+
+      it_behaves_like 'with an override repository'
+      it_behaves_like 'with raspberry pi repo'
+    end
+
+    context 'on a stable branch' do
+      before do
+        allow(IO).to receive(:popen).with(%w[git describe]).and_return("8.12.8+ce.0-1-gdac92d4\n")
+      end
+
+      context 'when EE' do
+        before do
+          allow(File).to receive(:read).with('VERSION').and_return("1.2.3-ee\n")
+        end
+
+        it 'prints gitlab-ee' do
+          expect(repo.target).to eq('gitlab-ee')
+        end
+
+        it_behaves_like 'with an override repository'
+        it_behaves_like 'with raspberry pi repo'
+      end
+
+      context 'when CE' do
+        before do
+          stub_is_ee(false)
+          allow(File).to receive(:read).with('VERSION').and_return("1.2.3\n")
+        end
+
+        it 'prints gitlab-ce' do
+          expect(repo.target).to eq('gitlab-ce')
+        end
+
+        it_behaves_like 'with an override repository'
+        it_behaves_like 'with raspberry pi repo'
+      end
+    end
+  end
+
+  describe :validate do
+    context 'with artifacts available' do
+      before do
+        allow(Build::Info).to receive(:package_list).and_return(['pkg/el-6/gitlab-ce.rpm'])
+      end
+
+      it 'in dry run mode prints the checksum commands' do
+        expect { repo.validate(true) }.to output("sha256sum -c pkg/el-6/gitlab-ce.rpm.sha256\n").to_stdout
+      end
+
+      it 'raises an exception when there is a mismatch' do
+        expect(repo).to receive(:verify_checksum).with('pkg/el-6/gitlab-ce.rpm.sha256', true).and_return(false)
+
+        expect { repo.validate(true) }.to raise_error(%r{Aborting, package .* has an invalid checksum!})
+      end
+    end
+
+    context 'with artifacts unavailable' do
+      before do
+        allow(Build::Info).to receive(:package_list).and_return([])
+      end
+
+      it 'prints nothing' do
+        expect { repo.validate(true) }.to output('').to_stdout
+      end
+    end
+  end
+
+  describe :upload do
+    describe 'with staging repository' do
+      context 'when upload user is not specified' do
+        it 'prints a message and aborts' do
+          expect { repo.upload('my-staging-repository', true) }.to output(%r{User for uploading to package server not specified!\n}).to_stdout
+        end
+      end
+
+      context 'with specified upload user' do
+        before do
+          stub_env_var('PACKAGECLOUD_USER', "gitlab")
+        end
+
+        context 'with artifacts available' do
+          before do
+            allow(Build::Info).to receive(:package_list).and_return(['pkg/el-6/gitlab-ce.rpm'])
+          end
+
+          it 'in dry run mode prints the upload commands' do
+            expect { repo.upload('my-staging-repository', true) }.to output(%r{Uploading...\n}).to_stdout
+            expect { repo.upload('my-staging-repository', true) }.to output(%r{bin/package_cloud push gitlab/my-staging-repository/scientific/6 pkg/el-6/gitlab-ce.rpm --url=https://packages.gitlab.com\n}).to_stdout
+            expect { repo.upload('my-staging-repository', true) }.to output(%r{bin/package_cloud push gitlab/my-staging-repository/ol/6 pkg/el-6/gitlab-ce.rpm --url=https://packages.gitlab.com\n}).to_stdout
+            expect { repo.upload('my-staging-repository', true) }.to output(%r{bin/package_cloud push gitlab/my-staging-repository/el/6 pkg/el-6/gitlab-ce.rpm --url=https://packages.gitlab.com\n}).to_stdout
+          end
+        end
+
+        context 'with artifacts unavailable' do
+          before do
+            allow(Dir).to receive(:glob).with("pkg/**/*.{deb,rpm}").and_return([])
+          end
+
+          it 'prints a message and aborts' do
+            expect { repo.upload('my-staging-repository', true) }.to raise_exception(%r{No packages found for upload. Are artifacts available?})
+          end
+        end
+      end
+    end
+
+    describe "with production repository" do
+      context 'with artifacts available' do
+        before do
+          stub_env_var('PACKAGECLOUD_USER', "gitlab")
+          allow(Dir).to receive(:glob).with("pkg/**/*.{deb,rpm}").and_return(['pkg/ubuntu-focal/gitlab.deb'])
+        end
+
+        context 'for stable release' do
+          before do
+            stub_env_var('PACKAGECLOUD_REPO', nil)
+            stub_env_var('RASPBERRY_REPO', nil)
+            allow_any_instance_of(PackageRepository).to receive(:repository_for_rc).and_return(nil)
+          end
+
+          context 'of EE' do
+            before do
+              stub_is_ee(true)
+            end
+
+            it 'in dry run mode prints the upload commands' do
+              expect { repo.upload(nil, true) }.to output(%r{Uploading...\n}).to_stdout
+              expect { repo.upload(nil, true) }.to output(%r{bin/package_cloud push gitlab/gitlab-ee/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
+            end
+          end
+
+          context 'of CE' do
+            before do
+              stub_is_ee(nil)
+            end
+
+            it 'in dry run mode prints the upload commands' do
+              expect { repo.upload(nil, true) }.to output(%r{Uploading...\n}).to_stdout
+              expect { repo.upload(nil, true) }.to output(%r{bin/package_cloud push gitlab/gitlab-ce/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
+            end
+          end
+        end
+
+        context 'for nightly release' do
+          before do
+            set_nightly_env_variable
+            allow_any_instance_of(PackageRepository).to receive(:repository_for_rc).and_return(nil)
+          end
+
+          it 'in dry run mode prints the upload commands' do
+            expect { repo.upload(Gitlab::Util.get_env('STAGING_REPO'), true) }.to output(%r{Uploading...\n}).to_stdout
+            expect { repo.upload(Gitlab::Util.get_env('STAGING_REPO'), true) }.to output(%r{bin/package_cloud push gitlab/nightly-builds/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
+          end
+        end
+
+        context 'for raspbian release' do
+          before do
+            set_raspi_env_variable
+            allow_any_instance_of(PackageRepository).to receive(:repository_for_rc).and_return(nil)
+          end
+
+          it 'in dry run mode prints the upload commands' do
+            expect { repo.upload(nil, true) }.to output(%r{Uploading...\n}).to_stdout
+            expect { repo.upload(nil, true) }.to output(%r{bin/package_cloud push gitlab/raspi/ubuntu/focal pkg/ubuntu-focal/gitlab.deb --url=https://packages.gitlab.com\n}).to_stdout
+          end
+        end
+      end
+    end
+
+    describe 'when artifacts contain unexpected files' do
+      before do
+        stub_env_var('PACKAGECLOUD_USER', "gitlab")
+        set_all_env_variables
+        allow(Dir).to receive(:glob).with("pkg/**/*.{deb,rpm}").and_return(['pkg/ubuntu-focal/gitlab.deb', 'pkg/ubuntu-focal/testing/gitlab.deb'])
+      end
+
+      it 'raises an exception' do
+        expect { repo.upload(nil, true) }.to raise_exception(%r{Found unexpected contents in the directory:})
+      end
+    end
+  end
+
+  def set_all_env_variables
+    stub_env_var("PACKAGECLOUD_REPO", "super-stable-1234")
+    stub_env_var("RASPBERRY_REPO", "raspi")
+  end
+
+  def set_nightly_env_variable
+    stub_env_var("PACKAGECLOUD_REPO", "")
+    stub_env_var("RASPBERRY_REPO", "")
+    stub_env_var("STAGING_REPO", "nightly-builds")
+  end
+
+  def set_raspi_env_variable
+    stub_env_var("PACKAGECLOUD_REPO", "")
+    stub_env_var("RASPBERRY_REPO", "raspi")
+  end
+end
diff --git a/spec/lib/gitlab/tasks/aws_spec.rb b/spec/lib/gitlab/tasks/aws_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/tasks/aws_spec.rb
@@ -0,0 +1,154 @@
+require 'spec_helper'
+
+Struct.new("Image", :image_id, :name, :tags)
+Struct.new("Region", :region_name)
+Struct.new("Response", :images)
+Struct.new("Tag", :key, :value)
+Struct.new("DescribeRegionResult", :regions)
+
+class AwsDummyClass
+  # Dummy class which mimicks AWS::EC2::Client class from aws-sdk and stubs
+  # necessary methods
+
+  def describe_images(parameters)
+    images = if parameters['filters'.to_sym][1][:values] == ["GitLab Community Edition"]
+               [
+                 Struct::Image.new("ami-422", "GitLab Community Edition 8.13.2", [Struct::Tag.new("Version", "8.13.2")])
+               ]
+             else
+               [
+                 Struct::Image.new("ami-322", "GitLab Enterprise Edition 10.5.4", [Struct::Tag.new("Version", "10.5.4")])
+               ]
+             end
+    @response = Struct::Response.new(images)
+  end
+
+  def describe_regions
+    Struct::DescribeRegionResult.new([Struct::Region.new('us-east-1')])
+  end
+
+  def deregister_image(parameters)
+    true
+  end
+end
+
+RSpec.describe 'aws:ami:create', type: :rake do
+  before :all do
+    Rake.application.rake_require 'gitlab/tasks/aws'
+  end
+
+  before do
+    Rake::Task['aws:ami:create'].reenable
+    allow_any_instance_of(Kernel).to receive(:system).and_return(true)
+  end
+
+  describe 'on a regular tag' do
+    before do
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      allow(Build::Check).to receive(:is_auto_deploy?).and_return(false)
+      allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
+      allow(Build::Info).to receive(:deb_package_download_url).and_return('http://example.com')
+    end
+
+    it 'should identify ce category correctly, if specified' do
+      allow(Build::Info).to receive(:edition).and_return('ce')
+      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
+
+      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ce", "http://example.com", ""])
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+
+    it 'should identify ce category correctly if nothing is specified' do
+      allow(Build::Info).to receive(:edition).and_return(nil)
+      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
+
+      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ce", "http://example.com", ""])
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+
+    it 'should identify ee category correctly' do
+      allow(Build::Info).to receive(:edition).and_return('ee')
+      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
+
+      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee", "http://example.com", ""])
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+
+    it 'should identify ce arm64 correctly' do
+      allow(Gitlab::Util).to receive(:get_env).and_call_original
+      allow(Gitlab::Util).to receive(:get_env).with('AWS_ARCHITECTURE').and_return('arm64')
+      allow(Build::Info).to receive(:edition).and_return(nil)
+      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
+
+      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ce-arm64", "http://example.com", ""])
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+
+    it 'should identify ee arm64 correctly' do
+      allow(Gitlab::Util).to receive(:get_env).and_call_original
+      allow(Gitlab::Util).to receive(:get_env).with('AWS_ARCHITECTURE').and_return('arm64')
+      allow(Build::Info).to receive(:edition).and_return('ee')
+      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
+
+      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee-arm64", "http://example.com", ""])
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+
+    it 'should identify ee ultimate category correctly' do
+      allow(Build::Info).to receive(:edition).and_return('ee')
+      allow(Gitlab::Util).to receive(:get_env).and_call_original
+      allow(Gitlab::Util).to receive(:get_env).with("AWS_RELEASE_TYPE").and_return('ultimate')
+      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
+
+      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee-ultimate", "http://example.com", "AWS_ULTIMATE_LICENSE_FILE"])
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+
+    it 'should identify ee premium category correctly' do
+      allow(Build::Info).to receive(:edition).and_return('ee')
+      allow(Gitlab::Util).to receive(:get_env).and_call_original
+      allow(Gitlab::Util).to receive(:get_env).with("AWS_RELEASE_TYPE").and_return('premium')
+      allow(Omnibus::BuildVersion).to receive(:semver).and_return('9.3.0')
+
+      expect_any_instance_of(Kernel).to receive(:system).with(*["support/packer/packer_ami.sh", "9.3.0", "ee-premium", "http://example.com", "AWS_PREMIUM_LICENSE_FILE"])
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+  end
+
+  describe 'on an rc tag' do
+    before do
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      allow(Build::Check).to receive(:is_auto_deploy?).and_return(false)
+      allow(Build::Check).to receive(:is_rc_tag?).and_return(true)
+      allow(Build::Info).to receive(:deb_package_download_url).and_return('http://example.com')
+    end
+
+    it 'does not do anything' do
+      expect(AWSHelper).not_to receive(:new)
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+  end
+
+  describe 'on an auto-deploy tag' do
+    before do
+      allow(Build::Check).to receive(:on_tag?).and_return(true)
+      allow(Build::Check).to receive(:is_auto_deploy?).and_return(true)
+      allow(Build::Check).to receive(:is_rc_tag?).and_return(false)
+      allow(Build::Info).to receive(:deb_package_download_url).and_return('http://example.com')
+    end
+
+    it 'does not do anything' do
+      expect(AWSHelper).not_to receive(:new)
+
+      Rake::Task['aws:ami:create'].invoke
+    end
+  end
+end
diff --git a/spec/lib/gitlab/tasks/docker_tasks_spec.rb b/spec/lib/gitlab/tasks/docker_tasks_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/tasks/docker_tasks_spec.rb
@@ -0,0 +1,119 @@
+require 'spec_helper'
+require 'gitlab/docker_operations'
+
+RSpec.describe 'docker', type: :rake do
+  before :all do
+    Rake.application.rake_require 'gitlab/tasks/docker_tasks'
+  end
+
+  describe 'docker:build:image' do
+    before do
+      Rake::Task['docker:build:image'].reenable
+      allow(ENV).to receive(:[]).and_call_original
+    end
+
+    it 'calls build command with correct parameters' do
+      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('dev.gitlab.org:5005/gitlab/omnibus-gitlab')
+      allow(Build::Info).to receive(:package).and_return('gitlab-ce')
+      allow(Build::GitlabImage).to receive(:write_release_file).and_return(true)
+      allow(File).to receive(:expand_path).and_return('/tmp/omnibus-gitlab/lib/gitlab/tasks/docker_tasks.rake')
+      allow(DockerOperations).to receive(:build).and_call_original
+
+      expect(DockerOperations).to receive(:build).with("/tmp/omnibus-gitlab/docker", "dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce", "latest")
+      expect(Docker::Image).to receive(:build_from_dir).with("/tmp/omnibus-gitlab/docker", { t: "dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce:latest", pull: true })
+      Rake::Task['docker:build:image'].invoke
+    end
+  end
+
+  describe 'docker:pull:staging' do
+    before do
+      Rake::Task['docker:pull:staging'].reenable
+      allow(ENV).to receive(:[]).and_call_original
+    end
+
+    it 'pulls in correct image' do
+      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('dev.gitlab.org:5005/gitlab/omnibus-gitlab')
+      allow(Build::Info).to receive(:package).and_return('gitlab-ce')
+      allow(Build::Info).to receive(:docker_tag).and_return('9.0.0')
+      allow(DockerOperations).to receive(:authenticate).and_return(true)
+
+      expect(Docker::Image).to receive(:create).with('fromImage' => 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce:9.0.0')
+      Rake::Task['docker:pull:staging'].invoke
+    end
+  end
+
+  describe 'docker:push' do
+    let(:dummy_image) { Docker::Image.new(Docker::Connection.new("test", {}), "id" => "test") }
+    let(:dummy_creds) { { username: "test", password: "test" } }
+
+    before do
+      Rake::Task['docker:push:staging'].reenable
+      Rake::Task['docker:push:stable'].reenable
+      Rake::Task['docker:push:nightly'].reenable
+      Rake::Task['docker:push:rc'].reenable
+      Rake::Task['docker:push:latest'].reenable
+
+      allow(ENV).to receive(:[]).and_call_original
+      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('dev.gitlab.org:5005/gitlab/omnibus-gitlab')
+      allow(Build::Info).to receive(:package).and_return('gitlab-ce')
+      allow(Build::Info).to receive(:docker_tag).and_return('9.0.0')
+      allow(DockerOperations).to receive(:authenticate).and_return(true)
+      allow(Docker::Image).to receive(:get).and_return(dummy_image)
+      allow(Docker).to receive(:creds).and_return(dummy_creds)
+      allow(dummy_image).to receive(:tag).and_return(true)
+    end
+
+    it 'pushes to staging correctly' do
+      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce:9.0.0')
+      Rake::Task['docker:push:staging'].invoke
+    end
+
+    it 'pushes nightly images correctly' do
+      allow(Build::Check).to receive(:is_nightly?).and_return(true)
+
+      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'gitlab/gitlab-ce:nightly')
+      Rake::Task['docker:push:nightly'].invoke
+    end
+
+    it 'pushes latest images correctly' do
+      allow(Build::Check).to receive(:is_latest_stable_tag?).and_return(true)
+
+      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'gitlab/gitlab-ce:latest')
+      Rake::Task['docker:push:latest'].invoke
+    end
+
+    it 'pushes rc images correctly' do
+      allow(Build::Check).to receive(:is_latest_tag?).and_return(true)
+
+      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'gitlab/gitlab-ce:rc')
+      Rake::Task['docker:push:rc'].invoke
+    end
+
+    it 'pushes triggered images correctly' do
+      allow(ENV).to receive(:[]).with('CI_REGISTRY_IMAGE').and_return('registry.gitlab.com/gitlab-org/omnibus-gitlab')
+      allow(ENV).to receive(:[]).with("IMAGE_TAG").and_return("omnibus-12345")
+      allow(Build::Info).to receive(:docker_tag).and_call_original
+
+      expect(dummy_image).to receive(:push).with(dummy_creds, repo_tag: 'registry.gitlab.com/gitlab-org/omnibus-gitlab/gitlab-ce:omnibus-12345')
+      Rake::Task['docker:push:triggered'].invoke
+    end
+  end
+end
+
+RSpec.describe 'docker_operations' do
+  describe 'without docker operations timeout variable' do
+    it 'sets default value as timeout' do
+      DockerOperations.set_timeout
+      expect(Docker.options[:read_timeout]).to eq(1200)
+    end
+  end
+
+  describe 'with docker operations timeout variable specified' do
+    it 'sets provided value as timeout' do
+      allow(ENV).to receive(:[]).and_call_original
+      allow(ENV).to receive(:[]).with('DOCKER_TIMEOUT').and_return("500")
+      DockerOperations.set_timeout
+      expect(Docker.options[:read_timeout]).to eq("500")
+    end
+  end
+end
diff --git a/spec/lib/gitlab/tasks/license_spec.rb b/spec/lib/gitlab/tasks/license_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/tasks/license_spec.rb
@@ -0,0 +1,151 @@
+require 'spec_helper'
+
+RSpec.describe 'license:check', type: :rake do
+  let(:f) { double("Mocked file object") }
+
+  before :all do
+    Rake.application.rake_require 'gitlab/tasks/license'
+  end
+
+  before do
+    Rake::Task['license:check'].reenable
+    allow(File).to receive(:exist?).and_return(true)
+    allow(File).to receive(:open).and_call_original
+    allow(File).to receive(:open).with(/pkg.*license-status.json/, "w").and_return(f)
+    allow(f).to receive(:write).and_return(true)
+    allow(f).to receive(:close).and_return(true)
+    allow(Build::Info).to receive(:release_version).and_return("11.5.1+ce.0")
+  end
+
+  it 'detects good licenses correctly' do
+    license_info = '[
+      {
+        "name": "chef-zero",
+        "version": "4.8.0",
+        "license": "Apache-2.0",
+        "dependencies": [
+          {
+            "name": "sample",
+            "version": "1.0.0",
+            "license": "MIT"
+          }
+        ]
+      }
+     ]'
+    allow(File).to receive(:read).and_return(license_info)
+
+    expect { Rake::Task['license:check'].invoke }.to output(/✓.*chef-zero - 4.8.0.*Apache-2.0/).to_stdout
+  end
+
+  it 'detects blacklisted softwares with good licenses correctly' do
+    license_info = '[
+      {
+        "name": "readline",
+        "version": "4.8.0",
+        "license": "Apache-2.0",
+        "dependencies": [
+          {
+            "name": "sample",
+            "version": "1.0.0",
+            "license": "MIT"
+          }
+        ]
+      }
+     ]'
+    allow(File).to receive(:read).and_return(license_info)
+
+    expect { Rake::Task['license:check'].invoke }.to output(/readline.*Blacklisted software/).to_stdout.and raise_error(RuntimeError, "Build Aborted due to license violations")
+  end
+
+  it 'detects bad licenses correctly' do
+    license_info = '[
+      {
+        "name": "foo",
+        "version": "4.8.0",
+        "license": "GPL-3.0",
+        "dependencies": [
+          {
+            "name": "sample",
+            "version": "1.0.0",
+            "license": "GPL-3.0"
+          }
+        ]
+      }
+     ]'
+
+    allow(File).to receive(:read).and_return(license_info)
+    expect { Rake::Task['license:check'].invoke }.to output(/foo.*Unacceptable license/).to_stdout.and raise_error(RuntimeError, "Build Aborted due to license violations")
+  end
+
+  it 'detects whitelisted softwares with bad licenses correctly' do
+    license_info = '[
+      {
+        "name": "git",
+        "version": "4.8.0",
+        "license": "GPL-3.0",
+        "dependencies": [
+          {
+            "name": "sample",
+            "version": "1.0.0",
+            "license": "LGPL"
+          }
+        ]
+      }
+     ]'
+    allow(File).to receive(:read).and_return(license_info)
+
+    expect { Rake::Task['license:check'].invoke }.to output(/git.*Whitelisted software/).to_stdout
+  end
+
+  it 'detects blacklisted softwares with unknown licenses correctly' do
+    license_info = '[
+      {
+        "name": "readline",
+        "version": "4.8.0",
+        "license": "jargon",
+        "dependencies": [
+          {
+            "name": "sample",
+            "version": "1.0.0",
+            "license": "MIT"
+          }
+        ]
+      }
+     ]'
+    allow(File).to receive(:read).and_return(license_info)
+
+    expect { Rake::Task['license:check'].invoke }.to output(/readline.*Blacklisted software/).to_stdout.and raise_error(RuntimeError, "Build Aborted due to license violations")
+  end
+
+  it 'detects whitelisted software with unknown licenses correctly' do
+    license_info = '[
+      {
+        "name": "git",
+        "version": "4.8.0",
+        "license": "jargon",
+        "dependencies": [
+          {
+            "name": "sample",
+            "version": "1.0.0",
+            "license": "MIT"
+          }
+        ]
+      }
+     ]'
+    allow(File).to receive(:read).and_return(license_info)
+    expect { Rake::Task['license:check'].invoke }.to output(/git.*Whitelisted software/).to_stdout
+  end
+
+  it 'should detect if install directory not found' do
+    allow(File).to receive(:read).and_return('install_dir   /opt/gitlab')
+    allow(File).to receive(:exist?).with('/opt/gitlab').and_return(false)
+    expect { Rake::Task['license:check'].invoke }.to raise_error(StandardError, "Unable to retrieve install_dir, thus unable to check /opt/gitlab/dependency_licenses.json")
+  end
+
+  it 'should detect if dependency_license.json file not found' do
+    allow(File).to receive(:read).and_return('install_dir   /opt/gitlab')
+    allow(File).to receive(:exist?).with('/opt/gitlab').and_return(true)
+    allow(File).to receive(:exist?).with('/opt/gitlab/dependency_licenses.json').and_return(false)
+    expect { Rake::Task['license:check'].invoke }.to raise_error(StandardError, "Unable to open /opt/gitlab/dependency_licenses.json")
+  end
+end
diff --git a/spec/lib/gitlab/tasks/qa_spec.rb b/spec/lib/gitlab/tasks/qa_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/tasks/qa_spec.rb
@@ -0,0 +1,110 @@
+require 'spec_helper'
+
+RSpec.describe 'qa', type: :rake do
+  let(:gitlab_registry_image_address) { 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce-qa' }
+  let(:gitlab_version) { '10.2.0' }
+  let(:commit_sha) { 'abcd1234' }
+  let(:image_tag) { 'omnibus-12345' }
+  let(:version_manifest) { { "software": { "gitlab-rails": { "locked_version": "123445" } } } }
+
+  before(:all) do
+    Rake.application.rake_require 'gitlab/tasks/qa'
+  end
+
+  describe 'qa:build' do
+    let(:repo_path) { "/tmp/gitlab" }
+    before do
+      Rake::Task['qa:build'].reenable
+
+      allow(Build::QA).to receive(:get_gitlab_repo).and_return(repo_path)
+      allow(Build::QA).to receive(:gitlab_repo).and_return(repo_path)
+      allow(Build::QAImage).to receive(:gitlab_registry_image_address).and_return(gitlab_registry_image_address)
+      allow(JSON).to receive(:parse).and_return(version_manifest)
+    end
+
+    it 'calls build method with correct parameters' do
+      expect(DockerOperations).to receive(:build).with(repo_path, 'dev.gitlab.org:5005/gitlab/omnibus-gitlab/gitlab-ce-qa', 'latest', dockerfile: "qa/Dockerfile")
+
+      Rake::Task['qa:build'].invoke
+    end
+  end
+
+  describe 'qa:push' do
+    before do
+      Rake::Task['qa:push:stable'].reenable
+      Rake::Task['qa:push:nightly'].reenable
+      Rake::Task['qa:push:rc'].reenable
+      Rake::Task['qa:push:latest'].reenable
+
+      allow(Build::Info).to receive(:gitlab_version).and_return(gitlab_version)
+    end
+
+    it 'pushes stable images correctly' do
+      expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(gitlab_version)
+      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with(gitlab_version, initial_tag: 'latest')
+
+      Rake::Task['qa:push:stable'].invoke
+    end
+
+    it 'pushes nightly images correctly' do
+      expect(Build::Check).to receive(:is_nightly?).and_return(true)
+
+      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with('nightly', initial_tag: 'latest')
+
+      Rake::Task['qa:push:nightly'].invoke
+    end
+
+    it 'pushes latest images correctly' do
+      expect(Build::Check).to receive(:is_latest_stable_tag?).and_return(true)
+
+      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with('latest', initial_tag: 'latest')
+
+      Rake::Task['qa:push:latest'].invoke
+    end
+
+    it 'pushes rc images correctly' do
+      expect(Build::Check).to receive(:is_latest_tag?).and_return(true)
+
+      expect(Build::QAImage).to receive(:tag_and_push_to_dockerhub).with('rc', initial_tag: 'latest')
+
+      Rake::Task['qa:push:rc'].invoke
+    end
+
+    it 'pushes triggered images correctly' do
+      allow(ENV).to receive(:[]).with('CI').and_return('true')
+      expect(ENV).to receive(:[]).with('IMAGE_TAG').and_return(image_tag)
+
+      expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(image_tag)
+
+      Rake::Task['qa:push:triggered'].invoke
+    end
+
+    describe ':staging' do
+      before do
+        Rake::Task['qa:push:staging'].reenable
+
+        allow(Build::Info).to receive(:gitlab_version).and_return(gitlab_version)
+        allow(Build::Info).to receive(:commit_sha).and_return(commit_sha)
+      end
+
+      it 'pushes staging images correctly' do
+        stub_is_auto_deploy(false)
+        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(gitlab_version)
+        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(commit_sha)
+
+        Rake::Task['qa:push:staging'].invoke
+      end
+
+      it 'pushes staging auto-deploy images correctly' do
+        allow(ENV).to receive(:[]).with('CI').and_return('true')
+        allow(ENV).to receive(:[]).with('CI_COMMIT_TAG').and_return('12.0.12345+5159f2949cb.59c9fa631')
+        allow(Build::Info).to receive(:current_git_tag).and_return('12.0.12345+5159f2949cb.59c9fa631')
+
+        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with('12.0-5159f2949cb')
+        expect(Build::QAImage).to receive(:tag_and_push_to_gitlab_registry).with(commit_sha)
+
+        Rake::Task['qa:push:staging'].invoke
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/util_spec.rb b/spec/lib/gitlab/util_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/util_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+require 'gitlab/util'
+
+RSpec.describe Gitlab::Util do
+  describe :get_env do
+    it 'strips value of env variable correctly' do
+      allow(ENV).to receive(:[]).with('foo').and_return('  bar  ')
+
+      expect(Gitlab::Util.get_env('foo')).to eq('bar')
+    end
+
+    it 'does not fail if env variable is nil' do
+      allow(ENV).to receive(:[]).with('foo').and_return(nil)
+
+      expect { Gitlab::Util.get_env('foo') }.not_to raise_error
+      expect(Gitlab::Util.get_env('foo')).to eq(nil)
+    end
+  end
+
+  describe :set_env do
+    it 'strips value before setting env variable' do
+      Gitlab::Util.set_env('foo', '  blahblah ')
+      expect(ENV['foo']).to eq('blahblah')
+    end
+
+    it 'does not fail if value is nil' do
+      expect { Gitlab::Util.set_env('foo', nil) }.not_to raise_error
+      expect(ENV['foo']).to eq(nil)
+    end
+  end
+
+  describe :set_env_if_missing do
+    it 'does not override existing value' do
+      allow(ENV).to receive(:[]).with('foo').and_return('lorem')
+
+      Gitlab::Util.set_env_if_missing('foo', 'ipsum')
+      expect(ENV['foo']).to eq('lorem')
+    end
+
+    it 'sets value if env variable is mising' do
+      Gitlab::Util.set_env_if_missing('foo', 'ipsum')
+      expect(ENV['foo']).to eq('ipsum')
+    end
+
+    it 'does not fail if value is nil' do
+      expect { Gitlab::Util.set_env_if_missing('bar', nil) }.not_to raise_error
+      expect(ENV['bar']).to eq(nil)
+    end
+  end
+end
diff --git a/spec/lib/gitlab/version_spec.rb b/spec/lib/gitlab/version_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/gitlab/version_spec.rb
@@ -0,0 +1,318 @@
+require 'spec_helper'
+require 'gitlab/version'
+
+RSpec.describe Gitlab::Version do
+  before do
+    allow(ENV).to receive(:[]).and_call_original
+    stub_env_var('GITLAB_ALTERNATIVE_REPO', nil)
+    stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', nil)
+  end
+
+  describe '.sources_channel' do
+    subject { described_class }
+    using RSpec::Parameterized::TableSyntax
+    where(:alternative_sources, :security_sources, :source_channel) do
+      nil | nil | "alternative"
+      nil | 'true' | "security"
+      nil | 'false' | "alternative"
+      'true' | nil | "alternative"
+      'true' | 'true' | "security"
+      'true' | 'false' | "alternative"
+      'false' | nil | "remote"
+      'false' | 'true' | "security"
+      'false' | 'false' | "remote"
+    end
+
+    with_them do
+      before do
+        stub_env_var('ALTERNATIVE_SOURCES', alternative_sources)
+        stub_env_var('SECURITY_SOURCES', security_sources)
+      end
+
+      context 'when checking the source channel environment variables' do
+        it 'uses the correct source channel' do
+          expect(subject.sources_channel).to eq(source_channel)
+        end
+      end
+    end
+  end
+
+  describe '.fallback_sources_channel' do
+    subject { described_class }
+
+    context 'with ALTERNATIVE_SOURCES=true' do
+      it 'returns "alternative"' do
+        stub_env_var('ALTERNATIVE_SOURCES', 'true')
+
+        expect(subject.fallback_sources_channel).to eq('alternative')
+      end
+    end
+
+    context 'with ALTERNATIVE_SOURCES not set true' do
+      it 'returns "remote"' do
+        stub_env_var('ALTERNATIVE_SOURCES', 'false')
+
+        expect(subject.fallback_sources_channel).to eq('remote')
+      end
+    end
+  end
+
+  describe '.security_channel?' do
+    subject { described_class }
+
+    it 'returns true when sources_channel is set for security' do
+      mock_sources_channel('security')
+
+      expect(subject.security_channel?).to be_truthy
+    end
+
+    it 'returns false when sources_channel is not set for security' do
+      mock_sources_channel
+
+      expect(subject.security_channel?).to be_falsey
+    end
+  end
+
+  describe :remote do
+    subject { Gitlab::Version.new(software) }
+
+    context 'with a valid software name' do
+      let(:software) { 'gitlab-rails-ee' }
+
+      it 'returns a link from custom_sources yml' do
+        mock_sources_channel
+
+        expect(subject.remote).to eq('git@dev.gitlab.org:gitlab/gitlab-ee.git')
+      end
+    end
+
+    context 'with an invalid software name' do
+      let(:software) { 'not a valid software' }
+
+      it 'outputs an empty string' do
+        expect(subject.remote).to eq('')
+      end
+    end
+
+    context 'with default fallback' do
+      let(:software) { 'gitlab-rails-ee' }
+
+      it 'returns "remote" link from custom_sources yml' do
+        mock_sources_channel
+
+        expect(subject.remote).to eq('git@dev.gitlab.org:gitlab/gitlab-ee.git')
+      end
+    end
+
+    context 'with alternative fallback' do
+      let(:software) { 'gitlab-rails-ee' }
+
+      it 'returns "alternative" link from custom_sources yml' do
+        mock_sources_channel('alternative')
+
+        expect(subject.remote).to eq('https://gitlab.com/gitlab-org/gitlab.git')
+      end
+    end
+
+    context 'with alternative env override' do
+      let(:software) { 'gitlab-rails-ee' }
+
+      it 'returns "alternative" link from the environment whenever present' do
+        stub_env_var('GITLAB_ALTERNATIVE_REPO', 'https://gitlab.example.com/gitlab.git')
+
+        expect(subject.remote).to eq('https://gitlab.example.com/gitlab.git')
+      end
+
+      it 'attaches credentials to alternative env links when present' do
+        stub_env_var('GITLAB_ALTERNATIVE_REPO', 'https://gitlab.example.com/gitlab.git')
+        stub_env_var('ALTERNATIVE_PRIVATE_TOKEN', 'APT')
+
+        expect(subject.remote).to eq('https://gitlab-ci-token:APT@gitlab.example.com/gitlab.git')
+      end
+    end
+
+    context 'with security source channel selected' do
+      before do
+        stub_env_var('CI_JOB_TOKEN', 'CJT')
+        mock_sources_channel('security')
+      end
+
+      context 'when security source is defined for the software' do
+        let(:software) { 'gitlab-rails-ee' }
+
+        it 'returns "security" link attached with credential from custom_sources yml' do
+          expect(subject.remote).to eq('https://gitlab-ci-token:CJT@gitlab.com/gitlab-org/security/gitlab.git')
+        end
+
+        context 'when "security" link is in not URI compliant' do
+          before do
+            allow(YAML).to receive(:load_file)
+              .and_return(software => { "security" => "git@dev.gitlab.org:gitlab/gitlab-ee.git" })
+          end
+
+          it 'returns "security" link without attaching credential' do
+            expect(subject.remote).to eq("git@dev.gitlab.org:gitlab/gitlab-ee.git")
+          end
+        end
+      end
+
+      context 'when security source is not defined for the software' do
+        let(:software) { 'prometheus' }
+
+        it 'returns "remote" link from custom_sources yml' do
+          mock_fallback_channel
+
+          expect(subject.remote).to eq('git@dev.gitlab.org:omnibus-mirror/prometheus.git')
+        end
+
+        it 'returns expected link from custom_sources yml when asked for a specific remote' do
+          mock_fallback_channel
+
+          expect(subject.remote('alternative')).to eq('https://gitlab.com/gitlab-org/build/omnibus-mirror/prometheus.git')
+        end
+
+        context 'with alternative fallback' do
+          it 'returns "alternative" link from custom_sources yml' do
+            mock_fallback_channel('alternative')
+
+            expect(subject.remote).to eq('https://gitlab.com/gitlab-org/build/omnibus-mirror/prometheus.git')
+          end
+        end
+      end
+    end
+  end
+
+  describe :print do
+    subject { Gitlab::Version.new(software, version) }
+
+    context 'with a valid software name and version' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { '12.34.567' }
+
+      it 'returns correct version with v appended' do
+        expect(subject.print).to eq('v12.34.567')
+      end
+    end
+
+    context 'with a valid software name and version' do
+      let(:software) { 'gitlab-rails-ee' }
+      let(:version) { '12.34.567-ee' }
+
+      it 'returns correct version with v appended' do
+        expect(subject.print).to eq('v12.34.567-ee')
+      end
+    end
+
+    context 'with a valid software name and no version' do
+      let(:software) { 'ruby' }
+      let(:version) { nil }
+
+      it 'outputs an empty string' do
+        expect(subject.print).to eq(nil)
+      end
+    end
+
+    context 'with a valid software name and a version' do
+      let(:software) { 'ruby' }
+      let(:version) { '2.3.1' }
+
+      it 'adds a v prefix' do
+        expect(subject.print).to eq("v2.3.1")
+      end
+
+      it 'does not add a v prefix if explicitly set' do
+        expect(subject.print(false)).to eq("2.3.1")
+      end
+    end
+
+    context 'with a valid software name and a branch name' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { '9-0-stable' }
+
+      it 'does not add a v prefix' do
+        expect(subject.print).to eq("9-0-stable")
+      end
+    end
+
+    context 'with a valid software name and a branch name' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { 'master' }
+
+      it 'does not add a v prefix' do
+        expect(subject.print).to eq("master")
+      end
+    end
+
+    context 'with a valid software name and an rc tag ' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { '9.1.0-rc1' }
+
+      it 'add a v prefix' do
+        expect(subject.print).to eq("v9.1.0-rc1")
+      end
+    end
+
+    context 'with a valid software name and an rc tag ' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { '9.1.0-rc2-ee' }
+
+      it 'add a v prefix' do
+        expect(subject.print).to eq("v9.1.0-rc2-ee")
+      end
+    end
+
+    context 'with a valid software name and a branch name' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { '9.1.0-fix' }
+
+      it 'does not add a v prefix' do
+        expect(subject.print).to eq("9.1.0-fix")
+      end
+    end
+
+    context 'with a valid software name and a branch name' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { 'fix-9.1.0' }
+
+      it 'does not add a v prefix' do
+        expect(subject.print).to eq("fix-9.1.0")
+      end
+    end
+
+    context 'with a valid software name and a commit sha' do
+      let(:software) { 'gitlab-rails' }
+      let(:version) { '1076385cb57a03fa254be5604f6c6ceb6e39987f' }
+
+      it 'does not add a v prefix' do
+        expect(subject.print).to eq("1076385cb57a03fa254be5604f6c6ceb6e39987f")
+      end
+    end
+  end
+
+  describe :version do
+    subject { Gitlab::Version.new(software) }
+
+    context 'env variable for setting version' do
+      let(:software) { 'gitlab-rails' }
+
+      it 'identifies correct version from env variable' do
+        stub_env_var('GITLAB_VERSION', '5.6.7')
+        allow(File).to receive(:read).and_return("1.2.3")
+        expect(subject.print).to eq("v5.6.7")
+      end
+
+      it 'falls back to VERSION file if env variable not found' do
+        allow(File).to receive(:read).and_return("1.2.3")
+        expect(subject.print).to eq("v1.2.3")
+      end
+    end
+  end
+
+  def mock_sources_channel(channel = 'remote')
+    allow(::Gitlab::Version).to receive(:sources_channel).and_return(channel)
+  end
+
+  def mock_fallback_channel(channel = 'remote')
+    allow(::Gitlab::Version).to receive(:fallback_sources_channel).and_return(channel)
+  end
+end
diff --git a/spec/lib/rubocop/cop/avoid_using_env_spec.rb b/spec/lib/rubocop/cop/avoid_using_env_spec.rb
new file mode 100644
--- /dev/null
+++ b/spec/lib/rubocop/cop/avoid_using_env_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+require 'rubocop/rspec/cop_helper'
+require 'rubocop/rspec/expect_offense'
+
+require 'rubocop/cop/avoid_using_env'
+
+RSpec.describe Rubocop::Cop::AvoidUsingEnv do
+  include CopHelper
+  include RuboCop::RSpec::ExpectOffense
+
+  subject(:cop) { described_class.new }
+
+  it 'flags violation for setting env vars directly' do
+    expect_offense(<<~RUBY)
+      call do
+        ENV['foo'] = 'blah'
+        ^^^^^^^^^^^^^^^^^^^ Do not use ENV directly to set environment variables, use Gitlab::Util.set_env or Gitlab::Util.set_env_if_missing methods instead.
+      end
+    RUBY
+  end
+
+  it 'flags violation for getting env vars directly ENV' do
+    expect_offense(<<~RUBY)
+      call do
+      value = ENV['foo']
+              ^^^^^^^^^^ Do not use ENV directly to retrieve environment variables. Use Gitlab::Util.get_env method instead.
+      end
+    RUBY
+  end
+
+  it 'flags violation for using ||= with ENV' do
+    expect_offense(<<~RUBY)
+      call do
+      ENV['bar'] ||= ENV['foo']
+                     ^^^^^^^^^^ Do not use ENV directly to retrieve environment variables. Use Gitlab::Util.get_env method instead.
+      ^^^^^^^^^^ Do not use ENV directly to retrieve environment variables. Use Gitlab::Util.get_env method instead.
+      ^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use ENV directly to set environment variables, use Gitlab::Util.set_env or Gitlab::Util.set_env_if_missing methods instead.
+      end
+    RUBY
+  end
+
+  it 'does not flag violation for comments' do
+    expect_no_offenses(<<~RUBY)
+      call do
+      # ENV['bar'] ||= ENV['foo']
+      puts valu
+      end
+    RUBY
+  end
+end
diff --git a/spec/rubocop/cop/avoid_using_env_spec.rb b/spec/rubocop/cop/avoid_using_env_spec.rb
deleted file mode 100644
--- a/spec/rubocop/cop/avoid_using_env_spec.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-require 'spec_helper'
-require 'rubocop/rspec/cop_helper'
-require 'rubocop/rspec/expect_offense'
-
-require_relative '../../../lib/rubocop/cop/avoid_using_env'
-
-RSpec.describe Rubocop::Cop::AvoidUsingEnv do
-  include CopHelper
-  include RuboCop::RSpec::ExpectOffense
-
-  subject(:cop) { described_class.new }
-
-  it 'flags violation for setting env vars directly' do
-    expect_offense(<<~RUBY)
-      call do
-        ENV['foo'] = 'blah'
-        ^^^^^^^^^^^^^^^^^^^ Do not use ENV directly to set environment variables, use Gitlab::Util.set_env or Gitlab::Util.set_env_if_missing methods instead.
-      end
-    RUBY
-  end
-
-  it 'flags violation for getting env vars directly ENV' do
-    expect_offense(<<~RUBY)
-      call do
-      value = ENV['foo']
-              ^^^^^^^^^^ Do not use ENV directly to retrieve environment variables. Use Gitlab::Util.get_env method instead.
-      end
-    RUBY
-  end
-
-  it 'flags violation for using ||= with ENV' do
-    expect_offense(<<~RUBY)
-      call do
-      ENV['bar'] ||= ENV['foo']
-                     ^^^^^^^^^^ Do not use ENV directly to retrieve environment variables. Use Gitlab::Util.get_env method instead.
-      ^^^^^^^^^^ Do not use ENV directly to retrieve environment variables. Use Gitlab::Util.get_env method instead.
-      ^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use ENV directly to set environment variables, use Gitlab::Util.set_env or Gitlab::Util.set_env_if_missing methods instead.
-      end
-    RUBY
-  end
-
-  it 'does not flag violation for comments' do
-    expect_no_offenses(<<~RUBY)
-      call do
-      # ENV['bar'] ||= ENV['foo']
-      puts valu
-      end
-    RUBY
-  end
-end