DEV: Optimize specs (#238)
Git repositories will be initialized less often and then copied for each spec. This reduces the calls to 'git' and the total execution time of the specs.
This commit is contained in:
parent
3a43aa6be7
commit
957867798e
|
|
@ -38,7 +38,7 @@ RSpec.describe DockerManager::GitRepo do
|
|||
|
||||
subject(:repo) do
|
||||
prepare_repos
|
||||
repo = described_class.new(@local_repo.path)
|
||||
repo = described_class.new(@local_git_repo.path)
|
||||
repo.update_remote! unless @skip_update_remote
|
||||
repo
|
||||
end
|
||||
|
|
@ -47,7 +47,7 @@ RSpec.describe DockerManager::GitRepo do
|
|||
|
||||
before do
|
||||
@skip_update_remote = false
|
||||
@local_repo = @remote_git_repo = nil
|
||||
@local_git_repo = @remote_git_repo = nil
|
||||
@before_local_repo_clone = []
|
||||
@after_local_repo_clone = []
|
||||
end
|
||||
|
|
@ -55,32 +55,41 @@ RSpec.describe DockerManager::GitRepo do
|
|||
after { @remote_git_repo.destroy }
|
||||
|
||||
def prepare_repos
|
||||
return if @local_repo && @remote_git_repo
|
||||
return if @local_git_repo && @remote_git_repo
|
||||
|
||||
@remote_git_repo = GitHelpers::RemoteGitRepo.new(initial_branch: initial_branch)
|
||||
@remote_git_repo.commit(
|
||||
filename: "foo.txt",
|
||||
commits: [
|
||||
{ content: "A", date: "2023-03-06T20:31:17Z" },
|
||||
{
|
||||
content: "B",
|
||||
date: "2023-03-06T21:08:52Z",
|
||||
tags: %w[v3.1.0.beta1 beta latest-release],
|
||||
},
|
||||
{ content: "C", date: "2023-03-06T22:48:29Z" },
|
||||
],
|
||||
)
|
||||
@remote_git_repo.create_branches("tests-passed")
|
||||
cache_key =
|
||||
Digest::SHA1.hexdigest(
|
||||
"#{initial_branch}-" + @before_local_repo_clone.map(&:source_location).flatten.join(","),
|
||||
)
|
||||
|
||||
@before_local_repo_clone.each { |callback| callback.call }
|
||||
@local_repo = @remote_git_repo.create_local_clone(method: clone_method)
|
||||
@after_local_repo_clone.each { |callback| callback.call }
|
||||
@remote_git_repo =
|
||||
GitHelpers::RemoteGitRepo.new(initial_branch:, cache_key:) do |repo|
|
||||
repo.commit(
|
||||
filename: "foo.txt",
|
||||
commits: [
|
||||
{ content: "A", date: "2023-03-06T20:31:17Z" },
|
||||
{
|
||||
content: "B",
|
||||
date: "2023-03-06T21:08:52Z",
|
||||
tags: %w[v3.1.0.beta1 beta latest-release],
|
||||
},
|
||||
{ content: "C", date: "2023-03-06T22:48:29Z" },
|
||||
],
|
||||
)
|
||||
|
||||
repo.create_branches("tests-passed")
|
||||
|
||||
@before_local_repo_clone.each { |callback| callback.call(repo) }
|
||||
end
|
||||
|
||||
@local_git_repo = @remote_git_repo.create_local_clone(method: clone_method)
|
||||
@after_local_repo_clone.each { |callback| callback.call(@remote_git_repo, @local_git_repo) }
|
||||
|
||||
@remote_git_repo.in_remote_repo { |git| git.call("log --pretty=oneline") }
|
||||
end
|
||||
|
||||
def add_new_commits
|
||||
@remote_git_repo.commit(
|
||||
def add_new_commits(remote_repo, local_repo)
|
||||
remote_repo.commit(
|
||||
filename: "foo.txt",
|
||||
commits: [
|
||||
{ content: "D", date: "2023-03-07T10:11:19Z" },
|
||||
|
|
@ -92,12 +101,16 @@ RSpec.describe DockerManager::GitRepo do
|
|||
{ content: "F", date: "2023-03-07T15:22:23Z" },
|
||||
],
|
||||
)
|
||||
@remote_git_repo.rebase(source_branch: "main", target_branch: "tests-passed")
|
||||
remote_repo.rebase(source_branch: "main", target_branch: "tests-passed")
|
||||
end
|
||||
|
||||
shared_examples "common tests" do
|
||||
context "when tracking `tests-passed` branch" do
|
||||
before { @after_local_repo_clone << -> { @local_repo.checkout("tests-passed") } }
|
||||
before do
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
local_repo.checkout("tests-passed")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#has_local_main?" do
|
||||
context "with existing `main` branch" do
|
||||
|
|
@ -125,15 +138,19 @@ RSpec.describe DockerManager::GitRepo do
|
|||
context "with `master` as initial branch" do
|
||||
let(:initial_branch) { "master" }
|
||||
|
||||
before { @after_local_repo_clone << -> { @local_repo.checkout("master") } }
|
||||
before do
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
local_repo.checkout("master")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns `origin/master` if a repo hasn't been renamed" do
|
||||
expect(repo.tracking_ref).to eq("origin/master")
|
||||
end
|
||||
|
||||
it "returns `origin/main` if a repo has been renamed but still tracks `master`" do
|
||||
@after_local_repo_clone << -> do
|
||||
@remote_git_repo.rename_branch(old_name: "master", new_name: "main")
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
remote_repo.rename_branch(old_name: "master", new_name: "main")
|
||||
end
|
||||
|
||||
expect(repo.tracking_ref).to eq("origin/main")
|
||||
|
|
@ -141,7 +158,9 @@ RSpec.describe DockerManager::GitRepo do
|
|||
end
|
||||
|
||||
context "with `main` as current local branch" do
|
||||
before { @after_local_repo_clone << -> { @local_repo.checkout("main") } }
|
||||
before do
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) { local_repo.checkout("main") }
|
||||
end
|
||||
|
||||
it "returns `origin/main` if a repo points at `origin/main`" do
|
||||
expect(repo.tracking_ref).to eq("origin/main")
|
||||
|
|
@ -157,15 +176,19 @@ RSpec.describe DockerManager::GitRepo do
|
|||
context "with `master` as initial branch" do
|
||||
let(:initial_branch) { "master" }
|
||||
|
||||
before { @after_local_repo_clone << -> { @local_repo.checkout("master") } }
|
||||
before do
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
local_repo.checkout("master")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns `origin/master` if a repo hasn't been renamed" do
|
||||
expect(repo.upstream_branch).to eq("origin/master")
|
||||
end
|
||||
|
||||
it "returns `origin/master` if a repo has been renamed but still tracks `master`" do
|
||||
@after_local_repo_clone << -> do
|
||||
@remote_git_repo.rename_branch(old_name: "master", new_name: "main")
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
remote_repo.rename_branch(old_name: "master", new_name: "main")
|
||||
end
|
||||
|
||||
expect(repo.upstream_branch).to eq("origin/master")
|
||||
|
|
@ -173,7 +196,9 @@ RSpec.describe DockerManager::GitRepo do
|
|||
end
|
||||
|
||||
context "with `main` as current local branch" do
|
||||
before { @after_local_repo_clone << -> { @local_repo.checkout("main") } }
|
||||
before do
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) { local_repo.checkout("main") }
|
||||
end
|
||||
|
||||
it "returns `origin/main` if a repo points at `origin/main`" do
|
||||
expect(repo.upstream_branch).to eq("origin/main")
|
||||
|
|
@ -187,7 +212,9 @@ RSpec.describe DockerManager::GitRepo do
|
|||
end
|
||||
|
||||
it "returns false when upstream branch doesn't exist" do
|
||||
@after_local_repo_clone << -> { @remote_git_repo.delete_branches("tests-passed") }
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
remote_repo.delete_branches("tests-passed")
|
||||
end
|
||||
expect(repo.upstream_branch_exist?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
|
@ -225,8 +252,8 @@ RSpec.describe DockerManager::GitRepo do
|
|||
|
||||
context "with no tags" do
|
||||
before do
|
||||
@before_local_repo_clone << -> do
|
||||
@remote_git_repo.delete_tags("beta", "latest-release", "v3.1.0.beta1")
|
||||
@before_local_repo_clone << ->(repo) do
|
||||
repo.delete_tags("beta", "latest-release", "v3.1.0.beta1")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -262,7 +289,7 @@ RSpec.describe DockerManager::GitRepo do
|
|||
context "with `beta` and version tags on HEAD~1" do
|
||||
before do
|
||||
skip_for_shallow_clone
|
||||
@before_local_repo_clone << -> { @remote_git_repo.delete_tags("latest-release") }
|
||||
@before_local_repo_clone << ->(repo) { repo.delete_tags("latest-release") }
|
||||
end
|
||||
|
||||
describe "#latest_local_tag_version" do
|
||||
|
|
@ -287,7 +314,7 @@ RSpec.describe DockerManager::GitRepo do
|
|||
describe "#update_remote!" do
|
||||
it "fetches the correct amount of new commits" do
|
||||
prepare_repos
|
||||
expect { repo.update_remote! }.to not_change { @local_repo.commit_count }
|
||||
expect { repo.update_remote! }.to not_change { @local_git_repo.commit_count }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -343,7 +370,7 @@ RSpec.describe DockerManager::GitRepo do
|
|||
describe "#update_remote!" do
|
||||
it "fetches the correct amount of new commits" do
|
||||
prepare_repos
|
||||
expect { repo.update_remote! }.to change { @local_repo.commit_count }.by(
|
||||
expect { repo.update_remote! }.to change { @local_git_repo.commit_count }.by(
|
||||
fetch_commit_count,
|
||||
)
|
||||
end
|
||||
|
|
@ -353,13 +380,13 @@ RSpec.describe DockerManager::GitRepo do
|
|||
|
||||
context "when tracking `beta` tag" do
|
||||
before do
|
||||
@after_local_repo_clone << -> do
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
unless shallow_clone?
|
||||
@local_repo.checkout("beta")
|
||||
local_repo.checkout("beta")
|
||||
# Mimics the behavior of `web.template.yml` where we store the value of the `$version` variable
|
||||
# as a user-defined config value in git.
|
||||
# See https://github.com/discourse/discourse_docker/blob/main/templates/web.template.yml
|
||||
@local_repo.git("config user.discourse-version beta")
|
||||
local_repo.git("config user.discourse-version beta")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -462,7 +489,7 @@ RSpec.describe DockerManager::GitRepo do
|
|||
describe "#update_remote!" do
|
||||
it "fetches the correct amount of new commits" do
|
||||
prepare_repos
|
||||
expect { repo.update_remote! }.to not_change { @local_repo.commit_count }
|
||||
expect { repo.update_remote! }.to not_change { @local_git_repo.commit_count }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -522,7 +549,7 @@ RSpec.describe DockerManager::GitRepo do
|
|||
describe "#update_remote!" do
|
||||
it "fetches the correct amount of new commits" do
|
||||
prepare_repos
|
||||
expect { repo.update_remote! }.to change { @local_repo.commit_count }.by(
|
||||
expect { repo.update_remote! }.to change { @local_git_repo.commit_count }.by(
|
||||
fetch_commit_count,
|
||||
)
|
||||
end
|
||||
|
|
@ -532,14 +559,14 @@ RSpec.describe DockerManager::GitRepo do
|
|||
|
||||
context "when tracking deleted branch" do
|
||||
before do
|
||||
@before_local_repo_clone << -> do
|
||||
@remote_git_repo.delete_tags("beta")
|
||||
@remote_git_repo.create_branches("beta")
|
||||
@before_local_repo_clone << ->(repo) do
|
||||
repo.delete_tags("beta")
|
||||
repo.create_branches("beta")
|
||||
end
|
||||
@after_local_repo_clone << -> do
|
||||
@local_repo.checkout("beta")
|
||||
@remote_git_repo.delete_branches("beta")
|
||||
@remote_git_repo.in_working_directory do |git|
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
local_repo.checkout("beta")
|
||||
remote_repo.delete_branches("beta")
|
||||
remote_repo.in_working_directory do |git|
|
||||
git.call("tag -m 'latest beta release' -a beta latest-release^{}")
|
||||
git.call("push origin beta")
|
||||
end
|
||||
|
|
@ -595,7 +622,9 @@ RSpec.describe DockerManager::GitRepo do
|
|||
describe "#url" do
|
||||
before do
|
||||
@skip_update_remote = true
|
||||
@after_local_repo_clone << -> { @local_repo.git("remote set-url origin #{remote_url}") }
|
||||
@after_local_repo_clone << ->(remote_repo, local_repo) do
|
||||
local_repo.git("remote set-url origin #{remote_url}")
|
||||
end
|
||||
end
|
||||
|
||||
context "with GitHub HTTPS URL" do
|
||||
|
|
@ -657,8 +686,8 @@ RSpec.describe DockerManager::GitRepo do
|
|||
let!(:clone_method) { GitHelpers::CLONE_SHALLOW }
|
||||
|
||||
before do
|
||||
@before_local_repo_clone << -> do
|
||||
@remote_git_repo.commit(
|
||||
@before_local_repo_clone << ->(repo) do
|
||||
repo.commit(
|
||||
filename: ".discourse-compatibility",
|
||||
commits: [{ content: "<= 1000.0.0: twoPointFiveBranch", date: "2023-03-06T20:31:17Z" }],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,16 +6,25 @@ module GitHelpers
|
|||
CLONE_TREELESS = :treeless
|
||||
|
||||
class RemoteGitRepo
|
||||
attr_reader :url, :work_path, :remote_path
|
||||
attr_reader :url, :root_path, :work_path, :remote_path
|
||||
|
||||
def initialize(initial_branch: "main")
|
||||
@@caches = {}
|
||||
|
||||
def initialize(initial_branch: "main", cache_key: nil, force: false, &blk)
|
||||
@initial_branch = initial_branch
|
||||
@local_clone_count = 0
|
||||
@root_path = Dir.mktmpdir
|
||||
|
||||
@remote_path = File.join(@root_path, "remote.git")
|
||||
@work_path = File.join(@root_path, "work")
|
||||
@url = "file://#{@remote_path}"
|
||||
|
||||
if !force
|
||||
@@caches[cache_key] ||= self.class.new(initial_branch:, cache_key:, force: true, &blk)
|
||||
FileUtils.cp_r(@@caches[cache_key].root_path + "/.", @root_path)
|
||||
Dir.chdir(@work_path) { git "remote set-url origin #{@url}" }
|
||||
return
|
||||
end
|
||||
|
||||
Dir.mkdir(@remote_path)
|
||||
Dir.chdir(@remote_path) do
|
||||
git "init --bare --initial-branch=#{initial_branch}"
|
||||
|
|
@ -23,12 +32,13 @@ module GitHelpers
|
|||
git "config receive.denyNonFastforwards true"
|
||||
git "config receive.denyCurrentBranch ignore"
|
||||
git "config uploadpack.allowFilter true"
|
||||
git "config commit.gpgsign false"
|
||||
end
|
||||
|
||||
@work_path = File.join(@root_path, "work")
|
||||
Dir.mkdir(@work_path)
|
||||
Dir.chdir(@work_path) do
|
||||
git "init . --initial-branch=#{initial_branch}"
|
||||
git "config commit.gpgsign false"
|
||||
git "remote add origin #{@url}"
|
||||
|
||||
File.write("README.md", "This is a git repo for testing docker_manager.")
|
||||
|
|
@ -38,6 +48,8 @@ module GitHelpers
|
|||
git "commit -m 'Initial commit'"
|
||||
git "push --set-upstream origin #{initial_branch}"
|
||||
end
|
||||
|
||||
yield(self) if block_given?
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
|
@ -162,7 +174,7 @@ module GitHelpers
|
|||
if status.success? || !raise_exception
|
||||
stdout.presence
|
||||
else
|
||||
raise RuntimeError
|
||||
raise RuntimeError.new("stderr while running #{command}: #{stderr}")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue