diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 87acbe162d4eb7e5a3b2f83f73abd4baf53c9eed..a4849b4c4f19353a79579d9e4150c7ee18f7b3ff 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,15 +2,14 @@ image: stretch_packages
 
 stages:
   - build
-  - test
 
-before_script:
-  - export LANG="en_US.UTF-8"
-  - export DEBIAN_FRONTEND="noninteractive"
-  - export DEBIAN_PRIORITY="critical"
-  - export DEBFULLNAME="FSMPI Admin-Team"
-  - export DEBEMAIL="admin@fsmpi.rwth-aachen.de"
-  - export QUILT_PATCHES="debian/patches"
+variables:
+  LANG: "en_US.UTF-8"
+  DEBIAN_FRONTEND: "noninteractive"
+  DEBIAN_PRIORITY: "critical"
+  DEBFULLNAME: "FSMPI Admin-Team"
+  DEBEMAIL: "admin@fsmpi.rwth-aachen.de"
+  QUILT_PATCHES: "debian/patches"
 
 sssd:
   stage: build
@@ -63,13 +62,3 @@ painintheapt:
   artifacts: 
     paths: 
       - packages/*
-
-install-grml-zsh-config:
-  stage: test
-  script: dpkg -i packages/grml-zsh-config*.deb
-  only:
-    - master
-
-install-painintheapt:
-  stage: test
-  script: dpkg -i packages/painintheapt*.deb
diff --git a/scripts/adcli.sh b/scripts/adcli.sh
index 7ded7112510aaa23c2bb40d5fdf444e4117eda51..afb06455e41ce1d44ccdbf71a1f369786dbd0635 100755
--- a/scripts/adcli.sh
+++ b/scripts/adcli.sh
@@ -1,31 +1,13 @@
 #!/bin/bash
 
+source "${BASH_SOURCE%/*}/common.sh"
 
+VERSION=$(get_sources adcli stretch)
+import_patches adcli
 
-ADCLI_VERSION=$(rmadison adcli --architecture=amd64 -s stretch| cut -d\| -f2 | sed s"/ //g" | sed s"/\-.*$//g")
-
-apt-get update
-apt-get source --only-source adcli
-TARGET_DIR=adcli-$ADCLI_VERSION
-
-cd ${TARGET_DIR}/debian
-
-for patch in ../../patches/adcli/*.patch ; do
-    quilt import $patch
-done 
-
-cd ..
-
-debchange --preserve --newversion ${ADCLI_VERSION}-fsmpi "Apply the unreleased upstream-patches, fixing RT#100"
-
-apt-get build-dep -y adcli
-
-fakeroot debian/rules binary
-debuild -b -uc -us
-
-cd ..
-mkdir debug packages
-mv *dbgsym* debug
-mv *.deb packages
-
+dch_custom $VERSION "Apply the unreleased upstream-patches, fixing RT#100"
 
+install_build_deps
+build
+test_install
+prepare_artifacts
diff --git a/scripts/common.sh b/scripts/common.sh
new file mode 100755
index 0000000000000000000000000000000000000000..47cdd158bd14c903da60590b6e42cb6c29feefb7
--- /dev/null
+++ b/scripts/common.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+
+# $1: source package name
+# $2: distribution
+# ->: version number retrieved
+function get_sources() {
+	local version
+	apt-get source --only-source -t $2 $1
+	version=$(rmadison $1 --architecture=all,amd64 -s $2 | head -n1 | cut -d\| -f2 | sed s"/ //g" | sed s"/\-.*$//g")
+	cd $1-$version
+	return $version
+}
+
+# $1: source package name
+# $2: git repository
+# ->: version number retrieved
+function get_git_sources() {
+	local version
+	git clone $2 $1
+	cd $1
+	git tag --sort "version:refname" -l | tail -n1 | xargs git checkout
+	version=$(git tag --sort "version:refname" -l | tail -n1 | sed s/v//)
+	return $version
+}
+
+# $1: patch directory name
+function import_patches() {
+	shopt -s nullglob
+	for patch in ../patches/$1/*.patch ; do
+	    quilt import $patch
+	    quilt push
+	done
+}
+
+# $1: patch directory name
+function apply_patches_manually() {
+	shopt -s nullglob
+	for patch in ../patches/$1/*.patch ; do
+		patch -p1 < $patch
+	done
+}
+
+# $1: official version number
+# $2: changelog entry
+function dch_custom() {
+	# TODO consider using local suffixes like backports
+	debchange --preserve --newversion $1-fsmpi $2
+}
+
+function dch_backport() {
+	local version, name
+	version=$(cat /etc/os-release | grep VERSION_ID= | sed -E 's/.*([0-9]+).*/\1/'))
+	name=$(cat /etc/os-release | grep VERSION= | sed 's/.*(\(.*\)).*/\1/')
+	debchange --local ~bpo$version+ --distribution $name-backports "Rebuild for $name-backports."
+}
+
+function install_build_deps() {
+	mk-build-deps --install --remove --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes"
+}
+
+function build() {
+	debuild -us -uc -nc
+}
+
+function test_install() {
+	debi --with-depends
+}
+
+function prepare_artifacts() {
+	cd ..
+	mkdir -p packages sources debug
+	shopt -s nullglob
+	for f in *dbgsym*.deb ; do
+		mv -t debug $f
+	done
+	for f in *.deb ; do
+		mv -t packages $f
+	done
+	for f in *.tar.gz *.changes *.dsc ; do
+		mv -t sources $f
+	done
+}
diff --git a/scripts/ganeti.sh b/scripts/ganeti.sh
index 89d9a8c0fd904aa81ee232682b1952e73b989a0a..1bce22880d1e411a590e732bf9a638b1a5da180e 100755
--- a/scripts/ganeti.sh
+++ b/scripts/ganeti.sh
@@ -1,38 +1,16 @@
 #!/bin/bash
 
+source "${BASH_SOURCE%/*}/common.sh"
 
+VERSION=$(get_sources ganeti stretch)
+import_patches ganeti
 
-GANETI_VERSION=$(rmadison ganeti -s stretch| cut -d\| -f2 | sed s"/ //g" | sed s"/\-.*$//g")
-
-apt-get source --only-source ganeti
-TARGET_DIR=ganeti-$GANETI_VERSION
-
-cd ${TARGET_DIR}/debian
-
-for patch in ../../patches/ganeti/*.patch ; do
-    quilt import $patch
-done 
-
-cd ..
-
-
-function dch() {
-    debchange --preserve --newversion ${GANETI_VERSION}-fsmpi $1
-}
-
-dch "Fix broken ceph support in bdev.py, see GitHub #1233." 
-dch "Remove blockdev storage from the movable and mirrored devices lists."
-dch "Increase maximum disk count per instance."
-dch "Add support for disk cache usage with rbd devices."
-
-apt-get build-dep -y ganeti
-
-fakeroot debian/rules binary
-debuild -b -uc -us
-
-cd ..
-mkdir debug packages
-mv *dbgsym* debug
-mv *.deb packages
-
+dch_custom $VERSION "Fix broken ceph support in bdev.py, see GitHub #1233." 
+dch_custom $VERSION "Remove blockdev storage from the movable and mirrored devices lists."
+dch_custom $VERSION "Increase maximum disk count per instance."
+dch_custom $VERSION "Add support for disk cache usage with rbd devices."
 
+install_build_deps
+build
+test_install
+prepare_artifacts
diff --git a/scripts/grml-zsh-config.sh b/scripts/grml-zsh-config.sh
index 017320daa87d81cd8518efd464ae1178fad9bafc..bf99b855d2b0082d07c4be7f594b89819416fddc 100755
--- a/scripts/grml-zsh-config.sh
+++ b/scripts/grml-zsh-config.sh
@@ -1,27 +1,14 @@
 #!/bin/bash
 
+source "${BASH_SOURCE%/*}/common.sh"
 
-git clone https://github.com/grml/grml-etc-core grml-zsh-config
-cd grml-zsh-config
-git tag --sort "version:refname" -l | tail -n1 | xargs git checkout
-
-GRML_ZSH_CONFIG_VERSION=$(git tag --sort "version:refname" -l | tail -n1 | sed s/v//)
-
-for patch in ../patches/grml-zsh-config/*.patch ; do
-	patch -p1 < ${patch}
-done 
-
+VERSION=$(get_git_sources grml-zsh-config https://github.com/grml/grml-etc-core )
+apply_patches_manually grml-zsh-config
 sed -i s/grml-etc-core/grml-zsh-config/g debian/changelog
 
-debchange --preserve --newversion ${GRML_ZSH_CONFIG_VERSION}-fsmpi "Remove unneeded grml-configs"
-
-apt-get install -y txt2tags debhelper
-
-fakeroot debian/rules binary
-debuild -b -uc -us
-
-cd ..
-mkdir packages
-mv *.deb packages
-
+dch_custom $VERSION "Remove unneeded grml-configs"
 
+install_build_deps
+build
+test_install
+prepare_artifacts
diff --git a/scripts/nginx-shib.sh b/scripts/nginx-shib.sh
index fbb4e912355b1056b6442a16559aa65eac82a03f..f4d7c7237ab19c2c1d9f58e0fb8d55d12f4cf7ba 100755
--- a/scripts/nginx-shib.sh
+++ b/scripts/nginx-shib.sh
@@ -1,33 +1,19 @@
 #!/bin/bash
 
+source "${BASH_SOURCE%/*}/common.sh"
 
+VERSION=$(get_sources nginx stretch)
 
-NGINX_VERSION=$(rmadison nginx -s stretch| cut -d\| -f2 | sed s"/ //g" | sed s"/\-.*$//g")
-
-apt-get source --only-source nginx
-TARGET_DIR=nginx-$NGINX_VERSION
-
-cd ${TARGET_DIR}/debian/modules
-
-git clone "https://github.com/nginx-shib/nginx-http-shibboleth.git"
-
-cd ..
+cd debian
 cp libnginx-mod.nginx.skeleton libnginx-mod-http-shibboleth.nginx
-
-cd ..
-
+cd modules
+git clone "https://github.com/nginx-shib/nginx-http-shibboleth.git"
+cd ../..
 patch -d . -p0 < ../patches/nginx/00-add-module.patch
 
-debchange --preserve --newversion ${NGINX_VERSION}-fsmpi "Add libnginx-mod-http-shibboleth"
-
-apt-get build-dep -y nginx
-
-fakeroot debian/rules binary
-debuild -b -uc -us
-
-cd ..
-mkdir debug packages
-mv *dbgsym* debug
-mv *.deb packages
-
+dch_custom $VERSION "Add libnginx-mod-http-shibboleth"
 
+install_build_deps
+build
+test_install
+prepare_artifacts
diff --git a/scripts/painintheapt.sh b/scripts/painintheapt.sh
index 7480a328417247d9bef57b2bbe6dc19b1565b68b..b09240c21ce0567dfca0977634552f0e22a9ba87 100755
--- a/scripts/painintheapt.sh
+++ b/scripts/painintheapt.sh
@@ -1,27 +1,22 @@
 #!/bin/bash
 
+source "${BASH_SOURCE%/*}/common.sh"
+
 echo "deb-src http://ftp.halifax.rwth-aachen.de/debian/ buster main" > /etc/apt/sources.list.d/buster_src.list
 apt-get update
 
-apt-get source --only-source -t buster painintheapt
-VERSION=$(rmadison painintheapt --architecture=all -s buster | cut -d\| -f2 | sed s"/ //g" | sed s"/\-.*$//g")
-cd painintheapt-$VERSION
+VERSION=$(get_sources painintheapt buster)
+import_patches painintheapt
 
-for patch in ../patches/painintheapt/*.patch ; do
-    quilt import $patch
-    quilt push
-done
 sed -i '/python3-sleekxmpp/d' debian/control
 sed -i 's/Build-Depends: debhelper (>= 11),/Build-Depends: debhelper (>= 10),/g' debian/control
 echo "10" > debian/compat
 
-mk-build-deps --install --remove --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes"
-dch --local ~bpo9+ --distribution stretch-backports "Rebuild for stretch-backports."
-dch --preserve --newversion ${VERSION}-fsmpi "Add HTTP-JSON support."
-dch --preserve --newversion ${VERSION}-fsmpi "Remove XMPP support."
-debuild -us -uc -nc
-debi --with-depends
+dch_backport
+dch_custom $VERSION "Add HTTP-JSON support."
+dch_custom $VERSION "Remove XMPP support."
 
-cd ..
-mkdir packages
-mv *.deb packages
+install_build_deps
+build
+test_install
+prepare_artifacts
diff --git a/scripts/sssd.sh b/scripts/sssd.sh
index 88672a540a4fe9e737ba761814bd9002de597520..256171a75d7ba3ad646aa3eee532c8052e630d79 100755
--- a/scripts/sssd.sh
+++ b/scripts/sssd.sh
@@ -1,17 +1,13 @@
 #!/bin/bash
 
+source "${BASH_SOURCE%/*}/common.sh"
+
 echo "deb-src http://ftp.halifax.rwth-aachen.de/debian/ buster main" > /etc/apt/sources.list.d/buster_src.list
 apt-get update
-apt-get source --only-source -t buster sssd
-SSSD_VERSION=$(rmadison sssd --architecture=amd64 -s buster | cut -d\| -f2 | sed s"/ //g" | sed s"/\-.*$//g")
-cd sssd-$SSSD_VERSION
-mk-build-deps --install --remove --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes"
-dch --local ~bpo9+ --distribution stretch-backports "Rebuild for stretch-backports."
-fakeroot debian/rules binary
-debuild -us -uc -nc
-
-cd ..
-mkdir debug packages
-mv *dbgsym* debug
-mv *.deb packages
 
+get_sources sssd buster
+dch_backport
+install_build_deps
+build
+test_install
+prepare_artifacts