Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-04-27 09:09:51 +00:00
parent a59d305223
commit 39fa1b5987
64 changed files with 731 additions and 235 deletions

View File

@ -11,6 +11,10 @@ class Projects::RefsController < Projects::ApplicationController
before_action :assign_ref_vars
before_action :authorize_download_code!
before_action only: [:logs_tree] do
push_frontend_feature_flag(:vue_file_list_lfs_badge)
end
def switch
respond_to do |format|
format.html do

View File

@ -17,7 +17,7 @@ module BlobHelper
options[:link_opts])
end
def ide_edit_path(project = @project, ref = @ref, path = @path, options = {})
def ide_edit_path(project = @project, ref = @ref, path = @path)
project_path =
if !current_user || can?(current_user, :push_code, project)
project.full_path
@ -52,28 +52,25 @@ module BlobHelper
edit_button_tag(blob,
common_classes,
_('Edit'),
Feature.enabled?(:web_ide_default) ? ide_edit_path(project, ref, path, options) : edit_blob_path(project, ref, path, options),
Feature.enabled?(:web_ide_default) ? ide_edit_path(project, ref, path) : edit_blob_path(project, ref, path, options),
project,
ref)
end
def ide_edit_button(project = @project, ref = @ref, path = @path, options = {})
def ide_edit_button(project = @project, ref = @ref, path = @path, blob:)
return if Feature.enabled?(:web_ide_default)
return unless blob = readable_blob(options, path, project, ref)
return unless blob
edit_button_tag(blob,
'btn btn-inverted btn-primary ide-edit-button ml-2',
_('Web IDE'),
ide_edit_path(project, ref, path, options),
ide_edit_path(project, ref, path),
project,
ref)
end
def modify_file_button(project = @project, ref = @ref, path = @path, label:, action:, btn_class:, modal_type:)
def modify_file_button(project = @project, ref = @ref, path = @path, blob:, label:, action:, btn_class:, modal_type:)
return unless current_user
blob = project.repository.blob_at(ref, path) rescue nil
return unless blob
common_classes = "btn btn-#{btn_class}"
@ -89,11 +86,12 @@ module BlobHelper
end
end
def replace_blob_link(project = @project, ref = @ref, path = @path)
def replace_blob_link(project = @project, ref = @ref, path = @path, blob:)
modify_file_button(
project,
ref,
path,
blob: blob,
label: _("Replace"),
action: "replace",
btn_class: "default",
@ -101,11 +99,12 @@ module BlobHelper
)
end
def delete_blob_link(project = @project, ref = @ref, path = @path)
def delete_blob_link(project = @project, ref = @ref, path = @path, blob:)
modify_file_button(
project,
ref,
path,
blob: blob,
label: _("Delete"),
action: "delete",
btn_class: "default",

View File

@ -3,7 +3,18 @@
module InternalIdEnums
def self.usage_resources
# when adding new resource, make sure it doesn't conflict with EE usage_resources
{ issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4, ci_pipelines: 5, operations_feature_flags: 6, operations_user_lists: 7, alert_management_alerts: 8 }
{
issues: 0,
merge_requests: 1,
deployments: 2,
milestones: 3,
epics: 4,
ci_pipelines: 5,
operations_feature_flags: 6,
operations_user_lists: 7,
alert_management_alerts: 8,
sprints: 9
}
end
end

View File

@ -31,6 +31,7 @@ class Issue < ApplicationRecord
belongs_to :project
belongs_to :duplicated_to, class_name: 'Issue'
belongs_to :closed_by, class_name: 'User'
belongs_to :sprint
belongs_to :moved_to, class_name: 'Issue'
has_one :moved_from, class_name: 'Issue', foreign_key: :moved_to_id

View File

@ -32,6 +32,7 @@ class MergeRequest < ApplicationRecord
belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project"
belongs_to :merge_user, class_name: "User"
belongs_to :sprint
has_internal_id :iid, scope: :target_project, track_if: -> { !importing? }, init: ->(s) { s&.target_project&.merge_requests&.maximum(:iid) }

View File

@ -1,6 +1,19 @@
# frozen_string_literal: true
class Sprint < ApplicationRecord
STATE_ID_MAP = {
active: 1,
closed: 2
}.with_indifferent_access.freeze
include AtomicInternalId
has_many :issues
has_many :merge_requests
belongs_to :project
belongs_to :group
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.sprints&.maximum(:iid) }
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.sprints&.maximum(:iid) }
end

View File

@ -4,13 +4,13 @@
.file-actions<
= render 'projects/blob/viewer_switcher', blob: blob unless blame
= edit_blob_button
= ide_edit_button
= edit_blob_button(@project, @ref, @path, blob: blob)
= ide_edit_button(@project, @ref, @path, blob: blob)
.btn-group.ml-2{ role: "group" }>
= render_if_exists 'projects/blob/header_file_locks_link'
- if current_user
= replace_blob_link
= delete_blob_link
= replace_blob_link(@project, @ref, @path, blob: blob)
= delete_blob_link(@project, @ref, @path, blob: blob)
.btn-group.ml-2{ role: "group" }
= copy_blob_source_button(blob) unless blame
= open_raw_blob_button(blob)

View File

@ -19,6 +19,10 @@
%li
.monospace
= File.basename(file)
- if File.dirname(file).ends_with?('plugins')
.text-warning
= _('Plugins directory is deprecated and will be removed in 14.0. Please move this file into /file_hooks directory.')
- else
.card.bg-light.text-center
.nothing-here-block= _('No file hooks found.')

View File

@ -0,0 +1,5 @@
---
title: Flesh out Sprints relationships and constraints
merge_request: 30127
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Map labels from Jira to labels in GitLab
merge_request: 29970
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add clusters index to improve usage data queries
merge_request: 28626
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Deprecate /plugins directory
merge_request: 29678
author:
type: deprecated

View File

