diff mbox series

[5/5] ci: add support for GitLab CI

Message ID 35b07e5378d960b93ae8990a3abb525e1762d97d.1698305961.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series ci: add GitLab CI definition | expand

Commit Message

Patrick Steinhardt Oct. 26, 2023, 8 a.m. UTC
We already support Azure Pipelines and GitHub Workflows in the Git
project, but until now we do not have support for GitLab CI. While it is
arguably not in the interest of the Git project to maintain a ton of
different CI platforms, GitLab has recently ramped up its efforts and
tries to contribute to the Git project more regularly.

Part of a problem we hit at GitLab rather frequently is that our own,
custom CI setup we have is so different to the setup that the Git
project has. More esoteric jobs like "linux-TEST-vars" that also sets a
couple of environment variables do not exist in GitLab's custom CI
setup, and maintaining them to keep up with what Git does feels like
wasted time. The result is that we regularly send patch series upstream
that would otherwise fail to compile or pass tests in GitHub Workflows.
We would thus like to integrate the GitLab CI configuration into the Git
project to help us ensure to send better patch series upstream and thus
reduce overhead for the maintainer.

The integration does not necessarily have to be a first-class citizen,
which would in practice only add to the fallout that pipeline failures
have for the maintainer. That being said, we are happy to maintain this
alternative CI setup for the Git project and will make test results
available as part of our own mirror of the Git project at [1].

This commit introduces the integration into our regular CI scripts so
that most of the setup continues to be shared across all of the CI
solutions.

[1]: https://gitlab.com/gitlab-org/git

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 .gitlab-ci.yml                    | 51 +++++++++++++++++++++++
 ci/install-docker-dependencies.sh |  9 +++-
 ci/lib.sh                         | 69 +++++++++++++++++++++++++++++++
 ci/print-test-failures.sh         |  6 +++
 4 files changed, 134 insertions(+), 1 deletion(-)
 create mode 100644 .gitlab-ci.yml

Comments

Oswald Buddenhagen Oct. 26, 2023, 9:07 a.m. UTC | #1
On Thu, Oct 26, 2023 at 10:00:20AM +0200, Patrick Steinhardt wrote:
>project has. More esoteric jobs like "linux-TEST-vars" that also sets a
								     ^ 
								     -s

>couple of environment variables do not exist in GitLab's custom CI
>setup, and maintaining them to keep up with what Git does feels like
>wasted time. The result is that we regularly send patch series upstream
>that would otherwise fail to compile or pass tests in GitHub Workflows.
       ^^^^^^^^^^^^^^^
       that inverts the meaning

>[...]
>project to help us ensure to send better patch series upstream and thus
			   ^^
			   "we"
>reduce overhead for the maintainer.

>--- a/ci/install-docker-dependencies.sh
>+++ b/ci/install-docker-dependencies.sh
>@@ -16,9 +19,13 @@ linux32)
> 	'
> 	;;
> linux-musl)
>-	apk add --update build-base curl-dev openssl-dev expat-dev gettext \
>+	apk add --update git shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
> 		pcre2-dev python3 musl-libintl perl-utils ncurses >/dev/null
> 	;;
>+linux-*)
>
you should probably choose a less generic name for the jobs, at least 
debian-*.

>diff --git a/ci/lib.sh b/ci/lib.sh
>index 33005854520..102e9d04a1f 100755
>--- a/ci/lib.sh
>+++ b/ci/lib.sh
>@@ -15,6 +15,42 @@ then
> 		echo '::endgroup::' >&2
> 	}
> 
>+	group () {
>[...]
>+	}
>
this counter-intutive patch structure reveals that the function is 
duplicated between github and gitlab. you may want to factor it out and 
alias it. or change the structure entirely (circling back to patch 1/5).

>+	CI_BRANCH="$CI_COMMIT_REF_NAME"
>+	CI_COMMIT="$CI_COMMIT_SHA"
>
assignments need no quoting to prevent word splitting.
repeats below.

