summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2020-04-20 16:40:50 +0100
committerEmmanuele Bassi <ebassi@gnome.org>2020-04-22 14:52:02 +0100
commit822dd6c670eba4b6d41982222460446f14d277bd (patch)
treea73de3aeb9a2b6c9bc94c5e0a540c0815405cd1e
parent4801e4657bfa6633a14e79e3f54c6ab460d4e01b (diff)
downloadatk-822dd6c670eba4b6d41982222460446f14d277bd.tar.gz
Add CI pipeline for ATK
Use the GitLab CI support to build ATK, so we can at least be confident that we're not breaking stuff with every commit.
-rw-r--r--.gitlab-ci.yml65
-rw-r--r--.gitlab-ci/README.md38
-rw-r--r--.gitlab-ci/debian-stable.Dockerfile44
-rw-r--r--.gitlab-ci/fedora-latest.Dockerfile38
-rwxr-xr-x.gitlab-ci/meson-junit-report.py111
-rwxr-xr-x.gitlab-ci/run-docker.sh135
-rwxr-xr-x.gitlab-ci/run-tests-docker.sh26
-rwxr-xr-x.gitlab-ci/setup-build-docker.sh8
8 files changed, 465 insertions, 0 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..b67fafa
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,65 @@
+stages:
+ - build
+ - docs
+ - deploy
+
+.cache-paths: &cache-paths
+ paths:
+ - _ccache/
+
+# Common variables
+variables:
+ COMMON_MESON_FLAGS: "--fatal-meson-warnings --werror"
+ MESON_TEST_TIMEOUT_MULTIPLIER: 2
+
+.default-build:
+ script:
+ - .gitlab-ci/setup-build-docker.sh
+ - ninja -C _build
+ - .gitlab-ci/run-tests-docker.sh _build
+ artifacts:
+ when: always
+ reports:
+ junit:
+ - "${CI_PROJECT_DIR}/_build/report.xml"
+ name: "atk-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}"
+ paths:
+ - "_build/meson-logs"
+ - "_build/report.xml"
+
+fedora-latest:
+ extends: .default-build
+ stage: build
+ image: registry.gitlab.gnome.org/gnome/atk/fedora-latest:v1
+ variables:
+ EXTRA_MESON_FLAGS: "-Dbuildtype=debug -Ddefault_library=both"
+
+debian-stable:
+ extends: .default-build
+ stage: build
+ image: registry.gitlab.gnome.org/gnome/atk/debian-stable:v1
+ variables:
+ EXTRA_MESON_FLAGS: "-Dbuildtype=debug -Ddefault_library=both"
+
+reference:
+ image: registry.gitlab.gnome.org/gnome/atk/fedora-latest:v1
+ stage: docs
+ variables:
+ EXTRA_MESON_FLAGS: "--buildtype=release -Ddocs=true"
+ script:
+ - .gitlab-ci/setup-build-docker.sh
+ - ninja -C _build atk-doc
+ - mv _build/docs/html _reference
+ artifacts:
+ paths:
+ - _reference
+
+pages:
+ stage: deploy
+ script:
+ - mv _reference/ public/
+ artifacts:
+ paths:
+ - public
+ only:
+ - master
diff --git a/.gitlab-ci/README.md b/.gitlab-ci/README.md
new file mode 100644
index 0000000..b090cfb
--- /dev/null
+++ b/.gitlab-ci/README.md
@@ -0,0 +1,38 @@
+## ATK CI infrastructure
+
+ATK uses different CI images depending on platform and jobs.
+
+The CI images are Docker containers, generated either using `docker` or
+`podman`, and pushed to the GitLab [container registry][registry].
+
+Each Docker image has a tag composed of two parts:
+
+ - `${image}`: the base image for a given platform, like "fedora-latest"
+ or "debian-stable"
+ - `${number}`: an incremental version number, or `latest`
+
+See the [container registry][registry] for the available images for each
+branch, as well as their available versions.
+
+### Checklist for Updating a CI image
+
+ - [ ] Update the `${image}.Dockerfile` file with the dependencies
+ - [ ] Run `./run-docker.sh build --base ${image} --base-version ${number}`
+ - [ ] Run `./run-docker.sh push --base ${image} --base-version ${number}`
+ once the Docker image is built; you may need to log in by using
+ `docker login` or `podman login`
+ - [ ] Update the `image` keys in the `.gitlab-ci.yml` file with the new
+ image tag
+ - [ ] Open a merge request with your changes and let it run
+
+### Checklist for Adding a new CI image
+
+ - [ ] Write a new `${image}.Dockerfile` with the instructions to set up
+ a build environment
+ - [ ] Add the `pip3 install meson` incantation
+ - [ ] Run `./run-docker.sh build --base ${image} --base-version ${number}`
+ - [ ] Run `./run-docker.sh push --base ${image} --base-version ${number}`
+ - [ ] Add the new job to `.gitlab-ci.yml` referencing the image
+ - [ ] Open a merge request with your changes and let it run
+
+[registry]: https://gitlab.gnome.org/GNOME/atk/container_registry
diff --git a/.gitlab-ci/debian-stable.Dockerfile b/.gitlab-ci/debian-stable.Dockerfile
new file mode 100644
index 0000000..75e2105
--- /dev/null
+++ b/.gitlab-ci/debian-stable.Dockerfile
@@ -0,0 +1,44 @@
+FROM debian:buster
+
+RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \
+ ccache \
+ dconf-gsettings-backend \
+ g++ \
+ gcc \
+ gettext \
+ git \
+ gobject-introspection \
+ itstool \
+ libc6-dev \
+ libgirepository1.0-dev \
+ libglib2.0-dev \
+ libwayland-dev \
+ libx11-dev \
+ libxml2-dev \
+ libxrandr-dev \
+ locales \
+ ninja-build \
+ pkg-config \
+ python3 \
+ python3-pip \
+ python3-setuptools \
+ python3-wheel \
+ shared-mime-info \
+ wayland-protocols \
+ xauth \
+ xvfb \
+ && rm -rf /usr/share/doc/* /usr/share/man/*
+
+# Locale for our build
+RUN locale-gen C.UTF-8 && /usr/sbin/update-locale LANG=C.UTF-8
+
+ARG HOST_USER_ID=5555
+ENV HOST_USER_ID ${HOST_USER_ID}
+RUN useradd -u $HOST_USER_ID -ms /bin/bash user
+
+USER user
+WORKDIR /home/user
+
+RUN pip3 install --user meson==0.49.2
+
+ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
diff --git a/.gitlab-ci/fedora-latest.Dockerfile b/.gitlab-ci/fedora-latest.Dockerfile
new file mode 100644
index 0000000..b257596
--- /dev/null
+++ b/.gitlab-ci/fedora-latest.Dockerfile
@@ -0,0 +1,38 @@
+FROM fedora:31
+
+RUN dnf -y install \
+ at-spi2-atk-devel \
+ ccache \
+ dbus-x11 \
+ gcc \
+ gcc-c++ \
+ gettext \
+ gettext-devel \
+ git \
+ glib2-devel \
+ gobject-introspection-devel \
+ gtk-doc \
+ iso-codes \
+ itstool \
+ make \
+ meson \
+ ninja-build \
+ python3 \
+ python3-pip \
+ python3-wheel \
+ redhat-rpm-config \
+ wayland-devel \
+ wayland-protocols-devel \
+ xorg-x11-server-Xvfb \
+ && dnf clean all
+
+ARG HOST_USER_ID=5555
+ENV HOST_USER_ID ${HOST_USER_ID}
+RUN useradd -u $HOST_USER_ID -ms /bin/bash user
+
+USER user
+WORKDIR /home/user
+
+RUN pip3 install --user meson==0.49.2
+
+ENV LANG C.utf8
diff --git a/.gitlab-ci/meson-junit-report.py b/.gitlab-ci/meson-junit-report.py
new file mode 100755
index 0000000..623f275
--- /dev/null
+++ b/.gitlab-ci/meson-junit-report.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+
+# Turns a Meson testlog.json file into a JUnit XML report
+#
+# Copyright 2019 GNOME Foundation
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Original author: Emmanuele Bassi
+
+import argparse
+import datetime
+import json
+import os
+import sys
+import xml.etree.ElementTree as ET
+
+aparser = argparse.ArgumentParser(description='Turns a Meson test log into a JUnit report')
+aparser.add_argument('--project-name', metavar='NAME',
+ help='The project name',
+ default='unknown')
+aparser.add_argument('--job-id', metavar='ID',
+ help='The job ID for the report',
+ default='Unknown')
+aparser.add_argument('--branch', metavar='NAME',
+ help='Branch of the project being tested',
+ default='master')
+aparser.add_argument('--output', metavar='FILE',
+ help='The output file, stdout by default',
+ type=argparse.FileType('w', encoding='UTF-8'),
+ default=sys.stdout)
+aparser.add_argument('infile', metavar='FILE',
+ help='The input testlog.json, stdin by default',
+ type=argparse.FileType('r', encoding='UTF-8'),
+ default=sys.stdin)
+
+args = aparser.parse_args()
+
+outfile = args.output
+
+testsuites = ET.Element('testsuites')
+testsuites.set('id', '{}/{}'.format(args.job_id, args.branch))
+testsuites.set('package', args.project_name)
+testsuites.set('timestamp', datetime.datetime.utcnow().isoformat(timespec='minutes'))
+
+suites = {}
+for line in args.infile:
+ data = json.loads(line)
+ unit_name = data['name']
+ suite_name = args.project_name
+
+ duration = data['duration']
+ return_code = data['returncode']
+ result = data['result']
+ log = data['stdout']
+
+ unit = {
+ 'suite': args.project_name,
+ 'name': unit_name,
+ 'duration': duration,
+ 'returncode': return_code,
+ 'result': result,
+ 'stdout': log,
+ }
+
+ units = suites.setdefault(suite_name, [])
+ units.append(unit)
+
+for name, units in suites.items():
+ print('Processing suite {} (units: {})'.format(name, len(units)))
+
+ def if_failed(unit):
+ if unit['result'] in ['ERROR', 'FAIL', 'UNEXPECTEDPASS', 'TIMEOUT']:
+ return True
+ return False
+
+ def if_succeded(unit):
+ if unit['result'] in ['OK', 'EXPECTEDFAIL', 'SKIP']:
+ return True
+ return False
+
+ successes = list(filter(if_succeded, units))
+ failures = list(filter(if_failed, units))
+ print(' - {}: {} pass, {} fail'.format(name, len(successes), len(failures)))
+
+ testsuite = ET.SubElement(testsuites, 'testsuite')
+ testsuite.set('name', '{}/{}'.format(args.project_name, name))
+ testsuite.set('tests', str(len(units)))
+ testsuite.set('errors', str(len(failures)))
+ testsuite.set('failures', str(len(failures)))
+
+ for unit in successes:
+ testcase = ET.SubElement(testsuite, 'testcase')
+ testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
+ testcase.set('name', unit['name'])
+ testcase.set('time', str(unit['duration']))
+
+ for unit in failures:
+ testcase = ET.SubElement(testsuite, 'testcase')
+ testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
+ testcase.set('name', unit['name'])
+ testcase.set('time', str(unit['duration']))
+
+ failure = ET.SubElement(testcase, 'failure')
+ failure.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
+ failure.set('name', unit['name'])
+ failure.set('type', 'error')
+ failure.text = unit['stdout']
+
+output = ET.tostring(testsuites, encoding='unicode')
+outfile.write(output)
diff --git a/.gitlab-ci/run-docker.sh b/.gitlab-ci/run-docker.sh
new file mode 100755
index 0000000..618ddd9
--- /dev/null
+++ b/.gitlab-ci/run-docker.sh
@@ -0,0 +1,135 @@
+#!/bin/bash
+
+read_arg() {
+ # $1 = arg name
+ # $2 = arg value
+ # $3 = arg parameter
+ local rematch='^[^=]*=(.*)$'
+ if [[ $2 =~ $rematch ]]; then
+ read "$1" <<< "${BASH_REMATCH[1]}"
+ else
+ read "$1" <<< "$3"
+ # There is no way to shift our callers args, so
+ # return 1 to indicate they should do it instead.
+ return 1
+ fi
+}
+
+set -e
+
+build=0
+run=0
+push=0
+list=0
+print_help=0
+no_login=0
+
+while (($# > 0)); do
+ case "${1%%=*}" in
+ build) build=1;;
+ run) run=1;;
+ push) push=1;;
+ list) list=1;;
+ help) print_help=1;;
+ --base|-b) read_arg base "$@" || shift;;
+ --base-version) read_arg base_version "$@" || shift;;
+ --no-login) no_login=1;;
+ *) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;;
+ esac
+ shift
+done
+
+if [ $print_help == 1 ]; then
+ echo "$0 - Build and run Docker images"
+ echo ""
+ echo "Usage: $0 <command> [options] [basename]"
+ echo ""
+ echo "Available commands"
+ echo ""
+ echo " build --base=<BASENAME> - Build Docker image <BASENAME>.Dockerfile"
+ echo " run --base=<BASENAME> - Run Docker image <BASENAME>"
+ echo " push --base=<BASENAME> - Push Docker image <BASENAME> to the registry"
+ echo " list - List available images"
+ echo " help - This help message"
+ echo ""
+ exit 0
+fi
+
+cd "$(dirname "$0")"
+
+if [ $list == 1 ]; then
+ echo "Available Docker images:"
+ for f in *.Dockerfile; do
+ filename=$( basename -- "$f" )
+ basename="${filename%.*}"
+
+ echo -e " \e[1;39m$basename\e[0m"
+ done
+ exit 0
+fi
+
+# All commands after this require --base to be set
+if [ -z $base ]; then
+ echo "Usage: $0 <command>"
+ exit 1
+fi
+
+if [ ! -f "$base.Dockerfile" ]; then
+ echo -e "\e[1;31mERROR\e[0m: Dockerfile for '$base' not found"
+ exit 1
+fi
+
+if [ -z $base_version ]; then
+ base_version="latest"
+else
+ base_version="v$base_version"
+fi
+
+if [ ! -x "$(command -v docker)" ] || [ docker --help |& grep -q podman ]; then
+ # Docker is actually implemented by podman, and its OCI output
+ # is incompatible with some of the dockerd instances on GitLab
+ # CI runners.
+ echo "Using: Podman"
+ format="--format docker"
+ CMD="podman"
+else
+ echo "Using: Docker"
+ format=""
+ CMD="sudo socker"
+fi
+
+REGISTRY="registry.gitlab.gnome.org"
+TAG="${REGISTRY}/gnome/atk/${base}:${base_version}"
+
+if [ $build == 1 ]; then
+ echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}"
+ ${CMD} build \
+ ${format} \
+ --build-arg HOST_USER_ID="$UID" \
+ --tag "${TAG}" \
+ --file "${base}.Dockerfile" .
+ exit $?
+fi
+
+if [ $push == 1 ]; then
+ echo -e "\e[1;32mPUSHING\e[0m: ${base} as ${TAG}"
+
+ if [ $no_login == 0 ]; then
+ ${CMD} login ${REGISTRY}
+ fi
+
+ ${CMD} push ${TAG}
+ exit $?
+fi
+
+if [ $run == 1 ]; then
+ echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
+ ${CMD} run \
+ --rm \
+ --volume "$(pwd)/..:/home/user/app" \
+ --workdir "/home/user/app" \
+ --tty \
+ --interactive "${TAG}" \
+ bash
+ exit $?
+fi
diff --git a/.gitlab-ci/run-tests-docker.sh b/.gitlab-ci/run-tests-docker.sh
new file mode 100755
index 0000000..b35dd6e
--- /dev/null
+++ b/.gitlab-ci/run-tests-docker.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set +x
+set +e
+
+srcdir=$( pwd )
+builddir=$1
+
+export PATH="${HOME}/.local/bin:${PATH}"
+
+meson test -C ${builddir} \
+ --print-errorlogs
+
+# Store the exit code for the CI run, but always
+# generate the reports
+exit_code=$?
+
+cd ${builddir}
+
+$srcdir/.gitlab-ci/meson-junit-report.py \
+ --project-name=atk \
+ --job-id="${CI_JOB_NAME}" \
+ --output=report.xml \
+ meson-logs/testlog.json
+
+exit $exit_code
diff --git a/.gitlab-ci/setup-build-docker.sh b/.gitlab-ci/setup-build-docker.sh
new file mode 100755
index 0000000..96fd6d2
--- /dev/null
+++ b/.gitlab-ci/setup-build-docker.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set +e
+set +x
+
+export PATH="${HOME}/.local/bin:${PATH}"
+
+meson ${EXTRA_MESON_FLAGS:-} _build .