Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(cmd-version): add support for partial tags#1115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
MatthieuSarter wants to merge3 commits intopython-semantic-release:master
base:master
Choose a base branch
Loading
fromMatthieuSarter:master
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletionsdocs/configuration/configuration.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1162,6 +1162,30 @@ from the :ref:`remote.name <config-remote-name>` location of your git repository

----

.. _config-add_partial_tags:

``add_partial_tags``
""""""""""""""""""""

**Type:** ``bool``

Specify if partial version tags should be handled when creating a new version. If set to
``true``, a major and a major.minor tag will be created or updated, using the format
specified in :ref:`tag_format`. If version has build metadata, a major.minor.patch tag
will also be created or updated.

For example, with tag format ``v{version}`` and ``add_partial_tags`` set to ``true``, when
creating version ``1.2.3``, the tags ``v1`` and ``v1.2`` will be created or updated and
will point to the same commit as the ``v1.2.3`` tag. When creating version ``1.2.3+build.1234``,
the tags ``v1``, ``v1.2`` and ``v1.2.3`` will be created or updated and will point to the
same commit as the ``v1.2.3+build.1234`` tag.

The partial version tags will not be created or updated if the version is a pre-release.

**Default:** ``false``

----

.. _config-tag_format:

``tag_format``
Expand Down
35 changes: 32 additions & 3 deletionssrc/semantic_release/cli/commands/version.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -75,10 +75,13 @@ def is_forced_prerelease(
)


def last_released(repo_dir: Path, tag_format: str) -> tuple[Tag, Version] | None:
def last_released(
repo_dir: Path, tag_format: str, add_partial_tags: bool = False
) -> tuple[Tag, Version] | None:
with Repo(str(repo_dir)) as git_repo:
ts_and_vs = tags_and_versions(
git_repo.tags, VersionTranslator(tag_format=tag_format)
git_repo.tags,
VersionTranslator(tag_format=tag_format, add_partial_tags=add_partial_tags),
)

