Repository: conan-io/conan
Pull request #4325 (2019-01-17 09:57:05)

Fix bug in server revisions
Changelog: Fixed a bug in the migration of the server storage to the revisions layout.
Docs: omit

It failed once in my conan_server. Couldn't reproduce it later. Not sure how to test it.

@revisions: 1

lasote: https://github.com/conan-io/conan/pull/4293 change a lot related with that. I'm not saying fixing, maybe bugs are already there but I think it should be merged first. The CI of this PR is very broken.

Patch:
diff --git a/conans/client/build/cmake.py b/conans/client/build/cmake.py
index 9bfcd123b..f6f2727ce 100644
--- a/conans/client/build/cmake.py
+++ b/conans/client/build/cmake.py
@@ -59,7 +59,8 @@ class CMake(object):
         self.definitions = builder.get_definitions()
         self.toolset = toolset or get_toolset(self._settings)
         self.build_dir = None
-        self.msbuild_verbosity = msbuild_verbosity or get_env("CONAN_MSBUILD_VERBOSITY", "minimal")
+        self.msbuild_verbosity = (os.getenv("CONAN_MSBUILD_VERBOSITY") or msbuild_verbosity or
+                                  "minimal")
 
     @property
     def build_folder(self):
@@ -189,7 +190,8 @@ class CMake(object):
             pkg_env = {"PKG_CONFIG_PATH": self._conanfile.install_folder} if set_env else {}
 
         with tools.environment_append(pkg_env):
-            command = "cd %s && %s %s" % (args_to_string([self.build_dir]), self._cmake_program, arg_list)
+            command = "cd %s && %s %s" % (args_to_string([self.build_dir]), self._cmake_program,
+                                          arg_list)
             if platform.system() == "Windows" and self.generator == "MinGW Makefiles":
                 with tools.remove_from_path("sh"):
                     self._run(command)
diff --git a/conans/client/build/cmake_flags.py b/conans/client/build/cmake_flags.py
index 624ae6533..f3df58ec3 100644
--- a/conans/client/build/cmake_flags.py
+++ b/conans/client/build/cmake_flags.py
@@ -36,8 +36,7 @@ def get_generator(settings):
 
     if not compiler or not compiler_version or not arch:
         if os_build == "Windows":
-            # Not enough settings to set a generator in Windows
-            return None
+            return "MinGW Makefiles"
         return "Unix Makefiles"
 
     if compiler == "Visual Studio":
diff --git a/conans/client/build/msbuild.py b/conans/client/build/msbuild.py
index 394c9cc90..fee14a3e0 100644
--- a/conans/client/build/msbuild.py
+++ b/conans/client/build/msbuild.py
@@ -1,4 +1,5 @@
 import copy
+import os
 import re
 import subprocess
 
@@ -79,7 +80,8 @@ class MSBuild(object):
                                        targets=targets, upgrade_project=upgrade_project,
                                        build_type=build_type, arch=arch, parallel=parallel,
                                        toolset=toolset, platforms=platforms,
-                                       use_env=use_env, properties=properties, output_binary_log=output_binary_log,
+                                       use_env=use_env, properties=properties,
+                                       output_binary_log=output_binary_log,
                                        verbosity=verbosity)
             command = "%s && %s" % (vcvars, command)
             return self._conanfile.run(command)
@@ -99,7 +101,7 @@ class MSBuild(object):
 
         build_type = build_type or self._settings.get_safe("build_type")
         arch = arch or self._settings.get_safe("arch")
-        verbosity = verbosity or get_env("CONAN_MSBUILD_VERBOSITY", "minimal")
+        verbosity = os.getenv("CONAN_MSBUILD_VERBOSITY") or verbosity or "minimal"
         if not build_type:
             raise ConanException("Cannot build_sln_command, build_type not defined")
         if not arch:
@@ -125,7 +127,8 @@ class MSBuild(object):
         else:
             config = "%s|%s" % (build_type, msvc_arch)
             if config not in "".join(lines):
-                self._output.warn("***** The configuration %s does not exist in this solution *****" % config)
+                self._output.warn("***** The configuration %s does not exist in this solution *****"
+                                  % config)
                 self._output.warn("Use 'platforms' argument to define your architectures")
 
         if output_binary_log:
