Commit 281a93fd authored by Grant Young's avatar Grant Young Committed by Kamil Trzciński

Change terminology from Demo to Sample Data

Better reflects what feature will be used for
parent ea88b7e4
import { s__ } from '~/locale';
export default {
basic: {
text: s__('ProjectTemplates|Basic'),
icon: '.template-option .icon-basic',
},
serenity_valley: {
text: s__('ProjectTemplates|Serenity Valley'),
icon: '.template-option .icon-serenity_valley',
},
};
import $ from 'jquery';
import DEFAULT_PROJECT_TEMPLATES from 'ee_else_ce/projects/default_project_templates';
import DEFAULT_SAMPLE_DATA_TEMPLATES from '~/projects/default_sample_data_templates';
import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils';
import {
convertToTitleCase,
......@@ -146,7 +147,8 @@ const bindEvents = () => {
$selectedIcon.empty();
const value = $(this).val();
const selectedTemplate = DEFAULT_PROJECT_TEMPLATES[value];
const selectedTemplate =
DEFAULT_PROJECT_TEMPLATES[value] || DEFAULT_SAMPLE_DATA_TEMPLATES[value];
$selectedTemplateText.text(selectedTemplate.text);
$(selectedTemplate.icon)
.clone()
......
......@@ -14,10 +14,16 @@ module Projects
def execute
return project unless validate_template!
file = built_in_template&.file
file = built_in_template&.file || sample_data_template&.file
override_params = params.dup
params[:file] = file
if built_in_template
params[:file] = built_in_template.file
elsif sample_data_template
params[:file] = sample_data_template.file
params[:sample_data] = true
end
GitlabProjectsImportService.new(current_user, params, override_params).execute
ensure
......@@ -27,7 +33,7 @@ module Projects
private
def validate_template!
return true if built_in_template
return true if built_in_template || sample_data_template
project.errors.add(:template_name, _("'%{template_name}' is unknown or invalid" % { template_name: template_name }))
false
......@@ -39,6 +45,12 @@ module Projects
end
end
def sample_data_template
strong_memoize(:sample_data_template) do
Gitlab::SampleDataTemplate.find(template_name)
end
end
def project
@project ||= ::Project.new(namespace_id: params[:namespace_id])
end
......
......@@ -66,6 +66,7 @@ module Projects
end
if template_file
data[:sample_data] = params.delete(:sample_data) if params.key?(:sample_data)
params[:import_type] = 'gitlab_project'
end
......
- f ||= local_assigns[:f]
.project-templates-buttons.import-buttons.col-sm-12
= render 'projects/project_templates/built_in_templates'
.project-templates-buttons.col-sm-12
%ul.nav-tabs.nav-links.nav.scrolling-tabs
%li.built-in-tab
%a.nav-link.active{ href: "#built-in", data: { toggle: 'tab'} }
= _('Built-in')
%span.badge.badge-pill= Gitlab::ProjectTemplate.all.count
%li.sample-data-templates-tab
%a.nav-link{ href: "#sample-data-templates", data: { toggle: 'tab'} }
= _('Sample Data')
%span.badge.badge-pill= Gitlab::SampleDataTemplate.all.count
.tab-content
.project-templates-buttons.import-buttons.tab-pane.active#built-in
= render partial: 'projects/project_templates/template', collection: Gitlab::ProjectTemplate.all
.project-templates-buttons.import-buttons.tab-pane#sample-data-templates
= render partial: 'projects/project_templates/template', collection: Gitlab::SampleDataTemplate.all
.project-fields-form
= render 'projects/project_templates/project_fields_form'
......
- Gitlab::ProjectTemplate.all.each do |template|
.template-option.d-flex.align-items-center{ data: { qa_selector: 'template_option_row' } }
.logo.gl-mr-3.px-1
= image_tag template.logo, size: 32, class: "btn-template-icon icon-#{template.name}"
.description
%strong
= template.title
%br
.text-muted
= template.description
.controls.d-flex.align-items-center
%a.btn.btn-default.gl-mr-3{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } }
= _("Preview")
%label.btn.btn-success.template-button.choose-template.gl-mb-0{ for: template.name }
%input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } }
%span{ data: { qa_selector: 'use_template_button' } }
= _("Use template")
.template-option.d-flex.align-items-center{ data: { qa_selector: 'template_option_row' } }
.logo.gl-mr-3.px-1
= image_tag template.logo, size: 32, class: "btn-template-icon icon-#{template.name}"
.description
%strong
= template.title
%br
.text-muted
= template.description
.controls.d-flex.align-items-center
%a.btn.gl-button.btn-default.gl-mr-3{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } }
= _("Preview")
%label.btn.gl-button.btn-success.template-button.choose-template.gl-mb-0{ for: template.name }
%input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } }
%span{ data: { qa_selector: 'use_template_button' } }
= _("Use template")
---
title: Add Sample Data
merge_request: 41699
author:
type: added
......@@ -58,7 +58,7 @@ To create a new blank project on the **New project** page:
Project templates can pre-populate a new project with the necessary files to get you
started quickly.
There are two types of project templates:
There are two main types of project templates:
- [Built-in templates](#built-in-templates), sourced from the following groups:
- [`project-templates`](https://gitlab.com/gitlab-org/project-templates)
......
......@@ -17,16 +17,22 @@
= _('Group')
%span.badge.badge-pill.qa-group-template-tab-badge
= group_project_templates_count(group_id)
%li.sample-data-templates-tab
%a.nav-link{ href: "#sample-data-templates", data: { toggle: 'tab'} }
= _('Sample Data')
%span.badge.badge-pill= Gitlab::SampleDataTemplate.all.count
.tab-content
.project-templates-buttons.import-buttons.tab-pane.active#built-in
= render 'projects/project_templates/built_in_templates'
= render partial: 'projects/project_templates/template', collection: Gitlab::ProjectTemplate.all
.project-templates-buttons.import-buttons.tab-pane.js-custom-instance-project-templates-tab-content#custom-instance-project-templates{ data: {initial_templates: user_available_project_templates_path(current_user)} }
.text-center.m-4
= icon("spin spinner 2x")
.project-templates-buttons.import-buttons.tab-pane.js-custom-group-project-templates-tab-content#custom-group-project-templates{ data: {initial_templates: user_available_group_templates_path(current_user, group_id: group_id)} }
.text-center.m-4
= icon("spin spinner 2x")
.project-templates-buttons.import-buttons.tab-pane#sample-data-templates
= render partial: 'projects/project_templates/template', collection: Gitlab::SampleDataTemplate.all
.project-fields-form
= render 'projects/project_templates/project_fields_form'
......
......@@ -69,6 +69,7 @@ RSpec.describe Projects::CreateFromTemplateService do
it 'creates an empty project' do
expect(::Gitlab::ProjectTemplate).to receive(:find)
expect(::Gitlab::SampleDataTemplate).to receive(:find)
expect(subject).not_to receive(:find_template_project)
end
end
......@@ -78,6 +79,7 @@ RSpec.describe Projects::CreateFromTemplateService do
stub_licensed_features(custom_project_templates: false)
expect(::Gitlab::ProjectTemplate).to receive(:find)
expect(::Gitlab::SampleDataTemplate).to receive(:find)
expect(subject).not_to receive(:find_template_project)
end
end
......
......@@ -35,6 +35,7 @@ module Gitlab
# This reads from `tree/project/merge_requests.ndjson`
path = file_path(importable_path, "#{key}.ndjson")
next unless File.exist?(path)
File.foreach(path, MAX_JSON_DOCUMENT_SIZE).with_index do |line, line_num|
......@@ -43,6 +44,11 @@ module Gitlab
end
end
# TODO: Move clear logic into main comsume_relation method (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430465330)
def clear_consumed_relations
@consumed_relations.clear
end
private
def json_decode(string)
......
# frozen_string_literal: true
module Gitlab
module ImportExport
module Project
module Sample
class DateCalculator
include Gitlab::Utils::StrongMemoize
def initialize(dates)
@dates = dates.dup
@dates.flatten!
@dates.compact!
@dates.sort!
@dates.map! { |date| date.to_time.to_f }
end
def closest_date_to_average
strong_memoize(:closest_date_to_average) do
next if @dates.empty?
average_date = (@dates.first + @dates.last) / 2.0
closest_date = @dates.min_by { |date| (date - average_date).abs }
Time.zone.at(closest_date)
end
end
def calculate_by_closest_date_to_average(date)
return date unless closest_date_to_average && closest_date_to_average < Time.current
date + (Time.current - closest_date_to_average).seconds
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module ImportExport
module Project
module Sample
class SampleDataRelationTreeRestorer < RelationTreeRestorer
DATE_MODELS = %i[issues milestones].freeze
def initialize(*args)
super
date_calculator
end
private
def build_relation(relation_key, relation_definition, data_hash)
# Override due date attributes in data hash for Sample Data templates
# Dates are moved by taking the closest one to average and moving that (and rest around it) to the date of import
# TODO: To move this logic to RelationFactory (see: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430465333)
override_date_attributes!(relation_key, data_hash)
super
end
def override_date_attributes!(relation_key, data_hash)
return unless DATE_MODELS.include?(relation_key.to_sym)
data_hash['start_date'] = date_calculator.calculate_by_closest_date_to_average(data_hash['start_date'].to_time) unless data_hash['start_date'].nil?
data_hash['due_date'] = date_calculator.calculate_by_closest_date_to_average(data_hash['due_date'].to_time) unless data_hash['due_date'].nil?
end
# TODO: Move clear logic into main comsume_relation method (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430465330)
def dates
unless relation_reader.legacy?
DATE_MODELS.map do |tag|
relation_reader.consume_relation(@importable_path, tag).map { |model| model.first['due_date'] }.tap do
relation_reader.clear_consumed_relations
end
end
end
end
def date_calculator
@date_calculator ||= Gitlab::ImportExport::Project::Sample::DateCalculator.new(dates)
end
end
end
end
end
end
......@@ -70,7 +70,7 @@ module Gitlab
end
def relation_tree_restorer
@relation_tree_restorer ||= RelationTreeRestorer.new(
@relation_tree_restorer ||= relation_tree_restorer_class.new(
user: @user,
shared: @shared,
relation_reader: relation_reader,
......@@ -84,6 +84,14 @@ module Gitlab
)
end
def relation_tree_restorer_class
sample_data_template? ? Sample::SampleDataRelationTreeRestorer : RelationTreeRestorer
end
def sample_data_template?
@project&.import_data&.data&.dig('sample_data')
end
def members_mapper
@members_mapper ||= Gitlab::ImportExport::MembersMapper.new(exported_members: @project_members,
user: @user,
......
This diff is collapsed.
# frozen_string_literal: true
module Gitlab
class SampleDataTemplate < ProjectTemplate
class << self
def localized_templates_table
[
SampleDataTemplate.new('basic', 'Basic', _('Basic Sample Data template with Issues, Merge Requests and Milestones.'), 'https://gitlab.com/gitlab-org/sample-data-templates/basic'),
SampleDataTemplate.new('serenity_valley', 'Serenity Valley', _('Serenity Valley Sample Data template.'), 'https://gitlab.com/gitlab-org/sample-data-templates/serenity-valley')
].freeze
end
def all
localized_templates_table
end
def archive_directory
Rails.root.join("vendor/sample_data_templates")
end
end
end
end
......@@ -4115,6 +4115,9 @@ msgstr ""
msgid "Based on"
msgstr ""
msgid "Basic Sample Data template with Issues, Merge Requests and Milestones."
msgstr ""
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
......@@ -20773,6 +20776,9 @@ msgstr ""
msgid "ProjectTemplates|Android"
msgstr ""
msgid "ProjectTemplates|Basic"
msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
......@@ -20827,6 +20833,9 @@ msgstr ""
msgid "ProjectTemplates|SalesforceDX"
msgstr ""
msgid "ProjectTemplates|Serenity Valley"
msgstr ""
msgid "ProjectTemplates|Serverless Framework/JS"
msgstr ""
......@@ -22806,6 +22815,9 @@ msgstr ""
msgid "SSL Verification:"
msgstr ""
msgid "Sample Data"
msgstr ""
msgid "Satisfied"
msgstr ""
......@@ -23739,6 +23751,9 @@ msgstr ""
msgid "September"
msgstr ""
msgid "Serenity Valley Sample Data template."
msgstr ""
msgid "SeriesFinalConjunction|and"
msgstr ""
......
......@@ -27,7 +27,7 @@ module QA
element :import_github, "icon('github', text: 'GitHub')" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/project_templates/_built_in_templates.html.haml' do
view 'app/views/projects/project_templates/_template.html.haml' do
element :use_template_button
element :template_option_row
end
......
......@@ -6,25 +6,35 @@ RSpec.describe 'Project' do
include ProjectForksHelper
include MobileHelpers
describe 'creating from template' do
describe 'template' do
let(:user) { create(:user) }
let(:template) { Gitlab::ProjectTemplate.find(:rails) }
before do
sign_in user
visit new_project_path
end
it "allows creation from templates", :js do
find('#create-from-template-tab').click
find("label[for=#{template.name}]").click
fill_in("project_name", with: template.name)
shared_examples 'creates from template' do |template, sub_template_tab = nil|
it "is created from template", :js do
find('#create-from-template-tab').click
find(".project-template #{sub_template_tab}").click if sub_template_tab
find("label[for=#{template.name}]").click
fill_in("project_name", with: template.name)
page.within '#content-body' do
click_button "Create project"
page.within '#content-body' do
click_button "Create project"
end
expect(page).to have_content template.name
end
end
context 'create with project template' do
it_behaves_like 'creates from template', Gitlab::ProjectTemplate.find(:rails)
end
expect(page).to have_content template.name
context 'create with sample data template' do
it_behaves_like 'creates from template', Gitlab::SampleDataTemplate.find(:basic), '.sample-data-templates-tab'
end
end
......
{"description":"Nisi et repellendus ut enim quo accusamus vel magnam.","import_type":"gitlab_project","creator_id":2147483547,"visibility_level":10,"archived":false,"hooks":[]}
{"id":2,"title":"test2","color":"#428bca","project_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","type":"ProjectLabel","priorities":[]}
{"id":3,"title":"test3","color":"#428bca","group_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","project_id":null,"type":"GroupLabel","priorities":[{"id":1,"project_id":5,"label_id":1,"priority":1,"created_at":"2016-10-18T09:35:43.338Z","updated_at":"2016-10-18T09:35:43.338Z"}]}
{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":"2020-08-07","created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]}
{"id":20,"title":"v4.0","project_id":5,"description":"Totam quam laborum id magnam natus eaque aspernatur.","due_date":"2020-08-14","created_at":"2016-06-14T15:02:04.590Z","updated_at":"2016-06-14T15:02:04.590Z","state":"active","iid":5,"events":[{"id":240,"target_type":"Milestone","target_id":20,"project_id":36,"created_at":"2016-06-14T15:02:04.593Z","updated_at":"2016-06-14T15:02:04.593Z","action":1,"author_id":1},{"id":60,"target_type":"Milestone","target_id":20,"project_id":5,"created_at":"2016-06-14T15:02:04.593Z","updated_at":"2016-06-14T15:02:04.593Z","action":1,"author_id":20}]}
{"id":19,"title":"v3.0","project_id":5,"description":"Rerum at autem exercitationem ea voluptates harum quam placeat.","due_date":"2020-08-21","created_at":"2016-06-14T15:02:04.583Z","updated_at":"2016-06-14T15:02:04.583Z","state":"active","iid":4,"events":[{"id":241,"target_type":"Milestone","target_id":19,"project_id":36,"created_at":"2016-06-14T15:02:04.585Z","updated_at":"2016-06-14T15:02:04.585Z","action":1,"author_id":1},{"id":59,"target_type":"Milestone","target_id":19,"project_id":5,"created_at":"2016-06-14T15:02:04.585Z","updated_at":"2016-06-14T15:02:04.585Z","action":1,"author_id":25}]}
......@@ -102,4 +102,14 @@ RSpec.describe Gitlab::ImportExport::JSON::NdjsonReader do
end
end
end
describe '#clear_consumed_relations' do
let(:dir_path) { fixture }
subject { ndjson_reader.clear_consumed_relations }
it 'returns empty set' do
expect(subject).to be_empty
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::Project::Sample::DateCalculator do
describe '#closest date to average' do
subject { described_class.new(dates).closest_date_to_average }
context 'when dates are empty' do
let(:dates) { [] }
it { is_expected.to be_nil }
end
context 'when dates are not empty' do
let(:dates) { [[nil, '2020-01-01 00:00:00 +0000'], [nil, '2021-01-01 00:00:00 +0000'], [nil, '2022-01-01 23:59:59 +0000']] }
it { is_expected.to eq(Time.zone.parse('2021-01-01 00:00:00 +0000')) }
end
end
describe '#calculate_by_closest_date_to_average' do
let(:calculator) { described_class.new([]) }
let(:date) { Time.current }
subject { calculator.calculate_by_closest_date_to_average(date) }
context 'when average date is nil' do
before do
allow(calculator).to receive(:closest_date_to_average).and_return(nil)
end
it { is_expected.to eq(date) }
end
context 'when average date is in the past' do
before do
allow(calculator).to receive(:closest_date_to_average).and_return(date - 365.days)
allow(Time).to receive(:current).and_return(date)
end
it { is_expected.to eq(date + 365.days) }
end
context 'when average date is in the future' do
before do
allow(calculator).to receive(:closest_date_to_average).and_return(date + 10.days)
end
it { is_expected.to eq(date) }
end
end
end
# frozen_string_literal: true
# This spec is a lightweight version of:
# * project/tree_restorer_spec.rb
#
# In depth testing is being done in the above specs.
# This spec tests that restore of the sample project works
# but does not have 100% relation coverage.
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::Project::Sample::SampleDataRelationTreeRestorer do
include_context 'relation tree restorer shared context'
let(:sample_data_relation_tree_restorer) do
described_class.new(
user: user,
shared: shared,
relation_reader: relation_reader,
object_builder: object_builder,
members_mapper: members_mapper,
relation_factory: relation_factory,
reader: reader,
importable: importable,
importable_path: importable_path,
importable_attributes: attributes
)
end
subject { sample_data_relation_tree_restorer.restore }
shared_examples 'import project successfully' do
it 'restores project tree' do
expect(subject).to eq(true)
end
describe 'imported project' do
let(:project) { Project.find_by_path('project') }
before do
subject
end
it 'has the project attributes and relations', :aggregate_failures do
expect(project.description).to eq('Nisi et repellendus ut enim quo accusamus vel magnam.')
expect(project.issues.count).to eq(10)
expect(project.milestones.count).to eq(3)
expect(project.labels.count).to eq(2)
expect(project.project_feature).not_to be_nil
end
it 'has issues with correctly updated due dates' do
due_dates = due_dates(project.issues)
expect(due_dates).to match_array([Date.today - 7.days, Date.today, Date.today + 7.days])
end
it 'has milestones with correctly updated due dates' do
due_dates = due_dates(project.milestones)
expect(due_dates).to match_array([Date.today - 7.days, Date.today, Date.today + 7.days])
end
def due_dates(relations)
due_dates = relations.map { |relation| relation['due_date'] }
due_dates.compact!
due_dates.sort
end
end
end
context 'when restoring a project' do
let(:importable) { create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project') }
let(:importable_name) { 'project' }
let(:importable_path) { 'project' }
let(:object_builder) { Gitlab::ImportExport::Project::ObjectBuilder }
let(:relation_factory) { Gitlab::ImportExport::Project::RelationFactory }
let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) }
context 'using ndjson reader' do
let(:path) { 'spec/fixtures/lib/gitlab/import_export/sample_data/tree' }
let(:relation_reader) { Gitlab::ImportExport::JSON::NdjsonReader.new(path) }
it_behaves_like 'import project successfully'
end
end
end
......@@ -1040,6 +1040,41 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
it_behaves_like 'project tree restorer work properly', :legacy_reader, true
it_behaves_like 'project tree restorer work properly', :ndjson_reader, true
context 'Sample Data JSON' do
let(:user) { create(:user) }
let!(:project) { create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') }
let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) }
before do
setup_import_export_config('sample_data')
setup_reader(:ndjson_reader)
end
context 'with sample_data_template' do
before do
allow(project).to receive_message_chain(:import_data, :data, :dig).with('sample_data') { true }
end
it 'initialize SampleDataRelationTreeRestorer' do
expect_next_instance_of(Gitlab::ImportExport::Project::Sample::SampleDataRelationTreeRestorer) do |restorer|
expect(restorer).to receive(:restore).and_return(true)
end
expect(project_tree_restorer.restore).to eq(true)
end
end
context 'without sample_data_template' do
it 'initialize RelationTreeRestorer' do
expect_next_instance_of(Gitlab::ImportExport::RelationTreeRestorer) do |restorer|
expect(restorer).to receive(:restore).and_return(true)
end
expect(project_tree_restorer.restore).to eq(true)
end
end
end
end
context 'disable ndjson import' do
......
......@@ -10,15 +10,7 @@
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::RelationTreeRestorer do
include ImportExport::CommonUtil
let(:user) { create(:user) }
let(:shared) { Gitlab::ImportExport::Shared.new(importable) }
let(:attributes) { relation_reader.consume_attributes(importable_name) }
let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new(exported_members: {}, user: user, importable: importable)
end
include_context 'relation tree restorer shared context'
let(:relation_tree_restorer) do
described_class.new(
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::SampleDataTemplate do
describe '.all' do
it 'returns all templates' do
expected = %w[
basic
serenity_valley
]
expect(described_class.all).to be_an(Array)
expect(described_class.all.map(&:name)).to match_array(expected)
end
end
describe '.find' do
subject { described_class.find(query) }
context 'when there is a match' do
let(:query) { :basic }
it { is_expected.to be_a(described_class) }
end
context 'when there is no match' do
let(:query) { 'no-match' }
it { is_expected.to be(nil) }
end
end
describe '.archive_directory' do
subject { described_class.archive_directory }
it { is_expected.to be_a Pathname }
end
describe 'validate all templates' do
let_it_be(:admin) { create(:admin) }
described_class.all.each do |template|
it "#{template.name} has a valid archive" do
archive = template.archive_path
expect(File.exist?(archive)).to be(true)
end
context 'with valid parameters' do
it 'can be imported' do
params = {
template_name: template.name,
namespace_id: admin.namespace.id,
path: template.name
}
project = Projects::CreateFromTemplateService.new(admin, params).execute
expect(project).to be_valid
expect(project).to be_persisted
end
end
end
end
end
# frozen_string_literal: true
RSpec.shared_context 'relation tree restorer shared context' do
include ImportExport::CommonUtil
let(:user) { create(:user) }
let(:shared) { Gitlab::ImportExport::Shared.new(importable) }
let(:attributes) { relation_reader.consume_attributes(importable_name) }
let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new(exported_members: {}, user: user, importable: importable)
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