Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-05-26 12:08:22 +00:00
parent 27c6c4bf06
commit 1691cbe307
67 changed files with 796 additions and 827 deletions

View File

@ -15,4 +15,8 @@ gitlab_danger.rule_names.each do |file|
danger.import_dangerfile(path: File.join('danger', file))
end
markdown("**If needed, you can retry the [`danger-review` job](#{ENV['CI_JOB_URL']}) that generated this comment.**") if gitlab_danger.ci?
anything_to_post = status_report.values.any? { |data| data.any? }
if gitlab_danger.ci? && anything_to_post
markdown("**If needed, you can retry the [`danger-review` job](#{ENV['CI_JOB_URL']}) that generated this comment.**")
end

View File

@ -30,6 +30,11 @@ export default {
required: false,
default: SIMPLE_BLOB_VIEWER,
},
hasRenderError: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
@ -75,6 +80,7 @@ export default {
v-if="showDefaultActions"
:raw-path="blob.rawPath"
:active-viewer="viewer"
:has-render-error="hasRenderError"
@copy="proxyCopyRequest"
/>
</div>

View File

@ -27,6 +27,11 @@ export default {
default: SIMPLE_BLOB_VIEWER,
required: false,
},
hasRenderError: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
downloadUrl() {
@ -44,11 +49,13 @@ export default {
<template>
<gl-button-group>
<gl-deprecated-button
v-if="!hasRenderError"
v-gl-tooltip.hover
:aria-label="$options.BTN_COPY_CONTENTS_TITLE"
:title="$options.BTN_COPY_CONTENTS_TITLE"
:disabled="copyDisabled"
data-clipboard-target="#blob-code-content"
data-testid="copyContentsButton"
>
<gl-icon name="copy-to-clipboard" :size="14" />
</gl-deprecated-button>

View File

@ -74,6 +74,9 @@ export default {
canBeCloned() {
return this.snippet.sshUrlToRepo || this.snippet.httpUrlToRepo;
},
hasRenderError() {
return Boolean(this.viewer.renderError);
},
},
methods: {
switchViewer(newViewer) {
@ -92,7 +95,12 @@ export default {
<div>
<blob-embeddable v-if="embeddable" class="mb-3" :url="snippet.webUrl" />
<article class="file-holder snippet-file-content">
<blob-header :blob="blob" :active-viewer-type="viewer.type" @viewer-changed="switchViewer">
<blob-header
:blob="blob"
:active-viewer-type="viewer.type"
:has-render-error="hasRenderError"
@viewer-changed="switchViewer"
>
<template #actions>
<clone-dropdown-button
v-if="canBeCloned"

View File

@ -127,7 +127,7 @@ export default {
</button>
<span v-if="!rebasingError" class="bold">{{
__(
'Fast-forward merge is not possible. Rebase the source branch onto the target branch or merge target branch into source branch to allow this merge request to be merged.',
'Fast-forward merge is not possible. Rebase the source branch onto the target branch.',
)
}}</span>
<span v-else class="bold danger">{{ rebasingError }}</span>

View File

@ -425,7 +425,6 @@ img.emoji {
.append-right-32 { margin-right: 32px; }
.append-right-48 { margin-right: 48px; }
.prepend-right-32 { margin-right: 32px; }
.append-bottom-2 { margin-bottom: 2px; }
.append-bottom-4 { margin-bottom: $gl-padding-4; }
.append-bottom-5 { margin-bottom: 5px; }
.append-bottom-8 { margin-bottom: $grid-size; }

View File

@ -1,22 +1,4 @@
.alert-management-list {
// consider adding these stateful variants to @gitlab-ui
// https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1178
.hover-bg-blue-50:hover {
background-color: $blue-50;
}
.hover-gl-cursor-pointer:hover {
cursor: pointer;
}
.hover-gl-border-b-solid:hover {
@include gl-border-b-solid;
}
.hover-gl-border-blue-200:hover {
border-color: $blue-200;
}
// these styles need to be deleted once GlTable component looks in GitLab same as in @gitlab/ui
table {
color: $gray-700;

View File

@ -6,7 +6,6 @@ module Projects
before_action :authenticate_user!
before_action :check_issues_available!
before_action :authorize_read_project!
before_action :jira_import_enabled?
before_action :jira_integration_configured?
before_action :authorize_admin_project!, only: [:import]
@ -44,12 +43,6 @@ module Projects
private
def jira_import_enabled?
return if @project.jira_issues_import_feature_flag_enabled?
redirect_to project_issues_path(@project)
end
def jira_integration_configured?
return if Feature.enabled?(:jira_issue_import_vue, @project, default_enabled: true)
return if @project.jira_service

View File

@ -14,8 +14,6 @@ module Resolvers
end
def authorized_resource?(project)
return false unless project.jira_issues_import_feature_flag_enabled?
context[:current_user].present? && Ability.allowed?(context[:current_user], :read_project, project)
end
end

View File

@ -20,7 +20,7 @@ module Resolvers
end
def authorized_resource?(project)
Feature.enabled?(:jira_issue_import, project) && Ability.allowed?(context[:current_user], :admin_project, project)
Ability.allowed?(context[:current_user], :admin_project, project)
end
private

View File

@ -3,6 +3,13 @@
module NotesHelper
MAX_PRERENDERED_NOTES = 10
def note_target_title(note)
# The design title is already present in `Event#note_target_reference`.
return if note.nil? || note.for_design?
note.title
end
def note_target_fields(note)
if note.noteable
hidden_field_tag(:target_type, note.noteable.class.name.underscore) +

View File

@ -808,10 +808,6 @@ class Project < ApplicationRecord
Feature.enabled?(:context_commits, default_enabled: true)
end
def jira_issues_import_feature_flag_enabled?
Feature.enabled?(:jira_issue_import, self, default_enabled: true)
end
# LFS and hashed repository storage are required for using Design Management.
def design_management_enabled?
lfs_enabled? && hashed_storage?(:repository)
@ -900,7 +896,6 @@ class Project < ApplicationRecord
end
def validate_jira_import_settings!(user: nil)
raise Projects::ImportService::Error, _('Jira import feature is disabled.') unless jira_issues_import_feature_flag_enabled?
raise Projects::ImportService::Error, _('Jira integration not configured.') unless jira_service&.active?
if user
@ -1015,7 +1010,7 @@ class Project < ApplicationRecord
end
def jira_import?
import_type == 'jira' && latest_jira_import.present? && jira_issues_import_feature_flag_enabled?
import_type == 'jira' && latest_jira_import.present?
end
def gitlab_project_import?

View File

@ -1818,7 +1818,7 @@ class User < ApplicationRecord
def update_highest_role?
return false unless persisted?
(previous_changes.keys & %w(state user_type ghost)).any?
(previous_changes.keys & %w(state user_type)).any?
end
def update_highest_role_attribute

View File

@ -7,8 +7,10 @@
%span.event-type.d-inline-block.append-right-4{ class: event.action_name }
= event.action_name
= event_note_title_html(event)
%span.event-target-title.append-right-4{ dir: "auto" }
= "&quot;".html_safe + event.target.title + "&quot".html_safe
- title = note_target_title(event.target)
- if title.present?
%span.event-target-title.append-right-4{ dir: "auto" }
= "&quot;".html_safe + title + "&quot".html_safe
= render "events/event_scope", event: event

View File

@ -1,22 +1,14 @@
- type = local_assigns.fetch(:type, :icon)
- if @project.jira_issues_import_feature_flag_enabled?
.dropdown.btn-group
%button.btn.rounded-right.text-center{ class: ('has-tooltip' if type == :icon), title: (_('Import issues') if type == :icon),
data: { toggle: 'dropdown' }, 'aria-label' => _('Import issues'), 'aria-haspopup' => 'true', 'aria-expanded' => 'false' }
- if type == :icon
= sprite_icon('import')
- else
= _('Import issues')
%ul.dropdown-menu
%li
%button.btn{ data: { toggle: 'modal', target: '.issues-import-modal' } }
= _('Import CSV')
%li= link_to _('Import from Jira'), project_import_jira_path(@project)
- else
%button.csv-import-button.btn{ title: _('Import CSV'), class: ('has-tooltip' if type == :icon),
data: { toggle: 'modal', target: '.issues-import-modal' } }
.dropdown.btn-group
%button.btn.rounded-right.text-center{ class: ('has-tooltip' if type == :icon), title: (_('Import issues') if type == :icon),
data: { toggle: 'dropdown' }, 'aria-label' => _('Import issues'), 'aria-haspopup' => 'true', 'aria-expanded' => 'false' }
- if type == :icon
= sprite_icon('import')
- else
= _('Import CSV')
= _('Import issues')
%ul.dropdown-menu
%li
%button.btn{ data: { toggle: 'modal', target: '.issues-import-modal' } }
= _('Import CSV')
%li= link_to _('Import from Jira'), project_import_jira_path(@project)

View File

@ -6,11 +6,10 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@project.name} issues")
- if @project.jira_issues_import_feature_flag_enabled?
.js-projects-issues-root{ data: { can_edit: can?(current_user, :admin_project, @project).to_s,
is_jira_configured: @project.jira_service.present?.to_s,
issues_path: project_issues_path(@project),
project_path: @project.full_path } }
.js-projects-issues-root{ data: { can_edit: can?(current_user, :admin_project, @project).to_s,
is_jira_configured: @project.jira_service.present?.to_s,
issues_path: project_issues_path(@project),
project_path: @project.full_path } }
- if project_issues(@project).exists?
.top-area

View File

@ -27,7 +27,6 @@ module Gitlab
def can_import?(project)
return false unless project
return false unless project.jira_issues_import_feature_flag_enabled?
project.latest_jira_import&.started?
end

View File

@ -25,7 +25,6 @@ module Gitlab
def start_import
return false unless project
return false unless project.jira_issues_import_feature_flag_enabled?
return true if start(project.latest_jira_import)
Gitlab::Import::Logger.info(

View File

@ -0,0 +1,5 @@
---
title: Hid copy contents button when blob has rendering error
merge_request: 32632
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Remove obsolete users.ghost column
merge_request: 32957
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Improve fast-forward merge is not possible message
merge_request: 22834
author: Ben Bodenmiller
type: other

View File

@ -0,0 +1,5 @@
---
title: Fix filename duplication in design notes in activity feeds
merge_request: 32823
author: Arun Kumar Mohan
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add btree_gist PGSQL extension and add DB constraints for Iteration date ranges
merge_request: 32335
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Use build_stubbed to avoid interacting with the DB in todos helper specs
merge_request: 32906
author: Arun Kumar Mohan
type: performance

View File

@ -465,7 +465,6 @@ tables:
- auditor
- require_two_factor_authentication_from_group
- two_factor_grace_period
- ghost
- last_activity_on
- notified_of_own_activity
- user_type

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class EnableBtreeGistExtension < ActiveRecord::Migration[6.0]
DOWNTIME = false
def up
execute 'CREATE EXTENSION IF NOT EXISTS btree_gist'
end
def down
execute 'DROP EXTENSION IF EXISTS btree_gist'
end
end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
class IterationDateRangeConstraint < ActiveRecord::Migration[6.0]
DOWNTIME = false
def up
execute <<~SQL
ALTER TABLE sprints
ADD CONSTRAINT iteration_start_and_due_daterange_project_id_constraint
EXCLUDE USING gist
( project_id WITH =,
daterange(start_date, due_date, '[]') WITH &&
)
WHERE (project_id IS NOT NULL)
SQL
execute <<~SQL
ALTER TABLE sprints
ADD CONSTRAINT iteration_start_and_due_daterange_group_id_constraint
EXCLUDE USING gist
( group_id WITH =,
daterange(start_date, due_date, '[]') WITH &&
)
WHERE (group_id IS NOT NULL)
SQL
end
def down
execute <<~SQL
ALTER TABLE sprints
DROP CONSTRAINT IF EXISTS iteration_start_and_due_daterange_project_id_constraint
SQL
execute <<~SQL
ALTER TABLE sprints
DROP CONSTRAINT IF EXISTS iteration_start_and_due_daterange_group_id_constraint
SQL
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class RenameUserTypeIndex < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :users, [:state, :user_type], name: 'index_users_on_state_and_user_type'
remove_concurrent_index_by_name :users, 'index_users_on_state_and_user_type_internal'
end
def down
add_concurrent_index :users, [:state, :user_type], where: 'ghost IS NOT TRUE', name: 'index_users_on_state_and_user_type_internal'
remove_concurrent_index_by_name :users, 'index_users_on_state_and_user_type'
end
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
class DropUsersGhostColumn < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index_by_name :users, 'index_users_on_ghost'
with_lock_retries do
remove_column :users, :ghost
end
end
def down
unless column_exists?(:users, :ghost)
with_lock_retries do
add_column :users, :ghost, :boolean # rubocop:disable Migration/AddColumnsToWideTables
end
end
execute 'UPDATE users set ghost = TRUE WHERE user_type = 5'
add_concurrent_index :users, :ghost
end
end

View File

@ -2,6 +2,8 @@ SET search_path=public;
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
CREATE EXTENSION IF NOT EXISTS btree_gist WITH SCHEMA public;
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
CREATE TABLE public.abuse_reports (
@ -6806,7 +6808,6 @@ CREATE TABLE public.users (
auditor boolean DEFAULT false NOT NULL,
require_two_factor_authentication_from_group boolean DEFAULT false NOT NULL,
two_factor_grace_period integer DEFAULT 48 NOT NULL,
ghost boolean,
last_activity_on date,
notified_of_own_activity boolean,
preferred_language character varying,
@ -8410,6 +8411,12 @@ ALTER TABLE ONLY public.issue_user_mentions
ALTER TABLE ONLY public.issues
ADD CONSTRAINT issues_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.sprints
ADD CONSTRAINT iteration_start_and_due_daterange_group_id_constraint EXCLUDE USING gist (group_id WITH =, daterange(start_date, due_date, '[]'::text) WITH &&) WHERE ((group_id IS NOT NULL));
ALTER TABLE ONLY public.sprints
ADD CONSTRAINT iteration_start_and_due_daterange_project_id_constraint EXCLUDE USING gist (project_id WITH =, daterange(start_date, due_date, '[]'::text) WITH &&) WHERE ((project_id IS NOT NULL));
ALTER TABLE ONLY public.jira_connect_installations
ADD CONSTRAINT jira_connect_installations_pkey PRIMARY KEY (id);
@ -10826,8 +10833,6 @@ CREATE INDEX index_users_on_email_trigram ON public.users USING gin (email publi
CREATE INDEX index_users_on_feed_token ON public.users USING btree (feed_token);
CREATE INDEX index_users_on_ghost ON public.users USING btree (ghost);
CREATE INDEX index_users_on_group_view ON public.users USING btree (group_view);
CREATE INDEX index_users_on_incoming_email_token ON public.users USING btree (incoming_email_token);
@ -10844,7 +10849,7 @@ CREATE UNIQUE INDEX index_users_on_reset_password_token ON public.users USING bt
CREATE INDEX index_users_on_state ON public.users USING btree (state);
CREATE INDEX index_users_on_state_and_user_type_internal ON public.users USING btree (state, user_type) WHERE (ghost IS NOT TRUE);
CREATE INDEX index_users_on_state_and_user_type ON public.users USING btree (state, user_type);
CREATE UNIQUE INDEX index_users_on_static_object_token ON public.users USING btree (static_object_token);
@ -13922,8 +13927,12 @@ COPY "schema_migrations" (version) FROM STDIN;
20200514000009
20200514000132
20200514000340
20200515152649
20200515153633
20200515155620
20200519115908
20200519171058
20200525114553
20200525121014
\.

View File

@ -199,6 +199,7 @@ authentication](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/configurati
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
grafana['enable'] = false
gitlab_exporter['enable'] = false
# If you run a separate monitoring node you can disable these services
alertmanager['enable'] = false
@ -211,7 +212,6 @@ authentication](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/configurati
# prometheus['monitor_kubernetes'] = false
# If you don't want to run monitoring services uncomment the following (not recommended)
# gitlab_exporter['enable'] = false
# node_exporter['enable'] = false
# Prevent database connections during 'gitlab-ctl reconfigure'

View File

@ -310,7 +310,6 @@ include:
- template: 'Workflows/Branch-Pipelines.gitlab-ci.yml'
```
The [`MergeRequest-Pipelines` include](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines.gitlab-ci.yml) sets your pipelines to run for the default branch (usually `master`), tags, and
The [`MergeRequest-Pipelines` template](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines.gitlab-ci.yml)
makes your pipelines run for the default branch (usually `master`), tags, and
all types of merge request pipelines. Use this template if you use any of the

View File

@ -257,11 +257,11 @@ Your Rails console will return the generated SQL queries.
Example:
```ruby
pry(main)> Gitlab::UsageData.count(User.active)
(0.4ms) SELECT "features"."key" FROM "features"
(0.7ms) SELECT MIN("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND (ghost IS NOT TRUE) AND ("users"."user_type" IS NULL OR "users"."user_type" NOT IN (2, 1, 3))
(0.6ms) SELECT MAX("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND (ghost IS NOT TRUE) AND ("users"."user_type" IS NULL OR "users"."user_type" NOT IN (2, 1, 3))
(0.5ms) SELECT COUNT("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND (ghost IS NOT TRUE) AND ("users"."user_type" IS NULL OR "users"."user_type" NOT IN (2, 1, 3)) AND "users"."id" BETWEEN 0 AND 99999
pry(main)> Gitlab::UsageData.count(User.active)
(2.6ms) SELECT "features"."key" FROM "features"
(15.3ms) SELECT MIN("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
(2.4ms) SELECT MAX("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
(1.9ms) SELECT COUNT("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4)) AND "users"."id" BETWEEN 1 AND 100000
```
### 3. Optimize queries with #database-lab

View File

@ -315,25 +315,30 @@ the `Indexes:` section:
```sql
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"users_confirmation_token_key" UNIQUE CONSTRAINT, btree (confirmation_token)
"users_email_key" UNIQUE CONSTRAINT, btree (email)
"users_reset_password_token_key" UNIQUE CONSTRAINT, btree (reset_password_token)
"index_on_users_lower_email" btree (lower(email::text))
"index_on_users_lower_username" btree (lower(username::text))
"index_users_on_confirmation_token" UNIQUE, btree (confirmation_token)
"index_users_on_email" UNIQUE, btree (email)
"index_users_on_reset_password_token" UNIQUE, btree (reset_password_token)
"index_users_on_static_object_token" UNIQUE, btree (static_object_token)
"index_users_on_unlock_token" UNIQUE, btree (unlock_token)
"index_on_users_name_lower" btree (lower(name::text))
"index_users_on_accepted_term_id" btree (accepted_term_id)
"index_users_on_admin" btree (admin)
"index_users_on_created_at" btree (created_at)
"index_users_on_email_trigram" gin (email gin_trgm_ops)
"index_users_on_feed_token" btree (feed_token)
"index_users_on_ghost" btree (ghost)
"index_users_on_group_view" btree (group_view)
"index_users_on_incoming_email_token" btree (incoming_email_token)
"index_users_on_managing_group_id" btree (managing_group_id)
"index_users_on_name" btree (name)
"index_users_on_name_trigram" gin (name gin_trgm_ops)
"index_users_on_public_email" btree (public_email) WHERE public_email::text <> ''::text
"index_users_on_state" btree (state)
"index_users_on_state_and_internal_attrs" btree (state) WHERE ghost <> true AND support_bot <> true
"index_users_on_support_bot" btree (support_bot)
"index_users_on_state_and_user_type" btree (state, user_type)
"index_users_on_unconfirmed_email" btree (unconfirmed_email) WHERE unconfirmed_email IS NOT NULL
"index_users_on_user_type" btree (user_type)
"index_users_on_username" btree (username)
"index_users_on_username_trigram" gin (username gin_trgm_ops)
"tmp_idx_on_user_id_where_bio_is_filled" btree (id) WHERE COALESCE(bio, ''::character varying)::text IS DISTINCT FROM ''::text
```
Here we can see there is no index on the `twitter` column, which means

View File

@ -237,7 +237,9 @@ On the EC2 dashboard, look for Load Balancer in the left navigation bar:
1. Click **Assign Security Groups** and select **Create a new security group**, give it a name
(we'll use `gitlab-loadbalancer-sec-group`) and description, and allow both HTTP and HTTPS traffic
from anywhere (`0.0.0.0/0, ::/0`). Also allow SSH traffic from a single IP address or an IP address range in CIDR notation.
1. Click **Configure Security Settings** and select an SSL/TLS certificate from ACM or upload a certificate to IAM.
1. Click **Configure Security Settings** and set the following:
1. Select an SSL/TLS certificate from ACM or upload a certificate to IAM.
1. Under **Select a Cipher**, pick a predefined security policy from the dropdown. You can see a breakdown of [Predefined SSL Security Policies for Classic Load Balancers](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html) in the AWS docs. Check the GitLab codebase for a list of [supported SSL ciphers and protocols](https://gitlab.com/gitlab-org/gitlab/-/blob/9ee7ad433269b37251e0dd5b5e00a0f00d8126b4/lib/support/nginx/gitlab-ssl#L97-99).
1. Click **Configure Health Check** and set up a health check for your EC2 instances.
1. For **Ping Protocol**, select HTTP.
1. For **Ping Port**, enter 80.

View File

@ -1,42 +1,36 @@
# Akismet
> *Note:* Before 8.11 only issues submitted via the API and for non-project
members were submitted to Akismet.
GitLab leverages [Akismet](https://akismet.com/) to protect against spam. Currently
GitLab uses Akismet to prevent the creation of spam issues on public projects. Issues
created via the WebUI or the API can be submitted to Akismet for review.
created via the web UI or the API can be submitted to Akismet for review.
Detected spam will be rejected, and an entry in the "Spam Log" section in the
Admin page will be created.
Privacy note: GitLab submits the user's IP and user agent to Akismet. Note that
adding a user to a project will disable the Akismet check and prevent this
from happening.
Privacy note: GitLab submits the user's IP and user agent to Akismet.
NOTE: **Note:**
In GitLab 8.11 and later, all issues are submitted to Akismet.
In earlier GitLab versions, this only applied to API and non-project members.
## Configuration
To use Akismet:
1. Go to the URL: <https://akismet.com/account/>
1. Sign-in or create a new account.
1. Click on **Show** to reveal the API key.
1. Go to **Admin Area > Settings > Reporting** (`/admin/application_settings/reporting`).
1. Check the **Enable Akismet** checkbox.
1. Fill in the API key from step 3.
1. Save the configuration.
![Screenshot of Akismet settings](img/akismet_settings.png)
## Training
> *Note:* Training the Akismet filter is only available in 8.11 and above.
NOTE: **Note:**
Training the Akismet filter is only available in GitLab 8.11 and later.
As a way to better recognize between spam and ham, you can train the Akismet
filter whenever there is a false positive or false negative.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 195 KiB

View File

@ -5699,9 +5699,6 @@ msgstr ""
msgid "Configure Prometheus"
msgstr ""
msgid "Configure Security %{wordBreakOpportunity}and Compliance"
msgstr ""
msgid "Configure Tracing"
msgstr ""
@ -9291,7 +9288,7 @@ msgstr ""
msgid "Fast-forward merge is not possible. Rebase the source branch onto %{targetBranch} to allow this merge request to be merged."
msgstr ""
msgid "Fast-forward merge is not possible. Rebase the source branch onto the target branch or merge target branch into source branch to allow this merge request to be merged."
msgid "Fast-forward merge is not possible. Rebase the source branch onto the target branch."
msgstr ""
msgid "Fast-forward merge without a merge commit"
@ -12204,9 +12201,6 @@ msgstr ""
msgid "Jira Issue Import"
msgstr ""
msgid "Jira import feature is disabled."
msgstr ""
msgid "Jira import is already running."
msgstr ""
@ -18994,9 +18988,6 @@ msgstr ""
msgid "Security Dashboard"
msgstr ""
msgid "Security configuration help link"
msgstr ""
msgid "Security dashboard"
msgstr ""
@ -19009,21 +19000,21 @@ msgstr ""
msgid "SecurityConfiguration|Enabled"
msgstr ""
msgid "SecurityConfiguration|Feature"
msgstr ""
msgid "SecurityConfiguration|Feature documentation for %{featureName}"
msgstr ""
msgid "SecurityConfiguration|Not yet enabled"
msgstr ""
msgid "SecurityConfiguration|Secure features"
msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
msgstr ""
msgid "SecurityConfiguration|Testing & Compliance"
msgstr ""
msgid "SecurityReports|%{firstProject} and %{secondProject}"
msgstr ""

View File

@ -41,7 +41,7 @@
"@babel/preset-env": "^7.8.4",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.130.0",
"@gitlab/ui": "15.5.0",
"@gitlab/ui": "15.6.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3",
"@sentry/browser": "^5.10.2",

View File

@ -10,10 +10,6 @@ describe Projects::Import::JiraController do
let_it_be(:jira_project_key) { 'Test' }
context 'with anonymous user' do
before do
stub_feature_flags(jira_issue_import: true)
end
context 'get show' do
it 'redirects to issues page' do
get :show, params: { namespace_id: project.namespace, project_id: project }
@ -35,195 +31,167 @@ describe Projects::Import::JiraController do
before do
sign_in(user)
project.add_maintainer(user)
stub_feature_flags(jira_issue_import_vue: false)
stub_jira_service_test
end
context 'when feature flag not enabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
context 'when Jira service is enabled for the project' do
let_it_be(:jira_service) { create(:jira_service, project: project) }
context 'get show' do
it 'redirects to issues page' do
get :show, params: { namespace_id: project.namespace, project_id: project }
context 'when user is developer' do
let_it_be(:dev) { create(:user) }
expect(response).to redirect_to(project_issues_path(project))
before do
sign_in(dev)
project.add_developer(dev)
end
end
context 'post import' do
it 'redirects to issues page' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: jira_project_key }
expect(response).to redirect_to(project_issues_path(project))
end
end
end
context 'when feature flag enabled' do
before do
stub_feature_flags(jira_issue_import: true)
stub_feature_flags(jira_issue_import_vue: false)
stub_jira_service_test
end
context 'when Jira service is enabled for the project' do
let_it_be(:jira_service) { create(:jira_service, project: project) }
context 'when user is developer' do
let_it_be(:dev) { create(:user) }
context 'get show' do
before do
sign_in(dev)
project.add_developer(dev)
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
end
context 'get show' do
before do
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
end
it 'does not query Jira service' do
expect(project).not_to receive(:jira_service)
end
it 'does not query Jira service' do
expect(project).not_to receive(:jira_service)
it 'renders show template' do
expect(response).to render_template(:show)
expect(assigns(:jira_projects)).not_to be_present
end
end
context 'post import' do
it 'returns 404' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: jira_project_key }
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'when issues disabled' do
let_it_be(:disabled_issues_project) { create(:project, :public, :issues_disabled) }
context 'get show' do
it 'returs 404' do
get :show, params: { namespace_id: project.namespace.to_param, project_id: disabled_issues_project }
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'post import' do
it 'returs 404' do
post :import, params: { namespace_id: disabled_issues_project.namespace, project_id: disabled_issues_project, jira_project_key: jira_project_key }
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'when running Jira import first time' do
context 'get show' do
before do
allow(JIRA::Resource::Project).to receive(:all).and_return(jira_projects)
expect(project.jira_imports).to be_empty
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
end
context 'when no projects have been retrieved from Jira' do
let(:jira_projects) { [] }
it 'render an error message' do
expect(flash[:alert]).to eq('No projects have been returned from Jira. Please check your Jira configuration.')
expect(response).to render_template(:show)
end
end
context 'when projects retrieved from Jira' do
let(:jira_projects) { [double(name: 'FOO project', key: 'FOO')] }
it 'renders show template' do
expect(response).to render_template(:show)
expect(assigns(:jira_projects)).not_to be_present
end
end
end
context 'post import' do
context 'when Jira project key is empty' do
it 'redirects back to show with an error' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: '' }
expect(response).to redirect_to(project_import_jira_path(project))
expect(flash[:alert]).to eq('No Jira project key has been provided.')
end
end
context 'post import' do
it 'returns 404' do
context 'when everything is ok' do
it 'creates import state' do
expect(project.latest_jira_import).to be_nil
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: jira_project_key }
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'when issues disabled' do
let_it_be(:disabled_issues_project) { create(:project, :public, :issues_disabled) }
context 'get show' do
it 'returs 404' do
get :show, params: { namespace_id: project.namespace.to_param, project_id: disabled_issues_project }
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'post import' do
it 'returs 404' do
post :import, params: { namespace_id: disabled_issues_project.namespace, project_id: disabled_issues_project, jira_project_key: jira_project_key }
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'when running Jira import first time' do
context 'get show' do
before do
allow(JIRA::Resource::Project).to receive(:all).and_return(jira_projects)
expect(project.jira_imports).to be_empty
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
end
context 'when no projects have been retrieved from Jira' do
let(:jira_projects) { [] }
it 'render an error message' do
expect(flash[:alert]).to eq('No projects have been returned from Jira. Please check your Jira configuration.')
expect(response).to render_template(:show)
end
end
context 'when projects retrieved from Jira' do
let(:jira_projects) { [double(name: 'FOO project', key: 'FOO')] }
it 'renders show template' do
expect(response).to render_template(:show)
end
end
end
context 'post import' do
context 'when Jira project key is empty' do
it 'redirects back to show with an error' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: '' }
expect(response).to redirect_to(project_import_jira_path(project))
expect(flash[:alert]).to eq('No Jira project key has been provided.')
end
end
context 'when everything is ok' do
it 'creates import state' do
expect(project.latest_jira_import).to be_nil
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: jira_project_key }
project.reload
jira_import = project.latest_jira_import
expect(project.import_type).to eq 'jira'
expect(jira_import.status).to eq 'scheduled'
expect(jira_import.jira_project_key).to eq jira_project_key
expect(response).to redirect_to(project_import_jira_path(project))
end
end
end
end
context 'when import state is scheduled' do
let_it_be(:jira_import_state) { create(:jira_import_state, :scheduled, project: project) }
context 'get show' do
it 'renders import status' do
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
project.reload
jira_import = project.latest_jira_import
expect(project.import_type).to eq 'jira'
expect(jira_import.status).to eq 'scheduled'
expect(flash.now[:notice]).to eq 'Import scheduled'
end
end
context 'post import' do
it 'uses the existing import data' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' }
expect(flash[:notice]).to eq('Jira import is already running.')
expect(jira_import.jira_project_key).to eq jira_project_key
expect(response).to redirect_to(project_import_jira_path(project))
end
end
end
end
context 'when Jira import ran before' do
let_it_be(:jira_import_state) { create(:jira_import_state, :finished, project: project, jira_project_key: jira_project_key) }
context 'when import state is scheduled' do
let_it_be(:jira_import_state) { create(:jira_import_state, :scheduled, project: project) }
context 'get show' do
it 'renders import status' do
allow(JIRA::Resource::Project).to receive(:all).and_return([])
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
context 'get show' do
it 'renders import status' do
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
expect(project.latest_jira_import.status).to eq 'finished'
expect(flash.now[:notice]).to eq 'Import finished'
end
jira_import = project.latest_jira_import
expect(jira_import.status).to eq 'scheduled'
expect(flash.now[:notice]).to eq 'Import scheduled'
end
end
context 'post import' do
it 'uses the existing import data' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' }
context 'post import' do
it 'uses the existing import data' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' }
project.reload
expect(project.latest_jira_import.status).to eq 'scheduled'
expect(project.jira_imports.size).to eq 2
expect(project.jira_imports.first.jira_project_key).to eq jira_project_key
expect(project.jira_imports.last.jira_project_key).to eq 'New Project'
expect(response).to redirect_to(project_import_jira_path(project))
end
expect(flash[:notice]).to eq('Jira import is already running.')
expect(response).to redirect_to(project_import_jira_path(project))
end
end
end
context 'when Jira import ran before' do
let_it_be(:jira_import_state) { create(:jira_import_state, :finished, project: project, jira_project_key: jira_project_key) }
context 'get show' do
it 'renders import status' do
allow(JIRA::Resource::Project).to receive(:all).and_return([])
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }
expect(project.latest_jira_import.status).to eq 'finished'
expect(flash.now[:notice]).to eq 'Import finished'
end
end
context 'post import' do
it 'uses the existing import data' do
post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: 'New Project' }
project.reload
expect(project.latest_jira_import.status).to eq 'scheduled'
expect(project.jira_imports.size).to eq 2
expect(project.jira_imports.first.jira_project_key).to eq jira_project_key
expect(project.jira_imports.last.jira_project_key).to eq 'New Project'
expect(response).to redirect_to(project_import_jira_path(project))
end
end
end

View File

@ -118,10 +118,7 @@ describe 'Mermaid rendering', :js do
visit project_issue_path(project, issue)
svg = page.find('svg.mermaid')
expect(svg[:style]).to match(/max-width/)
expect(svg[:width].to_i).to eq(100)
expect(svg[:height].to_i).to eq(0)
expect(page).to have_css('svg.mermaid[style*="max-width"][width="100%"]')
end
it 'display button when diagram exceeds length', :js do

View File

@ -66,5 +66,13 @@ describe('Blob Header Default Actions', () => {
expect(buttons.at(0).attributes('disabled')).toBeTruthy();
});
it('does not render the copy button if a rendering error is set', () => {
createComponent({
hasRenderError: true,
});
expect(wrapper.find('[data-testid="copyContentsButton"]').exists()).toBe(false);
});
});
});

View File

@ -87,6 +87,17 @@ describe('Blob Header Default Actions', () => {
expect(wrapper.text()).toContain(slotContent);
});
});
it('passes information about render error down to default actions', () => {
createComponent(
{},
{},
{
hasRenderError: true,
},
);
expect(wrapper.find(DefaultActions).props('hasRenderError')).toBe(true);
});
});
describe('functionality', () => {

View File

@ -1,6 +1,6 @@
import { range as rge } from 'lodash';
import Vue from 'vue';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import app from '~/releases/components/app_index.vue';
import createStore from '~/releases/stores';
import listModule from '~/releases/stores/modules/list';
@ -9,11 +9,11 @@ import { resetStore } from '../stores/modules/list/helpers';
import {
pageInfoHeadersWithoutPagination,
pageInfoHeadersWithPagination,
release,
release2 as release,
releases,
} from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import waitForPromises from 'spec/helpers/wait_for_promises';
import waitForPromises from 'helpers/wait_for_promises';
describe('Releases App ', () => {
const Component = Vue.extend(app);
@ -42,83 +42,67 @@ describe('Releases App ', () => {
describe('while loading', () => {
beforeEach(() => {
spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [], headers: {} }));
jest
.spyOn(api, 'releases')
// Need to defer the return value here to the next stack,
// otherwise the loading state disappears before our test even starts.
.mockImplementation(() => waitForPromises().then(() => ({ data: [], headers: {} })));
vm = mountComponentWithStore(Component, { props, store });
});
it('renders loading icon', done => {
it('renders loading icon', () => {
expect(vm.$el.querySelector('.js-loading')).not.toBeNull();
expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
expect(vm.$el.querySelector('.js-success-state')).toBeNull();
expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
waitForPromises()
.then(done)
.catch(done.fail);
return waitForPromises();
});
});
describe('with successful request', () => {
beforeEach(() => {
spyOn(api, 'releases').and.returnValue(
Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination }),
);
jest
.spyOn(api, 'releases')
.mockResolvedValue({ data: releases, headers: pageInfoHeadersWithoutPagination });
vm = mountComponentWithStore(Component, { props, store });
});
it('renders success state', done => {
waitForPromises()
.then(() => {
expect(vm.$el.querySelector('.js-loading')).toBeNull();
expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
expect(vm.$el.querySelector('.js-success-state')).not.toBeNull();
expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
done();
})
.catch(done.fail);
it('renders success state', () => {
expect(vm.$el.querySelector('.js-loading')).toBeNull();
expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
expect(vm.$el.querySelector('.js-success-state')).not.toBeNull();
expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
});
});
describe('with successful request and pagination', () => {
beforeEach(() => {
spyOn(api, 'releases').and.returnValue(
Promise.resolve({ data: releasesPagination, headers: pageInfoHeadersWithPagination }),
);
jest
.spyOn(api, 'releases')
.mockResolvedValue({ data: releasesPagination, headers: pageInfoHeadersWithPagination });
vm = mountComponentWithStore(Component, { props, store });
});
it('renders success state', done => {
waitForPromises()
.then(() => {
expect(vm.$el.querySelector('.js-loading')).toBeNull();
expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
expect(vm.$el.querySelector('.js-success-state')).not.toBeNull();
expect(vm.$el.querySelector('.gl-pagination')).not.toBeNull();
done();
})
.catch(done.fail);
it('renders success state', () => {
expect(vm.$el.querySelector('.js-loading')).toBeNull();
expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
expect(vm.$el.querySelector('.js-success-state')).not.toBeNull();
expect(vm.$el.querySelector('.gl-pagination')).not.toBeNull();
});
});
describe('with empty request', () => {
beforeEach(() => {
spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [], headers: {} }));
jest.spyOn(api, 'releases').mockResolvedValue({ data: [], headers: {} });
vm = mountComponentWithStore(Component, { props, store });
});
it('renders empty state', done => {
waitForPromises()
.then(() => {
expect(vm.$el.querySelector('.js-loading')).toBeNull();
expect(vm.$el.querySelector('.js-empty-state')).not.toBeNull();
expect(vm.$el.querySelector('.js-success-state')).toBeNull();
expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
done();
})
.catch(done.fail);
it('renders empty state', () => {
expect(vm.$el.querySelector('.js-loading')).toBeNull();
expect(vm.$el.querySelector('.js-empty-state')).not.toBeNull();
expect(vm.$el.querySelector('.js-success-state')).toBeNull();
expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
});
});
@ -126,7 +110,7 @@ describe('Releases App ', () => {
const findNewReleaseButton = () => vm.$el.querySelector('.js-new-release-btn');
beforeEach(() => {
spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [], headers: {} }));
jest.spyOn(api, 'releases').mockResolvedValue({ data: [], headers: {} });
});
const factory = additionalProps => {
@ -146,38 +130,20 @@ describe('Releases App ', () => {
factory({ newReleasePath });
});
it('renders the "New release" button', done => {
waitForPromises()
.then(() => {
expect(findNewReleaseButton()).not.toBeNull();
done();
})
.catch(done.fail);
it('renders the "New release" button', () => {
expect(findNewReleaseButton()).not.toBeNull();
});
it('renders the "New release" button with the correct href', done => {
waitForPromises()
.then(() => {
expect(findNewReleaseButton().getAttribute('href')).toBe(newReleasePath);
done();
})
.catch(done.fail);
it('renders the "New release" button with the correct href', () => {
expect(findNewReleaseButton().getAttribute('href')).toBe(newReleasePath);
});
});
describe('when the user is not allowed to create a new Release', () => {
beforeEach(() => factory());
it('does not render the "New release" button', done => {
waitForPromises()
.then(() => {
expect(findNewReleaseButton()).toBeNull();
done();
})
.catch(done.fail);
it('does not render the "New release" button', () => {
expect(findNewReleaseButton()).toBeNull();
});
});
});

View File

@ -131,3 +131,91 @@ export const release = {
edit_url: 'http://0.0.0.0:3001/root/release-test/-/releases/v0.3/edit',
},
};
export const pageInfoHeadersWithoutPagination = {
'X-NEXT-PAGE': '',
'X-PAGE': '1',
'X-PER-PAGE': '20',
'X-PREV-PAGE': '',
'X-TOTAL': '19',
'X-TOTAL-PAGES': '1',
};
export const pageInfoHeadersWithPagination = {
'X-NEXT-PAGE': '2',
'X-PAGE': '1',
'X-PER-PAGE': '20',
'X-PREV-PAGE': '',
'X-TOTAL': '21',
'X-TOTAL-PAGES': '2',
};
export const release2 = {
name: 'Bionic Beaver',
tag_name: '18.04',
description: '## changelog\n\n* line 1\n* line2',
description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>',
author_name: 'Release bot',
author_email: 'release-bot@example.com',
created_at: '2012-05-28T05:00:00-07:00',
commit: {
id: '2695effb5807a22ff3d138d593fd856244e155e7',
short_id: '2695effb',
title: 'Initial commit',
created_at: '2017-07-26T11:08:53.000+02:00',
parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'],
message: 'Initial commit',
author: {
avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
id: 482476,
name: 'John Doe',
path: '/johndoe',
state: 'active',
status_tooltip_html: null,
username: 'johndoe',
web_url: 'https://gitlab.com/johndoe',
},
authored_date: '2012-05-28T04:42:42-07:00',
committer_name: 'Jack Smith',
committer_email: 'jack@example.com',
committed_date: '2012-05-28T04:42:42-07:00',
},
assets: {
count: 6,
sources: [
{
format: 'zip',
url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.zip',
},
{
format: 'tar.gz',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz',
},
{
format: 'tar.bz2',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2',
},
{
format: 'tar',
url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar',
},
],
links: [
{
name: 'release-18.04.dmg',
url: 'https://my-external-hosting.example.com/scrambled-url/',
external: true,
},
{
name: 'binary-linux-amd64',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50',
external: false,
},
],
},
};
export const releases = [release, release2];

View File

@ -1,4 +1,4 @@
import testAction from 'spec/helpers/vuex_action_helper';
import testAction from 'helpers/vuex_action_helper';
import {
requestReleases,
fetchReleases,
@ -31,7 +31,7 @@ describe('Releases State actions', () => {
describe('fetchReleases', () => {
describe('success', () => {
it('dispatches requestReleases and receiveReleasesSuccess', done => {
spyOn(api, 'releases').and.callFake((id, options) => {
jest.spyOn(api, 'releases').mockImplementation((id, options) => {
expect(id).toEqual(1);
expect(options.page).toEqual('1');
return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
@ -56,7 +56,7 @@ describe('Releases State actions', () => {
});
it('dispatches requestReleases and receiveReleasesSuccess on page two', done => {
spyOn(api, 'releases').and.callFake((_, options) => {
jest.spyOn(api, 'releases').mockImplementation((_, options) => {
expect(options.page).toEqual('2');
return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
});
@ -82,7 +82,7 @@ describe('Releases State actions', () => {
describe('error', () => {
it('dispatches requestReleases and receiveReleasesError', done => {
spyOn(api, 'releases').and.returnValue(Promise.reject());
jest.spyOn(api, 'releases').mockReturnValue(Promise.reject());
testAction(
fetchReleases,

View File

@ -3,7 +3,11 @@ import SnippetBlobView from '~/snippets/components/snippet_blob_view.vue';
import BlobHeader from '~/blob/components/blob_header.vue';
import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import BlobContent from '~/blob/components/blob_content.vue';
import { BLOB_RENDER_EVENT_LOAD, BLOB_RENDER_EVENT_SHOW_SOURCE } from '~/blob/components/constants';
import {
BLOB_RENDER_EVENT_LOAD,
BLOB_RENDER_EVENT_SHOW_SOURCE,
BLOB_RENDER_ERRORS,
} from '~/blob/components/constants';
import { RichViewer, SimpleViewer } from '~/vue_shared/components/blob_viewers';
import {
SNIPPET_VISIBILITY_PRIVATE,
@ -109,6 +113,20 @@ describe('Blob Embeddable', () => {
});
});
it('passes information about render error down to blob header', () => {
createComponent({
blob: {
...BlobMock,
simpleViewer: {
...SimpleViewerMock,
renderError: BLOB_RENDER_ERRORS.REASONS.COLLAPSED.id,
},
},
});
expect(wrapper.find(BlobHeader).props('hasRenderError')).toBe(true);
});
describe('URLS with hash', () => {
beforeEach(() => {
window.location.hash = '#LC2';

View File

@ -45,10 +45,8 @@ describe('Merge request widget rebase component', () => {
expect(text).toContain('Fast-forward merge is not possible.');
expect(text.replace(/\s\s+/g, ' ')).toContain(
'Rebase the source branch onto the target branch or merge target',
'Rebase the source branch onto the target branch.',
);
expect(text).toContain('branch into source branch to allow this merge request to be merged.');
});
it('it should render error message when it fails', done => {

View File

@ -40,16 +40,6 @@ describe Resolvers::Projects::JiraImportsResolver do
let_it_be(:jira_import1) { create(:jira_import_state, :finished, project: project, jira_project_key: 'AA', created_at: 2.days.ago) }
let_it_be(:jira_import2) { create(:jira_import_state, :finished, project: project, jira_project_key: 'BB', created_at: 5.days.ago) }
context 'when feature flag disabled' do
let(:current_user) { user }
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'no Jira import access'
end
context 'when user cannot read Jira imports' do
context 'when anonymous user' do
let(:current_user) { nil }

View File

@ -24,6 +24,36 @@ describe NotesHelper do
project.add_guest(guest)
end
describe '#note_target_title' do
context 'note does not exist' do
it 'returns nil' do
expect(helper.note_target_title(nil)).to be_blank
end
end
context 'target does not exist' do
it 'returns nil' do
note = Note.new
expect(helper.note_target_title(note)).to be_blank
end
end
context 'when given a design target' do
it 'returns nil' do
note = build_stubbed(:note_on_design)
expect(helper.note_target_title(note)).to be_blank
end
end
context 'when given a non-design target' do
it 'returns the issue title' do
issue = build_stubbed(:issue, title: 'Issue 1')
note = build_stubbed(:note, noteable: issue)
expect(helper.note_target_title(note)).to eq('Issue 1')
end
end
end
describe "#notes_max_access_for_users" do
it 'returns access levels' do
expect(helper.note_max_access_for_user(owner_note)).to eq(Gitlab::Access::OWNER)

View File

@ -89,7 +89,7 @@ describe TodosHelper do
context 'when given a non-design todo' do
let(:todo) do
create(:todo, :assigned,
build_stubbed(:todo, :assigned,
user: user,
project: issue.project,
target: issue,

View File

@ -1,148 +0,0 @@
export const pageInfoHeadersWithoutPagination = {
'X-NEXT-PAGE': '',
'X-PAGE': '1',
'X-PER-PAGE': '20',
'X-PREV-PAGE': '',
'X-TOTAL': '19',
'X-TOTAL-PAGES': '1',
};
export const pageInfoHeadersWithPagination = {
'X-NEXT-PAGE': '2',
'X-PAGE': '1',
'X-PER-PAGE': '20',
'X-PREV-PAGE': '',
'X-TOTAL': '21',
'X-TOTAL-PAGES': '2',
};
export const release = {
name: 'Bionic Beaver',
tag_name: '18.04',
description: '## changelog\n\n* line 1\n* line2',
description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>',
author_name: 'Release bot',
author_email: 'release-bot@example.com',
created_at: '2012-05-28T05:00:00-07:00',
commit: {
id: '2695effb5807a22ff3d138d593fd856244e155e7',
short_id: '2695effb',
title: 'Initial commit',
created_at: '2017-07-26T11:08:53.000+02:00',
parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'],
message: 'Initial commit',
author: {
avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
id: 482476,
name: 'John Doe',
path: '/johndoe',
state: 'active',
status_tooltip_html: null,
username: 'johndoe',
web_url: 'https://gitlab.com/johndoe',
},
authored_date: '2012-05-28T04:42:42-07:00',
committer_name: 'Jack Smith',
committer_email: 'jack@example.com',
committed_date: '2012-05-28T04:42:42-07:00',
},
assets: {
count: 6,
sources: [
{
format: 'zip',
url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.zip',
},
{
format: 'tar.gz',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz',
},
{
format: 'tar.bz2',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2',
},
{
format: 'tar',
url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar',
},
],
links: [
{
name: 'release-18.04.dmg',
url: 'https://my-external-hosting.example.com/scrambled-url/',
external: true,
},
{
name: 'binary-linux-amd64',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50',
external: false,
},
],
},
};
export const releases = [
release,
{
name: 'JoJos Bizarre Adventure',
tag_name: '19.00',
description: '## changelog\n\n* line 1\n* line2',
description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>',
author_name: 'Release bot',
author_email: 'release-bot@example.com',
created_at: '2012-05-28T05:00:00-07:00',
commit: {
id: '2695effb5807a22ff3d138d593fd856244e155e7',
short_id: '2695effb',
title: 'Initial commit',
created_at: '2017-07-26T11:08:53.000+02:00',
parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'],
message: 'Initial commit',
author: {
avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
id: 482476,
name: 'John Doe',
path: '/johndoe',
state: 'active',
status_tooltip_html: null,
username: 'johndoe',
web_url: 'https://gitlab.com/johndoe',
},
authored_date: '2012-05-28T04:42:42-07:00',
committer_name: 'Jack Smith',
committer_email: 'jack@example.com',
committed_date: '2012-05-28T04:42:42-07:00',
},
assets: {
count: 4,
sources: [
{
format: 'tar.gz',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz',
},
{
format: 'tar.bz2',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2',
},
{
format: 'tar',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar',
},
],
links: [
{
name: 'binary-linux-amd64',
url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50',
external: false,
},
],
},
},
];

View File

@ -8,24 +8,10 @@ describe Gitlab::JiraImport::BaseImporter do
let(:project) { create(:project) }
describe 'with any inheriting class' do
context 'when an error is returned from the project validation' do
before do
stub_feature_flags(jira_issue_import: false)
allow(project).to receive(:validate_jira_import_settings!)
.and_raise(Projects::ImportService::Error, 'Jira import feature is disabled.')
end
it 'raises exception' do
expect { described_class.new(project) }.to raise_error(Projects::ImportService::Error, 'Jira import feature is disabled.')
end
end
context 'when project validation is ok' do
let!(:jira_service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
allow(project).to receive(:validate_jira_import_settings!)

View File

@ -14,7 +14,6 @@ describe Gitlab::JiraImport::IssuesImporter do
subject { described_class.new(project) }
before do
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
end

View File

@ -15,7 +15,6 @@ describe Gitlab::JiraImport::LabelsImporter do
subject { importer.execute }
before do
stub_feature_flags(jira_issue_import: true)
stub_const('Gitlab::JiraImport::LabelsImporter::MAX_LABELS', 2)
end

View File

@ -50,7 +50,10 @@ describe Iteration do
end
context 'when dates overlap' do
context 'same group' do
let(:start_date) { 5.days.from_now }
let(:due_date) { 6.days.from_now }
shared_examples_for 'overlapping dates' do
context 'when start_date is in range' do
let(:start_date) { 5.days.from_now }
let(:due_date) { 3.weeks.from_now }
@ -59,6 +62,11 @@ describe Iteration do
expect(subject).not_to be_valid
expect(subject.errors[:base]).to include('Dates cannot overlap with other existing Iterations')
end
it 'is not valid even if forced' do
subject.validate # to generate iid/etc
expect { subject.save(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
end
end
context 'when end_date is in range' do
@ -69,25 +77,84 @@ describe Iteration do
expect(subject).not_to be_valid
expect(subject.errors[:base]).to include('Dates cannot overlap with other existing Iterations')
end
it 'is not valid even if forced' do
subject.validate # to generate iid/etc
expect { subject.save(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
end
end
context 'when both overlap' do
let(:start_date) { 5.days.from_now }
let(:due_date) { 6.days.from_now }
it 'is not valid' do
expect(subject).not_to be_valid
expect(subject.errors[:base]).to include('Dates cannot overlap with other existing Iterations')
end
it 'is not valid even if forced' do
subject.validate # to generate iid/etc
expect { subject.save(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
end
end
end
context 'different group' do
let(:start_date) { 5.days.from_now }
let(:due_date) { 6.days.from_now }
let(:group) { create(:group) }
context 'group' do
it_behaves_like 'overlapping dates' do
let(:constraint_name) { 'iteration_start_and_due_daterange_group_id_constraint' }
end
it { is_expected.to be_valid }
context 'different group' do
let(:group) { create(:group) }
it { is_expected.to be_valid }
it 'does not trigger exclusion constraints' do
expect { subject.save }.not_to raise_exception
end
end
context 'in a project' do
let(:project) { create(:project) }
subject { build(:iteration, project: project, start_date: start_date, due_date: due_date) }
it { is_expected.to be_valid }
it 'does not trigger exclusion constraints' do
expect { subject.save }.not_to raise_exception
end
end
end
context 'project' do
let_it_be(:existing_iteration) { create(:iteration, project: project, start_date: 4.days.from_now, due_date: 1.week.from_now) }
subject { build(:iteration, project: project, start_date: start_date, due_date: due_date) }
it_behaves_like 'overlapping dates' do
let(:constraint_name) { 'iteration_start_and_due_daterange_project_id_constraint' }
end
context 'different project' do
let(:project) { create(:project) }
it { is_expected.to be_valid }
it 'does not trigger exclusion constraints' do
expect { subject.save }.not_to raise_exception
end
end
context 'in a group' do
let(:group) { create(:group) }
subject { build(:iteration, group: group, start_date: start_date, due_date: due_date) }
it { is_expected.to be_valid }
it 'does not trigger exclusion constraints' do
expect { subject.save }.not_to raise_exception
end
end
end
end
end

View File

@ -6053,34 +6053,20 @@ describe Project do
end
shared_examples 'jira configuration base checks' do
context 'when feature flag is disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'raise Jira import error', 'Jira import feature is disabled.'
context 'when Jira service was not setup' do
it_behaves_like 'raise Jira import error', 'Jira integration not configured.'
end
context 'when feature flag is enabled' do
before do
stub_feature_flags(jira_issue_import: true)
end
context 'when Jira service exists' do
let!(:jira_service) { create(:jira_service, project: project, active: true) }
context 'when Jira service was not setup' do
it_behaves_like 'raise Jira import error', 'Jira integration not configured.'
end
context 'when Jira service exists' do
let!(:jira_service) { create(:jira_service, project: project, active: true) }
context 'when Jira connection is not valid' do
before do
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/serverInfo')
.to_raise(JIRA::HTTPError.new(double(message: 'Some failure.')))
end
it_behaves_like 'raise Jira import error', 'Unable to connect to the Jira instance. Please check your Jira integration configuration.'
context 'when Jira connection is not valid' do
before do
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/serverInfo')
.to_raise(JIRA::HTTPError.new(double(message: 'Some failure.')))
end
it_behaves_like 'raise Jira import error', 'Unable to connect to the Jira instance. Please check your Jira integration configuration.'
end
end
end
@ -6116,38 +6102,32 @@ describe Project do
it_behaves_like 'jira configuration base checks'
end
context 'when feature flag is enabled' do
context 'when user does not have permissions to run the import' do
before do
stub_feature_flags(jira_issue_import: true)
create(:jira_service, project: project, active: true)
project.add_developer(user)
end
context 'when user does not have permissions to run the import' do
before do
create(:jira_service, project: project, active: true)
it_behaves_like 'raise Jira import error', 'You do not have permissions to run the import.'
end
project.add_developer(user)
end
it_behaves_like 'raise Jira import error', 'You do not have permissions to run the import.'
context 'when user has permission to run import' do
before do
project.add_maintainer(user)
end
context 'when user has permission to run import' do
before do
project.add_maintainer(user)
end
let!(:jira_service) { create(:jira_service, project: project, active: true) }
let!(:jira_service) { create(:jira_service, project: project, active: true) }
context 'when issues feature is disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
context 'when issues feature is disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
it_behaves_like 'raise Jira import error', 'Cannot import because issues are not available in this project.'
end
it_behaves_like 'raise Jira import error', 'Cannot import because issues are not available in this project.'
end
context 'when everything is ok' do
it 'does not return any error' do
expect { subject }.not_to raise_error
end
context 'when everything is ok' do
it 'does not return any error' do
expect { subject }.not_to raise_error
end
end
end

View File

@ -29,10 +29,6 @@ describe 'Starting a Jira Import' do
end
context 'when the user does not have permission' do
before do
stub_feature_flags(jira_issue_import: true)
end
shared_examples 'Jira import does not start' do
it 'does not start the Jira import' do
post_graphql_mutation(mutation, current_user: current_user)
@ -83,53 +79,39 @@ describe 'Starting a Jira Import' do
end
end
context 'when feature jira_issue_import feature flag is disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira import feature is disabled.']
context 'when project has no Jira service' do
it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira integration not configured.']
end
context 'when feature jira_issue_import feature flag is enabled' do
context 'when when project has Jira service' do
let!(:service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
project.reload
stub_jira_service_test
end
context 'when project has no Jira service' do
it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira integration not configured.']
context 'when issues feature are disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
it_behaves_like 'a mutation that returns errors in the response', errors: ['Cannot import because issues are not available in this project.']
end
context 'when when project has Jira service' do
let!(:service) { create(:jira_service, project: project) }
context 'when jira_project_key not provided' do
let(:jira_project_key) { '' }
before do
project.reload
it_behaves_like 'a mutation that returns errors in the response', errors: ['Unable to find Jira project to import data from.']
end
stub_jira_service_test
end
context 'when Jira import successfully scheduled' do
it 'schedules a Jira import' do
post_graphql_mutation(mutation, current_user: current_user)
context 'when issues feature are disabled' do
let_it_be(:project, reload: true) { create(:project, :issues_disabled) }
it_behaves_like 'a mutation that returns errors in the response', errors: ['Cannot import because issues are not available in this project.']
end
context 'when jira_project_key not provided' do
let(:jira_project_key) { '' }
it_behaves_like 'a mutation that returns errors in the response', errors: ['Unable to find Jira project to import data from.']
end
context 'when Jira import successfully scheduled' do
it 'schedules a Jira import' do
post_graphql_mutation(mutation, current_user: current_user)
expect(jira_import['jiraProjectKey']).to eq 'AA'
expect(jira_import['scheduledBy']['username']).to eq current_user.username
expect(project.latest_jira_import).not_to be_nil
expect(project.latest_jira_import).to be_scheduled
end
expect(jira_import['jiraProjectKey']).to eq 'AA'
expect(jira_import['scheduledBy']['username']).to eq current_user.username
expect(project.latest_jira_import).not_to be_nil
expect(project.latest_jira_import).to be_scheduled
end
end
end

View File

@ -11,47 +11,33 @@ describe Gitlab::JiraImport::Stage::FinishImportWorker do
end
describe '#perform' do
context 'when feature flag enabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
let_it_be(:import_label) { create(:label, project: project, title: 'jira-import') }
let_it_be(:imported_issues) { create_list(:labeled_issue, 3, project: project, labels: [import_label]) }
before do
stub_feature_flags(jira_issue_import: true)
expect(Gitlab::JiraImport).to receive(:get_import_label_id).and_return(import_label.id)
expect(Gitlab::JiraImport).to receive(:issue_failures).and_return(2)
jira_import.start!
worker.perform(project.id)
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it 'changes import state to finished' do
expect(project.jira_import_status).to eq('finished')
end
context 'when import started' do
let_it_be(:import_label) { create(:label, project: project, title: 'jira-import') }
let_it_be(:imported_issues) { create_list(:labeled_issue, 3, project: project, labels: [import_label]) }
before do
expect(Gitlab::JiraImport).to receive(:get_import_label_id).and_return(import_label.id)
expect(Gitlab::JiraImport).to receive(:issue_failures).and_return(2)
jira_import.start!
worker.perform(project.id)
end
it 'changes import state to finished' do
expect(project.jira_import_status).to eq('finished')
end
it 'saves imported issues counts' do
latest_jira_import = project.latest_jira_import
expect(latest_jira_import.total_issue_count).to eq(5)
expect(latest_jira_import.failed_to_import_count).to eq(2)
expect(latest_jira_import.imported_issues_count).to eq(3)
end
it 'saves imported issues counts' do
latest_jira_import = project.latest_jira_import
expect(latest_jira_import.total_issue_count).to eq(5)
expect(latest_jira_import.failed_to_import_count).to eq(2)
expect(latest_jira_import.imported_issues_count).to eq(3)
end
end
end

View File

@ -10,34 +10,19 @@ describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
before do
stub_feature_flags(jira_issue_import: true)
jira_import.start!
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when import started' do
before do
jira_import.start!
end
it_behaves_like 'advance to next stage', :notes
end
it_behaves_like 'advance to next stage', :notes
end
end
end

View File

@ -13,65 +13,53 @@ describe Gitlab::JiraImport::Stage::ImportIssuesWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
before do
stub_jira_service_test
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started', :clean_gitlab_redis_cache do
let_it_be(:jira_service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
jira_import.start!
allow_next_instance_of(Gitlab::JiraImport::IssuesImporter) do |instance|
allow(instance).to receive(:fetch_issues).and_return([])
end
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
context 'when start_at is nil' do
it_behaves_like 'advance to next stage', :attachments
end
context 'when import started', :clean_gitlab_redis_cache do
let_it_be(:jira_service) { create(:jira_service, project: project) }
context 'when start_at is zero' do
before do
jira_import.start!
allow_next_instance_of(Gitlab::JiraImport::IssuesImporter) do |instance|
allow(instance).to receive(:fetch_issues).and_return([])
end
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(0)
end
context 'when start_at is nil' do
it_behaves_like 'advance to next stage', :attachments
it_behaves_like 'advance to next stage', :issues
end
context 'when start_at is greater than zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(25)
end
context 'when start_at is zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(0)
end
it_behaves_like 'advance to next stage', :issues
end
it_behaves_like 'advance to next stage', :issues
context 'when start_at is below zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(-1)
end
context 'when start_at is greater than zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(25)
end
it_behaves_like 'advance to next stage', :issues
end
context 'when start_at is below zero' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(-1)
end
it_behaves_like 'advance to next stage', :attachments
end
it_behaves_like 'advance to next stage', :attachments
end
end
end

View File

@ -13,48 +13,33 @@ describe Gitlab::JiraImport::Stage::ImportLabelsWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
let!(:jira_service) { create(:jira_service, project: project) }
before do
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
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
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
it_behaves_like 'advance to next stage', :issues
context 'when import started' do
let!(:jira_service) { create(:jira_service, project: project) }
before do
stub_jira_service_test
jira_import.start!
WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/label?maxResults=500&startAt=0')
.to_return(body: {}.to_json )
it 'executes labels importer' do
expect_next_instance_of(Gitlab::JiraImport::LabelsImporter) do |instance|
expect(instance).to receive(:execute).and_return(Gitlab::JobWaiter.new)
end
it_behaves_like 'advance to next stage', :issues
it 'executes labels importer' do
expect_next_instance_of(Gitlab::JiraImport::LabelsImporter) do |instance|
expect(instance).to receive(:execute).and_return(Gitlab::JobWaiter.new)
end
described_class.new.perform(project.id)
end
described_class.new.perform(project.id)
end
end
end

View File

@ -10,34 +10,19 @@ describe Gitlab::JiraImport::Stage::ImportNotesWorker do
end
describe '#perform' do
context 'when feature flag disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when feature flag enabled' do
let_it_be(:jira_import) { create(:jira_import_state, :scheduled, project: project) }
context 'when import started' do
before do
stub_feature_flags(jira_issue_import: true)
jira_import.start!
end
context 'when import did not start' do
it_behaves_like 'cannot do Jira import'
it_behaves_like 'does not advance to next stage'
end
context 'when import started' do
before do
jira_import.start!
end
it_behaves_like 'advance to next stage', :finish
end
it_behaves_like 'advance to next stage', :finish
end
end
end

View File

@ -12,81 +12,63 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do
end
describe '#perform' do
context 'when feature flag not disabled' do
before do
stub_feature_flags(jira_issue_import: false)
end
let_it_be(:jira_import, reload: true) { create(:jira_import_state, project: project, jid: jid) }
it 'exits because import not allowed' do
context 'when import is not scheduled' do
it 'exits because import not started' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
end
context 'when feature flag enabled' do
let_it_be(:jira_import, reload: true) { create(:jira_import_state, project: project, jid: jid) }
context 'when import is scheduled' do
before do
stub_feature_flags(jira_issue_import: true)
jira_import.schedule!
end
context 'when import is not scheduled' do
it 'exits because import not started' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
it 'advances to importing labels' do
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
worker.perform(project.id)
end
worker.perform(project.id)
end
end
context 'when import is started' do
before do
jira_import.update!(status: :started)
end
context 'when import is scheduled' do
before do
jira_import.schedule!
end
context 'when this is the same worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
worker.perform(project.id)
end
end
context 'when import is started' do
before do
jira_import.update!(status: :started)
end
context 'when this is the same worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async)
worker.perform(project.id)
end
end
context 'when this is a different worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return('87654321')
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
end
end
context 'when import is finished' do
before do
jira_import.update!(status: :finished)
end
context 'when this is a different worker that stated import' do
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
allow(worker).to receive(:jid).and_return('87654321')
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
end
end
context 'when import is finished' do
before do
jira_import.update!(status: :finished)
end
it 'advances to importing labels' do
allow(worker).to receive(:jid).and_return(jid)
expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async)
worker.perform(project.id)
end
end
end
end

View File

@ -787,10 +787,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.130.0.tgz#0c2f3cdc0a4b0f54c47b2861c8fa31b2a58c570a"
integrity sha512-azJ1E9PBk6fGOaP6816BSr8oYrQu3m3BbYZwWOCUp8AfbZuf0ZOZVYmlR9i/eAOhoqqqmwF8hYCK2VjAklbpPA==
"@gitlab/ui@15.5.0":
version "15.5.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-15.5.0.tgz#96b563875ab8f587ee0e55d16c14c98f1d698957"
integrity sha512-AmYPR5X2UtipfkrZd8e8VvOo26YKHfXT+2XRd+Hysjdg+DBaGcUDTbO67cMb9dKkFPSgPdN67SgV+C8CBuBONQ==
"@gitlab/ui@15.6.0":
version "15.6.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-15.6.0.tgz#0fc4ca7fd6ecc3c1be7e127dce3dde78fb4faa06"
integrity sha512-drb+f+xcAOtov2mAE3FX49845Fe4o41/jTKDxONDlsescKggZBXaSl1PQtL4EkspllIFb3JYdvL0sXbmp/dz3w==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"