diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3fed1cbc26f5dc775601fc96af06dfbb8ac6304d..01f9528cea1b56dd94359c38a571f94dc8cb9f5c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,5 @@
 stages:
   - init
-  - pre
   - test
   - pages
 
@@ -24,55 +23,127 @@ version:
     paths:
       - badges/
 
-### pretests ###
-tests1:
+### Tests (from scratch) ###
+tests (from scratch):
   tags:
-    - mlt
+    - base
     - zam347
-  stage: pre
+  stage: test
+  only:
+    - master
+    - /^release.*$/
+    - develop
+  variables:
+    FAILURE_THRESHOLD: 100
+  before_script:
+    - chmod +x ./CI/update_badge.sh
+    - ./CI/update_badge.sh > /dev/null
   script:
-    echo "RZobXyF8 working"
+    - zypper --non-interactive install binutils libproj-devel gdal-devel
+    - zypper --non-interactive install proj geos-devel
+    - pip install -r requirements.txt
+    - chmod +x ./CI/run_pytest.sh
+    - ./CI/run_pytest.sh
+  after_script:
+    - ./CI/update_badge.sh > /dev/null
+  artifacts:
+    name: pages
+    when: always
+    paths:
+      - badges/
+      - test_results/
 
-tests2:
+coverage (from scratch):
   tags:
-    - era5
+    - base
     - zam347
-  stage: pre
+  stage: test
+  only:
+    - master
+    - /^release.*$/
+    - develop
+  variables:
+    FAILURE_THRESHOLD: 50
+    COVERAGE_PASS_THRESHOLD: 80
+  before_script:
+    - chmod +x ./CI/update_badge.sh
+    - ./CI/update_badge.sh > /dev/null
   script:
-    echo "vmWZifEA working"
+    - zypper --non-interactive install binutils libproj-devel gdal-devel
+    - zypper --non-interactive install proj geos-devel
+    - pip install -r requirements.txt
+    - chmod +x ./CI/run_pytest_coverage.sh
+    - ./CI/run_pytest_coverage.sh
+  after_script:
+    - ./CI/update_badge.sh > /dev/null
+  artifacts:
+    name: pages
+    when: always
+    paths:
+      - badges/
+      - coverage/
 
-tests3:
+### Tests (on GPU) ###
+tests (on GPU):
   tags:
     - gpu
     - zam347
-  stage: pre
-  script:
-    echo "sRi9-Bvw working"
-
-tests4:
-  tags:
-    - django
-    - zam347
-  stage: pre
+  stage: test
+  only:
+    - master
+    - /^release.*$/
+    - develop
+  variables:
+    FAILURE_THRESHOLD: 100
+  before_script:
+    - chmod +x ./CI/update_badge.sh
+    - ./CI/update_badge.sh > /dev/null
   script:
-    echo "6HmDp9Qd working"
+    - pip install -r requirements.txt
+    - chmod +x ./CI/run_pytest.sh
+    - ./CI/run_pytest.sh
+  after_script:
+    - ./CI/update_badge.sh > /dev/null
+  artifacts:
+    name: pages
+    when: always
+    paths:
+      - badges/
+      - test_results/
 
-tests5:
+coverage (on GPU):
   tags:
-    - base
+    - gpu
     - zam347
-  stage: pre
+  stage: test
+  only:
+    - master
+    - /^release.*$/
+    - develop
+  variables:
+    FAILURE_THRESHOLD: 50
+    COVERAGE_PASS_THRESHOLD: 80
+  before_script:
+    - chmod +x ./CI/update_badge.sh
+    - ./CI/update_badge.sh > /dev/null
   script:
-    echo "xkwF75N9 working"
-
+    - pip install -r requirements.txt
+    - chmod +x ./CI/run_pytest_coverage.sh
+    - ./CI/run_pytest_coverage.sh
+  after_script:
+    - ./CI/update_badge.sh > /dev/null
+  artifacts:
+    name: pages
+    when: always
+    paths:
+      - badges/
+      - coverage/
 
-### Tests (from scratch) ###
+### Tests ###
 tests:
   tags:
-    - leap
+    - machinelearningtools
     - zam347
-    - base
-    - django
   stage: test
   variables:
     FAILURE_THRESHOLD: 100
@@ -94,10 +165,8 @@ tests:
 
 coverage:
   tags:
-    - leap
+    - machinelearningtools
     - zam347
-    - base
-    - django
   stage: test
   variables:
     FAILURE_THRESHOLD: 50
@@ -122,7 +191,6 @@ coverage:
 pages:
   stage: pages
   tags:
-    - leap
     - zam347
     - base
   script: