diff --git a/README.rst b/README.rst
index 4c2bce4..9a8c7d6 100644
--- a/README.rst
+++ b/README.rst
@@ -163,6 +163,25 @@ branch
Anonymously only. Authorization is not supported yet.
+Check GitLab
+-------------
+Check `GitLab `_ for updates. The version returned is in date format ``%Y%m%d``, e.g. ``20130701``.
+
+gitlab
+ The gitlab repository, with author, e.g. ``Deepin/deepin-music``.
+
+branch
+ Which branch to track? Default: ``master``.
+
+use_max_tag
+ Set this to ``true`` to check for the max tag on BitBucket. Will return the biggest one
+ sorted by ``pkg_resources.parse_version``.
+
+host
+ Hostname for self-hosted GitLab instance.
+
+Authenticated only.
+
Check PyPI
----------
Check `PyPI `_ for updates.
diff --git a/nvchecker/get_version.py b/nvchecker/get_version.py
index ed58ef2..c403d8e 100644
--- a/nvchecker/get_version.py
+++ b/nvchecker/get_version.py
@@ -5,7 +5,7 @@ logger = logging.getLogger(__name__)
handler_precedence = (
'github', 'gitcafe', 'aur', 'pypi', 'archpkg', 'gems', 'pacman',
'cmd', 'bitbucket', 'gcode_hg', 'gcode_svn', 'regex', 'manual', 'vcs',
- 'npm', 'hackage', 'cpan',
+ 'npm', 'hackage', 'cpan', 'gitlab',
)
def get_version(name, conf, callback):
diff --git a/nvchecker/source/gitlab.py b/nvchecker/source/gitlab.py
new file mode 100644
index 0000000..34fade7
--- /dev/null
+++ b/nvchecker/source/gitlab.py
@@ -0,0 +1,45 @@
+import os
+import json
+from functools import partial
+import logging
+import urllib.parse
+
+from pkg_resources import parse_version
+from tornado.httpclient import AsyncHTTPClient, HTTPRequest
+
+GITLAB_URL = 'https://%s/api/v3/projects/%s/repository/commits?ref_name=%s'
+GITLAB_MAX_TAG = 'https://%s/api/v3/projects/%s/repository/tags'
+
+logger = logging.getLogger(__name__)
+
+def get_version(name, conf, callback):
+ repo = urllib.parse.quote_plus(conf.get('gitlab'))
+ br = conf.get('branch', 'master')
+ host = conf.get('host', "gitlab.com")
+ use_max_tag = conf.getboolean('use_max_tag', False)
+
+ env_name = "NVCHECKER_GITLAB_TOKEN_" + host.upper().replace(".", "_").replace("/", "_")
+ token = conf.get('token', os.environ.get(env_name, None))
+ if token is None:
+ logger.error('%s: No gitlab token specified.', name)
+ callback(name, None)
+ return
+
+ if use_max_tag:
+ url = GITLAB_MAX_TAG % (host, repo)
+ else:
+ url = GITLAB_URL % (host, repo, br)
+
+ headers = {"PRIVATE-TOKEN": token}
+ request = HTTPRequest(url, headers=headers, user_agent='lilydjwg/nvchecker')
+ AsyncHTTPClient().fetch(request,
+ callback=partial(_gitlab_done, name, use_max_tag, callback))
+
+def _gitlab_done(name, use_max_tag, callback, res):
+ data = json.loads(res.body.decode('utf-8'))
+ if use_max_tag:
+ data.sort(key=lambda tag: parse_version(tag["name"]))
+ version = data[-1]["name"]
+ else:
+ version = data[0]['created_at'].split('T', 1)[0].replace('-', '')
+ callback(name, version)
diff --git a/tests/test_gitlab.py b/tests/test_gitlab.py
new file mode 100644
index 0000000..1aca3bc
--- /dev/null
+++ b/tests/test_gitlab.py
@@ -0,0 +1,13 @@
+import os
+import pytest
+from tests.helper import ExternalVersionTestCase
+
+
+@pytest.mark.skipif("NVCHECKER_GITLAB_TOKEN_GITLAB_COM" not in os.environ,
+ reason="requires NVCHECKER_GITLAB_TOKEN_GITLAB_COM")
+class GitLabTest(ExternalVersionTestCase):
+ def test_gitlab(self):
+ self.assertEqual(self.sync_get_version("example", {"gitlab": "gitlab-org/gitlab-test"}), "20150825")
+
+ def test_gitlab_max_tag(self):
+ self.assertEqual(self.sync_get_version("example", {"gitlab": "gitlab-org/gitlab-test", "use_max_tag": 1}), "v1.1.0")