За более 3х летний срок существования продукта у нас собралось  более чем 20 репозиториев со spark проектами. Процесс CICD был  реализован на Jenkins. С определенного момента у GitLab CI появилась  возможность создавать собственные CICD. Но долгое время я совершенно не  воспринимал всерьез этот инструмент. Так как мне нравилось, что в  Jenkins можно взять и дописать то чего тебе не хватает на Groovy.  Настройка WebUI предоставляет широкие возможности для организации  параметризованных сборок. Поначалу функционал GitlabCI я воспринимал это  как жалкое подобие Jenkins: чтобы реализовать ну что-то очень очевидное  и простое, я уже молчу про параметризованную сборку. Но прошло время и мне показали как возможно шарить между проектами  джобы, чтобы реализация под конкретный проект выглядела с наименьшим  количеством кода.  Для примера у вас где-то в отдельном репозитории лежат yml,  которые выполняют что-то вполне определенное, которое у вас может  повторяться не только в одном проекте. Выполнять include какого-то джоба у себя в конвейере и прям стало  одной из киллер фич. И в какой-то момент перевод пайплайн на GitLabCI  уже не выглядело как необходимость, а собственным желанием реализовать  интересную задачу. более 20 репозиториев в gitlab spark проектов; часть из них работают со spark часть из них spark + kafka; CICD реализован на Jenkins Выполнить трансформацию CICD с Jenkins на Gitlab CI c наименьшим  количеством шагов: чтобы команда разработки, если хотела бы вникнуть то  могла это сделать, а если нет то было бы что-нибудь типа создать  такой-то файл и скопировать туда такой-то yaml код и чтобы  гарантированно заработало причем без активной помощи со стороны devops  разработчика. В каждом из Spark проектов реализовано было тестирование по одному  из 2-х сценариев: с кафка или без. Описать сценарий в одном job было не  возможно и поэтому были созданы 2 yaml, которые подключались следующим  образом Для того, чтобы .gitlab-ci.yml выглядел  для каждого проекта одинаковым необходимо было придумать логику таким  образом, чтобы пайплайн на основании семантического анализа кода в test/fixtures.py мог  определить какой сценарий необходим. Решить эту задачу оказалось  достаточно тривиальной задачей, первая проблема была дальше.  Предполагалось создать job, который в процессе анализа определял  переменную CICD_KAFKA_HOST либо в true либо в false и в последующих job нужно запускать тесты либо c кафка либо без.  Но по ходу реализации выяснилось, что использовать rules нельзя, потому  variables для rules определяются при старте пайплайна и не могут быть  переопределены/изменены в процессе работы конвейера и расширения extends  должны быть определены в пайплайне однозначным образом. Реализация идеи "smart" пайплайна первый раз подверглась сомнению. НО по на помощь должны были прийти триггеры. Триггер  предоставляет возможность запустить в текущем пайплайне другой  пайплайн. Текущий пайплайн становится родительским, а запускаемый другой  пайплан ребенком. Реализация получилась такой В такой реализации обычный пайплайн трансформировался в  мультипайплайн: родительский пайплайн инициировал запуск  пайплайна-ребенка Такие  образом появилось smart начало: он умеет определять какой сценарий  выбрать и в job с интеграционным тестированием переиспользует именно тот  сценарий который необходим: либо с кафка либо без. Начало положено, НО  возникла проблема №2: результатом выполнения pipeline ребенка -  формирование coverage отчета, который не мультипайплайнах мы далее  передаем в job c SonarQube. Решить  задачу по передаче между job artifact в виде файлов как раньше было  нельзя, вернуть artifact из child в parent оказалось невозможно. Очевидное  решение - добавить upload artifact в наш aftifactory и в job c  SonarQube просто его скачать. Но хотелось найти более изящный способ,  чтобы исключить дополнительные обращения к Artifactory. И способ был  найден: Gitlab CI API Чтобы иметь возможность подключаться к Gitlab CI API необходимо  для пользователя, который имеет права на репозиторий сгенерировать  token. Для того чтобы воспользоваться API скачать artifact из pipeline  ребенка необходимо выяснить его CI_JOB_ID. GET /projects/:id/jobs/:job_id/artifacts  Как это сделать из pipeline родителя? - определяем ID pipeline ребенка GET /projects/:id/pipelines/:pipeline_id/bridges - по id pipeline ребенка определяем id job GET /projects/:id/pipelines/:pipeline_id/jobs - после этого уже выполняем скачивание методом /projects/:id/jobs/:job_id/artifacts  Итоговая реализация job по скачиванию artifacts будет выглядеть  так: в список переменных группы проектов куда входит и наш репозиторий  положили значение token - GITLAB_USER_TOKEN и для разбора json ответа от  Gitlab API использовали jq Таким образом удалось реализовать Multi-project пайплайн имхо со "smart" фичой Сбор, хранение и аналитика