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:
Bianca Nenciu 2024-09-06 09:45:34 +03:00 committed by GitHub
parent 3a43aa6be7
commit 957867798e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 99 additions and 58 deletions

View File

@ -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" }],
)

View File

@ -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