Skip to content

Commit

Permalink
Add --pattern-prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
mtkennerly committed Apr 29, 2024
1 parent 42828f5 commit f223462
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 21 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
and it could be incorrect for a monorepo with different tags for different packages.

Now, Dunamai will use 0.0.0 in this case as well, unless strict mode is enabled.
* You can now specify a pattern prefix.
For example, `--pattern default --pattern-prefix some-package-`
would match tags like `some-package-v1.2.3`.
This is useful if you just want a custom prefix without writing a whole pattern.

## v1.20.0 (2024-04-12)

Expand Down
82 changes: 63 additions & 19 deletions dunamai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,26 @@ class Pattern(Enum):
DefaultUnprefixed = "default-unprefixed"
"""Default pattern, but without `v` prefix."""

def regex(self) -> str:
def regex(self, prefix: Optional[str] = None) -> str:
"""
Get the regular expression for this preset pattern.
:param prefix: Insert this after the pattern's start anchor (`^`).
:returns: Regular expression.
"""
variants = {
Pattern.Default: VERSION_SOURCE_PATTERN,
Pattern.DefaultUnprefixed: VERSION_SOURCE_PATTERN.replace("^v", "^v?", 1),
}
return variants[self]

out = variants[self]
if prefix:
out = out.replace("^", "^{}".format(prefix), 1)

return out

@staticmethod
def parse(pattern: Union[str, "Pattern"]) -> str:
def parse(pattern: Union[str, "Pattern"], prefix: Optional[str] = None) -> str:
"""
Parse a pattern string into a regular expression.
Expand All @@ -135,10 +141,14 @@ def parse(pattern: Union[str, "Pattern"]) -> str:
`Pattern` enum.
:param pattern: Pattern to parse.
:param prefix: Insert this after the pattern's start anchor (`^`).
:returns: Regular expression.
"""
if isinstance(pattern, str) and "?P<base>" in pattern:
return pattern
if prefix:
return pattern.replace("^", "^{}".format(prefix), 1)
else:
return pattern

try:
pattern = Pattern(pattern)
Expand All @@ -152,7 +162,7 @@ def parse(pattern: Union[str, "Pattern"]) -> str:
pattern,
)
)
return pattern.regex()
return pattern.regex(prefix)


