File: test_main.py

package info (click to toggle)
python-semantic-release 10.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,112 kB
  • sloc: python: 36,523; sh: 340; makefile: 156
file content (264 lines) | stat: -rw-r--r-- 7,493 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
from __future__ import annotations

import json
import subprocess
from pathlib import Path
from textwrap import dedent
from typing import TYPE_CHECKING

import git
import pytest
from click.testing import CliRunner
from pytest_lazy_fixtures.lazy_fixture import lf as lazy_fixture

from semantic_release import __version__

from tests.const import MAIN_PROG_NAME, SUCCESS_EXIT_CODE, VERSION_SUBCMD
from tests.fixtures.repos import repo_w_no_tags_conventional_commits
from tests.util import assert_exit_code, assert_successful_exit_code

if TYPE_CHECKING:
    from pathlib import Path

    from tests.conftest import RunCliFn
    from tests.e2e.conftest import StripLoggingMessagesFn
    from tests.fixtures.example_project import ExProjectDir, UpdatePyprojectTomlFn
    from tests.fixtures.git_repo import BuiltRepoResult


@pytest.mark.parametrize(
    "project_script_name",
    [
        "python-semantic-release",
        "semantic-release",
        "psr",
    ],
)
def test_entrypoint_scripts(project_script_name: str):
    # Setup
    command = str.join(" ", [project_script_name, "--version"])
    expected_output = f"semantic-release, version {__version__}\n"

    # Act
    proc = subprocess.run(  # noqa: S602, PLW1510
        command, shell=True, text=True, capture_output=True
    )

    # Evaluate
    assert SUCCESS_EXIT_CODE == proc.returncode  # noqa: SIM300
    assert expected_output == proc.stdout
    assert not proc.stderr


def test_main_prints_version_and_exits(run_cli: RunCliFn):
    cli_cmd = [MAIN_PROG_NAME, "--version"]

    # Act
    result = run_cli(cli_cmd[1:])

    # Evaluate
    assert_successful_exit_code(result, cli_cmd)
    assert result.output == f"semantic-release, version {__version__}\n"


def test_main_no_args_passes_w_help_text():
    from semantic_release.cli.commands.main import main

    cli_cmd = [MAIN_PROG_NAME]
    result = CliRunner().invoke(main, prog_name=cli_cmd[0])
    assert_successful_exit_code(result, cli_cmd)
    assert "Usage: " in result.output


@pytest.mark.parametrize(
    "repo_result",
    [lazy_fixture(repo_w_no_tags_conventional_commits.__name__)],
)
def test_not_a_release_branch_exit_code(
    repo_result: BuiltRepoResult, run_cli: RunCliFn
):
    # Run anything that doesn't trigger the help text
    repo_result["repo"].git.checkout("-b", "branch-does-not-exist")

    # Act
    cli_cmd = [MAIN_PROG_NAME, VERSION_SUBCMD, "--no-commit"]
    result = run_cli(cli_cmd[1:])

    # Evaluate
    assert_successful_exit_code(result, cli_cmd)


@pytest.mark.parametrize(
    "repo_result",
    [lazy_fixture(repo_w_no_tags_conventional_commits.__name__)],
)
def test_not_a_release_branch_exit_code_with_strict(
    repo_result: BuiltRepoResult,
    run_cli: RunCliFn,
):
    # Run anything that doesn't trigger the help text
    repo_result["repo"].git.checkout("-b", "branch-does-not-exist")

    # Act
    cli_cmd = [MAIN_PROG_NAME, "--strict", VERSION_SUBCMD, "--no-commit"]
    result = run_cli(cli_cmd[1:])

    # Evaluate
    assert_exit_code(2, result, cli_cmd)


@pytest.mark.parametrize(
    "repo_result",
    [lazy_fixture(repo_w_no_tags_conventional_commits.__name__)],
)
def test_not_a_release_branch_detached_head_exit_code(
    repo_result: BuiltRepoResult,
    run_cli: RunCliFn,
):
    expected_err_msg = (
        "Detached HEAD state cannot match any release groups; no release will be made"
    )

    # cause repo to be in detached head state without file changes
    repo_result["repo"].git.checkout("HEAD", "--detach")

    # Act
    cli_cmd = [MAIN_PROG_NAME, VERSION_SUBCMD, "--no-commit"]
    result = run_cli(cli_cmd[1:])

    # detached head states should throw an error as release branches cannot be determined
    assert_exit_code(1, result, cli_cmd)
    assert expected_err_msg in result.stderr