>+	case "$CI_JOB_IMAGE" in
>
... as does the selector in case statements.

>--- a/ci/print-test-failures.sh
>+++ b/ci/print-test-failures.sh
>@@ -51,6 +51,12 @@ do
> 			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
> 			continue
> 			;;
>+		gitlab-ci)
>+			mkdir -p failed-test-artifacts
>+			cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
>+			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
>
you're just following the precedent, but imo it's more legible to quote 
the entire string, not just the variable expansion. the code doesn't 
even agree with itself, as the line directly above apparently agrees 
with me.

regards
Patrick Steinhardt Oct. 27, 2023, 8:17 a.m. UTC | #2
On Thu, Oct 26, 2023 at 11:07:08AM +0200, Oswald Buddenhagen wrote:
> On Thu, Oct 26, 2023 at 10:00:20AM +0200, Patrick Steinhardt wrote:
> > project has. More esoteric jobs like "linux-TEST-vars" that also sets a
> 								     ^ 								     -s
> 
> > couple of environment variables do not exist in GitLab's custom CI
> > setup, and maintaining them to keep up with what Git does feels like
> > wasted time. The result is that we regularly send patch series upstream
> > that would otherwise fail to compile or pass tests in GitHub Workflows.
>       ^^^^^^^^^^^^^^^
>       that inverts the meaning
> 
> > [...]
> > project to help us ensure to send better patch series upstream and thus
> 			   ^^
> 			   "we"
> > reduce overhead for the maintainer.
> 
> > --- a/ci/install-docker-dependencies.sh
> > +++ b/ci/install-docker-dependencies.sh
> > @@ -16,9 +19,13 @@ linux32)
> > 	'
> > 	;;
> > linux-musl)
> > -	apk add --update build-base curl-dev openssl-dev expat-dev gettext \
> > +	apk add --update git shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
> > 		pcre2-dev python3 musl-libintl perl-utils ncurses >/dev/null
> > 	;;
> > +linux-*)
> > 
> you should probably choose a less generic name for the jobs, at least
> debian-*.

The names are all preexisting, so I cannot change them. And the CI infra
does indeed rely on the exact names to choose what to do.

> > diff --git a/ci/lib.sh b/ci/lib.sh
> > index 33005854520..102e9d04a1f 100755
> > --- a/ci/lib.sh
> > +++ b/ci/lib.sh
> > @@ -15,6 +15,42 @@ then
> > 		echo '::endgroup::' >&2
> > 	}
> > 
> > +	group () {
> > [...]
> > +	}
> > 
> this counter-intutive patch structure reveals that the function is
> duplicated between github and gitlab. you may want to factor it out and
> alias it. or change the structure entirely (circling back to patch 1/5).

I don't quite know what you mean by counter-intuitive patch structure.
But regarding the duplication for the `group ()` function I agree, it's
a bit unfortunate. My first version did de-duplicate it indeed, but it
resulted in some weirdness in the stubbed case.

I'll revisit this.

> > +	CI_BRANCH="$CI_COMMIT_REF_NAME"
> > +	CI_COMMIT="$CI_COMMIT_SHA"
> > 
> assignments need no quoting to prevent word splitting.
> repeats below.
> 
> > +	case "$CI_JOB_IMAGE" in
> > 
> ... as does the selector in case statements.

True, but I'm simply matching the coding style in this script.

> > --- a/ci/print-test-failures.sh
> > +++ b/ci/print-test-failures.sh
> > @@ -51,6 +51,12 @@ do
> > 			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
> > 			continue
> > 			;;
> > +		gitlab-ci)
> > +			mkdir -p failed-test-artifacts
> > +			cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
> > +			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
> > 
> you're just following the precedent, but imo it's more legible to quote the
> entire string, not just the variable expansion. the code doesn't even agree
> with itself, as the line directly above apparently agrees with me.
> 
> regards

Yeah, as you say, this is another case where I follow precedent. I
honestly don't quite care which way we go in this case.

