Chat Commands have presenters
This improves the styling and readability of the code. This is supported by both Mattermost and Slack.
This commit is contained in:
parent
b525aff665
commit
dc6921bdbb
29 changed files with 480 additions and 688 deletions
|
@ -28,20 +28,24 @@ class ChatSlashCommandsService < Service
|
|||
end
|
||||
|
||||
def trigger(params)
|
||||
return unless valid_token?(params[:token])
|
||||
return access_presenter unless valid_token?(params[:token])
|
||||
|
||||
user = find_chat_user(params)
|
||||
unless user
|
||||
url = authorize_chat_name_url(params)
|
||||
return presenter.authorize_chat_name(url)
|
||||
end
|
||||
|
||||
Gitlab::ChatCommands::Command.new(project, user,
|
||||
params).execute
|
||||
if user
|
||||
Gitlab::ChatCommands::Command.new(project, user, params).execute
|
||||
else
|
||||
url = authorize_chat_name_url(params)
|
||||
access_presenter(url).authorize
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def access_presenter(url = nil)
|
||||
Gitlab::ChatCommands::Presenters::Access.new(url)
|
||||
end
|
||||
|
||||
def find_chat_user(params)
|
||||
ChatNames::FindUserService.new(self, params).execute
|
||||
end
|
||||
|
@ -49,8 +53,4 @@ class ChatSlashCommandsService < Service
|
|||
def authorize_chat_name_url(params)
|
||||
ChatNames::AuthorizeUserService.new(self, params).execute
|
||||
end
|
||||
|
||||
def presenter
|
||||
Gitlab::ChatCommands::Presenter.new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -42,10 +42,6 @@ module Gitlab
|
|||
def find_by_iid(iid)
|
||||
collection.find_by(iid: iid)
|
||||
end
|
||||
|
||||
def presenter
|
||||
Gitlab::ChatCommands::Presenter.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,9 +13,9 @@ module Gitlab
|
|||
|
||||
if command
|
||||
if command.allowed?(project, current_user)
|
||||
present command.new(project, current_user, params).execute(match)
|
||||
command.new(project, current_user, params).execute(match)
|
||||
else
|
||||
access_denied
|
||||
Gitlab::ChatCommands::Presenters::Access.new.access_denied
|
||||
end
|
||||
else
|
||||
help(help_messages)
|
||||
|
@ -25,7 +25,7 @@ module Gitlab
|
|||
def match_command
|
||||
match = nil
|
||||
service = available_commands.find do |klass|
|
||||
match = klass.match(command)
|
||||
match = klass.match(params[:text])
|
||||
end
|
||||
|
||||
[service, match]
|
||||
|
@ -42,22 +42,6 @@ module Gitlab
|
|||
klass.available?(project)
|
||||
end
|
||||
end
|
||||
|
||||
def command
|
||||
params[:text]
|
||||
end
|
||||
|
||||
def help(messages)
|
||||
presenter.help(messages, params[:command])
|
||||
end
|
||||
|
||||
def access_denied
|
||||
presenter.access_denied
|
||||
end
|
||||
|
||||
def present(resource)
|
||||
presenter.present(resource)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
module Gitlab
|
||||
module ChatCommands
|
||||
class Deploy < BaseCommand
|
||||
include Gitlab::Routing.url_helpers
|
||||
|
||||
def self.match(text)
|
||||
/\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text)
|
||||
end
|
||||
|
@ -24,35 +22,29 @@ module Gitlab
|
|||
to = match[:to]
|
||||
|
||||
actions = find_actions(from, to)
|
||||
return unless actions.present?
|
||||
|
||||
if actions.one?
|
||||
play!(from, to, actions.first)
|
||||
if actions.none?
|
||||
Gitlab::ChatCommands::Presenters::Deploy.new(nil).no_actions
|
||||
elsif actions.one?
|
||||
action = play!(from, to, actions.first)
|
||||
Gitlab::ChatCommands::Presenters::Deploy.new(action).present(from, to)
|
||||
else
|
||||
Result.new(:error, 'Too many actions defined')
|
||||
Gitlab::ChatCommands::Presenters::Deploy.new(actions).too_many_actions
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def play!(from, to, action)
|
||||
new_action = action.play(current_user)
|
||||
|
||||
Result.new(:success, "Deployment from #{from} to #{to} started. Follow the progress: #{url(new_action)}.")
|
||||
action.play(current_user)
|
||||
end
|
||||
|
||||
def find_actions(from, to)
|
||||
environment = project.environments.find_by(name: from)
|
||||
return unless environment
|
||||
return [] unless environment
|
||||
|
||||
environment.actions_for(to).select(&:starts_environment?)
|
||||
end
|
||||
|
||||
def url(subject)
|
||||
polymorphic_url(
|
||||
[subject.project.namespace.becomes(Namespace), subject.project, subject]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ module Gitlab
|
|||
module ChatCommands
|
||||
class IssueCreate < IssueCommand
|
||||
def self.match(text)
|
||||
# we can not match \n with the dot by passing the m modifier as than
|
||||
# we can not match \n with the dot by passing the m modifier as than
|
||||
# the title and description are not seperated
|
||||
/\Aissue\s+(new|create)\s+(?<title>[^\n]*)\n*(?<description>(.|\n)*)/.match(text)
|
||||
end
|
||||
|
@ -19,8 +19,24 @@ module Gitlab
|
|||
title = match[:title]
|
||||
description = match[:description].to_s.rstrip
|
||||
|
||||
issue = create_issue(title: title, description: description)
|
||||
|
||||
if issue.errors.any?
|
||||
presenter(issue).display_errors
|
||||
else
|
||||
presenter(issue).present
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_issue(title:, description:)
|
||||
Issues::CreateService.new(project, current_user, title: title, description: description).execute
|
||||
end
|
||||
|
||||
def presenter(issue)
|
||||
Gitlab::ChatCommands::Presenters::ShowIssue.new(issue)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,15 @@ module Gitlab
|
|||
end
|
||||
|
||||
def execute(match)
|
||||
collection.search(match[:query]).limit(QUERY_LIMIT)
|
||||
issues = collection.search(match[:query]).limit(QUERY_LIMIT)
|
||||
|
||||
if issues.none?
|
||||
Presenters::Access.new(issues).not_found
|
||||
elsif issues.one?
|
||||
Presenters::ShowIssue.new(issues.first).present
|
||||
else
|
||||
Presenters::ListIssues.new(issues).present
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,13 @@ module Gitlab
|
|||
end
|
||||
|
||||
def execute(match)
|
||||
find_by_iid(match[:iid])
|
||||
issue = find_by_iid(match[:iid])
|
||||
|
||||
if issue
|
||||
Gitlab::ChatCommands::Presenters::ShowIssue.new(issue).present
|
||||
else
|
||||
Gitlab::ChatCommands::Presenters::Access.new.not_found
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
module Gitlab
|
||||
module ChatCommands
|
||||
class Presenter
|
||||
include Gitlab::Routing
|
||||
|
||||
def authorize_chat_name(url)
|
||||
message = if url
|
||||
":wave: Hi there! Before I do anything for you, please [connect your GitLab account](#{url})."
|
||||
else
|
||||
":sweat_smile: Couldn't identify you, nor can I autorize you!"
|
||||
end
|
||||
|
||||
ephemeral_response(message)
|
||||
end
|
||||
|
||||
def help(commands, trigger)
|
||||
if commands.none?
|
||||
ephemeral_response("No commands configured")
|
||||
else
|
||||
commands.map! { |command| "#{trigger} #{command}" }
|
||||
message = header_with_list("Available commands", commands)
|
||||
|
||||
ephemeral_response(message)
|
||||
end
|
||||
end
|
||||
|
||||
def present(subject)
|
||||
return not_found unless subject
|
||||
|
||||
if subject.is_a?(Gitlab::ChatCommands::Result)
|
||||
show_result(subject)
|
||||
elsif subject.respond_to?(:count)
|
||||
if subject.none?
|
||||
not_found
|
||||
elsif subject.one?
|
||||
single_resource(subject.first)
|
||||
else
|
||||
multiple_resources(subject)
|
||||
end
|
||||
else
|
||||
single_resource(subject)
|
||||
end
|
||||
end
|
||||
|
||||
def access_denied
|
||||
ephemeral_response("Whoops! That action is not allowed. This incident will be [reported](https://xkcd.com/838/).")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def show_result(result)
|
||||
case result.type
|
||||
when :success
|
||||
in_channel_response(result.message)
|
||||
else
|
||||
ephemeral_response(result.message)
|
||||
end
|
||||
end
|
||||
|
||||
def not_found
|
||||
ephemeral_response("404 not found! GitLab couldn't find what you were looking for! :boom:")
|
||||
end
|
||||
|
||||
def single_resource(resource)
|
||||
return error(resource) if resource.errors.any? || !resource.persisted?
|
||||
|
||||
message = "#{title(resource)}:"
|
||||
message << "\n\n#{resource.description}" if resource.try(:description)
|
||||
|
||||
in_channel_response(message)
|
||||
end
|
||||
|
||||
def multiple_resources(resources)
|
||||
titles = resources.map { |resource| title(resource) }
|
||||
|
||||
message = header_with_list("Multiple results were found:", titles)
|
||||
|
||||
ephemeral_response(message)
|
||||
end
|
||||
|
||||
def error(resource)
|
||||
message = header_with_list("The action was not successful, because:", resource.errors.messages)
|
||||
|
||||
ephemeral_response(message)
|
||||
end
|
||||
|
||||
def title(resource)
|
||||
reference = resource.try(:to_reference) || resource.try(:id)
|
||||
title = resource.try(:title) || resource.try(:name)
|
||||
|
||||
"[#{reference} #{title}](#{url(resource)})"
|
||||
end
|
||||
|
||||
def header_with_list(header, items)
|
||||
message = [header]
|
||||
|
||||
items.each do |item|
|
||||
message << "- #{item}"
|
||||
end
|
||||
|
||||
message.join("\n")
|
||||
end
|
||||
|
||||
def url(resource)
|
||||
url_for(
|
||||
[
|
||||
resource.project.namespace.becomes(Namespace),
|
||||
resource.project,
|
||||
resource
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def ephemeral_response(message)
|
||||
{
|
||||
response_type: :ephemeral,
|
||||
text: message,
|
||||
status: 200
|
||||
}
|
||||
end
|
||||
|
||||
def in_channel_response(message)
|
||||
{
|
||||
response_type: :in_channel,
|
||||
text: message,
|
||||
status: 200
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
22
lib/gitlab/chat_commands/presenters/access.rb
Normal file
22
lib/gitlab/chat_commands/presenters/access.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
module Gitlab::ChatCommands::Presenters
|
||||
class Access < Gitlab::ChatCommands::Presenters::Base
|
||||
def access_denied
|
||||
ephemeral_response(text: "Whoops! This action is not allowed. This incident will be [reported](https://xkcd.com/838/).")
|
||||
end
|
||||
|
||||
def not_found
|
||||
ephemeral_response(text: "404 not found! GitLab couldn't find what you were looking for! :boom:")
|
||||
end
|
||||
|
||||
def authorize
|
||||
message =
|
||||
if @resource
|
||||
":wave: Hi there! Before I do anything for you, please [connect your GitLab account](#{@resource})."
|
||||
else
|
||||
":sweat_smile: Couldn't identify you, nor can I autorize you!"
|
||||
end
|
||||
|
||||
ephemeral_response(text: message)
|
||||
end
|
||||
end
|
||||
end
|
73
lib/gitlab/chat_commands/presenters/base.rb
Normal file
73
lib/gitlab/chat_commands/presenters/base.rb
Normal file
|
@ -0,0 +1,73 @@
|
|||
module Gitlab::ChatCommands::Presenters
|
||||
class Base
|
||||
include Gitlab::Routing.url_helpers
|
||||
|
||||
def initialize(resource = nil)
|
||||
@resource = resource
|
||||
end
|
||||
|
||||
def display_errors
|
||||
message = header_with_list("The action was not successful, because:", @resource.errors.full_messages)
|
||||
|
||||
ephemeral_response(text: message)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def header_with_list(header, items)
|
||||
message = [header]
|
||||
|
||||
items.each do |item|
|
||||
message << "- #{item}"
|
||||
end
|
||||
|
||||
message.join("\n")
|
||||
end
|
||||
|
||||
def ephemeral_response(message)
|
||||
response = {
|
||||
response_type: :ephemeral,
|
||||
status: 200
|
||||
}.merge(message)
|
||||
|
||||
format_response(response)
|
||||
end
|
||||
|
||||
def in_channel_response(message)
|
||||
response = {
|
||||
response_type: :in_channel,
|
||||
status: 200
|
||||
}.merge(message)
|
||||
|
||||
format_response(response)
|
||||
end
|
||||
|
||||
def format_response(response)
|
||||
response[:text] = format(response[:text]) if response.has_key?(:text)
|
||||
|
||||
if response.has_key?(:attachments)
|
||||
response[:attachments].each do |attachment|
|
||||
attachment[:pretext] = format(attachment[:pretext]) if attachment[:pretext]
|
||||
attachment[:text] = format(attachment[:text]) if attachment[:text]
|
||||
end
|
||||
end
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
# Convert Markdown to slacks format
|
||||
def format(string)
|
||||
Slack::Notifier::LinkFormatter.format(string)
|
||||
end
|
||||
|
||||
def resource_url
|
||||
url_for(
|
||||
[
|
||||
@resource.project.namespace.becomes(Namespace),
|
||||
@resource.project,
|
||||
@resource
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
24
lib/gitlab/chat_commands/presenters/deploy.rb
Normal file
24
lib/gitlab/chat_commands/presenters/deploy.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Gitlab::ChatCommands::Presenters
|
||||
class Deploy < Gitlab::ChatCommands::Presenters::Base
|
||||
def present(from, to)
|
||||
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")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resource_url
|
||||
polymorphic_url(
|
||||
[ @resource.project.namespace.becomes(Namespace), @resource.project, @resource]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
33
lib/gitlab/chat_commands/presenters/issuable.rb
Normal file
33
lib/gitlab/chat_commands/presenters/issuable.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
module Gitlab::ChatCommands::Presenters
|
||||
class Issuable < Gitlab::ChatCommands::Presenters::Base
|
||||
private
|
||||
|
||||
def project
|
||||
@resource.project
|
||||
end
|
||||
|
||||
def author
|
||||
@resource.author
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{
|
||||
title: "Assignee",
|
||||
value: @resource.assignee ? @resource.assignee.name : "_None_",
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Milestone",
|
||||
value: @resource.milestone ? @resource.milestone.title : "_None_",
|
||||
short: true
|
||||
},
|
||||
{
|
||||
title: "Labels",
|
||||
value: @resource.labels.any? ? @resource.label_names : "_None_",
|
||||
short: true
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
32
lib/gitlab/chat_commands/presenters/list_issues.rb
Normal file
32
lib/gitlab/chat_commands/presenters/list_issues.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Gitlab::ChatCommands::Presenters
|
||||
class ListIssues < Gitlab::ChatCommands::Presenters::Base
|
||||
def present
|
||||
ephemeral_response(text: "Here are the issues I found:", attachments: attachments)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def attachments
|
||||
@resource.map do |issue|
|
||||
state = issue.open? ? "Open" : "Closed"
|
||||
|
||||
{
|
||||
fallback: "Issue #{issue.to_reference}: #{issue.title}",
|
||||
color: "#d22852",
|
||||
text: "[#{issue.to_reference}](#{url_for([namespace, project, issue])}) · #{issue.title} (#{state})",
|
||||
mrkdwn_in: [
|
||||
"text"
|
||||
]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def project
|
||||
@project ||= @resource.first.project
|
||||
end
|
||||
|
||||
def namespace
|
||||
@namespace ||= project.namespace.becomes(Namespace)
|
||||
end
|
||||
end
|
||||
end
|
38
lib/gitlab/chat_commands/presenters/show_issue.rb
Normal file
38
lib/gitlab/chat_commands/presenters/show_issue.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module Gitlab::ChatCommands::Presenters
|
||||
class ShowIssue < Gitlab::ChatCommands::Presenters::Issuable
|
||||
def present
|
||||
in_channel_response(show_issue)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def show_issue
|
||||
{
|
||||
attachments: [
|
||||
{
|
||||
title: @resource.title,
|
||||
title_link: resource_url,
|
||||
author_name: author.name,
|
||||
author_icon: author.avatar_url,
|
||||
fallback: "#{@resource.to_reference}: #{@resource.title}",
|
||||
text: text,
|
||||
fields: fields,
|
||||
mrkdwn_in: [
|
||||
:title,
|
||||
:text
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
def text
|
||||
message = ""
|
||||
message << ":+1: #{@resource.upvotes} " unless @resource.upvotes.zero?
|
||||
message << ":-1: #{@resource.downvotes} " unless @resource.downvotes.zero?
|
||||
message << ":speech_balloon: #{@resource.user_notes_count}" unless @resource.user_notes_count.zero?
|
||||
|
||||
message
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
module Mattermost
|
||||
class Error < StandardError; end
|
||||
end
|
|
@ -1,160 +0,0 @@
|
|||
module Mattermost
|
||||
class NoSessionError < Mattermost::Error
|
||||
def message
|
||||
'No session could be set up, is Mattermost configured with Single Sign On?'
|
||||
end
|
||||
end
|
||||
|
||||
class ConnectionError < Mattermost::Error; end
|
||||
|
||||
# This class' prime objective is to obtain a session token on a Mattermost
|
||||
# instance with SSO configured where this GitLab instance is the provider.
|
||||
#
|
||||
# The process depends on OAuth, but skips a step in the authentication cycle.
|
||||
# For example, usually a user would click the 'login in GitLab' button on
|
||||
# Mattermost, which would yield a 302 status code and redirects you to GitLab
|
||||
# to approve the use of your account on Mattermost. Which would trigger a
|
||||
# callback so Mattermost knows this request is approved and gets the required
|
||||
# data to create the user account etc.
|
||||
#
|
||||
# This class however skips the button click, and also the approval phase to
|
||||
# speed up the process and keep it without manual action and get a session
|
||||
# going.
|
||||
class Session
|
||||
include Doorkeeper::Helpers::Controller
|
||||
include HTTParty
|
||||
|
||||
LEASE_TIMEOUT = 60
|
||||
|
||||
base_uri Settings.mattermost.host
|
||||
|
||||
attr_accessor :current_resource_owner, :token
|
||||
|
||||
def initialize(current_user)
|
||||
@current_resource_owner = current_user
|
||||
end
|
||||
|
||||
def with_session
|
||||
with_lease do
|
||||
raise Mattermost::NoSessionError unless create
|
||||
|
||||
begin
|
||||
yield self
|
||||
rescue Errno::ECONNREFUSED
|
||||
raise Mattermost::NoSessionError
|
||||
ensure
|
||||
destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Next methods are needed for Doorkeeper
|
||||
def pre_auth
|
||||
@pre_auth ||= Doorkeeper::OAuth::PreAuthorization.new(
|
||||
Doorkeeper.configuration, server.client_via_uid, params)
|
||||
end
|
||||
|
||||
def authorization
|
||||
@authorization ||= strategy.request
|
||||
end
|
||||
|
||||
def strategy
|
||||
@strategy ||= server.authorization_request(pre_auth.response_type)
|
||||
end
|
||||
|
||||
def request
|
||||
@request ||= OpenStruct.new(parameters: params)
|
||||
end
|
||||
|
||||
def params
|
||||
Rack::Utils.parse_query(oauth_uri.query).symbolize_keys
|
||||
end
|
||||
|
||||
def get(path, options = {})
|
||||
handle_exceptions do
|
||||
self.class.get(path, options.merge(headers: @headers))
|
||||
end
|
||||
end
|
||||
|
||||
def post(path, options = {})
|
||||
handle_exceptions do
|
||||
self.class.post(path, options.merge(headers: @headers))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create
|
||||
return unless oauth_uri
|
||||
return unless token_uri
|
||||
|
||||
@token = request_token
|
||||
@headers = {
|
||||
Authorization: "Bearer #{@token}"
|
||||
}
|
||||
|
||||
@token
|
||||
end
|
||||
|
||||
def destroy
|
||||
post('/api/v3/users/logout')
|
||||
end
|
||||
|
||||
def oauth_uri
|
||||
return @oauth_uri if defined?(@oauth_uri)
|
||||
|
||||
@oauth_uri = nil
|
||||
|
||||
response = get("/api/v3/oauth/gitlab/login", follow_redirects: false)
|
||||
return unless 300 <= response.code && response.code < 400
|
||||
|
||||
redirect_uri = response.headers['location']
|
||||
return unless redirect_uri
|
||||
|
||||
@oauth_uri = URI.parse(redirect_uri)
|
||||
end
|
||||
|
||||
def token_uri
|
||||
@token_uri ||=
|
||||
if oauth_uri
|
||||
authorization.authorize.redirect_uri if pre_auth.authorizable?
|
||||
end
|
||||
end
|
||||
|
||||
def request_token
|
||||
response = get(token_uri, follow_redirects: false)
|
||||
|
||||
if 200 <= response.code && response.code < 400
|
||||
response.headers['token']
|
||||
end
|
||||
end
|
||||
|
||||
def with_lease
|
||||
lease_uuid = lease_try_obtain
|
||||
raise NoSessionError unless lease_uuid
|
||||
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
Gitlab::ExclusiveLease.cancel(lease_key, lease_uuid)
|
||||
end
|
||||
end
|
||||
|
||||
def lease_key
|
||||
"mattermost:session"
|
||||
end
|
||||
|
||||
def lease_try_obtain
|
||||
lease = ::Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT)
|
||||
lease.try_obtain
|
||||
end
|
||||
|
||||
def handle_exceptions
|
||||
yield
|
||||
rescue HTTParty::Error => e
|
||||
raise Mattermost::ConnectionError.new(e.message)
|
||||
rescue Errno::ECONNREFUSED
|
||||
raise Mattermost::ConnectionError.new(e.message)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,6 +5,7 @@ describe Gitlab::ChatCommands::Command, service: true do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
describe '#execute' do
|
||||
<<<<<<< HEAD
|
||||
subject do
|
||||
described_class.new(project, user, params).execute
|
||||
end
|
||||
|
@ -18,6 +19,9 @@ describe Gitlab::ChatCommands::Command, service: true do
|
|||
expect(subject[:text]).to start_with('404 not found')
|
||||
end
|
||||
end
|
||||
=======
|
||||
subject { described_class.new(project, user, params).execute }
|
||||
>>>>>>> Chat Commands have presenters
|
||||
|
||||
context 'when an unknown command is triggered' do
|
||||
let(:params) { { command: '/gitlab', text: "unknown command 123" } }
|
||||
|
@ -34,47 +38,7 @@ describe Gitlab::ChatCommands::Command, service: true do
|
|||
|
||||
it 'rejects the actions' do
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
expect(subject[:text]).to start_with('Whoops! That action is not allowed')
|
||||
end
|
||||
end
|
||||
|
||||
context 'issue is successfully created' do
|
||||
let(:params) { { text: "issue create my new issue" } }
|
||||
|
||||
before do
|
||||
project.team << [user, :master]
|
||||
end
|
||||
|
||||
it 'presents the issue' do
|
||||
expect(subject[:text]).to match("my new issue")
|
||||
end
|
||||
|
||||
it 'shows a link to the new issue' do
|
||||
expect(subject[:text]).to match(/\/issues\/\d+/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'searching for an issue' do
|
||||
let(:params) { { text: 'issue search find me' } }
|
||||
let!(:issue) { create(:issue, project: project, title: 'find me') }
|
||||
|
||||
before do
|
||||
project.team << [user, :master]
|
||||
end
|
||||
|
||||
context 'a single issue is found' do
|
||||
it 'presents the issue' do
|
||||
expect(subject[:text]).to match(issue.title)
|
||||
end
|
||||
end
|
||||
|
||||
context 'multiple issues found' do
|
||||
let!(:issue2) { create(:issue, project: project, title: "someone find me") }
|
||||
|
||||
it 'shows a link to the new issue' do
|
||||
expect(subject[:text]).to match(issue.title)
|
||||
expect(subject[:text]).to match(issue2.title)
|
||||
end
|
||||
expect(subject[:text]).to start_with('Whoops! This action is not allowed')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -90,7 +54,7 @@ describe Gitlab::ChatCommands::Command, service: true do
|
|||
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')
|
||||
expect(subject[:text]).to start_with('Whoops! This action is not allowed')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -100,7 +64,7 @@ describe Gitlab::ChatCommands::Command, service: true do
|
|||
end
|
||||
|
||||
it 'returns action' do
|
||||
expect(subject[:text]).to include('Deployment from staging to production started.')
|
||||
expect(subject[:text]).to include('Deployment started from staging to production')
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
end
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do
|
|||
end
|
||||
|
||||
context 'if no environment is defined' do
|
||||
it 'returns nil' do
|
||||
expect(subject).to be_nil
|
||||
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")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -26,8 +27,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do
|
|||
let!(:deployment) { create(:deployment, environment: staging, deployable: build) }
|
||||
|
||||
context 'without actions' do
|
||||
it 'returns nil' do
|
||||
expect(subject).to be_nil
|
||||
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")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -37,8 +39,8 @@ describe Gitlab::ChatCommands::Deploy, service: true do
|
|||
end
|
||||
|
||||
it 'returns success result' do
|
||||
expect(subject.type).to eq(:success)
|
||||
expect(subject.message).to include('Deployment from staging to production started')
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
expect(subject[:text]).to start_with('Deployment started from staging to production')
|
||||
end
|
||||
|
||||
context 'when duplicate action exists' do
|
||||
|
@ -47,8 +49,8 @@ describe Gitlab::ChatCommands::Deploy, service: true do
|
|||
end
|
||||
|
||||
it 'returns error' do
|
||||
expect(subject.type).to eq(:error)
|
||||
expect(subject.message).to include('Too many actions defined')
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
expect(subject[:text]).to eq('Too many actions defined')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -59,9 +61,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do
|
|||
name: 'teardown', environment: 'production')
|
||||
end
|
||||
|
||||
it 'returns success result' do
|
||||
expect(subject.type).to eq(:success)
|
||||
expect(subject.message).to include('Deployment from staging to production started')
|
||||
it 'returns the success message' do
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
expect(subject[:text]).to start_with('Deployment started from staging to production')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
|
|||
it 'creates the issue' do
|
||||
expect { subject }.to change { project.issues.count }.by(1)
|
||||
|
||||
expect(subject.title).to eq('bird is the word')
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -41,6 +41,16 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
|
|||
expect { subject }.to change { project.issues.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'issue cannot be created' do
|
||||
let!(:issue) { create(:issue, project: project, title: 'bird is the word') }
|
||||
let(:regex_match) { described_class.match("issue create #{'a' * 512}}") }
|
||||
|
||||
it 'displays the errors' do
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
expect(subject[:text]).to match("- Title is too long")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.match' do
|
||||
|
|
|
@ -2,9 +2,9 @@ require 'spec_helper'
|
|||
|
||||
describe Gitlab::ChatCommands::IssueSearch, service: true do
|
||||
describe '#execute' do
|
||||
let!(:issue) { create(:issue, title: 'find me') }
|
||||
let!(:issue) { create(:issue, project: project, title: 'find me') }
|
||||
let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') }
|
||||
let(:project) { issue.project }
|
||||
let(:project) { create(:empty_project) }
|
||||
let(:user) { issue.author }
|
||||
let(:regex_match) { described_class.match("issue search find") }
|
||||
|
||||
|
@ -14,7 +14,8 @@ describe Gitlab::ChatCommands::IssueSearch, service: true do
|
|||
|
||||
context 'when the user has no access' do
|
||||
it 'only returns the open issues' do
|
||||
expect(subject).not_to include(confidential)
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
expect(subject[:text]).to match("not found")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -24,13 +25,14 @@ describe Gitlab::ChatCommands::IssueSearch, service: true do
|
|||
end
|
||||
|
||||
it 'returns all results' do
|
||||
expect(subject).to include(confidential, issue)
|
||||
expect(subject).to have_key(:attachments)
|
||||
expect(subject[:text]).to match("Here are the issues I found:")
|
||||
end
|
||||
end
|
||||
|
||||
context 'without hits on the query' do
|
||||
it 'returns an empty collection' do
|
||||
expect(subject).to be_empty
|
||||
expect(subject[:text]).to match("not found")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,8 +2,8 @@ require 'spec_helper'
|
|||
|
||||
describe Gitlab::ChatCommands::IssueShow, service: true do
|
||||
describe '#execute' do
|
||||
let(:issue) { create(:issue) }
|
||||
let(:project) { issue.project }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
let(:project) { create(:empty_project) }
|
||||
let(:user) { issue.author }
|
||||
let(:regex_match) { described_class.match("issue show #{issue.iid}") }
|
||||
|
||||
|
@ -16,15 +16,19 @@ describe Gitlab::ChatCommands::IssueShow, service: true do
|
|||
end
|
||||
|
||||
context 'the issue exists' do
|
||||
let(:title) { subject[:attachments].first[:title] }
|
||||
|
||||
it 'returns the issue' do
|
||||
expect(subject.iid).to be issue.iid
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
expect(title).to eq(issue.title)
|
||||
end
|
||||
|
||||
context 'when its reference is given' do
|
||||
let(:regex_match) { described_class.match("issue show #{issue.to_reference}") }
|
||||
|
||||
it 'shows the issue' do
|
||||
expect(subject.iid).to be issue.iid
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
expect(title).to eq(issue.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -32,17 +36,24 @@ describe Gitlab::ChatCommands::IssueShow, service: true do
|
|||
context 'the issue does not exist' do
|
||||
let(:regex_match) { described_class.match("issue show 2343242") }
|
||||
|
||||
it "returns nil" do
|
||||
expect(subject).to be_nil
|
||||
it "returns not found" do
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
expect(subject[:text]).to match("not found")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'self.match' do
|
||||
describe '.match' do
|
||||
it 'matches the iid' do
|
||||
match = described_class.match("issue show 123")
|
||||
|
||||
expect(match[:iid]).to eq("123")
|
||||
end
|
||||
|
||||
it 'accepts a reference' do
|
||||
match = described_class.match("issue show #{Issue.reference_prefix}123")
|
||||
|
||||
expect(match[:iid]).to eq("123")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
49
spec/lib/gitlab/chat_commands/presenters/access_spec.rb
Normal file
49
spec/lib/gitlab/chat_commands/presenters/access_spec.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::ChatCommands::Presenters::Access do
|
||||
describe '#access_denied' do
|
||||
subject { described_class.new.access_denied }
|
||||
|
||||
it { is_expected.to be_a(Hash) }
|
||||
|
||||
it 'displays an error message' do
|
||||
expect(subject[:text]).to match("is not allowed")
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#not_found' do
|
||||
subject { described_class.new.not_found }
|
||||
|
||||
it { is_expected.to be_a(Hash) }
|
||||
|
||||
it 'tells the user the resource was not found' do
|
||||
expect(subject[:text]).to match("not found!")
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#authorize' do
|
||||
context 'with an authorization URL' do
|
||||
subject { described_class.new('http://authorize.me').authorize }
|
||||
|
||||
it { is_expected.to be_a(Hash) }
|
||||
|
||||
it 'tells the user to authorize' do
|
||||
expect(subject[:text]).to match("connect your GitLab account")
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without authorization url' do
|
||||
subject { described_class.new.authorize }
|
||||
|
||||
it { is_expected.to be_a(Hash) }
|
||||
|
||||
it 'tells the user to authorize' do
|
||||
expect(subject[:text]).to match("Couldn't identify you")
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
47
spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb
Normal file
47
spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::ChatCommands::Presenters::Deploy do
|
||||
let(:build) { create(:ci_build) }
|
||||
|
||||
describe '#present' do
|
||||
subject { described_class.new(build).present('staging', 'prod') }
|
||||
|
||||
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 'messages the channel of the deploy' do
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
expect(subject[:text]).to start_with("Deployment started from staging to prod")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#no_actions' do
|
||||
subject { described_class.new(nil).no_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("No action found to be executed")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#too_many_actions' do
|
||||
subject { described_class.new(nil).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")
|
||||
end
|
||||
end
|
||||
end
|
24
spec/lib/gitlab/chat_commands/presenters/list_issues_spec.rb
Normal file
24
spec/lib/gitlab/chat_commands/presenters/list_issues_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::ChatCommands::Presenters::ListIssues do
|
||||
let(:project) { create(:empty_project) }
|
||||
let(:message) { subject[:text] }
|
||||
let(:issue) { project.issues.first }
|
||||
|
||||
before { create_list(:issue, 2, project: project) }
|
||||
|
||||
subject { described_class.new(project.issues).present }
|
||||
|
||||
it do
|
||||
is_expected.to have_key(:text)
|
||||
is_expected.to have_key(:status)
|
||||
is_expected.to have_key(:response_type)
|
||||
is_expected.to have_key(:attachments)
|
||||
end
|
||||
|
||||
it 'shows a list of results' do
|
||||
expect(subject[:response_type]).to be(:ephemeral)
|
||||
|
||||
expect(message).to start_with("Here are the issues I found")
|
||||
end
|
||||
end
|
27
spec/lib/gitlab/chat_commands/presenters/show_issue_spec.rb
Normal file
27
spec/lib/gitlab/chat_commands/presenters/show_issue_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::ChatCommands::Presenters::ShowIssue do
|
||||
let(:project) { create(:empty_project) }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
let(:attachment) { subject[:attachments].first }
|
||||
|
||||
subject { described_class.new(issue).present }
|
||||
|
||||
it { is_expected.to be_a(Hash) }
|
||||
|
||||
it 'shows the issue' do
|
||||
expect(subject[:response_type]).to be(:in_channel)
|
||||
expect(subject).to have_key(:attachments)
|
||||
expect(attachment[:title]).to eq(issue.title)
|
||||
end
|
||||
|
||||
context 'with upvotes' do
|
||||
before do
|
||||
create(:award_emoji, :upvote, awardable: issue)
|
||||
end
|
||||
|
||||
it 'shows the upvote count' do
|
||||
expect(attachment[:text]).to start_with(":+1: 1")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mattermost::Client do
|
||||
let(:user) { build(:user) }
|
||||
|
||||
subject { described_class.new(user) }
|
||||
|
||||
context 'JSON parse error' do
|
||||
before do
|
||||
Struct.new("Request", :body, :success?)
|
||||
end
|
||||
|
||||
it 'yields an error on malformed JSON' do
|
||||
bad_json = Struct::Request.new("I'm not json", true)
|
||||
expect { subject.send(:json_response, bad_json) }.to raise_error(Mattermost::ClientError)
|
||||
end
|
||||
|
||||
it 'shows a client error if the request was unsuccessful' do
|
||||
bad_request = Struct::Request.new("true", false)
|
||||
|
||||
expect { subject.send(:json_response, bad_request) }.to raise_error(Mattermost::ClientError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,61 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mattermost::Command do
|
||||
let(:params) { { 'token' => 'token', team_id: 'abc' } }
|
||||
|
||||
before do
|
||||
Mattermost::Session.base_uri('http://mattermost.example.com')
|
||||
|
||||
allow_any_instance_of(Mattermost::Client).to receive(:with_session).
|
||||
and_yield(Mattermost::Session.new(nil))
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
let(:params) do
|
||||
{ team_id: 'abc',
|
||||
trigger: 'gitlab'
|
||||
}
|
||||
end
|
||||
|
||||
subject { described_class.new(nil).create(params) }
|
||||
|
||||
context 'for valid trigger word' do
|
||||
before do
|
||||
stub_request(:post, 'http://mattermost.example.com/api/v3/teams/abc/commands/create').
|
||||
with(body: {
|
||||
team_id: 'abc',
|
||||
trigger: 'gitlab' }.to_json).
|
||||
to_return(
|
||||
status: 200,
|
||||
headers: { 'Content-Type' => 'application/json' },
|
||||
body: { token: 'token' }.to_json
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns a token' do
|
||||
is_expected.to eq('token')
|
||||
end
|
||||
end
|
||||
|
||||
context 'for error message' do
|
||||
before do
|
||||
stub_request(:post, 'http://mattermost.example.com/api/v3/teams/abc/commands/create').
|
||||
to_return(
|
||||
status: 500,
|
||||
headers: { 'Content-Type' => 'application/json' },
|
||||
body: {
|
||||
id: 'api.command.duplicate_trigger.app_error',
|
||||
message: 'This trigger word is already in use. Please choose another word.',
|
||||
detailed_error: '',
|
||||
request_id: 'obc374man7bx5r3dbc1q5qhf3r',
|
||||
status_code: 500
|
||||
}.to_json
|
||||
)
|
||||
end
|
||||
|
||||
it 'raises an error with message' do
|
||||
expect { subject }.to raise_error(Mattermost::Error, 'This trigger word is already in use. Please choose another word.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,123 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mattermost::Session, type: :request do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
let(:gitlab_url) { "http://gitlab.com" }
|
||||
let(:mattermost_url) { "http://mattermost.com" }
|
||||
|
||||
subject { described_class.new(user) }
|
||||
|
||||
# Needed for doorkeeper to function
|
||||
it { is_expected.to respond_to(:current_resource_owner) }
|
||||
it { is_expected.to respond_to(:request) }
|
||||
it { is_expected.to respond_to(:authorization) }
|
||||
it { is_expected.to respond_to(:strategy) }
|
||||
|
||||
before do
|
||||
described_class.base_uri(mattermost_url)
|
||||
end
|
||||
|
||||
describe '#with session' do
|
||||
let(:location) { 'http://location.tld' }
|
||||
let!(:stub) do
|
||||
WebMock.stub_request(:get, "#{mattermost_url}/api/v3/oauth/gitlab/login").
|
||||
to_return(headers: { 'location' => location }, status: 307)
|
||||
end
|
||||
|
||||
context 'without oauth uri' do
|
||||
it 'makes a request to the oauth uri' do
|
||||
expect { subject.with_session }.to raise_error(Mattermost::NoSessionError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with oauth_uri' do
|
||||
let!(:doorkeeper) do
|
||||
Doorkeeper::Application.create(
|
||||
name: "GitLab Mattermost",
|
||||
redirect_uri: "#{mattermost_url}/signup/gitlab/complete\n#{mattermost_url}/login/gitlab/complete",
|
||||
scopes: "")
|
||||
end
|
||||
|
||||
context 'without token_uri' do
|
||||
it 'can not create a session' do
|
||||
expect do
|
||||
subject.with_session
|
||||
end.to raise_error(Mattermost::NoSessionError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with token_uri' do
|
||||
let(:state) { "state" }
|
||||
let(:params) do
|
||||
{ response_type: "code",
|
||||
client_id: doorkeeper.uid,
|
||||
redirect_uri: "#{mattermost_url}/signup/gitlab/complete",
|
||||
state: state }
|
||||
end
|
||||
let(:location) do
|
||||
"#{gitlab_url}/oauth/authorize?#{URI.encode_www_form(params)}"
|
||||
end
|
||||
|
||||
before do
|
||||
WebMock.stub_request(:get, "#{mattermost_url}/signup/gitlab/complete").
|
||||
with(query: hash_including({ 'state' => state })).
|
||||
to_return do |request|
|
||||
post "/oauth/token",
|
||||
client_id: doorkeeper.uid,
|
||||
client_secret: doorkeeper.secret,
|
||||
redirect_uri: params[:redirect_uri],
|
||||
grant_type: 'authorization_code',
|
||||
code: request.uri.query_values['code']
|
||||
|
||||
if response.status == 200
|
||||
{ headers: { 'token' => 'thisworksnow' }, status: 202 }
|
||||
end
|
||||
end
|
||||
|
||||
WebMock.stub_request(:post, "#{mattermost_url}/api/v3/users/logout").
|
||||
to_return(headers: { Authorization: 'token thisworksnow' }, status: 200)
|
||||
end
|
||||
|
||||
it 'can setup a session' do
|
||||
subject.with_session do |session|
|
||||
end
|
||||
|
||||
expect(subject.token).not_to be_nil
|
||||
end
|
||||
|
||||
it 'returns the value of the block' do
|
||||
result = subject.with_session do |session|
|
||||
"value"
|
||||
end
|
||||
|
||||
expect(result).to eq("value")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with lease' do
|
||||
before do
|
||||
allow(subject).to receive(:lease_try_obtain).and_return('aldkfjsldfk')
|
||||
end
|
||||
|
||||
it 'tries to obtain a lease' do
|
||||
expect(subject).to receive(:lease_try_obtain)
|
||||
expect(Gitlab::ExclusiveLease).to receive(:cancel)
|
||||
|
||||
# Cannot setup a session, but we should still cancel the lease
|
||||
expect { subject.with_session }.to raise_error(Mattermost::NoSessionError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without lease' do
|
||||
before do
|
||||
allow(subject).to receive(:lease_try_obtain).and_return(nil)
|
||||
end
|
||||
|
||||
it 'returns a NoSessionError error' do
|
||||
expect { subject.with_session }.to raise_error(Mattermost::NoSessionError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,66 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mattermost::Team do
|
||||
before do
|
||||
Mattermost::Session.base_uri('http://mattermost.example.com')
|
||||
|
||||
allow_any_instance_of(Mattermost::Client).to receive(:with_session).
|
||||
and_yield(Mattermost::Session.new(nil))
|
||||
end
|
||||
|
||||
describe '#all' do
|
||||
subject { described_class.new(nil).all }
|
||||
|
||||
context 'for valid request' do
|
||||
let(:response) do
|
||||
[{
|
||||
"id" => "xiyro8huptfhdndadpz8r3wnbo",
|
||||
"create_at" => 1482174222155,
|
||||
"update_at" => 1482174222155,
|
||||
"delete_at" => 0,
|
||||
"display_name" => "chatops",
|
||||
"name" => "chatops",
|
||||
"email" => "admin@example.com",
|
||||
"type" => "O",
|
||||
"company_name" => "",
|
||||
"allowed_domains" => "",
|
||||
"invite_id" => "o4utakb9jtb7imctdfzbf9r5ro",
|
||||
"allow_open_invite" => false }]
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:get, 'http://mattermost.example.com/api/v3/teams/all').
|
||||
to_return(
|
||||
status: 200,
|
||||
headers: { 'Content-Type' => 'application/json' },
|
||||
body: response.to_json
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns a token' do
|
||||
is_expected.to eq(response)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for error message' do
|
||||
before do
|
||||
stub_request(:get, 'http://mattermost.example.com/api/v3/teams/all').
|
||||
to_return(
|
||||
status: 500,
|
||||
headers: { 'Content-Type' => 'application/json' },
|
||||
body: {
|
||||
id: 'api.team.list.app_error',
|
||||
message: 'Cannot list teams.',
|
||||
detailed_error: '',
|
||||
request_id: 'obc374man7bx5r3dbc1q5qhf3r',
|
||||
status_code: 500
|
||||
}.to_json
|
||||
)
|
||||
end
|
||||
|
||||
it 'raises an error with message' do
|
||||
expect { subject }.to raise_error(Mattermost::Error, 'Cannot list teams.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue