diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
index 0ae1d18fce7..eacfc29440d 100644
--- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
@@ -164,11 +164,10 @@ cache-gems:
_ee:quarantine:
extends:
- .qa
- - .rules:test:quarantine
+ - .rules:test:manual
needs:
- trigger-omnibus
stage: test
- allow_failure: true
variables:
QA_RSPEC_TAGS: --tag quarantine
@@ -344,6 +343,7 @@ ee:update-minor:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Instance::Smoke/
+ - !reference [.rules:test:manual, rules]
ee:update-major:
extends:
@@ -355,6 +355,7 @@ ee:update-major:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Instance::Smoke/
+ - !reference [.rules:test:manual, rules]
ee:gitaly-cluster:
extends: .qa
@@ -363,6 +364,7 @@ ee:gitaly-cluster:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::GitalyCluster/
+ - !reference [.rules:test:manual, rules]
ee:group-saml:
extends: .qa
@@ -371,6 +373,7 @@ ee:group-saml:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::GroupSAML/
+ - !reference [.rules:test:manual, rules]
ee:instance-saml:
extends: .qa
@@ -379,6 +382,7 @@ ee:instance-saml:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::InstanceSAML/
+ - !reference [.rules:test:manual, rules]
ee:jira:
extends: .qa
@@ -389,6 +393,7 @@ ee:jira:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::Jira/
+ - !reference [.rules:test:manual, rules]
ee:ldap-no-server:
extends: .qa
@@ -397,6 +402,7 @@ ee:ldap-no-server:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::LDAPNoServer/
+ - !reference [.rules:test:manual, rules]
ee:ldap-tls:
extends: .qa
@@ -405,6 +411,7 @@ ee:ldap-tls:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::LDAPTLS/
+ - !reference [.rules:test:manual, rules]
ee:ldap-no-tls:
extends: .qa
@@ -413,6 +420,7 @@ ee:ldap-no-tls:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::LDAPNoTLS/
+ - !reference [.rules:test:manual, rules]
ee:mtls:
extends: .qa
@@ -421,6 +429,7 @@ ee:mtls:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::MTLS/
+ - !reference [.rules:test:manual, rules]
ee:mattermost:
extends: .qa
@@ -429,6 +438,7 @@ ee:mattermost:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::Mattermost/
+ - !reference [.rules:test:manual, rules]
ee:registry:
extends: .qa
@@ -437,6 +447,7 @@ ee:registry:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::Registry/
+ - !reference [.rules:test:manual, rules]
ee:registry-with-cdn:
extends: .qa
@@ -453,6 +464,7 @@ ee:registry-with-cdn:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::RegistryWithCDN/
+ - !reference [.rules:test:manual, rules]
ee:repository-storage:
extends: .qa
@@ -461,6 +473,7 @@ ee:repository-storage:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Instance::RepositoryStorage/
+ - !reference [.rules:test:manual, rules]
ee:service-ping-disabled:
extends: .qa
@@ -469,6 +482,7 @@ ee:service-ping-disabled:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::ServicePingDisabled/
+ - !reference [.rules:test:manual, rules]
ee:smtp:
extends: .qa
@@ -477,6 +491,7 @@ ee:smtp:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::SMTP/
+ - !reference [.rules:test:manual, rules]
ee:cloud-activation:
extends: .qa
@@ -486,6 +501,7 @@ ee:cloud-activation:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::CloudActivation/
+ - !reference [.rules:test:manual, rules]
ee:large-setup:
extends: .qa
@@ -495,6 +511,7 @@ ee:large-setup:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Instance::LargeSetup/
+ - !reference [.rules:test:manual, rules]
ee:metrics:
extends: .qa
@@ -503,6 +520,7 @@ ee:metrics:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Instance::Metrics/
+ - !reference [.rules:test:manual, rules]
ee:elasticsearch:
extends: .qa
@@ -514,6 +532,7 @@ ee:elasticsearch:
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::Elasticsearch/
+ - !reference [.rules:test:manual, rules]
ee:registry-object-storage-tls:
extends: ee:object-storage-aws
diff --git a/.gitlab/ci/package-and-test/rules.gitlab-ci.yml b/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
index 0602d2228c3..31a865fbe83 100644
--- a/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
@@ -52,9 +52,10 @@
# ------------------------------------------
# Test
# ------------------------------------------
-.rules:test:quarantine:
+.rules:test:manual:
rules:
- when: manual
+ allow_failure: true
variables:
QA_TESTS: ""
@@ -86,7 +87,10 @@
rules:
- *qa-framework-changes
- <<: *specific-specs
- when: never
+ when: manual
+ allow_failure: true
+ variables:
+ QA_TESTS: ""
- *feature-flags-set-manual
# general qa job rule for jobs without the need to run in parallel
diff --git a/.gitlab/ci/review-apps/qa.gitlab-ci.yml b/.gitlab/ci/review-apps/qa.gitlab-ci.yml
index 21e6a8e42fb..b709707bbab 100644
--- a/.gitlab/ci/review-apps/qa.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/qa.gitlab-ci.yml
@@ -58,7 +58,7 @@ include:
download-knapsack-report:
extends:
- .bundle-base
- - .rules:app-or-qa-framework-changes-or-review-scenarios
+ - .rules:prepare-report
stage: prepare
script:
- bundle exec rake "knapsack:download[qa]"
@@ -134,7 +134,7 @@ review-performance:
e2e-test-report:
extends:
- .generate-allure-report-base
- - .rules:app-or-qa-framework-changes-or-review-scenarios
+ - .rules:prepare-report
stage: post-qa
variables:
ALLURE_JOB_NAME: e2e-review-qa
@@ -162,7 +162,7 @@ upload-knapsack-report:
delete-test-resources:
extends:
- .bundle-base
- - .rules:app-or-qa-framework-changes-or-review-scenarios
+ - .rules:prepare-report
stage: post-qa
variables:
QA_TEST_RESOURCES_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/test-resources-*.json
diff --git a/.gitlab/ci/review-apps/rules.gitlab-ci.yml b/.gitlab/ci/review-apps/rules.gitlab-ci.yml
index 9141ad0ed4a..ea180c553f0 100644
--- a/.gitlab/ci/review-apps/rules.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/rules.gitlab-ci.yml
@@ -19,6 +19,12 @@
.qa-framework-changes: &qa-framework-changes
if: $QA_FRAMEWORK_CHANGES == "true"
+.qa-manual: &qa-manual
+ when: manual
+ allow_failure: true
+ variables:
+ QA_TESTS: ""
+
.never-when-qa-framework-changes-or-no-specific-specs:
- <<: *qa-framework-changes
when: never
@@ -27,7 +33,10 @@
.never-when-specific-specs-always-when-qa-framework-changes:
- <<: *specific-specs
- when: never
+ when: manual
+ allow_failure: true
+ variables:
+ QA_TESTS: ""
- *qa-framework-changes
# ------------------------------------------
@@ -52,6 +61,7 @@
QA_TESTS: "" # unset QA_TESTS even if specific tests were inferred from stage label
- *qa-framework-changes
- if: $QA_SUITES =~ /Test::Instance::Smoke/
+ - *qa-manual
.rules:qa-blocking:
rules:
@@ -81,12 +91,6 @@
# ------------------------------------------
# Prepare/Report
# ------------------------------------------
-# if no rules for test execution are matched, pipeline will not have e2e test jobs
-# so we need to skip knapsack, allure and test resource deletion jobs as well
-.rules:app-or-qa-framework-changes-or-review-scenarios:
+.rules:prepare-report:
rules:
- - *app-changes
- - *qa-framework-changes
- - if: $QA_SUITES =~ /Test::Instance::Smoke/
- - if: $QA_SUITES =~ /Test::Instance::ReviewBlocking/
- - if: $QA_SUITES =~ /Test::Instance::ReviewNonBlocking/
+ - when: always
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 577201cf016..6c1a135573b 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -1839,6 +1839,11 @@
- when: manual
allow_failure: true
+.setup:rules:gitlab_git_test:
+ rules:
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
+
.setup:rules:no-ee-check:
rules:
- <<: *if-not-foss
diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml
index 81b266686ef..4f3111de2bf 100644
--- a/.gitlab/ci/setup.gitlab-ci.yml
+++ b/.gitlab/ci/setup.gitlab-ci.yml
@@ -43,6 +43,14 @@ dont-interrupt-me:
script:
- echo "This jobs makes sure this pipeline won't be interrupted! See https://docs.gitlab.com/ee/ci/yaml/#interruptible."
+gitlab_git_test:
+ extends:
+ - .minimal-job
+ - .setup:rules:gitlab_git_test
+ stage: test
+ script:
+ - spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
+
no-ee-check:
extends:
- .minimal-job
diff --git a/.rubocop.yml b/.rubocop.yml
index 223ce2c04c5..21e2f8f2827 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -45,6 +45,7 @@ AllCops:
- 'file_hooks/**/*'
- 'workhorse/**/*'
- 'shared/packages/**/*'
+ - 'spec/support/*.git/**/*' # e.g. spec/support/gitlab-git-test.git
- 'db/ci_migrate/*.rb' # since the `db/ci_migrate` is a symlinked to `db/migrate`
# Use absolute path to avoid orphan directories with changed workspace root.
CacheRootDirectory: <%= Dir.getwd %>/tmp
diff --git a/.rubocop_todo/style/string_concatenation.yml b/.rubocop_todo/style/string_concatenation.yml
index ad425b53e59..ec15edbc206 100644
--- a/.rubocop_todo/style/string_concatenation.yml
+++ b/.rubocop_todo/style/string_concatenation.yml
@@ -329,6 +329,7 @@ Style/StringConcatenation:
- 'spec/support/shared_examples/models/wiki_shared_examples.rb'
- 'spec/support/shared_examples/requests/api/hooks_shared_examples.rb'
- 'spec/support/shared_examples/requests/snippet_shared_examples.rb'
+ - 'spec/support/unpack-gitlab-git-test'
- 'spec/tooling/lib/tooling/kubernetes_client_spec.rb'
- 'spec/uploaders/job_artifact_uploader_spec.rb'
- 'spec/validators/addressable_url_validator_spec.rb'
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a1de8e1caba..a4e18babd17 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -20664,7 +20664,8 @@ Iteration sort values.
| Value | Description |
| ----- | ----------- |
-| `CADENCE_AND_DUE_DATE_ASC` | Sort by cadence id and due date in ascending order. |
+| `CADENCE_AND_DUE_DATE_ASC` | Sort by cadence id in ascending and due date in ascending order. |
+| `CADENCE_AND_DUE_DATE_DESC` | Sort by cadence id in ascending and due date in descending order. |
### `IterationState`
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb
index 041fb019376..1ae1dd87c07 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Repository License Detection', :reliable, product_group: :source_code do
+ describe 'Repository License Detection', product_group: :source_code do
after do
project.remove_via_api!
end
diff --git a/spec/support/generate-seed-repo-rb b/spec/support/generate-seed-repo-rb
new file mode 100755
index 00000000000..b63ff7147ec
--- /dev/null
+++ b/spec/support/generate-seed-repo-rb
@@ -0,0 +1,165 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# # generate-seed-repo-rb
+#
+# This script generates the seed_repo.rb file used by lib/gitlab/git
+# tests. The seed_repo.rb file needs to be updated anytime there is a
+# Git push to https://gitlab.com/gitlab-org/gitlab-git-test.
+#
+# Usage:
+#
+# ./spec/support/generate-seed-repo-rb > spec/support/helpers/seed_repo.rb
+#
+#
+
+require 'erb'
+require 'tempfile'
+
+SOURCE = File.expand_path('gitlab-git-test.git', __dir__)
+SCRIPT_NAME = 'generate-seed-repo-rb'
+REPO_NAME = 'gitlab-git-test.git'
+
+def main
+ Dir.mktmpdir do |dir|
+ unless system(*%W[git clone --bare #{SOURCE} #{REPO_NAME}], chdir: dir)
+ abort "git clone failed"
+ end
+
+ repo = File.join(dir, REPO_NAME)
+ erb = ERB.new(DATA.read)
+ erb.run(binding)
+ end
+end
+
+def capture!(cmd, dir)
+ output = IO.popen(cmd, 'r', chdir: dir) { |io| io.read }
+ raise "command failed with #{$?}: #{cmd.join(' ')}" unless $?.success?
+
+ output.chomp
+end
+
+main
+
+__END__
+# This file is generated by <%= SCRIPT_NAME %>. Do not edit this file manually.
+#
+# Seed repo:
+<%= capture!(%w{git log --format=#\ %H\ %s}, repo) %>
+
+module SeedRepo
+ module BigCommit
+ ID = "913c66a37b4a45b9769037c55c2d238bd0942d2e".freeze
+ PARENT_ID = "cfe32cf61b73a0d5e9f13e774abde7ff789b1660".freeze
+ MESSAGE = "Files, encoding and much more".freeze
+ AUTHOR_FULL_NAME = "Dmitriy Zaporozhets".freeze
+ FILES_COUNT = 2
+ end
+
+ module Commit
+ ID = "570e7b2abdd848b95f2f578043fc23bd6f6fd24d".freeze
+ PARENT_ID = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9".freeze
+ MESSAGE = "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \n".freeze
+ AUTHOR_FULL_NAME = "Dmitriy Zaporozhets".freeze
+ FILES = ["files/ruby/popen.rb", "files/ruby/regex.rb"].freeze
+ FILES_COUNT = 2
+ C_FILE_PATH = "files/ruby".freeze
+ C_FILES = ["popen.rb", "regex.rb", "version_info.rb"].freeze
+ BLOB_FILE = %{%h3= @key.title\n%hr\n%pre= @key.key\n.actions\n = link_to 'Remove', @key, :confirm => 'Are you sure?', :method => :delete, :class => \"btn danger delete-key\"\n\n\n}.freeze
+ BLOB_FILE_PATH = "app/views/keys/show.html.haml".freeze
+ end
+
+ module EmptyCommit
+ ID = "b0e52af38d7ea43cf41d8a6f2471351ac036d6c9".freeze
+ PARENT_ID = "40f4a7a617393735a95a0bb67b08385bc1e7c66d".freeze
+ MESSAGE = "Empty commit".freeze
+ AUTHOR_FULL_NAME = "Rémy Coutable".freeze
+ FILES = [].freeze
+ FILES_COUNT = FILES.count
+ end
+
+ module EncodingCommit
+ ID = "40f4a7a617393735a95a0bb67b08385bc1e7c66d".freeze
+ PARENT_ID = "66028349a123e695b589e09a36634d976edcc5e8".freeze
+ MESSAGE = "Add ISO-8859-encoded file".freeze
+ AUTHOR_FULL_NAME = "Stan Hu".freeze
+ FILES = ["encoding/iso8859.txt"].freeze
+ FILES_COUNT = FILES.count
+ end
+
+ module FirstCommit
+ ID = "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863".freeze
+ PARENT_ID = nil
+ MESSAGE = "Initial commit".freeze
+ AUTHOR_FULL_NAME = "Dmitriy Zaporozhets".freeze
+ FILES = ["LICENSE", ".gitignore", "README.md"].freeze
+ FILES_COUNT = 3
+ end
+
+ module LastCommit
+ ID = <%= capture!(%w[git show -s --format=%H HEAD], repo).inspect %>.freeze
+ PARENT_ID = <%= capture!(%w[git show -s --format=%P HEAD], repo).split.last.inspect %>.freeze
+ MESSAGE = <%= capture!(%w[git show -s --format=%s HEAD], repo).inspect %>.freeze
+ AUTHOR_FULL_NAME = <%= capture!(%w[git show -s --format=%an HEAD], repo).inspect %>.freeze
+ FILES = <%=
+ parents = capture!(%w[git show -s --format=%P HEAD], repo).split
+ merge_base = parents.size > 1 ? capture!(%w[git merge-base] + parents, repo) : parents.first
+ capture!( %W[git diff --name-only #{merge_base}..HEAD --], repo).split("\n").inspect
+ %>.freeze
+ FILES_COUNT = FILES.count
+ end
+
+ module Repo
+ HEAD = "master".freeze
+ BRANCHES = %w[
+<%= capture!(%W[git for-each-ref --format=#{' ' * 3}%(refname:strip=2) refs/heads/], repo) %>
+ ].freeze
+ TAGS = %w[
+<%= capture!(%W[git for-each-ref --format=#{' ' * 3}%(refname:strip=2) refs/tags/], repo) %>
+ ].freeze
+ end
+
+ module RubyBlob
+ ID = "7e3e39ebb9b2bf433b4ad17313770fbe4051649c".freeze
+ NAME = "popen.rb".freeze
+ CONTENT = <<-eos.freeze
+require 'fileutils'
+require 'open3'
+
+module Popen
+ extend self
+
+ def popen(cmd, path=nil)
+ unless cmd.is_a?(Array)
+ raise RuntimeError, "System commands must be given as an array of strings"
+ end
+
+ path ||= Dir.pwd
+
+ vars = {
+ "PWD" => path
+ }
+
+ options = {
+ chdir: path
+ }
+
+ unless File.directory?(path)
+ FileUtils.mkdir_p(path)
+ end
+
+ @cmd_output = ""
+ @cmd_status = 0
+
+ Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
+ @cmd_output << stdout.read
+ @cmd_output << stderr.read
+ @cmd_status = wait_thr.value.exitstatus
+ end
+
+ return @cmd_output, @cmd_status
+ end
+end
+ eos
+ end
+end
diff --git a/spec/support/gitlab-git-test.git/HEAD b/spec/support/gitlab-git-test.git/HEAD
new file mode 100644
index 00000000000..cb089cd89a7
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/spec/support/gitlab-git-test.git/README.md b/spec/support/gitlab-git-test.git/README.md
new file mode 100644
index 00000000000..4e2cee766fa
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/README.md
@@ -0,0 +1,16 @@
+# Gitlab::Git test repository
+
+This repository is used by (some of) the tests in spec/lib/gitlab/git.
+
+Do not add new large files to this repository. Otherwise we needlessly
+inflate the size of the gitlab-ce repository.
+
+## How to make changes to this repository
+
+- (if needed) clone `https://gitlab.com/gitlab-org/gitlab-foss.git` to your local machine
+- clone `gitlab-ce/spec/support/gitlab-git-test.git` locally (i.e. clone from your hard drive, not from the internet)
+- make changes in your local clone of gitlab-git-test
+- run `git push` which will push to your local source `gitlab-ce/spec/support/gitlab-git-test.git`
+- in gitlab-ce: run `spec/support/prepare-gitlab-git-test-for-commit`
+- in gitlab-ce: `git add spec/support/helpers/seed_repo.rb spec/support/gitlab-git-test.git`
+- commit your changes in gitlab-ce
diff --git a/spec/support/gitlab-git-test.git/config b/spec/support/gitlab-git-test.git/config
new file mode 100644
index 00000000000..03e2d1b1e0f
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/config
@@ -0,0 +1,7 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = true
+ precomposeunicode = true
+[remote "origin"]
+ url = https://gitlab.com/gitlab-org/gitlab-git-test.git
diff --git a/spec/support/gitlab-git-test.git/objects/3e/20715310a699808282e772720b9c04a0696bcc b/spec/support/gitlab-git-test.git/objects/3e/20715310a699808282e772720b9c04a0696bcc
new file mode 100644
index 00000000000..86bf37ac887
Binary files /dev/null and b/spec/support/gitlab-git-test.git/objects/3e/20715310a699808282e772720b9c04a0696bcc differ
diff --git a/spec/support/gitlab-git-test.git/objects/88/3e379fcaa5f818fca81cdbabd7a497794d6535 b/spec/support/gitlab-git-test.git/objects/88/3e379fcaa5f818fca81cdbabd7a497794d6535
new file mode 100644
index 00000000000..1c47f34b9a5
Binary files /dev/null and b/spec/support/gitlab-git-test.git/objects/88/3e379fcaa5f818fca81cdbabd7a497794d6535 differ
diff --git a/spec/support/gitlab-git-test.git/objects/95/96bc54a6f0c0c98248fe97077eb5ccf48a98d0 b/spec/support/gitlab-git-test.git/objects/95/96bc54a6f0c0c98248fe97077eb5ccf48a98d0
new file mode 100644
index 00000000000..d90cb028e9b
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/objects/95/96bc54a6f0c0c98248fe97077eb5ccf48a98d0
@@ -0,0 +1,2 @@
+xOn1䜯 9&O "noYD6ՒҪ?j;wQ GrN(HPrArR7tpM#McNrsI
+%p>۫pz?Y3XBB̰GB4
p?kv۞y~W])[a<CP_
\ No newline at end of file
diff --git a/spec/support/gitlab-git-test.git/objects/c8/b1ab16c858c67b680eea4644cf652485f555cf b/spec/support/gitlab-git-test.git/objects/c8/b1ab16c858c67b680eea4644cf652485f555cf
new file mode 100644
index 00000000000..ca13c8df66a
Binary files /dev/null and b/spec/support/gitlab-git-test.git/objects/c8/b1ab16c858c67b680eea4644cf652485f555cf differ
diff --git a/spec/support/gitlab-git-test.git/objects/e3/7697aea12699f0b44544332a7c0f41ace5fb16 b/spec/support/gitlab-git-test.git/objects/e3/7697aea12699f0b44544332a7c0f41ace5fb16
new file mode 100644
index 00000000000..3be244dbda4
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/objects/e3/7697aea12699f0b44544332a7c0f41ace5fb16
@@ -0,0 +1,2 @@
+xK
+0EgNI|ADt*^
mZ qGčY8ZK7"Fc%oHD9rZLsMJ2=ACmeFgVxI9H2XJrp6;N8z??>+zWƏBÞf}bN@K\SYiSC
\ No newline at end of file
diff --git a/spec/support/gitlab-git-test.git/objects/eb/a0c153ed20d927bab00507f356043b6b4be31e b/spec/support/gitlab-git-test.git/objects/eb/a0c153ed20d927bab00507f356043b6b4be31e
new file mode 100644
index 00000000000..2bf27fe5048
Binary files /dev/null and b/spec/support/gitlab-git-test.git/objects/eb/a0c153ed20d927bab00507f356043b6b4be31e differ
diff --git a/spec/support/gitlab-git-test.git/objects/f6/5ad228d96e2a2ae7088e8557fe8906f6dd2b3f b/spec/support/gitlab-git-test.git/objects/f6/5ad228d96e2a2ae7088e8557fe8906f6dd2b3f
new file mode 100644
index 00000000000..8ab8606c6be
Binary files /dev/null and b/spec/support/gitlab-git-test.git/objects/f6/5ad228d96e2a2ae7088e8557fe8906f6dd2b3f differ
diff --git a/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.idx b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.idx
new file mode 100644
index 00000000000..2253da798c4
Binary files /dev/null and b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.idx differ
diff --git a/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.pack b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.pack
new file mode 100644
index 00000000000..3a61107c5b1
Binary files /dev/null and b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.pack differ
diff --git a/spec/support/gitlab-git-test.git/packed-refs b/spec/support/gitlab-git-test.git/packed-refs
new file mode 100644
index 00000000000..6a61e5df267
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/packed-refs
@@ -0,0 +1,20 @@
+# pack-refs with: peeled fully-peeled sorted
+0b4bc9a49b562e85de7cc9e834518ea6828729b9 refs/heads/feature
+12d65c8dd2b2676fa3ac47d955accc085a37a9c1 refs/heads/fix
+6473c90867124755509e100d0d35ebdc85a0b6ae refs/heads/fix-blob-path
+58fa1a3af4de73ea83fe25a1ef1db8e0c56f67e5 refs/heads/fix-existing-submodule-dir
+40f4a7a617393735a95a0bb67b08385bc1e7c66d refs/heads/fix-mode
+9abd6a8c113a2dd76df3fdb3d58a8cec6db75f8d refs/heads/gitattributes
+46e1395e609395de004cacd4b142865ab0e52a29 refs/heads/gitattributes-updated
+4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6 refs/heads/master
+5937ac0a7beb003549fc5fd26fc247adbce4a52e refs/heads/merge-test
+9596bc54a6f0c0c98248fe97077eb5ccf48a98d0 refs/heads/missing-gitmodules
+4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6 refs/heads/Ääh-test-utf-8
+f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8 refs/tags/v1.0.0
+^6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b refs/tags/v1.1.0
+^5937ac0a7beb003549fc5fd26fc247adbce4a52e
+10d64eed7760f2811ee2d64b44f1f7d3b364f17b refs/tags/v1.2.0
+^eb49186cfa5c4338011f5f590fac11bd66c5c631
+2ac1f24e253e08135507d0830508febaaccf02ee refs/tags/v1.2.1
+^fa1b1e6c004a68b7d8763b86455da9e6b23e36d6
diff --git a/spec/support/gitlab-git-test.git/refs/heads/.gitkeep b/spec/support/gitlab-git-test.git/refs/heads/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/spec/support/gitlab-git-test.git/refs/tags/.gitkeep b/spec/support/gitlab-git-test.git/refs/tags/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/spec/support/prepare-gitlab-git-test-for-commit b/spec/support/prepare-gitlab-git-test-for-commit
new file mode 100755
index 00000000000..77c7f309312
--- /dev/null
+++ b/spec/support/prepare-gitlab-git-test-for-commit
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+abort unless [
+ system('spec/support/generate-seed-repo-rb', out: 'spec/support/helpers/seed_repo.rb'),
+ system('spec/support/unpack-gitlab-git-test')
+].all?
+
+exit if ARGV.first != '--check-for-changes'
+
+git_status = IO.popen(%w[git status --porcelain], &:read)
+abort unless $?.success?
+
+puts git_status
+
+if git_status.lines.grep(%r{^.. spec/support/gitlab-git-test.git}).any?
+ abort "error: detected changes in gitlab-git-test.git"
+end
diff --git a/spec/support/unpack-gitlab-git-test b/spec/support/unpack-gitlab-git-test
new file mode 100755
index 00000000000..5d5f1b7d082
--- /dev/null
+++ b/spec/support/unpack-gitlab-git-test
@@ -0,0 +1,40 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'fileutils'
+
+REPO = 'spec/support/gitlab-git-test.git'
+PACK_DIR = REPO + '/objects/pack'
+GIT = %W[git --git-dir=#{REPO}].freeze
+BASE_PACK = 'pack-691247af2a6acb0b63b73ac0cb90540e93614043'
+
+def main
+ unpack
+ # We want to store the refs in a packed-refs file because if we don't
+ # they can get mangled by filesystems.
+ abort unless system(*GIT, *%w[pack-refs --all])
+ abort unless system(*GIT, 'fsck')
+end
+
+# We don't want contributors to commit new pack files because those
+# create unnecessary churn.
+def unpack
+ pack_files = Dir[File.join(PACK_DIR, '*')].reject do |pack|
+ pack.start_with?(File.join(PACK_DIR, BASE_PACK))
+ end
+ return if pack_files.empty?
+
+ pack_files.each do |pack|
+ unless pack.end_with?('.pack')
+ FileUtils.rm(pack)
+ next
+ end
+
+ File.open(pack, 'rb') do |open_pack|
+ File.unlink(pack)
+ abort unless system(*GIT, 'unpack-objects', in: open_pack)
+ end
+ end
+end
+
+main