Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 644675b

Browse files
pan93412Lee-W
authored andcommitted
feat: Determine newline to write with Git
Determine the newline character to write with `git config core.eof`. Close #492
1 parent 9172745 commit 644675b

File tree

8 files changed

+91
-11
lines changed

8 files changed

+91
-11
lines changed

commitizen/bump.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from commitizen.defaults import MAJOR, MINOR, PATCH, bump_message
1010
from commitizen.exceptions import CurrentVersionNotFoundError
11-
from commitizen.git import GitCommit
11+
from commitizen.git import GitCommit, smart_open
1212

1313

1414
def find_increment(
@@ -164,7 +164,7 @@ def update_version_in_files(
164164
)
165165

166166
# Write the file out again
167-
with open(filepath, "w") as file:
167+
with smart_open(filepath, "w") as file:
168168
file.write("".join(version_file))
169169

170170

commitizen/commands/changelog.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
NotAGitProjectError,
1414
NotAllowed,
1515
)
16-
from commitizen.git import GitTag
16+
from commitizen.git import GitTag, smart_open
1717

1818

1919
def similar(a, b):
@@ -89,7 +89,7 @@ def write_changelog(
8989
)
9090

9191
changelog_hook: Optional[Callable] = self.cz.changelog_hook
92-
with open(self.file_name, "w") as changelog_file:
92+
with smart_open(self.file_name, "w") as changelog_file:
9393
partial_changelog: Optional[str] = None
9494
if self.incremental:
9595
new_lines = changelog.incremental_build(
@@ -121,6 +121,9 @@ def __call__(self):
121121
if self.incremental and self.rev_range:
122122
raise NotAllowed("--incremental cannot be combined with a rev_range")
123123

124+
# Don't continue if no `file_name` specified.
125+
assert self.file_name
126+
124127
tags = git.get_tags()
125128
if not tags:
126129
tags = []

commitizen/commands/commit.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
NotAGitProjectError,
1717
NothingToCommitError,
1818
)
19+
from commitizen.git import smart_open
1920

2021

2122
class Commit:
@@ -89,7 +90,7 @@ def __call__(self):
8990
out.error(c.err)
9091

9192
# Create commit backup
92-
with open(self.temp_file, "w") as f:
93+
with smart_open(self.temp_file, "w") as f:
9394
f.write(m)
9495

9596
raise CommitError()

commitizen/commands/init.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from commitizen.cz import registry
1111
from commitizen.defaults import config_files
1212
from commitizen.exceptions import NoAnswersError
13-
from commitizen.git import get_latest_tag_name, get_tag_names
13+
from commitizen.git import get_latest_tag_name, get_tag_names, smart_open
1414

1515

1616
class Init:
@@ -138,7 +138,7 @@ def _install_pre_commit_hook(self):
138138
# .pre-commit-config exists but there's no "repos" key
139139
config_data["repos"] = [cz_hook_config]
140140

141-
with open(pre_commit_config_filename, "w") as config_file:
141+
with smart_open(pre_commit_config_filename, "w") as config_file:
142142
yaml.safe_dump(config_data, stream=config_file)
143143

144144
c = cmd.run("pre-commit install --hook-type commit-msg")

commitizen/config/json_config.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from pathlib import Path
33
from typing import Union
44

5+
from commitizen.git import smart_open
6+
57
from .base_config import BaseConfig
68

79

@@ -13,7 +15,7 @@ def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]):
1315
self.add_path(path)
1416

1517
def init_empty_config_content(self):
16-
with open(self.path, "a") as json_file:
18+
with smart_open(self.path, "a") as json_file:
1719
json.dump({"commitizen": {}}, json_file)
1820

1921
def set_key(self, key, value):
@@ -26,7 +28,7 @@ def set_key(self, key, value):
2628
parser = json.load(f)
2729

2830
parser["commitizen"][key] = value
29-
with open(self.path, "w") as f:
31+
with smart_open(self.path, "w") as f:
3032
json.dump(parser, f, indent=2)
3133
return self
3234

commitizen/config/yaml_config.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import yaml
55

6+
from commitizen.git import smart_open
7+
68
from .base_config import BaseConfig
79

810

