mongo/buildscripts/tests/test_sync_repo_with_copybara.py
Daniel Moody fc6c183e2d SERVER-122303 Move copybara syncs to master (#50337)
GitOrigin-RevId: d2045870869e65f9c864106f9351cb3e3a0db823
2026-05-04 16:00:45 +00:00

3297 lines
141 KiB
Python

import io
import json
import os
import shutil
import subprocess
import sys
import tempfile
import textwrap
import traceback
import unittest
from collections.abc import Sequence
from contextlib import redirect_stdout
from pathlib import Path
from unittest.mock import MagicMock, call, patch
from buildscripts.copybara import generate_evergreen, sync_repo_with_copybara
from buildscripts.copybara.path_rules import render_copybara_path_rules_module_from_files
DEFAULT_COMMON_EXCLUDED_PATTERNS = [
".agents/**",
".claude/**",
".cursor/**",
".github/CODEOWNERS",
".github/workflows/**",
"AGENTS.md",
"CLAUDE.md",
"buildscripts/copybara/**",
"buildscripts/modules/**",
"etc/evergreen_yml_components/**",
"monguard/**",
"sbom.private.json",
"src/mongo/db/modules/**",
"src/third_party/private/**",
]
DEFAULT_TEST_COPYBARA_PATH_RULES_INCLUDES = ("**",)
DEFAULT_TEST_COPYBARA_PATH_RULES_EXCLUDES = tuple(DEFAULT_COMMON_EXCLUDED_PATTERNS)
REPO_COPYBARA_TEMPLATE_PATH = (
Path(__file__).resolve().parents[2]
/ "buildscripts"
/ "copybara"
/ "copybara_path_rules.bara.sky.template"
)
def get_repo_base_copybara_config_path(root: Path) -> Path:
return root / sync_repo_with_copybara.COPYBARA_BASE_CONFIG_PATH
def get_repo_copybara_path_rules_path(root: Path) -> Path:
return root / sync_repo_with_copybara.COPYBARA_PATH_RULES_PATH
def get_repo_copybara_path_rules_template_path(root: Path) -> Path:
return root / sync_repo_with_copybara.COPYBARA_PATH_RULES_TEMPLATE_PATH
def get_repo_copybara_path_rules_module_path(root: Path) -> Path:
return root / sync_repo_with_copybara.COPYBARA_PATH_RULES_MODULE_PATH
def write_copybara_path_rules(
path: Path,
*,
common_includes: Sequence[str],
common_excludes: Sequence[str],
) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(
json.dumps(
{
"common_files_to_include": list(common_includes),
"common_files_to_exclude": list(common_excludes),
},
indent=2,
)
+ "\n"
)
def write_copybara_path_rules_module(path: Path, path_rules_path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(
render_copybara_path_rules_module_from_files(
REPO_COPYBARA_TEMPLATE_PATH,
path_rules_path,
)
)
def write_copybara_path_rules_template(path: Path, template_text: str | None = None) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
if template_text is None:
template_text = REPO_COPYBARA_TEMPLATE_PATH.read_text()
path.write_text(template_text)
@unittest.skipIf(
sys.platform == "win32" or sys.platform == "darwin",
reason="No need to run this unittest on windows or macos",
)
class TestBranchFunctions(unittest.TestCase):
@staticmethod
def create_mock_repo_git_config(mongodb_mongo_dir, config_content):
"""
Create a mock Git repository configuration.
:param mongodb_mongo_dir: The directory path of the mock MongoDB repository.
:param config_content: The content to be written into the Git configuration file.
"""
os.makedirs(mongodb_mongo_dir, exist_ok=True)
# Create .git directory
git_dir = os.path.join(mongodb_mongo_dir, ".git")
os.makedirs(git_dir, exist_ok=True)
# Write contents to .git/config
config_path = os.path.join(git_dir, "config")
with open(config_path, "w") as f:
# Write contents to .git/config
f.write(config_content)
@staticmethod
def create_mock_repo_commits(repo_directory, num_commits, private_commit_hashes=None):
"""
Create mock commits in a Git repository.
:param repo_directory: The directory path of the Git repository where the commits will be created.
:param num_commits: The number of commits to create.
:param private_commit_hashes: Optional. A list of private commit hashes to be included in the commit messages.
:return: A list of commit hashes generated for the new commits.
"""
os.chdir(repo_directory)
sync_repo_with_copybara.run_command("git init")
sync_repo_with_copybara.run_command('git config --local user.email "test@example.com"')
sync_repo_with_copybara.run_command('git config --local user.name "Test User"')
sync_repo_with_copybara.run_command("git config --local commit.gpgsign false")
# Used to store commit hashes
commit_hashes = []
for i in range(num_commits):
with open("test.txt", "a") as f:
f.write(str(i))
sync_repo_with_copybara.run_command("git add test.txt")
commit_message = f"test commit {i}"
# If there are private commit hashes need to be added in public repo commits, include them in the commit message
if private_commit_hashes:
commit_message += f"\nGitOrigin-RevId: {private_commit_hashes[i]}"
# Get the current commit hash
sync_repo_with_copybara.run_command(f'git commit -m "{commit_message}"')
commit_hashes.append(
sync_repo_with_copybara.run_command('git log --pretty=format:"%H" -1')
)
return commit_hashes
@staticmethod
def create_repo_branch(repo_directory, branch_name):
"""
Create a branch in a Git repository
:param repo_directory: The directory path of the Git repository where the branch will be created.
:param branch_name: The name of the new branch
"""
os.chdir(repo_directory)
sync_repo_with_copybara.run_command(f"git branch {branch_name}")
@staticmethod
def mock_search(test_name, num_commits, matched_public_commits):
"""
Mock search function to simulate finding matching commits.
:param test_name: The name of the test.
:param num_commits: The number of commits in the repository.
:param matched_public_commits: The number of commits in the public repository that match the private repository with tag 'GitOrigin-RevId'.
:return: True if the last commit in the search result matches the last commit in the public repository, False otherwise.
"""
with tempfile.TemporaryDirectory() as tmpdir:
try:
os.chdir(tmpdir)
mock_10gen_dir = os.path.join(tmpdir, "mock_10gen")
mock_mongodb_dir = os.path.join(tmpdir, "mock_mongodb")
os.mkdir(mock_10gen_dir)
os.mkdir(mock_mongodb_dir)
os.chdir(mock_10gen_dir)
# Create a mock private repository and get all commit hashes
private_hashes = TestBranchFunctions.create_mock_repo_commits(
mock_10gen_dir, num_commits
)
# Create a mock public repository and pass the list of private commit hashes
if matched_public_commits != 0:
public_hashes = TestBranchFunctions.create_mock_repo_commits(
mock_mongodb_dir, matched_public_commits, private_hashes
)
else:
public_hashes = TestBranchFunctions.create_mock_repo_commits(
mock_mongodb_dir, num_commits
)
os.chdir(tmpdir)
result = sync_repo_with_copybara.find_matching_commit(
mock_10gen_dir, mock_mongodb_dir
)
# Check if the commit in the search result matches the last commit in the public repository
if result == public_hashes[-1]:
return True
else:
assert result is None
except Exception as err:
print(f"{test_name}: FAIL!\n Exception occurred: {err}\n {traceback.format_exc()}")
return False
def test_no_search(self):
"""Perform a test where no search is required."""
test_name = "no_search_test"
result = self.mock_search(test_name, 5, 5)
self.assertTrue(result, f"{test_name}: SUCCESS!")
def test_search(self):
"""Perform a test where searching back 5 commits to find the matching commit."""
test_name = "search_test"
result = self.mock_search(test_name, 10, 5)
self.assertTrue(result, f"{test_name}: SUCCESS!")
def test_no_commit_found(self):
"""Perform a test where no matching commit is found."""
test_name = "no_commit_found_test"
result = self.mock_search(test_name, 2, 0)
self.assertIsNone(result, f"{test_name}: SUCCESS!")
def test_prefers_newest_destination_commit_for_duplicate_origin_rev_id(self):
with tempfile.TemporaryDirectory() as tmpdir:
source_dir = os.path.join(tmpdir, "source")
destination_dir = os.path.join(tmpdir, "destination")
os.mkdir(source_dir)
os.mkdir(destination_dir)
private_hashes = TestBranchFunctions.create_mock_repo_commits(source_dir, 1)
public_hashes = TestBranchFunctions.create_mock_repo_commits(
destination_dir,
2,
[private_hashes[0], private_hashes[0]],
)
result = sync_repo_with_copybara.find_matching_commit(source_dir, destination_dir)
self.assertEqual(result, public_hashes[-1])
def test_find_matching_commit_pair_returns_source_and_destination(self):
with tempfile.TemporaryDirectory() as tmpdir:
source_dir = os.path.join(tmpdir, "source")
destination_dir = os.path.join(tmpdir, "destination")
os.mkdir(source_dir)
os.mkdir(destination_dir)
private_hashes = TestBranchFunctions.create_mock_repo_commits(source_dir, 3)
public_hashes = TestBranchFunctions.create_mock_repo_commits(
destination_dir,
2,
[private_hashes[0], private_hashes[1]],
)
result = sync_repo_with_copybara.find_matching_commit_pair(source_dir, destination_dir)
self.assertEqual(
result,
sync_repo_with_copybara.MatchingCommit(
source_commit=private_hashes[1],
destination_commit=public_hashes[-1],
),
)
def test_branch_exists(self):
"""Perform a test to check that the branch exists in a repository."""
test_name = "branch_exists_test"
branch = "v0.0"
with tempfile.TemporaryDirectory() as tmpdir:
remote_repo_dir = os.path.join(tmpdir, "remote_repo")
os.mkdir(remote_repo_dir)
self.create_mock_repo_commits(remote_repo_dir, 1)
self.create_repo_branch(remote_repo_dir, branch)
copybara_config = sync_repo_with_copybara.CopybaraConfig(
source=None,
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url=remote_repo_dir,
branch=branch,
),
)
result = sync_repo_with_copybara.check_destination_branch_exists(copybara_config)
self.assertTrue(result, f"{test_name}: SUCCESS!")
def test_branch_not_exists(self):
"""Perform a test to check that the branch does not exist in a repository."""
test_name = "branch_not_exists_test"
branch = "..invalid-therefore-impossible-to-create-branch-name"
with tempfile.TemporaryDirectory() as tmpdir:
remote_repo_dir = os.path.join(tmpdir, "remote_repo")
os.mkdir(remote_repo_dir)
self.create_mock_repo_commits(remote_repo_dir, 1)
copybara_config = sync_repo_with_copybara.CopybaraConfig(
source=None,
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url=remote_repo_dir,
branch=branch,
),
)
result = sync_repo_with_copybara.check_destination_branch_exists(copybara_config)
self.assertFalse(result, f"{test_name}: SUCCESS!")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_branch_exists_remote_requires_exact_branch_match(self, mock_run_command):
mock_run_command.return_value = "\n".join(
[
"08995ea824ba2492ba1e496a2fb58e80ea2d22c3\trefs/heads/markbenvenuto/master",
"b4dbdfd07f20ec4e0f4873bff4059073c9da62c4\trefs/heads/sql/master",
]
)
self.assertFalse(
sync_repo_with_copybara.branch_exists_remote("https://example.com/source.git", "master")
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_get_remote_branch_head_prefers_exact_branch_match(self, mock_run_command):
mock_run_command.return_value = "\n".join(
[
"08995ea824ba2492ba1e496a2fb58e80ea2d22c3\trefs/heads/markbenvenuto/master",
"78efcf74c13378efe35e4e49fdf7cf0c9206af56\trefs/heads/master",
"b4dbdfd07f20ec4e0f4873bff4059073c9da62c4\trefs/heads/sql/master",
]
)
self.assertEqual(
sync_repo_with_copybara.get_remote_branch_head(
"https://example.com/source.git", "master"
),
"78efcf74c13378efe35e4e49fdf7cf0c9206af56",
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_check_destination_branch_exists_requires_exact_branch_match(self, mock_run_command):
mock_run_command.return_value = "\n".join(
[
"08995ea824ba2492ba1e496a2fb58e80ea2d22c3\trefs/heads/markbenvenuto/master",
"b4dbdfd07f20ec4e0f4873bff4059073c9da62c4\trefs/heads/sql/master",
]
)
self.assertFalse(
sync_repo_with_copybara.check_destination_branch_exists(
sync_repo_with_copybara.CopybaraConfig(
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="https://example.com/destination.git",
branch="master",
)
)
)
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_check_destination_branch_exists_accepts_exact_branch_match(self, mock_run_command):
mock_run_command.return_value = "\n".join(
[
"78efcf74c13378efe35e4e49fdf7cf0c9206af56\trefs/heads/master",
"b4dbdfd07f20ec4e0f4873bff4059073c9da62c4\trefs/heads/sql/master",
]
)
self.assertTrue(
sync_repo_with_copybara.check_destination_branch_exists(
sync_repo_with_copybara.CopybaraConfig(
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="https://example.com/destination.git",
branch="master",
)
)
)
)
def test_only_mongodb_mongo_repo(self):
"""Perform a test that the repository is only the MongoDB official repository."""
test_name = "only_mongodb_mongo_repo_test"
# Define the content for the Git configuration file
config_content = "blalla\n"
config_content += "url = git@github.com:mongodb/mongo.git "
with tempfile.TemporaryDirectory() as tmpdir:
mongodb_mongo_dir = os.path.join(tmpdir, "mock_mongodb_mongo_repo")
# Create Git configuration file
self.create_mock_repo_git_config(mongodb_mongo_dir, config_content)
os.chdir(mongodb_mongo_dir)
try:
# Check if the repository is only the MongoDB official repository
result = sync_repo_with_copybara.has_only_destination_repo_remote("mongodb/mongo")
except Exception as err:
print(f"{test_name}: FAIL!\n Exception occurred: {err}\n {traceback.format_exc()}")
self.fail(f"{test_name}: FAIL!")
return
self.assertTrue(result, f"{test_name}: SUCCESS!")
def test_not_only_mongodb_mongo_repo(self):
"""Perform a test that the repository is not only the MongoDB official repository."""
test_name = "not_only_mongodb_mongo_repo_test"
# Define the content for the Git configuration file
config_content = "blalla\n"
config_content += "url = git@github.com:mongodb/mongo.git "
config_content += "url = git@github.com:10gen/mongo.git "
with tempfile.TemporaryDirectory() as tmpdir:
mongodb_mongo_dir = os.path.join(tmpdir, "mock_mongodb_mongo_repo")
# Create Git configuration file with provided content
self.create_mock_repo_git_config(mongodb_mongo_dir, config_content)
try:
# Call function to push branch to public repository, expecting an exception
sync_repo_with_copybara.push_branch_to_destination_repo(
mongodb_mongo_dir,
copybara_config=sync_repo_with_copybara.CopybaraConfig(
source=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="",
repo_name="",
branch="",
),
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="",
repo_name="",
branch="",
),
),
branching_off_commit="",
)
except Exception as err:
if (
str(err)
== f"{mongodb_mongo_dir} git repo has not only the destination repo remote"
):
return
self.fail(f"{test_name}: FAIL!")
def test_new_branch_commits_not_match_branching_off_commit(self):
"""Perform a test that the new branch commits do not match the branching off commit."""
test_name = "new_branch_commits_not_match_branching_off_commit_test"
# Define the content for the Git configuration file
config_content = "blalla\n"
config_content += "url = git@github.com:mongodb/mongo.git "
# Define a invalid branching off commit
invalid_branching_off_commit = "123456789"
with tempfile.TemporaryDirectory() as tmpdir:
mongodb_mongo_dir = os.path.join(tmpdir, "mock_mongodb_mongo_repo")
# Create Git configuration file with provided content
self.create_mock_repo_git_config(mongodb_mongo_dir, config_content)
os.chdir(mongodb_mongo_dir)
# Create some mock commits in the repository
self.create_mock_repo_commits(mongodb_mongo_dir, 2)
try:
# Call function to push branch to public repository, expecting an exception
sync_repo_with_copybara.push_branch_to_destination_repo(
mongodb_mongo_dir,
sync_repo_with_copybara.CopybaraConfig(
source=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="",
repo_name="",
branch="",
),
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="",
repo_name="",
branch="",
),
),
invalid_branching_off_commit,
)
except Exception as err:
if (
str(err)
== "The new branch top commit does not match the branching_off_commit. Aborting push."
):
return
self.fail(f"{test_name}: FAIL!")
class TestReleaseTagHelpers(unittest.TestCase):
def test_parse_release_tag_request_maps_public_branch(self):
self.assertEqual(
sync_repo_with_copybara.parse_release_tag_request("r8.2.7"),
sync_repo_with_copybara.ReleaseTagRequest(
release_tag="r8.2.7",
public_branch="v8.2.7",
),
)
def test_parse_release_tag_request_preserves_suffix_in_public_branch(self):
self.assertEqual(
sync_repo_with_copybara.parse_release_tag_request("r8.2.7-hotfix"),
sync_repo_with_copybara.ReleaseTagRequest(
release_tag="r8.2.7-hotfix",
public_branch="v8.2.7-hotfix",
),
)
def test_parse_release_tag_request_rejects_invalid_format(self):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.parse_release_tag_request("r8.2")
def test_prepared_copybara_workflow_name_prefers_release_tag(self):
self.assertEqual(
sync_repo_with_copybara.get_prepared_copybara_workflow_name(
"prod", "v8.2.7-hotfix", "r8.2.7-hotfix"
),
"prod_r8.2.7-hotfix",
)
def test_prepared_copybara_workflow_name_uses_branch_without_release_tag(self):
self.assertEqual(
sync_repo_with_copybara.get_prepared_copybara_workflow_name("prod", "v8.2"),
"prod_v8.2",
)
def test_parse_remote_tag_commit_prefers_exact_peeled_match(self):
output = "\n".join(
[
"1111111111111111111111111111111111111111\trefs/tags/r8.2.70",
"2222222222222222222222222222222222222222\trefs/tags/r8.2.7",
"3333333333333333333333333333333333333333\trefs/tags/r8.2.7^{}",
]
)
self.assertEqual(
sync_repo_with_copybara.parse_remote_tag_commit(output, "r8.2.7"),
"3333333333333333333333333333333333333333",
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_tag_exists_remote_requires_exact_tag_match(self, mock_run_command):
mock_run_command.return_value = (
"1111111111111111111111111111111111111111\trefs/tags/r8.2.70\n"
"2222222222222222222222222222222222222222\trefs/tags/r8.2.7-hotfix"
)
self.assertFalse(
sync_repo_with_copybara.tag_exists_remote("https://example.com/public.git", "r8.2.7")
)
def test_resolve_requested_release_tag_branches_creates_synthetic_fragment(self):
with tempfile.TemporaryDirectory() as tmpdir:
branch_to_fragment = {"master": Path("master.sky")}
requested_branches, release_requests = (
sync_repo_with_copybara.resolve_requested_release_tag_branches(
requested_branches="master, r8.2.7",
branch_to_fragment=branch_to_fragment,
bundle_dir=Path(tmpdir),
)
)
self.assertEqual(requested_branches, "master,v8.2.7")
self.assertEqual(
release_requests,
{
"v8.2.7": sync_repo_with_copybara.ReleaseTagRequest(
release_tag="r8.2.7",
public_branch="v8.2.7",
)
},
)
synthetic_fragment = branch_to_fragment["v8.2.7"]
self.assertTrue(synthetic_fragment.is_file())
self.assertIn('sync_tag("r8.2.7")', synthetic_fragment.read_text())
def test_resolve_requested_release_tag_branches_preserves_suffix(self):
with tempfile.TemporaryDirectory() as tmpdir:
branch_to_fragment = {"master": Path("master.sky")}
requested_branches, release_requests = (
sync_repo_with_copybara.resolve_requested_release_tag_branches(
requested_branches="r8.2.7-hotfix",
branch_to_fragment=branch_to_fragment,
bundle_dir=Path(tmpdir),
)
)
self.assertEqual(requested_branches, "v8.2.7-hotfix")
self.assertEqual(
release_requests,
{
"v8.2.7-hotfix": sync_repo_with_copybara.ReleaseTagRequest(
release_tag="r8.2.7-hotfix",
public_branch="v8.2.7-hotfix",
)
},
)
self.assertIn(
'sync_tag("r8.2.7-hotfix")',
branch_to_fragment["v8.2.7-hotfix"].read_text(),
)
def test_extract_release_tags_from_fragment_reads_sync_tag(self):
with tempfile.TemporaryDirectory() as tmpdir:
fragment_path = Path(tmpdir) / "release_tag.sky"
fragment_path.write_text('sync_tag("r8.2.7-hotfix")\n')
self.assertEqual(
sync_repo_with_copybara.extract_release_tags_from_fragment(fragment_path),
["r8.2.7-hotfix"],
)
def test_extract_branches_from_fragment_rejects_release_tag_as_branch(self):
with tempfile.TemporaryDirectory() as tmpdir:
fragment_path = Path(tmpdir) / "bad_branch.sky"
fragment_path.write_text('sync_branch("r8.2.7")\n')
with self.assertRaises(SystemExit):
sync_repo_with_copybara.extract_branches_from_fragment(fragment_path)
def test_extract_release_tags_from_fragment_rejects_branch_as_release_tag(self):
with tempfile.TemporaryDirectory() as tmpdir:
fragment_path = Path(tmpdir) / "bad_tag.sky"
fragment_path.write_text('sync_tag("v8.2")\n')
with self.assertRaises(SystemExit):
sync_repo_with_copybara.extract_release_tags_from_fragment(fragment_path)
def write_base_copybara_config(
path: Path,
common_patterns: list[str] | None = None,
common_includes: list[str] | None = None,
source_url: str = sync_repo_with_copybara.SOURCE_REPO_URL,
prod_url: str = sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL,
test_url: str = sync_repo_with_copybara.TEST_REPO_URL,
) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
if common_patterns is None:
common_patterns = list(DEFAULT_COMMON_EXCLUDED_PATTERNS)
if common_includes is None:
common_includes = ["**"]
include_entries = "\n".join(f' "{pattern}",' for pattern in common_includes)
exclude_entries = "\n".join(f' "{pattern}",' for pattern in common_patterns)
path.write_text(
f'source_url = "{source_url}"\n'
f'prod_url = "{prod_url}"\n'
f'test_url = "{test_url}"\n'
f'test_branch_prefix = "{sync_repo_with_copybara.DEFAULT_TEST_BRANCH_PREFIX}"\n'
f'test_workflow_base_branch = ""\n'
f'test_workflow_source_branch = ""\n'
f"source_refs = {{}}\n"
f"\n"
f"common_files_to_include = [\n"
f"{include_entries}\n"
f"]\n"
f"\n"
f"common_files_to_exclude = [\n"
f"{exclude_entries}\n"
f"]\n"
f"\n"
f"def make_workflow(\n"
f" workflow_name,\n"
f" destination_url,\n"
f" source_ref,\n"
f" destination_ref,\n"
f"):\n"
f" pass\n"
f"\n"
f"def sync_branch(branch_name):\n"
f" source_ref = source_refs.get(branch_name, branch_name)\n"
f' make_workflow("prod_" + branch_name, prod_url, source_ref, branch_name)\n'
f" make_workflow(\n"
f' "test_" + branch_name,\n'
f" test_url,\n"
f" source_ref,\n"
f' test_branch_prefix + "_" + branch_name,\n'
f" )\n"
)
class TestSkyExclusionChecks(unittest.TestCase):
def test_extract_sky_excluded_patterns(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
patterns = sync_repo_with_copybara.extract_sky_excluded_patterns(str(sky_path))
self.assertIn("src/mongo/db/modules/**", patterns)
self.assertIn("AGENTS.md", patterns)
def test_extract_sky_excluded_patterns_prefers_adjacent_path_rules(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
sky_path.write_text('common_files_to_exclude = ["ignored/**"]\n')
write_copybara_path_rules(
sky_path.with_name("copybara_path_rules.json"),
common_includes=DEFAULT_TEST_COPYBARA_PATH_RULES_INCLUDES,
common_excludes=["src/authoritative/**"],
)
patterns = sync_repo_with_copybara.extract_sky_excluded_patterns(str(sky_path))
self.assertEqual(patterns, {"src/authoritative/**"})
def test_get_preview_excluded_patterns_includes_common_exclusions(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_patterns=DEFAULT_COMMON_EXCLUDED_PATTERNS + ["docs/private-notes/**"],
)
sky_path.write_text(sky_path.read_text() + '\nsync_branch("master")\n')
patterns = sync_repo_with_copybara.get_preview_excluded_patterns(
str(sky_path), "master"
)
self.assertIn("docs/private-notes/**", patterns)
self.assertIn("AGENTS.md", patterns)
def test_get_preview_excluded_patterns_includes_branch_specific_additions(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
sky_path.write_text(
sky_path.read_text()
+ '\nrelease_files_to_exclude = [\n "docs/private-notes/**",\n]\n'
+ 'sync_branch("v8.2", release_files_to_exclude)\n'
)
patterns = sync_repo_with_copybara.get_preview_excluded_patterns(str(sky_path), "v8.2")
self.assertIn("docs/private-notes/**", patterns)
self.assertIn("AGENTS.md", patterns)
def test_get_preview_excluded_patterns_deduplicates_common_and_branch_exclusions(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_patterns=["AGENTS.md", "internal/"],
)
sky_path.write_text(
sky_path.read_text()
+ '\nrelease_files_to_exclude = [\n "internal/",\n "private/**",\n]\n'
+ 'sync_branch("v8.2", release_files_to_exclude)\n'
)
patterns = sync_repo_with_copybara.get_preview_excluded_patterns(str(sky_path), "v8.2")
self.assertEqual(patterns, ["AGENTS.md", "internal/", "private/**"])
def test_extract_branch_public_patterns_defaults_to_all_files(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
sky_path.write_text(sky_path.read_text() + '\nsync_branch("master")\n')
patterns = sync_repo_with_copybara.extract_branch_public_patterns(
str(sky_path), "master"
)
self.assertEqual(patterns, {"**"})
def test_extract_branch_public_patterns_from_common_list(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_includes=["README.md", "docs/**"],
)
sky_path.write_text(sky_path.read_text() + '\nsync_branch("master")\n')
patterns = sync_repo_with_copybara.extract_branch_public_patterns(
str(sky_path), "master"
)
self.assertEqual(patterns, {"README.md", "docs/**"})
def test_extract_branch_public_patterns_supports_sync_tag(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_includes=["README.md", "docs/**"],
)
sky_path.write_text(sky_path.read_text() + '\nsync_tag("r8.2.7")\n')
patterns = sync_repo_with_copybara.extract_branch_public_patterns(
str(sky_path), "v8.2.7"
)
self.assertEqual(patterns, {"README.md", "docs/**"})
def test_extract_branch_public_patterns_ignores_branch_exclusions_only(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_patterns=["AGENTS.md", "internal/**"],
common_includes=["src/", "buildscripts/", "jstests/**"],
)
sky_path.write_text(
sky_path.read_text()
+ '\nrelease_exclusions = [\n "private/**",\n "secrets/**",\n]\n'
+ 'sync_branch("v8.2", release_exclusions)\n'
)
patterns = sync_repo_with_copybara.extract_branch_public_patterns(str(sky_path), "v8.2")
self.assertEqual(patterns, {"src/", "buildscripts/", "jstests/**"})
def test_extract_branch_public_patterns_prefers_adjacent_path_rules(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
sky_path.write_text(
'common_files_to_include = ["ignored/**"]\n' + '\nsync_branch("master")\n'
)
write_copybara_path_rules(
sky_path.with_name("copybara_path_rules.json"),
common_excludes=DEFAULT_TEST_COPYBARA_PATH_RULES_EXCLUDES,
common_includes=["README.md", "docs/**"],
)
patterns = sync_repo_with_copybara.extract_branch_public_patterns(
str(sky_path), "master"
)
self.assertEqual(patterns, {"README.md", "docs/**"})
def test_extract_branch_public_patterns_from_named_list(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
sky_path.write_text(
sky_path.read_text()
+ '\nmaster_public_files = [\n "README.md",\n "docs/**",\n]\n'
+ 'sync_branch("master", [], master_public_files)\n'
)
patterns = sync_repo_with_copybara.extract_branch_public_patterns(
str(sky_path), "master"
)
self.assertEqual(patterns, {"README.md", "docs/**"})
def test_check_branch_top_level_paths_are_labeled_passes(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_includes=["README.md", "docs/**"],
)
sky_path.write_text(sky_path.read_text() + '\nsync_branch("master")\n')
sync_repo_with_copybara.check_branch_top_level_paths_are_labeled(
str(sky_path),
"master",
{"README.md", "docs", "monguard", "sbom.private.json"},
)
def test_check_branch_top_level_paths_are_labeled_supports_sync_tag(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_includes=["README.md", "docs/**"],
)
sky_path.write_text(sky_path.read_text() + '\nsync_tag("r8.2.7")\n')
sync_repo_with_copybara.check_branch_top_level_paths_are_labeled(
str(sky_path),
"v8.2.7",
{"README.md", "docs", "monguard", "sbom.private.json"},
)
def test_check_branch_top_level_paths_are_labeled_fails_for_unlabeled_path(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
sky_path,
common_includes=["README.md", "docs/**"],
)
sky_path.write_text(sky_path.read_text() + '\nsync_branch("master")\n')
with self.assertRaises(SystemExit):
sync_repo_with_copybara.check_branch_top_level_paths_are_labeled(
str(sky_path),
"master",
{"README.md", "docs", "src"},
)
class TestCopybaraConfigHelpers(unittest.TestCase):
def test_build_copybara_config_uses_test_branch_prefix(self):
config = sync_repo_with_copybara.build_copybara_config(
workflow="test",
branch="v8.2",
source_ref="deadbeef123",
test_branch_prefix="copybara_test_branch_patch123",
)
self.assertEqual(config.source.branch, "v8.2")
self.assertEqual(config.source.ref, "deadbeef123")
self.assertEqual(config.destination.branch, "copybara_test_branch_patch123_v8.2")
self.assertEqual(config.destination.repo_name, sync_repo_with_copybara.TEST_REPO_NAME)
@patch("buildscripts.copybara.sync_repo_with_copybara.get_installation_access_token")
def test_get_copybara_tokens_uses_master_sync_public_app_expansion(
self, mock_get_installation_access_token
):
expansions = {
"app_id_copybara_syncer_master_sync": "101",
"private_key_copybara_syncer": "public-private-key",
"installation_id_copybara_syncer": "202",
"app_id_copybara_syncer_10gen": "303",
"private_key_copybara_syncer_10gen": "private-private-key",
"installation_id_copybara_syncer_10gen": "404",
}
mock_get_installation_access_token.side_effect = ["public-token", "private-token"]
tokens = sync_repo_with_copybara.get_copybara_tokens(expansions)
self.assertEqual(
mock_get_installation_access_token.call_args_list,
[
call(101, "public-private-key", 202),
call(303, "private-private-key", 404),
],
)
self.assertEqual(
tokens,
{
sync_repo_with_copybara.SOURCE_REPO_URL: "private-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "public-token",
sync_repo_with_copybara.TEST_REPO_URL: "private-token",
},
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_list_copybara_fragment_paths_excludes_base_config(self, mock_run_command):
mock_run_command.return_value = "\n".join(
[
sync_repo_with_copybara.COPYBARA_BASE_CONFIG_PATH.as_posix(),
sync_repo_with_copybara.COPYBARA_PATH_RULES_MODULE_PATH.as_posix(),
"buildscripts/copybara/master.sky",
"buildscripts/copybara/v8_2.sky",
]
)
fragment_paths = sync_repo_with_copybara.list_copybara_fragment_paths(
Path("/tmp/fetch"),
sync_repo_with_copybara.COPYBARA_CONFIG_FETCH_REF,
)
self.assertEqual(
fragment_paths,
["buildscripts/copybara/master.sky", "buildscripts/copybara/v8_2.sky"],
)
def test_discover_copybara_branches_reads_fragments(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
write_base_copybara_config(get_repo_base_copybara_config_path(root))
write_copybara_path_rules(
get_repo_copybara_path_rules_path(root),
common_includes=DEFAULT_TEST_COPYBARA_PATH_RULES_INCLUDES,
common_excludes=DEFAULT_TEST_COPYBARA_PATH_RULES_EXCLUDES,
)
write_copybara_path_rules_module(
get_repo_copybara_path_rules_module_path(root),
get_repo_copybara_path_rules_path(root),
)
fragment_dir = root / "buildscripts" / "copybara"
fragment_dir.mkdir(parents=True, exist_ok=True)
(fragment_dir / "master.sky").write_text('sync_branch("master")\n')
(fragment_dir / "v8_2.sky").write_text(
'sync_branch("v8.2")\n' 'sync_branch("v8.2.6-hotfix")\n'
)
(fragment_dir / "v8_2_7_tag.sky").write_text('sync_tag("r8.2.7")\n')
branch_to_fragment = sync_repo_with_copybara.discover_copybara_branches(tmpdir)
self.assertEqual(branch_to_fragment["master"], fragment_dir / "master.sky")
self.assertEqual(branch_to_fragment["v8.2"], fragment_dir / "v8_2.sky")
self.assertEqual(branch_to_fragment["v8.2.6-hotfix"], fragment_dir / "v8_2.sky")
self.assertNotIn("v8.2.7", branch_to_fragment)
def test_resolve_requested_branches_preserves_user_order(self):
branch_to_fragment = {
"master": Path("master.sky"),
"v8.0": Path("v8_0.sky"),
"v8.2": Path("v8_2.sky"),
}
selected = sync_repo_with_copybara.resolve_requested_branches(
"v8.2, master, v8.2", branch_to_fragment
)
self.assertEqual(selected, ["v8.2", "master"])
def test_prepare_branch_sync_for_test_workflow_generates_branch_specific_config(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
base_config_path = get_repo_base_copybara_config_path(root)
write_base_copybara_config(base_config_path)
path_rules_path = get_repo_copybara_path_rules_path(root)
write_copybara_path_rules(
path_rules_path,
common_includes=DEFAULT_TEST_COPYBARA_PATH_RULES_INCLUDES,
common_excludes=DEFAULT_TEST_COPYBARA_PATH_RULES_EXCLUDES,
)
path_rules_module_path = get_repo_copybara_path_rules_module_path(root)
write_copybara_path_rules_module(path_rules_module_path, path_rules_path)
fragment_dir = root / "buildscripts" / "copybara"
fragment_dir.mkdir(parents=True, exist_ok=True)
fragment_path = fragment_dir / "v8_2.sky"
fragment_path.write_text('sync_branch("v8.2")\n')
config_bundle = sync_repo_with_copybara.CopybaraConfigBundle(
config_sha="configsha123",
bundle_dir=root,
base_config_path=base_config_path,
path_rules_path=path_rules_path,
path_rules_module_path=path_rules_module_path,
branch_to_fragment={"v8.2": fragment_path},
)
test_baseline = sync_repo_with_copybara.TestWorkflowBaseline(
source_last_rev="feedface123",
destination_base_revision="publicdeadbeef456",
public_branch="v8.2",
)
stdout = io.StringIO()
with redirect_stdout(stdout):
prepared = sync_repo_with_copybara.prepare_branch_sync(
current_dir=tmpdir,
workflow="test",
branch="v8.2",
source_ref="deadbeef123",
config_bundle=config_bundle,
fragment_path=fragment_path,
tokens_map={
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
},
test_branch_prefix="copybara_test_branch_patch123",
test_baseline=test_baseline,
)
log_output = stdout.getvalue()
self.assertTrue(prepared.config_file.with_name("copybara_path_rules.json").is_file())
self.assertTrue(
prepared.config_file.with_name("copybara_path_rules.bara.sky").is_file()
)
generated_config = prepared.config_file.read_text()
expected_test_branch = "copybara_test_branch_patch123_v8.2"
self.assertIn('sync_branch("v8.2")', generated_config)
self.assertIn('test_branch_prefix = "copybara_test_branch_patch123"', generated_config)
self.assertIn(f'source_refs = {{"v8.2": "{expected_test_branch}"}}', generated_config)
self.assertEqual(prepared.source_ref, expected_test_branch)
self.assertEqual(prepared.config_sha, "configsha123")
self.assertEqual(prepared.workflow_name, "test_v8.2")
self.assertEqual(prepared.copybara_config.source.branch, expected_test_branch)
self.assertEqual(prepared.copybara_config.source.ref, expected_test_branch)
self.assertEqual(prepared.copybara_config.destination.branch, expected_test_branch)
self.assertEqual(prepared.last_rev, "feedface123")
self.assertEqual(prepared.test_baseline, test_baseline)
self.assertEqual(
prepared.dry_run_args,
("--init-history", "--last-rev=feedface123"),
)
self.assertIn(f"{prepared.config_file.parent}:/usr/src/app", prepared.docker_command)
self.assertNotIn(
f"{prepared.config_file}:/usr/src/app/copy.bara.sky", prepared.docker_command
)
self.assertIn("[v8.2] BEGIN generated Copybara config:", log_output)
self.assertIn("[v8.2] BEGIN generated Copybara path rules module:", log_output)
self.assertIn(
'source_url = "https://x-access-token:<REDACTED>@github.com/10gen/mongo.git"',
log_output,
)
self.assertIn("common_files_to_exclude = [", log_output)
self.assertIn('"src/mongo/db/modules/**"', log_output)
self.assertNotIn("source-token", log_output)
self.assertNotIn("prod-token", log_output)
self.assertNotIn("test-token", log_output)
@patch("buildscripts.copybara.sync_repo_with_copybara.check_destination_branch_exists")
def test_prepare_branch_sync_for_prod_workflow_uses_configured_prod_destination(
self, mock_check_destination_branch_exists
):
mock_check_destination_branch_exists.return_value = True
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
base_config_path = get_repo_base_copybara_config_path(root)
write_base_copybara_config(
base_config_path,
prod_url=sync_repo_with_copybara.TEST_REPO_URL,
)
path_rules_path = get_repo_copybara_path_rules_path(root)
write_copybara_path_rules(
path_rules_path,
common_includes=DEFAULT_TEST_COPYBARA_PATH_RULES_INCLUDES,
common_excludes=DEFAULT_TEST_COPYBARA_PATH_RULES_EXCLUDES,
)
path_rules_module_path = get_repo_copybara_path_rules_module_path(root)
write_copybara_path_rules_module(path_rules_module_path, path_rules_path)
fragment_dir = root / "buildscripts" / "copybara"
fragment_dir.mkdir(parents=True, exist_ok=True)
fragment_path = fragment_dir / "v8_2.sky"
fragment_path.write_text('sync_branch("v8.2")\n')
config_bundle = sync_repo_with_copybara.CopybaraConfigBundle(
config_sha="configsha123",
bundle_dir=root,
base_config_path=base_config_path,
path_rules_path=path_rules_path,
path_rules_module_path=path_rules_module_path,
branch_to_fragment={"v8.2": fragment_path},
)
prepared = sync_repo_with_copybara.prepare_branch_sync(
current_dir=tmpdir,
workflow="prod",
branch="v8.2",
source_ref="deadbeef123",
config_bundle=config_bundle,
fragment_path=fragment_path,
tokens_map={
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
},
test_branch_prefix="copybara_test_branch_patch123",
)
self.assertEqual(
prepared.copybara_config.destination.git_url,
"https://x-access-token:test-token@github.com/10gen/mongo-copybara.git",
)
self.assertEqual(
prepared.copybara_config.destination.repo_name,
sync_repo_with_copybara.TEST_REPO_NAME,
)
mock_check_destination_branch_exists.assert_called_once_with(prepared.copybara_config)
class TestCopybaraConfigAndTestWorkflowHelpers(unittest.TestCase):
def test_get_test_workflow_base_branch_override_reads_sky_variable(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
sky_path.write_text(
sky_path.read_text().replace(
'test_workflow_base_branch = ""',
'test_workflow_base_branch = " v8.2 "',
)
)
self.assertEqual(
sync_repo_with_copybara.get_test_workflow_base_branch_override(sky_path),
"v8.2",
)
def test_get_test_workflow_base_branch_override_defaults_to_none(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
self.assertIsNone(
sync_repo_with_copybara.get_test_workflow_base_branch_override(sky_path)
)
def test_resolve_test_workflow_requested_branches_prefers_base_branch_override(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
sky_path.write_text(
sky_path.read_text().replace(
'test_workflow_base_branch = ""',
'test_workflow_base_branch = "v8.2"',
)
)
requested, override = sync_repo_with_copybara.resolve_test_workflow_requested_branches(
"master",
sky_path,
)
self.assertEqual(requested, "v8.2")
self.assertEqual(override, "v8.2")
def test_resolve_test_workflow_requested_branches_defaults_to_requested_branches(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
requested, override = sync_repo_with_copybara.resolve_test_workflow_requested_branches(
"master",
sky_path,
)
self.assertEqual(requested, "master")
self.assertIsNone(override)
def test_get_test_workflow_source_branch_override_reads_sky_variable(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
sky_path.write_text(
sky_path.read_text().replace(
'test_workflow_source_branch = ""',
'test_workflow_source_branch = " daniel.moody/8.3_test_branch "',
)
)
self.assertEqual(
sync_repo_with_copybara.get_test_workflow_source_branch_override(sky_path),
"daniel.moody/8.3_test_branch",
)
def test_get_test_workflow_source_branch_override_defaults_to_none(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
self.assertIsNone(
sync_repo_with_copybara.get_test_workflow_source_branch_override(sky_path)
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_list_untracked_paths_skips_untracked_directories(self, mock_run_command):
with tempfile.TemporaryDirectory() as tmpdir:
repo_dir = Path(tmpdir)
(repo_dir / "new.txt").write_text("new")
(repo_dir / "copybara").mkdir()
mock_run_command.return_value = "new.txt\0copybara\0"
untracked_paths = sync_repo_with_copybara.list_untracked_paths(repo_dir)
self.assertEqual(untracked_paths, [Path("new.txt")])
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_list_untracked_paths_keeps_symlinked_directories(self, mock_run_command):
if sys.platform == "win32":
self.skipTest("symlink permissions vary on Windows")
with tempfile.TemporaryDirectory() as tmpdir:
repo_dir = Path(tmpdir)
(repo_dir / "target_dir").mkdir()
os.symlink("target_dir", repo_dir / "linked_dir")
mock_run_command.return_value = "linked_dir\0"
untracked_paths = sync_repo_with_copybara.list_untracked_paths(repo_dir)
self.assertEqual(untracked_paths, [Path("linked_dir")])
def test_filter_untracked_paths_for_test_source_skips_task_generated_paths(self):
filtered_paths = sync_repo_with_copybara.filter_untracked_paths_for_test_source(
[
Path(".evergreen.yml"),
Path("tmp_copybara/config_bundle/copy.bara.sky"),
Path("new.txt"),
Path("buildscripts/new_copybara_fragment.sky"),
]
)
self.assertEqual(
filtered_paths,
[
Path("new.txt"),
Path("buildscripts/new_copybara_fragment.sky"),
],
)
def test_copy_paths_into_repo_skips_directories(self):
with (
tempfile.TemporaryDirectory() as source_tmpdir,
tempfile.TemporaryDirectory() as dest_tmpdir,
):
source_dir = Path(source_tmpdir)
destination_dir = Path(dest_tmpdir)
(source_dir / "tracked.txt").write_text("tracked")
(source_dir / "copybara").mkdir()
(source_dir / "copybara" / "README.md").write_text("nested repo contents")
sync_repo_with_copybara.copy_paths_into_repo(
source_dir,
destination_dir,
[Path("copybara"), Path("tracked.txt")],
)
self.assertFalse((destination_dir / "copybara").exists())
self.assertEqual((destination_dir / "tracked.txt").read_text(), "tracked")
def test_copy_paths_into_repo_preserves_symlinks(self):
if sys.platform == "win32":
self.skipTest("symlink permissions vary on Windows")
with (
tempfile.TemporaryDirectory() as source_tmpdir,
tempfile.TemporaryDirectory() as dest_tmpdir,
):
source_dir = Path(source_tmpdir)
destination_dir = Path(dest_tmpdir)
(source_dir / "target.txt").write_text("target")
os.symlink("target.txt", source_dir / "linked.txt")
(destination_dir / "linked.txt").write_text("stale")
sync_repo_with_copybara.copy_paths_into_repo(
source_dir,
destination_dir,
[Path("linked.txt")],
)
self.assertTrue((destination_dir / "linked.txt").is_symlink())
self.assertEqual(os.readlink(destination_dir / "linked.txt"), "target.txt")
def test_remove_paths_from_repo_removes_symlinks(self):
if sys.platform == "win32":
self.skipTest("symlink permissions vary on Windows")
with tempfile.TemporaryDirectory() as tmpdir:
repo_dir = Path(tmpdir)
(repo_dir / "target.txt").write_text("target")
os.symlink("target.txt", repo_dir / "linked.txt")
sync_repo_with_copybara.remove_paths_from_repo(repo_dir, [Path("linked.txt")])
self.assertFalse((repo_dir / "linked.txt").exists())
self.assertFalse((repo_dir / "linked.txt").is_symlink())
@patch("buildscripts.copybara.sync_repo_with_copybara.tempfile.mkdtemp")
@patch("buildscripts.copybara.sync_repo_with_copybara.find_matching_commit_pair")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
@patch("buildscripts.copybara.sync_repo_with_copybara.branch_exists_remote")
def test_resolve_test_workflow_baseline_uses_public_branch_when_present(
self,
mock_branch_exists_remote,
mock_run_command,
mock_find_matching_commit_pair,
mock_mkdtemp,
):
mock_branch_exists_remote.return_value = True
public_baseline_dir = Path("/tmp/public-baseline")
mock_mkdtemp.return_value = str(public_baseline_dir)
mock_find_matching_commit_pair.return_value = sync_repo_with_copybara.MatchingCommit(
source_commit="private123",
destination_commit="public456",
)
baseline = sync_repo_with_copybara.resolve_test_workflow_baseline(
current_dir="/repo",
branch="v8.2",
patch_base_revision="deadbeef123",
public_repo_url="https://example.com/public.git",
)
self.assertEqual(
baseline,
sync_repo_with_copybara.TestWorkflowBaseline(
source_last_rev="private123",
destination_base_revision="public456",
public_branch="v8.2",
),
)
mock_run_command.assert_called_once_with(
"git clone --filter=blob:none --no-checkout --single-branch -b v8.2 "
f"https://example.com/public.git {sync_repo_with_copybara.shell_quote(public_baseline_dir)}"
)
mock_find_matching_commit_pair.assert_called_once_with(
"/repo",
str(public_baseline_dir),
source_ref="deadbeef123",
)
@patch("buildscripts.copybara.sync_repo_with_copybara.tempfile.mkdtemp")
@patch("buildscripts.copybara.sync_repo_with_copybara.find_matching_commit_pair")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
@patch("buildscripts.copybara.sync_repo_with_copybara.branch_exists_remote")
def test_resolve_test_workflow_baseline_uses_source_branch_override(
self,
mock_branch_exists_remote,
mock_run_command,
mock_find_matching_commit_pair,
mock_mkdtemp,
):
mock_branch_exists_remote.return_value = True
public_baseline_dir = Path("/tmp/public-baseline")
private_source_dir = Path("/tmp/private-source")
mock_mkdtemp.side_effect = [str(public_baseline_dir), str(private_source_dir)]
mock_find_matching_commit_pair.return_value = sync_repo_with_copybara.MatchingCommit(
source_commit="private123",
destination_commit="public456",
)
baseline = sync_repo_with_copybara.resolve_test_workflow_baseline(
current_dir="/repo",
branch="v8.2",
patch_base_revision="deadbeef123",
public_repo_url="https://example.com/public.git",
source_repo_url="https://example.com/source.git",
test_source_branch="daniel.moody/8.3_test_branch",
)
self.assertEqual(
baseline,
sync_repo_with_copybara.TestWorkflowBaseline(
source_last_rev="private123",
destination_base_revision="public456",
public_branch="v8.2",
),
)
self.assertEqual(
mock_run_command.call_args_list[0].args[0],
"git clone --filter=blob:none --no-checkout --single-branch -b "
"daniel.moody/8.3_test_branch https://example.com/source.git "
f"{sync_repo_with_copybara.shell_quote(private_source_dir)}",
)
self.assertEqual(
mock_run_command.call_args_list[1].args[0],
"git clone --filter=blob:none --no-checkout --single-branch -b v8.2 "
f"https://example.com/public.git {sync_repo_with_copybara.shell_quote(public_baseline_dir)}",
)
mock_find_matching_commit_pair.assert_called_once_with(
str(private_source_dir),
str(public_baseline_dir),
source_ref="HEAD",
)
@patch("buildscripts.copybara.sync_repo_with_copybara.tempfile.mkdtemp")
@patch("buildscripts.copybara.sync_repo_with_copybara.find_matching_commit_pair")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
@patch("buildscripts.copybara.sync_repo_with_copybara.branch_exists_remote")
def test_resolve_test_workflow_baseline_falls_back_to_public_default_branch(
self,
mock_branch_exists_remote,
mock_run_command,
mock_find_matching_commit_pair,
mock_mkdtemp,
):
mock_branch_exists_remote.return_value = False
public_baseline_dir = Path("/tmp/public-baseline")
mock_mkdtemp.return_value = str(public_baseline_dir)
mock_find_matching_commit_pair.return_value = sync_repo_with_copybara.MatchingCommit(
source_commit="private123",
destination_commit="public456",
)
baseline = sync_repo_with_copybara.resolve_test_workflow_baseline(
current_dir="/repo",
branch="v8.2-hotfix",
patch_base_revision="deadbeef123",
public_repo_url="https://example.com/public.git",
)
self.assertEqual(baseline.public_branch, sync_repo_with_copybara.COPYBARA_CONFIG_REF)
mock_run_command.assert_called_once_with(
"git clone --filter=blob:none --no-checkout --single-branch -b master "
f"https://example.com/public.git {sync_repo_with_copybara.shell_quote(public_baseline_dir)}"
)
@patch("buildscripts.copybara.sync_repo_with_copybara.remove_paths_from_repo")
@patch("buildscripts.copybara.sync_repo_with_copybara.copy_paths_into_repo")
@patch("buildscripts.copybara.sync_repo_with_copybara.list_untracked_paths")
@patch("buildscripts.copybara.sync_repo_with_copybara.list_changed_paths_between_refs")
@patch("buildscripts.copybara.sync_repo_with_copybara.tempfile.mkdtemp")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_create_patched_test_source_repo_rebuilds_from_base_revision(
self,
mock_run_command,
mock_mkdtemp,
mock_list_changed_paths_between_refs,
mock_list_untracked_paths,
mock_copy_paths_into_repo,
mock_remove_paths_from_repo,
):
patched_source_dir = Path("/tmp/patched-source")
mock_mkdtemp.return_value = str(patched_source_dir)
mock_list_changed_paths_between_refs.return_value = (
[Path("tracked.txt")],
[Path("deleted.txt")],
)
mock_list_untracked_paths.return_value = [
Path(".evergreen.yml"),
Path("tmp_copybara/config_bundle/copy.bara.sky"),
Path("new.txt"),
]
mock_run_command.side_effect = ["", "", "", "M tracked.txt\n", ""]
result = sync_repo_with_copybara.create_patched_test_source_repo(
"/repo",
"deadbeef123",
"patch123",
)
self.assertEqual(result, patched_source_dir)
mock_list_changed_paths_between_refs.assert_called_once_with("/repo", "deadbeef123")
mock_list_untracked_paths.assert_called_once_with("/repo")
mock_copy_paths_into_repo.assert_called_once_with(
"/repo",
patched_source_dir,
[Path("new.txt"), Path("tracked.txt")],
)
mock_remove_paths_from_repo.assert_called_once_with(
patched_source_dir,
[Path("deleted.txt")],
)
self.assertEqual(
mock_run_command.call_args_list[0].args[0],
"git clone --shared --no-checkout /repo "
f"{sync_repo_with_copybara.shell_quote(patched_source_dir)}",
)
self.assertEqual(
mock_run_command.call_args_list[1].args[0],
"git -C "
f"{sync_repo_with_copybara.shell_quote(patched_source_dir)} "
"checkout --detach deadbeef123",
)
for command_call in mock_run_command.call_args_list:
self.assertNotIn(" apply ", command_call.args[0])
@patch("buildscripts.copybara.sync_repo_with_copybara.tempfile.mkdtemp")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_create_test_source_repo_from_branch_clones_existing_branch(
self,
mock_run_command,
mock_mkdtemp,
):
source_branch_dir = Path("/tmp/source-branch")
mock_mkdtemp.return_value = str(source_branch_dir)
result = sync_repo_with_copybara.create_test_source_repo_from_branch(
"https://example.com/source.git",
"daniel.moody/8.3_test_branch",
)
self.assertEqual(result, source_branch_dir)
mock_run_command.assert_called_once_with(
"git clone --filter=blob:none --no-checkout --single-branch -b "
"daniel.moody/8.3_test_branch https://example.com/source.git "
f"{sync_repo_with_copybara.shell_quote(source_branch_dir)}"
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
@patch("buildscripts.copybara.sync_repo_with_copybara.push_test_destination_branch")
@patch("buildscripts.copybara.sync_repo_with_copybara.branch_exists_remote")
@patch("buildscripts.copybara.sync_repo_with_copybara.create_patched_test_source_repo")
@patch("buildscripts.copybara.sync_repo_with_copybara.is_current_repo_origin")
def test_push_test_branches_pushes_clean_destination_and_patched_source(
self,
mock_is_current_repo_origin,
mock_create_patched_test_source_repo,
mock_branch_exists_remote,
mock_push_test_destination_branch,
mock_run_command,
):
mock_is_current_repo_origin.return_value = True
patched_source_dir = Path("/tmp/patched-source")
mock_create_patched_test_source_repo.return_value = patched_source_dir
mock_branch_exists_remote.return_value = True
test_branch = "copybara_test_branch_patch123_v8.2"
source_url = "https://example.com/source.git"
destination_url = "https://example.com/destination.git"
sync = sync_repo_with_copybara.PreparedBranchSync(
branch="v8.2",
source_ref=test_branch,
config_sha="local",
workflow_name="test_v8.2",
config_file=Path("/tmp/copy.bara.sky"),
preview_dir=Path("/tmp/preview"),
docker_command=("echo",),
copybara_config=sync_repo_with_copybara.CopybaraConfig(
source=sync_repo_with_copybara.CopybaraRepoConfig(
git_url=source_url,
repo_name=sync_repo_with_copybara.SOURCE_REPO_NAME,
branch=test_branch,
ref=test_branch,
),
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url=destination_url,
repo_name=sync_repo_with_copybara.TEST_REPO_NAME,
branch=test_branch,
),
),
last_rev="privatebase123",
test_baseline=sync_repo_with_copybara.TestWorkflowBaseline(
source_last_rev="privatebase123",
destination_base_revision="publicbase456",
public_branch="v8.2",
),
)
sync_repo_with_copybara.push_test_branches(
"/repo",
[sync],
"patch123",
patch_base_revision="deadbeef123",
public_repo_url="https://example.com/public.git",
source_repo_url=source_url,
)
mock_create_patched_test_source_repo.assert_called_once_with(
"/repo",
"deadbeef123",
"patch123",
)
mock_push_test_destination_branch.assert_called_once_with(
public_repo_url="https://example.com/public.git",
public_branch="v8.2",
destination_url=destination_url,
destination_branch=test_branch,
destination_base_revision="publicbase456",
)
mock_run_command.assert_has_calls(
[
call(
"git push "
f"{sync_repo_with_copybara.shell_quote(source_url)} --delete "
f"{sync_repo_with_copybara.shell_quote(test_branch)}"
),
call(
"git push "
f"{sync_repo_with_copybara.shell_quote(destination_url)} --delete "
f"{sync_repo_with_copybara.shell_quote(test_branch)}"
),
call(
f"git -C {sync_repo_with_copybara.shell_quote(patched_source_dir)} push "
f"{sync_repo_with_copybara.shell_quote(source_url)} "
f"{sync_repo_with_copybara.shell_quote(f'HEAD:refs/heads/{test_branch}')}"
),
]
)
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
@patch("buildscripts.copybara.sync_repo_with_copybara.push_test_destination_branch")
@patch("buildscripts.copybara.sync_repo_with_copybara.branch_exists_remote")
@patch("buildscripts.copybara.sync_repo_with_copybara.create_test_source_repo_from_branch")
@patch("buildscripts.copybara.sync_repo_with_copybara.create_patched_test_source_repo")
@patch("buildscripts.copybara.sync_repo_with_copybara.is_current_repo_origin")
def test_push_test_branches_uses_source_branch_override(
self,
mock_is_current_repo_origin,
mock_create_patched_test_source_repo,
mock_create_test_source_repo_from_branch,
mock_branch_exists_remote,
mock_push_test_destination_branch,
mock_run_command,
):
mock_is_current_repo_origin.return_value = True
source_branch_dir = Path("/tmp/source-branch")
mock_create_test_source_repo_from_branch.return_value = source_branch_dir
mock_branch_exists_remote.return_value = True
test_branch = "copybara_test_branch_patch123_v8.2"
source_url = "https://example.com/source.git"
destination_url = "https://example.com/destination.git"
sync = sync_repo_with_copybara.PreparedBranchSync(
branch="v8.2",
source_ref=test_branch,
config_sha="local",
workflow_name="test_v8.2",
config_file=Path("/tmp/copy.bara.sky"),
preview_dir=Path("/tmp/preview"),
docker_command=("echo",),
copybara_config=sync_repo_with_copybara.CopybaraConfig(
source=sync_repo_with_copybara.CopybaraRepoConfig(
git_url=source_url,
repo_name=sync_repo_with_copybara.SOURCE_REPO_NAME,
branch=test_branch,
ref=test_branch,
),
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url=destination_url,
repo_name=sync_repo_with_copybara.TEST_REPO_NAME,
branch=test_branch,
),
),
last_rev="privatebase123",
test_baseline=sync_repo_with_copybara.TestWorkflowBaseline(
source_last_rev="privatebase123",
destination_base_revision="publicbase456",
public_branch="v8.2",
),
)
sync_repo_with_copybara.push_test_branches(
"/repo",
[sync],
"patch123",
patch_base_revision="deadbeef123",
public_repo_url="https://example.com/public.git",
source_repo_url=source_url,
test_source_branch="daniel.moody/8.3_test_branch",
)
mock_create_patched_test_source_repo.assert_not_called()
mock_create_test_source_repo_from_branch.assert_called_once_with(
source_url,
"daniel.moody/8.3_test_branch",
)
mock_push_test_destination_branch.assert_called_once()
self.assertEqual(
mock_run_command.call_args_list[-1].args[0],
f"git -C {sync_repo_with_copybara.shell_quote(source_branch_dir)} push "
f"{sync_repo_with_copybara.shell_quote(source_url)} "
f"{sync_repo_with_copybara.shell_quote(f'HEAD:refs/heads/{test_branch}')}",
)
class TestMainWorkflow(unittest.TestCase):
@patch(
"buildscripts.copybara.sync_repo_with_copybara.ensure_generated_copybara_evergreen_is_current"
)
@patch("buildscripts.copybara.sync_repo_with_copybara.handle_failure")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_branch_migrate")
@patch("buildscripts.copybara.sync_repo_with_copybara.rewrite_copybara_config")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_branch_dry_run")
@patch("buildscripts.copybara.sync_repo_with_copybara.push_test_branches")
@patch("buildscripts.copybara.sync_repo_with_copybara.prepare_branch_sync")
@patch("buildscripts.copybara.sync_repo_with_copybara.resolve_test_workflow_baseline")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_test_workflow_source_branch_override")
@patch("buildscripts.copybara.sync_repo_with_copybara.resolve_test_workflow_requested_branches")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_local_copybara_config_bundle")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_test_workflow_base_revision")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_copybara_tokens")
@patch("buildscripts.copybara.sync_repo_with_copybara.create_mongodb_bot_gitconfig")
@patch("buildscripts.copybara.sync_repo_with_copybara.ensure_copybara_checkout_and_image")
@patch("buildscripts.copybara.sync_repo_with_copybara.read_config_file")
@patch("buildscripts.copybara.sync_repo_with_copybara.os.getcwd")
def test_main_runs_test_migration_after_successful_dry_run(
self,
mock_getcwd,
mock_read_config_file,
mock_ensure_copybara_checkout_and_image,
mock_create_mongodb_bot_gitconfig,
mock_get_copybara_tokens,
mock_get_test_workflow_base_revision,
mock_get_local_copybara_config_bundle,
mock_resolve_test_workflow_requested_branches,
mock_get_test_workflow_source_branch_override,
mock_resolve_test_workflow_baseline,
mock_prepare_branch_sync,
mock_push_test_branches,
mock_run_branch_dry_run,
mock_rewrite_copybara_config,
mock_run_branch_migrate,
mock_handle_failure,
mock_ensure_generated_copybara_evergreen_is_current,
):
mock_read_config_file.return_value = {
"project": sync_repo_with_copybara.EXPECTED_EVERGREEN_PROJECT,
"version_id": "patch123",
}
mock_getcwd.return_value = "/repo"
tokens = {
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
}
mock_get_copybara_tokens.side_effect = [tokens, tokens]
mock_get_test_workflow_base_revision.return_value = "base123"
mock_resolve_test_workflow_requested_branches.return_value = ("v8.2", "v8.2")
mock_get_test_workflow_source_branch_override.return_value = "daniel.moody/v8.2_test_branch"
test_baseline = sync_repo_with_copybara.TestWorkflowBaseline(
source_last_rev="private123",
destination_base_revision="public456",
public_branch="v8.2",
)
mock_resolve_test_workflow_baseline.return_value = test_baseline
with tempfile.TemporaryDirectory() as tmpdir:
base_config_path = Path(tmpdir) / "copy.bara.sky"
fragment_path = Path(tmpdir) / "v8_2.sky"
write_base_copybara_config(base_config_path)
fragment_path.write_text('sync_branch("v8.2")\n')
mock_get_local_copybara_config_bundle.return_value = (
sync_repo_with_copybara.CopybaraConfigBundle(
config_sha="local",
bundle_dir=Path(tmpdir),
base_config_path=base_config_path,
path_rules_path=Path(tmpdir) / "copybara_path_rules.json",
path_rules_module_path=Path(tmpdir) / "copybara_path_rules.bara.sky",
branch_to_fragment={"v8.2": fragment_path},
)
)
prepared_sync = sync_repo_with_copybara.PreparedBranchSync(
branch="v8.2",
source_ref="copybara_test_branch_patch123_v8.2",
config_sha="local",
workflow_name="test_v8.2",
config_file=Path(tmpdir) / "generated.sky",
preview_dir=Path(tmpdir) / "preview",
docker_command=("echo",),
copybara_config=sync_repo_with_copybara.CopybaraConfig(
source=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="https://example.com/source.git",
repo_name=sync_repo_with_copybara.SOURCE_REPO_NAME,
branch="copybara_test_branch_patch123_v8.2",
ref="copybara_test_branch_patch123_v8.2",
),
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="https://example.com/destination.git",
repo_name=sync_repo_with_copybara.TEST_REPO_NAME,
branch="copybara_test_branch_patch123_v8.2",
),
),
last_rev="private123",
test_baseline=test_baseline,
)
mock_prepare_branch_sync.return_value = prepared_sync
mock_run_branch_dry_run.return_value = sync_repo_with_copybara.BranchDryRunResult(
branch="v8.2"
)
argv = ["buildscripts/copybara/sync_repo_with_copybara.py", "--workflow=test"]
with patch.object(sys, "argv", argv):
sync_repo_with_copybara.main()
mock_prepare_branch_sync.assert_called_once_with(
current_dir="/repo",
workflow="test",
branch="v8.2",
source_ref="private123",
config_bundle=mock_get_local_copybara_config_bundle.return_value,
fragment_path=fragment_path,
tokens_map=tokens,
test_branch_prefix="copybara_test_branch_patch123",
test_baseline=test_baseline,
expansions=mock_read_config_file.return_value,
release_tag=None,
release_source_commit=None,
)
mock_push_test_branches.assert_called_once()
mock_ensure_generated_copybara_evergreen_is_current.assert_called_once_with(Path(tmpdir))
mock_run_branch_dry_run.assert_called_once_with(prepared_sync)
mock_rewrite_copybara_config.assert_called_once_with(prepared_sync.config_file, tokens)
mock_run_branch_migrate.assert_called_once_with(prepared_sync)
mock_handle_failure.assert_not_called()
@patch(
"buildscripts.copybara.sync_repo_with_copybara.ensure_generated_copybara_evergreen_is_current"
)
@patch("buildscripts.copybara.sync_repo_with_copybara.publish_release_tag")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_branch_migrate")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_branch_dry_run")
@patch("buildscripts.copybara.sync_repo_with_copybara.prepare_branch_sync")
@patch("buildscripts.copybara.sync_repo_with_copybara.activate_new_hotfix_tasks")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_remote_tag_commit")
@patch("buildscripts.copybara.sync_repo_with_copybara.tag_exists_remote")
@patch("buildscripts.copybara.sync_repo_with_copybara.fetch_remote_copybara_config_bundle")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_copybara_tokens")
@patch("buildscripts.copybara.sync_repo_with_copybara.create_mongodb_bot_gitconfig")
@patch("buildscripts.copybara.sync_repo_with_copybara.ensure_copybara_checkout_and_image")
@patch("buildscripts.copybara.sync_repo_with_copybara.read_config_file")
@patch("buildscripts.copybara.sync_repo_with_copybara.os.getcwd")
def test_main_runs_prod_release_tag_sync_and_publishes_tag(
self,
mock_getcwd,
mock_read_config_file,
mock_ensure_copybara_checkout_and_image,
mock_create_mongodb_bot_gitconfig,
mock_get_copybara_tokens,
mock_fetch_remote_copybara_config_bundle,
mock_tag_exists_remote,
mock_get_remote_tag_commit,
mock_activate_new_hotfix_tasks,
mock_prepare_branch_sync,
mock_run_branch_dry_run,
mock_run_branch_migrate,
mock_publish_release_tag,
mock_ensure_generated_copybara_evergreen_is_current,
):
mock_read_config_file.return_value = {
"project": sync_repo_with_copybara.EXPECTED_EVERGREEN_PROJECT,
}
mock_getcwd.return_value = "/repo"
tokens = {
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
}
mock_get_copybara_tokens.side_effect = [tokens, tokens]
mock_tag_exists_remote.return_value = False
mock_get_remote_tag_commit.return_value = "tagsha123"
synthetic_fragment_contents = ""
with tempfile.TemporaryDirectory() as tmpdir:
base_config_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
base_config_path,
prod_url=sync_repo_with_copybara.TEST_REPO_URL,
)
fragment_path = Path(tmpdir) / "master.sky"
fragment_path.write_text('sync_branch("master")\n')
mock_fetch_remote_copybara_config_bundle.return_value = (
sync_repo_with_copybara.CopybaraConfigBundle(
config_sha="configsha123",
bundle_dir=Path(tmpdir),
base_config_path=base_config_path,
path_rules_path=Path(tmpdir) / "copybara_path_rules.json",
path_rules_module_path=Path(tmpdir) / "copybara_path_rules.bara.sky",
branch_to_fragment={"master": fragment_path},
)
)
prepared_sync = sync_repo_with_copybara.PreparedBranchSync(
branch="v8.2.7",
source_ref="tagsha123",
config_sha="configsha123",
workflow_name="prod_r8.2.7",
config_file=Path("/tmp/generated.sky"),
preview_dir=Path("/tmp/preview"),
docker_command=("echo",),
release_tag="r8.2.7",
release_source_commit="tagsha123",
)
mock_prepare_branch_sync.return_value = prepared_sync
mock_run_branch_dry_run.return_value = sync_repo_with_copybara.BranchDryRunResult(
branch="v8.2.7",
noop=True,
)
argv = [
"buildscripts/copybara/sync_repo_with_copybara.py",
"--workflow=prod",
"--branches=r8.2.7",
]
with patch.object(sys, "argv", argv):
sync_repo_with_copybara.main()
synthetic_fragment_contents = mock_prepare_branch_sync.call_args.kwargs[
"fragment_path"
].read_text()
prepare_call = mock_prepare_branch_sync.call_args.kwargs
self.assertEqual(prepare_call["branch"], "v8.2.7")
self.assertEqual(prepare_call["source_ref"], "tagsha123")
self.assertEqual(prepare_call["release_tag"], "r8.2.7")
self.assertEqual(prepare_call["release_source_commit"], "tagsha123")
self.assertIn('sync_tag("r8.2.7")', synthetic_fragment_contents)
mock_ensure_generated_copybara_evergreen_is_current.assert_called_once_with(Path(tmpdir))
mock_run_branch_migrate.assert_not_called()
mock_publish_release_tag.assert_called_once_with(prepared_sync, tokens)
mock_activate_new_hotfix_tasks.assert_called_once()
mock_tag_exists_remote.assert_called_once_with(
"https://x-access-token:test-token@github.com/10gen/mongo-copybara.git",
"r8.2.7",
)
@patch(
"buildscripts.copybara.sync_repo_with_copybara.ensure_generated_copybara_evergreen_is_current"
)
@patch("buildscripts.copybara.sync_repo_with_copybara.prepare_branch_sync")
@patch("buildscripts.copybara.sync_repo_with_copybara.tag_exists_remote")
@patch("buildscripts.copybara.sync_repo_with_copybara.fetch_remote_copybara_config_bundle")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_copybara_tokens")
@patch("buildscripts.copybara.sync_repo_with_copybara.create_mongodb_bot_gitconfig")
@patch("buildscripts.copybara.sync_repo_with_copybara.ensure_copybara_checkout_and_image")
@patch("buildscripts.copybara.sync_repo_with_copybara.read_config_file")
@patch("buildscripts.copybara.sync_repo_with_copybara.os.getcwd")
def test_main_rejects_existing_public_release_tag(
self,
mock_getcwd,
mock_read_config_file,
mock_ensure_copybara_checkout_and_image,
mock_create_mongodb_bot_gitconfig,
mock_get_copybara_tokens,
mock_fetch_remote_copybara_config_bundle,
mock_tag_exists_remote,
mock_prepare_branch_sync,
mock_ensure_generated_copybara_evergreen_is_current,
):
mock_read_config_file.return_value = {
"project": sync_repo_with_copybara.EXPECTED_EVERGREEN_PROJECT,
}
mock_getcwd.return_value = "/repo"
tokens = {
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
}
mock_get_copybara_tokens.return_value = tokens
mock_tag_exists_remote.return_value = True
with tempfile.TemporaryDirectory() as tmpdir:
base_config_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
base_config_path,
prod_url=sync_repo_with_copybara.TEST_REPO_URL,
)
fragment_path = Path(tmpdir) / "master.sky"
fragment_path.write_text('sync_branch("master")\n')
mock_fetch_remote_copybara_config_bundle.return_value = (
sync_repo_with_copybara.CopybaraConfigBundle(
config_sha="configsha123",
bundle_dir=Path(tmpdir),
base_config_path=base_config_path,
path_rules_path=Path(tmpdir) / "copybara_path_rules.json",
path_rules_module_path=Path(tmpdir) / "copybara_path_rules.bara.sky",
branch_to_fragment={"master": fragment_path},
)
)
argv = [
"buildscripts/copybara/sync_repo_with_copybara.py",
"--workflow=prod",
"--branches=r8.2.7",
]
with patch.object(sys, "argv", argv):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.main()
mock_prepare_branch_sync.assert_not_called()
mock_ensure_generated_copybara_evergreen_is_current.assert_called_once_with(Path(tmpdir))
mock_tag_exists_remote.assert_called_once_with(
"https://x-access-token:test-token@github.com/10gen/mongo-copybara.git",
"r8.2.7",
)
def test_rewrite_copybara_config_refreshes_existing_tokens_and_prefix(self):
with tempfile.TemporaryDirectory() as tmpdir:
config_path = Path(tmpdir) / "copy.bara.sky"
config_path.write_text(
'source_url = "https://x-access-token:old@github.com/10gen/mongo.git"\n'
'prod_url = "https://github.com/mongodb/mongo.git"\n'
'test_url = "https://x-access-token:old@github.com/10gen/mongo-copybara.git"\n'
'test_branch_prefix = "copybara_test_branch"\n'
"\n"
"def make_workflow(workflow_name, destination_url, source_ref, destination_ref, branch_excluded_files):\n"
" pass\n"
"\n"
"def sync_branch(branch_name, branch_excluded_files = []):\n"
' make_workflow("prod_" + branch_name, prod_url, branch_name, branch_name, branch_excluded_files)\n'
" make_workflow(\n"
' "test_" + branch_name,\n'
" test_url,\n"
" branch_name,\n"
' test_branch_prefix + "_" + branch_name,\n'
" branch_excluded_files,\n"
" )\n"
)
sync_repo_with_copybara.rewrite_copybara_config(
config_file=config_path,
tokens_map={
sync_repo_with_copybara.SOURCE_REPO_URL: "new-source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "new-prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "new-test-token",
},
test_branch_prefix="copybara_test_branch_patch456",
source_refs={"v8.2": "deadbeef123"},
)
rewritten = config_path.read_text()
self.assertIn(
"https://x-access-token:new-source-token@github.com/10gen/mongo.git",
rewritten,
)
self.assertIn(
"https://x-access-token:new-prod-token@github.com/mongodb/mongo.git",
rewritten,
)
self.assertIn(
"https://x-access-token:new-test-token@github.com/10gen/mongo-copybara.git",
rewritten,
)
self.assertIn('test_branch_prefix = "copybara_test_branch_patch456"', rewritten)
self.assertIn('source_refs = {"v8.2": "deadbeef123"}', rewritten)
self.assertIn("source_ref = source_refs.get(branch_name, branch_name)", rewritten)
@patch("buildscripts.copybara.sync_repo_with_copybara.validate_preview_exclusions")
@patch("buildscripts.copybara.sync_repo_with_copybara.validate_sync_config")
@patch("buildscripts.copybara.sync_repo_with_copybara.rewrite_copybara_config")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_copybara_tokens")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_run_branch_dry_run_refreshes_tokens_on_auth_failure(
self,
mock_run_command,
mock_get_copybara_tokens,
mock_rewrite_copybara_config,
mock_validate_sync_config,
mock_validate_preview_exclusions,
):
with tempfile.TemporaryDirectory() as tmpdir:
preview_dir = Path(tmpdir) / "preview"
preview_dir.mkdir()
stale_file = preview_dir / "stale.txt"
stale_file.write_text("stale")
sync = sync_repo_with_copybara.PreparedBranchSync(
branch="v8.2",
source_ref="deadbeef123",
config_sha="local",
workflow_name="prod_v8.2",
config_file=Path(tmpdir) / "copy.bara.sky",
preview_dir=preview_dir,
docker_command=("echo", "copybara"),
expansions={"version_id": "patch123"},
)
auth_error = subprocess.CalledProcessError(
128,
"copybara",
output=(
"remote: Invalid username or token. Password authentication is not supported "
"for Git operations.\n"
"fatal: Authentication failed for 'https://github.com/10gen/mongo-copybara.git/'"
),
)
mock_run_command.side_effect = [auth_error, ""]
refreshed_tokens = {
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
}
mock_get_copybara_tokens.return_value = refreshed_tokens
result = sync_repo_with_copybara.run_branch_dry_run(sync)
self.assertEqual(result, sync_repo_with_copybara.BranchDryRunResult(branch="v8.2"))
self.assertFalse(stale_file.exists())
self.assertEqual(mock_run_command.call_count, 2)
mock_get_copybara_tokens.assert_called_once_with(sync.expansions)
mock_rewrite_copybara_config.assert_called_once_with(sync.config_file, refreshed_tokens)
mock_validate_sync_config.assert_called()
mock_validate_preview_exclusions.assert_called_once_with(sync)
@patch("buildscripts.copybara.sync_repo_with_copybara.rewrite_copybara_config")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_copybara_tokens")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_run_branch_migrate_refreshes_tokens_on_auth_failure(
self,
mock_run_command,
mock_get_copybara_tokens,
mock_rewrite_copybara_config,
):
sync = sync_repo_with_copybara.PreparedBranchSync(
branch="v8.2",
source_ref="deadbeef123",
config_sha="local",
workflow_name="prod_v8.2",
config_file=Path("/tmp/copy.bara.sky"),
preview_dir=Path("/tmp/preview"),
docker_command=("echo", "copybara"),
expansions={"version_id": "patch123"},
)
auth_error = subprocess.CalledProcessError(
128,
"copybara",
output=(
"remote: Invalid username or token. Password authentication is not supported "
"for Git operations.\n"
"fatal: Authentication failed for 'https://github.com/10gen/mongo-copybara.git/'"
),
)
mock_run_command.side_effect = [auth_error, ""]
refreshed_tokens = {
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
}
mock_get_copybara_tokens.return_value = refreshed_tokens
sync_repo_with_copybara.run_branch_migrate(sync)
self.assertEqual(mock_run_command.call_count, 2)
mock_get_copybara_tokens.assert_called_once_with(sync.expansions)
mock_rewrite_copybara_config.assert_called_once_with(sync.config_file, refreshed_tokens)
@patch("buildscripts.copybara.sync_repo_with_copybara.get_remote_branch_head")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_fetch_remote_copybara_config_bundle_reads_latest_master_bundle(
self, mock_run_command, mock_get_remote_branch_head
):
mock_get_remote_branch_head.return_value = "configsha123"
local_runner_contents = Path(sync_repo_with_copybara.__file__).resolve().read_text()
local_path_rules_contents = (
Path(sync_repo_with_copybara.__file__).resolve().with_name("path_rules.py").read_text()
)
template_text = (
"rendered_from_template = True\n"
"common_files_to_include = [\n"
"{{COMMON_FILES_TO_INCLUDE}}\n"
"]\n"
"\n"
"common_files_to_exclude = [\n"
"{{COMMON_FILES_TO_EXCLUDE}}\n"
"]\n"
)
def run_command_side_effect(command):
if command.startswith("git init "):
return ""
if "fetch --depth 1" in command:
return ""
if f"rev-parse {sync_repo_with_copybara.COPYBARA_CONFIG_FETCH_REF}" in command:
return "configsha123\n"
if sync_repo_with_copybara.COPYBARA_SYNC_RUNNER_PATH.as_posix() in command:
return local_runner_contents
if sync_repo_with_copybara.COPYBARA_PATH_RULES_HELPER_PATH.as_posix() in command:
return local_path_rules_contents
if "ls-tree -r --name-only" in command:
return "\n".join(
[
sync_repo_with_copybara.COPYBARA_BASE_CONFIG_PATH.as_posix(),
"buildscripts/copybara/master.sky",
"buildscripts/copybara/v8_2.sky",
]
)
if sync_repo_with_copybara.COPYBARA_BASE_CONFIG_PATH.as_posix() in command:
return (
'source_url = "https://github.com/10gen/mongo.git"\n'
'prod_url = "https://github.com/mongodb/mongo.git"\n'
'test_url = "https://github.com/10gen/mongo-copybara.git"\n'
'test_branch_prefix = "copybara_test_branch"\n'
"source_refs = {}\n"
"\n"
"def make_workflow(workflow_name, destination_url, source_ref, destination_ref, branch_excluded_files):\n"
" pass\n"
"\n"
"def sync_branch(branch_name, branch_excluded_files = []):\n"
' make_workflow("prod_" + branch_name, prod_url, branch_name, branch_name, branch_excluded_files)\n'
" make_workflow(\n"
' "test_" + branch_name,\n'
" test_url,\n"
" branch_name,\n"
' test_branch_prefix + "_" + branch_name,\n'
" branch_excluded_files,\n"
" )\n"
)
if sync_repo_with_copybara.COPYBARA_PATH_RULES_PATH.as_posix() in command:
return json.dumps(
{
"common_files_to_include": ["**"],
"common_files_to_exclude": ["src/mongo/db/modules/**"],
}
)
if sync_repo_with_copybara.COPYBARA_PATH_RULES_TEMPLATE_PATH.as_posix() in command:
return template_text
if (
sync_repo_with_copybara.COPYBARA_GENERATED_EVERGREEN_CONFIG_PATH.as_posix()
in command
):
return "generated Copybara Evergreen YAML\n"
if "buildscripts/copybara/master.sky" in command:
return 'sync_branch("master")\n'
if "buildscripts/copybara/v8_2.sky" in command:
return 'sync_branch("v8.2")\n'
raise AssertionError(f"Unexpected command: {command}")
mock_run_command.side_effect = run_command_side_effect
with tempfile.TemporaryDirectory() as tmpdir:
bundle = sync_repo_with_copybara.fetch_remote_copybara_config_bundle(
tmpdir,
"https://x-access-token:token@github.com/10gen/mongo.git",
)
self.assertEqual(bundle.config_sha, "configsha123")
self.assertEqual(
bundle.base_config_path.read_text().splitlines()[0],
'source_url = "https://github.com/10gen/mongo.git"',
)
self.assertEqual(
bundle.path_rules_path.read_text(),
json.dumps(
{
"common_files_to_include": ["**"],
"common_files_to_exclude": ["src/mongo/db/modules/**"],
}
),
)
self.assertIn(
"rendered_from_template = True",
bundle.path_rules_module_path.read_text(),
)
generated_evergreen_config_path = (
bundle.bundle_dir / sync_repo_with_copybara.COPYBARA_GENERATED_EVERGREEN_CONFIG_PATH
)
self.assertEqual(
generated_evergreen_config_path.read_text(),
"generated Copybara Evergreen YAML\n",
)
self.assertIn('"src/mongo/db/modules/**"', bundle.path_rules_module_path.read_text())
self.assertIn("master", bundle.branch_to_fragment)
self.assertIn("v8.2", bundle.branch_to_fragment)
@patch("buildscripts.copybara.sync_repo_with_copybara.get_remote_branch_head")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_fetch_remote_copybara_config_bundle_fails_for_stale_checked_out_runner(
self, mock_run_command, mock_get_remote_branch_head
):
mock_get_remote_branch_head.return_value = "configsha123"
def run_command_side_effect(command):
if command.startswith("git init "):
return ""
if "fetch --depth 1" in command:
return ""
if f"rev-parse {sync_repo_with_copybara.COPYBARA_CONFIG_FETCH_REF}" in command:
return "configsha123\n"
if sync_repo_with_copybara.COPYBARA_SYNC_RUNNER_PATH.as_posix() in command:
return "# stale runner from old build\n"
raise AssertionError(f"Unexpected command: {command}")
mock_run_command.side_effect = run_command_side_effect
with tempfile.TemporaryDirectory() as tmpdir:
stdout = io.StringIO()
with redirect_stdout(stdout):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.fetch_remote_copybara_config_bundle(
tmpdir,
"https://x-access-token:token@github.com/10gen/mongo.git",
)
log_output = stdout.getvalue()
self.assertIn("latest master-owned", log_output)
self.assertIn(sync_repo_with_copybara.COPYBARA_SYNC_RUNNER_PATH.as_posix(), log_output)
self.assertIn("Start a new master build", log_output)
@patch("buildscripts.copybara.sync_repo_with_copybara.get_remote_branch_head")
@patch("buildscripts.copybara.sync_repo_with_copybara.run_command")
def test_fetch_remote_copybara_config_bundle_fails_for_stale_checked_out_path_rules(
self, mock_run_command, mock_get_remote_branch_head
):
mock_get_remote_branch_head.return_value = "configsha123"
local_runner_contents = Path(sync_repo_with_copybara.__file__).resolve().read_text()
def run_command_side_effect(command):
if command.startswith("git init "):
return ""
if "fetch --depth 1" in command:
return ""
if f"rev-parse {sync_repo_with_copybara.COPYBARA_CONFIG_FETCH_REF}" in command:
return "configsha123\n"
if sync_repo_with_copybara.COPYBARA_SYNC_RUNNER_PATH.as_posix() in command:
return local_runner_contents
if sync_repo_with_copybara.COPYBARA_PATH_RULES_HELPER_PATH.as_posix() in command:
return "# stale path rules helper from old build\n"
raise AssertionError(f"Unexpected command: {command}")
mock_run_command.side_effect = run_command_side_effect
with tempfile.TemporaryDirectory() as tmpdir:
stdout = io.StringIO()
with redirect_stdout(stdout):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.fetch_remote_copybara_config_bundle(
tmpdir,
"https://x-access-token:token@github.com/10gen/mongo.git",
)
log_output = stdout.getvalue()
self.assertIn("latest master-owned", log_output)
self.assertIn(
sync_repo_with_copybara.COPYBARA_PATH_RULES_HELPER_PATH.as_posix(), log_output
)
self.assertIn("path rules helper", log_output)
self.assertIn("Start a new master build", log_output)
def test_get_local_copybara_config_bundle_renders_checked_out_path_rules_module(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
base_config_path = get_repo_base_copybara_config_path(root)
write_base_copybara_config(base_config_path)
path_rules_path = get_repo_copybara_path_rules_path(root)
write_copybara_path_rules(
path_rules_path,
common_includes=DEFAULT_TEST_COPYBARA_PATH_RULES_INCLUDES,
common_excludes=DEFAULT_TEST_COPYBARA_PATH_RULES_EXCLUDES,
)
path_rules_template_path = get_repo_copybara_path_rules_template_path(root)
write_copybara_path_rules_template(path_rules_template_path)
path_rules_module_path = get_repo_copybara_path_rules_module_path(root)
fragment_dir = root / "buildscripts" / "copybara"
fragment_dir.mkdir(parents=True, exist_ok=True)
(fragment_dir / "master.sky").write_text('sync_branch("master")\n')
(fragment_dir / "v8_2.sky").write_text('sync_branch("v8.2")\n')
bundle = sync_repo_with_copybara.get_local_copybara_config_bundle(tmpdir)
self.assertEqual(bundle.config_sha, "local")
self.assertEqual(bundle.base_config_path, base_config_path)
self.assertEqual(bundle.path_rules_path, path_rules_path)
self.assertEqual(bundle.path_rules_module_path, path_rules_module_path)
self.assertEqual(
path_rules_module_path.read_text(),
render_copybara_path_rules_module_from_files(
path_rules_template_path,
path_rules_path,
),
)
self.assertEqual(bundle.branch_to_fragment["master"], fragment_dir / "master.sky")
self.assertEqual(bundle.branch_to_fragment["v8.2"], fragment_dir / "v8_2.sky")
class TestGenerateCopybaraEvergreen(unittest.TestCase):
@staticmethod
def write_fragment(root: Path, filename: str, contents: str) -> None:
fragment_path = root / sync_repo_with_copybara.COPYBARA_CONFIG_DIRECTORY / filename
fragment_path.parent.mkdir(parents=True, exist_ok=True)
fragment_path.write_text(contents)
def test_render_expected_copybara_evergreen_uses_branch_and_tag_fragments(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
self.write_fragment(root, "master.sky", 'sync_branch("master")\n')
self.write_fragment(
root,
"v8_2.sky",
'sync_branch("v8.2")\n'
'sync_branch("v8.2.7-hotfix")\n'
'sync_tag("r8.2.7-hotfix")\n',
)
generated = generate_evergreen.render_expected_copybara_evergreen(root)
self.assertIn(
"# This file is generated by buildscripts/copybara/generate_evergreen.py.",
generated,
)
self.assertIn(" - name: sync_copybara_master", generated)
self.assertIn(" - name: sync_copybara_v8_2", generated)
self.assertIn(" - name: sync_copybara_v8_2_7_hotfix", generated)
self.assertIn(' copybara_branches: "v8.2.7-hotfix"', generated)
self.assertIn(" - name: sync_copybara_r8_2_7_hotfix", generated)
self.assertIn(' copybara_branches: "r8.2.7-hotfix"', generated)
self.assertNotIn("sync_copybara_task_template", generated)
self.assertLess(
generated.index("sync_copybara_master"),
generated.index("sync_copybara_v8_2"),
)
self.assertLess(
generated.index("sync_copybara_v8_2_7_hotfix"),
generated.index("sync_copybara_r8_2_7_hotfix"),
)
def test_check_generated_copybara_evergreen_detects_stale_file(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
self.write_fragment(root, "master.sky", 'sync_branch("master")\n')
generated_path = root / generate_evergreen.COPYBARA_EVERGREEN_GENERATED_CONFIG_PATH
generated_path.parent.mkdir(parents=True, exist_ok=True)
generated_path.write_text("stale\n")
stdout = io.StringIO()
with redirect_stdout(stdout):
is_current = generate_evergreen.check_generated_copybara_evergreen(root)
self.assertFalse(is_current)
self.assertIn("Generated Copybara Evergreen config is stale", stdout.getvalue())
def test_check_generated_copybara_evergreen_accepts_current_file(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
self.write_fragment(root, "master.sky", 'sync_branch("master")\n')
generated_path = root / generate_evergreen.COPYBARA_EVERGREEN_GENERATED_CONFIG_PATH
generated_path.parent.mkdir(parents=True, exist_ok=True)
generated_path.write_text(generate_evergreen.render_expected_copybara_evergreen(root))
self.assertTrue(generate_evergreen.check_generated_copybara_evergreen(root))
@patch("buildscripts.copybara.generate_evergreen.check_generated_copybara_evergreen")
def test_sync_precheck_accepts_current_generated_evergreen(self, mock_check_generated):
mock_check_generated.return_value = True
stdout = io.StringIO()
with redirect_stdout(stdout):
sync_repo_with_copybara.ensure_generated_copybara_evergreen_is_current("/repo")
mock_check_generated.assert_called_once_with(Path("/repo"))
self.assertIn("Generated Copybara Evergreen config is current", stdout.getvalue())
@patch("buildscripts.copybara.generate_evergreen.check_generated_copybara_evergreen")
def test_sync_precheck_rejects_stale_generated_evergreen(self, mock_check_generated):
mock_check_generated.return_value = False
with self.assertRaises(SystemExit) as context:
sync_repo_with_copybara.ensure_generated_copybara_evergreen_is_current("/repo")
self.assertEqual(context.exception.code, 1)
mock_check_generated.assert_called_once_with(Path("/repo"))
class TestValidateSyncConfig(unittest.TestCase):
@patch("buildscripts.copybara.sync_repo_with_copybara.check_branch_top_level_paths_are_labeled")
@patch("buildscripts.copybara.sync_repo_with_copybara.list_top_level_paths_for_remote_ref")
def test_uses_pinned_source_ref_for_top_level_validation(
self,
mock_list_top_level_paths_for_remote_ref,
mock_check_branch_top_level_paths_are_labeled,
):
mock_list_top_level_paths_for_remote_ref.return_value = {"README.md", "src"}
sync = sync_repo_with_copybara.PreparedBranchSync(
branch="v8.2",
source_ref="deadbeef123",
config_sha="configsha123",
workflow_name="prod_v8.2",
config_file=Path("/tmp/generated.sky"),
preview_dir=Path("/tmp/preview"),
docker_command=("echo", "copybara"),
copybara_config=sync_repo_with_copybara.CopybaraConfig(
source=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="https://example.com/source.git",
repo_name=sync_repo_with_copybara.SOURCE_REPO_NAME,
branch="v8.2",
ref="deadbeef123",
),
destination=sync_repo_with_copybara.CopybaraRepoConfig(
git_url="https://example.com/destination.git",
repo_name=sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_NAME,
branch="v8.2",
),
),
)
sync_repo_with_copybara.validate_sync_config(sync)
mock_list_top_level_paths_for_remote_ref.assert_called_once_with(
"https://example.com/source.git",
"deadbeef123",
)
mock_check_branch_top_level_paths_are_labeled.assert_called_once_with(
str(sync.config_file),
"v8.2",
{"README.md", "src"},
)
class TestEnsureCopybaraSourceRefSupport(unittest.TestCase):
"""Verify that ensure_copybara_source_ref_support correctly injects or preserves source_refs."""
def _make_config_without_source_refs(self) -> str:
return textwrap.dedent("""\
source_url = "https://github.com/10gen/mongo.git"
test_branch_prefix = "copybara_test_branch"
def sync_branch(branch_name):
make_workflow("prod_" + branch_name, prod_url, branch_name, branch_name)
make_workflow(
"test_" + branch_name,
test_url,
branch_name,
test_branch_prefix + "_" + branch_name,
)
""")
def _make_config_with_source_refs(self) -> str:
return textwrap.dedent("""\
source_url = "https://github.com/10gen/mongo.git"
test_branch_prefix = "copybara_test_branch"
source_refs = {}
def sync_branch(branch_name):
source_ref = source_refs.get(branch_name, branch_name)
make_workflow(
"prod_" + branch_name,
prod_url,
source_ref,
branch_name,
)
make_workflow(
"test_" + branch_name,
test_url,
source_ref,
test_branch_prefix + "_" + branch_name,
)
""")
def _make_legacy_config_with_source_refs(self) -> str:
return textwrap.dedent("""\
source_url = "https://github.com/10gen/mongo.git"
test_branch_prefix = "copybara_test_branch"
source_refs = {}
def sync_branch(branch_name, branch_excluded_files = [], branch_public_files = ["**"]):
source_ref = source_refs.get(branch_name, branch_name)
make_workflow(
"prod_" + branch_name,
prod_url,
source_ref,
branch_name,
branch_excluded_files,
branch_public_files,
)
make_workflow(
"test_" + branch_name,
test_url,
source_ref,
test_branch_prefix + "_" + branch_name,
branch_excluded_files,
branch_public_files,
)
""")
def test_injects_source_refs_when_missing(self):
contents = self._make_config_without_source_refs()
result = sync_repo_with_copybara.ensure_copybara_source_ref_support(
contents, Path("test.sky")
)
self.assertIn("source_refs = {}", result)
self.assertIn("source_ref = source_refs.get(branch_name, branch_name)", result)
self.assertIn("def sync_tag(tag_name):", result)
self.assertIn(
'make_workflow("prod_" + branch_name, prod_url, source_ref, branch_name)',
result,
)
self.assertIn(
'make_workflow("prod_" + tag_name, prod_url, source_ref, branch_name)',
result,
)
def test_preserves_existing_source_refs(self):
contents = self._make_config_with_source_refs()
result = sync_repo_with_copybara.ensure_copybara_source_ref_support(
contents, Path("test.sky")
)
self.assertIn("source_refs = {}", result)
self.assertIn("source_ref = source_refs.get(branch_name, branch_name)", result)
self.assertIn("def sync_branch(branch_name):", result)
def test_preserves_legacy_source_refs_with_public_files(self):
contents = self._make_legacy_config_with_source_refs()
result = sync_repo_with_copybara.ensure_copybara_source_ref_support(
contents, Path("test.sky")
)
self.assertIn("source_refs = {}", result)
self.assertIn("source_ref = source_refs.get(branch_name, branch_name)", result)
self.assertIn('branch_public_files = ["**"]', result)
self.assertIn("branch_public_files,\n )", result)
def test_exits_when_sync_branch_not_found(self):
contents = textwrap.dedent("""\
source_url = "https://github.com/10gen/mongo.git"
test_branch_prefix = "copybara_test_branch"
source_refs = {}
""")
with self.assertRaises(SystemExit):
sync_repo_with_copybara.ensure_copybara_source_ref_support(contents, Path("test.sky"))
def test_exits_when_test_branch_prefix_not_found(self):
contents = textwrap.dedent("""\
source_url = "https://github.com/10gen/mongo.git"
def sync_branch(branch_name, branch_excluded_files = []):
pass
""")
with self.assertRaises(SystemExit):
sync_repo_with_copybara.ensure_copybara_source_ref_support(contents, Path("test.sky"))
class TestValidatePreviewExclusions(unittest.TestCase):
"""Verify dry-run output validation catches forbidden files."""
def _make_sync_with_preview(
self,
files: list[str],
branch: str = "master",
branch_excluded_patterns: list[str] | None = None,
) -> sync_repo_with_copybara.PreparedBranchSync:
tmpdir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, tmpdir)
root = Path(tmpdir)
config_path = root / "copy.bara.sky"
write_base_copybara_config(config_path, common_includes=["README.md"])
branch_excluded_patterns = branch_excluded_patterns or []
if branch_excluded_patterns:
exclude_entries = "\n".join(f' "{pattern}",' for pattern in branch_excluded_patterns)
config_path.write_text(
config_path.read_text()
+ "\nbranch_files_to_exclude = [\n"
+ f"{exclude_entries}\n"
+ "]\n"
+ f'sync_branch("{branch}", branch_files_to_exclude)\n'
)
else:
config_path.write_text(config_path.read_text() + f'\nsync_branch("{branch}")\n')
preview_dir = root / "preview" / "checkout"
preview_dir.mkdir(parents=True)
for file_path in files:
full_path = preview_dir / file_path
full_path.parent.mkdir(parents=True, exist_ok=True)
full_path.write_text("content")
return sync_repo_with_copybara.PreparedBranchSync(
branch=branch,
source_ref="abc123",
config_sha="sha123",
workflow_name=f"prod_{branch}",
config_file=config_path,
preview_dir=root / "preview",
docker_command=("echo",),
)
def test_passes_when_no_excluded_files_present(self):
sync = self._make_sync_with_preview(
[
"src/mongo/db/catalog/collection.cpp",
"README.md",
"jstests/core/basic.js",
]
)
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_modules_directory_present(self):
sync = self._make_sync_with_preview(
[
"src/mongo/db/modules/enterprise/something.cpp",
]
)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError) as ctx:
sync_repo_with_copybara.validate_preview_exclusions(sync)
self.assertIn("preview validation", ctx.exception.stage)
def test_fails_when_agents_md_present(self):
sync = self._make_sync_with_preview(["AGENTS.md"])
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_private_third_party_present(self):
sync = self._make_sync_with_preview(
[
"src/third_party/private/secret.h",
]
)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_cursor_directory_present(self):
sync = self._make_sync_with_preview(
[
".cursor/rules/my_rule.md",
]
)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_github_codeowners_present(self):
sync = self._make_sync_with_preview(
[
".github/CODEOWNERS",
]
)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_monguard_present(self):
sync = self._make_sync_with_preview(
[
"monguard/config.yaml",
]
)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_branch_specific_excluded_file_present(self):
sync = self._make_sync_with_preview(
["docs/private-notes/secret.md"],
branch="v8.2",
branch_excluded_patterns=["docs/private-notes/**"],
)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_private_commercial_header_present(self):
sync = self._make_sync_with_preview([])
public_header_path = sync.preview_dir / "checkout" / "src/mongo/util/public_header.h"
public_header_path.parent.mkdir(parents=True, exist_ok=True)
public_header_path.write_text(
textwrap.dedent("""\
/**
* Copyright (C) 2025-present MongoDB, Inc. and subject to applicable commercial license.
*/
""")
)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_excluded_broken_symlink_present(self):
if sys.platform == "win32":
self.skipTest("symlink permissions vary on Windows")
sync = self._make_sync_with_preview([])
excluded_symlink = sync.preview_dir / "checkout" / "AGENTS.md"
os.symlink("missing-target", excluded_symlink)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
def test_fails_when_excluded_symlinked_directory_present(self):
if sys.platform == "win32":
self.skipTest("symlink permissions vary on Windows")
sync = self._make_sync_with_preview([])
excluded_symlink_dir = sync.preview_dir / "checkout" / "src/mongo/db/modules"
excluded_symlink_dir.parent.mkdir(parents=True, exist_ok=True)
os.symlink("missing-target", excluded_symlink_dir)
with self.assertRaises(sync_repo_with_copybara.BranchSyncError):
sync_repo_with_copybara.validate_preview_exclusions(sync)
class TestRedactSecrets(unittest.TestCase):
"""Verify token redaction in log output."""
def test_redacts_known_tokens(self):
original_secrets = list(sync_repo_with_copybara.REDACTED_STRINGS)
try:
sync_repo_with_copybara.REDACTED_STRINGS.clear()
sync_repo_with_copybara.REDACTED_STRINGS.append("ghp_SuperSecretToken123")
result = sync_repo_with_copybara.redact_secrets(
"Using token ghp_SuperSecretToken123 for auth"
)
self.assertNotIn("ghp_SuperSecretToken123", result)
self.assertIn("<REDACTED>", result)
finally:
sync_repo_with_copybara.REDACTED_STRINGS.clear()
sync_repo_with_copybara.REDACTED_STRINGS.extend(original_secrets)
def test_redacts_github_url_credentials(self):
url = "https://x-access-token:ghs_abc123xyz@github.com/10gen/mongo.git"
result = sync_repo_with_copybara.redact_secrets(url)
self.assertNotIn("ghs_abc123xyz", result)
self.assertIn("https://x-access-token:<REDACTED>@github.com", result)
def test_redacts_unknown_github_url_credentials(self):
"""Credentials not in REDACTED_STRINGS are still caught by the regex fallback."""
url = "https://x-access-token:unknown_ambient_token@github.com/mongodb/mongo.git"
result = sync_repo_with_copybara.redact_secrets(url)
self.assertNotIn("unknown_ambient_token", result)
def test_preserves_non_sensitive_text(self):
text = "Running copybara for branch master"
result = sync_repo_with_copybara.redact_secrets(text)
self.assertEqual(text, result)
def test_handles_empty_redacted_strings_list(self):
original_secrets = list(sync_repo_with_copybara.REDACTED_STRINGS)
try:
sync_repo_with_copybara.REDACTED_STRINGS.clear()
result = sync_repo_with_copybara.redact_secrets("no secrets here")
self.assertEqual("no secrets here", result)
finally:
sync_repo_with_copybara.REDACTED_STRINGS.clear()
sync_repo_with_copybara.REDACTED_STRINGS.extend(original_secrets)
class TestExtractSkyExcludedPatternsRejectsDuplicates(unittest.TestCase):
"""Verify that duplicate common_files_to_exclude definitions are rejected."""
def test_rejects_multiple_common_files_to_exclude_definitions(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
sky_path.write_text(
textwrap.dedent("""\
common_files_to_exclude = [
"src/mongo/db/modules/**",
]
common_files_to_exclude = [
"harmless_file.txt",
]
""")
)
with self.assertRaises(SystemExit):
sync_repo_with_copybara.extract_sky_excluded_patterns(str(sky_path))
def test_accepts_single_definition(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(sky_path)
patterns = sync_repo_with_copybara.extract_sky_excluded_patterns(str(sky_path))
self.assertIsInstance(patterns, set)
self.assertTrue(len(patterns) > 0)
def test_ignores_commented_out_definitions(self):
with tempfile.TemporaryDirectory() as tmpdir:
sky_path = Path(tmpdir) / "copy.bara.sky"
sky_path.write_text(
textwrap.dedent("""\
# common_files_to_exclude = ["should_be_ignored/**"]
common_files_to_exclude = [
"src/mongo/db/modules/**",
]
""")
)
patterns = sync_repo_with_copybara.extract_sky_excluded_patterns(str(sky_path))
self.assertNotIn("should_be_ignored/**", patterns)
self.assertIn("src/mongo/db/modules/**", patterns)
class TestMatchesExcludedPattern(unittest.TestCase):
"""Verify path matching logic for excluded patterns."""
def test_directory_pattern_matches_files_in_subtree(self):
self.assertTrue(
sync_repo_with_copybara.matches_excluded_pattern(
"src/mongo/db/modules/enterprise/foo.cpp", "src/mongo/db/modules/"
)
)
def test_directory_pattern_matches_directory_itself(self):
self.assertTrue(
sync_repo_with_copybara.matches_excluded_pattern(
"src/mongo/db/modules", "src/mongo/db/modules/"
)
)
def test_directory_pattern_with_glob_suffix(self):
self.assertTrue(
sync_repo_with_copybara.matches_excluded_pattern(
"src/third_party/private/secret.h", "src/third_party/private/**"
)
)
def test_directory_pattern_does_not_match_unrelated_path(self):
self.assertFalse(
sync_repo_with_copybara.matches_excluded_pattern(
"src/mongo/db/storage/wiredtiger.cpp", "src/mongo/db/modules/"
)
)
def test_exact_file_pattern_matches_exact_path(self):
self.assertTrue(sync_repo_with_copybara.matches_excluded_pattern("AGENTS.md", "AGENTS.md"))
def test_exact_file_pattern_does_not_match_different_file(self):
self.assertFalse(sync_repo_with_copybara.matches_excluded_pattern("README.md", "AGENTS.md"))
def test_exact_file_pattern_does_not_match_subdirectory_file(self):
self.assertFalse(
sync_repo_with_copybara.matches_excluded_pattern("docs/AGENTS.md", "AGENTS.md")
)
def test_directory_pattern_does_not_match_prefix_overlap(self):
"""monguard/ should not match monguard_extra/."""
self.assertFalse(
sync_repo_with_copybara.matches_excluded_pattern("monguard_extra/file.txt", "monguard/")
)
class TestCanonicalizeExcludedPattern(unittest.TestCase):
"""Verify pattern normalization for preview exclusion matching."""
def test_trailing_slash_becomes_directory_pattern(self):
self.assertEqual(
sync_repo_with_copybara.canonicalize_excluded_pattern("monguard/"),
"monguard/",
)
def test_glob_suffix_becomes_directory_pattern(self):
self.assertEqual(
sync_repo_with_copybara.canonicalize_excluded_pattern("monguard/**"),
"monguard/",
)
def test_exact_file_stays_exact(self):
self.assertEqual(
sync_repo_with_copybara.canonicalize_excluded_pattern("AGENTS.md"),
"AGENTS.md",
)
def test_rejects_wildcard_patterns(self):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.canonicalize_excluded_pattern("*.py")
def test_rejects_empty_pattern(self):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.canonicalize_excluded_pattern("")
def test_rejects_slash_only_pattern(self):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.canonicalize_excluded_pattern("/")
class TestAssembleCopybaraConfig(unittest.TestCase):
"""Verify that base config and fragments are correctly concatenated."""
def test_combines_base_and_single_fragment(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
base = root / "base.sky"
base.write_text('# base config\nsource_url = "foo"\n')
fragment = root / "master.sky"
fragment.write_text('sync_branch("master")\n')
output = root / "assembled.sky"
sync_repo_with_copybara.assemble_copybara_config(base, [fragment], output)
assembled = output.read_text()
self.assertIn("# base config", assembled)
self.assertIn('sync_branch("master")', assembled)
self.assertIn(f"# BEGIN {fragment.as_posix()}", assembled)
self.assertIn(f"# END {fragment.as_posix()}", assembled)
def test_combines_base_and_multiple_fragments(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
base = root / "base.sky"
base.write_text("# base\n")
frag_a = root / "a.sky"
frag_a.write_text('sync_branch("a")\n')
frag_b = root / "b.sky"
frag_b.write_text('sync_branch("b")\n')
output = root / "out.sky"
sync_repo_with_copybara.assemble_copybara_config(base, [frag_a, frag_b], output)
assembled = output.read_text()
self.assertIn('sync_branch("a")', assembled)
self.assertIn('sync_branch("b")', assembled)
idx_a = assembled.index('sync_branch("a")')
idx_b = assembled.index('sync_branch("b")')
self.assertLess(idx_a, idx_b)
def test_output_ends_with_newline(self):
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
base = root / "base.sky"
base.write_text("# base\n")
fragment = root / "f.sky"
fragment.write_text('sync_branch("x")\n')
output = root / "out.sky"
sync_repo_with_copybara.assemble_copybara_config(base, [fragment], output)
self.assertTrue(output.read_text().endswith("\n"))
class TestParseBranchList(unittest.TestCase):
"""Verify edge-case handling for comma-separated branch parsing."""
def test_returns_empty_for_none(self):
self.assertEqual(sync_repo_with_copybara.parse_branch_list(None), [])
def test_returns_empty_for_blank_string(self):
self.assertEqual(sync_repo_with_copybara.parse_branch_list(""), [])
def test_single_branch(self):
self.assertEqual(
sync_repo_with_copybara.parse_branch_list("master"),
["master"],
)
def test_deduplicates_preserving_order(self):
self.assertEqual(
sync_repo_with_copybara.parse_branch_list("v8.2, master, v8.2"),
["v8.2", "master"],
)
def test_strips_whitespace(self):
self.assertEqual(
sync_repo_with_copybara.parse_branch_list(" master , v8.0 , v8.2 "),
["master", "v8.0", "v8.2"],
)
def test_skips_empty_entries_from_trailing_comma(self):
self.assertEqual(
sync_repo_with_copybara.parse_branch_list("master,v8.0,"),
["master", "v8.0"],
)
def test_skips_empty_entries_from_double_comma(self):
self.assertEqual(
sync_repo_with_copybara.parse_branch_list("master,,v8.0"),
["master", "v8.0"],
)
class TestRealCopybaraSkyConfiguration(unittest.TestCase):
"""Integration tests for the checked-in Copybara config files."""
REAL_COPYBARA_ROOT = Path(__file__).resolve().parents[2]
REAL_SKY_PATH = REAL_COPYBARA_ROOT / sync_repo_with_copybara.COPYBARA_BASE_CONFIG_PATH
REAL_TEMPLATE_PATH = (
REAL_COPYBARA_ROOT / "buildscripts" / "copybara" / "copybara_path_rules.bara.sky.template"
)
REAL_PATH_RULES_PATH = REAL_COPYBARA_ROOT / sync_repo_with_copybara.COPYBARA_PATH_RULES_PATH
REAL_PATH_RULES_MODULE_PATH = (
REAL_COPYBARA_ROOT / sync_repo_with_copybara.COPYBARA_PATH_RULES_MODULE_PATH
)
REAL_GENERATED_EVERGREEN_PATH = (
REAL_COPYBARA_ROOT / generate_evergreen.COPYBARA_EVERGREEN_GENERATED_CONFIG_PATH
)
@unittest.skipUnless(
REAL_PATH_RULES_MODULE_PATH.is_file()
and REAL_TEMPLATE_PATH.is_file()
and REAL_PATH_RULES_PATH.is_file(),
"checked-in Copybara source-of-truth files not found at expected paths",
)
def test_real_path_rules_module_matches_rendered_source_of_truth(self):
rendered = render_copybara_path_rules_module_from_files(
self.REAL_TEMPLATE_PATH,
self.REAL_PATH_RULES_PATH,
)
self.assertEqual(self.REAL_PATH_RULES_MODULE_PATH.read_text(), rendered)
@unittest.skipUnless(
REAL_SKY_PATH.is_file(),
"checked-in copy.bara.sky not found at expected path",
)
def test_real_base_config_loads_generated_path_rules_module(self):
contents = self.REAL_SKY_PATH.read_text()
self.assertIn('load("copybara_path_rules"', contents)
self.assertIn('"common_files_to_include"', contents)
self.assertIn('"common_files_to_exclude"', contents)
@unittest.skipUnless(
REAL_PATH_RULES_PATH.is_file(),
"checked-in Copybara path rules JSON not found at expected path",
)
def test_real_path_rules_json_lists_are_sorted(self):
payload = json.loads(self.REAL_PATH_RULES_PATH.read_text())
for field_name in ("common_files_to_include", "common_files_to_exclude"):
with self.subTest(field_name=field_name):
self.assertEqual(
payload[field_name],
sorted(payload[field_name]),
f"{field_name} in copybara_path_rules.json must remain sorted.",
)
@unittest.skipUnless(
REAL_SKY_PATH.is_file(),
"checked-in copy.bara.sky not found at expected path",
)
def test_real_fragments_match_expected_mainline_branch_allowlist(self):
branch_to_fragment = sync_repo_with_copybara.discover_copybara_branches(
str(self.REAL_COPYBARA_ROOT)
)
mainline_branches = sorted(
branch for branch in branch_to_fragment if not branch.endswith("-hotfix")
)
hotfix_branches = sorted(
branch for branch in branch_to_fragment if branch.endswith("-hotfix")
)
self.assertEqual(mainline_branches, ["master", "v7.0", "v8.0", "v8.2"])
self.assertTrue(all(branch.endswith("-hotfix") for branch in hotfix_branches))
@unittest.skipUnless(
REAL_GENERATED_EVERGREEN_PATH.is_file(),
"checked-in generated Copybara Evergreen config not found at expected path",
)
def test_real_generated_evergreen_matches_copybara_fragments(self):
self.assertEqual(
self.REAL_GENERATED_EVERGREEN_PATH.read_text(),
generate_evergreen.render_expected_copybara_evergreen(self.REAL_COPYBARA_ROOT),
)
class TestEvergreenProjectGuard(unittest.TestCase):
def test_passes_for_expected_master_project(self):
sync_repo_with_copybara.ensure_expected_evergreen_project(
{"project": sync_repo_with_copybara.EXPECTED_EVERGREEN_PROJECT}
)
def test_fails_for_missing_project(self):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.ensure_expected_evergreen_project({})
def test_fails_for_non_master_project(self):
with self.assertRaises(SystemExit):
sync_repo_with_copybara.ensure_expected_evergreen_project(
{"project": "mongodb-mongo-master-nightly"}
)
class TestHotfixTaskActivation(unittest.TestCase):
def test_get_hotfix_branches_for_release(self):
hotfix_branches = sync_repo_with_copybara.get_hotfix_branches_for_release(
"v8.2",
["master", "v8.2", "v8.2-hotfix", "v8.2.6-hotfix", "v8.0.10-hotfix"],
)
self.assertEqual(hotfix_branches, ["v8.2-hotfix", "v8.2.6-hotfix"])
@patch("buildscripts.copybara.sync_repo_with_copybara.retry_operation")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_evergreen_api")
@patch("buildscripts.copybara.sync_repo_with_copybara.check_destination_branch_exists")
@patch("buildscripts.copybara.sync_repo_with_copybara.branch_exists_remote")
def test_activate_new_hotfix_tasks_activates_unsynced_hotfix_task(
self,
mock_branch_exists_remote,
mock_check_destination_branch_exists,
mock_get_api,
mock_retry_operation,
):
mock_branch_exists_remote.return_value = True
mock_check_destination_branch_exists.return_value = False
inactive_task = MagicMock()
inactive_task.display_name = "sync_copybara_v8_2_6_hotfix"
inactive_task.activated = False
inactive_task.task_id = "task_1"
mock_api = mock_get_api.return_value
mock_api.tasks_by_build.return_value = [inactive_task]
with tempfile.TemporaryDirectory() as tmpdir:
config_file = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
config_file,
prod_url=sync_repo_with_copybara.TEST_REPO_URL,
)
sync_repo_with_copybara.activate_new_hotfix_tasks(
selected_branches=["v8.2"],
configured_branches=["master", "v8.2", "v8.2.6-hotfix"],
expansions={"build_id": "build_1"},
tokens_map={
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
},
config_file=config_file,
)
mock_retry_operation.assert_called_once_with(
mock_api.configure_task,
"task_1",
activated=True,
tries=3,
delay_seconds=5,
backoff_factor=2,
)
self.assertEqual(
mock_check_destination_branch_exists.call_args.args[0].destination.repo_name,
sync_repo_with_copybara.TEST_REPO_NAME,
)
@patch("buildscripts.copybara.sync_repo_with_copybara.retry_operation")
@patch("buildscripts.copybara.sync_repo_with_copybara.get_evergreen_api")
@patch("buildscripts.copybara.sync_repo_with_copybara.check_destination_branch_exists")
@patch("buildscripts.copybara.sync_repo_with_copybara.branch_exists_remote")
def test_activate_new_hotfix_tasks_skips_existing_public_branch(
self,
mock_branch_exists_remote,
mock_check_destination_branch_exists,
mock_get_api,
mock_retry_operation,
):
mock_branch_exists_remote.return_value = True
mock_check_destination_branch_exists.return_value = True
mock_get_api.return_value.tasks_by_build.return_value = []
with tempfile.TemporaryDirectory() as tmpdir:
config_file = Path(tmpdir) / "copy.bara.sky"
write_base_copybara_config(
config_file,
prod_url=sync_repo_with_copybara.TEST_REPO_URL,
)
sync_repo_with_copybara.activate_new_hotfix_tasks(
selected_branches=["v8.2"],
configured_branches=["master", "v8.2", "v8.2.6-hotfix"],
expansions={"build_id": "build_1"},
tokens_map={
sync_repo_with_copybara.SOURCE_REPO_URL: "source-token",
sync_repo_with_copybara.PUBLIC_GITHUB_APP_REPO_URL: "prod-token",
sync_repo_with_copybara.TEST_REPO_URL: "test-token",
},
config_file=config_file,
)
mock_retry_operation.assert_not_called()
if __name__ == "__main__":
unittest.main()