Backed out changeset d33734cbe630 (bug 1929372) fo causing python failures. CLOSED TREE

This commit is contained in:
Goloman Adrian
2025-04-16 01:15:20 +03:00
parent 6f7fc59c1c
commit 3c2e0547c3
18 changed files with 41 additions and 632 deletions

View File

@@ -10,6 +10,5 @@ from mozversioncontrol.factory import ( # noqa
)
from mozversioncontrol.repo.base import Repository # noqa
from mozversioncontrol.repo.git import GitRepository # noqa
from mozversioncontrol.repo.jj import JujutsuRepository # noqa
from mozversioncontrol.repo.mercurial import HgRepository # noqa
from mozversioncontrol.repo.source import SrcRepository # noqa

View File

@@ -2,7 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this,
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
from pathlib import Path
from typing import (
Optional,
@@ -16,13 +15,12 @@ from mozversioncontrol.errors import (
MissingVCSTool,
)
from mozversioncontrol.repo.git import GitRepository
from mozversioncontrol.repo.jj import JujutsuRepository
from mozversioncontrol.repo.mercurial import HgRepository
from mozversioncontrol.repo.source import SrcRepository
def get_repository_object(
path: Optional[Union[str, Path]], hg="hg", git="git", jj="jj", src="src"
path: Optional[Union[str, Path]], hg="hg", git="git", src="src"
):
"""Get a repository object for the repository at `path`.
If `path` is not a known VCS repository, raise an exception.
@@ -33,27 +31,12 @@ def get_repository_object(
path = Path(path).resolve()
if (path / ".hg").is_dir():
return HgRepository(path, hg=hg)
if (path / ".jj").is_dir():
# Warn (once) if MOZ_AVOID_JJ_VCS is unset. If it is set to 0, then use
# jj without warning. If it is set to anything else, do not use jj (so
# eg fall back to git if .git exists.)
avoid = os.getenv("MOZ_AVOID_JJ_VCS")
if avoid is None or avoid == "0":
if avoid is None and not hasattr(get_repository_object, "_warned"):
get_repository_object._warned = True
print(
"""\
Using JujutsuRepository because a .jj/ directory was detected!
Warning: jj support is currently experimental, and may be disabled
by setting the environment variable MOZ_AVOID_JJ_VCS=1.
"""
)
return JujutsuRepository(path, jj=jj, git=git)
if (path / ".git").exists():
elif (path / ".git").exists():
return GitRepository(path, git=git)
if (path / "config" / "milestone.txt").exists():
elif (path / "config" / "milestone.txt").exists():
return SrcRepository(path, src=src)
raise InvalidRepoPath(f"Unknown VCS, or not a source checkout: {path}")
else:
raise InvalidRepoPath(f"Unknown VCS, or not a source checkout: {path}")
def get_repository_from_build_config(config):
@@ -75,10 +58,6 @@ def get_repository_from_build_config(config):
if flavor == "hg":
return HgRepository(Path(config.topsrcdir), hg=config.substs["HG"])
elif flavor == "jj":
return JujutsuRepository(
Path(config.topsrcdir), jj=config.substs["JJ"], git=config.substs["GIT"]
)
elif flavor == "git":
return GitRepository(Path(config.topsrcdir), git=config.substs["GIT"])
elif flavor == "src":
@@ -110,6 +89,4 @@ def get_repository_from_env():
except InvalidRepoPath:
continue
raise MissingVCSInfo(
f"Could not find Mercurial / Git / JJ checkout for {Path.cwd()}"
)
raise MissingVCSInfo(f"Could not find Mercurial or Git checkout for {Path.cwd()}")

View File

@@ -59,10 +59,6 @@ class Repository:
def _run(self, *args, encoding="utf-8", **runargs):
return_codes = runargs.get("return_codes", [])
env = self._env
if "env" in runargs:
env = env.copy()
env.update(runargs["env"])
cmd = (str(self._tool),) + args
# Check if we have a tool, either hg or git. If this is a
@@ -76,7 +72,7 @@ class Repository:
return subprocess.check_output(
cmd,
cwd=self.path,
env=env,
env=self._env,
encoding=encoding,
)
except subprocess.CalledProcessError as e:

View File

@@ -1,346 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this,
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import string
import subprocess
from contextlib import contextmanager
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Union
from mozpack.files import FileListFinder
from mozversioncontrol.errors import (
CannotDeleteFromRootOfRepositoryException,
MissingVCSExtension,
MissingVCSInfo,
)
from mozversioncontrol.repo.base import Repository
from mozversioncontrol.repo.git import GitRepository
class JujutsuRepository(Repository):
"""An implementation of `Repository` for JJ repositories using the git backend."""
def __init__(self, path: Path, jj="jj", git="git"):
super(JujutsuRepository, self).__init__(path, tool=jj)
self._git = GitRepository(path, git=git)
# Find git root. Newer jj has `jj git root`, but this should support
# older versions for now.
out = self._run("root")
if not out:
raise MissingVCSInfo("cannot find jj workspace root")
try:
jj_ws_root = Path(out.rstrip())
jj_repo = jj_ws_root / ".jj" / "repo"
if not jj_repo.is_dir():
jj_repo = Path(jj_repo.read_text())
except Exception:
raise MissingVCSInfo("cannot find jj repo")
try:
git_target = jj_repo / "store" / "git_target"
git_dir = git_target.parent / Path(git_target.read_text())
except Exception:
raise MissingVCSInfo("cannot find git dir")
if not git_dir.is_dir():
raise MissingVCSInfo("cannot find git dir")
self._git._env["GIT_DIR"] = str(git_dir.resolve())
def resolve_to_change(self, revset: str) -> Optional[str]:
change_id = self._run(
"log", "--no-graph", "-n1", "-r", revset, "-T", "change_id.short()"
).rstrip()
return change_id if change_id != "" else None
@property
def name(self):
return "jj"
@property
def head_ref(self):
# This is not really a defined concept in jj. Map it to @, or rather the
# persistent change id for the current @. Warning: this cannot be passed
# directly to a git command, it must be converted to a commit id first
# (eg via convert_change_to_commit). This isn't done here because
# callers should be aware when they're dropping down to git semantics.
return self.resolve_to_change("@")
@property
def base_ref(self):
ref = self.resolve_to_change("latest(roots(::@ & mutable())-)")
return ref if ref else self.head_ref
def convert_change_to_commit(self, change_id):
commit = self._run(
"log", "--no-graph", "-r", f"latest({change_id})", "-T", "commit_id"
).rstrip()
return commit
def base_ref_as_hg(self):
base_ref = self.convert_change_to_commit(self.base_ref)
try:
return self._git._run("cinnabar", "git2hg", base_ref).strip()
except subprocess.CalledProcessError:
return
@property
def branch(self):
# jj does not have an "active branch" concept. Invent something similar,
# the latest bookmark in the descendants of @.
bookmark = self._run(
"log", "--no-graph", "-r", "latest(::@ & bookmarks())", "-T", "bookmarks"
)
return bookmark or None
@property
def has_git_cinnabar(self):
return self._git.has_git_cinnabar
def get_commit_time(self):
return int(
self.run(
"log", "-n1", "--no-graph", "-T", 'commit_timestamp(self).format("%s")'
).strip()
)
def sparse_checkout_present(self):
return self.run("sparse", "list").rstrip() != "."
def get_user_email(self):
email = self._run("config", "get", "user.email", return_codes=[0, 1])
if not email:
return None
return email.strip()
def get_changed_files(self, diff_filter="ADM", mode="(ignored)", rev="@"):
assert all(f.lower() in self._valid_diff_filter for f in diff_filter)
out = self._run(
"log",
"-r",
rev,
"--no-graph",
"-T",
'diff.files().map(|f| surround("", "\n", separate("\t", f.status(), f.source().path(), f.target().path()))).join("")',
)
changed = []
for line in out.splitlines():
op, source, target = line.split("\t")
if op == "modified":
if "M" in diff_filter:
changed.append(source)
elif op == "added":
if "A" in diff_filter:
changed.append(source)
elif op == "removed":
if "D" in diff_filter:
changed.append(source)
elif op == "copied":
if "A" in diff_filter:
changed.append(target)
elif op == "renamed":
if "A" in diff_filter:
changed.append(target)
if "D" in diff_filter:
changed.append(source)
else:
raise Exception(f"unexpected jj file status '{op}'")
return changed
def get_outgoing_files(self, diff_filter="ADM", upstream=None):
assert all(f.lower() in self._valid_diff_filter for f in diff_filter)
if upstream is None:
upstream = self.base_ref
lines = self._run(
"diff",
"--from",
upstream,
"--to",
"@",
"--summary",
).splitlines()
outgoing = []
for line in lines:
op, file = line.split(" ", 1)
if op.upper() in diff_filter:
outgoing.append(file)
return outgoing
def add_remove_files(self, *paths: Union[str, Path]):
if not paths:
return
paths = [str(path) for path in paths]
self._run("file", "track", *paths)
def forget_add_remove_files(self, *paths: Union[str, Path]):
if not paths:
return
paths = [str(path) for path in paths]
self._run("file", "untrack", *paths)
def get_tracked_files_finder(self, path=None):
return FileListFinder(self._run("file", "list").splitlines())
def get_ignored_files_finder(self):
raise Exception("unimplemented")
def working_directory_clean(self, untracked=False, ignored=False):
# Working directory is in the top commit.
return True
def update(self, ref):
self._run("new", ref)
def edit(self, ref):
self._run("edit", ref)
def clean_directory(self, path: Union[str, Path]):
if Path(self.path).samefile(path):
raise CannotDeleteFromRootOfRepositoryException()
self._run("restore", "-r", "@-", str(path))
def commit(self, message, author=None, date=None, paths=None):
run_kwargs = {}
cmd = ["commit", "-m", message]
if author:
cmd += ["--author", author]
if date:
dt = datetime.strptime(date, "%Y-%m-%d %H:%M:%S %z")
run_kwargs["env"] = {"JJ_TIMESTAMP": dt.isoformat()}
if paths:
cmd.extend(paths)
self._run(*cmd, **run_kwargs)
def push_to_try(
self,
message: str,
changed_files: Dict[str, str] = {},
allow_log_capture: bool = False,
):
if not self.has_git_cinnabar:
raise MissingVCSExtension("cinnabar")
with self.try_commit(message, changed_files) as head:
self._run("git", "remote", "remove", "mach_tryserver", return_codes=[0, 1])
# `jj git remote add` would barf on the cinnabar syntax here.
self._git._run(
"remote", "add", "mach_tryserver", "hg::ssh://hg.mozilla.org/try"
)
self._run("git", "import")
cmd = (
str(self._tool),
"git",
"push",
"--remote",
"mach_tryserver",
"--change",
head,
"--allow-new",
"--allow-empty-description",
)
if allow_log_capture:
self._push_to_try_with_log_capture(
cmd,
{
"stdout": subprocess.PIPE,
"stderr": subprocess.STDOUT,
"cwd": self.path,
"universal_newlines": True,
"bufsize": 1,
},
)
else:
subprocess.check_call(cmd, cwd=self.path)
self._run("git", "remote", "remove", "mach_tryserver", return_codes=[0, 1])
def set_config(self, name, value):
self._run("config", name, value)
def get_branch_nodes(self, head: Optional[str] = "@") -> List[str]:
"""Return a list of commit SHAs for nodes on the current branch, in order that they should be applied."""
# Note: lando gets grumpy if you try to push empty commits.
return list(
reversed(
self._run(
"log",
"--no-graph",
"-r",
f"(::{head} & mutable()) ~ empty()",
"-T",
'commit_id ++ "\n"',
).splitlines()
)
)
def looks_like_change_id(self, id):
return len(id) > 0 and all(letter >= "k" and letter <= "z" for letter in id)
def looks_like_commit_id(self, id):
return len(id) > 0 and all(letter in string.hexdigits for letter in id)
def get_commit_patches(self, nodes: List[str]) -> List[bytes]:
"""Return the contents of the patch `node` in the git standard format."""
# Warning: tests, at least, may call this with change ids rather than
# commit ids.
nodes = [
id if self.looks_like_commit_id(id) else self.convert_change_to_commit(id)
for id in nodes
]
return [
self._git._run(
"format-patch", node, "-1", "--always", "--stdout", encoding=None
)
for node in nodes
]
@contextmanager
def try_commit(
self, commit_message: str, changed_files: Optional[Dict[str, str]] = None
):
"""Create a temporary try commit as a context manager.
Create a new commit using `commit_message` as the commit message. The commit
may be empty, for example when only including try syntax.
`changed_files` may contain a dict of file paths and their contents,
see `stage_changes`.
"""
opid = self._run(
"operation", "log", "-n1", "--no-graph", "-T", "id.short(16)"
).rstrip()
try:
self._run("new", "-m", commit_message, "latest((@ | @-) ~ empty())")
for path, content in (changed_files or {}).items():
p = self.path / Path(path)
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(content)
yield self.resolve_to_change("@")
finally:
self._run("operation", "restore", opid)
def get_last_modified_time_for_file(self, path: Path) -> datetime:
"""Return last modified in VCS time for the specified file."""
date = self._run(
"log",
"--no-graph",
"-n1",
"-T",
"committer.timestamp()",
str(path),
).rstrip()
return datetime.strptime(date, "%Y-%m-%d %H:%M:%S.%f %z")

View File

@@ -6,13 +6,9 @@ import os
import shutil
import subprocess
from pathlib import Path
from typing import List
import pytest
# Execute the first element in each list of steps within a `repo` directory,
# then copy the whole directory to a `remoterepo`, and finally execute the
# second element on just `repo`.
SETUP = {
"hg": [
"""
@@ -44,32 +40,11 @@ SETUP = {
git branch -u upstream/master
""",
],
"jj": [
"""
echo "foo" > foo
echo "bar" > bar
git init
git config user.name "Testing McTesterson"
git config user.email "<test@example.org>"
git add *
git commit -am "Initial commit"
""",
"""
# Pass in user name/email via env vars because the initial commit
# will use them before we have a chance to configure them.
JJ_USER="Testing McTesterson" JJ_EMAIL="test@example.org" jj git init --colocate
jj config set --repo user.name "Testing McTesterson"
jj config set --repo user.email "test@example.org"
jj git remote add upstream ../remoterepo
jj git fetch --remote upstream
jj bookmark track master@upstream
""",
],
}
class RepoTestFixture:
def __init__(self, repo_dir: Path, vcs: str, steps: List[str]):
def __init__(self, repo_dir: Path, vcs: str, steps: [str]):
self.dir = repo_dir
self.vcs = vcs
@@ -86,13 +61,8 @@ def shell(cmd, working_dir):
subprocess.check_call(step, shell=True, cwd=working_dir)
@pytest.fixture(params=["git", "hg", "jj"])
@pytest.fixture(params=["git", "hg"])
def repo(tmpdir, request):
if request.param == "jj":
avoid = os.getenv("MOZ_AVOID_JJ_VCS")
if avoid and avoid != "0":
pytest.skip("jj support disabled")
tmpdir = Path(tmpdir)
vcs = request.param
steps = SETUP[vcs]

View File

@@ -25,22 +25,12 @@ STEPS = {
git commit -a -m "second commit"
""",
],
"jj": [
"""
jj bookmark set test
""",
"""
jj new -m "xyzzy" zzzzzzzz
jj new -m "second commit" test
echo "bar" > foo
""",
],
}
def test_branch(repo):
vcs = get_repository_object(repo.dir)
if vcs.name in ("git", "jj"):
if vcs.name == "git":
assert vcs.branch == "master"
else:
assert vcs.branch is None
@@ -52,23 +42,11 @@ def test_branch(repo):
assert vcs.branch == "test"
vcs.update(vcs.head_ref)
if repo.vcs == "jj":
# jj "branches" do not auto-advance (in our JujutsuRepository
# implementation, anyway), so this is the rev marked as the root of the
# test branch.
assert vcs.branch == "test"
else:
assert vcs.branch is None
assert vcs.branch is None
vcs.update("test")
assert vcs.branch == "test"
# for jj only, check that a topological branch with no bookmarks is not
# considered a "branch":
if repo.vcs == "jj":
vcs.update("description('xyzzy')")
assert vcs.branch is None
if __name__ == "__main__":
mozunit.main()