Patrick
Phillip Wood Oct. 27, 2023, 10:22 a.m. UTC | #3
On 27/10/2023 09:17, Patrick Steinhardt wrote:
>>> +	CI_BRANCH="$CI_COMMIT_REF_NAME"
>>> +	CI_COMMIT="$CI_COMMIT_SHA"
>>>
>> assignments need no quoting to prevent word splitting.
>> repeats below.
>>
>>> +	case "$CI_JOB_IMAGE" in
>>>
>> ... as does the selector in case statements.
> 
> True, but I'm simply matching the coding style in this script.

I think it is quite common for us to quote variables when it isn't 
strictly necessary as it makes it clear to anyone reading the script 
that there is no word splitting going on and ensures that we don't start 
splitting the variable if the contents changes in the future.

>>> --- a/ci/print-test-failures.sh
>>> +++ b/ci/print-test-failures.sh
>>> @@ -51,6 +51,12 @@ do
>>> 			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
>>> 			continue
>>> 			;;
>>> +		gitlab-ci)
>>> +			mkdir -p failed-test-artifacts
>>> +			cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
>>> +			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
>>>
>> you're just following the precedent, but imo it's more legible to quote the
>> entire string, not just the variable expansion. the code doesn't even agree
>> with itself, as the line directly above apparently agrees with me.
>>
>> regards
> 
> Yeah, as you say, this is another case where I follow precedent. I
> honestly don't quite care which way we go in this case.

Yes, if you're following existing practice I don't think this is worth 
worrying about.

Best Wishes

Phillip
Oswald Buddenhagen Oct. 27, 2023, 10:43 a.m. UTC | #4
On Fri, Oct 27, 2023 at 11:22:35AM +0100, Phillip Wood wrote:
>On 27/10/2023 09:17, Patrick Steinhardt wrote:
>>>> +	CI_BRANCH="$CI_COMMIT_REF_NAME"
>>>> +	CI_COMMIT="$CI_COMMIT_SHA"
>>>>
>>> assignments need no quoting to prevent word splitting.
>>> repeats below.
>>>
>>>> +	case "$CI_JOB_IMAGE" in
>>>>
>>> ... as does the selector in case statements.
>> 
>> True, but I'm simply matching the coding style in this script.
>
>I think it is quite common for us to quote variables when it isn't 
>strictly necessary as it makes it clear to anyone reading the script 
>that there is no word splitting going on

>and ensures that we don't start splitting the variable if the contents 
>changes in the future.
>
the point was that it *isn't* content-dependent; it's simply the shell 
rules. of course, many people (apparently you included) don't know these 
subtleties, so just quoting everything isn't the worst idea (though it 
would backfire with some *really* old buggy shells, but this doesn't 
need to concern us).

regards
Oswald Buddenhagen Oct. 27, 2023, 10:49 a.m. UTC | #5
On Fri, Oct 27, 2023 at 10:17:33AM +0200, Patrick Steinhardt wrote:
>On Thu, Oct 26, 2023 at 11:07:08AM +0200, Oswald Buddenhagen wrote:
>> you should probably choose a less generic name for the jobs, at least
>> debian-*.
>
>The names are all preexisting, so I cannot change them.
>
aren't they coming from the yml file? would adjusting them in the 
company setup be an unreasonable effort?

>I don't quite know what you mean by counter-intuitive patch structure.
>
it looked like you're adding the function to the github branch, not to 
the freshly added gitlab branch. of course that's just a diffing 
artifact.

regards
Patrick Steinhardt Oct. 27, 2023, 11:11 a.m. UTC | #6
On Fri, Oct 27, 2023 at 12:49:19PM +0200, Oswald Buddenhagen wrote:
> On Fri, Oct 27, 2023 at 10:17:33AM +0200, Patrick Steinhardt wrote:
> > On Thu, Oct 26, 2023 at 11:07:08AM +0200, Oswald Buddenhagen wrote:
> > > you should probably choose a less generic name for the jobs, at least
> > > debian-*.
> > 
> > The names are all preexisting, so I cannot change them.
> > 
> aren't they coming from the yml file? would adjusting them in the company
> setup be an unreasonable effort?

