Commit 7d465e21 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Add "issue comment" Slack command

Introduces a Slack slash command to add a comment to an issue

https://gitlab.com/gitlab-org/gitlab/issues/30822
parent 8262749a
......@@ -10,6 +10,7 @@ module Gitlab
Gitlab::SlashCommands::IssueSearch,
Gitlab::SlashCommands::IssueMove,
Gitlab::SlashCommands::IssueClose,
Gitlab::SlashCommands::IssueComment,
Gitlab::SlashCommands::Deploy,
Gitlab::SlashCommands::Run
]
......
# frozen_string_literal: true
module Gitlab
module SlashCommands
class IssueComment < IssueCommand
def self.match(text)
/\Aissue\s+comment\s+#{Issue.reference_prefix}?(?<iid>\d+)\n*(?<note_body>(.|\n)*)/.match(text)
end
def self.help_message
'issue comment <id> *`⇧ Shift`*+*`↵ Enter`* <comment>'
end
def execute(match)
note_body = match[:note_body].to_s.strip
issue = find_by_iid(match[:iid])
return not_found unless issue
note = create_note(issue: issue, note: note_body)
if note.persisted?
presenter(note).present
else
presenter(note).display_errors
end
end
private
def not_found
Gitlab::SlashCommands::Presenters::Access.new.not_found
end
def create_note(issue:, note:)
note_params = { noteable: issue, note: note }
Notes::CreateService.new(project, current_user, note_params).execute
end
def presenter(note)
Gitlab::SlashCommands::Presenters::IssueComment.new(note)
end
end
end
end
# frozen_string_literal: true
module Gitlab
module SlashCommands
module Presenters
class IssueComment < Presenters::Base
include Presenters::NoteBase
def present
ephemeral_response(new_note)
end
private
def new_note
{
attachments: [
{
title: "#{issue.title} · #{issue.to_reference}",
title_link: resource_url,
author_name: author.name,
author_icon: author.avatar_url,
fallback: "New comment on #{issue.to_reference}: #{issue.title}",
pretext: pretext,
color: color,
fields: fields,
mrkdwn_in: [
:title,
:pretext,
:text,
:fields
]
}
]
}
end
def pretext
"I commented on an issue on #{author_profile_link}'s behalf: *#{issue.to_reference}* in #{project_link}"
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module SlashCommands
module Presenters
module NoteBase
GREEN = '#38ae67'
def color
GREEN
end
def issue
resource.noteable
end
def project
issue.project
end
def project_link
"[#{project.full_name}](#{project.web_url})"
end
def author
resource.author
end
def author_profile_link
"[#{author.to_reference}](#{url_for(author)})"
end
def fields
[
{
title: "Comment",
value: resource.note
}
]
end
private
attr_reader :resource
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::SlashCommands::IssueComment do
describe '#execute' do
let(:issue) { create(:issue, project: project) }
let(:project) { create(:project) }
let(:user) { issue.author }
let(:chat_name) { double(:chat_name, user: user) }
let(:regex_match) { described_class.match("issue comment #{issue.iid}\nComment body") }
subject { described_class.new(project, chat_name).execute(regex_match) }
context 'when the issue exists' do
context 'when the user does not have premission' do
let(:chat_name) { double(:chat_name, user: create(:user)) }
it 'does not allow the user to comment' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to match("not found")
expect(issue.reload.notes.count).to be_zero
end
end
context 'when the user can comment on the issue' do
context 'when comment body exists' do
it 'creates a new comment' do
expect { subject }.to change { issue.notes.count }.by(1)
end
end
context 'when comment body does not exist' do
let(:regex_match) { described_class.match("issue comment #{issue.iid}") }
it 'does not create a new comment' do
expect { subject }.not_to change { issue.notes.count }
end
it 'displays the errors' do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to match("- Note can't be blank")
end
end
end
end
context 'the issue does not exist' do
let(:regex_match) { described_class.match("issue comment 2343242\nComment body") }
it "returns not found" do
expect(subject[:response_type]).to be(:ephemeral)
expect(subject[:text]).to match("not found")
end
end
end
describe '.match' do
subject(:match) { described_class.match(command) }
context 'when a command has an issue ID' do
context 'when command has a comment body' do
let(:command) { "issue comment 503\nComment body" }
it 'matches an issue ID' do
expect(match[:iid]).to eq('503')
end
it 'matches an note body' do
expect(match[:note_body]).to eq('Comment body')
end
end
end
context 'when a command has a reference prefix for issue ID' do
let(:command) { "issue comment #503\nComment body" }
it 'matches an issue ID' do
expect(match[:iid]).to eq('503')
end
end
context 'when a command does not have an issue ID' do
let(:command) { 'issue comment' }
it 'does not match' do
is_expected.to be_nil
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::SlashCommands::Presenters::IssueComment do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:note) { create(:note, project: project, noteable: issue) }
let(:author) { note.author }
describe '#present' do
let(:attachment) { subject[:attachments].first }
subject { described_class.new(note).present }
it { is_expected.to be_a(Hash) }
it 'sets ephemeral response type' do
expect(subject[:response_type]).to be(:ephemeral)
end
it 'sets the title' do
expect(attachment[:title]).to eq("#{issue.title} · #{issue.to_reference}")
end
it 'sets the fallback text' do
expect(attachment[:fallback]).to eq("New comment on #{issue.to_reference}: #{issue.title}")
end
it 'sets the fields' do
expect(attachment[:fields]).to eq([{ title: 'Comment', value: note.note }])
end
it 'sets the color' do
expect(attachment[:color]).to eq('#38ae67')
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