View File

@@ -11,25 +11,12 @@ from mozversioncontrol import get_repository_object
STEPS = {
"hg": [
"",
"""
echo "bar" >> bar
echo "baz" > foo
""",
],
"git": [
"",
"""
echo "bar" >> bar
echo "baz" > foo
""",
],
"jj": [
"""
jj describe -m 'Ignore file for testing'
echo foo > .gitignore
jj new
""",
"""
echo "bar" >> bar
echo "baz" > foo
@@ -42,14 +29,9 @@ def test_commit(repo):
vcs = get_repository_object(repo.dir)
assert vcs.working_directory_clean()
# Setup step for jj to allow untracked changes.
repo.execute_next_step()
# Modify both foo and bar
repo.execute_next_step()
if repo.vcs != "jj":
# jj never has a dirty working directory.
assert not vcs.working_directory_clean()
assert not vcs.working_directory_clean()
date_string = "2017-07-14 02:40:00 +0000"
@@ -66,18 +48,13 @@ def test_commit(repo):
assert original_date == date_from_vcs
# We only committed bar, so foo is still keeping the working dir dirty. jj
# always treats the working directory as clean, because the top commit holds
# any changes in it.
if repo.vcs == "jj":
assert vcs.working_directory_clean()
else:
assert not vcs.working_directory_clean()
# We only committed bar, so foo is still keeping the working dir dirty
assert not vcs.working_directory_clean()
if repo.vcs == "git":
log_cmd = ["log", "-1", "--format=%an,%ae,%aD,%B"]
patch_cmd = ["log", "-1", "-p"]
elif repo.vcs == "hg":
else:
log_cmd = [
"log",
"-l",
@@ -86,18 +63,8 @@ def test_commit(repo):
"{person(author)},{email(author)},{date|rfc822date},{desc}",
]
patch_cmd = ["log", "-l", "1", "-p"]
elif repo.vcs == "jj":
log_cmd = [
"log",
"-n1",
"--no-graph",
"-r@-",
"-T",
'separate(",", author.name(), author.email(), commit_timestamp(self).format("%a, %d %b %Y %H:%M:%S %z"), description)',
]
patch_cmd = ["show", "@-"]
# Verify commit metadata (we rstrip to normalize trivial differences)
# Verify commit metadata (we rstrip to normalize trivial git/hg differences)
log = vcs._run(*log_cmd).rstrip()
assert log == (
"Testing McTesterson,test@example.org,Fri, 14 "

View File

@@ -8,25 +8,19 @@ from mozversioncontrol import get_repository_object
def test_context_manager(repo):
cmd = {
"git": ["show", "--no-patch"],
"hg": ["tip"],
"jj": ["show", "@-"],
}[repo.vcs]
is_git = repo.vcs == "git"
cmd = ["show", "--no-patch"] if is_git else ["tip"]
vcs = get_repository_object(repo.dir)
output_subprocess = vcs._run(*cmd)
if repo.vcs == "hg":
assert vcs._client.server is None
assert is_git or vcs._client.server is None
assert "Initial commit" in output_subprocess
with vcs:
if repo.vcs == "hg":
assert vcs._client.server is not None
assert is_git or vcs._client.server is not None
output_client = vcs._run(*cmd)
if repo.vcs == "hg":
assert vcs._client.server is None
assert is_git or vcs._client.server is None
assert output_subprocess == output_client

View File

@@ -26,14 +26,6 @@ STEPS = {
git commit -m "commit 2"
"""
],
"jj": [
"""
jj new -m "commit 1"
echo bar >> bar
jj commit -m "commit 2"
echo baz > baz
"""
],
}

