diff --git a/app/models/concerns/import/has_import_source.rb b/app/models/concerns/import/has_import_source.rb index cdede6ddc7740e7e7e8c808f8823a2482d110011..e7be1200dec2b8908b2f87187889fa7f64c61cbd 100644 --- a/app/models/concerns/import/has_import_source.rb +++ b/app/models/concerns/import/has_import_source.rb @@ -2,6 +2,8 @@ module Import SOURCE_DIRECT_TRANSFER = :gitlab_migration # aka BulkImports + SOURCE_PROJECT_EXPORT_IMPORT = :gitlab_project + SOURCE_GROUP_EXPORT_IMPORT = :gitlab_group module HasImportSource extend ActiveSupport::Concern @@ -9,15 +11,16 @@ module HasImportSource IMPORT_SOURCES = { none: 0, # not imported SOURCE_DIRECT_TRANSFER => 1, - gitlab_project: 2, # aka gitlab import/export - github: 3, - bitbucket: 4, # aka bitbucket cloud - bitbucket_server: 5, - fogbugz: 6, - gitea: 7, - git: 8, # aka repository by url - manifest: 9, # aka manifest file - custom_template: 10 # aka gitlab custom project template export + SOURCE_PROJECT_EXPORT_IMPORT => 2, + SOURCE_GROUP_EXPORT_IMPORT => 3, + github: 4, + bitbucket: 5, # aka bitbucket cloud + bitbucket_server: 6, + fogbugz: 7, + gitea: 8, + git: 9, # aka repository by url + manifest: 10, # aka manifest file + custom_template: 11 # aka gitlab custom project template export }.freeze included do diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index f84d2e828b7a74a7322fb10d67b8509a0ea35ce8..7dffff88f7fb34e8a8794e70cfe0e66a338959f7 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -33881,6 +33881,7 @@ Import source. | <a id="importsourcegit"></a>`GIT` | Imported from Git. | | <a id="importsourcegitea"></a>`GITEA` | Imported from Gitea. | | <a id="importsourcegithub"></a>`GITHUB` | Imported from Github. | +| <a id="importsourcegitlab_group"></a>`GITLAB_GROUP` | Imported from Gitlab Group. | | <a id="importsourcegitlab_migration"></a>`GITLAB_MIGRATION` | Imported from Gitlab Migration. | | <a id="importsourcegitlab_project"></a>`GITLAB_PROJECT` | Imported from Gitlab Project. | | <a id="importsourcemanifest"></a>`MANIFEST` | Imported from Manifest. | diff --git a/doc/user/project/index.md b/doc/user/project/index.md index a4a48916f9fe03a4fc3c931aba6e216fc1983017..c343a1094944b76688876938c34f40bceae14657 100644 --- a/doc/user/project/index.md +++ b/doc/user/project/index.md @@ -61,10 +61,11 @@ To create a project from a built-in template: change the **Visibility Level**. 1. Select **Create project**. -NOTE: -A user who creates a project [from a template](#create-a-project-from-a-built-in-template) or [by import](settings/import_export.md#import-a-project-and-its-data) is displayed as the author of the imported objects (such as issues and merge requests), which keep the original timestamp from the template or import. -Imported objects are labeled as `By <username> on <timestamp> (imported from GitLab)`. -For this reason, the creation date of imported objects can be older than the creation date of the user's account. This can lead to objects appearing to have been created by a user before they even had an account. +Users who create projects [from a template](#create-a-project-from-a-built-in-template) or [by importing them](settings/import_export.md#import-a-project-and-its-data) are +displayed as the author of the imported items, which keep the original timestamp from the template or import. For this reason, the creation date of imported items can be +older than the creation date of the user's account. This can make items appear to have been created by a user before they even had an account. + +Imported objects are labeled as `By <username> on <timestamp>`. Before GitLab 17.1, the label was suffixed with `(imported from GitLab)`. ## Create a project from a custom template diff --git a/ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb b/ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb index 5dc4a56957ccde249b4a3e5c8a29403ac09134fd..718bb085777baeee4250eb076040a57a9b4896af 100644 --- a/ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb +++ b/ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::ImportExport::Group::RelationFactory do +RSpec.describe Gitlab::ImportExport::Group::RelationFactory, feature_category: :importers do let(:group) { create(:group) } let(:members_mapper) { double('members_mapper').as_null_object } let(:admin) { create(:admin) } @@ -17,6 +17,7 @@ object_builder: Gitlab::ImportExport::Group::ObjectBuilder, user: importer_user, importable: group, + import_source: ::Import::SOURCE_GROUP_EXPORT_IMPORT, excluded_keys: excluded_keys ) end diff --git a/ee/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/ee/spec/lib/gitlab/import_export/project/relation_factory_spec.rb index 0343208bdc5c94f416bcea3e96a8500e70d215b3..477e6eeba2e80a51a04ea106c339da6a13e2e7e7 100644 --- a/ee/spec/lib/gitlab/import_export/project/relation_factory_spec.rb +++ b/ee/spec/lib/gitlab/import_export/project/relation_factory_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::ImportExport::Project::RelationFactory do +RSpec.describe Gitlab::ImportExport::Project::RelationFactory, feature_category: :importers do let(:user) { create(:user, admin: true) } let_it_be(:project) { create(:project) } @@ -16,6 +16,7 @@ object_builder: Gitlab::ImportExport::Project::ObjectBuilder, user: user, importable: project, + import_source: :gitlab_project, excluded_keys: [] ) end diff --git a/lib/gitlab/import_export/base/relation_factory.rb b/lib/gitlab/import_export/base/relation_factory.rb index 1711dd169a528f4858bd91626daa5e46aad13a79..ab3c7e4d6ea0e0b1a162a6ab78b9eab807867aba 100644 --- a/lib/gitlab/import_export/base/relation_factory.rb +++ b/lib/gitlab/import_export/base/relation_factory.rb @@ -50,7 +50,7 @@ def self.relation_class(relation_name) end # rubocop:disable Metrics/ParameterLists -- Keyword arguments are not adding complexity to initializer - def initialize(relation_sym:, relation_index:, relation_hash:, members_mapper:, object_builder:, user:, importable:, excluded_keys: [], import_source: nil) + def initialize(relation_sym:, relation_index:, relation_hash:, members_mapper:, object_builder:, user:, importable:, import_source:, excluded_keys: []) @relation_sym = relation_sym @relation_name = self.class.overrides[relation_sym]&.to_sym || relation_sym @relation_index = relation_index @@ -188,7 +188,7 @@ def imported_object existing_or_new_object.importing = true end - if @import_source && existing_or_new_object.respond_to?(:imported_from) + if existing_or_new_object.respond_to?(:imported_from) existing_or_new_object.imported_from = @import_source end @@ -329,7 +329,7 @@ def set_note_author def missing_author_note(updated_at, author_name) timestamp = updated_at.split('.').first - "*By #{author_name} on #{timestamp} (imported from GitLab)*" + "*By #{author_name} on #{timestamp}*" end def existing_object? diff --git a/lib/gitlab/import_export/group/relation_tree_restorer.rb b/lib/gitlab/import_export/group/relation_tree_restorer.rb index e5120e8c29cb45f159ac605336c5e2a83bf174ad..3ae9f67e9017ce470f1bae638c83b34ffb80b399 100644 --- a/lib/gitlab/import_export/group/relation_tree_restorer.rb +++ b/lib/gitlab/import_export/group/relation_tree_restorer.rb @@ -311,7 +311,8 @@ def relation_factory_params(relation_key, relation_index, data_hash) members_mapper: @members_mapper, object_builder: @object_builder, user: @user, - excluded_keys: excluded_keys_for_relation(relation_key) + excluded_keys: excluded_keys_for_relation(relation_key), + import_source: ::Import::SOURCE_GROUP_EXPORT_IMPORT } end diff --git a/lib/gitlab/import_export/project/relation_tree_restorer.rb b/lib/gitlab/import_export/project/relation_tree_restorer.rb index 056c30a996f9d6997f342551fff08e3dd728774d..88610ce05b343c380ec138c41213dfcc098c2ae9 100644 --- a/lib/gitlab/import_export/project/relation_tree_restorer.rb +++ b/lib/gitlab/import_export/project/relation_tree_restorer.rb @@ -13,6 +13,10 @@ def restore_single_relation(relation_key) end end + def relation_factory_params(relation_key, relation_index, data_hash) + super.merge({ import_source: ::Import::SOURCE_PROJECT_EXPORT_IMPORT }) + end + private def group_models diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb index 4d63a8402d51c55b7468db6ba31b7f7bc3b92c5f..dab1b379ee6fa994805eb3abcc168abdcd692e77 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb @@ -426,7 +426,7 @@ def sanitize_description(body, transform_urls) # # @return [Regex] def created_by_pattern - @created_by_pattern ||= /\n\n \*By .+ on \S+ \(imported from GitLab\)\*/ + @created_by_pattern ||= /\n\n \*By .+ on \S+\*/ end # Source project url diff --git a/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb index c0c4e2ce8ed8200785104756ec09e8fd4e62ff7c..87a92d7f23cfbb47c4a417e894057da44fd571e9 100644 --- a/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb +++ b/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb @@ -162,7 +162,7 @@ note = project.issues.last.notes.first aggregate_failures do - expect(note.note).to eq("Issue note\n\n *By User 22 on 2016-06-14T15:02:47 (imported from GitLab)*") + expect(note.note).to eq("Issue note\n\n *By User 22 on 2016-06-14T15:02:47*") expect(note.award_emoji.first.name).to eq('clapper') end end diff --git a/spec/lib/bulk_imports/projects/pipelines/snippets_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/snippets_pipeline_spec.rb index 7e308e8024be34f3b39c3e039770b94f3fe1ae4a..8570bcecc7f164ef104c391d9b2be2a90c48b36f 100644 --- a/spec/lib/bulk_imports/projects/pipelines/snippets_pipeline_spec.rb +++ b/spec/lib/bulk_imports/projects/pipelines/snippets_pipeline_spec.rb @@ -106,7 +106,7 @@ note_updated_at = exported_snippet['notes'].first['updated_at'].split('.').first expect(snippet_note).to have_attributes( - note: note.note + "\n\n *By #{author_name} on #{note_updated_at} (imported from GitLab)*", + note: note.note + "\n\n *By #{author_name} on #{note_updated_at}*", noteable_type: note.noteable_type, author_id: user.id, updated_at: note.updated_at, diff --git a/spec/lib/gitlab/import_export/base/relation_factory_spec.rb b/spec/lib/gitlab/import_export/base/relation_factory_spec.rb index cd1ad355fddcf7073eb187304553872ce7b92550..85738b8f3c8bb4d69899992b571a08689454390d 100644 --- a/spec/lib/gitlab/import_export/base/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/base/relation_factory_spec.rb @@ -9,7 +9,7 @@ let(:relation_sym) { :project_snippets } let(:relation_hash) { {} } let(:excluded_keys) { [] } - let(:import_source) { nil } + let(:import_source) { Import::SOURCE_DIRECT_TRANSFER } subject do described_class.create( # rubocop:disable Rails/SaveBang @@ -92,21 +92,25 @@ expect(subject).to be_instance_of(Note) end - context 'when import_source is given' do - let(:import_source) { Import::SOURCE_DIRECT_TRANSFER } + it 'sets imported_from' do + expect(subject.imported_from).to eq(Import::SOURCE_DIRECT_TRANSFER.to_s) + end + + context 'when import_source is gitlab_project' do + let(:import_source) { Import::SOURCE_PROJECT_EXPORT_IMPORT } - it 'sets the imported_from' do - expect(subject.imported_from).to eq(import_source.to_s) + it 'sets imported_from' do + expect(subject.imported_from).to eq(Import::SOURCE_PROJECT_EXPORT_IMPORT.to_s) end + end - context 'when object does not have an imported_from attribute' do - let(:relation_sym) { :user } - let(:relation_hash) { attributes_for(:user) } + context 'when object does not have an imported_from attribute' do + let(:relation_sym) { :user } + let(:relation_hash) { attributes_for(:user) } - it 'works without an error' do - expect(subject).not_to respond_to(:imported_from) # Sanity check: This must be true for test subject - expect(subject).to be_instance_of(User) - end + it 'works without an error' do + expect(subject).not_to respond_to(:imported_from) # Sanity check: This must be true for test subject + expect(subject).to be_instance_of(User) end end diff --git a/spec/lib/gitlab/import_export/group/relation_factory_spec.rb b/spec/lib/gitlab/import_export/group/relation_factory_spec.rb index 9dbe8426f5271b9ed6b8ad682f3226ac5accac82..8ec00c46f2b7f0d581ee0a886a5d7cab2b3a3a05 100644 --- a/spec/lib/gitlab/import_export/group/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/group/relation_factory_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::ImportExport::Group::RelationFactory do +RSpec.describe Gitlab::ImportExport::Group::RelationFactory, feature_category: :importers do let(:group) { create(:group) } let(:members_mapper) { double('members_mapper').as_null_object } let(:admin) { create(:admin) } @@ -17,6 +17,7 @@ object_builder: Gitlab::ImportExport::Group::ObjectBuilder, user: importer_user, importable: group, + import_source: ::Import::SOURCE_GROUP_EXPORT_IMPORT, excluded_keys: excluded_keys ) end diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb index 5079090569f2491852a23147eb9e1e92334b7428..3e731a75fe356bad0b5aa9ac31e666733a64ed87 100644 --- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb @@ -19,6 +19,7 @@ members_mapper: members_mapper, user: importer_user, importable: project, + import_source: ::Import::SOURCE_PROJECT_EXPORT_IMPORT, excluded_keys: excluded_keys ) end diff --git a/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb index 553d64cde68a874b701fdf0ba78b7f0def616477..962fd789dfee23d1406d40c02a3c9fe0e130c666 100644 --- a/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb @@ -52,6 +52,22 @@ expect(project.snippets.count).to eq(1) expect(project.commit_notes.count).to eq(3) end + + it 'assigns the correct import source' do + expect(subject).to eq(true) + + project = Project.find_by_path('project') + + issues = project.issues + snippets = project.snippets + merge_requests = project.merge_requests + notes = project.notes + + expect(issues.map).to all(have_attributes(imported_from: 'gitlab_project')) + expect(snippets.map).to all(have_attributes(imported_from: 'gitlab_project')) + expect(merge_requests.map).to all(have_attributes(imported_from: 'gitlab_project')) + expect(notes.map).to all(have_attributes(imported_from: 'gitlab_project')) + end end end diff --git a/spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb index 9dde09a76021b45a9ebbd2af0dd9ff25f0e63231..afe2724e6456302129d2d1dc5fba3ff78abebd23 100644 --- a/spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::ImportExport::Project::Sample::RelationFactory do +RSpec.describe Gitlab::ImportExport::Project::Sample::RelationFactory, feature_category: :importers do let(:group) { create(:group) } let(:project) { create(:project, :repository, group: group) } let(:members_mapper) { double('members_mapper').as_null_object } @@ -22,6 +22,7 @@ members_mapper: members_mapper, user: importer_user, importable: project, + import_source: ::Import::SOURCE_PROJECT_EXPORT_IMPORT, excluded_keys: excluded_keys, date_calculator: date_calculator )