Gitlab-CI: укажите, что задание C должно выполняться после задания B в случае сбоя задания A

#gitlab #gitlab-ci

#gitlab #gitlab-ci

Вопрос:

Представьте, что у вас есть следующий конвейер:

 Job A (deploy) -> Job B (test) -> Job C (remove test deployment)
  

Конвейер должен развернуть тестовый образ и протестировать его после успешного развертывания. После теста я хочу запустить скрипт очистки независимо от результатов теста, но только в том случае, если тестовый образ (задание A) был развернут.

Подводя итог: я хочу, чтобы Gitlab выполнял задание C только в том случае, если задание A выполнено успешно, но после задания B.

Вещи, которые не будут работать:

  • when: on-failure (Задание A или задание B может завершиться с ошибкой, но важно только задание A)
  • when: always (возможно, задание A завершилось с ошибкой, что приводит к сбою задания C)
  • when: on-success (требуется, чтобы все задания выполнялись успешно)

Я знаю, что в GitLab есть функция, называемая конвейерами DAG, которая позволяет вам указывать несколько зависимостей от других заданий с needs помощью ключевого слова, но, к сожалению when , ключевое слово всегда распространяется на все предыдущие задания. Итак, вы не можете сказать что-то вроде:

 when:
    on-success: job-a
    always: job-b
  

Я что-то пропустил или нет способа добиться такого поведения?

Комментарии:

1. Чтобы уточнить — вы хотите , чтобы задание B (задание тестирования) выполнялось, даже если задание A (развертывание) завершается с ошибкой?

2. Нет, его следует пропустить. Я хочу запустить задание C после завершения или сбоя задания B. Но задание A должно было быть выполнено.

Ответ №1:

Поле needs DAG можно использовать для условного выполнения очистки (задание C), если задание B завершается неудачно или успешно, но НЕ тогда, когда оно пропущено из-за сбоя задания A.

Создайте 2 задания очистки, которые соответствуют следующим логическим условиям:

  • (Job A succeeds and Job B succeeds) : Если все предыдущие задачи завершились успешно (задание A и задание B), мы можем запустить очистку с when: on_success помощью . Однако это не сработает, если задание A завершается успешно, а задание B завершается с ошибкой.
  • (Job A succeeds and Job B fails) : Чтобы обойти предыдущий сценарий с необработанной очисткой (задание C), мы используем тот факт, что если задание B завершается с ошибкой, это означает, что задание A выполнено успешно в конвейере. Создав повторяющуюся задачу очистки и указав needs тег для задания B и when: on_failure , задача очистки будет выполняться только в случае успешного выполнения задания A и сбоя задания B.

Повторяю: задание очистки будет выполняться, если (Job A succeeds and Job B succeeds) или (Job A succeeds and Job B fails) , что по логическому выражению эквивалентно (Job A succeeds) .

Очевидным предостережением здесь является то, что теперь в конвейере отображаются 2 задания очистки; однако они являются взаимоисключающими, и только одно может быть выполнено.

Вот пример конфигурации:

 stages:
  - deploy
  - test
  - cleanup

deploy_job:
  stage: deploy
  script:
    - echo Deployed
    - "true"
  when: always

test_job:
  stage: test
  script:
    - echo Executing tests
    - "true"
  when: on_success

# a YAML anchor reduces repetition
.cleanup_job: amp;cleanup_job
  stage: cleanup
  script:
    - echo Cleaned up deployment

cleanup_deployment_success:
  when: on_success
  <<: *cleanup_job

cleanup_deployment_failure:
  needs: ["test_job"]
  when: on_failure
  <<: *cleanup_job
  

При различных преднамеренных условиях сбоя создаются следующие состояния конвейера:

  • сбой конвейера: Задание A завершается успешно, а задание B завершается с ошибкой
  • сбой конвейера: Задание A завершается с ошибкой, и задание B пропускается
  • переданный конвейер: Задание A выполнено успешно, а задание B выполнено успешно

Логически это указывает на то, что независимо от того, выполнено задание B успешно или неудачно, задание C выполняется, если задание A выполнено успешно. Кроме того, состояние сбоя сохраняется во всем конвейере.

