Skip to content

Commit

Permalink
New revision_mode = scm_folder for monorepos (#13562)
Browse files Browse the repository at this point in the history
* changing revision_mode=scm base folder

* wip
  • Loading branch information
memsharded authored May 4, 2023
1 parent 5cf93ae commit e33561a
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 48 deletions.
7 changes: 3 additions & 4 deletions conans/client/cmd/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def cmd_export(app, conanfile_path, name, version, user, channel, graph_lock=Non


def _calc_revision(scoped_output, path, manifest, revision_mode):
if revision_mode not in ["scm", "hash"]:
if revision_mode not in ["scm", "scm_folder", "hash"]:
raise ConanException("Revision mode should be one of 'hash' (default) or 'scm'")

# Use the proper approach depending on 'revision_mode'
Expand All @@ -93,7 +93,8 @@ def _calc_revision(scoped_output, path, manifest, revision_mode):
else:
try:
with chdir(path):
rev_detected = check_output_runner('git rev-list HEAD -n 1 --full-history').strip()
f = '-- "."' if revision_mode == "scm_folder" else ""
revision = check_output_runner(f'git rev-list HEAD -n 1 --full-history {f}').strip()
except Exception as exc:
error_msg = "Cannot detect revision using '{}' mode from repository at " \
"'{}'".format(revision_mode, path)
Expand All @@ -104,8 +105,6 @@ def _calc_revision(scoped_output, path, manifest, revision_mode):
raise ConanException("Can't have a dirty repository using revision_mode='scm' and doing"
" 'conan export', please commit the changes and run again.")

revision = rev_detected

scoped_output.info("Using git commit as the recipe revision: %s" % revision)

return revision
Expand Down
66 changes: 51 additions & 15 deletions conans/test/functional/command/export_test.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,66 @@
import textwrap
import unittest
import os

import pytest

from conans.model.recipe_ref import RecipeReference
from conans.test.assets.genconanfile import GenConanfile
from conans.test.utils.scm import git_add_changes_commit
from conans.test.utils.tools import TestClient


class ExportMetadataTest(unittest.TestCase):
conanfile = textwrap.dedent("""
from conan import ConanFile
@pytest.mark.tool("git")
class TestRevisionModeSCM:

class Lib(ConanFile):
revision_mode = "{revision_mode}"
""")
def test_revision_mode_scm(self):
t = TestClient()
conanfile = str(GenConanfile().with_class_attribute('revision_mode = "scm"'))
commit = t.init_git_repo({'conanfile.py': conanfile})

summary_hash = "bfe8b4a6a2a74966c0c4e0b34705004a"
t.run(f"export . --name=pkg --version=0.1")

@pytest.mark.tool("git")
def test_revision_mode_scm(self):
ref = RecipeReference.loads("pkg/0.1")
latest_rev = t.cache.get_latest_recipe_reference(ref)
assert latest_rev.revision == commit

# Now it will fail if dirty
t.save({"conanfile.py": conanfile + "\n#comment"})
t.run(f"export . --name=pkg --version=0.1", assert_error=True)
assert "Can't have a dirty repository using revision_mode='scm' and doing" in t.out
# Commit to fix
commit2 = git_add_changes_commit(t.current_folder, msg="fix")
t.run(f"export . --name=pkg --version=0.1")
latest_rev = t.cache.get_latest_recipe_reference(ref)
assert latest_rev.revision == commit2

def test_revision_mode_scm_subfolder(self):
""" emulates a mono-repo with 2 subprojects, when a change is done in a subproject
it gets a different folder commit
"""
t = TestClient()
commit = t.init_git_repo({'conanfile.py': self.conanfile.format(revision_mode="scm")})
conanfile = str(GenConanfile().with_class_attribute('revision_mode = "scm_folder"'))
commit = t.init_git_repo({'pkga/conanfile.py': conanfile,
'pkgb/conanfile.py': conanfile})

ref = RecipeReference.loads("name/version@user/channel")
t.run(f"export . --name={ref.name} --version={ref.version} --user={ref.user} --channel={ref.channel}")
t.save({"pkgb/conanfile.py": conanfile + "\n#comment"})
commit_b = git_add_changes_commit(os.path.join(t.current_folder, "pkgb"), msg="fix")

# pkga still gets the initial commit, as it didn't change its contents
t.run(f"export pkga --name=pkga --version=0.1")
ref = RecipeReference.loads("pkga/0.1")
latest_rev = t.cache.get_latest_recipe_reference(ref)
assert latest_rev.revision == commit

self.assertEqual(latest_rev.revision, commit)
# but pkgb will get the commit of the new changed folder
t.run(f"export pkgb --name=pkgb --version=0.1")
ref = RecipeReference.loads("pkgb/0.1")
latest_rev = t.cache.get_latest_recipe_reference(ref)
assert latest_rev.revision == commit_b

def test_auto_revision_without_commits(self):
"""If we have a repo but without commits, it has to fail when the revision_mode=scm"""
t = TestClient()
t.run_command('git init .')
t.save({"conanfile.py": GenConanfile("lib", "0.1").with_revision_mode("scm")})
t.run("export .", assert_error=True)
# It errors, because no commits yet
assert "Cannot detect revision using 'scm' mode from repository" in t.out
29 changes: 0 additions & 29 deletions conans/test/functional/revisions_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,35 +796,6 @@ def test_upload_no_overwrite_packages(self):
pref2.revision)


class SCMRevisions(unittest.TestCase):

def test_auto_revision_even_without_scm_git(self):
"""
Can't do conan create/export with uncommited changes if using revision_mode=scm
"""
ref = RecipeReference.loads("lib/1.0@conan/testing")
client = TurboTestClient()
conanfile = GenConanfile().with_revision_mode("scm")
commit = client.init_git_repo(files={"file.txt": "hey", "conanfile.py": str(conanfile)},
origin_url="http://myrepo.git")
client.create(ref, conanfile=conanfile)
self.assertEqual(client.recipe_revision(ref), commit)

# Change the conanfile and make another create, the revision should be the same
client.save({"conanfile.py": str(conanfile.with_build_msg("New changes!"))})
client.create(ref, conanfile=conanfile, assert_error=True)
self.assertIn("Can't have a dirty repository using revision_mode='scm' and doing", client.out)

def test_auto_revision_without_commits(self):
"""If we have a repo but without commits, it has to fail when the revision_mode=scm"""
client = TurboTestClient()
client.run_command('git init .')
client.save({"conanfile.py": GenConanfile("lib", "0.1").with_revision_mode("scm")})
client.run("create .", assert_error=True)
# It error, because the revision_mode is explicitly set to scm
self.assertIn("Cannot detect revision using 'scm' mode from repository", client.out)


class CapabilitiesRevisionsTest(unittest.TestCase):
def test_server_with_only_v2_capability(self):
server = TestServer(server_capabilities=[])
Expand Down

0 comments on commit e33561a

Please sign in to comment.