From 075712a9d7e7d9cac8731debb0312a092bcefbb2 Mon Sep 17 00:00:00 2001
From: Daniel Dehennin <daniel.dehennin@ac-dijon.fr>
Date: Thu, 9 Dec 2021 09:18:51 +0100
Subject: [PATCH] refactor(rules): permit to combine individual rules

The previous rules template set did not permit to combine rules easily
in user jobs.

Using a single hash of individual rules permit to reference them more
clearly. It avoids duplicated conditionnals in the current rules set
and marke it easier to combine them in user jobs, with some
limitations[1].

* templates/Rules.yaml: define the `.rules-map` hash of individual
  rules and reference them in rules templates

* templates/Release/Semantic-release.yaml: use the `.rules-map`
  directly to reduce the conditionnal duplication

Closes #3

Footnotes:
[1]  https://forum.gitlab.com/t/add-conditions-to-rules-array-merged-with-reference/62600
---
 templates/Release/Semantic-release.yaml |   9 +-
 templates/Rules.yaml                    | 156 +++++++++++++-----------
 2 files changed, 89 insertions(+), 76 deletions(-)

diff --git a/templates/Release/Semantic-release.yaml b/templates/Release/Semantic-release.yaml
index 240958d..632cd77 100644
--- a/templates/Release/Semantic-release.yaml
+++ b/templates/Release/Semantic-release.yaml
@@ -46,14 +46,13 @@
 #
 # We can't merge rules with `!reference` until we switch to Gitlab >= 14.3
 # https://gitlab.com/gitlab-org/gitlab/-/issues/322992
+# Use a `.rules-map` as a workaround
 
 .on-stable-with-semantic-release-config:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
-      when: never
-    # Exclude semantic-release commits on $STABLE_BRANCH
-    - if: $CI_COMMIT_BRANCH == $STABLE_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
-      when: never
+    - !reference [.rules-map, not-on-schedule]
+    - !reference [.rules-map, not-on-draft]
+    - !reference [.rules-map, not-on-semantic-release-commit]
     - if: $CI_COMMIT_BRANCH == $STABLE_BRANCH
       exists:
         - release.config.js
diff --git a/templates/Rules.yaml b/templates/Rules.yaml
index 966fed4..d9907aa 100644
--- a/templates/Rules.yaml
+++ b/templates/Rules.yaml
@@ -37,6 +37,7 @@
 #     - `wip foo`
 #     - `foo (draft)`
 #     - `foo [WIP]`
+#   - message generated by `semantic-release`
 ---
 variables:
   STABLE_BRANCH: stable
@@ -47,97 +48,110 @@ variables:
   BUGFIX_PREFIX: bugfix/
   FEATURE_PREFIX: feature/
 
-
 # This rules template should be used as the default rules.
 # It select all branches except the stable one.
-# We always exclude schedules.
 .not-on-stable:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
-      when: never
-    - if: $CI_COMMIT_BRANCH == $STABLE_BRANCH
-      when: never
-    # Exclude `Draft` or `WIP` messages
-    - if: $CI_COMMIT_MESSAGE =~ /(?:draft|wip):|\[(?:draft|wip)\]|\((?:draft|wip)\)/i
-      when: never
-    - if: $CI_COMMIT_BRANCH
-      when: on_success
+    - !reference [.rules-map, not-on-schedule]
+    - !reference [.rules-map, not-on-stable]
+    - !reference [.rules-map, not-on-draft]
+    - !reference [.rules-map, not-on-semantic-release-commit]
+    - !reference [.rules-map, on-branch]
 
 # Select only branches that are not stable, testing or development.
-# We always exclude schedules.
 .on-branches:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
-      when: never
-    - if: $CI_COMMIT_TAG
-      when: never
-    - if: $CI_COMMIT_BRANCH == $STABLE_BRANCH
-      when: never
-    - if: $CI_COMMIT_BRANCH == $TESTING_BRANCH
-      when: never
-    - if: $CI_COMMIT_BRANCH == $DEV_BRANCH
-      when: never
-    # Exclude `Draft` or `WIP` messages
-    - if: $CI_COMMIT_MESSAGE =~ /(?:draft|wip):|\[(?:draft|wip)\]|\((?:draft|wip)\)/i
-      when: never
-    - if: $CI_COMMIT_BRANCH
-      when: on_success
+    - !reference [.rules-map, not-on-schedule]
+    - !reference [.rules-map, not-on-tag]
+    - !reference [.rules-map, not-on-stable]
+    - !reference [.rules-map, not-on-testing]
+    - !reference [.rules-map, not-on-dev]
+    - !reference [.rules-map, not-on-draft]
+    - !reference [.rules-map, not-on-semantic-release-commit]
+    - !reference [.rules-map, on-branch]
 
-# Select the developpment branch except for commits comming from `semantic-release`
-# We always exclude schedules.
+# Select the developpment branch
 .on-dev:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
