Skip to content
Snippets Groups Projects
Commit a36d5561 authored by Kamil Trzcinski's avatar Kamil Trzcinski
Browse files

Introduce deploy command that allows to start deployment from one environment to second one

parent 1d16f137
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -103,8 +103,8 @@ class Environment < ActiveRecord::Base
def actions_for(environment)
return [] unless manual_actions
 
manual_actions.select |action|
action.expanded_environment_name = environment
manual_actions.select do |action|
action.expanded_environment_name == environment
end
end
end
---
title: Add deployment command to ChatOps
merge_request: 7619
author:
Loading
Loading
@@ -4,6 +4,7 @@ module Gitlab
COMMANDS = [
Gitlab::ChatCommands::IssueShow,
Gitlab::ChatCommands::IssueCreate,
Gitlab::ChatCommands::Deploy,
].freeze
 
def execute
Loading
Loading
Loading
Loading
@@ -9,6 +9,10 @@ module Gitlab
'deploy <environment> to <target-environment>'
end
 
def self.available?(project)
project.builds_enabled?
end
def self.allowed?(project, user)
can?(user, :create_deployment, project)
end
Loading
Loading
@@ -17,11 +21,8 @@ module Gitlab
from = match[:from]
to = match[:to]
 
environment = project.environments.find_by(name: from)
return unless environment
actions = environment.actions_for(to)
return unless actions.any?
actions = find_actions(from, to)
return unless actions.present?
 
if actions.one?
actions.first.play(current_user)
Loading
Loading
@@ -29,6 +30,15 @@ module Gitlab
Result.new(:error, 'Too many actions defined')
end
end
private
def find_actions(from, to)
environment = project.environments.find_by(name: from)
return unless environment
environment.actions_for(to).select(&:starts_environment?)
end
end
end
end
Loading
Loading
@@ -55,6 +55,12 @@ FactoryGirl.define do
self.when 'manual'
end
 
trait :teardown_environment do
options do
{ environment: { action: 'stop' } }
end
end
trait :allowed_to_fail do
allow_failure true
end
Loading
Loading
Loading
Loading
@@ -4,9 +4,9 @@ describe Gitlab::ChatCommands::Command, service: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
 
subject { described_class.new(project, user, params).execute }
describe '#execute' do
subject { described_class.new(project, user, params).execute }
context 'when no command is available' do
let(:params) { { text: 'issue show 1' } }
let(:project) { create(:project, has_external_issue_tracker: true) }
Loading
Loading
@@ -51,5 +51,44 @@ describe Gitlab::ChatCommands::Command, service: true do
expect(subject[:text]).to match(/\/issues\/\d+/)
end
end
context 'when trying to do deployment' do
let(:params) { { text: 'deploy staging to production' } }
let!(:build) { create(:ci_build, project: project) }
let!(:staging) { create(:environment, name: 'staging', project: project) }
let!(:deployment) { create(:deployment, environment: staging, deployable: build) }
let!(:manual) do
create(:ci_build, :manual, project: project, pipeline: build.pipeline, name: 'first', environment: 'production')
end
context 'and user can not create deployment' do
it 'returns action' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to start_with('Whoops! That action is not allowed')
end
end
context 'and user does have deployment permission' do
before do
project.team << [user, :developer]
end
it 'returns action' do
expect(subject[:text]).to include(manual.name)
expect(subject[:response_type]).to be(:in_channel)
end
context 'when duplicate action exists' do
let!(:manual2) do
create(:ci_build, :manual, project: project, pipeline: build.pipeline, name: 'second', environment: 'production')
end
it 'returns error' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to include('Too many actions defined')
end
end
end
end
end
end
require 'spec_helper'
describe Gitlab::ChatCommands::Deploy, service: true do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:regex_match) { described_class.match('deploy staging to production') }
before do
project.team << [user, :master]
end
subject do
described_class.new(project, user).execute(regex_match)
end
context 'if no environment is defined' do
it 'returns nil' do
expect(subject).to be_nil
end
end
context 'with environment' do
let!(:staging) { create(:environment, name: 'staging', project: project) }
let!(:build) { create(:ci_build, project: project) }
let!(:deployment) { create(:deployment, environment: staging, deployable: build) }
context 'without actions' do
it 'returns nil' do
expect(subject).to be_nil
end
end
context 'with action' do
let!(:manual1) do
create(:ci_build, :manual, project: project, pipeline: build.pipeline, name: 'first', environment: 'production')
end
it 'returns action' do
expect(subject).to eq(manual1)
end
context 'when duplicate action exists' do
let!(:manual2) do
create(:ci_build, :manual, project: project, pipeline: build.pipeline, name: 'second', environment: 'production')
end
it 'returns error' do
expect(subject.message).to eq('Too many actions defined')
end
end
context 'when teardown action exists' do
let!(:teardown) do
create(:ci_build, :manual, :teardown_environment, project: project, pipeline: build.pipeline,
name: 'teardown', environment: 'production')
end
it 'returns error' do
expect(subject).to eq(action)
end
end
end
end
end
describe 'self.match' do
it 'matches the environment' do
match = described_class.match('deploy staging to production')
expect(match[:from]).to eq('staging')
expect(match[:to]).to eq('production')
end
end
end
Loading
Loading
@@ -9,6 +9,7 @@ describe Environment, models: true do
it { is_expected.to delegate_method(:last_deployment).to(:deployments).as(:last) }
 
it { is_expected.to delegate_method(:stop_action).to(:last_deployment) }
it { is_expected.to delegate_method(:manual_actions).to(:last_deployment) }
 
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:project_id) }
Loading
Loading
@@ -187,4 +188,15 @@ describe Environment, models: true do
it { is_expected.to be false }
end
end
describe '#actions_for' do
let(:deployment) { create(:deployment, environment: environment) }
let(:pipeline) { deployment.deployable.pipeline }
let!(:review_action) { create(:ci_build, :manual, name: 'review-apps', pipeline: pipeline, environment: 'review/$CI_BUILD_REF_NAME' )}
let!(:production_action) { create(:ci_build, :manual, name: 'production', pipeline: pipeline, environment: 'production' )}
it 'returns a list of actions with matching environment' do
expect(environment.actions_for('review/master')).to contain_exactly(review_action)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment