|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | | -import time |
| 3 | +import sys |
4 | 4 | import uuid |
| 5 | +from dataclasses import dataclass |
| 6 | +from datetime import datetime |
5 | 7 | from pathlib import Path |
6 | 8 | from typing import TYPE_CHECKING, NamedTuple |
7 | 9 |
|
8 | | -from deprecated import deprecated |
| 10 | +import pytest |
9 | 11 |
|
10 | | -from commitizen import cmd, exceptions, git |
| 12 | +from commitizen import cli, cmd, exceptions, git |
11 | 13 |
|
12 | 14 | if TYPE_CHECKING: |
| 15 | + from freezegun.api import FrozenDateTimeFactory |
| 16 | + from pytest_mock import MockerFixture |
| 17 | + |
13 | 18 | from commitizen.version_schemes import Increment, Prerelease |
14 | 19 |
|
15 | 20 |
|
@@ -61,36 +66,106 @@ def merge_branch(branch: str): |
61 | 66 | raise exceptions.GitCommandError(c.err) |
62 | 67 |
|
63 | 68 |
|
64 | | -def get_current_branch() -> str: |
65 | | - c = cmd.run("git rev-parse --abbrev-ref HEAD") |
66 | | - if c.return_code != 0: |
67 | | - raise exceptions.GitCommandError(c.err) |
68 | | - return c.out |
69 | | - |
70 | | - |
71 | 69 | def create_tag(tag: str, message: str | None = None) -> None: |
72 | 70 | c = git.tag(tag, annotated=(message is not None), msg=message) |
73 | 71 | if c.return_code != 0: |
74 | 72 | raise exceptions.CommitError(c.err) |
75 | 73 |
|
76 | 74 |
|
77 | | -@deprecated( |
78 | | - reason="\n\ |
79 | | -Prefer using `create_file_and_commit(filename, committer_date={your_date})` to influence the order of tags.\n\ |
80 | | -This is because lightweight tags (like the ones created here) use the commit's creatordate which we can specify \ |
81 | | -with the GIT_COMMITTER_DATE flag, instead of waiting entire seconds during tests." |
82 | | -) |
83 | | -def wait_for_tag(): |
84 | | - """Deprecated -- use `create_file_and_commit(filename, committer_date={your_date})` to order tags instead |
85 | | -
|
86 | | - Wait for tag. |
87 | | -
|
88 | | - The resolution of timestamps is 1 second, so we need to wait |
89 | | - to create another tag unfortunately. |
90 | | -
|
91 | | - This means: |
92 | | - If we create 2 tags under the same second, they might be returned in the wrong order |
| 75 | +@dataclass |
| 76 | +class UtilFixture: |
| 77 | + """ |
| 78 | + An helper fixture providing most common operations for tests. |
93 | 79 |
|
94 | | - See https://stackoverflow.com/questions/28237043/what-is-the-resolution-of-gits-commit-date-or-author-date-timestamps |
| 80 | + git and cli operations grant control over time. |
95 | 81 | """ |
96 | | - time.sleep(1.1) |
| 82 | + |
| 83 | + mocker: MockerFixture |
| 84 | + monkeypatch: pytest.MonkeyPatch |
| 85 | + freezer: FrozenDateTimeFactory |
| 86 | + |
| 87 | + def __post_init__(self): |
| 88 | + self.patch_env() |
| 89 | + |
| 90 | + def create_file_and_commit( |
| 91 | + self, |
| 92 | + message: str, |
| 93 | + filename: str | None = None, |
| 94 | + committer_date: str | None = None, |
| 95 | + ): |
| 96 | + """Create a file and commit it.""" |
| 97 | + if not filename: |
| 98 | + filename = str(uuid.uuid4()) |
| 99 | + |
| 100 | + Path(filename).touch() |
| 101 | + c = cmd.run("git add .") |
| 102 | + if c.return_code != 0: |
| 103 | + raise exceptions.CommitError(c.err) |
| 104 | + c = git.commit(message, committer_date=committer_date) |
| 105 | + if c.return_code != 0: |
| 106 | + raise exceptions.CommitError(c.err) |
| 107 | + self.tick() |
| 108 | + |
| 109 | + def branch(self, name: str): |
| 110 | + """Create a new branch.""" |
| 111 | + c = cmd.run(f"git branch {name}") |
| 112 | + if c.return_code != 0: |
| 113 | + raise exceptions.GitCommandError(c.err) |
| 114 | + |
| 115 | + def switch_branch(self, branch: str): |
| 116 | + """Switch to given branch.""" |
| 117 | + c = cmd.run(f"git switch {branch}") |
| 118 | + if c.return_code != 0: |
| 119 | + raise exceptions.GitCommandError(c.err) |
| 120 | + |
| 121 | + def merge_branch(self, branch: str): |
| 122 | + """Merge given branch into current branch.""" |
| 123 | + c = cmd.run(f"git merge {branch}") |
| 124 | + if c.return_code != 0: |
| 125 | + raise exceptions.GitCommandError(c.err) |
| 126 | + self.tick() |
| 127 | + |
| 128 | + def current_branch(self) -> str: |
| 129 | + """Get current git branch name.""" |
| 130 | + c = cmd.run("git rev-parse --abbrev-ref HEAD") |
| 131 | + if c.return_code != 0: |
| 132 | + raise exceptions.GitCommandError(c.err) |
| 133 | + return c.out |
| 134 | + |
| 135 | + def tag( |
| 136 | + self, tag: str, message: str | None = None, annotated: bool | None = None |
| 137 | + ) -> None: |
| 138 | + """Create a git tag.""" |
| 139 | + c = git.tag( |
| 140 | + tag, annotated=(annotated is True or message is not None), msg=message |
| 141 | + ) |
| 142 | + if c.return_code != 0: |
| 143 | + raise exceptions.CommitError(c.err) |
| 144 | + self.tick() |
| 145 | + |
| 146 | + def cli(self, *args: str): |
| 147 | + """Execute commitizen CLI with given args.""" |
| 148 | + self.mocker.patch.object(sys, "argv", ["cz", *args]) |
| 149 | + cli.main() |
| 150 | + self.tick() |
| 151 | + |
| 152 | + def patch_env(self): |
| 153 | + """Patch environment variables to sync with FreezeGun time.""" |
| 154 | + self.monkeypatch.setenv("DATE", datetime.now().isoformat()) |
| 155 | + self.monkeypatch.setenv("GIT_AUTHOR_DATE", datetime.now().isoformat()) |
| 156 | + self.monkeypatch.setenv("GIT_COMMITTER_DATE", datetime.now().isoformat()) |
| 157 | + |
| 158 | + def tick(self): |
| 159 | + """Advance time by 1 second.""" |
| 160 | + self.freezer.tick() |
| 161 | + self.patch_env() |
| 162 | + |
| 163 | + |
| 164 | +@pytest.fixture |
| 165 | +def util( |
| 166 | + monkeypatch: pytest.MonkeyPatch, |
| 167 | + mocker: MockerFixture, |
| 168 | + freezer: FrozenDateTimeFactory, |
| 169 | +) -> UtilFixture: |
| 170 | + """An helper fixture""" |
| 171 | + return UtilFixture(mocker=mocker, monkeypatch=monkeypatch, freezer=freezer) |
0 commit comments