-      when: never
-    # Exclude `Draft` or `WIP` messages
-    - if: $CI_COMMIT_MESSAGE =~ /(?:draft|wip):|\[(?:draft|wip)\]|\((?:draft|wip)\)/i
-      when: never
-    # Exclude $CI_DEFAULT_BRANCH of semantic-release commits
-    - if: $CI_COMMIT_BRANCH == $DEV_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
-      when: never
-    - if: $CI_COMMIT_BRANCH == $DEV_BRANCH
-      when: on_success
+    - !reference [.rules-map, not-on-schedule]
+    - !reference [.rules-map, not-on-draft]
+    - !reference [.rules-map, not-on-semantic-release-commit]
+    - !reference [.rules-map, on-dev]
 
-# Select the pre-release testing branch except for commits comming from `semantic-release`
-# We always exclude schedules.
+# Select the pre-release testing branch
 .on-testing:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
-      when: never
-    # Exclude `Draft` or `WIP` messages
-    - if: $CI_COMMIT_MESSAGE =~ /(?:draft|wip):|\[(?:draft|wip)\]|\((?:draft|wip)\)/i
-      when: never
-    # Exclude $CI_DEFAULT_BRANCH of semantic-release commits
-    - if: $CI_COMMIT_BRANCH == $TESTING_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
-      when: never
-    - if: $CI_COMMIT_BRANCH == $TESTING_BRANCH
-      when: on_success
+    - !reference [.rules-map, not-on-schedule]
+    - !reference [.rules-map, not-on-draft]
+    - !reference [.rules-map, not-on-semantic-release-commit]
+    - !reference [.rules-map, on-testing]
 
-# Select the stable branch except for commits comming from `semantic-release`
-# We always exclude schedules.
+# Select the stable branch
 .on-stable:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
-      when: never
-    # Exclude `Draft` or `WIP` messages
-    - if: $CI_COMMIT_MESSAGE =~ /(?:draft|wip):|\[(?:draft|wip)\]|\((?:draft|wip)\)/i
-      when: never
-    # Exclude $CI_DEFAULT_BRANCH of semantic-release commits
-    - if: $CI_COMMIT_BRANCH == $STABLE_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
-      when: never
-    - if: $CI_COMMIT_BRANCH == $STABLE_BRANCH
-      when: on_success
+    - !reference [.rules-map, not-on-schedule]
+    - !reference [.rules-map, not-on-draft]
+    - !reference [.rules-map, not-on-semantic-release-commit]
+    - !reference [.rules-map, on-stable]
 
 # Select the protected release tags
-# We always exclude schedules.
 .on-release-tag:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
-      when: never
+    - !reference [.rules-map, not-on-schedule]
+    - !reference [.rules-map, not-on-draft]
+    - !reference [.rules-map, on-release-tag]
+
+# We use a single rules hash to be referenced as array elements by
+# individual rules templates above.
+# This avoid the duplication of rules conditions
+#
+# SEE ALSO
+# ========
+#
+# - https://forum.gitlab.com/t/add-conditions-to-rules-array-merged-with-reference/62600
+# - https://gitlab.com/gitlab-org/gitlab/-/issues/322992
+# - https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67922
+# - https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67922
+.rules-map:
+  not-on-schedule:
+    if: '$CI_PIPELINE_SOURCE == "schedule"'
+    when: never
+  not-on-tag:
+    if: $CI_COMMIT_TAG
+    when: never
+  not-on-stable:
+    if: $CI_COMMIT_BRANCH == $STABLE_BRANCH
+    when: never
+  not-on-testing:
+    if: $CI_COMMIT_BRANCH == $TESTING_BRANCH
+    when: never
+  not-on-dev:
+    if: $CI_COMMIT_BRANCH == $DEV_BRANCH
+    when: never
+  not-on-draft:
     # Exclude `Draft` or `WIP` messages
-    - if: $CI_COMMIT_MESSAGE =~ /(?:draft|wip):|\[(?:draft|wip)\]|\((?:draft|wip)\)/i
-      when: never
-    # Only for protected release tags
-    - if: $CI_COMMIT_TAG =~ /^release\// && $CI_COMMIT_REF_PROTECTED
-      when: on_success
+    if: $CI_COMMIT_MESSAGE =~ /(?:draft|wip):|\[(?:draft|wip)\]|\((?:draft|wip)\)/i
+    when: never
+  not-on-semantic-release-commit:
+    # Exclude $CI_DEFAULT_BRANCH of semantic-release commits
+    if: $CI_COMMIT_BRANCH && $CI_COMMIT_MESSAGE =~ /^chore\(release\):/
+    when: never
+  on-branch:
+    if: $CI_COMMIT_BRANCH
+    when: on_success
+  on-stable:
+    if: $CI_COMMIT_BRANCH == $STABLE_BRANCH
+    when: on_success
+  on-testing:
+    if: $CI_COMMIT_BRANCH == $TESTING_BRANCH
+    when: on_success
+  on-dev:
+    if: $CI_COMMIT_BRANCH == $DEV_BRANCH
+    when: on_success
+  on-tag:
+    if: $CI_COMMIT_TAG
+    when: on_success
+  on-release-tag:
+    if: $CI_COMMIT_TAG =~ /^release\// && $CI_COMMIT_REF_PROTECTED
+    when: on_success
 ...
-- 
GitLab