They come from the ".gitlab-ci.yml" file, but I have to reuse the exact
names that GitHub Actions already uses or otherwise we're not testing
for the same thing. The preexisting CI scripts for Git expect exactly
those names.

I do agree that they may benefit from a redesign so that they're more
explicit. But I don't think this patch series here is where we should do
that refactoring.

> > I don't quite know what you mean by counter-intuitive patch structure.
> > 
> it looked like you're adding the function to the github branch, not to the
> freshly added gitlab branch. of course that's just a diffing artifact.

Ah, thought you meant the larger "structure of how things were layed
out". Agreed and fixed in v2 of the patch series.

Patrick
Phillip Wood Oct. 27, 2023, 2:32 p.m. UTC | #7
On 27/10/2023 11:43, Oswald Buddenhagen wrote:
> On Fri, Oct 27, 2023 at 11:22:35AM +0100, Phillip Wood wrote:
>> On 27/10/2023 09:17, Patrick Steinhardt wrote:
>>>>> +    CI_BRANCH="$CI_COMMIT_REF_NAME"
>>>>> +    CI_COMMIT="$CI_COMMIT_SHA"
>>>>>
>>>> assignments need no quoting to prevent word splitting.
>>>> repeats below.
>>>>
>>>>> +    case "$CI_JOB_IMAGE" in
>>>>>
>>>> ... as does the selector in case statements.
>>>
>>> True, but I'm simply matching the coding style in this script.
>>
>> I think it is quite common for us to quote variables when it isn't 
>> strictly necessary as it makes it clear to anyone reading the script 
>> that there is no word splitting going on
> 
>> and ensures that we don't start splitting the variable if the contents 
>> changes in the future.
>>
> the point was that it *isn't* content-dependent; it's simply the shell 
> rules.

Oh, I'd misunderstood what you were saying which was that assignment and 
case statements are not subject to field splitting.

> of course, many people (apparently you included) don't know these 
> subtleties

I find this comment to be condescending, needlessly antagonistic and 
completely at odds with the norms of constructive discussion on this list.

Best Wishes

Phillip
Oswald Buddenhagen Oct. 27, 2023, 5:47 p.m. UTC | #8
On Fri, Oct 27, 2023 at 03:32:48PM +0100, Phillip Wood wrote:
>On 27/10/2023 11:43, Oswald Buddenhagen wrote:
>> On Fri, Oct 27, 2023 at 11:22:35AM +0100, Phillip Wood wrote:
>>>>>> +    CI_BRANCH="$CI_COMMIT_REF_NAME"
>>>>>> +    CI_COMMIT="$CI_COMMIT_SHA"
>>>>>>
>>>>> assignments need no quoting to prevent word splitting.
>>>>> repeats below.
>>>>>
>>> I think it is quite common for us to quote variables when it isn't 
>>> strictly necessary as it makes it clear to anyone reading the script 
>>> that there is no word splitting going on
>> 
>>> and ensures that we don't start splitting the variable if the contents 
>>> changes in the future.
>>>
>> the point was that it *isn't* content-dependent; it's simply the shell 
>> rules.
>
>Oh, I'd misunderstood what you were saying which was that assignment and 
>case statements are not subject to field splitting.
>
>> of course, many people (apparently you included) don't know these 
>> subtleties
>
>I find this comment to be condescending, needlessly antagonistic and 
>completely at odds with the norms of constructive discussion on this list.
>
the observation was necessary for the point i subsequently made (which 
was basically agreeing with the first part of your response).

i think it's a rather uncontroversial statement that many people don't 
know the ins and outs of the shell's word splitting rules. in fact, this 
is to be expected given how arbitrary the rules seem.

that you seem to be among these people was a reasonable inference from 
what you actually wrote. mentioning it was meant to provide a segue and 
add emphasis.