View File

@@ -30,16 +30,6 @@ STEPS = {
git commit -m "SECOND PATCH"
""",
],
"jj": [
"""
jj new -m "FIRST PATCH"
echo bar >> bar
""",
"""
jj new -m "SECOND PATCH"
printf "baz\\r\\nqux" > baz
""",
],
}

View File

@@ -16,11 +16,10 @@ STEPS = {
git remote add try hg::https://hg.mozilla.org/try
""",
],
"jj": [],
}
def test_get_mozilla_remote_args(repo):
def test_get_upstream_remotes(repo):
# Test is only relevant for Git.
if not repo.vcs == "git":
return

View File

@@ -16,7 +16,6 @@ STEPS = {
git remote add try hg::https://hg.mozilla.org/try
""",
],
"jj": [],
}

View File

@@ -77,7 +77,7 @@ def test_push_to_try(repo, monkeypatch):
(str(tool), "revert", "-a"),
]
expected_inputs = []
elif repo.vcs == "git":
else:
expected = [
(str(tool), "cinnabar", "--version"),
(str(tool), "rev-parse", "HEAD"),
@@ -133,46 +133,6 @@ def test_push_to_try(repo, monkeypatch):
"""
),
]
else:
assert repo.vcs == "jj"
expected = [
(str(vcs._git._tool), "cinnabar", "--version"),
(str(tool), "operation", "log", "-n1", "--no-graph", "-T", "id.short(16)"),
(str(tool), "new", "-m", "commit message", "latest((@ | @-) ~ empty())"),
(
str(tool),
"log",
"--no-graph",
"-n1",
"-r",
"@",
"-T",
"change_id.short()",
),
(str(tool), "git", "remote", "remove", "mach_tryserver"),
(
str(vcs._git._tool),
"remote",
"add",
"mach_tryserver",
"hg::ssh://hg.mozilla.org/try",
),
(str(tool), "git", "import"),
(
str(tool),
"git",
"push",
"--remote",
"mach_tryserver",
"--change",
None,
"--allow-new",
"--allow-empty-description",
),
(str(tool), "operation", "restore", ""),
(str(tool), "git", "remote", "remove", "mach_tryserver"),
]
expected_inputs = []
for i, value in enumerate(captured_commands):
assert value == expected[i]
@@ -186,7 +146,7 @@ def test_push_to_try(repo, monkeypatch):
def test_push_to_try_missing_extensions(repo, monkeypatch):
if repo.vcs not in ("git", "jj"):
if repo.vcs != "git":
return
vcs = get_repository_object(repo.dir)
@@ -200,8 +160,6 @@ def test_push_to_try_missing_extensions(repo, monkeypatch):
return orig(*args, **kwargs)
monkeypatch.setattr(vcs, "_run", cinnabar_raises)
if hasattr(vcs, "_git"):
monkeypatch.setattr(vcs._git, "_run", cinnabar_raises)
with pytest.raises(MissingVCSExtension):
vcs.push_to_try("commit message")