class Concern(Enum):
Expand Down Expand Up @@ -226,7 +236,11 @@ def _run_cmd(


def _match_version_pattern(
pattern: Union[str, Pattern], sources: Sequence[str], latest_source: bool, strict: bool
pattern: Union[str, Pattern],
sources: Sequence[str],
latest_source: bool,
strict: bool,
pattern_prefix: Optional[str],
) -> Optional[_MatchedVersionPattern]:
"""
:returns: Tuple of:
Expand All @@ -245,7 +259,7 @@ def _match_version_pattern(
tagged_metadata = None
epoch = None # type: Optional[Union[str, int]]

pattern = Pattern.parse(pattern)
pattern = Pattern.parse(pattern, pattern_prefix)

for source in sources[:1] if latest_source else sources:
try:
Expand Down Expand Up @@ -849,7 +863,9 @@ def parse(cls, version: str, pattern: Union[str, Pattern] = Pattern.Default) ->

failed = False
try:
matched_pattern = _match_version_pattern(pattern, [normalized], True, strict=True)
matched_pattern = _match_version_pattern(
pattern, [normalized], True, strict=True, pattern_prefix=None
)
except ValueError:
failed = True

Expand Down Expand Up @@ -998,6 +1014,7 @@ def from_git(
full_commit: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on Git tags.
Expand All @@ -1013,6 +1030,7 @@ def from_git(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = Vcs.Git
Expand Down Expand Up @@ -1066,7 +1084,9 @@ def from_git(
vcs=vcs,
)

matched_pattern = _match_version_pattern(pattern, [tag], latest_tag, strict)
matched_pattern = _match_version_pattern(
pattern, [tag], latest_tag, strict, pattern_prefix
)
if matched_pattern is None:
return cls._fallback(
strict,
Expand Down Expand Up @@ -1174,7 +1194,9 @@ def from_git(
vcs=vcs,
)
tags = [line.replace("refs/tags/", "") for line in msg.splitlines()]
matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict)
matched_pattern = _match_version_pattern(
pattern, tags, latest_tag, strict, pattern_prefix
)
else:
code, msg = _run_cmd(
'git for-each-ref "refs/tags/**" --merged {}'.format(tag_branch)
Expand Down Expand Up @@ -1213,7 +1235,9 @@ def from_git(
detailed_tags.append(_GitRefInfo(*parts).with_tag_topo_lookup(tag_topo_lookup))

tags = [t.ref for t in sorted(detailed_tags, key=lambda x: x.sort_key, reverse=True)]
matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict)
matched_pattern = _match_version_pattern(
pattern, tags, latest_tag, strict, pattern_prefix
)

if matched_pattern is None:
distance = 0
Expand Down Expand Up @@ -1264,6 +1288,7 @@ def from_mercurial(
full_commit: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on Mercurial tags.
Expand All @@ -1277,6 +1302,7 @@ def from_mercurial(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = Vcs.Mercurial
Expand Down Expand Up @@ -1314,7 +1340,9 @@ def from_mercurial(
continue
all_tags.append(parts[1])

matched_pattern = _match_version_pattern(pattern, all_tags, latest_tag, strict)
matched_pattern = _match_version_pattern(
pattern, all_tags, latest_tag, strict, pattern_prefix
)
if matched_pattern is None:
return cls._fallback(
strict,
Expand Down Expand Up @@ -1378,7 +1406,7 @@ def from_mercurial(
)
tags = [tag for tags in [line.split(":") for line in msg.splitlines()] for tag in tags]

matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict)
matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict, pattern_prefix)
if matched_pattern is None:
return cls._fallback(
strict,
Expand Down Expand Up @@ -1418,6 +1446,7 @@ def from_darcs(
latest_tag: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on Darcs tags.
Expand All @@ -1430,6 +1459,7 @@ def from_darcs(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = Vcs.Darcs
Expand Down Expand Up @@ -1459,7 +1489,7 @@ def from_darcs(
)
tags = msg.splitlines()

matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict)
matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict, pattern_prefix)
if matched_pattern is None:
return cls._fallback(
strict,
Expand Down Expand Up @@ -1498,6 +1528,7 @@ def from_subversion(
tag_dir: str = "tags",
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on Subversion tags.
Expand All @@ -1511,6 +1542,7 @@ def from_subversion(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = Vcs.Subversion
Expand Down Expand Up @@ -1562,7 +1594,7 @@ def from_subversion(
tags_to_sources_revs[tag] = (source, rev)
tags = sorted(tags_to_sources_revs, key=lambda x: tags_to_sources_revs[x], reverse=True)

matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict)
matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict, pattern_prefix)
if matched_pattern is None:
return cls._fallback(
strict,
Expand Down Expand Up @@ -1600,6 +1632,7 @@ def from_bazaar(
latest_tag: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on Bazaar tags.
Expand All @@ -1612,6 +1645,7 @@ def from_bazaar(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = Vcs.Bazaar
Expand Down Expand Up @@ -1659,7 +1693,7 @@ def from_bazaar(
}
tags = [x[1] for x in sorted([(v, k) for k, v in tags_to_revs.items()], reverse=True)]

matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict)
matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict, pattern_prefix)
if matched_pattern is None:
return cls._fallback(
strict,
Expand Down Expand Up @@ -1697,6 +1731,7 @@ def from_fossil(
latest_tag: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on Fossil tags.
Expand All @@ -1708,6 +1743,7 @@ def from_fossil(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = Vcs.Fossil
Expand Down Expand Up @@ -1793,7 +1829,7 @@ def from_fossil(
]

matched_pattern = _match_version_pattern(
pattern, [t for t, d in tags_to_distance], latest_tag, strict
pattern, [t for t, d in tags_to_distance], latest_tag, strict, pattern_prefix
)
if matched_pattern is None:
return cls._fallback(
Expand Down Expand Up @@ -1832,6 +1868,7 @@ def from_pijul(
latest_tag: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on Pijul tags.
Expand All @@ -1844,6 +1881,7 @@ def from_pijul(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = Vcs.Pijul
Expand Down Expand Up @@ -1934,7 +1972,7 @@ def from_pijul(
for t in sorted(tag_meta_by_msg.values(), key=lambda x: x["timestamp"], reverse=True)
]

matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict)
matched_pattern = _match_version_pattern(pattern, tags, latest_tag, strict, pattern_prefix)
if matched_pattern is None:
return cls._fallback(
strict,
Expand Down Expand Up @@ -1983,6 +2021,7 @@ def from_any_vcs(
full_commit: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on a detected version control system.
Expand Down Expand Up @@ -2011,6 +2050,7 @@ def from_any_vcs(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
vcs = _detect_vcs_from_archival(path)
Expand All @@ -2031,6 +2071,7 @@ def from_vcs(
full_commit: bool = False,
strict: bool = False,
path: Optional[Path] = None,
pattern_prefix: Optional[str] = None,
) -> "Version":
r"""
Determine a version based on a specific VCS setting.
Expand All @@ -2053,10 +2094,11 @@ def from_vcs(
:param strict: Elevate warnings to errors.
When there are no tags, fail instead of falling back to 0.0.0.
:param path: Directory to inspect, if not the current working directory.
:param pattern_prefix: Insert this after the pattern's start anchor (`^`).
:returns: Detected version.
"""
return cls._do_vcs_callback(
vcs, pattern, latest_tag, tag_dir, tag_branch, full_commit, strict, path
vcs, pattern, latest_tag, tag_dir, tag_branch, full_commit, strict, path, pattern_prefix
)

@classmethod
Expand All @@ -2070,6 +2112,7 @@ def _do_vcs_callback(
full_commit: bool,
strict: bool,
path: Optional[Path],
pattern_prefix: Optional[str] = None,
) -> "Version":
mapping = {
Vcs.Any: cls.from_any_vcs,
Expand All @@ -2091,6 +2134,7 @@ def _do_vcs_callback(
("full_commit", full_commit),
("strict", strict),
("path", path),
("pattern_prefix", pattern_prefix),
]:
if kwarg in inspect.getfullargspec(callback).args:
kwargs[kwarg] = value
Expand Down
8 changes: 7 additions & 1 deletion dunamai/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
" as a named preset, which may be one of the following: {}"
).format(", ".join(["`{}`".format(x.value) for x in Pattern])),
},
{
"triggers": ["--pattern-prefix"],
"help": "Insert this after the pattern's start anchor (`^`).",
},
{
"triggers": ["--format"],
"help": (
Expand Down Expand Up @@ -256,9 +260,10 @@ def from_vcs(
full_commit: bool,
strict: bool,
path: Optional[Path],
pattern_prefix: Optional[str],
) -> None:
version = Version.from_vcs(
vcs, pattern, latest_tag, tag_dir, tag_branch, full_commit, strict, path
vcs, pattern, latest_tag, tag_dir, tag_branch, full_commit, strict, path, pattern_prefix
)

for concern in version.concerns:
Expand Down Expand Up @@ -294,6 +299,7 @@ def main() -> None:
full_commit,
args.strict,
Path(args.path) if args.path is not None else None,
args.pattern_prefix,
)
elif args.command == "check":
version = from_stdin(args.version)
Expand Down

0 comments on commit f223462

Please sign in to comment.