Комментарии:

1. Не приведет ли это к тому, что конвейер будет находиться в переданном состоянии, даже если тесты завершились неудачей? Я хочу, чтобы конвейер находился в состоянии сбоя, если одно задание завершается с ошибкой.

2. @Sebi2020 К сожалению, это так. Если задание завершается с ошибкой, но конвейер «проходит», вместо зеленой галочки «передано» используется восклицательный знак оранжевого цвета с надписью «передано». Я обновил свой ответ, чтобы продемонстрировать, как это выглядит. Триггеры when условий не очень сложны в GitLab CI. Я посмотрю еще раз и посмотрю, смогу ли я разрешить состояние сбоя конвейера, но у меня есть серьезные сомнения.

3. @Sebi2020 Я обновил свой ответ, чтобы использовать needs базы данных и тег. Дайте мне знать, удовлетворяет ли это вашим ограничениям / условиям.

4. @Sebi2020 К сожалению, система CI GitLab очень жесткая в своем подходе к конвейерам. Для этого указанного 3-этапного конвейера единственным предостережением здесь является дубликат пропущенного задания очистки, который отображается в конвейере. Если я найду другое решение, я обновлю свой ответ. Однако, прочитав документацию более часа, я не особенно уверен, что будет более чистое решение, пока GitLab не добавит более расширенное сопоставление для when тега. Чаще всего большинство моих конфигураций GitLab CI заканчиваются грязными решениями / взломами из-за их незаинтересованности в поддержке нетривиальных вариантов использования.

5. Отличные мысли, мой друг. В настоящее время пытаюсь использовать artifacts:when:always для сохранения кода выхода тестового скрипта и вывода его в файл build.env, чтобы я мог прочитать результат в следующем задании. Если это сработает, я тоже опубликую ответ здесь. Мне нравится GitLab, но, милорд, это неуместно.

Ответ №2:

Поле базы данных потребностей может использоваться для условного выполнения очистки (задания C ), если задание B завершается неудачно или успешно, но НЕ тогда, когда оно пропущено из A -за сбоя задания.

Это могло измениться с GitLab 13.11 (апрель 2021)

Необязательные задания DAG (‘needs:’) в конвейерах CI / CD

Ориентированный ациклический граф (DAG) в GitLab CI / CD позволяет использовать needs синтаксис для настройки запуска задания раньше его этапа (как только завершатся зависимые задания). > У нас также есть rules ключевые слова , only , или except , которые определяют, добавлено ли задание в конвейер вообще.

К сожалению, если вы объедините needs эти другие ключевые слова, возможно, что ваш конвейер может завершиться сбоем, когда зависимое задание не будет добавлено в конвейер.

В этом выпуске мы добавляем optional ключевое слово в needs синтаксис заданий DAG.

  • Если зависимое задание помечено как optional , но отсутствует в конвейере, needs задание игнорирует его.
  • Если задание находится optional и присутствует в конвейере, needs задание ожидает его завершения перед запуском.

Это значительно упрощает безопасное объединение rules , only , и except с ростом популярности DAG.

https://about.gitlab.com/images/13_11/optional.png -- Необязательные задания DAG ('needs:') в конвейерах CI/CD

Смотрите Документацию и проблему.

Ответ №3:

Я хотел бы добавить еще одну альтернативу. В настоящее время я ищу возможность реализовать именно этот вариант использования для e2e-тестов, и я, вероятно, предпочту отложить представление результатов тестирования с помощью артефактов. Настройка будет примерно такой:

 Job A (deploy) -> Job B (run test, collect results into artifact) -> Job C (undeploy) -> Job D (publish test results from artifact)
  

Задание B будет настроено так, чтобы всегда быть успешным, и сохранять свои результаты только как артефакт (например, JUnit xml). Затем задание D опубликует результаты, и конвейер завершится с ошибкой, если тесты не увенчались успехом. Это должно сохранить состояние сбоя конвейера, даже если задание C и задание D выполняются безоговорочно с использованием ранее упомянутого метода дублирования задания с несколькими when: условиями.