regards
Phillip Wood Oct. 30, 2023, 9:49 a.m. UTC | #9
On 27/10/2023 18:47, Oswald Buddenhagen wrote:
> On Fri, Oct 27, 2023 at 03:32:48PM +0100, Phillip Wood wrote:
>> On 27/10/2023 11:43, Oswald Buddenhagen wrote:
>>> On Fri, Oct 27, 2023 at 11:22:35AM +0100, Phillip Wood wrote:
>>>>>>> +    CI_BRANCH="$CI_COMMIT_REF_NAME"
>>>>>>> +    CI_COMMIT="$CI_COMMIT_SHA"
>>>>>>>
>>>>>> assignments need no quoting to prevent word splitting.
>>>>>> repeats below.
>>>>>>
>>>> I think it is quite common for us to quote variables when it isn't 
>>>> strictly necessary as it makes it clear to anyone reading the script 
>>>> that there is no word splitting going on
>>>
>>>> and ensures that we don't start splitting the variable if the 
>>>> contents changes in the future.
>>>>
>>> the point was that it *isn't* content-dependent; it's simply the 
>>> shell rules.
>>
>> Oh, I'd misunderstood what you were saying which was that assignment 
>> and case statements are not subject to field splitting.
>>
>>> of course, many people (apparently you included) don't know these 
>>> subtleties
>>
>> I find this comment to be condescending, needlessly antagonistic and 
>> completely at odds with the norms of constructive discussion on this 
>> list.
>>
> the observation was necessary for the point i subsequently made (which 
> was basically agreeing with the first part of your response).

It was not necessary to phrase it as you did though. Before replying on 
Friday I showed your comment to someone else and their reaction was 
"That's rude". You could have made your point by saying something like

     It is hard to remember all the shell's word splitting rules so
     quoting everywhere is not a bad idea.

This is not the first time I've found your comments unnecessarily 
adversarial and at odds with the norms of constructive discussion and 
respectful disagreement on this list. I don't think I'm the only one 
either - in [1] Junio points out an ad-hominem remark and in [2] Marc 
comments on the unreceptive tone of you review responses.

I would urge you to try and strike a more conciliatory tone in your 
messages - it is perfectly possible to correct or disagree with someone 
without alienating them in the process.

Best Wishes

Phillip

[1] https://lore.kernel.org/git/xmqqleeihok5.fsf@gitster.g/
[2] 
https://lore.kernel.org/git/e33f919d-1b6a-4944-ab5d-93ad0d323b68@xiplink.com/
Dragan Simic Oct. 30, 2023, 2:04 p.m. UTC | #10
On 2023-10-30 10:49, Phillip Wood wrote:
> On 27/10/2023 18:47, Oswald Buddenhagen wrote:
>> On Fri, Oct 27, 2023 at 03:32:48PM +0100, Phillip Wood wrote:
>>> On 27/10/2023 11:43, Oswald Buddenhagen wrote:
>>>> On Fri, Oct 27, 2023 at 11:22:35AM +0100, Phillip Wood wrote:
>>>>>>>> +    CI_BRANCH="$CI_COMMIT_REF_NAME"
>>>>>>>> +    CI_COMMIT="$CI_COMMIT_SHA"
>>>>>>>> 
>>>>>>> assignments need no quoting to prevent word splitting.
>>>>>>> repeats below.
>>>>>>> 
>>>>> I think it is quite common for us to quote variables when it isn't 
>>>>> strictly necessary as it makes it clear to anyone reading the 
>>>>> script that there is no word splitting going on
>>>> 
>>>>> and ensures that we don't start splitting the variable if the 
>>>>> contents changes in the future.
>>>>> 
>>>> the point was that it *isn't* content-dependent; it's simply the 
>>>> shell rules.
>>> 
>>> Oh, I'd misunderstood what you were saying which was that assignment 
>>> and case statements are not subject to field splitting.
>>> 
>>>> of course, many people (apparently you included) don't know these 
>>>> subtleties
>>> 
>>> I find this comment to be condescending, needlessly antagonistic and 
>>> completely at odds with the norms of constructive discussion on this 
>>> list.
>>> 
>> the observation was necessary for the point i subsequently made (which 
>> was basically agreeing with the first part of your response).
> 
> It was not necessary to phrase it as you did though. Before replying
> on Friday I showed your comment to someone else and their reaction was
> "That's rude". You could have made your point by saying something like
> 
>     It is hard to remember all the shell's word splitting rules so
>     quoting everywhere is not a bad idea.
> 
> This is not the first time I've found your comments unnecessarily
> adversarial and at odds with the norms of constructive discussion and
> respectful disagreement on this list. I don't think I'm the only one
> either - in [1] Junio points out an ad-hominem remark and in [2] Marc
> comments on the unreceptive tone of you review responses.
> 
> I would urge you to try and strike a more conciliatory tone in your
> messages - it is perfectly possible to correct or disagree with
> someone without alienating them in the process.