@ -0,0 +1,5 @@
---
title: Add LFS badge feature flag to RefsController#logs_tree
merge_request: 30442
author:
type: fixed

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class AddSprintToIssues < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
with_lock_retries do
# index will be added in another migration with `add_concurrent_index`
add_column :issues, :sprint_id, :bigint
end
end
def down
with_lock_retries do
remove_column :issues, :sprint_id
end
end
end

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class AddSprintToMergeRequests < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
with_lock_retries do
# index will be added in another migration with `add_concurrent_index`
add_column :merge_requests, :sprint_id, :bigint
end
end
def down
with_lock_retries do
remove_column :merge_requests, :sprint_id
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddSprintIdIndexToIssues < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :issues, :sprint_id
add_concurrent_foreign_key :issues, :sprints, column: :sprint_id
end
def down
with_lock_retries do # rubocop:disable Migration/WithLockRetriesWithoutDdlTransaction
remove_foreign_key :issues, column: :sprint_id
end
remove_concurrent_index :issues, :sprint_id
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddSprintIdIndexToMergeRequests < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :merge_requests, :sprint_id
add_concurrent_foreign_key :merge_requests, :sprints, column: :sprint_id
end
def down
with_lock_retries do # rubocop:disable Migration/WithLockRetriesWithoutDdlTransaction
remove_foreign_key :merge_requests, column: :sprint_id
end
remove_concurrent_index :merge_requests, :sprint_id
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AddClusterTypeIndexToClusters < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
INDEX_NAME = 'index_clusters_on_enabled_cluster_type_id_and_created_at'
disable_ddl_transaction!
def up
add_concurrent_index :clusters, [:enabled, :cluster_type, :id, :created_at], name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :clusters, INDEX_NAME
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AddCheckConstraintToSprintMustBelongToProjectOrGroup < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
CONSTRAINT_NAME = 'sprints_must_belong_to_project_or_group'
def up
add_check_constraint :sprints, '(project_id != NULL AND group_id IS NULL) OR (group_id != NULL AND project_id IS NULL)', CONSTRAINT_NAME
end
def down
remove_check_constraint :sprints, CONSTRAINT_NAME
end
end

View File

