diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000000000000000000000000000000000000..98782486db3c0327ddac9f0f4607a9ec83cc1e34_LmNvdmVyYWdlcmM=
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,4 @@
+[run]
+omit=
+  hgitaly/stub/*
+  hgitaly/tests/*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..98782486db3c0327ddac9f0f4607a9ec83cc1e34_LmdpdGxhYi1jaS55bWw=
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,40 @@
+stages:
+  - lint
+  - test
+
+before_script:
+   - pip3 install --user -r dev-requirements.txt
+
+lint:
+    stage: lint
+    image: octobus/ci-base
+    before_script: []
+    script:
+      - flake8 --exclude stub hgitaly
+
+tests-5.2:
+  stage: test
+  image: octobus/ci-py3-hgext3rd:latest
+  script:
+    # should have a base image for that
+    - hg -R /ci/repos/mercurial up 5.2.1
+    - make -C /ci/repos/mercurial
+    - PYTHONPATH=/ci/repos/mercurial ~/.local/bin/pytest --cov hgitaly --cov-config=.coveragerc -v
+
+tests-hg-stable:
+  stage: test
+  image: octobus/ci-py3-hgext3rd:latest
+  script:
+    - hg pull -R /ci/repos/mercurial/ --rev stable
+    - hg -R /ci/repos/mercurial up stable
+    - make -C /ci/repos/mercurial local PYTHON=python3
+    - PYTHONPATH=/ci/repos/mercurial ~/.local/bin/pytest --cov hgitaly --cov-config=.coveragerc -v
+
+tests-hg-default:
+  stage: test
+  image: octobus/ci-py3-hgext3rd:latest
+  script:
+    - hg pull -R /ci/repos/mercurial/ --rev default
+    - hg -R /ci/repos/mercurial up default
+    - make -C /ci/repos/mercurial local PYTHON=python3
+    - PYTHONPATH=/ci/repos/mercurial ~/.local/bin/pytest --cov hgitaly --cov-config=.coveragerc -v
diff --git a/dev-requirements.txt b/dev-requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..98782486db3c0327ddac9f0f4607a9ec83cc1e34_ZGV2LXJlcXVpcmVtZW50cy50eHQ=
--- /dev/null
+++ b/dev-requirements.txt
@@ -0,0 +1,2 @@
+flake8
+pytest-cov