@@ -14,7 +16,7 @@ def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]):
1416
self.add_path(path)
1517

1618
def init_empty_config_content(self):
17-
with open(self.path, "a") as json_file:
19+
with smart_open(self.path, "a") as json_file:
1820
yaml.dump({"commitizen": {}}, json_file)
1921

2022
def _parse_setting(self, data: Union[bytes, str]) -> None:
@@ -41,7 +43,7 @@ def set_key(self, key, value):
4143
parser = yaml.load(yaml_file, Loader=yaml.FullLoader)
4244

4345
parser["commitizen"][key] = value
44-
with open(self.path, "w") as yaml_file:
46+
with smart_open(self.path, "w") as yaml_file:
4547
yaml.dump(parser, yaml_file)
4648

4749
return self

commitizen/git.py

+51
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
11
import os
2+
from enum import Enum
3+
from os import linesep
24
from pathlib import Path
35
from tempfile import NamedTemporaryFile
46
from typing import List, Optional
57

68
from commitizen import cmd
79

10+
UNIX_EOL = "\n"
11+
WINDOWS_EOL = "\r\n"
12+
13+
14+
class EOLTypes(Enum):
15+
"""The EOL type from `git config core.eol`."""
16+
17+
LF = "lf"
18+
CRLF = "crlf"
19+
NATIVE = "native"
20+
21+
def get_eol_for_open(self) -> str:
22+
"""Get the EOL character for `open()`."""
23+
map = {
24+
EOLTypes.CRLF: WINDOWS_EOL,
25+
EOLTypes.LF: UNIX_EOL,
26+
EOLTypes.NATIVE: linesep,
27+
}
28+
29+
return map[self]
30+
831

932
class GitObject:
1033
rev: str
@@ -177,3 +200,31 @@ def is_git_project() -> bool:
177200
if c.out.strip() == "true":
178201
return True
179202
return False
203+
204+
205+
def get_eol_style() -> EOLTypes:
206+
c = cmd.run("git config core.eol")
207+
eol = c.out.strip().lower()
208+
209+
# We enumerate the EOL types of the response of
210+
# `git config core.eol`, and map it to our enumration EOLTypes.
211+
#
212+
# It is just like the varient of the "match" syntax.
213+
map = {
214+
"lf": EOLTypes.LF,
215+
"crlf": EOLTypes.CRLF,
216+
"native": EOLTypes.NATIVE,
217+
}
218+
219+
# If the response of `git config core.eol` is in the map:
220+
if eol in map:
221+
return map[eol]
222+
else:
223+
# The default value is "native".
224+
# https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreeol
225+
return map["native"]
226+
227+
228+
def smart_open(*args, **kargs):
229+
"""Open a file with the EOL style determined from Git."""
230+
return open(*args, newline=get_eol_style().get_eol_for_open(), **kargs)

tests/test_git.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import inspect
2+
import os
23
import shutil
34
from typing import List, Optional
45

@@ -203,3 +204,23 @@ def test_is_staging_clean_when_updating_file(tmp_commitizen_project):
203204
cmd.run("git add test_file")
204205

205206
assert git.is_staging_clean() is False
207+
208+
209+
def test_git_eol_style(tmp_commitizen_project):
210+
with tmp_commitizen_project.as_cwd():
211+
assert git.get_eol_style() == git.EOLTypes.NATIVE
212+
213+
cmd.run("git config core.eol lf")
214+
assert git.get_eol_style() == git.EOLTypes.LF
215+
216+
cmd.run("git config core.eol crlf")
217+
assert git.get_eol_style() == git.EOLTypes.CRLF
218+
219+
cmd.run("git config core.eol native")
220+
assert git.get_eol_style() == git.EOLTypes.NATIVE
221+
222+
223+
def test_eoltypes_get_eol_for_open():
224+
assert git.EOLTypes.get_eol_for_open(git.EOLTypes.NATIVE) == os.linesep
225+
assert git.EOLTypes.get_eol_for_open(git.EOLTypes.LF) == "\n"
226+
assert git.EOLTypes.get_eol_for_open(git.EOLTypes.CRLF) == "\r\n"

0 commit comments

Comments
 (0)