@ -3357,7 +3357,8 @@ CREATE TABLE public.issues (
duplicated_to_id integer,
promoted_to_epic_id integer,
health_status smallint,
external_key character varying(255)
external_key character varying(255),
sprint_id bigint
);
CREATE SEQUENCE public.issues_id_seq
@ -3932,7 +3933,8 @@ CREATE TABLE public.merge_requests (
allow_maintainer_to_push boolean,
state_id smallint DEFAULT 1 NOT NULL,
rebase_jid character varying,
squash_commit_sha bytea
squash_commit_sha bytea,
sprint_id bigint
);
CREATE TABLE public.merge_requests_closing_issues (
@ -6106,6 +6108,7 @@ CREATE TABLE public.sprints (
title_html text,
description text,
description_html text,
CONSTRAINT sprints_must_belong_to_project_or_group CHECK ((((project_id <> NULL::bigint) AND (group_id IS NULL)) OR ((group_id <> NULL::bigint) AND (project_id IS NULL)))),
CONSTRAINT sprints_title CHECK ((char_length(title) <= 255))
);
@ -9208,6 +9211,8 @@ CREATE INDEX index_clusters_kubernetes_namespaces_on_project_id ON public.cluste
CREATE INDEX index_clusters_on_enabled_and_provider_type_and_id ON public.clusters USING btree (enabled, provider_type, id);
CREATE INDEX index_clusters_on_enabled_cluster_type_id_and_created_at ON public.clusters USING btree (enabled, cluster_type, id, created_at);
CREATE INDEX index_clusters_on_management_project_id ON public.clusters USING btree (management_project_id) WHERE (management_project_id IS NOT NULL);
CREATE INDEX index_clusters_on_user_id ON public.clusters USING btree (user_id);
@ -9598,6 +9603,8 @@ CREATE INDEX index_issues_on_promoted_to_epic_id ON public.issues USING btree (p
CREATE INDEX index_issues_on_relative_position ON public.issues USING btree (relative_position);
CREATE INDEX index_issues_on_sprint_id ON public.issues USING btree (sprint_id);
CREATE INDEX index_issues_on_title_trigram ON public.issues USING gin (title public.gin_trgm_ops);
CREATE INDEX index_issues_on_updated_at ON public.issues USING btree (updated_at);
@ -9760,6 +9767,8 @@ CREATE INDEX index_merge_requests_on_source_branch ON public.merge_requests USIN
CREATE INDEX index_merge_requests_on_source_project_id_and_source_branch ON public.merge_requests USING btree (source_project_id, source_branch);
CREATE INDEX index_merge_requests_on_sprint_id ON public.merge_requests USING btree (sprint_id);
CREATE INDEX index_merge_requests_on_target_branch ON public.merge_requests USING btree (target_branch);
CREATE UNIQUE INDEX index_merge_requests_on_target_project_id_and_iid ON public.merge_requests USING btree (target_project_id, iid);
@ -10849,6 +10858,9 @@ ALTER TABLE ONLY public.push_event_payloads
ALTER TABLE ONLY public.ci_builds
ADD CONSTRAINT fk_3a9eaa254d FOREIGN KEY (stage_id) REFERENCES public.ci_stages(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.issues
ADD CONSTRAINT fk_3b8c72ea56 FOREIGN KEY (sprint_id) REFERENCES public.sprints(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.epics
ADD CONSTRAINT fk_3c1fd1cccc FOREIGN KEY (due_date_sourcing_milestone_id) REFERENCES public.milestones(id) ON DELETE SET NULL;
@ -10966,6 +10978,9 @@ ALTER TABLE ONLY public.vulnerabilities
ALTER TABLE ONLY public.labels
ADD CONSTRAINT fk_7de4989a69 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.merge_requests
ADD CONSTRAINT fk_7e85395a64 FOREIGN KEY (sprint_id) REFERENCES public.sprints(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.merge_request_metrics
ADD CONSTRAINT fk_7f28d925f3 FOREIGN KEY (merged_by_id) REFERENCES public.users(id) ON DELETE SET NULL;
@ -13285,6 +13300,10 @@ COPY "schema_migrations" (version) FROM STDIN;
20200303055348
20200303074328
20200303181648
20200304023245
20200304023851
20200304024025
20200304024042
20200304085423
20200304090155
20200304121828
@ -13394,6 +13413,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200401091051
20200401095430
20200401211005
20200402001106
20200402123926
20200402124802
20200402135250
@ -13457,6 +13477,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200420172113
20200420172752
20200420172927
20200420201933
20200421233150
20200423075720
20200423080334

View File

@ -190,6 +190,7 @@ excluded_attributes:
- :merge_request_diff_id
issues:
- :milestone_id
- :sprint_id
- :moved_to_id
- :sent_notifications
- :state_id
@ -197,6 +198,7 @@ excluded_attributes:
- :promoted_to_epic_id
merge_request:
- :milestone_id
- :sprint_id
- :ref_fetched
- :merge_jid
- :rebase_jid
@ -205,6 +207,7 @@ excluded_attributes:
- :state_id
merge_requests:
- :milestone_id
- :sprint_id
- :ref_fetched
- :merge_jid
- :rebase_jid

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
module Gitlab
module JiraImport
class HandleLabelsService
def initialize(project, jira_labels)
@project = project
@jira_labels = jira_labels
end
def execute
return if jira_labels.blank?
existing_labels = LabelsFinder.new(nil, project: project, title: jira_labels)
.execute(skip_authorization: true).select(:id, :name)
new_labels = create_missing_labels(existing_labels)
label_ids = existing_labels.map(&:id)
label_ids += new_labels if new_labels.present?
label_ids
end
private
attr_reader :project, :jira_labels
def create_missing_labels(existing_labels)
labels_to_create = jira_labels - existing_labels.map(&:name)
return if labels_to_create.empty?
new_labels_hash = labels_to_create.map do |title|
{ project_id: project.id, title: title, type: 'ProjectLabel' }
end
Label.insert_all(new_labels_hash).rows.flatten
end
end
end
end

View File

@ -21,7 +21,8 @@ module Gitlab
state_id: map_status(jira_issue.status.statusCategory),
updated_at: jira_issue.updated,
created_at: jira_issue.created,
author_id: project.creator_id # TODO: map actual author: https://gitlab.com/gitlab-org/gitlab/-/issues/210580
author_id: project.creator_id, # TODO: map actual author: https://gitlab.com/gitlab-org/gitlab/-/issues/210580
label_ids: label_ids
}
end
@ -49,6 +50,15 @@ module Gitlab
Issuable::STATE_ID_MAP[:opened]
end
end
# We already create labels in Gitlab::JiraImport::LabelsImporter stage but
# there is a possibility it may fail or
# new labels were created on the Jira in the meantime
def label_ids
return if jira_issue.fields['labels'].blank?
Gitlab::JiraImport::HandleLabelsService.new(project, jira_issue.fields['labels']).execute
end
end
end
end

View File

@ -5,6 +5,8 @@ module Gitlab
class LabelsImporter < BaseImporter
attr_reader :job_waiter
MAX_LABELS = 500
def initialize(project)
super
@job_waiter = JobWaiter.new
@ -25,9 +27,29 @@ module Gitlab
end
def import_jira_labels
# todo: import jira labels, see https://gitlab.com/gitlab-org/gitlab/-/issues/212651
start_at = 0
loop do
break if process_jira_page(start_at)
start_at += MAX_LABELS
end
job_waiter
end
def process_jira_page(start_at)
request = "/rest/api/2/label?maxResults=#{MAX_LABELS}&startAt=#{start_at}"
response = JSON.parse(client.get(request))
return true if response['values'].blank?
return true unless response.key?('isLast')
Gitlab::JiraImport::HandleLabelsService.new(project, response['values']).execute
response['isLast']
rescue => e
Gitlab::ErrorTracking.track_exception(e, project_id: project.id, request: request)
end
end
end
end

View File

@ -13,7 +13,6 @@ module Gitlab
def execute
add_field(%w(issuetype name), 'Issue type')
add_field(%w(priority name), 'Priority')
add_labels
add_field('environment', 'Environment')
add_field('duedate', 'Due date')
add_parent
@ -33,12 +32,6 @@ module Gitlab
metadata << "- #{field_label}: #{value}"
end
def add_labels
return if fields['labels'].blank? || !fields['labels'].is_a?(Array)
metadata << "- Labels: #{fields['labels'].join(', ')}"
end
def add_parent
parent_issue_key = fields.dig('parent', 'key')

View File

@ -24,6 +24,7 @@ module Gitlab
end
def ensure_deadline_not_exceeded!
return unless enabled?
return unless request_deadline
return if Gitlab::Metrics::System.real_time < request_deadline
@ -36,5 +37,9 @@ module Gitlab
def max_request_duration_seconds
Settings.gitlab.max_request_duration_seconds
end
def enabled?
!Rails.env.test?
end
end
end

View File

@ -4,6 +4,11 @@ namespace :file_hooks do
puts 'Validating file hooks from /file_hooks and /plugins directories'
Gitlab::FileHook.files.each do |file|
if File.dirname(file).ends_with?('plugins')
puts 'DEPRECATED: /plugins directory is deprecated and will be removed in 14.0. ' \
'Please move your files into /file_hooks directory.'
end
success, message = Gitlab::FileHook.execute(file, Gitlab::DataBuilder::Push::SAMPLE_DATA)
if success

View File

@ -8834,6 +8834,12 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
msgid "Failed to load labels. Please try again."
msgstr ""
msgid "Failed to load milestones. Please try again."
msgstr ""
msgid "Failed to load related branches"
msgstr ""
@ -15190,6 +15196,9 @@ msgstr ""
msgid "Please wait while we import the repository for you. Refresh at will."
msgstr ""
msgid "Plugins directory is deprecated and will be removed in 14.0. Please move this file into /file_hooks directory."
msgstr ""
msgid "Pod does not exist"
msgstr ""

View File

@ -84,7 +84,7 @@ describe SearchController do
with_them do
it do
project_wiki = create(:project_wiki, project: project, user: user)
create(:wiki_page, wiki: project_wiki, attrs: { title: 'merge', content: 'merge' })
create(:wiki_page, wiki: project_wiki, title: 'merge', content: 'merge')
expect(subject).to render_template("search/results/#{partial}")
end

48
spec/factories/sprints.rb Normal file
View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
FactoryBot.define do
factory :sprint do
title
transient do
project { nil }
group { nil }
project_id { nil }
group_id { nil }
resource_parent { nil }
end
trait :active do
state { Sprint::STATE_ID_MAP[:active] }
end
trait :closed do
state { Sprint::STATE_ID_MAP[:closed] }
end
trait :with_dates do
start_date { Date.new(2000, 1, 1) }
due_date { Date.new(2000, 1, 30) }
end
after(:build, :stub) do |sprint, evaluator|
if evaluator.group
sprint.group = evaluator.group
elsif evaluator.group_id
sprint.group_id = evaluator.group_id
elsif evaluator.project
sprint.project = evaluator.project
elsif evaluator.project_id
sprint.project_id = evaluator.project_id
elsif evaluator.resource_parent
id = evaluator.resource_parent.id
evaluator.resource_parent.is_a?(Group) ? evaluator.group_id = id : evaluator.project_id = id
else
sprint.project = create(:project)
end
end
factory :active_sprint, traits: [:active]
factory :closed_sprint, traits: [:closed]
end
end

View File

@ -7,11 +7,17 @@ FactoryBot.define do
transient do
title { generate(:wiki_page_title) }
content { 'Content for wiki page' }
format { 'markdown' }
format { :markdown }
message { nil }
project { association(:project, :wiki_repo) }
container { project }
attrs do
{
wiki { association(:wiki, container: container) }
page { OpenStruct.new(url_path: title) }
end
initialize_with do
new(wiki, page).tap do |page|
page.attributes = {
title: title,
content: content,
format: format
@ -19,25 +25,13 @@ FactoryBot.define do
end
end
page { OpenStruct.new(url_path: 'some-name') }
wiki { association(:wiki, container: container) }
initialize_with { new(wiki, page) }
before(:create) do |page, evaluator|
page.attributes = evaluator.attrs
# Clear our default @page, except when using build_stubbed
after(:build) do |page|
page.instance_variable_set('@page', nil)
end
to_create do |page|
page.create
end
trait :with_real_page do
page do
wiki.create_page(title, content)
page_title, page_dir = wiki.page_title_and_dir(title)
wiki.wiki.page(title: page_title, dir: page_dir, version: nil)
end
to_create do |page, evaluator|
page.create(message: evaluator.message)
end
end

View File

@ -36,6 +36,24 @@ describe 'Admin::Hooks' do
expect(page).to have_content('foo.rb')
expect(page).to have_content('bar.clj')
end
context 'deprecation warning' do
it 'shows warning for plugins directory' do
allow(Gitlab::FileHook).to receive(:files).and_return(['plugins/foo.rb'])
visit admin_hooks_path
expect(page).to have_content('Plugins directory is deprecated and will be removed in 14.0')
end
it 'does not show warning for file_hooks directory' do
allow(Gitlab::FileHook).to receive(:files).and_return(['file_hooks/foo.rb'])
visit admin_hooks_path
expect(page).not_to have_content('Plugins directory is deprecated and will be removed in 14.0')
end
end
end
describe 'New Hook' do

View File

@ -5,7 +5,7 @@ require 'spec_helper'
describe 'Projects > Wiki > User previews markdown changes', :js do
let_it_be(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' }) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') }
let(:wiki_content) do
<<-HEREDOC
[regular link](regular)

View File

@ -5,7 +5,7 @@ require 'spec_helper'
describe 'Wiki shortcuts', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: 'Home page' }) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: 'Home page') }
before do
sign_in(user)

View File

@ -195,7 +195,7 @@ describe "User creates wiki page" do
context "when wiki is not empty", :js do
before do
create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'Home page' })
create(:wiki_page, wiki: wiki, title: 'home', content: 'Home page')
visit(project_wikis_path(project))
end
@ -304,8 +304,8 @@ describe "User creates wiki page" do
describe 'sidebar feature' do
context 'when there are some existing pages' do
before do
create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'home' })
create(:wiki_page, wiki: wiki, attrs: { title: 'another', content: 'another' })
create(:wiki_page, wiki: wiki, title: 'home', content: 'home')
create(:wiki_page, wiki: wiki, title: 'another', content: 'another')
end
it 'renders a default sidebar when there is no customized sidebar' do
@ -316,7 +316,7 @@ describe "User creates wiki page" do
context 'when there is a customized sidebar' do
before do
create(:wiki_page, wiki: wiki, attrs: { title: '_sidebar', content: 'My customized sidebar' })
create(:wiki_page, wiki: wiki, title: '_sidebar', content: 'My customized sidebar')
end
it 'renders my customized sidebar instead of the default one' do
@ -330,8 +330,8 @@ describe "User creates wiki page" do
context 'when there are more than 15 existing pages' do
before do
create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'home' })
(1..14).each { |i| create(:wiki_page, wiki: wiki, attrs: { title: "page-#{i}", content: "page #{i}" }) }
create(:wiki_page, wiki: wiki, title: 'home', content: 'home')
(1..14).each { |i| create(:wiki_page, wiki: wiki, title: "page-#{i}", content: "page #{i}") }
end
it 'renders a default sidebar when there is no customized sidebar' do

