summaryrefslogtreecommitdiff
path: root/lib/gitlab/ci/config/entry/bridge.rb
blob: 7a6840218e1baccb5fbb9f49d23255d219023873 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# frozen_string_literal: true

module Gitlab
  module Ci
    class Config
      module Entry
        ##
        # Entry that represents a CI/CD Bridge job that is responsible for
        # defining a downstream project trigger.
        #
        class Bridge < ::Gitlab::Config::Entry::Node
          include ::Gitlab::Config::Entry::Configurable
          include ::Gitlab::Config::Entry::Attributable
          include ::Gitlab::Config::Entry::Inheritable

          ALLOWED_KEYS = %i[trigger stage allow_failure only except
                            when extends variables needs rules].freeze

          validations do
            validates :config, allowed_keys: ALLOWED_KEYS
            validates :config, presence: true
            validates :name, presence: true
            validates :name, type: Symbol
            validates :config, disallowed_keys: {
                in: %i[only except when start_in],
                message: 'key may not be used with `rules`'
              },
              if: :has_rules?

            with_options allow_nil: true do
              validates :when,
                inclusion: { in: %w[on_success on_failure always],
                              message: 'should be on_success, on_failure or always' }
              validates :extends, type: String
              validates :rules, array_of_hashes: true
            end

            validate on: :composed do
              unless trigger.present? || bridge_needs.present?
                errors.add(:config, 'should contain either a trigger or a needs:pipeline')
              end
            end

            validate on: :composed do
              next unless bridge_needs.present?
              next if bridge_needs.one?

              errors.add(:config, 'should contain at most one bridge need')
            end
          end

          entry :trigger, ::Gitlab::Ci::Config::Entry::Trigger,
            description: 'CI/CD Bridge downstream trigger definition.',
            inherit: false

          entry :needs, ::Gitlab::Ci::Config::Entry::Needs,
            description: 'CI/CD Bridge needs dependency definition.',
            inherit: false,
            metadata: { allowed_needs: %i[job bridge] }

          entry :stage, ::Gitlab::Ci::Config::Entry::Stage,
            description: 'Pipeline stage this job will be executed into.',
            inherit: false

          entry :only, ::Gitlab::Ci::Config::Entry::Policy,
            description: 'Refs policy this job will be executed for.',
            default: ::Gitlab::Ci::Config::Entry::Policy::DEFAULT_ONLY,
            inherit: false

          entry :except, ::Gitlab::Ci::Config::Entry::Policy,
            description: 'Refs policy this job will be executed for.',
            inherit: false

          entry :rules, ::Gitlab::Ci::Config::Entry::Rules,
            description: 'List of evaluable Rules to determine job inclusion.',
            inherit: false,
            metadata: {
              allowed_when: %w[on_success on_failure always never manual delayed].freeze
            }

          entry :variables, ::Gitlab::Ci::Config::Entry::Variables,
            description: 'Environment variables available for this job.',
            inherit: false

          helpers(*ALLOWED_KEYS)
          attributes(*ALLOWED_KEYS)

          def self.matching?(name, config)
            !name.to_s.start_with?('.') &&
              config.is_a?(Hash) &&
              (config.key?(:trigger) || config.key?(:needs))
          end

          def self.visible?
            true
          end

          def compose!(deps = nil)
            super do
              has_workflow_rules = deps&.workflow&.has_rules?

              # If workflow:rules: or rules: are used
              # they are considered not compatible
              # with `only/except` defaults
              #
              # Context: https://gitlab.com/gitlab-org/gitlab/merge_requests/21742
              if has_rules? || has_workflow_rules
                # Remove only/except defaults
                # defaults are not considered as defined
                @entries.delete(:only) unless only_defined?
                @entries.delete(:except) unless except_defined?
              end
            end
          end

          def has_rules?
            @config&.key?(:rules)
          end

          def name
            @metadata[:name]
          end

          def value
            { name: name,
              trigger: (trigger_value if trigger_defined?),
              needs: (needs_value if needs_defined?),
              ignore: !!allow_failure,
              stage: stage_value,
              when: when_value,
              extends: extends_value,
              variables: (variables_value if variables_defined?),
              rules: (rules_value if has_rules?),
              only: only_value,
              except: except_value }.compact
          end

          def bridge_needs
            needs_value[:bridge] if needs_value
          end

          private

          def overwrite_entry(deps, key, current_entry)
            deps.default[key] unless current_entry.specified?
          end
        end
      end
    end
  end
end