From d9142f2c97524fc2d5af7dda79b849d1e23f4910 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon <grzesiek.bizon@gmail.com>
Date: Fri, 8 Jul 2016 13:31:41 +0200
Subject: [PATCH] Add CI config known stage validation for job stage

---
 lib/gitlab/ci/config/node/stage.rb           | 13 +++++
 spec/lib/gitlab/ci/config/node/stage_spec.rb | 54 ++++++++++++++++----
 2 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/lib/gitlab/ci/config/node/stage.rb b/lib/gitlab/ci/config/node/stage.rb
index 9c76cf7c0b7..457f6dfa3ba 100644
--- a/lib/gitlab/ci/config/node/stage.rb
+++ b/lib/gitlab/ci/config/node/stage.rb
@@ -11,6 +11,19 @@ module Gitlab
           validations do
             validates :config, key: true
             validates :global, required_attribute: true
+            validate :known_stage, on: :after
+
+            def known_stage
+              unless known?
+                stages_list = global.stages.join(', ')
+                errors.add(:config,
+                           "should be one of defined stages (#{stages_list})")
+              end
+            end
+          end
+
+          def known?
+            @global.stages.include?(@config)
           end
 
           def self.default
diff --git a/spec/lib/gitlab/ci/config/node/stage_spec.rb b/spec/lib/gitlab/ci/config/node/stage_spec.rb
index 4047d46c80f..95b46d76adb 100644
--- a/spec/lib/gitlab/ci/config/node/stage_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/stage_spec.rb
@@ -1,33 +1,33 @@
 require 'spec_helper'
 
 describe Gitlab::Ci::Config::Node::Stage do
-  let(:entry) { described_class.new(config, global: global) }
+  let(:stage) { described_class.new(config, global: global) }
   let(:global) { spy('Global') }
 
   describe 'validations' do
-    context 'when entry config value is correct' do
+    context 'when stage config value is correct' do
       let(:config) { :build }
 
       describe '#value' do
         it 'returns a stage key' do
-          expect(entry.value).to eq config
+          expect(stage.value).to eq config
         end
       end
 
       describe '#valid?' do
         it 'is valid' do
-          expect(entry).to be_valid
+          expect(stage).to be_valid
         end
       end
     end
 
-    context 'when entry config is incorrect' do
+    context 'when stage config is incorrect' do
       describe '#errors' do
         context 'when reference to global node is not set' do
-          let(:entry) { described_class.new(config) }
+          let(:stage) { described_class.new(config) }
 
           it 'raises error' do
-            expect { entry }.to raise_error(
+            expect { stage }.to raise_error(
               Gitlab::Ci::Config::Node::Entry::InvalidError,
               /Entry needs global attribute set internally./
             )
@@ -38,21 +38,53 @@ describe Gitlab::Ci::Config::Node::Stage do
           let(:config) { { test: true } }
 
           it 'reports errors about wrong type' do
-            expect(entry.errors)
+            expect(stage.errors)
               .to include 'stage config should be a string or symbol'
           end
         end
 
         context 'when stage is not present in global configuration' do
-          pending 'reports error about missing stage' do
-            expect(entry.errors)
-              .to include 'stage config should be one of test, stage'
+          let(:config) { :unknown }
+
+          before do
+            allow(global)
+              .to receive(:stages).and_return([:test, :deploy])
+          end
+
+          it 'reports error about missing stage' do
+            stage.validate!
+
+            expect(stage.errors)
+              .to include 'stage config should be one of ' \
+                          'defined stages (test, deploy)'
           end
         end
       end
     end
   end
 
+  describe '#known?' do
+    before do
+      allow(global).to receive(:stages).and_return([:test, :deploy])
+    end
+
+    context 'when stage is not known' do
+      let(:config) { :unknown }
+
+      it 'returns false' do
+        expect(stage.known?).to be false
+      end
+    end
+
+    context 'when stage is known' do
+      let(:config) { :test }
+
+      it 'returns false' do
+        expect(stage.known?).to be true
+      end
+    end
+  end
+
   describe '.default' do
     it 'returns default stage' do
       expect(described_class.default).to eq :test
-- 
GitLab