View File

@ -5,7 +5,7 @@ require 'spec_helper'
describe 'Projects > Wiki > User views Git access wiki page' do
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, :public) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' }) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') }
before do
sign_in(user)

View File

@ -64,7 +64,7 @@ describe 'User updates wiki page' do
context 'when wiki is not empty' do
let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: 'home', content: 'Home page' }) }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: 'home', content: 'Home page') }
before do
visit(project_wikis_path(project))
@ -168,7 +168,7 @@ describe 'User updates wiki page' do
let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
let(:page_name) { 'page_name' }
let(:page_dir) { "foo/bar/#{page_name}" }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: page_dir, content: 'Home page' }) }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: page_dir, content: 'Home page') }
before do
visit(project_wiki_edit_path(project, wiki_page))

View File

@ -21,7 +21,7 @@ describe 'Projects > Wiki > User views wiki in project page' do
context 'when wiki homepage contains a link' do
before do
create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' })
create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)')
end
it 'displays the correct URL for the link' do

View File

@ -11,7 +11,7 @@ describe 'User views a wiki page' do
let(:wiki_page) do
create(:wiki_page,
wiki: project.wiki,
attrs: { title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" })
title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})")
end
before do

View File

@ -9,13 +9,13 @@ describe 'User views wiki pages' do
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let!(:wiki_page1) do
create(:wiki_page, wiki: project.wiki, attrs: { title: '3 home', content: '3' })
create(:wiki_page, wiki: project.wiki, title: '3 home', content: '3')
end
let!(:wiki_page2) do
create(:wiki_page, wiki: project.wiki, attrs: { title: '1 home', content: '1' })
create(:wiki_page, wiki: project.wiki, title: '1 home', content: '1')
end
let!(:wiki_page3) do
create(:wiki_page, wiki: project.wiki, attrs: { title: '2 home', content: '2' })
create(:wiki_page, wiki: project.wiki, title: '2 home', content: '2')
end
let(:pages) do

View File

@ -16,7 +16,7 @@ describe 'User views AsciiDoc page with includes', :js do
format: :asciidoc
}
create(:wiki_page, wiki: project.wiki, attrs: attrs)
create(:wiki_page, wiki: project.wiki, **attrs)
end
before do

View File

@ -5,7 +5,7 @@ require 'spec_helper'
describe 'User searches for wiki pages', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'directory/title', content: 'Some Wiki content' }) }
let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'directory/title', content: 'Some Wiki content') }
before do
project.add_maintainer(user)

View File

