diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index ae82c0db3f1ce40f0bc4de001d4ce0e42e5e8d5c..bbfa6cf7d05ab66d2061315f1667ef7e978007bf 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -14,7 +14,7 @@ module Gitlab
         @config = Loader.new(config).load!
 
         @global = Node::Global.new(@config)
-        @global.process!
+        @global.compose!
       end
 
       def valid?
diff --git a/lib/gitlab/ci/config/node/configurable.rb b/lib/gitlab/ci/config/node/configurable.rb
index fb3604edac260542a6015daeae9ba17b036dafba..530f95a6251ca9d4fbe61646a42e4192b738144a 100644
--- a/lib/gitlab/ci/config/node/configurable.rb
+++ b/lib/gitlab/ci/config/node/configurable.rb
@@ -23,9 +23,9 @@ module Gitlab
             end
           end
 
-          private
+          def compose!(deps)
+            return unless valid?
 
-          def compose!(_deps)
             self.class.nodes.each do |key, factory|
               factory
                 .value(@config[key])
@@ -33,6 +33,12 @@ module Gitlab
 
               @entries[key] = factory.create!
             end
+
+            yield if block_given?
+
+            @entries.each_value do |entry|
+              entry.compose!(deps)
+            end
           end
 
           class_methods do
diff --git a/lib/gitlab/ci/config/node/entry.rb b/lib/gitlab/ci/config/node/entry.rb
index 40ffa85d6da8bc443094b6601e324c7e2fab3899..e02f4bf0a0526a088d8ab0392b68615754e65dde 100644
--- a/lib/gitlab/ci/config/node/entry.rb
+++ b/lib/gitlab/ci/config/node/entry.rb
@@ -20,14 +20,16 @@ module Gitlab
             @validator.validate(:new)
           end
 
+          # Temporary method
+          #
           def process!(deps = nil)
-            return unless valid?
-
             compose!(deps)
+          end
 
-            descendants.each do |entry|
-              entry.process!(deps)
-            end
+          def compose!(deps = nil)
+            return unless valid?
+
+            yield if block_given?
           end
 
           def leaf?
@@ -76,11 +78,6 @@ module Gitlab
           def self.validator
             Validator
           end
-
-          private
-
-          def compose!(_deps)
-          end
         end
       end
     end
diff --git a/lib/gitlab/ci/config/node/global.rb b/lib/gitlab/ci/config/node/global.rb
index 4d65309cf44725b03ef399dcb3963e2679d8afd6..2a2943c92886ce205053e7096a356331b938518b 100644
--- a/lib/gitlab/ci/config/node/global.rb
+++ b/lib/gitlab/ci/config/node/global.rb
@@ -36,19 +36,15 @@ module Gitlab
           helpers :before_script, :image, :services, :after_script,
                   :variables, :stages, :types, :cache, :jobs
 
-          def process!(_deps = nil)
-            super(self)
+          def compose!(_deps = nil)
+            super(self) do
+              compose_jobs!
+              compose_deprecated_entries!
+            end
           end
 
           private
 
-          def compose!(_deps)
-            super
-
-            compose_jobs!
-            compose_deprecated_entries!
-          end
-
           def compose_jobs!
             factory = Node::Factory.new(Node::Jobs)
               .value(@config.except(*self.class.nodes.keys))
diff --git a/lib/gitlab/ci/config/node/job.rb b/lib/gitlab/ci/config/node/job.rb
index 55f34b446e588a814f6b95db43433264c788ebe2..9317bb40f5086c848b0e2d936f7bb07a625d1407 100644
--- a/lib/gitlab/ci/config/node/job.rb
+++ b/lib/gitlab/ci/config/node/job.rb
@@ -82,6 +82,16 @@ module Gitlab
                   :cache, :image, :services, :only, :except, :variables,
                   :artifacts
 
+          def compose!(deps)
+            super do
+              if type_defined? && !stage_defined?
+                @entries[:stage] = @entries[:type]
+              end
+
+              @entries.delete(:type)
+            end
+          end
+
           def name
             @metadata[:name]
           end
@@ -106,16 +116,6 @@ module Gitlab
               artifacts: artifacts,
               after_script: after_script }
           end
-
-          def compose!(_deps)
-            super
-
-            if type_defined? && !stage_defined?
-              @entries[:stage] = @entries[:type]
-            end
-
-            @entries.delete(:type)
-          end
         end
       end
     end
diff --git a/lib/gitlab/ci/config/node/jobs.rb b/lib/gitlab/ci/config/node/jobs.rb
index a2a8554ed19a4237ad2c84325f801a45cac8d286..45865825e4610a1c054fd952bd559b5ea8c06e09 100644
--- a/lib/gitlab/ci/config/node/jobs.rb
+++ b/lib/gitlab/ci/config/node/jobs.rb
@@ -26,19 +26,23 @@ module Gitlab
             name.to_s.start_with?('.')
           end
 
-          private
-
-          def compose!(_deps)
-            @config.each do |name, config|
-              node = hidden?(name) ? Node::HiddenJob : Node::Job
-
-              factory = Node::Factory.new(node)
-                .value(config || {})
-                .metadata(name: name)
-                .with(key: name, parent: self,
-                      description: "#{name} job definition.")
+          def compose!(deps = nil)
+            super do
+              @config.each do |name, config|
+                node = hidden?(name) ? Node::HiddenJob : Node::Job
+
+                factory = Node::Factory.new(node)
+                  .value(config || {})
+                  .metadata(name: name)
+                  .with(key: name, parent: self,
+                        description: "#{name} job definition.")
+
+                @entries[name] = factory.create!
+              end
 
-              @entries[name] = factory.create!
+              @entries.each_value do |entry|
+                entry.compose!(deps)
+              end
             end
           end
         end