Commit 8abaf9a8 authored by Alexandru Croitor's avatar Alexandru Croitor

Mark Jira imported issues with a auto-generated label

When jira issues are imported we would want to label them
with a known label so that it is easy to identify the newly
imported issues when the import is finished.
parent 00c62397
...@@ -159,6 +159,11 @@ class Label < ApplicationRecord ...@@ -159,6 +159,11 @@ class Label < ApplicationRecord
on_project_boards(project_id).where(id: label_id).exists? on_project_boards(project_id).where(id: label_id).exists?
end end
# Generate a hex color based on hex-encoded value
def self.color_for(value)
"##{Digest::MD5.hexdigest(value)[0..5]}"
end
def open_issues_count(user = nil) def open_issues_count(user = nil)
issues_count(user, state: 'opened') issues_count(user, state: 'opened')
end end
......
...@@ -9,8 +9,8 @@ module Gitlab ...@@ -9,8 +9,8 @@ module Gitlab
include Gitlab::Import::DatabaseHelpers include Gitlab::Import::DatabaseHelpers
def perform(project_id, jira_issue_id, issue_attributes, waiter_key) def perform(project_id, jira_issue_id, issue_attributes, waiter_key)
issue_id = insert_and_return_id(issue_attributes, Issue) issue_id = create_issue(issue_attributes, project_id)
cache_issue_mapping(issue_id, jira_issue_id, project_id) JiraImport.cache_issue_mapping(issue_id, jira_issue_id, project_id)
rescue => ex rescue => ex
# Todo: Record jira issue id(or better jira issue key), # Todo: Record jira issue id(or better jira issue key),
# so that we can report the list of failed to import issues to the user # so that we can report the list of failed to import issues to the user
...@@ -27,9 +27,31 @@ module Gitlab ...@@ -27,9 +27,31 @@ module Gitlab
private private
def cache_issue_mapping(issue_id, jira_issue_id, project_id) def create_issue(issue_attributes, project_id)
cache_key = JiraImport.jira_issue_cache_key(project_id, jira_issue_id) issue_id = insert_and_return_id(issue_attributes, Issue)
Gitlab::Cache::Import::Caching.write(cache_key, issue_id)
label_issue(project_id, issue_id)
issue_id
end
def label_issue(project_id, issue_id)
label_id = JiraImport.get_import_label_id(project_id)
return unless label_id
label_link_attrs = build_label_attrs(issue_id, label_id.to_i)
insert_and_return_id(label_link_attrs, LabelLink)
end
def build_label_attrs(issue_id, label_id)
time = Time.now
{
label_id: label_id,
target_id: issue_id,
target_type: 'Issue',
created_at: time,
updated_at: time
}
end end
end end
end end
......
...@@ -9,10 +9,8 @@ module Gitlab ...@@ -9,10 +9,8 @@ module Gitlab
private private
def import(project) def import(project)
# fake labels import workers for now job_waiter = Gitlab::JiraImport::LabelsImporter.new(project).execute
# new job waiter will have zero jobs_remaining by default, so it will just pass on to next stage Gitlab::JiraImport::AdvanceStageWorker.perform_async(project.id, { job_waiter.key => job_waiter.jobs_remaining }, :issues)
fake_waiter = JobWaiter.new
Gitlab::JiraImport::AdvanceStageWorker.perform_async(project.id, { fake_waiter.key => fake_waiter.jobs_remaining }, :issues)
end end
end end
end end
......
...@@ -6,6 +6,7 @@ module Gitlab ...@@ -6,6 +6,7 @@ module Gitlab
FAILED_ISSUES_COUNTER_KEY = 'jira-import/failed/%{project_id}/%{collection_type}' FAILED_ISSUES_COUNTER_KEY = 'jira-import/failed/%{project_id}/%{collection_type}'
NEXT_ITEMS_START_AT_KEY = 'jira-import/paginator/%{project_id}/%{collection_type}' NEXT_ITEMS_START_AT_KEY = 'jira-import/paginator/%{project_id}/%{collection_type}'
JIRA_IMPORT_LABEL = 'jira-import/import-label/%{project_id}'
ITEMS_MAPPER_CACHE_KEY = 'jira-import/items-mapper/%{project_id}/%{collection_type}/%{jira_isssue_id}' ITEMS_MAPPER_CACHE_KEY = 'jira-import/items-mapper/%{project_id}/%{collection_type}/%{jira_isssue_id}'
ALREADY_IMPORTED_ITEMS_CACHE_KEY = 'jira-importer/already-imported/%{project}/%{collection_type}' ALREADY_IMPORTED_ITEMS_CACHE_KEY = 'jira-importer/already-imported/%{project}/%{collection_type}'
...@@ -25,23 +26,45 @@ module Gitlab ...@@ -25,23 +26,45 @@ module Gitlab
FAILED_ISSUES_COUNTER_KEY % { project_id: project_id, collection_type: :issues } FAILED_ISSUES_COUNTER_KEY % { project_id: project_id, collection_type: :issues }
end end
def self.import_label_cache_key(project_id)
JIRA_IMPORT_LABEL % { project_id: project_id }
end
def self.increment_issue_failures(project_id) def self.increment_issue_failures(project_id)
Gitlab::Cache::Import::Caching.increment(self.failed_issues_counter_cache_key(project_id)) cache_class.increment(self.failed_issues_counter_cache_key(project_id))
end end
def self.get_issues_next_start_at(project_id) def self.get_issues_next_start_at(project_id)
Gitlab::Cache::Import::Caching.read(self.jira_issues_next_page_cache_key(project_id)).to_i cache_class.read(self.jira_issues_next_page_cache_key(project_id)).to_i
end end
def self.store_issues_next_started_at(project_id, value) def self.store_issues_next_started_at(project_id, value)
cache_key = self.jira_issues_next_page_cache_key(project_id) cache_key = self.jira_issues_next_page_cache_key(project_id)
Gitlab::Cache::Import::Caching.write(cache_key, value) cache_class.write(cache_key, value)
end
def self.cache_issue_mapping(issue_id, jira_issue_id, project_id)
cache_key = JiraImport.jira_issue_cache_key(project_id, jira_issue_id)
cache_class.write(cache_key, issue_id)
end
def self.get_import_label_id(project_id)
cache_class.read(JiraImport.import_label_cache_key(project_id))
end
def self.cache_import_label_id(project_id, label_id)
cache_class.write(JiraImport.import_label_cache_key(project_id), label_id)
end end
def self.cache_cleanup(project_id) def self.cache_cleanup(project_id)
Gitlab::Cache::Import::Caching.expire(self.failed_issues_counter_cache_key(project_id), JIRA_IMPORT_CACHE_TIMEOUT) cache_class.expire(self.import_label_cache_key(project_id), JIRA_IMPORT_CACHE_TIMEOUT)
Gitlab::Cache::Import::Caching.expire(self.jira_issues_next_page_cache_key(project_id), JIRA_IMPORT_CACHE_TIMEOUT) cache_class.expire(self.failed_issues_counter_cache_key(project_id), JIRA_IMPORT_CACHE_TIMEOUT)
Gitlab::Cache::Import::Caching.expire(self.already_imported_cache_key(:issues, project_id), JIRA_IMPORT_CACHE_TIMEOUT) cache_class.expire(self.jira_issues_next_page_cache_key(project_id), JIRA_IMPORT_CACHE_TIMEOUT)
cache_class.expire(self.already_imported_cache_key(:issues, project_id), JIRA_IMPORT_CACHE_TIMEOUT)
end
def self.cache_class
Gitlab::Cache::Import::Caching
end end
end end
end end
# frozen_string_literal: true
module Gitlab
module JiraImport
class LabelsImporter < BaseImporter
attr_reader :job_waiter
def initialize(project)
super
@job_waiter = JobWaiter.new
end
def execute
create_import_label(project)
import_jira_labels
end
private
def create_import_label(project)
label = Labels::CreateService.new(build_label_attrs(project)).execute(project: project)
raise Projects::ImportService::Error, _('Failed to create import label for jira import.') unless label
JiraImport.cache_import_label_id(project.id, label.id)
end
def build_label_attrs(project)
import_start_time = project&.import_state&.last_update_started_at || Time.now
title = "jira-import-#{import_start_time.strftime('%Y-%m-%d-%H-%M-%S')}"
description = "Label for issues that were imported from jira on #{import_start_time.strftime('%Y-%m-%d %H:%M:%S')}"
color = "#{Label.color_for(title)}"
{ title: title, description: description, color: color }
end
def import_jira_labels
# todo: import jira labels, see https://gitlab.com/gitlab-org/gitlab/-/issues/212651
job_waiter
end
end
end
end
...@@ -8481,6 +8481,9 @@ msgstr "" ...@@ -8481,6 +8481,9 @@ msgstr ""
msgid "Failed to create a branch for this issue. Please try again." msgid "Failed to create a branch for this issue. Please try again."
msgstr "" msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
msgid "Failed to create repository" msgid "Failed to create repository"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::JiraImport::LabelsImporter do
let(:user) { create(:user) }
let(:jira_import_data) do
data = JiraImportData.new
data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name })
data
end
let(:project) { create(:project, import_data: jira_import_data) }
let!(:jira_service) { create(:jira_service, project: project) }
subject { described_class.new(project).execute }
before do
stub_feature_flags(jira_issue_import: true)
end
describe '#execute', :clean_gitlab_redis_cache do
context 'when label creation failes' do
before do
allow_next_instance_of(Labels::CreateService) do |instance|
allow(instance).to receive(:execute).and_return(nil)
end
end
it 'raises error' do
expect { subject }.to raise_error(Projects::ImportService::Error, 'Failed to create import label for jira import.')
end
end
context 'when label is created successfully' do
it 'creates import label' do
expect { subject }.to change { Label.count }.by(1)
end
it 'caches import label' do
expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.import_label_cache_key(project.id))).to be nil
subject
expect(Gitlab::JiraImport.get_import_label_id(project.id).to_i).to be > 0
end
end
end
end
...@@ -32,12 +32,28 @@ describe Gitlab::JiraImport::ImportIssueWorker do ...@@ -32,12 +32,28 @@ describe Gitlab::JiraImport::ImportIssueWorker do
end end
context 'when record is successfully inserted' do context 'when record is successfully inserted' do
before do let(:label) { create(:label, project: project) }
subject.perform(project.id, 123, issue_attrs, 'some-key')
context 'when import label does not exist' do
it 'does not record import failure' do
subject.perform(project.id, 123, issue_attrs, 'some-key')
expect(label.issues.count).to eq(0)
expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0)
end
end end
it 'does not record import failure' do context 'when import label exists' do
expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0) before do
Gitlab::JiraImport.cache_import_label_id(project.id, label.id)
end
it 'does not record import failure' do
subject.perform(project.id, 123, issue_attrs, 'some-key')
expect(label.issues.count).to eq(1)
expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0)
end
end end
end end
end end
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::JiraImport::Stage::ImportLabelsWorker do describe Gitlab::JiraImport::Stage::ImportLabelsWorker do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
describe 'modules' do describe 'modules' do
...@@ -30,9 +31,24 @@ describe Gitlab::JiraImport::Stage::ImportLabelsWorker do ...@@ -30,9 +31,24 @@ describe Gitlab::JiraImport::Stage::ImportLabelsWorker do
end end
context 'when import started' do context 'when import started' do
let(:jira_import_data) do
data = JiraImportData.new
data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name })
data
end
let(:project) { create(:project, import_data: jira_import_data) }
let!(:jira_service) { create(:jira_service, project: project) }
let!(:import_state) { create(:import_state, status: :started, project: project) } let!(:import_state) { create(:import_state, status: :started, project: project) }
it_behaves_like 'advance to next stage', :issues it_behaves_like 'advance to next stage', :issues
it 'executes labels importer' do
expect_next_instance_of(Gitlab::JiraImport::LabelsImporter) do |instance|
expect(instance).to receive(:execute).and_return(Gitlab::JobWaiter.new)
end
described_class.new.perform(project.id)
end
end end
end 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