@ -57,7 +57,7 @@ describe Banzai::Pipeline::WikiPipeline do
let(:namespace) { create(:namespace, name: "wiki_link_ns") }
let(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
let(:project_wiki) { ProjectWiki.new(project, double(:user)) }
let(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
let(:page) { build(:wiki_page, wiki: project_wiki, title: 'nested/twice/start-page') }
{ 'when GitLab is hosted at a root URL' => '',
'when GitLab is hosted at a relative URL' => '/nested/relative/gitlab' }.each do |test_name, relative_url_root|
@ -264,7 +264,7 @@ describe Banzai::Pipeline::WikiPipeline do
let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") }
let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
let_it_be(:project_wiki) { ProjectWiki.new(project, double(:user)) }
let_it_be(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
let_it_be(:page) { build(:wiki_page, wiki: project_wiki, title: 'nested/twice/start-page') }
it 'generates video html structure' do
markdown = "![video_file](video_file_name.mp4)"

View File

@ -6,6 +6,7 @@ issues:
- assignees
- updated_by
- milestone
- sprint
- notes
- resource_label_events
- resource_weight_events
@ -113,6 +114,7 @@ merge_requests:
- assignee
- updated_by
- milestone
- sprint
- notes
- resource_label_events
- resource_milestone_events

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::JiraImport::HandleLabelsService do
describe '#execute' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:project_label) { create(:label, project: project, title: 'bug') }
let_it_be(:other_project_label) { create(:label, title: 'feature') }
let_it_be(:group_label) { create(:group_label, group: group, title: 'dev') }
let(:jira_labels) { %w(bug feature dev group::new) }
subject { described_class.new(project, jira_labels).execute }
context 'when some provided jira labels are missing' do
def created_labels
project.labels.reorder(id: :desc).first(2)
end
it 'creates the missing labels on the project level' do
expect { subject }.to change { Label.count }.from(3).to(5)
expect(created_labels.map(&:title)).to match_array(%w(feature group::new))
end
it 'returns the id of all labels matching the title' do
expect(subject).to match_array([project_label.id, group_label.id] + created_labels.map(&:id))
end
end
context 'when no provided jira labels are missing' do
let(:jira_labels) { %w(bug dev) }
it 'does not create any new labels' do
expect { subject }.not_to change { Label.count }.from(3)
end
it 'returns the id of all labels matching the title' do
expect(subject).to match_array([project_label.id, group_label.id])
end
end
context 'when no labels are provided' do
let(:jira_labels) { [] }
it 'does not create any new labels' do
expect { subject }.not_to change { Label.count }.from(3)
end
end
end
end

View File

@ -4,7 +4,11 @@ require 'spec_helper'
describe Gitlab::JiraImport::IssueSerializer do
describe '#execute' do
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:project_label) { create(:label, project: project, title: 'bug') }
let_it_be(:other_project_label) { create(:label, project: project, title: 'feature') }
let_it_be(:group_label) { create(:group_label, group: group, title: 'dev') }
let(:iid) { 5 }
let(:key) { 'PROJECT-5' }
@ -19,11 +23,13 @@ describe Gitlab::JiraImport::IssueSerializer do
{ 'key' => 'FOO-2', 'id' => '1050', 'fields' => { 'summary' => 'parent issue FOO' } }
end
let(:priority_field) { { 'name' => 'Medium' } }
let(:labels_field) { %w(bug dev backend frontend) }
let(:fields) do
{
'parent' => parent_field,
'priority' => priority_field
'priority' => priority_field,
'labels' => labels_field
}
end
@ -73,9 +79,33 @@ describe Gitlab::JiraImport::IssueSerializer do
state_id: 1,
updated_at: updated_at,
created_at: created_at,
author_id: project.creator_id
author_id: project.creator_id,
label_ids: [project_label.id, group_label.id] + Label.reorder(id: :asc).last(2).pluck(:id)
)
end
it 'creates a hash for valid issue' do
expect(Issue.new(subject)).to be_valid
end
it 'creates all missing labels (on project level)' do
expect { subject }.to change { Label.count }.from(3).to(5)
expect(Label.find_by(title: 'frontend').project).to eq(project)
expect(Label.find_by(title: 'backend').project).to eq(project)
end
context 'when there are no new labels' do
let(:labels_field) { %w(bug dev) }
it 'assigns the labels to the Issue hash' do
expect(subject[:label_ids]).to match_array([project_label.id, group_label.id])
end
it 'does not create new labels' do
expect { subject }.not_to change { Label.count }.from(3)
end
end
end
context 'with done status' do

View File

@ -3,18 +3,23 @@
require 'spec_helper'
describe Gitlab::JiraImport::LabelsImporter do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:jira_service) { create(:jira_service, project: project) }
subject { described_class.new(project).execute }
before do
stub_feature_flags(jira_issue_import: true)
stub_const('Gitlab::JiraImport::LabelsImporter::MAX_LABELS', 2)
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/serverInfo')
.to_return(body: { url: 'http://url' }.to_json )
end
describe '#execute', :clean_gitlab_redis_cache do
context 'when label is missing from jira import' do
context 'when jira import label is missing from jira import' do
let_it_be(:no_label_jira_import) { create(:jira_import_state, label: nil, project: project) }
it 'raises error' do
@ -22,16 +27,71 @@ describe Gitlab::JiraImport::LabelsImporter do
end
end
context 'when label exists' do
let_it_be(:label) { create(:label) }
context 'when jira import label exists' do
let_it_be(:label) { create(:label) }
let_it_be(:jira_import_with_label) { create(:jira_import_state, label: label, project: project) }
let_it_be(:issue_label) { create(:label, project: project, title: 'bug') }
it 'caches import label' do
expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.import_label_cache_key(project.id))).to be nil
let(:jira_labels_1) { { "maxResults" => 2, "startAt" => 0, "total" => 3, "isLast" => false, "values" => %w(backend bug) } }
let(:jira_labels_2) { { "maxResults" => 2, "startAt" => 2, "total" => 3, "isLast" => true, "values" => %w(feature) } }
subject
before do
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/label?maxResults=2&startAt=0')
.to_return(body: jira_labels_1.to_json )
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/label?maxResults=2&startAt=2')
.to_return(body: jira_labels_2.to_json )
end
expect(Gitlab::JiraImport.get_import_label_id(project.id).to_i).to eq(label.id)
context 'when labels are returned from jira' do
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 eq(label.id)
end
it 'calls Gitlab::JiraImport::HandleLabelsService' do
expect(Gitlab::JiraImport::HandleLabelsService).to receive(:new).with(project, %w(backend bug)).and_return(double(execute: [1, 2]))
expect(Gitlab::JiraImport::HandleLabelsService).to receive(:new).with(project, %w(feature)).and_return(double(execute: [3]))
subject
end
end
context 'when there are no labels to be handled' do
shared_examples 'no labels handling' do
it 'does not call Gitlab::JiraImport::HandleLabelsService' do
expect(Gitlab::JiraImport::HandleLabelsService).not_to receive(:new)
subject
end
end
let(:jira_labels) { { "maxResults" => 2, "startAt" => 0, "total" => 3, "values" => [] } }
before do
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/label?maxResults=2&startAt=0')
.to_return(body: jira_labels.to_json )
end
context 'when the labels field is empty' do
let(:jira_labels) { { "maxResults" => 2, "startAt" => 0, "isLast" => true, "total" => 3, "values" => [] } }
it_behaves_like 'no labels handling'
end
context 'when the labels field is missing' do
let(:jira_labels) { { "maxResults" => 2, "startAt" => 0, "isLast" => true, "total" => 3 } }
it_behaves_like 'no labels handling'
end
context 'when the isLast argument is missing' do
let(:jira_labels) { { "maxResults" => 2, "startAt" => 0, "total" => 3, "values" => %w(bug dev) } }
it_behaves_like 'no labels handling'
end
end
end
end

