Skip to content

Commit

Permalink
fix(algorithm): handle merge-base errors gracefully
Browse files Browse the repository at this point in the history
Merge-base errors generally occur from a shallow clone that is
primarily used by CI environments and will cause PSR to explode
prior to this change. Now it exits with an appropriate error.

Resolves: #724
  • Loading branch information
codejedi365 committed Mar 24, 2024
1 parent 3690b95 commit 4c998b7
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 20 deletions.
7 changes: 7 additions & 0 deletions semantic_release/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@ class CommitParseError(SemanticReleaseBaseError):
Raised when a commit cannot be parsed by a commit parser. Custom commit parsers
should also raise this Exception
"""


class MissingMergeBaseError(SemanticReleaseBaseError):
"""
Raised when the merge base cannot be found with the current history. Generally
because of a shallow git clone.
"""
60 changes: 40 additions & 20 deletions semantic_release/version/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from semantic_release.commit_parser import ParsedCommit
from semantic_release.const import DEFAULT_VERSION
from semantic_release.enums import LevelBump
from semantic_release.errors import InvalidVersion
from semantic_release.errors import InvalidVersion, MissingMergeBaseError
from semantic_release.version.version import Version

if TYPE_CHECKING:
Expand Down Expand Up @@ -289,30 +289,50 @@ def next_version(
iter(all_full_release_tags_and_versions),
(None, translator.from_string(DEFAULT_VERSION)),
)
if latest_full_release_tag is None:
# Workaround - we can safely scan the extra commits on this
# branch if it's never been released, but we have no other
# guarantees that other branches exist
log.info(
"No full releases have been made yet, the default version to use is %s",
latest_full_release_version,
)
merge_bases = repo.merge_base(repo.active_branch, repo.active_branch)
else:
# Note the merge_base might be on our current branch, it's not
# necessarily the merge base of the current branch with `main`
log.info(
"The last full release was %s, tagged as %r",
latest_full_release_version,
latest_full_release_tag,

# we can safely scan the extra commits on this
# branch if it's never been released, but we have no other
# guarantees that other branches exist
# Note the merge_base might be on our current branch, it's not
# necessarily the merge base of the current branch with `main`
other_ref = (
repo.active_branch
if latest_full_release_tag is None
else latest_full_release_tag.name
)

# Conditional log message to inform what was chosen as the comparison point
# to find the merge base of the current branch with the latest full release
log_msg = (
str.join(", ", [
"No full releases have been made yet",
f"the default version to use is {latest_full_release_version}",
])
if latest_full_release_tag is None
else str.join(", ", [
f"The last full release was {latest_full_release_version}",
f"tagged as {latest_full_release_tag!r}",
])
)

log.info(log_msg)
merge_bases = repo.merge_base(other_ref, repo.active_branch)

if len(merge_bases) < 1:
raise MissingMergeBaseError(
f"Unable to find merge-base between {other_ref} and {repo.active_branch.name}"
)
merge_bases = repo.merge_base(latest_full_release_tag.name, repo.active_branch)

if len(merge_bases) > 1:
raise NotImplementedError(
"This branch has more than one merge-base with the "
"latest version, which is not yet supported"
str.join(" ", [
"This branch has more than one merge-base with the",
"latest version, which is not yet supported"
])
)

merge_base = merge_bases[0]

if merge_base is None:
str_tag_name = (
"None" if latest_full_release_tag is None else latest_full_release_tag.name
Expand Down

0 comments on commit 4c998b7

Please sign in to comment.