View File

@@ -6,20 +6,17 @@ import mozunit
import pytest
from mozversioncontrol import get_repository_object
from mozversioncontrol.errors import MissingVCSExtension
@pytest.mark.xfail(reason="Requires the Mercurial evolve extension.", strict=False)
def test_try_commit(repo):
commit_message = "try commit message"
vcs = get_repository_object(repo.dir)
initial_head_ref = vcs.head_ref
# Create a non-empty commit.
try:
with vcs.try_commit(commit_message, {"try_task_config.json": "{}"}) as head:
assert vcs.get_changed_files(rev=head) == ["try_task_config.json"]
except MissingVCSExtension:
pytest.xfail("Requires the Mercurial evolve extension.")
with vcs.try_commit(commit_message, {"try_task_config.json": "{}"}) as head:
assert vcs.get_changed_files(rev=head) == ["try_task_config.json"]
assert (
vcs.head_ref == initial_head_ref

View File

@@ -31,16 +31,6 @@ STEPS = {
echo "foobar" > foo
""",
],
"jj": [
"""
echo "bar" >> bar
echo "baz" > foo
jj commit -m "second commit"
""",
"""
echo "foobar" > foo
""",
],
}
@@ -48,35 +38,25 @@ def test_update(repo):
vcs = get_repository_object(repo.dir)
rev0 = vcs.head_ref
# Create a commit with modified `foo` and `bar`.
repo.execute_next_step()
rev1 = vcs.head_ref
assert rev0 != rev1
if repo.vcs == "hg":
vcs.update(".~1")
elif repo.vcs == "git":
else:
vcs.update("HEAD~1")
elif repo.vcs == "jj":
vcs.edit("@-")
assert vcs.head_ref == rev0
if repo.vcs != "jj":
vcs.update(rev1)
else:
vcs.update(rev0)
rev1 = vcs.head_ref
vcs.update(rev1)
assert vcs.head_ref == rev1
# Modify `foo` and update. Should fail with dirty working directory.
# Update should fail with dirty working directory.
repo.execute_next_step()
if repo.vcs != "jj":
with pytest.raises(CalledProcessError):
vcs.update(rev0)
assert vcs.head_ref == rev1
else:
# jj doesn't have a "dirty working directory".
pass
with pytest.raises(CalledProcessError):
vcs.update(rev0)
assert vcs.head_ref == rev1
if __name__ == "__main__":

View File

@@ -47,23 +47,6 @@ STEPS = {
git commit -m "Modify baz; add baby"
""",
],
"jj": [
"""
echo "bar" >> bar
echo "baz" > baz
rm foo
""",
"""
jj commit -m "Remove foo; modify bar; add baz"
""",
"""
echo ooka >> baz
echo newborn > baby
""",
"""
jj describe -m "Modify baz; add baby"
""",
],
}
@@ -75,11 +58,7 @@ def test_workdir_outgoing(repo):
vcs = get_repository_object(repo.dir)
assert vcs.path == str(repo.dir)
remote_path = {
"hg": "../remoterepo",
"git": "upstream/master",
"jj": "master@upstream",
}[repo.vcs]
remote_path = "../remoterepo" if repo.vcs == "hg" else "upstream/master"
# Mutate files.
repo.execute_next_step()
@@ -89,14 +68,11 @@ def test_workdir_outgoing(repo):
assert_files(vcs.get_changed_files("D", "all"), ["foo"])
if repo.vcs == "git":
assert_files(vcs.get_changed_files("AM", mode="staged"), ["baz"])
else:
# Mercurial and jj do not use a staging area (and ignore the mode
# parameter.)
elif repo.vcs == "hg":
# Mercurial does not use a staging area (and ignores the mode parameter.)
assert_files(vcs.get_changed_files("AM", "unstaged"), ["bar", "baz"])
if repo.vcs != "jj":
# Everything is already committed in jj, and therefore outgoing.
assert_files(vcs.get_outgoing_files("AMD"), [])
assert_files(vcs.get_outgoing_files("AMD", remote_path), [])
assert_files(vcs.get_outgoing_files("AMD"), [])
assert_files(vcs.get_outgoing_files("AMD", remote_path), [])
# Create a commit.
repo.execute_next_step()
@@ -121,22 +97,11 @@ def test_workdir_outgoing(repo):
if repo.vcs == "git":
assert_files(vcs.get_changed_files("AM", rev="HEAD~1"), ["bar", "baz"])
assert_files(vcs.get_changed_files("AM", rev="HEAD"), ["baby", "baz"])
elif repo.vcs == "hg":
else:
assert_files(vcs.get_changed_files("AM", rev=".^"), ["bar", "baz"])
assert_files(vcs.get_changed_files("AM", rev="."), ["baby", "baz"])
assert_files(vcs.get_changed_files("AM", rev=".^::"), ["bar", "baz", "baby"])
assert_files(vcs.get_changed_files("AM", rev="modifies(baz)"), ["baz", "baby"])
elif repo.vcs == "jj":
assert_files(vcs.get_changed_files("AM", rev="@-"), ["bar", "baz"])
assert_files(vcs.get_changed_files("AM", rev="@"), ["baby", "baz"])
assert_files(vcs.get_changed_files("AM", rev="@-::"), ["bar", "baz", "baby"])
# Currently no direct equivalent of `modifies(baz)`. `files(baz)` will
# also select changes that added or deleted baz, and the diff_filter
# will applied be too late.
assert_files(
vcs.get_changed_files("AMD", rev="files(baz)"),
["foo", "baz", "baby", "bar"],
)
if __name__ == "__main__":

