Coverage for tests/helpers.py: 100.00%
42 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-02 00:26 +0200
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-02 00:26 +0200
1"""Helpers for writing tests."""
3from __future__ import annotations
5import os
6import random
7import shutil
8import subprocess
9import uuid
10from contextlib import contextmanager
11from typing import TYPE_CHECKING, Iterator
13if TYPE_CHECKING:
14 from pathlib import Path
17class GitRepo:
18 """Test utility class to initalize and work with a Git repository."""
20 _git_exec = shutil.which("git") or "git"
22 def __init__(self, repo: Path) -> None:
23 """Initialization the Git repository wrapper.
25 Initializes a new Git repository under the given path.
27 Parameters:
28 repo: Path to the git repository.
29 """
30 self.path = repo
31 self.path.mkdir(parents=True, exist_ok=True)
32 self.git("init", "-b", "main")
33 self.git("config", "user.name", "dummy")
34 self.git("config", "user.email", "dummy@example.com")
35 self.git("remote", "add", "origin", "git@github.com:example/example")
36 self.first_hash = self.commit("chore: Initial repository creation")
38 def git(self, *args: str) -> str:
39 """Run a Git command in the repository.
41 Parameters:
42 *args: Arguments passed to the Git command.
44 Returns:
45 The output of the command.
46 """
47 return subprocess.check_output(
48 [self._git_exec, "-C", str(self.path), *args], # noqa: S603
49 text=True,
50 )
52 def commit(self, message: str) -> str:
53 """Create, add and commit a new file into the Git repository.
55 Parameters:
56 message: The commit message.
58 Returns:
59 The Git commit hash.
60 """
61 with self.path.joinpath(str(uuid.uuid4())).open("w") as fh:
62 fh.write(str(random.randint(0, 1))) # noqa: S311
63 self.git("add", "-A")
64 self.git("commit", "-m", message)
65 return self.git("rev-parse", "HEAD").rstrip()
67 def tag(self, tagname: str) -> None:
68 """Create a new tag in the GIt repository.
70 Parameters:
71 tagname: The name of the new tag.
72 """
73 self.git("tag", tagname)
75 def branch(self, branchname: str) -> None:
76 """Create a new branch in the Git repository.
78 Parameters:
79 branchname: The name of the new branch.
80 """
81 self.git("branch", branchname)
83 def checkout(self, branchname: str) -> None:
84 """Checkout a branch.
86 Parameters:
87 branchname: The name of the branch.
88 """
89 self.git("checkout", branchname)
91 def merge(self, branchname: str) -> str:
92 """Merge a branch into the current branch, creating a new merge commit.
94 Parameters:
95 branchname: The name of the branch to merge.
97 Returns:
98 The Git commit hash of the merge commit.
99 """
100 self.git("merge", "--no-ff", "--commit", "-m", f"merge: Merge branch '{branchname}'", branchname)
101 return self.git("rev-parse", "HEAD").rstrip()
103 @contextmanager
104 def enter(self) -> Iterator[None]:
105 """Context manager to enter the repository directory."""
106 old_cwd = os.getcwd()
107 os.chdir(self.path)
108 try:
109 yield
110 finally:
111 os.chdir(old_cwd)