Skip to content

Commit

Permalink
fix: fix packing and uploading of the components with lightweight tags
Browse files Browse the repository at this point in the history
Related #51
  • Loading branch information
kumekay committed Feb 12, 2024
1 parent 42b3552 commit eb2c45f
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 32 deletions.
10 changes: 3 additions & 7 deletions idf_component_manager/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from idf_component_tools.environment import getenv_int
from idf_component_tools.errors import (
FatalError,
GitError,
InternalError,
ManifestError,
NothingToDoError,
Expand Down Expand Up @@ -375,18 +374,15 @@ def pack_component(
dest_path = os.path.join(self.path, dest_dir) if dest_dir else self.dist_path

if version == 'git':
try:
version = str(GitClient().get_tag_version())
except GitError:
raise FatalError('An error happened while getting version from git tag')
version = str(GitClient().get_tag_version(cwd=self.path))
elif version:
try:
Version.parse(version)
except ValueError:
raise FatalError(
'Version parameter must be either "git" or a valid version. '
'Documentation: https://docs.espressif.com/projects/idf-component-manager/'
'en/latest/reference/versioning.html#versioning-scheme'
'Documentation: https://docs.espressif.com/projects/idf-component-manager/en/'
'latest/reference/versioning.html#versioning-scheme'
)

manifest_manager = ManifestManager(
Expand Down
62 changes: 49 additions & 13 deletions idf_component_tools/git_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0

import os
Expand All @@ -13,14 +13,22 @@
from .semver import Version

try:
from typing import Any, Callable, List, Optional, Union
from typing import Any, Callable, Union
except ImportError:
pass


# Git error that is supposed to be handled in the code, non-fatal
class GitCommandError(Exception):
pass
"""
Exception class for git errors.
Git error that is supposed to be handled in the code in the code of this class,
not in the user code.
"""

def __init__(self, *args, **kwargs): # type: (Any, Any) -> None
self.exit_code = kwargs.get('exit_code')
super(GitCommandError, self).__init__(*args)


def clean_tag_version(tag): # type: (str) -> str
Expand Down Expand Up @@ -211,7 +219,25 @@ def has_gitmodules_by_ref(self, repo, bare_path, ref): # type: (str, str, str)
'.gitmodules' in self.run(['ls-tree', '--name-only', ref], cwd=bare_path).splitlines()
)

def run(self, args, cwd=None, env=None): # type: (List[str], str | None, dict | None) -> str
def run(self, args, cwd=None, env=None):
"""
Executes a Git command with the given arguments.
Args:
args (List[str]): The list of command-line arguments for the Git command.
cwd (str | None):
The current working directory for the Git command.
If None, the current working directory is used.
env (dict | None):
The environment variables for the Git command.
If None, the current environment variables are used.
Returns:
str: The output of the Git command as a string.
Raises:
GitCommandError: If the Git command fails with a non-zero exit code.
"""
if cwd is None:
cwd = os.getcwd()
env_copy = dict(os.environ)
Expand All @@ -232,8 +258,10 @@ def run(self, args, cwd=None, env=None): # type: (List[str], str | None, dict |
warn(stderr.decode('utf-8'))
else:
raise GitCommandError(
"'git %s' failed with exit code %d \n%s\n%s"
% (' '.join(args), p.returncode, stderr.decode('utf-8'), stdout.decode('utf-8'))
"'git {}' failed with exit code {} \n{}\n{}".format(
' '.join(args), p.returncode, stderr.decode('utf-8'), stdout.decode('utf-8')
),
exit_code=p.returncode,
)

return stdout.decode('utf-8')
Expand All @@ -256,7 +284,7 @@ def version(self): # type: () -> Version
[self.git_command, '--version'], stderr=subprocess.STDOUT
).decode('utf-8')
except OSError:
raise GitError("git command wasn't found")
raise GitError('"git" command was not found')

ver_match = re.match(r'^git version (\d+\.\d+\.\d+)', git_version_str)

Expand All @@ -269,14 +297,22 @@ def version(self): # type: () -> Version
raise GitError('Cannot recognize git version')

@_git_cmd
def get_tag_version(self): # type: () -> Optional[Version]
def get_tag_version(self, cwd=None): # type: (str | None) -> Version
"""
Return a valid component version of the current commit if it is tagged,
otherwise a `GitError` is raised.
"""

try:
tag_str = self.run(['describe', '--exact-match'])
except GitCommandError:
return None
tag_str = self.run(['describe', '--tags', '--exact-match'], cwd=cwd)
except GitCommandError as e:
if e.exit_code == 128:
raise GitError('Not a tagged commit, cannot get version')
else:
raise GitError('Cannot get tag version due to git error\n{}'.format(e))

try:
semantic_version = Version(clean_tag_version(tag_str))
return semantic_version
except ValueError:
return None
raise GitError('Git tag does not contain a valid component version: {}'.format(tag_str))
2 changes: 1 addition & 1 deletion tests/test_component_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def test_pack_component_version_from_git(monkeypatch, tmp_path, pre_release_comp
# remove the first version line
remove_version_line(tmp_path)

def mock_git_tag(self):
def mock_git_tag(self, cwd=None):
return Version('3.0.0')

monkeypatch.setattr(GitClient, 'get_tag_version', mock_git_tag)
Expand Down
50 changes: 39 additions & 11 deletions tests/test_git_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0

import os
Expand All @@ -11,8 +11,8 @@
from idf_component_tools.git_client import GitClient, clean_tag_version


@pytest.fixture(scope='session')
def git_repository_with_two_branches(tmpdir_factory):
@pytest.fixture()
def git_repository(tmpdir_factory):
temp_dir = tmpdir_factory.mktemp('git_repo')
subprocess.check_output(['git', 'init', temp_dir.strpath])

Expand All @@ -27,25 +27,30 @@ def git_repository_with_two_branches(tmpdir_factory):
subprocess.check_output(['git', 'add', '*'], cwd=temp_dir.strpath)
subprocess.check_output(['git', 'commit', '-m', '"Init commit"'], cwd=temp_dir.strpath)

return temp_dir


@pytest.fixture()
def git_repository_with_two_branches(git_repository):
main_commit_id = subprocess.check_output(
['git', 'rev-parse', 'default'], cwd=temp_dir.strpath
['git', 'rev-parse', 'default'], cwd=git_repository.strpath
).strip()

subprocess.check_output(['git', 'checkout', '-b', 'new_branch'], cwd=temp_dir.strpath)
subprocess.check_output(['git', 'checkout', '-b', 'new_branch'], cwd=git_repository.strpath)

f = temp_dir.mkdir('component2').join('test_file')
f = git_repository.mkdir('component2').join('test_file')
f.write(u'component2')

subprocess.check_output(['git', 'add', '*'], cwd=temp_dir.strpath)
subprocess.check_output(['git', 'commit', '-m', '"Add new branch"'], cwd=temp_dir.strpath)
subprocess.check_output(['git', 'add', '*'], cwd=git_repository.strpath)
subprocess.check_output(['git', 'commit', '-m', '"Add new branch"'], cwd=git_repository.strpath)

branch_commit_id = subprocess.check_output(
['git', 'rev-parse', 'new_branch'], cwd=temp_dir.strpath
['git', 'rev-parse', 'new_branch'], cwd=git_repository.strpath
).strip()
subprocess.check_output(['git', 'checkout', 'default'], cwd=temp_dir.strpath)
subprocess.check_output(['git', 'checkout', 'default'], cwd=git_repository.strpath)

return {
'path': temp_dir.strpath,
'path': git_repository.strpath,
'default_head': main_commit_id.decode('utf-8'),
'new_branch_head': branch_commit_id.decode('utf-8'),
}
Expand Down Expand Up @@ -142,3 +147,26 @@ def test_git_path_does_not_exist(git_repository_with_two_branches, tmpdir_factor
)
def test_clean_tag_version(input_str, expected_output):
assert clean_tag_version(input_str) == expected_output


def test_get_tag_version(git_repository):
client = GitClient()
git_repo = git_repository.strpath

# Create a lightweight tag
client.run(['tag', 'v1.2.3'], cwd=git_repo)
assert str(client.get_tag_version(cwd=git_repo)) == '1.2.3'

# Remove the tag
client.run(['tag', '-d', 'v1.2.3'], cwd=git_repo)

# Create an annotated tag
client.run(['tag', '-a', 'v1.2.4', '-m', 'Test tag'], cwd=git_repo)
assert str(client.get_tag_version(cwd=git_repo)) == '1.2.4'

# Remove the tag
client.run(['tag', '-d', 'v1.2.4'], cwd=git_repo)

# Not a tag raises an error
with pytest.raises(GitError, match='Not a tagged commit'):
client.get_tag_version(cwd=git_repo)

0 comments on commit eb2c45f

Please sign in to comment.