Commit 1d35ba5f authored by Alexandru Croitor's avatar Alexandru Croitor

Remove jira_issue_import feature flag

Remove jira_issue_import feature flag usages, as it has been
already used as default: true.
parent 1998e450
......@@ -6,7 +6,6 @@ module Projects
before_action :authenticate_user!
before_action :check_issues_available!
before_action :authorize_read_project!
before_action :jira_import_enabled?
before_action :jira_integration_configured?
before_action :authorize_admin_project!, only: [:import]
......@@ -44,12 +43,6 @@ module Projects
private
def jira_import_enabled?
return if @project.jira_issues_import_feature_flag_enabled?
redirect_to project_issues_path(@project)
end
def jira_integration_configured?
return if Feature.enabled?(:jira_issue_import_vue, @project, default_enabled: true)
return if @project.jira_service
......
......@@ -14,8 +14,6 @@ module Resolvers
end
def authorized_resource?(project)
return false unless project.jira_issues_import_feature_flag_enabled?
context[:current_user].present? && Ability.allowed?(context[:current_user], :read_project, project)
end
end
......
......@@ -20,7 +20,7 @@ module Resolvers
end
def authorized_resource?(project)
Feature.enabled?(:jira_issue_import, project) && Ability.allowed?(context[:current_user], :admin_project, project)
Ability.allowed?(context[:current_user], :admin_project, project)
end
private
......
......@@ -808,10 +808,6 @@ class Project < ApplicationRecord
Feature.enabled?(:context_commits, default_enabled: true)
end
def jira_issues_import_feature_flag_enabled?
Feature.enabled?(:jira_issue_import, self, default_enabled: true)
end
# LFS and hashed repository storage are required for using Design Management.
def design_management_enabled?
lfs_enabled? && hashed_storage?(:repository)
......@@ -900,7 +896,6 @@ class Project < ApplicationRecord
end
def validate_jira_import_settings!(user: nil)
raise Projects::ImportService::Error, _('Jira import feature is disabled.') unless jira_issues_import_feature_flag_enabled?
raise Projects::ImportService::Error, _('Jira integration not configured.') unless jira_service&.active?
if user
......@@ -1015,7 +1010,7 @@ class Project < ApplicationRecord
end
def jira_import?
import_type == 'jira' && latest_jira_import.present? && jira_issues_import_feature_flag_enabled?
import_type == 'jira' && latest_jira_import.present?
end
def gitlab_project_import?
......
- type = local_assigns.fetch(:type, :icon)
- if @project.jira_issues_import_feature_flag_enabled?
.dropdown.btn-group
%button.btn.rounded-right.text-center{ class: ('has-tooltip' if type == :icon), title: (_('Import issues') if type == :icon),
data: { toggle: 'dropdown' }, 'aria-label' => _('Import issues'), 'aria-haspopup' => 'true', 'aria-expanded' => 'false' }
- if type == :icon
= sprite_icon('import')
- else
= _('Import issues')
%ul.dropdown-menu
%li
%button.btn{ data: { toggle: 'modal', target: '.issues-import-modal' } }
= _('Import CSV')
%li= link_to _('Import from Jira'), project_import_jira_path(@project)
- else
%button.csv-import-button.btn{ title: _('Import CSV'), class: ('has-tooltip' if type == :icon),
data: { toggle: 'modal', target: '.issues-import-modal' } }
.dropdown.btn-group
%button.btn.rounded-right.text-center{ class: ('has-tooltip' if type == :icon), title: (_('Import issues') if type == :icon),
data: { toggle: 'dropdown' }, 'aria-label' => _('Import issues'), 'aria-haspopup' => 'true', 'aria-expanded' => 'false' }
- if type == :icon
= sprite_icon('import')
- else
= _('Import CSV')
= _('Import issues')
%ul.dropdown-menu
%li
%button.btn{ data: { toggle: 'modal', target: '.issues-import-modal' } }
= _('Import CSV')
%li= link_to _('Import from Jira'), project_import_jira_path(@project)
......@@ -6,11 +6,10 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@project.name} issues")
- if @project.jira_issues_import_feature_flag_enabled?
.js-projects-issues-root{ data: { can_edit: can?(current_user, :admin_project, @project).to_s,
is_jira_configured: @project.jira_service.present?.to_s,
issues_path: project_issues_path(@project),
project_path: @project.full_path } }
.js-projects-issues-root{ data: { can_edit: can?(current_user, :admin_project, @project).to_s,
is_jira_configured: @project.jira_service.present?.to_s,
issues_path: project_issues_path(@project),
project_path: @project.full_path } }
- if project_issues(@project).exists?
.top-area
......
......@@ -27,7 +27,6 @@ module Gitlab
def can_import?(project)
return false unless project
return false unless project.jira_issues_import_feature_flag_enabled?
project.latest_jira_import&.started?
end
......
......@@ -25,7 +25,6 @@ module Gitlab
def start_import
return false unless project
return false unless project.jira_issues_import_feature_flag_enabled?
return true if start(project.latest_jira_import)
Gitlab::Import::Logger.info(
......
......@@ -12174,9 +12174,6 @@ msgstr ""
msgid "Jira Issue Import"
msgstr ""
msgid "Jira import feature is disabled."
msgstr ""
msgid "Jira import is already running."
msgstr ""
......
......@@ -40,16 +40,6 @@ describe Resolvers::Projects::JiraImportsResolver do
let_it_be(:jira_import1) { create(:jira_import_state, :finished, project: project, jira_project_key: 'AA', created_at: 2.days.ago) }
let_it_be(:jira_import2) { create(:jira_import_state, :finished, project: project, jira_project_key: 'BB', created_at: 5.days.ago) }
context 'when feature flag disabled' do
let(:current_user) { user }
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'no Jira import access'
end
context 'when user cannot read Jira imports' do
context 'when anonymous user' do
let(:current_user) { nil }
......
......@@ -8,24 +8,10 @@ describe Gitlab::JiraImport::BaseImporter do
let(:project) { create(:project) }
describe 'with any inheriting class' do
context 'when an error is returned from the project validation' do
before do
stub_feature_flags(jira_issue_import: false)
allow(project).to receive(:validate_jira_import_settings!)
.and_raise(Projects::ImportService::Error, 'Jira import feature is disabled.')
end
it 'raises exception' do
expect { described_class.new(project) }.to raise_error(Projects::ImportService::Error, 'Jira import feature is disabled.')
end
end
context 'when project validation is ok' do
let!(:jira_service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
allow(project).to receive(:validate_jira_import_settings!)
......
......@@ -14,7 +14,6 @@ describe Gitlab::JiraImport::IssuesImporter do
subject { described_class.new(project) }
before do
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
end
......
......@@ -15,7 +15,6 @@ describe Gitlab::JiraImport::LabelsImporter do
subject { importer.execute }
before do
stub_feature_flags(jira_issue_import: true)
stub_const('Gitlab::JiraImport::LabelsImporter::MAX_LABELS', 2)
end
......
......@@ -6053,34 +6053,20 @@ describe Project do
end
shared_examples 'jira configuration base checks' do
context 'when feature flag is disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'raise Jira import error', 'Jira import feature is disabled.'
context 'when Jira service was not setup' do
it_behaves_like 'raise Jira import error', 'Jira integration not configured.'
end
context 'when feature flag is enabled' do
before do
stub_feature_flags(jira_issue_import: true)
end
context 'when Jira service was not setup' do
it_behaves_like 'raise Jira import error', 'Jira integration not configured.'
end
context 'when Jira service exists' do
let!(:jira_service) { create(:jira_service, project: project, active: true) }
context 'when Jira connection is not valid' do
before do
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/serverInfo')
.to_raise(JIRA::HTTPError.new(double(message: 'Some failure.')))
end
context 'when Jira service exists' do
let!(:jira_service) { create(:jira_service, project: project, active: true) }
it_behaves_like 'raise Jira import error', 'Unable to connect to the Jira instance. Please check your Jira integration configuration.'
context 'when Jira connection is not valid' do
before do
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/serverInfo')
.to_raise(JIRA::HTTPError.new(double(message: 'Some failure.')))
end
it_behaves_like 'raise Jira import error', 'Unable to connect to the Jira instance. Please check your Jira integration configuration.'
end
end
end
......@@ -6116,38 +6102,32 @@ describe Project do
it_behaves_like 'jira configuration base checks'
end
context 'when feature flag is enabled' do
context 'when user does not have permissions to run the import' do
before do
stub_feature_flags(jira_issue_import: true)
end
create(:jira_service, project: project, active: true)
context 'when user does not have permissions to run the import' do
before do
create(:jira_service, project: project, active: true)
project.add_developer(user)
end
project.add_developer(user)
end
it_behaves_like 'raise Jira import error', 'You do not have permissions to run the import.'
end
it_behaves_like 'raise Jira import error', 'You do not have permissions to run the import.'
context 'when user has permission to run import' do
before do
project.add_maintainer(user)
end
context 'when user has permission to run import' do
before do
project.add_maintainer(user)
end
let!(:jira_service) { create(:jira_service, project: project, active: true) }
let!(:jira_service) { create(:jira_service, project: project, active: true) }
context 'when issues feature is disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
context 'when issues feature is disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
it_behaves_like 'raise Jira import error', 'Cannot import because issues are not available in this project.'
end
it_behaves_like 'raise Jira import error', 'Cannot import because issues are not available in this project.'
end
context 'when everything is ok' do
it 'does not return any error' do
expect { subject }.not_to raise_error
end
context 'when everything is ok' do
it 'does not return any error' do
expect { subject }.not_to raise_error
end
end
end
......
......@@ -29,10 +29,6 @@ describe 'Starting a Jira Import' do
end
context 'when the user does not have permission' do
before do
stub_feature_flags(jira_issue_import: true)
end
shared_examples 'Jira import does not start' do
it 'does not start the Jira import' do
post_graphql_mutation(mutation, current_user: current_user)
......@@ -83,53 +79,39 @@ describe 'Starting a Jira Import' do
end
end
context 'when feature jira_issue_import feature flag is disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira import feature is disabled.']
context 'when project has no Jira service' do
it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira integration not configured.']
end
context 'when feature jira_issue_import feature flag is enabled' do
context 'when when project has Jira service' do
let!(:service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
end
project.reload
context 'when project has no Jira service' do
it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira integration not configured.']
stub_jira_service_test
end
context 'when when project has Jira service' do
let!(:service) { create(:jira_service, project: project) }
context 'when issues feature are disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
before do
project.reload
stub_jira_service_test
end
context 'when issues feature are disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
it_behaves_like 'a mutation that returns errors in the response', errors: ['Cannot import because issues are not available in this project.']
end
it_behaves_like 'a mutation that returns errors in the response', errors: ['Cannot import because issues are not available in this project.']
end
context 'when jira_project_key not provided' do
let(:jira_project_key) { '' }
context 'when jira_project_key not provided' do
let(:jira_project_key) { '' }
it_behaves_like 'a mutation that returns errors in the response', errors: ['Unable to find Jira project to import data from.']
end
it_behaves_like 'a mutation that returns errors in the response', errors: ['Unable to find Jira project to import data from.']
end
context 'when Jira import successfully scheduled' do
it 'schedules a Jira import' do
post_graphql_mutation(mutation, current_user: current_user)
context 'when Jira import successfully scheduled' do
it 'schedules a Jira import' do
post_graphql_mutation(mutation, current_user: current_user)
expect(jira_import['jiraProjectKey']).to eq 'AA'
expect(jira_import['scheduledBy']['username']).to eq current_user.username
expect(project.latest_jira_import).not_to be_nil
expect(project.latest_jira_import).to be_scheduled
end
expect(jira_import['jiraProjectKey']).to eq 'AA'
expect(jira_import['scheduledBy']['username']).to eq current_user.username
expect(project.latest_jira_import).not_to be_nil
expect(project.latest_jira_import).to be_scheduled
end
end
end
......
......@@ -11,47 +11,33 @@ describe Gitlab::JiraImport::Stage::FinishImportWorker do
end
describe '#perform' do
context 'when feature flag enabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
let_it_be(:import_label) { create(:label, project: project, title: 'jira-import') }
let_it_be(:imported_issues) { create_list(:labeled_issue, 3, project: project, labels: [import_label]) }
before do
stub_feature_flags(jira_issue_import: true)
end
expect(Gitlab::JiraImport).to receive(:get_import_label_id).and_return(import_label.id)
expect(Gitlab::JiraImport).to receive(:issue_failures).and_return(2)
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
jira_import.start!
worker.perform(project.id)
end
context 'when import started' do
let_it_be(:import_label) { create(:label, project: project, title: 'jira-import') }
let_it_be(:imported_issues) { create_list(:labeled_issue, 3, project: project, labels: [import_label]) }
before do
expect(Gitlab::JiraImport).to receive(:get_import_label_id).and_return(import_label.id)
expect(Gitlab::JiraImport).to receive(:issue_failures).and_return(2)
jira_import.start!
worker.perform(project.id)
end
it 'changes import state to finished' do
expect(project.jira_import_status).to eq('finished')
end
it 'changes import state to finished' do
expect(project.jira_import_status).to eq('finished')
end
it 'saves imported issues counts' do
latest_jira_import = project.latest_jira_import
expect(latest_jira_import.total_issue_count).to eq(5)
expect(latest_jira_import.failed_to_import_count).to eq(2)
expect(latest_jira_import.imported_issues_count).to eq(3)
end
it 'saves imported issues counts' do
latest_jira_import = project.latest_jira_import
expect(latest_jira_import.total_issue_count).to eq(5)
expect(latest_jira_import.failed_to_import_count).to eq(2)
expect(latest_jira_import.imported_issues_count).to eq(3)
end
end
end
......
......@@ -10,34 +10,19 @@ describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
before do
stub_feature_flags(jira_issue_import: true)
jira_import.start!
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when import started' do
before do
jira_import.start!
end
it_behaves_like 'advance to next stage', :notes
end
it_behaves_like 'advance to next stage', :notes
end
end
end
......@@ -13,65 +13,53 @@ describe Gitlab::JiraImport::Stage::ImportIssuesWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
before do
stub_jira_service_test
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started', :clean_gitlab_redis_cache do
let_it_be(:jira_service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
jira_import.start!
allow_next_instance_of(Gitlab::JiraImport::IssuesImporter) do |instance|
allow(instance).to receive(:fetch_issues).and_return([])
end
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
context 'when start_at is nil' do
it_behaves_like 'advance to next stage', :attachments
end
context 'when import started', :clean_gitlab_redis_cache do
let_it_be(:jira_service) { create(:jira_service, project: project) }
context 'when start_at is zero' do
before do
jira_import.start!
allow_next_instance_of(Gitlab::JiraImport::IssuesImporter) do |instance|
allow(instance).to receive(:fetch_issues).and_return([])
end
end
context 'when start_at is nil' do
it_behaves_like 'advance to next stage', :attachments
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(0)
end
context 'when start_at is zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(0)
end
it_behaves_like 'advance to next stage', :issues
end
it_behaves_like 'advance to next stage', :issues
context 'when start_at is greater than zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(25)
end
context 'when start_at is greater than zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(25)
end
it_behaves_like 'advance to next stage', :issues
end
it_behaves_like 'advance to next stage', :issues
context 'when start_at is below zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(-1)
end
context 'when start_at is below zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(-1)
end
it_behaves_like 'advance to next stage', :attachments
end
it_behaves_like 'advance to next stage', :attachments
end
end
end
......
......@@ -13,48 +13,33 @@ describe Gitlab::JiraImport::Stage::ImportLabelsWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
let!(:jira_service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
stub_jira_service_test
context 'when import started' do
let!(:jira_service) { create(:jira_service, project: project) }
jira_import.start!
before do
stub_jira_service_test
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/label?maxResults=500&startAt=0')
.to_return(body: {}.to_json )
end
jira_import.start!
it_behaves_like 'advance to next stage', :issues
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/label?maxResults=500&startAt=0')
.to_return(body: {}.to_json )
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
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
described_class.new.perform(project.id)
end
end
end
......
......@@ -10,34 +10,19 @@ describe Gitlab::JiraImport::Stage::ImportNotesWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
before do
stub_feature_flags(jira_issue_import: true)
jira_import.start!
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when import started' do
before do
jira_import.start!
end
it_behaves_like 'advance to next stage', :finish
end
it_behaves_like 'advance to next stage', :finish
end
end
end
......@@ -12,80 +12,62 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do
end
describe '#perform' do
context 'when feature flag not disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, project: project, jid: jid) }
it 'exits because import not allowed' do
context 'when import is not scheduled' do
it 'exits because import not started' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, project: project, jid: jid) }
context 'when import is scheduled' do
before do
stub_feature_flags(jira_issue_import: true)
jira_import.schedule!
end
context 'when import is not scheduled' do
it 'exits because import not started' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
it 'advances to importing labels' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
worker.perform(project.id)
end
worker.perform(project.id)
end
end
context 'when import is scheduled' do
before do
jira_import.schedule!
end
context 'when import is started' do
before do
jira_import.update!(status: :started)
end
context 'when this is the same worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
worker.perform(project.id)
end
end
context 'when import is started' do
before do
jira_import.update!(status: :started)
end
context 'when this is the same worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
worker.perform(project.id)
end
end
context 'when this is a different worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return('87654321')
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
context 'when this is a different worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return('87654321')
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
worker.perform(project.id)
end
end
end
context 'when import is finished' do
before do
jira_import.update!(status: :finished)
end
context 'when import is finished' do
before do
jira_import.update!(status: :finished)
end
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
worker.perform(project.id)
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