@pytest.fixture
def toml_file_with_no_configuration_for_psr(tmp_path: Path) -> Path:
    path = tmp_path / "config.toml"
    path.write_text(
        dedent(
            r"""
            [project]
            name = "foo"
            version = "1.2.0"
            """
        )
    )

    return path


@pytest.fixture
def json_file_with_no_configuration_for_psr(tmp_path: Path) -> Path:
    path = tmp_path / "config.json"
    path.write_text(json.dumps({"foo": [1, 2, 3]}))

    return path


@pytest.mark.usefixtures(repo_w_no_tags_conventional_commits.__name__)
def test_default_config_is_used_when_none_in_toml_config_file(
    run_cli: RunCliFn,
    toml_file_with_no_configuration_for_psr: Path,
):
    cli_cmd = [
        MAIN_PROG_NAME,
        "--noop",
        "--config",
        str(toml_file_with_no_configuration_for_psr),
        VERSION_SUBCMD,
    ]

    # Act
    result = run_cli(cli_cmd[1:])

    # Evaluate
    assert_successful_exit_code(result, cli_cmd)


@pytest.mark.usefixtures(repo_w_no_tags_conventional_commits.__name__)
def test_default_config_is_used_when_none_in_json_config_file(
    run_cli: RunCliFn,
    json_file_with_no_configuration_for_psr: Path,
):
    cli_cmd = [
        MAIN_PROG_NAME,
        "--noop",
        "--config",
        str(json_file_with_no_configuration_for_psr),
        VERSION_SUBCMD,
    ]

    # Act
    result = run_cli(cli_cmd[1:])

    # Evaluate
    assert_successful_exit_code(result, cli_cmd)


@pytest.mark.usefixtures(repo_w_no_tags_conventional_commits.__name__)
def test_errors_when_config_file_does_not_exist_and_passed_explicitly(
    run_cli: RunCliFn,
):
    cli_cmd = [
        MAIN_PROG_NAME,
        "--noop",
        "--config",
        "somenonexistantfile.123.txt",
        VERSION_SUBCMD,
    ]

    # Act
    result = run_cli(cli_cmd[1:])

    # Evaluate
    assert_exit_code(2, result, cli_cmd)
    assert "does not exist" in result.stderr


@pytest.mark.usefixtures(repo_w_no_tags_conventional_commits.__name__)
def test_errors_when_config_file_invalid_configuration(
    run_cli: RunCliFn,
    update_pyproject_toml: UpdatePyprojectTomlFn,
    strip_logging_messages: StripLoggingMessagesFn,
):
    # Setup
    update_pyproject_toml("tool.semantic_release.remote.type", "invalidType")
    cli_cmd = [MAIN_PROG_NAME, "--config", "pyproject.toml", VERSION_SUBCMD]

    # Act
    result = run_cli(cli_cmd[1:])

    # preprocess results
    stderr_lines = strip_logging_messages(result.stderr).splitlines()

    # Evaluate
    assert_exit_code(1, result, cli_cmd)
    assert "1 validation error for RawConfig" in stderr_lines[0]
    assert "remote.type" in stderr_lines[1]


def test_uses_default_config_when_no_config_file_found(
    run_cli: RunCliFn,
    example_project_dir: ExProjectDir,
    change_to_ex_proj_dir: None,
):
    # We have to initialise an empty git repository, as the example projects
    # all have pyproject.toml configs which would be used by default
    with git.Repo.init(example_project_dir) as repo:
        repo.git.branch("-M", "main")
        with repo.config_writer("repository") as config:
            config.set_value("user", "name", "semantic release testing")
            config.set_value("user", "email", "not_a_real@email.com")
            config.set_value("commit", "gpgsign", False)
            config.set_value("tag", "gpgsign", False)

        repo.create_remote(name="origin", url="foo@barvcs.com:user/repo.git")
        repo.git.commit("-m", "feat: initial commit", "--allow-empty")

        cli_cmd = [MAIN_PROG_NAME, "--noop", VERSION_SUBCMD]

        # Act
        result = run_cli(cli_cmd[1:])

    # Evaluate
    assert_successful_exit_code(result, cli_cmd)