Yeah, I've also noticed a not so great tone is some of Oswald's 
messages.  It's perfectly fine to disagree on something, but it isn't 
that great to put the other party down while doing that, even to the 
point of insulting them.

We're all humans, and we should treat each other with respect.  
Furthermore, disagreeing in a friendly and polite way can many times 
lead to finding a better solution together.

> Best Wishes
> 
> Phillip
> 
> [1] https://lore.kernel.org/git/xmqqleeihok5.fsf@gitster.g/
> [2] 
> https://lore.kernel.org/git/e33f919d-1b6a-4944-ab5d-93ad0d323b68@xiplink.com/
diff mbox series

Patch

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 00000000000..43d3a961fa0
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,51 @@ 
+default:
+  timeout: 2h
+
+workflow:
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+    - if: $CI_COMMIT_TAG
+    - if: $CI_COMMIT_REF_PROTECTED == "true"
+
+test:
+  image: $image
+  before_script:
+    - ./ci/install-docker-dependencies.sh
+  script:
+    - useradd builder --home-dir "${CI_PROJECT_DIR}"
+    - chown -R builder "${CI_PROJECT_DIR}"
+    - sudo --preserve-env --set-home --user=builder ./ci/run-build-and-tests.sh
+  after_script:
+    - |
+      if test "$CI_JOB_STATUS" != 'success'
+      then
+        sudo --preserve-env --set-home --user=builder ./ci/print-test-failures.sh
+      fi
+  parallel:
+    matrix:
+      - jobname: linux-sha256
+        image: ubuntu:latest
+        CC: clang
+      - jobname: linux-gcc
+        image: ubuntu:20.04
+        CC: gcc
+        CC_PACKAGE: gcc-8
+      - jobname: linux-TEST-vars
+        image: ubuntu:20.04
+        CC: gcc
+        CC_PACKAGE: gcc-8
+      - jobname: linux-gcc-default
+        image: ubuntu:latest
+        CC: gcc
+      - jobname: linux-leaks
+        image: ubuntu:latest
+        CC: gcc
+      - jobname: linux-asan-ubsan
+        image: ubuntu:latest
+        CC: clang
+      - jobname: linux-musl
+        image: alpine:latest
+  artifacts:
+    paths:
+      - t/failed-test-artifacts
+    when: on_failure
diff --git a/ci/install-docker-dependencies.sh b/ci/install-docker-dependencies.sh
index d0bc19d3bb3..1cd92db1876 100755
--- a/ci/install-docker-dependencies.sh
+++ b/ci/install-docker-dependencies.sh
@@ -7,6 +7,9 @@ 
 
 begin_group "Install dependencies"
 
+# Required so that apt doesn't wait for user input on certain packages.
+export DEBIAN_FRONTEND=noninteractive
+
 case "$jobname" in
 linux32)
 	linux32 --32bit i386 sh -c '
@@ -16,9 +19,13 @@  linux32)
 	'
 	;;
 linux-musl)
-	apk add --update build-base curl-dev openssl-dev expat-dev gettext \
+	apk add --update git shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
 		pcre2-dev python3 musl-libintl perl-utils ncurses >/dev/null
 	;;
+linux-*)
+	apt update -q &&
+	apt install -q -y sudo git make language-pack-is libsvn-perl apache2 libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl libemail-valid-perl libio-socket-ssl-perl libnet-smtp-ssl-perl ${CC_PACKAGE:-${CC:-gcc}}
+	;;
 pedantic)
 	dnf -yq update >/dev/null &&
 	dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
diff --git a/ci/lib.sh b/ci/lib.sh
index 33005854520..102e9d04a1f 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -15,6 +15,42 @@  then
 		echo '::endgroup::' >&2
 	}
 
+	group () {
+		set +x
+
+		group="$1"
+		shift
+		begin_group "$group"
+
+		# work around `dash` not supporting `set -o pipefail`
+		(
+			"$@" 2>&1
+			echo $? >exit.status
+		) |
+		sed 's/^\(\([^ ]*\):\([0-9]*\):\([0-9]*:\) \)\(error\|warning\): /::\5 file=\2,line=\3::\1/'
+		res=$(cat exit.status)
+		rm exit.status
+
+		end_group "$group"
+		return $res
+	}
+elif test true = "$GITLAB_CI"
+then
+	begin_group () {
+		need_to_end_group=t
+		echo -e "\e[0Ksection_start:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K$1"
+		trap "end_group '$1'" EXIT
+		set -x
+	}
+
+	end_group () {
+		test -n "$need_to_end_group" || return 0
+		set +x
+		need_to_end_group=
+		echo -e "\e[0Ksection_end:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K"
+		trap - EXIT
+	}
+
 	group () {
 		set +x
 
@@ -209,6 +245,39 @@  then
 	MAKEFLAGS="$MAKEFLAGS --jobs=10"
 	test windows != "$CI_OS_NAME" ||
 	GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"
+elif test true = "$GITLAB_CI"
+then
+	CI_TYPE=gitlab-ci
+	CI_BRANCH="$CI_COMMIT_REF_NAME"
+	CI_COMMIT="$CI_COMMIT_SHA"
+	case "$CI_JOB_IMAGE" in
+	macos-*)
+		CI_OS_NAME=osx;;
+	alpine:*|ubuntu:*)
+		CI_OS_NAME=linux;;
+	*)
+		echo "Could not identify OS image" >&2
+		env >&2
+		exit 1
+		;;
+	esac
+	CI_REPO_SLUG="$CI_PROJECT_PATH"
+	CI_JOB_ID="$CI_JOB_ID"
+	CC="${CC_PACKAGE:-${CC:-gcc}}"
+	DONT_SKIP_TAGS=t
+	handle_failed_tests () {
+		create_failed_test_artifacts
+	}
+
+	cache_dir="$HOME/none"
+
+	runs_on_pool=$(echo "$CI_JOB_IMAGE" | tr : -)
+
+	export GIT_PROVE_OPTS="--timer --jobs $(nproc)"
+	export GIT_TEST_OPTS="--verbose-log -x"
+	MAKEFLAGS="$MAKEFLAGS --jobs=$(nproc)"
+	test windows != "$CI_OS_NAME" ||
+	GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"
 else
 	echo "Could not identify CI type" >&2
 	env >&2
diff --git a/ci/print-test-failures.sh b/ci/print-test-failures.sh
index 57277eefcd0..c33ad4e3a22 100755
--- a/ci/print-test-failures.sh
+++ b/ci/print-test-failures.sh
@@ -51,6 +51,12 @@  do
 			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
 			continue
 			;;
+		gitlab-ci)
+			mkdir -p failed-test-artifacts
+			cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
+			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
+			continue
+			;;
 		*)
 			echo "Unhandled CI type: $CI_TYPE" >&2
 			exit 1