return ts_and_vs[0] if ts_and_vs else None
Expand DownExpand Up@@ -449,7 +452,11 @@ def version( # noqa: C901
if print_last_released or print_last_released_tag:
# TODO: get tag format a better way
if not (
last_release := last_released(config.repo_dir, tag_format=config.tag_format)
last_release := last_released(
config.repo_dir,
tag_format=config.tag_format,
add_partial_tags=config.add_partial_tags,
)
):
logger.warning("No release tags found.")
return
Expand All@@ -470,6 +477,7 @@ def version( # noqa: C901
major_on_zero = runtime.major_on_zero
no_verify = runtime.no_git_verify
opts = runtime.global_cli_options
add_partial_tags = config.add_partial_tags
gha_output = VersionGitHubActionsOutput(
gh_client=hvcs_client if isinstance(hvcs_client, Github) else None,
mode=(
Expand DownExpand Up@@ -744,6 +752,27 @@ def version( # noqa: C901
tag=new_version.as_tag(),
noop=opts.noop,
)
# Create or update partial tags for releases
if add_partial_tags and not prerelease:
partial_tags = [new_version.as_major_tag(), new_version.as_minor_tag()]
# If build metadata is set, also retag the version without the metadata
if build_metadata:
partial_tags.append(new_version.as_patch_tag())

for partial_tag in partial_tags:
project.git_tag(
tag_name=partial_tag,
message=f"{partial_tag} is {new_version.as_tag()}",
Copy link

CopilotAINov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

[nitpick] The tag message format could be more descriptive. Consider using a message like 'Points to {new_version.as_tag()}' or 'Tracks {new_version.as_tag()}' to clarify that this is a reference tag that may be updated in the future.

Suggested change
message=f"{partial_tag} is{new_version.as_tag()}",
message=f"Tracks{new_version.as_tag()}",

Copilot uses AI. Check for mistakes.
isotimestamp=commit_date.isoformat(),
noop=opts.noop,
force=True,
)
project.git_push_tag(
remote_url=remote_url,
tag=partial_tag,
noop=opts.noop,
force=True,
)

# Update GitHub Actions output value now that release has occurred
gha_output.released = True
Expand Down
5 changes: 4 additions & 1 deletionsrc/semantic_release/cli/config.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -366,6 +366,7 @@ class RawConfig(BaseModel):
remote: RemoteConfig = RemoteConfig()
no_git_verify: bool = False
tag_format: str = "v{version}"
add_partial_tags: bool = False
publish: PublishConfig = PublishConfig()
version_toml: Optional[Tuple[str, ...]] = None
version_variables: Optional[Tuple[str, ...]] = None
Expand DownExpand Up@@ -827,7 +828,9 @@ def from_raw_config( # noqa: C901

# version_translator
version_translator = VersionTranslator(
tag_format=raw.tag_format, prerelease_token=branch_config.prerelease_token
tag_format=raw.tag_format,
prerelease_token=branch_config.prerelease_token,
add_partial_tags=raw.add_partial_tags,
)

build_cmd_env = {}
Expand Down
51 changes: 31 additions & 20 deletionssrc/semantic_release/gitproject.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -197,7 +197,12 @@ def git_commit(
raise GitCommitError("Failed to commit changes") from err

def git_tag(
self, tag_name: str, message: str, isotimestamp: str, noop: bool = False
self,
tag_name: str,
message: str,
isotimestamp: str,
force: bool = False,
noop: bool = False,
) -> None:
try:
datetime.fromisoformat(isotimestamp)
Expand All@@ -207,21 +212,25 @@ def git_tag(
if noop:
command = str.join(
" ",
[
f"GIT_COMMITTER_DATE={isotimestamp}",
*(
[
f"GIT_AUTHOR_NAME={self._commit_author.name}",
f"GIT_AUTHOR_EMAIL={self._commit_author.email}",
f"GIT_COMMITTER_NAME={self._commit_author.name}",
f"GIT_COMMITTER_EMAIL={self._commit_author.email}",
]
if self._commit_author
else [""]
),
f"git tag -a {tag_name} -m '{message}'",
],
)
filter(
None,
[
f"GIT_COMMITTER_DATE={isotimestamp}",
*(
[
f"GIT_AUTHOR_NAME={self._commit_author.name}",
f"GIT_AUTHOR_EMAIL={self._commit_author.email}",
f"GIT_COMMITTER_NAME={self._commit_author.name}",
f"GIT_COMMITTER_EMAIL={self._commit_author.email}",
]
if self._commit_author
else [""]
),
f"git tag -a {tag_name} -m '{message}'",
"--force" if force else "",
],
),
).strip()
Copy link

CopilotAINov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thefilter(None, ...) call on line 215-216 combined with.strip() on line 233 will cause issues with the noop output formatting. The filter removes empty strings but the unpacking operator* on line 219 can still produce an empty string element (line 227), and when that's joined it creates extra spaces. The empty string on line 227 should be removed since the filter is now used.

Copilot uses AI. Check for mistakes.

noop_report(
indented(
Expand All@@ -238,7 +247,7 @@ def git_tag(
{"GIT_COMMITTER_DATE": isotimestamp},
):
try:
repo.git.tag("-a", tag_name, m=message)
repo.git.tag(tag_name, a=True, m=message, force=force)
except GitCommandError as err:
self.logger.exception(str(err))
raise GitTagError(f"Failed to create tag ({tag_name})") from err
Expand All@@ -264,21 +273,23 @@ def git_push_branch(self, remote_url: str, branch: str, noop: bool = False) -> N
f"Failed to push branch ({branch}) to remote"
) from err

def git_push_tag(self, remote_url: str, tag: str, noop: bool = False) -> None:
def git_push_tag(
self, remote_url: str, tag: str, noop: bool = False, force: bool = False
) -> None:
if noop:
noop_report(
indented(
f"""\
would have run:
git push {self._cred_masker.mask(remote_url)} tag {tag}
git push {self._cred_masker.mask(remote_url)} tag {tag} {"--force" if force else ""}
""" # noqa: E501
)
)
return

with Repo(str(self.project_root)) as repo:
try:
repo.git.push(remote_url, "tag", tag)
repo.git.push(remote_url, "tag", tag, force=force)
except GitCommandError as err:
self.logger.exception(str(err))
raise GitPushError(f"Failed to push tag ({tag}) to remote") from err
10 changes: 10 additions & 0 deletionssrc/semantic_release/version/translator.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,11 +42,17 @@ def __init__(
self,
tag_format: str = "v{version}",
prerelease_token: str = "rc", # noqa: S107
add_partial_tags: bool = False,
) -> None:
check_tag_format(tag_format)
self.tag_format = tag_format
self.prerelease_token = prerelease_token
self.add_partial_tags = add_partial_tags
self.from_tag_re = self._invert_tag_format_to_re(self.tag_format)
self.partial_tag_re = re.compile(
tag_format.replace(r"{version}", r"[0-9]+(\.(0|[1-9][0-9]*))?$"),
Copy link

CopilotAINov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The regex pattern does not escape thetag_format string before replacing{version}, which could lead to incorrect matching if the tag format contains regex special characters. Usere.escape() on the tag_format before replacing the placeholder, similar to how it's done in_invert_tag_format_to_re method.

Suggested change
tag_format.replace(r"{version}",r"[0-9]+(\.(0|[1-9][0-9]*))?$"),
re.escape(tag_format).replace(
re.escape("{version}"),r"[0-9]+(\.(0|[1-9][0-9]*))?$"
),

Copilot uses AI. Check for mistakes.
flags=re.VERBOSE,
)

def from_string(self, version_str: str) -> Version:
"""
Expand All@@ -69,6 +75,10 @@ def from_tag(self, tag: str) -> Version | None:
tag_match = self.from_tag_re.match(tag)
if not tag_match:
return None
if self.add_partial_tags:
partial_tag_match = self.partial_tag_re.match(tag)
if partial_tag_match:
return None
raw_version_str = tag_match.group("version")
return self.from_string(raw_version_str)

Expand Down
9 changes: 9 additions & 0 deletionssrc/semantic_release/version/version.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -203,6 +203,15 @@ def __repr__(self) -> str:
def as_tag(self) -> str:
return self.tag_format.format(version=str(self))

def as_major_tag(self) -> str:
return self.tag_format.format(version=f"{self.major}")

def as_minor_tag(self) -> str:
return self.tag_format.format(version=f"{self.major}.{self.minor}")

def as_patch_tag(self) -> str:
return self.tag_format.format(version=f"{self.major}.{self.minor}.{self.patch}")

def as_semver_tag(self) -> str:
return f"v{self!s}"

Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp