gitlab-org--gitlab-foss/lib/gitlab/fogbugz_import/importer.rb

305 lines
8.1 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module FogbugzImport
class Importer
attr_reader :project, :repo
def initialize(project)
@project = project
import_data = project.import_data.try(:data)
repo_data = import_data['repo'] if import_data
if repo_data
@repo = FogbugzImport::Repository.new(repo_data)
@known_labels = Set.new
else
raise Projects::ImportService::Error, "Unable to find project import data credentials for project ID: #{@project.id}"
end
end
def execute
return true unless repo.valid?
client = Gitlab::FogbugzImport::Client.new(token: fb_session[:token], uri: fb_session[:uri])
@cases = client.cases(@repo.id.to_i)
@categories = client.categories
import_cases
true
end
private
def fb_session
@import_data_credentials ||= project.import_data.credentials[:fb_session] if project.import_data && project.import_data.credentials
end
def user_map
@user_map ||= begin
user_map = {}
import_data = project.import_data.try(:data)
stored_user_map = import_data['user_map'] if import_data
user_map.update(stored_user_map) if stored_user_map
user_map
end
end
def import_labels
@categories['categories']['category'].each do |label|
create_label(label['sCategory'])
@known_labels << name
end
end
def nice_label_color(name)
case name
when 'Blocker'
'#ff0000'
when 'Crash'
'#ffcfcf'
when 'Major'
'#deffcf'
when 'Minor'
'#cfe9ff'
when 'Bug'
'#d9534f'
when 'Feature'
'#44ad8e'
when 'Technical Task'
'#4b6dd0'
else
'#e2e2e2'
end
end
def create_label(name)
params = { title: name, color: nice_label_color(name) }
::Labels::FindOrCreateService.new(nil, project, params).execute(skip_authorization: true)
end
# rubocop: disable CodeReuse/ActiveRecord
def user_info(person_id)
user_hash = user_map[person_id.to_s]
user_name = ''
gitlab_id = nil
unless user_hash.nil?
user_name = user_hash['name']
if user = User.find_by(id: user_hash['gitlab_user'])
user_name = "@#{user.username}"
gitlab_id = user.id
end
end
{ name: user_name, gitlab_id: gitlab_id }
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def import_cases
return unless @cases
while bug = @cases.shift
author = user_info(bug['ixPersonOpenedBy'])[:name]
date = DateTime.parse(bug['dtOpened'])
comments = bug['events']['event']
content = format_content(opened_content(comments))
body = format_issue_body(author, date, content)
labels = []
[bug['sCategory'], bug['sPriority']].each do |label|
unless label.blank?
labels << label
unless @known_labels.include?(label)
create_label(label)
@known_labels << label
end
end
end
assignee_id = user_info(bug['ixPersonAssignedTo'])[:gitlab_id]
author_id = user_info(bug['ixPersonOpenedBy'])[:gitlab_id] || project.creator_id
issue = Issue.create!(
iid: bug['ixBug'],
project_id: project.id,
title: bug['sTitle'],
description: body,
author_id: author_id,
assignee_ids: [assignee_id],
state: bug['fOpen'] == 'true' ? 'opened' : 'closed',
created_at: date,
updated_at: DateTime.parse(bug['dtLastUpdated'])
)
issue_labels = ::LabelsFinder.new(nil, project_id: project.id, title: labels).execute(skip_authorization: true)
issue.update_attribute(:label_ids, issue_labels.pluck(:id))
import_issue_comments(issue, comments)
end
end
# rubocop: enable CodeReuse/ActiveRecord
def opened_content(comments)
while comment = comments.shift
if comment['sVerb'] == 'Opened'
return comment['s']
end
end
''
end
def import_issue_comments(issue, comments)
Note.transaction do
while comment = comments.shift
verb = comment['sVerb']
next if verb == 'Opened'
content = format_content(comment['s'])
attachments = format_attachments(comment['rgAttachments'])
updates = format_updates(comment)
next if content.blank? && attachments.empty? && updates.empty?
author = user_info(comment['ixPerson'])[:name]
author_id = user_info(comment['ixPerson'])[:gitlab_id] || project.creator_id
date = DateTime.parse(comment['dt'])
body = format_issue_comment_body(
comment['ixBugEvent'],
author,
date,
content,
attachments,
updates
)
note = Note.create!(
project_id: project.id,
noteable_type: "Issue",
noteable_id: issue.id,
author_id: author_id,
note: body
)
note.update_attribute(:created_at, date)
note.update_attribute(:updated_at, date)
end
end
end
def linkify_issues(str)
str = str.gsub(/([Ii]ssue) ([0-9]+)/, '\1 #\2')
str.gsub(/([Cc]ase) ([0-9]+)/, '\1 #\2')
end
def escape_for_markdown(str)
str = str.gsub(/^#/, "\\#")
str = str.gsub(/^-/, "\\-")
str = str.gsub("`", "\\~")
str = str.delete("\r")
str.gsub("\n", " \n")
end
def format_content(raw_content)
return raw_content if raw_content.nil?
linkify_issues(escape_for_markdown(raw_content))
end
def format_attachments(raw_attachments)
return [] unless raw_attachments
attachments = case raw_attachments['attachment']
when Array
raw_attachments['attachment']
when Hash
[raw_attachments['attachment']]
else
[]
end
attachments.map! { |a| format_attachment(a) }
attachments.compact
end
def format_attachment(attachment)
link = build_attachment_url(attachment['sURL'])
res = ::Projects::DownloadService.new(project, link).execute
return if res.nil?
res[:markdown]
end
def build_attachment_url(rel_url)
uri = fb_session[:uri]
token = fb_session[:token]
"#{uri}/#{rel_url}&token=#{token}"
end
def format_updates(comment)
updates = []
if comment['sChanges']
updates << "*Changes: #{linkify_issues(comment['sChanges'].chomp)}*"
end
if comment['evtDescription']
updates << "*#{comment['evtDescription']}*"
end
updates
end
def format_issue_body(author, date, content)
body = []
body << "*By #{author} on #{date} (imported from FogBugz)*"
body << '---'
if content.blank?
content = '*(No description has been entered for this issue)*'
end
body << content
body.join("\n\n")
end
def format_issue_comment_body(id, author, date, content, attachments, updates)
body = []
body << "*By #{author} on #{date} (imported from FogBugz)*"
body << '---'
if content.blank?
content = "*(No comment has been entered for this change)*"
end
body << content
if updates.any?
body << '---'
body += updates
end
if attachments.any?
body << '---'
body += attachments
end
body.join("\n\n")
end
end
end
end