CI: WIP: attempt to clean up the registry before leaving
[platform/upstream/libinput.git] / .gitlab-ci.yml
1 # vim: set expandtab shiftwidth=2 tabstop=8 textwidth=0:
2 #
3 # This is a bit complicated for two reasons:
4 # - we really want to run dnf/apt/... only once, updating on the test runner for
5 #   each job takes forever. So we create a docker image for each distribution
6 #   tested, then run the tests on this docker image.
7 #
8 #   Creating a docker image is time-consuming, so we only do so for pushes to
9 #   libinput directly (not merge requests) and if the current image is 'old'.
10 #
11 # - GitLab only allows one script: set per job but we have a bunch of commands
12 #   we need to re-run for each build (meson && ninja && etc). YAML cannot merge
13 #   arrays templates so we're screwed.
14 #
15 #   So instead we use a default_build template and override everything with
16 #   variables. The only two variables that matter:
17 #     MESON_PARAMS=-Denable-something=true
18 #     NINJA_ARGS=dist ... to run 'ninja -C builddir dist'
19 #   Note that you cannot use scripts: in any target if you expect default_build
20 #   to work.
21 #
22 #
23 # All jobs must follow the naming scheme of
24 # <distribution>:<version>@activity:
25 #  e.g. fedora:28@build-default
26
27 stages:
28   - docker_check  # check if the current docker images are up to date
29   - docker_prep   # rebuild the docker images if previous step failed
30   - build         # for actually building things
31
32 variables:
33   ###############################################################################
34   # This is the list of packages required to build libinput with the default    #
35   # configuration.                                                              #
36   #                                                                             #
37   # Run dnf install/apt-get install/.. with the list of packages for your       #
38   # distribution                                                                #
39   #                                                                             #
40   # See the documentation here:                                                 #
41   # https://wayland.freedesktop.org/libinput/doc/latest/building_libinput.html  #
42   ###############################################################################
43   FEDORA_RPMS: 'git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel doxygen graphviz valgrind binutils libwacom-devel cairo-devel   gtk3-devel   glib2-devel    mtdev-devel'
44   UBUNTU_DEBS: 'git gcc g++     meson check       libudev-dev   libevdev-dev   doxygen graphviz valgrind binutils libwacom-dev   libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev'
45   ############################ end of package lists #############################
46   MESON_BUILDDIR: builddir
47   NINJA_ARGS: ''
48   MESON_PARAMS: ''
49   FEDORA_DOCKER_IMAGE: $CI_REGISTRY/libinput/$CI_PROJECT_NAME/fedora/$FEDORA_VERSION
50   UBUNTU_DOCKER_IMAGE: $CI_REGISTRY/libinput/$CI_PROJECT_NAME/ubuntu/$UBUNTU_VERSION
51   # When using docker-in-docker (dind), it's wise to use the overlayfs driver
52   # for improved performance.
53   DOCKER_DRIVER: overlay2
54   GIT_DEPTH: 1
55
56 .default_artifacts: &default_artifacts
57   artifacts:
58     name: "meson-logs-$CI_JOB_NAME"
59     when: always
60     expire_in: 1 week
61     paths:
62       - $MESON_BUILDDIR/meson-logs
63
64 # The default build instructions
65 .default_build: &default_build
66   script:
67    - rm -rf $MESON_BUILDDIR
68    - meson $MESON_BUILDDIR $MESON_PARAMS
69    - meson configure $MESON_BUILDDIR
70    - ninja -C $MESON_BUILDDIR $NINJA_ARGS
71
72 # special rule to not expose the docker creation runners to other users
73 # than those who have set up the CI to push on the registry.
74 # Users who have write access to libinput/libinput will have write
75 # access to the registry, so the libinput/libinput is a catch-all for
76 # our core developers.
77 #
78 # we can add as many users as we want by adding a new line like:
79 #   - $GITLAB_USER_LOGIN == "someone"
80 .restrict_docker_creation: &restrict_docker_creation
81   only:
82     variables:
83       # Note: this is a set of logical OR, not AND
84       - $CI_PROJECT_PATH == "libinput/libinput"
85
86 #################################################################
87 #                                                               #
88 #                     docker check stage                        #
89 #                                                               #
90 #################################################################
91
92 # we need a minimalist image capable of curl, jq, date and test.
93 # instead of using a full fedora and install the dependencies, we
94 # can reuse the one from https://github.com/endeveit/docker-jq with
95 # the following Dockerfile:
96 #   FROM alpine
97 #   MAINTAINER Nikita Vershinin <endeveit@gmail.com>
98 #
99 #   RUN apk add --update --no-cache curl jq
100 #
101 #   CMD ["sh"]
102
103 .docker-check: &docker_check
104   stage: docker_check
105   image: registry.freedesktop.org/libinput/libinput/jq:latest
106   script:
107     # get the full docker image name (CURRENT_DOCKER_IMAGE still has indirections)
108     - DOCKER_IMAGE=$(eval echo "$CURRENT_DOCKER_IMAGE")
109     - REPOSITORY=$(echo $DOCKER_IMAGE | cut -f2- -d/ | cut -f1 -d:)
110     - TAG=$(echo $DOCKER_IMAGE | cut -f2 -d:)
111
112     # request a token for the registry API
113     - REGISTRY_TOKEN=$(curl https://gitlab.freedesktop.org/jwt/auth --get
114                              --silent --show-error
115                              -d client_id=docker
116                              -d offline_token=true
117                              -d service=container_registry
118                              -d "scope=repository:$REPOSITORY:pull,*"
119                              --fail
120                              --user $CI_REGISTRY_USER:$CI_JOB_TOKEN
121                              | sed -r 's/(\{"token":"|"\})//g')
122
123     # get the date of the current image
124     - IMG_DATE=$(curl https://$CI_REGISTRY/v2/$REPOSITORY/manifests/$TAG --silent
125                       -H "accept:application/vnd.docker.distribution.manifest.v1+json"
126                       -H "authorization:Bearer $REGISTRY_TOKEN"
127                       | jq -r '[.history[]]|map(.v1Compatibility|fromjson|.created)|sort|reverse|.[0]'
128                       | cut -dT -f1)
129
130     - TODAY_SECS=$(date -u +%s)
131     - IMG_SECS=$(date -u --date="$IMG_DATE" +%s)
132     - echo "today $TODAY_SECS, image $IMG_SECS"
133
134     # check if image is less than a week old
135     - test $(($IMG_SECS + 604800)) -gt $TODAY_SECS
136
137     # export an artefact telling the next stage that the image is valid
138     - touch .img_ready
139   artifacts:
140     name: image $CURRENT_DOCKER_IMAGE check
141     expire_in: 20 min
142     paths:
143       - .img_ready
144   allow_failure: true
145   <<: *restrict_docker_creation
146
147
148 # TODO: check that the RPMS/DEBS are all in the current images
149
150 fedora:28@docker-check:
151   variables:
152     GIT_STRATEGY: none
153     FEDORA_VERSION: 28
154     CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE:latest
155   <<: *docker_check
156
157 fedora:27@docker-check:
158   variables:
159     GIT_STRATEGY: none
160     FEDORA_VERSION: 27
161     CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE:latest
162   <<: *docker_check
163
164 ubuntu:17.10@docker-check:
165   variables:
166     GIT_STRATEGY: none
167     UBUNTU_VERSION: "17.10"
168     CURRENT_DOCKER_IMAGE: $UBUNTU_DOCKER_IMAGE:latest
169   <<: *docker_check
170
171 ubuntu:18.04@docker-check:
172   variables:
173     GIT_STRATEGY: none
174     UBUNTU_VERSION: "18.04"
175     CURRENT_DOCKER_IMAGE: $UBUNTU_DOCKER_IMAGE:latest
176   <<: *docker_check
177
178
179 #################################################################
180 #                                                               #
181 #                     docker prep stage                         #
182 #                                                               #
183 #################################################################
184
185 #
186 # This stage will recreate the docker images only if the previous
187 # stage had a build failure, i.e. the image is too old or if it is
188 # missing some dependencies.
189 #
190 .fedora@docker-prep: &fedora_docker_prep
191   stage: docker_prep
192   services:
193     - docker:dind
194   script:
195     # if the check was successful, we just skip recreating the docker image
196     - test -e .img_ready && exit 0
197
198     - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
199
200     # create a Dockerfile with our dependencies
201     - echo "FROM fedora:$FEDORA_VERSION" > Dockerfile
202     - echo "WORKDIR /app" >> Dockerfile
203     - echo "RUN dnf upgrade -y ; dnf clean all" >> Dockerfile
204     - echo "RUN dnf install -y $FEDORA_RPMS ; dnf clean all" >> Dockerfile
205
206     # create the docker image
207     - docker build --tag $FEDORA_DOCKER_IMAGE:latest --tag $FEDORA_DOCKER_IMAGE:$CI_JOB_ID .
208
209     # push the docker image to the libinput registry
210     - docker push $FEDORA_DOCKER_IMAGE:latest
211     - docker push $FEDORA_DOCKER_IMAGE:$CI_JOB_ID
212   <<: *restrict_docker_creation
213
214 fedora:28@docker-prep:
215   variables:
216     GIT_STRATEGY: none
217     FEDORA_VERSION: 28
218   <<: *fedora_docker_prep
219   dependencies:
220     # Note: we can not use $FEDORA_VERSION here
221     - fedora:28@docker-check
222
223 fedora:27@docker-prep:
224   variables:
225     GIT_STRATEGY: none
226     FEDORA_VERSION: 27
227   <<: *fedora_docker_prep
228   dependencies:
229     # Note: we can not use $FEDORA_VERSION here
230     - fedora:27@docker-check
231
232 # FIXME: we should clean up the apt cache between each run
233 .ubuntu@docker-prep: &ubuntu_docker_prep
234   stage: docker_prep
235   services:
236     - docker:dind
237   script:
238     # if the check was successful, we just skip recreating the docker image
239     - test -e .img_ready && exit 0
240
241     - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
242
243     # create a Dockerfile with our dependencies
244     - echo "FROM ubuntu:$UBUNTU_VERSION" > Dockerfile
245     - echo "WORKDIR /app" >> Dockerfile
246     - echo "RUN apt-get update" >> Dockerfile
247     - echo "RUN apt-get install -y software-properties-common" >> Dockerfile
248     - echo "RUN add-apt-repository universe" >> Dockerfile
249     - echo "RUN apt-get update" >> Dockerfile
250     - echo "RUN apt-get install -y $UBUNTU_DEBS" >> Dockerfile
251
252     # create the docker image
253     - docker build --tag $UBUNTU_DOCKER_IMAGE:latest --tag $UBUNTU_DOCKER_IMAGE:$CI_JOB_ID .
254
255     # push the docker image to the libinput registry
256     - docker push $UBUNTU_DOCKER_IMAGE:latest
257     - docker push $UBUNTU_DOCKER_IMAGE:$CI_JOB_ID
258   <<: *restrict_docker_creation
259
260 ubuntu:17.10@docker-prep:
261   variables:
262     GIT_STRATEGY: none
263     UBUNTU_VERSION: "17.10"
264   <<: *ubuntu_docker_prep
265   dependencies:
266     # Note: we can not use $UBUNTU_VERSION here
267     - ubuntu:17.10@docker-check
268
269 ubuntu:18.04@docker-prep:
270   variables:
271     GIT_STRATEGY: none
272     UBUNTU_VERSION: "18.04"
273   <<: *ubuntu_docker_prep
274   dependencies:
275     # Note: we can not use $UBUNTU_VERSION here
276     - ubuntu:18.04@docker-check
277
278 # Add some manual runners to be able to recreate the cache on a day
279 # the list of the rpms changed
280
281 fedora:28@force-docker-prep:
282   variables:
283     GIT_STRATEGY: none
284     FEDORA_VERSION: 28
285   <<: *fedora_docker_prep
286   when: manual
287   dependencies: []
288
289 fedora:27@force-docker-prep:
290   variables:
291     GIT_STRATEGY: none
292     FEDORA_VERSION: 27
293   <<: *fedora_docker_prep
294   when: manual
295   dependencies: []
296
297 ubuntu:17.10@force-docker-prep:
298   variables:
299     GIT_STRATEGY: none
300     UBUNTU_VERSION: "17.10"
301   <<: *ubuntu_docker_prep
302   when: manual
303   dependencies: []
304
305 ubuntu:18.04@force-docker-prep:
306   variables:
307     GIT_STRATEGY: none
308     UBUNTU_VERSION: "18.04"
309   <<: *ubuntu_docker_prep
310   when: manual
311   dependencies: []
312
313 #################################################################
314 #                                                               #
315 #                     docker clean stage                        #
316 #                 run during the check stage                    #
317 #                                                               #
318 #################################################################
319
320 #
321 # This stage will look for the docker images we currently have in
322 # the registry and will remove any that are not tagged as 'latest'
323 #
324 .docker-clean: &docker_clean
325   stage: docker_check
326   image: registry.freedesktop.org/libinput/libinput/jq:latest
327   script:
328     # get the full docker image name (CURRENT_DOCKER_IMAGE still has indirections)
329     - DOCKER_IMAGE=$(eval echo "$CURRENT_DOCKER_IMAGE")
330     - REPOSITORY=$(echo $DOCKER_IMAGE | cut -f2- -d/)
331
332     # get the r/w token from the settings to access the registry
333     #
334     # each developer needs to register a secret variable that contains
335     # a personal token with api access in the form of:
336     # PERSONAL_TOKEN_$USER (for example PERSONAL_TOKEN_bentiss)
337     - tokenname="PERSONAL_TOKEN_$GITLAB_USER_LOGIN"
338     - token=$(eval echo "\$$tokenname")
339
340     # request a token for the registry API
341     - REGISTRY_TOKEN=$(curl https://gitlab.freedesktop.org/jwt/auth --get
342                              --silent --show-error
343                              -d client_id=docker
344                              -d offline_token=true
345                              -d service=container_registry
346                              -d "scope=repository:$REPOSITORY:pull,*"
347                              --fail
348                              --user $GITLAB_USER_LOGIN:$token
349                              | sed -r 's/(\{"token":"|"\})//g')
350
351     # get the digest of the latest image
352     - LATEST_MANIFEST=$(curl https://$CI_REGISTRY/v2/$REPOSITORY/manifests/latest --silent
353                              -H "accept:application/vnd.docker.distribution.manifest.v2+json"
354                              -H "authorization:Bearer $REGISTRY_TOKEN"
355                              --head
356                              | grep -i "Docker-Content-Digest"
357                              | grep -oi "sha256:\w\+")
358
359     # get the list of tags
360     - TAGS=$(curl https://$CI_REGISTRY/v2/$REPOSITORY/tags/list --silent
361                   -H "accept:application/vnd.docker.distribution.manifest.v2+json"
362                   -H "authorization:Bearer $REGISTRY_TOKEN"
363                   | jq -r '.tags[]')
364
365     # iterate over the tags
366     - for tag in $TAGS;
367       do
368         MANIFEST=$(curl https://$CI_REGISTRY/v2/$REPOSITORY/manifests/$tag --silent
369                              -H "accept:application/vnd.docker.distribution.manifest.v2+json"
370                              -H "authorization:Bearer $REGISTRY_TOKEN"
371                              --head
372                              | grep -i "Docker-Content-Digest"
373                              | grep -oi "sha256:\w\+");
374         if test x"$MANIFEST" != x"$LATEST_MANIFEST";
375           then
376             echo removing $tag as $MANIFEST;
377             curl https://$CI_REGISTRY/v2/$REPOSITORY/manifests/$MANIFEST --silent
378                  -H "accept:application/vnd.docker.distribution.manifest.v2+json"
379                  -H "authorization:Bearer $REGISTRY_TOKEN"
380                  --fail --show-error -X DELETE
381           ;fi
382       ;done
383   dependencies: []
384   allow_failure: true
385   <<: *restrict_docker_creation
386
387 fedora:28@docker-clean:
388   variables:
389     GIT_STRATEGY: none
390     FEDORA_VERSION: 28
391     CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE
392   <<: *docker_clean
393
394 fedora:27@docker-clean:
395   variables:
396     GIT_STRATEGY: none
397     FEDORA_VERSION: 27
398     CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE
399   <<: *docker_clean
400
401 ubuntu:17.10@docker-clean:
402   variables:
403     GIT_STRATEGY: none
404     UBUNTU_VERSION: "17.10"
405     CURRENT_DOCKER_IMAGE: $UBUNTU_DOCKER_IMAGE
406   <<: *docker_clean
407
408 ubuntu:18.04@docker-clean:
409   variables:
410     GIT_STRATEGY: none
411     UBUNTU_VERSION: "18.04"
412     CURRENT_DOCKER_IMAGE: $UBUNTU_DOCKER_IMAGE
413   <<: *docker_clean
414
415 #################################################################
416 #                                                               #
417 #                       build stage                             #
418 #                                                               #
419 #################################################################
420
421 #
422 # Fedora
423 #
424
425 .fedora@template: &fedora_template
426   stage: build
427   image: $FEDORA_DOCKER_IMAGE:latest
428   <<: *default_artifacts
429   dependencies: []
430
431 fedora:27@default-build:
432   variables:
433     FEDORA_VERSION: 27
434   <<: *fedora_template
435   <<: *default_build
436
437 .fedora:28@template: &fedora_28_template
438   variables:
439     FEDORA_VERSION: 28
440   <<: *fedora_template
441
442 fedora:28@default-build:
443   <<: *fedora_28_template
444   <<: *default_build
445
446 # Below jobs are build option combinations. We only
447 # run them on one image, they shouldn't fail on one distro
448 # when they succeed on another.
449
450 fedora:28@build-no-libwacom:
451   <<: *fedora_28_template
452   <<: *default_build
453   variables:
454     FEDORA_VERSION: 28
455     MESON_PARAMS: "-Dlibwacom=false"
456
457 fedora:28@build-no-libwacom-nodeps:
458   <<: *fedora_28_template
459   <<: *default_build
460   variables:
461     FEDORA_VERSION: 28
462     MESON_PARAMS: "-Dlibwacom=false"
463   before_script:
464     - dnf remove -y libwacom libwacom-devel
465
466 fedora:28@build-no-docs:
467   <<: *fedora_28_template
468   <<: *default_build
469   variables:
470     FEDORA_VERSION: 28
471     MESON_PARAMS: "-Ddocumentation=false"
472
473 fedora:28@build-no-docs-nodeps:
474   <<: *fedora_28_template
475   <<: *default_build
476   variables:
477     FEDORA_VERSION: 28
478     MESON_PARAMS: "-Ddocumentation=false"
479   before_script:
480     - dnf remove -y doxygen graphviz
481
482 fedora:28@build-no-debuggui:
483   <<: *fedora_28_template
484   <<: *default_build
485   variables:
486     FEDORA_VERSION: 28
487     MESON_PARAMS: "-Ddebug-gui=false"
488
489 fedora:28@build-no-debuggui-nodeps:
490   <<: *fedora_28_template
491   <<: *default_build
492   variables:
493     FEDORA_VERSION: 28
494     MESON_PARAMS: "-Ddebug-gui=false"
495   before_script:
496     - dnf remove -y gtk3-devel
497
498 fedora:28@build-no-tests:
499   <<: *fedora_28_template
500   <<: *default_build
501   variables:
502     FEDORA_VERSION: 28
503     MESON_PARAMS: "-Dtests=false"
504
505 fedora:28@build-no-tests-nodeps:
506   <<: *fedora_28_template
507   <<: *default_build
508   variables:
509     FEDORA_VERSION: 28
510     MESON_PARAMS: "-Dtests=false"
511   before_script:
512     - dnf remove -y check-devel
513
514 fedora:28@scan-build:
515   <<: *fedora_28_template
516   <<: *default_build
517   variables:
518     FEDORA_VERSION: 28
519     NINJA_ARGS: scan-build
520   before_script:
521     - dnf install -y clang-analyzer findutils
522   after_script:
523     - test ! -d $MESON_BUILDDIR/meson-logs/scanbuild && exit 0
524     - test $(find $MESON_BUILDDIR/meson-logs/scanbuild -maxdepth 0 ! -empty -exec echo "not empty" \; | wc -l) -eq 0 && exit 0
525     - echo "Check scan-build results"
526     - /bin/false
527
528 #
529 # Ubuntu
530 #
531
532 .ubuntu@template: &ubuntu_template
533   stage: build
534   image: $UBUNTU_DOCKER_IMAGE:latest
535   <<: *default_artifacts
536   dependencies: []
537
538 ubuntu:17.10@default-build:
539   variables:
540     UBUNTU_VERSION: "17.10"
541   <<: *ubuntu_template
542   <<: *default_build
543
544 ubuntu:18.04@default-build:
545   variables:
546     UBUNTU_VERSION: "17.10"
547   <<: *ubuntu_template
548   <<: *default_build