@@ -173,7 +176,8 @@ class MSBuild(object):
         runtime_library = {"MT": "MultiThreaded",
                            "MTd": "MultiThreadedDebug",
                            "MD": "MultiThreadedDLL",
-                           "MDd": "MultiThreadedDebugDLL"}.get(self._settings.get_safe("compiler.runtime"), "")
+                           "MDd": "MultiThreadedDebugDLL"}.get(
+                               self._settings.get_safe("compiler.runtime"), "")
 
         if self.build_env:
             # Take the flags from the build env, the user was able to alter them if needed
@@ -216,7 +220,7 @@ class MSBuild(object):
         vcvars = vcvars_command(settings)
         command = "%s && %s" % (vcvars, msbuild_cmd)
         try:
-            out, err = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()
+            out, _ = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()
             version_line = decode_text(out).split("\n")[-1]
             prog = re.compile("(\d+\.){2,3}\d+")
             result = prog.match(version_line).group()
diff --git a/conans/client/graph/build_mode.py b/conans/client/graph/build_mode.py
index e4f9f9fe4..ffbcb0b2c 100644
--- a/conans/client/graph/build_mode.py
+++ b/conans/client/graph/build_mode.py
@@ -6,6 +6,7 @@ from conans.errors import ConanException
 class BuildMode(object):
     """ build_mode => ["*"] if user wrote "--build"
                    => ["hello*", "bye*"] if user wrote "--build hello --build bye"
+                   => ["hello/0.1@foo/bar"] if user wrote "--build hello/0.1@foo/bar"
                    => False if user wrote "never"
                    => True if user wrote "missing"
                    => "outdated" if user wrote "--build outdated"
@@ -53,7 +54,7 @@ class BuildMode(object):
         ref = ref.name
         # Patterns to match, if package matches pattern, build is forced
         for pattern in self.patterns:
-            if fnmatch.fnmatch(ref, pattern):
+            if fnmatch.fnmatch(ref, pattern) or repr(reference) == pattern:
                 try:
                     self._unused_patterns.remove(pattern)
                 except ValueError:
@@ -61,7 +62,7 @@ class BuildMode(object):
                 return True
         return False
 
-    def allowed(self, conan_file, reference):
+    def allowed(self, conan_file):
         if self.missing or self.outdated:
             return True
         if conan_file.build_policy_missing:
diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py
index 83514b427..76c014288 100644
--- a/conans/client/graph/graph_binaries.py
+++ b/conans/client/graph/graph_binaries.py
@@ -146,7 +146,7 @@ class GraphBinariesAnalyzer(object):
                 node.binary = BINARY_DOWNLOAD
                 package_hash = remote_info.recipe_hash
             else:
-                if build_mode.allowed(conanfile, ref):
+                if build_mode.allowed(conanfile):
                     node.binary = BINARY_BUILD
                 else:
                     node.binary = BINARY_MISSING
diff --git a/conans/client/tools/scm.py b/conans/client/tools/scm.py
index 550314f91..a0e93641a 100644
--- a/conans/client/tools/scm.py
+++ b/conans/client/tools/scm.py
@@ -176,6 +176,15 @@ class Git(SCMBase):
         except Exception as e:
             raise ConanException("Unable to get git branch from %s: %s" % (self.folder, str(e)))
 
+    def get_tag(self):
+        self._check_git_repo()
+        try:
+            status = self.run("describe --exact-match --tags")
+            tag = status.strip()
+            return tag
+        except Exception:
+            return None
+
     def _check_git_repo(self):
         try:
             self.run("status")
@@ -333,20 +342,24 @@ class SVN(SCMBase):
             return self._show_item(item='last-changed-revision')
 
     def get_branch(self):
-        url = self._show_item('relative-url')
+        item = self._get_item("branches/[^/]+|trunk", "branch")
+        return item.replace("branches/", "") if item else None
+
+    def get_tag(self):
+        item = self._get_item("tags/[^/]+", "tag")
+        return item.replace("tags/", "") if item else None
+
+    def _get_item(self, pattern, item_name):
         try:
-            pattern = "(tags|branches)/[^/]+|trunk"
-            branch = re.search(pattern, url)
-            
-            if branch is None:
-                return None
-            else:
-                return branch.group(0)
+            url = self._show_item('relative-url')
         except Exception as e:
-            raise ConanException("Unable to get svn branch from %s: %s" % (self.folder, str(e)))
+            raise ConanException("Unable to get svn %s from %s: %s"
+                                 % (item_name, self.folder, str(e)))
+        item = re.search(pattern, url)
+        return item.group(0) if item else None
 
     def _check_svn_repo(self):
         try:
             self.run("info")
         except Exception:
-            raise ConanException("Not a valid SVN repository")
\ No newline at end of file
+            raise ConanException("Not a valid SVN repository")
diff --git a/conans/model/options.py b/conans/model/options.py
index 410206542..0d13a02ac 100644
--- a/conans/model/options.py
+++ b/conans/model/options.py
@@ -176,7 +176,8 @@ class OptionsValues(object):
             tokens = k.split(":")
             if len(tokens) == 2:
                 package, option = tokens
-                package_values = self._reqs_options.setdefault(package.strip(), PackageOptionValues())
+                package_values = self._reqs_options.setdefault(package.strip(),
+                                                               PackageOptionValues())
                 package_values.add_option(option, v)
             else:
                 self._package_values.add_option(k, v)
@@ -367,7 +368,7 @@ class PackageOptions(object):
 
     @staticmethod
     def loads(text):
-        return PackageOptions(yaml.load(text) or {})
+        return PackageOptions(yaml.safe_load(text) or {})
 
     def get_safe(self, field):
         return self._data.get(field)
@@ -461,7 +462,8 @@ class PackageOptions(object):
                 modified_value, modified_ref = modified
                 raise ConanException("%s tried to change %s option %s to %s\n"
                                      "but it was already assigned to %s by %s"
-                                     % (down_ref, own_ref, name, value, modified_value, modified_ref))
+                                     % (down_ref, own_ref, name, value,
+                                        modified_value, modified_ref))
             else:
                 if name in pattern_options:  # If it is a pattern-matched option, should check field
                     if name in self._data:
diff --git a/conans/model/settings.py b/conans/model/settings.py
index c9b42653c..90d7772cd 100644
--- a/conans/model/settings.py
+++ b/conans/model/settings.py
@@ -227,7 +227,7 @@ class Settings(object):
 
     @staticmethod
     def loads(text):
-        return Settings(yaml.load(text) or {})
+        return Settings(yaml.safe_load(text) or {})
 
     def validate(self):
         for field in self.fields:
diff --git a/conans/model/workspace.py b/conans/model/workspace.py
index 26f373d35..8352135a9 100644
--- a/conans/model/workspace.py
+++ b/conans/model/workspace.py
@@ -139,7 +139,7 @@ project({name} CXX)
 
     def _loads(self, text):
         try:
-            yml = yaml.load(text)
+            yml = yaml.safe_load(text)
             self._generator = yml.pop("generator", None)
             self._name = yml.pop("name", None)
             self._root = [s.strip() for s in yml.pop("root", "").split(",") if s.strip()]
diff --git a/conans/server/revision_list.py b/conans/server/revision_list.py
index 9ba56f59f..ce4d440ef 100644
--- a/conans/server/revision_list.py
+++ b/conans/server/revision_list.py
@@ -61,5 +61,3 @@ class RevisionList(object):
 
     def __eq__(self, other):
         return self.dumps() == other.dumps()
-
-
diff --git a/conans/server/store/server_store.py b/conans/server/store/server_store.py
index 97aa72cc8..db716955a 100644
--- a/conans/server/store/server_store.py
+++ b/conans/server/store/server_store.py
@@ -273,7 +273,7 @@ class ServerStore(SimplePaths):
                 rev_list.add_revision(DEFAULT_REVISION_V1)
                 self._storage_adapter.write_file(rev_file_path, rev_list.dumps(),
                                                  lock_file=rev_file_path + ".lock")
-                return DEFAULT_REVISION_V1
+                return rev_list.latest_revision()
             else:
                 return None
         return rev_list.latest_revision()


Test patch:
diff --git a/conans/test/functional/command/build_test.py b/conans/test/functional/command/build_test.py
index d6ebc886a..f6b6d9c5a 100644
--- a/conans/test/functional/command/build_test.py
+++ b/conans/test/functional/command/build_test.py
@@ -125,8 +125,8 @@ class AConan(ConanFile):
         client.run("build ./my_conanfile.py")
         pref = PackageReference.loads("Hello/0.1@lasote/testing:%s" % NO_SETTINGS_PACKAGE_ID)
         package_folder = client.cache.package(pref).replace("\\", "/")
-        self.assertIn("my_conanfile.py: INCLUDE PATH: %s/include" % package_folder, client.user_io.out)
-        self.assertIn("my_conanfile.py: HELLO ROOT PATH: %s" % package_folder, client.user_io.out)
+        self.assertIn("my_conanfile.py: INCLUDE PATH: %s/include" % package_folder, client.out)
+        self.assertIn("my_conanfile.py: HELLO ROOT PATH: %s" % package_folder, client.out)
         self.assertIn("my_conanfile.py: HELLO INCLUDE PATHS: %s/include"
                       % package_folder, client.user_io.out)
 
@@ -309,3 +309,41 @@ class AConan(ConanFile):
         client.save({CONANFILE: conanfile}, clean_first=True)
         client.run("install . --build missing")
         client.run("build .")
+
+    def build_single_full_reference_test(self):
+        client = TestClient()
+        conanfile = """
+from conans import ConanFile, CMake
+
+class FooConan(ConanFile):
+    name = "foo"
+    version = "1.0"
+"""
+        client.save({CONANFILE: conanfile})
+        client.run("create --build foo/1.0@user/stable . user/stable")
+        self.assertIn("foo/1.0@user/stable: WARN: Forced build from source", client.out)
+
+    def build_multiple_full_reference_test(self):
+        client = TestClient()
+        conanfile = """
+from conans import ConanFile, CMake
+
+class FooConan(ConanFile):
+    name = "foo"
+    version = "1.0"
+"""
+        client.save({CONANFILE: conanfile})
+        client.run("create . user/stable")
+
+        conanfile = """
+from conans import ConanFile
+
+class BarConan(ConanFile):
+    name = "bar"
+    version = "1.0"
+    requires = "foo/1.0@user/stable"
+"""
+        client.save({CONANFILE: conanfile}, clean_first=True)
+        client.run("create --build foo/1.0@user/stable --build bar/1.0@user/testing . user/testing")
+        self.assertIn("foo/1.0@user/stable: WARN: Forced build from source", client.out)
+        self.assertIn("bar/1.0@user/testing: WARN: Forced build from source", client.out)
diff --git a/conans/test/functional/generators/cmake_generator_test.py b/conans/test/functional/generators/cmake_generator_test.py
new file mode 100644
index 000000000..85fa31b52
--- /dev/null
+++ b/conans/test/functional/generators/cmake_generator_test.py
@@ -0,0 +1,64 @@
+import unittest
+
+from nose.plugins.attrib import attr
+
+from conans import tools
+from conans.test.utils.tools import TestClient
+
+
+CONAN_RECIPE = """
+from conans import ConanFile, CMake
+
+class FooConan(ConanFile):
+    name = "foo"
+    version = "0.1"
+    settings = "os_build", "compiler", "build_type"
+    generators = "cmake"
+    exports = '*'
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+"""
+
+
+CPP_CONTENT = """
+int main() {}
+"""
+
+CMAKE_RECIPE = """
+cmake_minimum_required(VERSION 2.8.12)
+project(dummy CXX)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+
+add_executable(dummy dummy.cpp)
+"""
+
+
+@attr("slow")
+class CMakeGeneratorTest(unittest.TestCase):
+
+    def _generator_test_helper(self, os_build, makefile):
+        try:
+            client = TestClient()
+            client.save({"conanfile.py": CONAN_RECIPE,
+                        "CMakeLists.txt": CMAKE_RECIPE,
+                        "dummy.cpp": CPP_CONTENT})
+            client.run("create . lasote/testing -s os_build={}".format(os_build))
+        finally:
+            self.assertNotIn("TypeError: argument of type 'NoneType' is not iterable", client.user_io.out)
+            self.assertNotIn("ERROR:", client.user_io.out)
+            self.assertIn("Check for working CXX compiler", client.user_io.out)
+            self.assertIn('cmake -G "{}"'.format(makefile), client.user_io.out)
+
+    def test_cmake_default_generator_linux(self):
+        self._generator_test_helper("Linux", "Unix Makefiles")
+
+    @unittest.skipUnless(tools.os_info.is_windows, "MinGW is only supported on Windows")
+    def test_cmake_default_generator_windows(self):
+        self._generator_test_helper("Windows", "MinGW Makefiles")
+
+    def test_cmake_default_generator_osx(self):
+        self._generator_test_helper("Macos", "Unix Makefiles")
diff --git a/conans/test/unittests/client/build/cmake_test.py b/conans/test/unittests/client/build/cmake_test.py
index 635607dcb..478be4521 100644
--- a/conans/test/unittests/client/build/cmake_test.py
+++ b/conans/test/unittests/client/build/cmake_test.py
@@ -1037,7 +1037,7 @@ build_type: [ Release]
         self.assertEquals(cmake.generator, "Unix Makefiles")
 
         cmake = instance_with_os_build("Windows")
-        self.assertEquals(cmake.generator, None)
+        self.assertEquals(cmake.generator, "MinGW Makefiles")
 
         with tools.environment_append({"CONAN_CMAKE_GENERATOR": "MyCoolGenerator"}):
             cmake = instance_with_os_build("Windows")
diff --git a/conans/test/unittests/client/graph/build_mode_test.py b/conans/test/unittests/client/graph/build_mode_test.py
new file mode 100644
index 000000000..1ee16c2da
--- /dev/null
+++ b/conans/test/unittests/client/graph/build_mode_test.py
@@ -0,0 +1,73 @@
+import unittest
+
+from conans.client.graph.build_mode import BuildMode
+from conans.model.ref import ConanFileReference
+from conans.errors import ConanException
+
+from conans.test.utils.tools import TestBufferConanOutput
+from conans.test.utils.conanfile import MockConanfile
+
+
+class BuildModeTest(unittest.TestCase):
+
+    def setUp(self):
+        self.output = TestBufferConanOutput()
+        self.conanfile = MockConanfile(None)
+
+    def test_valid_params(self):
+        build_mode = BuildMode(["outdated", "missing"], self.output)
+        self.assertTrue(build_mode.outdated)
+        self.assertTrue(build_mode.missing)
+        self.assertFalse(build_mode.never)
+
+        build_mode = BuildMode(["never"], self.output)
+        self.assertFalse(build_mode.outdated)
+        self.assertFalse(build_mode.missing)
+        self.assertTrue(build_mode.never)
+
+    def test_invalid_configuration(self):
+        with self.assertRaisesRegexp(ConanException,
+                                     "--build=never not compatible with other options"):
+            BuildMode(["outdated", "missing", "never"], self.output)
+
+    def test_common_build_force(self):
+        reference = ConanFileReference.loads("Hello/0.1@user/testing")
+        build_mode = BuildMode(["Hello"], self.output)
+        self.assertTrue(build_mode.forced(self.conanfile, reference))
+        build_mode.report_matches()
+        self.assertEqual("", self.output)
+
+    def test_non_matching_build_force(self):
+        reference = ConanFileReference.loads("Bar/0.1@user/testing")
+        build_mode = BuildMode(["Hello"], self.output)
+        self.assertFalse(build_mode.forced(self.conanfile, reference))
+        build_mode.report_matches()
+        self.assertIn("ERROR: No package matching 'Hello' pattern", self.output)
+
+    def test_full_reference_build_force(self):
+        reference = ConanFileReference.loads("Bar/0.1@user/testing")
+        build_mode = BuildMode(["Bar/0.1@user/testing"], self.output)
+        self.assertTrue(build_mode.forced(self.conanfile, reference))
+        build_mode.report_matches()
+        self.assertEqual("", self.output)
+
+    def test_non_matching_full_reference_build_force(self):
+        reference = ConanFileReference.loads("Bar/0.1@user/stable")
+        build_mode = BuildMode(["Bar/0.1@user/testing"], self.output)
+        self.assertFalse(build_mode.forced(self.conanfile, reference))
+        build_mode.report_matches()
+        self.assertIn("No package matching 'Bar/0.1@user/testing' pattern", self.output)
+
+    def test_multiple_builds(self):
+        reference = ConanFileReference.loads("Bar/0.1@user/stable")
+        build_mode = BuildMode(["Bar", "Foo"], self.output)
+        self.assertTrue(build_mode.forced(self.conanfile, reference))
+        build_mode.report_matches()
+        self.assertIn("ERROR: No package matching", self.output)
+
+    def test_allowed(self):
+        build_mode = BuildMode(["outdated", "missing"], self.output)
+        self.assertTrue(build_mode.allowed(self.conanfile))
+
+        build_mode = BuildMode([], self.output)
+        self.assertFalse(build_mode.allowed(self.conanfile))
diff --git a/conans/test/unittests/client/tools/os_info/osinfo_test.py b/conans/test/unittests/client/tools/os_info/osinfo_test.py
index 0b052d97c..c6f045c91 100644
--- a/conans/test/unittests/client/tools/os_info/osinfo_test.py
+++ b/conans/test/unittests/client/tools/os_info/osinfo_test.py
@@ -1,14 +1,12 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
 
-import unittest
-import platform
 import os
+import unittest
+from mock import mock
+
 from conans.client.tools import OSInfo, environment_append, CYGWIN, MSYS2, MSYS, remove_from_path
 from conans.errors import ConanException
-from mock import mock
-from nose.plugins.attrib import attr
 
 
 class OSInfoTest(unittest.TestCase):
diff --git a/conans/test/unittests/util/tools_test.py b/conans/test/unittests/util/tools_test.py
index 589ecdfc8..f2c04c790 100644
--- a/conans/test/unittests/util/tools_test.py
+++ b/conans/test/unittests/util/tools_test.py
@@ -1646,6 +1646,49 @@ class HelloConan(ConanFile):
         self.assertIn("specify a branch to checkout", client.out)
 
 
+class GitToolsTests(unittest.TestCase):
+
+    def setUp(self):
+        self.folder, self.rev = create_local_git_repo({'myfile.txt': "contents"})
+
+    def test_no_tag(self):
+        """
+        No tags has been created in repo
+        """
+        git = Git(folder=self.folder)
+        tag = git.get_tag()
+        self.assertIsNone(tag)
+
+    def test_in_tag(self):
+        """
+        Current checkout is on a tag
+        """
+        git = Git(folder=self.folder)
+        git.run("tag 0.0.0")
+        tag = git.get_tag()
+        self.assertEqual("0.0.0", tag)
+
+    def test_in_branch_with_tag(self):
+        """
+        Tag is defined but current commit is ahead of it
+        """
+        git = Git(folder=self.folder)
+        git.run("tag 0.0.0")
+        save(os.path.join(self.folder, "file.txt"), "")
+        git.run("add .")
+        git.run("commit -m \"new file\"")
+        tag = git.get_tag()
+        self.assertIsNone(tag)
+
+    def test_get_tag_no_git_repo(self):
+        """
+        Try to get tag out of a git repo
+        """
+        git = Git(folder=temp_folder())
+        with self.assertRaisesRegexp(ConanException, "Not a valid git repository"):
+            git.get_tag()
+
+
 @attr("slow")
 @attr('svn')
 class SVNToolTestsBasic(SVNLocalRepoTestCase):
@@ -1832,15 +1875,46 @@ class SVNToolTestsBasic(SVNLocalRepoTestCase):
 
         svn = SVN(folder=self.gimme_tmp())
         svn.checkout(url='/'.join([project_url, 'prj1', 'branches', 'my_feature']))
-        self.assertEqual("branches/my_feature", svn.get_branch())
+        self.assertEqual("my_feature", svn.get_branch())
 
         svn = SVN(folder=self.gimme_tmp())
         svn.checkout(url='/'.join([project_url, 'prj1', 'branches', 'issue3434']))
-        self.assertEqual("branches/issue3434", svn.get_branch())
+        self.assertEqual("issue3434", svn.get_branch())
 
         svn = SVN(folder=self.gimme_tmp())
         svn.checkout(url='/'.join([project_url, 'prj1', 'tags', 'v12.3.4']))
-        self.assertEqual("tags/v12.3.4", svn.get_branch())
+        self.assertIsNone(svn.get_branch())
+
+        svn = SVN(folder=self.gimme_tmp())
+        with self.assertRaisesRegexp(ConanException, "Unable to get svn branch"):
+            svn.get_branch()
+
+    def test_tag(self):
+        project_url, _ = self.create_project(files={'prj1/trunk/myfile': "contents",
+                                                    'prj1/branches/my_feature/myfile': "",
+                                                    'prj1/branches/issue3434/myfile': "",
+                                                    'prj1/tags/v12.3.4/myfile': "",
+                                                    })
+        svn = SVN(folder=self.gimme_tmp())
+        svn.checkout(url='/'.join([project_url, 'prj1', 'trunk']))
+        self.assertIsNone(svn.get_tag())
+
+        svn = SVN(folder=self.gimme_tmp())
+        svn.checkout(url='/'.join([project_url, 'prj1', 'branches', 'my_feature']))
+        self.assertIsNone(svn.get_tag())
+
+        svn = SVN(folder=self.gimme_tmp())
+        svn.checkout(url='/'.join([project_url, 'prj1', 'branches', 'issue3434']))
+        self.assertIsNone(svn.get_tag())
+
+        svn = SVN(folder=self.gimme_tmp())
+        svn.checkout(url='/'.join([project_url, 'prj1', 'tags', 'v12.3.4']))
+        self.assertEqual("v12.3.4", svn.get_tag())
+
+        svn = SVN(folder=self.gimme_tmp())
+        with self.assertRaisesRegexp(ConanException, "Unable to get svn tag"):
+            svn.get_tag()
+
 
 @attr("slow")
 @attr('svn')