Commit 0b0d04b4 authored by Kamil Trzciński's avatar Kamil Trzciński
Browse files

Merge branch 'fix/gb/fix-chatops-deploy-multiple-actions-matching' into 'master'

Improve deploy environment chatops slash command

Closes #34748

See merge request !13150
---
title: Improve deploy environment chatops slash command
merge_request: 13150
author:
......@@ -2,7 +2,11 @@
Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
Commands are scoped to a project, with a trigger term that is specified during configuration.
We suggest you use the project name as the trigger term for simplicity and clarity.
Taking the trigger term as `project-name`, the commands are:
| Command | Effect |
......@@ -12,3 +16,18 @@ Commands are scoped to a project, with a trigger term that is specified during c
| `/project-name issue show <id>` | Shows the issue with id `<id>` |
| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
## Issue commands
It is possible to create new issue, display issue details and search up to 5 issues.
## Deploy command
In order to deploy to an environment, GitLab will try to find a deployment
manual action in the pipeline.
If there is only one action for a given environment, it is going to be triggered.
If there is more than one action defined, GitLab will try to find an action
which name equals the environment name we want to deploy to.
Command will return an error when no matching action has been found.
......@@ -21,29 +21,34 @@ def execute(match)
from = match[:from]
to = match[:to]
actions = find_actions(from, to)
action = find_action(from, to)
if actions.none?
Gitlab::SlashCommands::Presenters::Deploy.new(nil).no_actions
elsif actions.one?
action = play!(from, to, actions.first)
Gitlab::SlashCommands::Presenters::Deploy.new(action).present(from, to)
if action.nil?
Gitlab::SlashCommands::Presenters::Deploy
.new(action).action_not_found
else
Gitlab::SlashCommands::Presenters::Deploy.new(actions).too_many_actions
deployment = action.play(current_user)
Gitlab::SlashCommands::Presenters::Deploy
.new(deployment).present(from, to)
end
end
private
def play!(from, to, action)
action.play(current_user)
end
def find_actions(from, to)
def find_action(from, to)
environment = project.environments.find_by(name: from)
return [] unless environment
return unless environment
environment.actions_for(to).select(&:starts_environment?)
actions = environment.actions_for(to).select do |action|
action.starts_environment?
end
if actions.many?
actions.find { |action| action.name == to.to_s }
else
actions.first
end
end
end
end
......
......@@ -3,17 +3,14 @@ module SlashCommands
module Presenters
class Deploy < Presenters::Base
def present(from, to)
message = "Deployment started from #{from} to #{to}. [Follow its progress](#{resource_url})."
message = "Deployment started from #{from} to #{to}. " \
"[Follow its progress](#{resource_url})."
in_channel_response(text: message)
end
def no_actions
ephemeral_response(text: "No action found to be executed")
end
def too_many_actions
ephemeral_response(text: "Too many actions defined")
def action_not_found
ephemeral_response(text: "Couldn't find a deployment manual action.")
end
end
end
......
......@@ -80,7 +80,7 @@
it 'returns error' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to include('Too many actions defined')
expect(subject[:text]).to include("Couldn't find a deployment manual action.")
end
end
end
......
......@@ -22,7 +22,7 @@
context 'if no environment is defined' do
it 'does not execute an action' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to eq("No action found to be executed")
expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
......@@ -35,12 +35,12 @@
context 'without actions' do
it 'does not execute an action' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to eq("No action found to be executed")
expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
context 'with action' do
let!(:manual1) do
context 'when single action has been matched' do
before do
create(:ci_build, :manual, pipeline: pipeline,
name: 'first',
environment: 'production')
......@@ -48,31 +48,61 @@
it 'returns success result' do
expect(subject[:response_type]).to be(:in_channel)
expect(subject[:text]).to start_with('Deployment started from staging to production')
expect(subject[:text])
.to start_with('Deployment started from staging to production')
end
end
context 'when more than one action has been matched' do
context 'when there is no specific actions with a environment name' do
before do
create(:ci_build, :manual, pipeline: pipeline,
name: 'first',
environment: 'production')
context 'when duplicate action exists' do
let!(:manual2) do
create(:ci_build, :manual, pipeline: pipeline,
name: 'second',
environment: 'production')
end
it 'returns error' do
it 'returns error about too many actions defined' do
expect(subject[:text]).to eq("Couldn't find a deployment manual action.")
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to eq('Too many actions defined')
end
end
context 'when teardown action exists' do
let!(:teardown) do
context 'when one of the actions is environement specific action' do
before do
create(:ci_build, :manual, pipeline: pipeline,
name: 'first',
environment: 'production')
create(:ci_build, :manual, pipeline: pipeline,
name: 'production',
environment: 'production')
end
it 'deploys to production' do
expect(subject[:text])
.to start_with('Deployment started from staging to production')
expect(subject[:response_type]).to be(:in_channel)
end
end
context 'when one of the actions is a teardown action' do
before do
create(:ci_build, :manual, pipeline: pipeline,
name: 'first',
environment: 'production')
create(:ci_build, :manual, :teardown_environment,
pipeline: pipeline, name: 'teardown', environment: 'production')
end
it 'returns the success message' do
it 'deploys to production' do
expect(subject[:text])
.to start_with('Deployment started from staging to production')
expect(subject[:response_type]).to be(:in_channel)
expect(subject[:text]).to start_with('Deployment started from staging to production')
end
end
end
......
......@@ -17,8 +17,8 @@
end
end
describe '#no_actions' do
subject { described_class.new(nil).no_actions }
describe '#action_not_found' do
subject { described_class.new(nil).action_not_found }
it { is_expected.to have_key(:text) }
it { is_expected.to have_key(:response_type) }
......@@ -27,21 +27,7 @@
it 'tells the user there is no action' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to eq("No action found to be executed")
end
end
describe '#too_many_actions' do
subject { described_class.new([]).too_many_actions }
it { is_expected.to have_key(:text) }
it { is_expected.to have_key(:response_type) }
it { is_expected.to have_key(:status) }
it { is_expected.not_to have_key(:attachments) }
it 'tells the user there is no action' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to eq("Too many actions defined")
expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment