Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2018-07-02 12:16:24 +0300
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2018-07-11 12:22:57 +0300
commit88e640374a82c3058b2a8cb54407fdc1784484d9 (patch)
treec6d0451ca3947e92a56c4d39e00cbf5b0272d257 /lib/gitlab/manifest_import
parente68a547bc790d44a1df3c9ae8b07b004ab8dd47e (diff)
Add manifest import feature
It allows user to automatically import multiple repositories with nested structure by uploading a manifest xml file. AOSP project was used as an example during development of this feature. Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Diffstat (limited to 'lib/gitlab/manifest_import')
-rw-r--r--lib/gitlab/manifest_import/importer.rb46
-rw-r--r--lib/gitlab/manifest_import/manifest.rb77
2 files changed, 123 insertions, 0 deletions
diff --git a/lib/gitlab/manifest_import/importer.rb b/lib/gitlab/manifest_import/importer.rb
new file mode 100644
index 00000000000..35b3bb1e0ca
--- /dev/null
+++ b/lib/gitlab/manifest_import/importer.rb
@@ -0,0 +1,46 @@
+module Gitlab
+ module ManifestImport
+ class Importer
+ attr_reader :repository, :destination, :user
+
+ def initialize(repository, destination, user)
+ @repository = repository
+ @destination = destination
+ @user = user
+ end
+
+ def execute
+ import_project
+ end
+
+ private
+
+ def import_project
+ group_full_path, _, project_path = repository[:path].rpartition('/')
+ group_full_path = File.join(destination.path, group_full_path) if destination
+ group = Group.find_by_full_path(group_full_path) ||
+ create_group_with_parents(group_full_path)
+
+ params = {
+ import_url: repository[:url],
+ import_type: 'manifest',
+ namespace_id: group.id,
+ path: project_path,
+ name: project_path,
+ visibility_level: destination.visibility_level
+ }
+
+ Projects::CreateService.new(user, params).execute
+ end
+
+ def create_group_with_parents(full_path)
+ params = {
+ group_path: full_path,
+ visibility_level: destination.visibility_level
+ }
+
+ Groups::NestedCreateService.new(user, params).execute
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/manifest_import/manifest.rb b/lib/gitlab/manifest_import/manifest.rb
new file mode 100644
index 00000000000..87959d4ae7f
--- /dev/null
+++ b/lib/gitlab/manifest_import/manifest.rb
@@ -0,0 +1,77 @@
+# Class to parse manifest file to import multiple projects at once
+#
+# <manifest>
+# <remote review="https://android-review.googlesource.com/" />
+# <project path="platform-common" name="platform" />
+# <project path="platform/art" name="platform/art" />
+# <project path="platform/device" name="platform/device" />
+# </manifest>
+#
+# 1. Project path must be uniq and can't be part of other project path.
+# For example, you can't have projects with 'foo' and 'foo/bar' paths.
+# 2. Remote must be present with review attribute so GitLab knows
+# where to fetch source code
+# 3. For each nested keyword in path a corresponding group will be created.
+# For example if a path is 'foo/bar' then GitLab will create a group 'foo'
+# and a project 'bar' in it.
+module Gitlab
+ module ManifestImport
+ class Manifest
+ attr_reader :parsed_xml, :errors
+
+ def initialize(file)
+ @parsed_xml = File.open(file) { |f| Nokogiri::XML(f) }
+ @errors = []
+ end
+
+ def projects
+ raw_projects.each_with_index.map do |project, i|
+ {
+ id: i,
+ name: project['name'],
+ path: project['path'],
+ url: repository_url(project['name'])
+ }
+ end
+ end
+
+ def valid?
+ unless validate_remote
+ @errors << 'Make sure a <remote> tag is present and is valid.'
+ end
+
+ unless validate_projects
+ @errors << 'Make sure every <project> tag has name and path attributes.'
+ end
+
+ @errors.empty?
+ end
+
+ private
+
+ def validate_remote
+ remote.present? && URI.parse(remote).host
+ rescue URI::Error
+ false
+ end
+
+ def validate_projects
+ raw_projects.all? do |project|
+ project['name'] && project['path']
+ end
+ end
+
+ def repository_url(name)
+ URI.join(remote, name).to_s
+ end
+
+ def remote
+ @remote ||= parsed_xml.css('manifest > remote').first['review']
+ end
+
+ def raw_projects
+ @raw_projects ||= parsed_xml.css('manifest > project')
+ end
+ end
+ end
+end