View File

@@ -27,14 +27,10 @@ STEPS = {
git commit -am "Remove foo; modify bar; touch baz (but don't add it)"
""",
],
"jj": [],
}
def test_working_directory_clean_untracked_files(repo):
if repo.vcs == "jj":
return
vcs = get_repository_object(repo.dir)
assert vcs.working_directory_clean()

View File

@@ -33,7 +33,6 @@ from mozbuild.base import MozbuildObject
from mozversioncontrol import (
GitRepository,
HgRepository,
JujutsuRepository,
)
TOKEN_FILE = (
@@ -41,7 +40,7 @@ TOKEN_FILE = (
)
# The supported variants of `Repository` for this workflow.
SupportedVcsRepository = Union[GitRepository, HgRepository, JujutsuRepository]
SupportedVcsRepository = Union[GitRepository, HgRepository]
here = os.path.abspath(os.path.dirname(__file__))
build = MozbuildObject.from_environment(cwd=here)
@@ -402,7 +401,6 @@ def push_to_lando_try(
PATCH_FORMAT_STRING_MAPPING = {
GitRepository: "git-format-patch",
HgRepository: "hgexport",
JujutsuRepository: "git-format-patch",
}
patch_format = PATCH_FORMAT_STRING_MAPPING.get(type(vcs))
if not patch_format: