Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add relative path support to Git SCM tool #11407

Merged
merged 3 commits into from Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion conan/tools/scm/git.py
Expand Up @@ -22,7 +22,7 @@ def get_commit(self):
# --full-history is needed to not avoid wrong commits:
# https://github.com/conan-io/conan/issues/10971
# https://git-scm.com/docs/git-rev-list#Documentation/git-rev-list.txt-Defaultmode
commit = self._run('rev-list HEAD -n 1 --full-history -- "{}"'.format(self.folder))
commit = self._run('rev-list HEAD -n 1 --full-history -- "."')
Copy link
Member

Choose a reason for hiding this comment

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

But this change will not guarantee that this is run in the specified self.folder, but in the cwd, which is not guarantee that it will be self.folder, if users specify a different value in the constructor, which they can.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The definition of _run above executes with chdir(self.folder)
The double use of self.folder means it ends up trying to resolve a relative path relative to the folder itself, and usually fails to find any commits touching that subtree.

Given the other uses of _run, its behavior seems correct and the adjustment to get_commit seemed more appropriate.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, yes, you are right, I missed that part. Looks good to me then.

return commit
except Exception as e:
raise ConanException("Unable to get git commit in '%s': %s" % (self.folder, str(e)))
Expand Down
107 changes: 107 additions & 0 deletions conans/test/unittests/tools/scm/test_git_get_commit.py
@@ -1,6 +1,7 @@
import os

from conan.tools.scm import Git
from conans.tools import chdir
from conans.test.utils.mocks import MockConanfile
from conans.test.utils.tools import TestClient

Expand Down Expand Up @@ -97,3 +98,109 @@ def test_multi_folder_repo():
c.run_command("git rev-parse HEAD")
commit_real = str(c.out).splitlines()[0]
assert new_commit_root == commit_real

def test_relative_folder_repo():
c = TestClient()
conanfile = MockConanfile({})
c.save({"lib_a/conanfile.py": ""})
c.run_command("git init .")
c.run_command('git config user.name myname')
c.run_command('git config user.email myname@mycompany.com')
c.run_command("git add .")
c.run_command('git commit -m "lib_a commit"')
c.save({"lib_b/conanfile.py": ""})
c.run_command("git add .")
c.run_command('git commit -m "lib_b commit"')
c.save({"lib_c/conanfile.py": ""})
c.run_command("git add .")
c.run_command('git commit -m "lib_c commit"')
c.save({"root_change": ""})
c.run_command("git add .")
c.run_command('git commit -m "root change"')

# Relative paths for folders, from the current_folder
with chdir(c.current_folder):
git = Git(conanfile, folder="lib_a")
commit_libA = git.get_commit()

git = Git(conanfile, folder="lib_b")
commit_libB = git.get_commit()

git = Git(conanfile, folder="./lib_c")
commit_libC = git.get_commit()

# this is folder default, but be explicit
git = Git(conanfile, folder=".")
commit_root = git.get_commit()

# All different
assert len({commit_libA, commit_libB, commit_libC, commit_root}) == 4

# Compare to Full paths
git = Git(conanfile, folder=os.path.join(c.current_folder, "lib_a"))
full_commit_libA = git.get_commit()

git = Git(conanfile, folder=os.path.join(c.current_folder, "lib_b"))
full_commit_libB = git.get_commit()

git = Git(conanfile, folder=os.path.join(c.current_folder, "lib_c"))
full_commit_libC = git.get_commit()

git = Git(conanfile, folder=c.current_folder)
full_commit_root = git.get_commit()

assert full_commit_libA == commit_libA
assert full_commit_libB == commit_libB
assert full_commit_libC == commit_libC
assert full_commit_root == commit_root

# Sanity checks
c.run_command("git rev-parse HEAD")
commit_real_root = str(c.out).splitlines()[0]
assert commit_real_root == commit_root

c.run_command("git rev-list -n 1 --full-history HEAD -- lib_a")
commit_real_libA = str(c.out).splitlines()[0]
assert commit_real_libA == commit_libA

def test_submodule_repo():
c = TestClient()
conanfile = MockConanfile({})
c.save({"conanfile.py": ""})
c.run_command("git init .")
c.run_command('git config user.name myname')
c.run_command('git config user.email myname@mycompany.com')
c.run_command("git add .")
c.run_command('git commit -m "Initial commit"')
c.run_command('git clone . source_subfolder')
c.run_command('git submodule add ../ source_subfolder')
c.run_command('git commit -m "submodule commit"')
c.save({"root_change": ""})
c.run_command("git add .")
c.run_command('git commit -m "root change"')

with chdir(c.current_folder):
# default case
git = Git(conanfile)
commit_root = git.get_commit()

# Relative paths
git = Git(conanfile, folder="source_subfolder")
commit_relA = git.get_commit()

git = Git(conanfile, folder="./source_subfolder")
commit_relB = git.get_commit()

# Full path
git = Git(conanfile, folder=os.path.join(c.current_folder, "source_subfolder"))
commit_full = git.get_commit()

assert commit_relA == commit_relB
assert commit_relA == commit_full
assert commit_root != commit_full

# This is the commit which modified the tree in the containing repo
# not the commit which the submodule is at
c.run_command("git rev-list HEAD -n 1 --full-history -- source_subfolder")
commit_submodule = str(c.out).splitlines()[0]
assert commit_submodule != commit_full