diff --git a/README.rst b/README.rst index e6d0834..bcfa125 100644 --- a/README.rst +++ b/README.rst @@ -332,6 +332,16 @@ Check a VCS repo for new commits. The version returned is currently not related vcs The url of the remote VCS repo, using the same syntax with a VCS url in PKGBUILD (`Pacman`_'s build script). The first VCS url found in the source array of the PKGBUILD will be used if this is left blank. (Note: for a blank ``vcs`` setting to work correctly, the PKGBUILD has to be in a directory with the name of the software under the path where nvchecker is run. Also, all the commands, if any, needed when sourcing the PKGBUILD need to be installed). +use_max_tag + Set this to ``true`` to check for the max tag. Currently only supported for ``git``. + This option returns the biggest tag sorted by ``pkg_resources.parse_version``. + +ignored_tags + Ignore certain tags while computing the max tag. Tags are separate by + whitespaces. This option must be used together with ``use_max_tag``. This can + be useful to avoid some known badly versioned tags, so the newer tags won't + be "overridden" by the old broken ones. + Other ----- More to come. Send me a patch or pull request if you can't wait and have written one yourself :-) diff --git a/nvchecker/source/vcs.py b/nvchecker/source/vcs.py index b2481f7..d8835b9 100644 --- a/nvchecker/source/vcs.py +++ b/nvchecker/source/vcs.py @@ -4,6 +4,8 @@ from functools import partial import tornado.process from tornado.ioloop import IOLoop +from pkg_resources import parse_version + import os.path as _path logger = logging.getLogger(__name__) @@ -27,19 +29,34 @@ def _parse_oldver(oldver): def get_version(name, conf, callback): vcs = conf['vcs'] + use_max_tag = conf.getboolean('use_max_tag', False) + ignored_tags = conf.get("ignored_tags", "").split() oldver = conf.get('oldver') cmd = _cmd_prefix + [name, vcs] + if use_max_tag: + cmd += ["get_tags"] p = tornado.process.Subprocess(cmd, io_loop=IOLoop.instance(), stdout=tornado.process.Subprocess.STREAM) - p.set_exit_callback(partial(_command_done, name, oldver, callback, p)) + p.set_exit_callback(partial(_command_done, name, oldver, use_max_tag, ignored_tags, callback, p)) -def _command_done(name, oldver, callback, process, status): +def _command_done(name, oldver, use_max_tag, ignored_tags, callback, process, status): if status != 0: logger.error('%s: command exited with %d.', name, status) callback(name, None) else: - process.stdout.read_until_close(partial(_got_version_from_cmd, - callback, name, oldver)) + if use_max_tag: + process.stdout.read_until_close(partial(_got_tags_from_cmd, + callback, name, ignored_tags)) + else: + process.stdout.read_until_close(partial(_got_version_from_cmd, + callback, name, oldver)) + +def _got_tags_from_cmd(callback, name, ignored_tags, output): + output = output.strip().decode('latin1') + data = [tag for tag in output.split("\n") if tag not in ignored_tags] + data.sort(key=parse_version) + version = data[-1] + callback(name, version) def _got_version_from_cmd(callback, name, oldver_str, output): output = output.strip().decode('latin1') diff --git a/nvchecker/source/vcs.sh b/nvchecker/source/vcs.sh index a807cf1..3e7339f 100644 --- a/nvchecker/source/vcs.sh +++ b/nvchecker/source/vcs.sh @@ -5,6 +5,7 @@ exec >&2 dir=$1 vcs=$2 +get_tags=$3 parse_vcs_url() { local _url=$1 @@ -101,6 +102,15 @@ bzr_get_version() { bzr revno -q "${_extra_arg[@]}" "${_url}" } +git_get_tags() { + local _url=$1 + git ls-remote "$_url" | grep -oP '(?<=refs/tags/)[^^]*$' +} + cd "${dir}" get_vcs "${vcs}" components || exit 1 -eval "${components[0]}_get_version"' ${components[@]:1}' >&3 +if [[ "x$get_tags" == "xget_tags" ]]; then + eval "${components[0]}_get_tags"' ${components[@]:1}' >&3 +else + eval "${components[0]}_get_version"' ${components[@]:1}' >&3 +fi diff --git a/tests/test_vcs.py b/tests/test_vcs.py index 092f22b..f6a224d 100644 --- a/tests/test_vcs.py +++ b/tests/test_vcs.py @@ -16,3 +16,15 @@ class VCSTest(ExternalVersionTestCase): def test_mercurial(self): os.path.exists("example") or os.mkdir("example") self.assertEqual(self.sync_get_version("example", {"vcs": "hg+https://bitbucket.org/pil0t/testrepo"}), "1.1.84679e29c7d9") + + @pytest.mark.skipif(shutil.which("git") is None, + reason="requires git command") + def test_git_max_tag(self): + os.path.exists("example") or os.mkdir("example") + self.assertEqual(self.sync_get_version("example", {"vcs": "git+https://github.com/harry-sanabria/ReleaseTestRepo.git", "use_max_tag": 1}), "second_release") + + @pytest.mark.skipif(shutil.which("git") is None, + reason="requires git command") + def test_git_max_tag_with_ignored_tags(self): + os.path.exists("example") or os.mkdir("example") + self.assertEqual(self.sync_get_version("example", {"vcs": "git+https://github.com/harry-sanabria/ReleaseTestRepo.git", "use_max_tag": 1, "ignored_tags": "second_release release3"}), "first_release")