View File

@ -9,7 +9,6 @@ describe Gitlab::JiraImport::MetadataCollector do
let(:description) { 'basic description' }
let(:created_at) { '2020-01-01 20:00:00' }
let(:updated_at) { '2020-01-10 20:00:00' }
let(:assignee) { double(displayName: 'Solver') }
let(:jira_status) { 'new' }
let(:parent_field) do
@ -18,7 +17,6 @@ describe Gitlab::JiraImport::MetadataCollector do
let(:issue_type_field) { { 'name' => 'Task' } }
let(:fix_versions_field) { [{ 'name' => '1.0' }, { 'name' => '1.1' }] }
let(:priority_field) { { 'name' => 'Medium' } }
let(:labels_field) { %w(bug backend) }
let(:environment_field) { 'staging' }
let(:duedate_field) { '2020-03-01' }
@ -28,7 +26,6 @@ describe Gitlab::JiraImport::MetadataCollector do
'issuetype' => issue_type_field,
'fixVersions' => fix_versions_field,
'priority' => priority_field,
'labels' => labels_field,
'environment' => environment_field,
'duedate' => duedate_field
}
@ -41,8 +38,6 @@ describe Gitlab::JiraImport::MetadataCollector do
description: description,
created: created_at,
updated: updated_at,
assignee: assignee,
reporter: double(displayName: 'Reporter'),
status: double(statusCategory: { 'key' => jira_status }),
fields: fields
)
@ -59,7 +54,6 @@ describe Gitlab::JiraImport::MetadataCollector do
- Issue type: Task
- Priority: Medium
- Labels: bug, backend
- Environment: staging
- Due date: 2020-03-01
- Parent issue: [FOO-2] parent issue FOO
@ -71,11 +65,9 @@ describe Gitlab::JiraImport::MetadataCollector do
end
context 'when some fields are in incorrect format' do
let(:assignee) { nil }
let(:parent_field) { nil }
let(:fix_versions_field) { [] }
let(:priority_field) { nil }
let(:labels_field) { [] }
let(:environment_field) { nil }
let(:duedate_field) { nil }
@ -112,22 +104,6 @@ describe Gitlab::JiraImport::MetadataCollector do
end
end
context 'when a labels field is not an array' do
let(:labels_field) { { 'first' => 'bug' } }
it 'skips the labels' do
expected_result = <<~MD
---
**Issue metadata**
- Issue type: Task
MD
expect(subject.strip).to eq(expected_result.strip)
end
end
context 'when a parent field has incorrectly formatted summary' do
let(:parent_field) do
{ 'key' => 'FOO-2', 'id' => '1050', 'other_field' => { 'summary' => 'parent issue FOO' } }
@ -167,10 +143,8 @@ describe Gitlab::JiraImport::MetadataCollector do
end
context 'when some metadata fields are missing' do
let(:assignee) { nil }
let(:parent_field) { nil }
let(:fix_versions_field) { [] }
let(:labels_field) { [] }
let(:environment_field) { nil }
it 'skips the missing fields' do
@ -189,12 +163,10 @@ describe Gitlab::JiraImport::MetadataCollector do
end
context 'when all metadata fields are missing' do
let(:assignee) { nil }
let(:parent_field) { nil }
let(:issue_type_field) { nil }
let(:fix_versions_field) { [] }
let(:priority_field) { nil }
let(:labels_field) { [] }
let(:environment_field) { nil }
let(:duedate_field) { nil }

View File

@ -5,6 +5,10 @@ require 'spec_helper'
describe Gitlab::RequestContext, :request_store do
subject { described_class.instance }
before do
allow(subject).to receive(:enabled?).and_return(true)
end
it { is_expected.to have_attributes(client_ip: nil, start_thread_cpu_time: nil, request_start_time: nil) }
describe '#request_deadline' do

View File

@ -40,7 +40,7 @@ describe BlobViewer::Readme do
context 'when the wiki is not empty' do
before do
create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: 'Home page' })
create(:wiki_page, wiki: project.wiki, title: 'home', content: 'Home page')
end
it 'returns nil' do

View File

@ -490,7 +490,7 @@ describe Event do
context 'for a wiki page event' do
let(:wiki_page) do
create(:wiki_page, :with_real_page, project: project)
create(:wiki_page, project: project)
end
subject(:event) { create(:wiki_page_event, project: project, wiki_page: wiki_page) }

View File

@ -24,6 +24,8 @@ describe Group do
it { is_expected.to have_many(:cluster_groups).class_name('Clusters::Group') }
it { is_expected.to have_many(:clusters).class_name('Clusters::Cluster') }
it { is_expected.to have_many(:container_repositories) }
it { is_expected.to have_many(:milestones) }
it { is_expected.to have_many(:sprints) }
it_behaves_like 'model with wiki' do
let(:container) { create(:group, :nested, :wiki_repo) }

View File

@ -7,6 +7,7 @@ describe Issue do
describe "Associations" do
it { is_expected.to belong_to(:milestone) }
it { is_expected.to belong_to(:sprint) }
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:moved_to).class_name('Issue') }
it { is_expected.to have_one(:moved_from).class_name('Issue') }

View File

@ -18,6 +18,8 @@ describe MergeRequest do
it { is_expected.to have_many(:assignees).through(:merge_request_assignees) }
it { is_expected.to have_many(:merge_request_diffs) }
it { is_expected.to have_many(:user_mentions).class_name("MergeRequestUserMention") }
it { is_expected.to belong_to(:milestone) }
it { is_expected.to belong_to(:sprint) }
context 'for forks' do
let!(:project) { create(:project) }

View File

