diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7cc5a7c075b5bc00c7f84c0863fe11aa12f8a961
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,31 @@
+stages:
+  - trigger pipelines
+
+variables:
+  IMAGE_REGISTRY_URL: $CI_REGISTRY/dumux-repositories/dumux-docker-ci
+
+# rules for the default triggers:
+# - pipelines are triggered for merge requests and external triggers (e.g. nightly build in dumux)
+# - Within merge requests, we require to start the pipeline manually by clicking play for the trigger
+# - if the pipeline was triggered externally (from dumux), we may receive merge-request-related variables
+.default-trigger:
+  stage: trigger pipelines
+  trigger:
+    include:
+      - local: .gitlab-ci/default.yml
+    strategy: depend
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "pipeline"
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+      when: manual
+  variables:
+    TRIGGER_SOURCE: $CI_PIPELINE_SOURCE
+    MR_TARGET_BRANCH_NAME: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
+    DUMUX_PIPELINE_SOURCE: $DUMUX_PIPELINE_SOURCE
+    DUMUX_MR_SOURCE_BRANCH: $DUMUX_MERGE_REQUEST_SOURCE_BRANCH
+    DUMUX_MR_TARGET_BRANCH: $DUMUX_MERGE_REQUEST_TARGET_BRANCH
+
+full-dune-2.7-gcc:
+  extends: .default-trigger
+  variables:
+    IMAGE: $IMAGE_REGISTRY_URL/full:dune-2.7-gcc-ubuntu-20.04
diff --git a/.gitlab-ci/default.yml b/.gitlab-ci/default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..633672b054954e7ef43e1d769e7e0b0b2d052c23
--- /dev/null
+++ b/.gitlab-ci/default.yml
@@ -0,0 +1,109 @@
+default:
+  image: $IMAGE
+
+stages:
+  - configure
+  - build
+  - test
+
+workflow:
+  rules:
+    - if: $CI_PIPELINE_SOURCE=="parent_pipeline"
+
+# variables that may be overwritten by the trigger
+variables:
+  TRIGGER_SOURCE: "unknown"
+  MR_TARGET_BRANCH_NAME: "master"
+  DUMUX_PIPELINE_SOURCE: "unknown"
+  DUMUX_MR_SOURCE_BRANCH: "unknown"
+  DUMUX_MR_TARGET_BRANCH: "unknown"
+
+select tests:
+  stage: configure
+  before_script:
+    - |
+      if [[ "$DUMUX_PIPELINE_SOURCE" == "merge_request_event" ]]; then
+          echo "Cloning upstream merge request source/target branches ${DUMUX_MR_SOURCE_BRANCH}/${DUMUX_MR_TARGET_BRANCH}"
+          git clone -b ${DUMUX_MR_SOURCE_BRANCH} --depth=1 https://git.iws.uni-stuttgart.de/dumux-repositories/dumux.git
+          pushd dumux
+              git fetch --depth=1 origin ${DUMUX_MR_TARGET_BRANCH}:${DUMUX_MR_TARGET_BRANCH}
+          popd
+      else
+          echo "Cloning into Dumux master"
+          git clone -b master --depth 1 https://git.iws.uni-stuttgart.de/dumux-repositories/dumux.git
+      fi
+    - dunecontrol --opts=$DUNE_OPTS_FILE --only=dumux all
+  script:
+    - dunecontrol --opts=$DUNE_OPTS_FILE --current all
+    - |
+      if [[ "$DUMUX_PIPELINE_SOURCE" == "merge_request_event" ]]; then
+          CHECK_FOLDER="dumux"
+          SOURCE_TREE=$DUMUX_MR_SOURCE_BRANCH
+          TARGET_TREE=$DUMUX_MR_TARGET_BRANCH
+      elif [[ "$TRIGGER_SOURCE" == "merge_request_event" ]]; then
+          CHECK_FOLDER="."
+          SOURCE_TREE="HEAD"
+          TARGET_TREE=origin/$MR_TARGET_BRANCH_NAME
+      fi
+    - |
+      if [[ -n "$SOURCE_TREE" ]]; then
+          echo "Detecting tests affected by changes in folder $CHECK_FOLDER,"
+          echo "using source/target trees: $SOURCE_TREE / $TARGET_TREE"
+          python3 dumux/bin/testing/getchangedfiles.py --folder $CHECK_FOLDER \
+                                                       --source-tree $SOURCE_TREE \
+                                                       --target-tree $TARGET_TREE \
+                                                       --outfile changedfiles.txt
+          python3 dumux/bin/testing/findtests.py --outfile affectedtests.json \
+                                                 --file-list changedfiles.txt \
+                                                 --build-dir build-cmake
+      else
+          echo "Received trigger source / dumux pipeline source: $TRIGGER_SOURCE / $DUMUX_PIPELINE_SOURCE"
+          echo "Skipping test selection, build/test stages will consider all tests!"
+          touch affectedtests.json
+      fi
+  artifacts:
+    paths:
+      - dumux
+      - build-cmake
+      - affectedtests.json
+    expire_in: 3 hours
+
+build lecture:
+  stage: build
+  script:
+    - |
+      pushd build-cmake
+        make clean
+        if [ -s ../affectedtests.json ]; then
+          python3 ../dumux/bin/testing/runselectedtests.py -c ../affectedtests.json -b
+        else
+          python3 ../dumux/bin/testing/runselectedtests.py --all -b
+        fi
+      popd
+  artifacts:
+    paths:
+      - build-cmake
+      - dumux
+      - affectedtests.json
+    expire_in: 3 hours
+
+test lecture:
+  stage: test
+  variables:
+    OMPI_ALLOW_RUN_AS_ROOT: 1
+    OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1
+  script:
+    - |
+      pushd build-cmake
+        if [ -s ../affectedtests.json ]; then
+          python3 ../dumux/bin/testing/runselectedtests.py -c ../affectedtests.json -t
+        else
+          python3 ../dumux/bin/testing/runselectedtests.py --all -t
+        fi
+      popd
+  needs:
+    - job: build lecture
+      artifacts: true
+  artifacts:
+    reports:
+      junit: junit/dumux-lecture-cmake.xml
diff --git a/lecture/efm/1p2c_2p_2p2c/CMakeLists.txt b/lecture/efm/1p2c_2p_2p2c/CMakeLists.txt
index 21994f415221d71a8fd5cdf4070f5ac5c1d9d706..246e7ef6d1df0aed5e11f3d2c387a67f5cbab863 100644
--- a/lecture/efm/1p2c_2p_2p2c/CMakeLists.txt
+++ b/lecture/efm/1p2c_2p_2p2c/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME lens2pexercise3
+dumux_add_test(NAME lens2pexercise3
               SOURCES lens2pexercise3.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
@@ -8,7 +8,7 @@ dune_add_test(NAME lens2pexercise3
                                ${CMAKE_CURRENT_BINARY_DIR}/lens-2p-00011.vtu
                        --command "${CMAKE_CURRENT_BINARY_DIR}/lens2pexercise3 -ParameterFile ${CMAKE_CURRENT_SOURCE_DIR}/exercise3.input -Problem.Name lens-2p")
 
-dune_add_test(NAME lens2p2cexercise3
+dumux_add_test(NAME lens2p2cexercise3
               SOURCES lens2p2cexercise3.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
@@ -16,7 +16,7 @@ dune_add_test(NAME lens2p2cexercise3
                                ${CMAKE_CURRENT_BINARY_DIR}/lens-2p2c-00011.vtu
                        --command "${CMAKE_CURRENT_BINARY_DIR}/lens2p2cexercise3 -ParameterFile ${CMAKE_CURRENT_SOURCE_DIR}/exercise3.input -Problem.Name lens-2p2c")
 
-dune_add_test(NAME lens1p2cexercise3
+dumux_add_test(NAME lens1p2cexercise3
               SOURCES lens1p2cexercise3.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/efm/1p2cvs2p/CMakeLists.txt b/lecture/efm/1p2cvs2p/CMakeLists.txt
index 54cb2fc76fa045900646eb13bbc4b543eb21375c..cf38fb0427d2c1199b9d9974d8c8a88da10a1275 100644
--- a/lecture/efm/1p2cvs2p/CMakeLists.txt
+++ b/lecture/efm/1p2cvs2p/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME lens1p2cexercise1
+dumux_add_test(NAME lens1p2cexercise1
               SOURCES lens1p2cexercise1.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
@@ -9,7 +9,7 @@ dune_add_test(NAME lens1p2cexercise1
                        --command "${CMAKE_CURRENT_BINARY_DIR}/lens1p2cexercise1 ${CMAKE_CURRENT_SOURCE_DIR}/exercise1.input -Problem.Name lens-1p2c"
                        --zeroThreshold {"x^N2_liq":1e-18,"X^N2_liq":1e-18})
 
-dune_add_test(NAME lens2pexercise1
+dumux_add_test(NAME lens2pexercise1
               SOURCES lens2pexercise1.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/efm/2p/CMakeLists.txt b/lecture/efm/2p/CMakeLists.txt
index d90e9171d45af944c948253863c461f603625d37..e43dcbdd496f108dab3bc237a7423766edac5807 100644
--- a/lecture/efm/2p/CMakeLists.txt
+++ b/lecture/efm/2p/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME lens2pexercise2
+dumux_add_test(NAME lens2pexercise2
               SOURCES lens2pexercise2.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mhs/groundwater/CMakeLists.txt b/lecture/mhs/groundwater/CMakeLists.txt
index efd16dde7fe3401c67cea9dcc280e5f5f457390c..ff1a2640f5b1ecdd316bf308980d0f3b6d8b635e 100644
--- a/lecture/mhs/groundwater/CMakeLists.txt
+++ b/lecture/mhs/groundwater/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME groundwater
+dumux_add_test(NAME groundwater
               SOURCES groundwater.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/buckleyleverett/CMakeLists.txt b/lecture/mm/buckleyleverett/CMakeLists.txt
index b905401295c9c163ad13e6ce6058b42d78757370..ecc346e31ecaa3f7e578d4f8724be65b725d3411 100644
--- a/lecture/mm/buckleyleverett/CMakeLists.txt
+++ b/lecture/mm/buckleyleverett/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME buckleyleverettexercise
+dumux_add_test(NAME buckleyleverettexercise
               SOURCES buckleyleverettexercise.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/co2plume/CMakeLists.txt b/lecture/mm/co2plume/CMakeLists.txt
index 4841ec021996595197a1a4dff439e625b1cb7b89..167a7ee1fbd5d3d0cbd37bf64972c996ec14100c 100644
--- a/lecture/mm/co2plume/CMakeLists.txt
+++ b/lecture/mm/co2plume/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME co2plumeshapeexercise
+dumux_add_test(NAME co2plumeshapeexercise
               SOURCES co2plumeshapeexercise.cc
               COMPILE_DEFINITIONS TYPETAG=PlumeShapeBoxTypeTag
               TIMEOUT 1800
diff --git a/lecture/mm/columnxylene/CMakeLists.txt b/lecture/mm/columnxylene/CMakeLists.txt
index dc69964f72c6c123e42b5b07ac6537c483f85107..1aa99f375ba60ca95c56099fa9a4f598c658d9b1 100644
--- a/lecture/mm/columnxylene/CMakeLists.txt
+++ b/lecture/mm/columnxylene/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_input_file_links()
 dune_symlink_to_source_files(FILES grids)
 
-dune_add_test(NAME columnxyleneexercise
+dumux_add_test(NAME columnxyleneexercise
               SOURCES columnxyleneexercise.cc
               COMPILE_DEFINITIONS TYPETAG=ColumnProblemBoxTypeTag
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
diff --git a/lecture/mm/convectivemixing/CMakeLists.txt b/lecture/mm/convectivemixing/CMakeLists.txt
index 17461a61e73b794f631e195e8589ad993ea5b086..5fefd10a5a17225466ac90684378d940d5f8ee5c 100644
--- a/lecture/mm/convectivemixing/CMakeLists.txt
+++ b/lecture/mm/convectivemixing/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(COMPILE_ONLY # the test produces different results due to the fingers on different machines
+dumux_add_test(COMPILE_ONLY # the test produces different results due to the fingers on different machines
               NAME convmixexercise
               SOURCES convmixexercise.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
diff --git a/lecture/mm/fractures/CMakeLists.txt b/lecture/mm/fractures/CMakeLists.txt
index e7be2a5e462dee8526089606a3c54ac52f86c021..64a7575b7a1f3c64e32988ce228d891c73f92e8f 100644
--- a/lecture/mm/fractures/CMakeLists.txt
+++ b/lecture/mm/fractures/CMakeLists.txt
@@ -1,7 +1,7 @@
 dune_symlink_to_source_files(FILES "grids" "fracture_exercise.input" "plot.p")
 
 # test for the exercise
-dune_add_test(NAME fracture_exercise
+dumux_add_test(NAME fracture_exercise
               CMAKE_GUARD "( dune-foamgrid_FOUND AND dune-alugrid_FOUND )"
               SOURCES fractures.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
diff --git a/lecture/mm/fuelcell/CMakeLists.txt b/lecture/mm/fuelcell/CMakeLists.txt
index 8f815a388574c87435dece72090f847d430e6215..29e35807c1eea33373a97805b6f6f650ecb74d71 100644
--- a/lecture/mm/fuelcell/CMakeLists.txt
+++ b/lecture/mm/fuelcell/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME fuelcell
+dumux_add_test(NAME fuelcell
               TIMEOUT 1800
               SOURCES fuelcell.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
diff --git a/lecture/mm/heatpipe/CMakeLists.txt b/lecture/mm/heatpipe/CMakeLists.txt
index 957a787a6834631d8d966d1ed0b9f31ae87f697f..bd97ed9f5f48839c464a95b6943e4ee69b123023 100644
--- a/lecture/mm/heatpipe/CMakeLists.txt
+++ b/lecture/mm/heatpipe/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_input_file_links()
 dune_symlink_to_source_files(FILES grids)
 
-dune_add_test(NAME heatpipe
+dumux_add_test(NAME heatpipe
               SOURCES heatpipe.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/heavyoil/sagd/CMakeLists.txt b/lecture/mm/heavyoil/sagd/CMakeLists.txt
index a11e9f50f016c095e6171b1e28b4dd72840b21ad..8fae54ed17a6735720337747d1af686aed351be4 100644
--- a/lecture/mm/heavyoil/sagd/CMakeLists.txt
+++ b/lecture/mm/heavyoil/sagd/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME sagd
+dumux_add_test(NAME sagd
               SOURCES sagd.cc
               TIMEOUT 1800
               COMMAND ${CMAKE_CURRENT_BINARY_DIR}/sagd
diff --git a/lecture/mm/heavyoil/sagdcyclic/CMakeLists.txt b/lecture/mm/heavyoil/sagdcyclic/CMakeLists.txt
index 0d84e1f3af49a993ac861bed833c474132226b83..208f39470007c6828b0ffd45474a1506bd381897 100644
--- a/lecture/mm/heavyoil/sagdcyclic/CMakeLists.txt
+++ b/lecture/mm/heavyoil/sagdcyclic/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME sagd_cyclic
+dumux_add_test(NAME sagd_cyclic
               SOURCES sagd_cyclic.cc
               TIMEOUT 1800
               COMMAND ${CMAKE_CURRENT_BINARY_DIR}/sagd_cyclic
diff --git a/lecture/mm/heavyoil/sagdcyclichyst/CMakeLists.txt b/lecture/mm/heavyoil/sagdcyclichyst/CMakeLists.txt
index d3727285ea3ff8cc77681a0f4471defabf3e5d7d..cdab63597f24004396d3d42a480df3aa4594234f 100644
--- a/lecture/mm/heavyoil/sagdcyclichyst/CMakeLists.txt
+++ b/lecture/mm/heavyoil/sagdcyclichyst/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME sagd_cyclic_hyst
+dumux_add_test(NAME sagd_cyclic_hyst
               SOURCES sagd_cyclic_hyst.cc
               TIMEOUT 1800
               COMMAND ${CMAKE_CURRENT_BINARY_DIR}/sagd_cyclic_hyst
diff --git a/lecture/mm/henryproblem/henry1p2c/CMakeLists.txt b/lecture/mm/henryproblem/henry1p2c/CMakeLists.txt
index 0d6cb332e7c97f13ef6c8d0403e8d8bc2a2e3996..fb633db7044bed6bc87b648f252e0ad5e92251ed 100644
--- a/lecture/mm/henryproblem/henry1p2c/CMakeLists.txt
+++ b/lecture/mm/henryproblem/henry1p2c/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_input_file_links()
 dune_symlink_to_source_files(FILES grids)
 
-dune_add_test(NAME henry1p2c
+dumux_add_test(NAME henry1p2c
               SOURCES henry1p2c.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/henryproblem/henry2p/CMakeLists.txt b/lecture/mm/henryproblem/henry2p/CMakeLists.txt
index 753fd58ae0980f76b585375af7ef17e59508ddec..7cdfbd6cbd7d51c273d88cc94bc1eda331ede059 100644
--- a/lecture/mm/henryproblem/henry2p/CMakeLists.txt
+++ b/lecture/mm/henryproblem/henry2p/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_input_file_links()
 dune_symlink_to_source_files(FILES grids)
 
-dune_add_test(NAME henry2p
+dumux_add_test(NAME henry2p
               SOURCES henry2p.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/mcwhorter/CMakeLists.txt b/lecture/mm/mcwhorter/CMakeLists.txt
index c78e7f9fcbaa93b6d58297de511297157d210758..7d3ff65d5d7ddd995bb9285887778551e58f2227 100644
--- a/lecture/mm/mcwhorter/CMakeLists.txt
+++ b/lecture/mm/mcwhorter/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links()
 
-dune_add_test(NAME mcwhorterexercise
+dumux_add_test(NAME mcwhorterexercise
               SOURCES mcwhorterexercise.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/naplinfiltration/3p/CMakeLists.txt b/lecture/mm/naplinfiltration/3p/CMakeLists.txt
index 1103704e9259bce858a2890bf56ba757d2643135..e73378eb583e3b9f30804da5d7a726b7e3760285 100644
--- a/lecture/mm/naplinfiltration/3p/CMakeLists.txt
+++ b/lecture/mm/naplinfiltration/3p/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_input_file_links()
 
 # for the test only simulate one week
-dune_add_test(NAME naplinfiltration3p
+dumux_add_test(NAME naplinfiltration3p
               SOURCES naplinfiltration3p.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/naplinfiltration/3p3c/CMakeLists.txt b/lecture/mm/naplinfiltration/3p3c/CMakeLists.txt
index 836089840e774d55b0e67acb06d3c18a98fe30d7..565d7f7cdca4fce6ec42fce848c2520f65a5ab68 100644
--- a/lecture/mm/naplinfiltration/3p3c/CMakeLists.txt
+++ b/lecture/mm/naplinfiltration/3p3c/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_input_file_links()
 
 # for the test only simulate one week
-dune_add_test(NAME naplinfiltration3p3c
+dumux_add_test(NAME naplinfiltration3p3c
               SOURCES naplinfiltration3p3c.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py
               CMD_ARGS --script fuzzy
diff --git a/lecture/mm/remediationscenarios/CMakeLists.txt b/lecture/mm/remediationscenarios/CMakeLists.txt
index 3657666d5e8a74094ab29fa0c557fb01bb07d826..973342693597726973b24a74bdf286a67a8e8e3b 100644
--- a/lecture/mm/remediationscenarios/CMakeLists.txt
+++ b/lecture/mm/remediationscenarios/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_input_file_links(remediationscenariosexercise.input)
 
-dune_add_test(NAME remediationscenariosexercise
+dumux_add_test(NAME remediationscenariosexercise
               TIMEOUT 1800
               SOURCES remediationscenariosexercise.cc
               COMMAND ${dumux_INCLUDE_DIRS}/bin/testing/runtest.py