Согласно документации, с операцией OR
сочетаются несколько правил, и она действительно ведет себя именно так. Но у меня конкретная ситуация.
Итак, у меня есть набор заданий, которые используются для PCF
платформы, и еще один набор для Kubernetes
платформы. Они управляются просто путем установки переменных. И возможно, что нам может понадобиться, чтобы оба были активны:
.pcf-platform:
rules:
- if: $PLATFORM_PCF == "true"
.k8s-platform:
rules:
- if: $PLATFORM_K8S == "true"
.manual-feature-branch-optional:
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule" && $CI_PIPELINE_SOURCE != "merge_request_event"
when: manual
allow_failure: true
.manual-default-branch-optional:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule"
when: manual
allow_failure: true
Теперь представьте, что у нас есть эти рабочие места:
deploy-dev-pcf:
extends:
- .manual-feature-branch-optional
- .pcf-platform
script:
- do deploy
deploy-dev-k8s:
extends:
- .manual-feature-branch-optional
- .k8s-platform
script:
- do deploy
deploy-prod-pcf:
extends:
- .manual-default-branch-optional
- .pcf-platform
script:
- do deploy
Теперь представьте, что и PLATFORM_K8S
, и PLATFORM_PCF
установлены на true
, а текущая ветвь является функциональной ветвью (не по умолчанию); как и ожидалось, оба deploy-dev-pcf
и deploy-dev-k8s
добавляются в конвейер, но так, как deploy-prod-pcf
.
Кажется, что первое правило, которое проверяет if the current branch is default branch
, разрешается в false
, но затем оно оценивает следующее правило, которое проверяет PLATFORM_PCF equals to true
, и, поскольку оно верно, оно добавляет задание, пока мы все еще находимся в функциональной ветке.
Мне нужно каким-то образом сделать эти два отдельных правила And
-ed, чтобы я мог включать/выключать задания в зависимости от желаемой платформы, а также типа ветки.
Я мог бы создать один набор правил для Kubernetes
и один набор для PCF
, но это необоснованно увеличивает количество правил, и я против такого подхода.
В документации говорится, что предложения only
оцениваются с помощью And
, но, похоже, only
устаревает в пользу rules
.
Как я могу этого добиться?
Чтобы понять это правильно, вам нужно понять:
Или вы можете просто перейти к последнему заголовку вашего ответа :-)
Часть вашей проблемы здесь, похоже, заключается в ваших ожиданиях того, что extends:
делает в этом случае. Когда значения массива встречаются через extends:
, они перекрывают друг друга и не объединяются. См. сведения о слиянии для дополнительного контекста.
Например, при такой конфигурации:
.foo:
rules:
- if: $FOO == "foo"
.bar:
rules:
- if: $BAR == "bar"
job:
extends:
- foo
- bar # array of rules here will override the previous declarations
Другими словами, в результирующей конфигурации в этом случае будет действовать только один набор этих правил, как если бы они были написаны так:
job:
rules:
- if: $BAR == "bar"
Итак, в вашем примере применяется только правило платформы, что приводит к поведению, которое вы наблюдаете.
Один из способов обойти это — использовать !reference
вместо создания массива правил:
rules:
- !reference [.foo, rules]
- !reference [.bar, rules]
Еще один аспект, требующий понимания, — это то, как оцениваются правила. GitLab будет оценивать каждое правило по порядку и остановится на первом правиле, которое оценивается как истинное. Может быть максимум одно правило, которое вступит в силу! Если никакие правила не совпадают, задание исключается из конвейера.
Итак, есть несколько способов получить эффект оценки AND
.
Вы можете объединить его в одно правило и комбинировать с операторами &&
:
rules:
- if: $FOO == "foo" && $BAR == "bar"
Вы также можете получить желаемый эффект, расположив различные правила в определенном порядке и используя обратную логику в сочетании с when: never
. Например, эти правила имеют тот же эффект, что и выше:
rules:
- if: $FOO != "foo"
when: never
- if: $BAR != "bar"
when: never
- when: on_success # base case is important!
Инвертируя логику здесь (проверяя !=
вместо ==
), мы позволяем оценке продолжаться по последующим правилам. Это важно, если вы хотите определить и повторно использовать правила по отдельности.
Применяя понимание, объясненное выше, используя ваш пример, вы можете сделать что-то вроде этого, что позволит вам определить каждое правило только один раз:
# define different sets of rules
.rules:
pcf-only:
- if: $PCF_PLATFORM != "true"
when: never
k8s-only:
- if: $K8S_PLATFORM != "true"
when: never
manual-feature-branch-optional:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule" && $CI_PIPELINE_SOURCE != "merge_request_event"
when: manual
allow_failure: true
# Combine these rules in different ways that can be reused
.k8s-deploy:
rules: # Order matters!
- !reference [.rules, k8s-only]
- !reference [.rules, manual-feature-branch-optional]
.pcf-deploy:
rules:
- !reference [.rules, pcf-only]
- !reference [.rules, manual-feature-branch-optional]
# Use `extends:` for each combination of rules as-needed
deploy-dev-pcf:
extends:
- .pcf-deploy
script:
- do deploy
# alternatively, you can define rules directly instead of using `extends:`
deploy-dev-k8s:
rules:
- !reference [.rules, k8s-only]
- !reference [.rules, manual-feature-branch-optional]
script:
- do deploy
# ... and so on
Здесь, вероятно, есть и другие возможности рефакторинга для вас, но это, возможно, не по существу вопроса :)
Отлично ... протестировал и сработало. Ваше объяснение того, как работает оценка, очень помогло, так как мне нужно было внести дополнительные коррективы. Я просматривал документацию GitLab, они очень краткие и не объясняют, что именно происходит. Еще раз спасибо, и я признателен, если у вас есть еще какие-либо точки рефакторинга для моего подхода.
@xbmono, что касается других возможностей для рефакторинга, в основном я думал, что вы сможете сориентировать все в матрицу с двумя измерениями: платформа и среда (например, pcf/k8s и dev/production). Но я полагаю, это зависит от деталей ваших сценариев и от того, что именно вы хотите. Возможно, вы также могли бы избежать повторения одного и того же script:
(при условии, что это на самом деле одно и то же или может быть одинаковым для каждой работы).
Огромное спасибо! Я реализую это и посмотрю, как оно пойдет, но мне также интересно узнать, какой другой рефакторинг вы предлагаете.