@ -121,7 +121,7 @@ describe MicrosoftTeamsService do
message: "user created page: Awesome wiki_page"
}
end
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: opts) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, **opts) }
let(:wiki_page_sample_data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
it "calls Microsoft Teams API" do

View File

@ -20,6 +20,7 @@ describe Project do
it { is_expected.to have_many(:merge_requests) }
it { is_expected.to have_many(:issues) }
it { is_expected.to have_many(:milestones) }
it { is_expected.to have_many(:sprints) }
it { is_expected.to have_many(:project_members).dependent(:delete_all) }
it { is_expected.to have_many(:users).through(:project_members) }
it { is_expected.to have_many(:requesters).dependent(:delete_all) }

View File

@ -0,0 +1,63 @@
# frozen_string_literal: true
require 'spec_helper'
describe Sprint do
let!(:project) { create(:project) }
let!(:group) { create(:group) }
describe 'modules' do
context 'with a project' do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:sprint, project: build(:project), group: nil) }
let(:scope) { :project }
let(:scope_attrs) { { project: instance.project } }
let(:usage) {:sprints }
end
end
context 'with a group' do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:sprint, project: nil, group: build(:group)) }
let(:scope) { :group }
let(:scope_attrs) { { namespace: instance.group } }
let(:usage) {:sprints }
end
end
end
describe "Associations" do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:group) }
it { is_expected.to have_many(:issues) }
it { is_expected.to have_many(:merge_requests) }
end
describe "#iid" do
it "is properly scoped on project and group" do
sprint1 = create(:sprint, project: project)
sprint2 = create(:sprint, project: project)
sprint3 = create(:sprint, group: group)
sprint4 = create(:sprint, group: group)
sprint5 = create(:sprint, project: project)
want = {
sprint1: 1,
sprint2: 2,
sprint3: 1,
sprint4: 2,
sprint5: 3
}
got = {
sprint1: sprint1.iid,
sprint2: sprint2.iid,
sprint3: sprint3.iid,
sprint4: sprint4.iid,
sprint5: sprint5.iid
}
expect(got).to eq(want)
end
end
end

View File

@ -6,17 +6,8 @@ describe WikiPage do
let_it_be(:user) { create(:user) }
let(:container) { create(:project, :wiki_repo) }
let(:wiki) { Wiki.for_container(container, user) }
let(:new_page) do
described_class.new(wiki).tap do |page|
page.attributes = { title: 'test page', content: 'test content' }
end
end
let(:existing_page) do
create_page('test page', 'test content')
wiki.find_page('test page')
end
let(:new_page) { build(:wiki_page, wiki: wiki, title: 'test page', content: 'test content') }
let(:existing_page) { create(:wiki_page, wiki: wiki, title: 'test page', content: 'test content', message: 'test commit') }
subject { new_page }
@ -41,13 +32,13 @@ describe WikiPage do
context 'when there are pages' do
before do
create_page('dir_1/dir_1_1/page_3', 'content')
create_page('page_1', 'content')
create_page('dir_1/page_2', 'content')
create_page('dir_2', 'page with dir name')
create_page('dir_2/page_5', 'content')
create_page('page_6', 'content')
create_page('dir_2/page_4', 'content')
wiki.create_page('dir_1/dir_1_1/page_3', 'content')
wiki.create_page('page_1', 'content')
wiki.create_page('dir_1/page_2', 'content')
wiki.create_page('dir_2', 'page with dir name')
wiki.create_page('dir_2/page_5', 'content')
wiki.create_page('page_6', 'content')
wiki.create_page('dir_2/page_4', 'content')
end
let(:page_1) { wiki.find_page('page_1') }
@ -353,7 +344,7 @@ describe WikiPage do
context 'with an existing page title exceeding the limit' do
subject do
title = 'a' * (max_title + 1)
create_page(title, 'content')
wiki.create_page(title, 'content')
wiki.find_page(title)
end
@ -397,6 +388,20 @@ describe WikiPage do
expect(wiki.find_page("Index").message).to eq 'Custom Commit Message'
end
it 'if the title is preceded by a / it is removed' do
subject.create(attributes.merge(title: '/New Page'))
expect(wiki.find_page('New Page')).not_to be_nil
end
end
context "with invalid attributes" do
it 'does not create the page' do
subject.create(title: '')
expect(wiki.find_page('New Page')).to be_nil
end
end
end
@ -419,14 +424,11 @@ describe WikiPage do
end
end
describe "#update" do
subject do
create_page(title, "content")
wiki.find_page(title)
end
describe '#update' do
subject { create(:wiki_page, wiki: wiki, title: title) }
it "updates the content of the page" do
subject.update(content: "new content")
it 'updates the content of the page' do
subject.update(content: 'new content')
page = wiki.find_page(title)
expect([subject.content, page.content]).to all(eq('new content'))
@ -438,24 +440,6 @@ describe WikiPage do
end
end
describe '#create' do
context 'with valid attributes' do
it 'raises an error if a page with the same path already exists' do
create_page('New Page', 'content')
create_page('foo/bar', 'content')
expect { create_page('New Page', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
expect { create_page('foo/bar', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
end
it 'if the title is preceded by a / it is removed' do
create_page('/New Page', 'content')
expect(wiki.find_page('New Page')).not_to be_nil
end
end
end
describe "#update" do
subject { existing_page }
@ -573,7 +557,7 @@ describe WikiPage do
context 'when renaming a page' do
it 'raises an error if the page already exists' do
create_page('Existing Page', 'content')
wiki.create_page('Existing Page', 'content')
expect { subject.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
expect(subject.title).to eq 'test page'
@ -595,7 +579,7 @@ describe WikiPage do
context 'when moving a page' do
it 'raises an error if the page already exists' do
create_page('foo/Existing Page', 'content')
wiki.create_page('foo/Existing Page', 'content')
expect { subject.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
expect(subject.title).to eq 'test page'
@ -615,10 +599,7 @@ describe WikiPage do
end
context 'in subdir' do
subject do
create_page('foo/Existing Page', 'content')
wiki.find_page('foo/Existing Page')
end
subject { create(:wiki_page, wiki: wiki, title: 'foo/Existing Page') }
it 'moves the page to the root folder if the title is preceded by /' do
expect(subject.slug).to eq 'foo/Existing-Page'
@ -656,7 +637,7 @@ describe WikiPage do
end
end
describe "#destroy" do
describe "#delete" do
subject { existing_page }
it "deletes the page" do
@ -688,10 +669,7 @@ describe WikiPage do
using RSpec::Parameterized::TableSyntax
let(:untitled_page) { described_class.new(wiki) }
let(:directory_page) do
create_page('parent directory/child page', 'test content')
wiki.find_page('parent directory/child page')
end
let(:directory_page) { create(:wiki_page, title: 'parent directory/child page') }
where(:page, :title, :changed) do
:untitled_page | nil | false
@ -754,10 +732,7 @@ describe WikiPage do
end
context 'when the page is inside an actual directory' do
subject do
create_page('dir_1/dir_1_1/file', 'content')
wiki.find_page('dir_1/dir_1_1/file')
end
subject { create(:wiki_page, title: 'dir_1/dir_1_1/file') }
it 'returns the full directory hierarchy' do
expect(subject.directory).to eq('dir_1/dir_1_1')
@ -804,6 +779,16 @@ describe WikiPage do
end
end
describe '#persisted?' do
it 'returns true for a persisted page' do
expect(existing_page).to be_persisted
end
it 'returns false for an unpersisted page' do
expect(new_page).not_to be_persisted
end
end
describe '#to_partial_path' do
it 'returns the relative path to the partial to be used' do
expect(subject.to_partial_path).to eq('projects/wikis/wiki_page')
@ -886,18 +871,6 @@ describe WikiPage do
private
def remove_temp_repo(path)
FileUtils.rm_rf path
end
def commit_details
Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "test commit")
end
def create_page(name, content)
wiki.wiki.write_page(name, :markdown, content, commit_details)
end
def get_slugs(page_or_dir)
if page_or_dir.is_a? WikiPage
[page_or_dir.slug]

View File

@ -401,7 +401,7 @@ describe API::Search do
context 'for wiki_blobs scope' do
before do
wiki = create(:project_wiki, project: project)
create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: "Awesome page" })
create(:wiki_page, wiki: wiki, title: 'home', content: "Awesome page")
get api("/projects/#{project.id}/search", user), params: { scope: 'wiki_blobs', search: 'awesome' }
end

View File

@ -25,8 +25,8 @@ describe API::Wikis do
shared_examples_for 'returns list of wiki pages' do
context 'when wiki has pages' do
let!(:pages) do
[create(:wiki_page, wiki: project_wiki, attrs: { title: 'page1', content: 'content of page1' }),
create(:wiki_page, wiki: project_wiki, attrs: { title: 'page2.with.dot', content: 'content of page2' })]
[create(:wiki_page, wiki: project_wiki, title: 'page1', content: 'content of page1'),
create(:wiki_page, wiki: project_wiki, title: 'page2.with.dot', content: 'content of page2')]
end
it 'returns the list of wiki pages without content' do

View File

@ -198,7 +198,7 @@ RSpec.shared_examples "chat service" do |service_name|
message: "user created page: Awesome wiki_page"
}
end
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: opts) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, **opts) }
let(:sample_data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, "create") }
it_behaves_like "triggered #{service_name} service"

View File

@ -112,7 +112,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
message: "user created page: Awesome wiki_page"
}
@wiki_page = create(:wiki_page, wiki: project.wiki, attrs: opts)
@wiki_page = create(:wiki_page, wiki: project.wiki, **opts)
@wiki_page_sample_data = Gitlab::DataBuilder::WikiPage.build(@wiki_page, user, 'create')
end

View File

@ -95,13 +95,14 @@ RSpec.shared_examples 'wiki model' do
let(:wiki_pages) { subject.list_pages }
before do
create_page('index', 'This is an index')
create_page('index2', 'This is an index2')
create_page('an index3', 'This is an index3')
subject.create_page('index', 'This is an index')
subject.create_page('index2', 'This is an index2')
subject.create_page('an index3', 'This is an index3')
end
it 'returns an array of WikiPage instances' do
expect(wiki_pages.first).to be_a WikiPage
expect(wiki_pages).to be_present
expect(wiki_pages).to all(be_a(WikiPage))
end
it 'does not load WikiPage content by default' do
@ -149,7 +150,7 @@ RSpec.shared_examples 'wiki model' do
describe '#find_page' do
before do
create_page('index page', 'This is an awesome Gollum Wiki')
subject.create_page('index page', 'This is an awesome Gollum Wiki')
end
it 'returns the latest version of the page if it exists' do
@ -176,7 +177,7 @@ RSpec.shared_examples 'wiki model' do
context 'pages with multibyte-character title' do
before do
create_page('autre pagé', "C'est un génial Gollum Wiki")
subject.create_page('autre pagé', "C'est un génial Gollum Wiki")
end
it 'can find a page by slug' do
@ -188,7 +189,7 @@ RSpec.shared_examples 'wiki model' do
context 'pages with invalidly-encoded content' do
before do
create_page('encoding is fun', "f\xFCr".b)
subject.create_page('encoding is fun', "f\xFCr".b)
end
it 'can find the page' do
@ -201,11 +202,11 @@ RSpec.shared_examples 'wiki model' do
describe '#find_sidebar' do
before do
create_page(described_class::SIDEBAR, 'This is an awesome Sidebar')
subject.create_page(described_class::SIDEBAR, 'This is an awesome Sidebar')
end
it 'finds the page defined as _sidebar' do
page = subject.find_page('_sidebar')
page = subject.find_sidebar
expect(page.content).to eq('This is an awesome Sidebar')
end
@ -284,58 +285,59 @@ RSpec.shared_examples 'wiki model' do
end
describe '#update_page' do
before do
create_page('update-page', 'some content')
@gitlab_git_wiki_page = subject.wiki.page(title: 'update-page')
let(:page) { create(:wiki_page, wiki: subject, title: 'update-page') }
def update_page
subject.update_page(
@gitlab_git_wiki_page,
page.page,
content: 'some other content',
format: :markdown,
message: 'updated page'
)
@page = subject.list_pages(load_content: true).first.page
end
it 'updates the content of the page' do
expect(@page.raw_data).to eq('some other content')
update_page
page = subject.find_page('update-page')
expect(page.raw_content).to eq('some other content')
end
it 'sets the correct commit message' do
expect(@page.version.message).to eq('updated page')
update_page
page = subject.find_page('update-page')
expect(page.version.message).to eq('updated page')
end
it 'sets the correct commit email' do
update_page
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it 'updates container activity' do
page
expect(subject).to receive(:update_container_activity)
subject.update_page(
@gitlab_git_wiki_page,
content: 'Yet more content',
format: :markdown,
message: 'Updated page again'
)
update_page
end
end
describe '#delete_page' do
before do
create_page('index', 'some content')
@page = subject.wiki.page(title: 'index')
end
let(:page) { create(:wiki_page, wiki: wiki) }
it 'deletes the page' do
subject.delete_page(@page)
subject.delete_page(page)
expect(subject.list_pages.count).to eq(0)
end
it 'sets the correct commit email' do
subject.delete_page(@page)
subject.delete_page(page)
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
@ -343,9 +345,11 @@ RSpec.shared_examples 'wiki model' do
end
it 'updates container activity' do
page
expect(subject).to receive(:update_container_activity)
subject.delete_page(@page)
subject.delete_page(page)
end
end
@ -378,23 +382,4 @@ RSpec.shared_examples 'wiki model' do
expect(subject.hook_attrs.keys).to contain_exactly(:web_url, :git_ssh_url, :git_http_url, :path_with_namespace, :default_branch)
end
end
private
def create_temp_repo(path)
FileUtils.mkdir_p path
system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path}))
end
def remove_temp_repo(path)
FileUtils.rm_rf path
end
def commit_details
Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.commit_email, 'test commit')
end
def create_page(name, content)
subject.wiki.write_page(name, :markdown, content, commit_details)
end
end

View File

@ -37,6 +37,9 @@ describe Gitlab::JiraImport::Stage::ImportLabelsWorker do
before do
jira_import.start!
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/label?maxResults=500&startAt=0')
.to_return(body: {}.to_json )
end
it_behaves_like 'advance to next stage', :issues