Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-02-01 21:09:15 +00:00
parent d7774ee304
commit 3feea9b607
36 changed files with 366 additions and 214 deletions

View File

@ -1,12 +1,17 @@
<script>
import { GlAvatarLink, GlAvatarLabeled, GlBadge } from '@gitlab/ui';
import { USER_AVATAR_SIZE } from '../constants';
import { GlAvatarLink, GlAvatarLabeled, GlBadge, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { truncate } from '~/lib/utils/text_utility';
import { USER_AVATAR_SIZE, LENGTH_OF_USER_NOTE_TOOLTIP } from '../constants';
export default {
directives: {
GlTooltip: GlTooltipDirective,
},
components: {
GlAvatarLink,
GlAvatarLabeled,
GlBadge,
GlIcon,
},
props: {
user: {
@ -22,6 +27,9 @@ export default {
adminUserHref() {
return this.adminUserPath.replace('id', this.user.username);
},
userNoteShort() {
return truncate(this.user.note, LENGTH_OF_USER_NOTE_TOOLTIP);
},
},
USER_AVATAR_SIZE,
};
@ -42,6 +50,9 @@ export default {
:sub-label="user.email"
>
<template #meta>
<div v-if="user.note" class="gl-text-gray-500 gl-p-1">
<gl-icon v-gl-tooltip="userNoteShort" name="document" />
</div>
<div v-for="(badge, idx) in user.badges" :key="idx" class="gl-p-1">
<gl-badge class="gl-display-flex!" size="sm" :variant="badge.variant">{{
badge.text

View File

@ -1,3 +1,5 @@
export const USER_AVATAR_SIZE = 32;
export const SHORT_DATE_FORMAT = 'd mmm, yyyy';
export const LENGTH_OF_USER_NOTE_TOOLTIP = 100;

View File

@ -1,7 +1,7 @@
import { isEmpty, isString } from 'lodash';
import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
export const headerTime = (state) => (state.job.started ? state.job.started : state.job.created_at);
export const headerTime = (state) => state.job.started ?? state.job.created_at;
export const hasForwardDeploymentFailure = (state) =>
state?.job?.failure_reason === 'forward_deployment_failure';
@ -28,11 +28,9 @@ export const hasEnvironment = (state) => !isEmpty(state.job.deployment_status);
export const hasTrace = (state) =>
state.job.has_trace || (!isEmpty(state.job.status) && state.job.status.group === 'running');
export const emptyStateIllustration = (state) =>
(state.job && state.job.status && state.job.status.illustration) || {};
export const emptyStateIllustration = (state) => state?.job?.status?.illustration || {};
export const emptyStateAction = (state) =>
(state.job && state.job.status && state.job.status.action) || null;
export const emptyStateAction = (state) => state?.job?.status?.action || null;
/**
* Shared runners limit is only rendered when
@ -48,4 +46,4 @@ export const shouldRenderSharedRunnerLimitWarning = (state) =>
export const isScrollingDown = (state) => isScrolledToBottom() && !state.isTraceComplete;
export const hasRunnersForProject = (state) =>
state.job.runners.available && !state.job.runners.online;
state?.job?.runners?.available && !state?.job?.runners?.online;

View File

@ -15,7 +15,7 @@ module Registrations
if current_user.save
hide_advanced_issues
if experiment_enabled?(:default_to_issues_board) && learn_gitlab.available?
if learn_gitlab.available?
redirect_to namespace_project_board_path(params[:namespace_path], learn_gitlab.project, learn_gitlab.board)
else
redirect_to group_path(params[:namespace_path])

View File

@ -26,42 +26,23 @@ class UserRecentEventsFinder
@params = params
end
# rubocop: disable CodeReuse/ActiveRecord
def execute
return Event.none unless can?(current_user, :read_user_profile, target_user)
recent_events(params[:offset] || 0)
.joins(:project)
target_events
.with_associations
.limit_recent(limit, params[:offset])
.order_created_desc
end
# rubocop: enable CodeReuse/ActiveRecord
private
# rubocop: disable CodeReuse/ActiveRecord
def recent_events(offset)
sql = <<~SQL
(#{projects}) AS projects_for_join
JOIN (#{target_events.to_sql}) AS #{Event.table_name}
ON #{Event.table_name}.project_id = projects_for_join.id
SQL
# Workaround for https://github.com/rails/rails/issues/24193
Event.from([Arel.sql(sql)])
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def target_events
Event.where(author: target_user)
end
# rubocop: enable CodeReuse/ActiveRecord
def projects
target_user.project_interactions.to_sql
end
def limit
return DEFAULT_LIMIT unless params[:limit].present?

View File

@ -7,19 +7,19 @@ class UserCallout < ApplicationRecord
gke_cluster_integration: 1,
gcp_signup_offer: 2,
cluster_security_warning: 3,
gold_trial: 4, # EE-only
geo_enable_hashed_storage: 5, # EE-only
geo_migrate_hashed_storage: 6, # EE-only
canary_deployment: 7, # EE-only
gold_trial_billings: 8, # EE-only
gold_trial: 4, # EE-only
geo_enable_hashed_storage: 5, # EE-only
geo_migrate_hashed_storage: 6, # EE-only
canary_deployment: 7, # EE-only
gold_trial_billings: 8, # EE-only
suggest_popover_dismissed: 9,
tabs_position_highlight: 10,
threat_monitoring_info: 11, # EE-only
account_recovery_regular_check: 12, # EE-only
threat_monitoring_info: 11, # EE-only
account_recovery_regular_check: 12, # EE-only
webhooks_moved: 13,
service_templates_deprecated: 14,
admin_integrations_moved: 15,
web_ide_alert_dismissed: 16, # no longer in use
web_ide_alert_dismissed: 16, # no longer in use
active_user_count_threshold: 18, # EE-only
buy_pipeline_minutes_notification_dot: 19, # EE-only
personal_access_token_expiry: 21, # EE-only
@ -27,8 +27,9 @@ class UserCallout < ApplicationRecord
customize_homepage: 23,
feature_flags_new_version: 24,
registration_enabled_callout: 25,
new_user_signups_cap_reached: 26, # EE-only
unfinished_tag_cleanup_callout: 27
new_user_signups_cap_reached: 26, # EE-only
unfinished_tag_cleanup_callout: 27,
eoa_bronze_plan_banner: 28 # EE-only
}
validates :user, presence: true

View File

@ -10,6 +10,7 @@ module Admin
expose :email
expose :last_activity_on
expose :avatar_url
expose :note
expose :badges do |user|
user_badges_in_admin_section(user)
end

View File

@ -2,6 +2,6 @@
module Admin
class UserSerializer < BaseSerializer
entity UserEntity
entity Admin::UserEntity
end
end

View File

@ -0,0 +1,5 @@
---
title: Display epic related events on user activity feed
merge_request: 52611
author:
type: added

View File

@ -1,8 +0,0 @@
---
name: default_to_issues_board_experiment_percentage
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43939
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/268298
milestone: '13.5'
type: experiment
group: group::conversion
default_enabled: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -376,7 +376,11 @@ from any device you're logged into.
## Suggest Changes
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/18008) in GitLab 11.6.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/18008) in GitLab 11.6.
> - Custom commit messages for suggestions were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25381) in GitLab 13.9.
> - Custom commit messages for suggestions is disabled on GitLab.com and not recommended for production use.
> - Custom commit messages for suggestions was deployed behind a [feature flag](../feature_flags.md), disabled by default.
> - To use custom commit messages for suggestions in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-custom-commit-messages-for-suggestions). **(FREE SELF)**
As a reviewer, you're able to suggest code changes with a simple
Markdown syntax in Merge Request Diff threads. Then, the
@ -388,24 +392,50 @@ the merge request authored by the user that applied them.
1. Choose a line of code to be changed, add a new comment, then click
on the **Insert suggestion** icon in the toolbar:
![Add a new comment](img/suggestion_button_v12_7.png)
![Add a new comment](img/suggestion_button_v13_9.png)
1. In the comment, add your suggestion to the pre-populated code block:
![Add a suggestion into a code block tagged properly](img/make_suggestion_v12_7.png)
![Add a suggestion into a code block tagged properly](img/make_suggestion_v13_9.png)
1. Click either **Start a review** or **Add to review** to add your comment to a [review](#merge-request-reviews), or **Add comment now** to add the comment to the thread immediately.
The Suggestion in the comment can be applied by the merge request author
directly from the merge request:
![Apply suggestions](img/apply_suggestion_v12_7.png)
![Apply suggestions](img/apply_suggestion_v13_9.png)
1. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25381) in GitLab 13.9,
you can opt to add a custom commit message to describe your change. If you don't
specify it, the default commit message will be used. Note that [this feature may not be available to you](#enable-or-disable-custom-commit-messages-for-suggestions).
Also, it is not supported for [batch suggestions](#batch-suggestions).
![Custom commit](img/custom_commit_v13_9.png)
After the author applies a Suggestion, it will be marked with the **Applied** label,
the thread will be automatically resolved, and GitLab will create a new commit
and push the suggested change directly into the codebase in the merge request's
branch. [Developer permission](../permissions.md) is required to do so.
### Enable or disable Custom commit messages for suggestions **(FREE SELF)**
Custom commit messages for suggestions is under development and not ready for production use. It is
deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can enable it.
To enable custom commit messages for suggestions:
```ruby
Feature.enable(:suggestions_custom_commit)
```
To disable custom commit messages for suggestions:
```ruby
Feature.disable(:suggestions_custom_commit)
```
### Multi-line Suggestions
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53310) in GitLab 11.10.

View File

@ -70,10 +70,6 @@ module Gitlab
tracking_category: 'Growth::Conversion::Experiment::GroupOnlyTrials',
use_backwards_compatible_subject_index: true
},
default_to_issues_board: {
tracking_category: 'Growth::Conversion::Experiment::DefaultToIssuesBoard',
use_backwards_compatible_subject_index: true
},
jobs_empty_state: {
tracking_category: 'Growth::Activation::Experiment::JobsEmptyState'
},

View File

@ -12,6 +12,8 @@
# redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] }
module Gitlab
class UsageData
DEPRECATED_VALUE = -1000
CE_MEMOIZED_VALUES = %i(
issue_minimum_id
issue_maximum_id
@ -584,26 +586,33 @@ module Gitlab
user_auth_by_provider: distinct_count_user_auth_by_provider(time_period),
unique_users_all_imports: unique_users_all_imports(time_period),
bulk_imports: {
gitlab: distinct_count(::BulkImport.where(time_period, source_type: :gitlab), :user_id)
gitlab: DEPRECATED_VALUE,
gitlab_v1: count(::BulkImport.where(time_period, source_type: :gitlab))
},
project_imports: project_imports(time_period),
issue_imports: issue_imports(time_period),
group_imports: group_imports(time_period),
# Deprecated data to be removed
projects_imported: {
total: distinct_count(::Project.where(time_period).where.not(import_type: nil), :creator_id),
gitlab_project: projects_imported_count('gitlab_project', time_period),
gitlab: projects_imported_count('gitlab', time_period),
github: projects_imported_count('github', time_period),
bitbucket: projects_imported_count('bitbucket', time_period),
bitbucket_server: projects_imported_count('bitbucket_server', time_period),
gitea: projects_imported_count('gitea', time_period),
git: projects_imported_count('git', time_period),
manifest: projects_imported_count('manifest', time_period)
total: DEPRECATED_VALUE,
gitlab_project: DEPRECATED_VALUE,
gitlab: DEPRECATED_VALUE,
github: DEPRECATED_VALUE,
bitbucket: DEPRECATED_VALUE,
bitbucket_server: DEPRECATED_VALUE,
gitea: DEPRECATED_VALUE,
git: DEPRECATED_VALUE,
manifest: DEPRECATED_VALUE
},
issues_imported: {
jira: distinct_count(::JiraImportState.where(time_period), :user_id),
fogbugz: projects_imported_count('fogbugz', time_period),
phabricator: projects_imported_count('phabricator', time_period),
csv: distinct_count(Issues::CsvImport.where(time_period), :user_id)
jira: DEPRECATED_VALUE,
fogbugz: DEPRECATED_VALUE,
phabricator: DEPRECATED_VALUE,
csv: DEPRECATED_VALUE
},
groups_imported: distinct_count(::GroupImportState.where(time_period), :user_id)
groups_imported: DEPRECATED_VALUE
# End of deprecated keys
}
end
# rubocop: enable CodeReuse/ActiveRecord
@ -900,8 +909,38 @@ module Gitlab
count relation, start: deployment_minimum_id, finish: deployment_maximum_id
end
def project_imports(time_period)
{
gitlab_project: projects_imported_count('gitlab_project', time_period),
gitlab: projects_imported_count('gitlab', time_period),
github: projects_imported_count('github', time_period),
bitbucket: projects_imported_count('bitbucket', time_period),
bitbucket_server: projects_imported_count('bitbucket_server', time_period),
gitea: projects_imported_count('gitea', time_period),
git: projects_imported_count('git', time_period),
manifest: projects_imported_count('manifest', time_period),
gitlab_migration: count(::BulkImports::Entity.where(time_period).project_entity) # rubocop: disable CodeReuse/ActiveRecord
}
end
def projects_imported_count(from, time_period)
distinct_count(::Project.imported_from(from).where(time_period).where.not(import_type: nil), :creator_id) # rubocop: disable CodeReuse/ActiveRecord
count(::Project.imported_from(from).where(time_period).where.not(import_type: nil)) # rubocop: disable CodeReuse/ActiveRecord
end
def issue_imports(time_period)
{
jira: count(::JiraImportState.where(time_period)), # rubocop: disable CodeReuse/ActiveRecord
fogbugz: projects_imported_count('fogbugz', time_period),
phabricator: projects_imported_count('phabricator', time_period),
csv: count(Issues::CsvImport.where(time_period)) # rubocop: disable CodeReuse/ActiveRecord
}
end
def group_imports(time_period)
{
group_import: count(::GroupImportState.where(time_period)), # rubocop: disable CodeReuse/ActiveRecord
gitlab_migration: count(::BulkImports::Entity.where(time_period).group_entity) # rubocop: disable CodeReuse/ActiveRecord
}
end
# rubocop:disable CodeReuse/ActiveRecord

View File

@ -10125,9 +10125,6 @@ msgstr ""
msgid "DevopsAdoption|Filter by name"
msgstr ""
msgid "DevopsAdoption|Group data pending until the start of next month"
msgstr ""
msgid "DevopsAdoption|Issues"
msgstr ""

View File

@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Registrations::ExperienceLevelsController do
include AfterNextHelpers
let_it_be(:namespace) { create(:group, path: 'group-path' ) }
let_it_be(:user) { create(:user) }
@ -45,6 +47,9 @@ RSpec.describe Registrations::ExperienceLevelsController do
end
context 'with an authenticated user' do
let_it_be(:project) { build(:project, namespace: namespace, creator: user, path: 'project-path') }
let_it_be(:issues_board) { build(:board, id: 123, project: project) }
before do
sign_in(user)
stub_experiment_for_subject(onboarding_issues: true)
@ -85,91 +90,57 @@ RSpec.describe Registrations::ExperienceLevelsController do
end
end
describe 'redirection' do
let(:project) { build(:project, namespace: namespace, creator: user, path: 'project-path') }
let(:issues_board) { build(:board, id: 123, project: project) }
context 'when "Learn GitLab" project exists' do
let(:learn_gitlab_available?) { true }
before do
stub_experiment_for_subject(
onboarding_issues: true,
default_to_issues_board: default_to_issues_board_xp?
)
allow_next_instance_of(LearnGitlab) do |learn_gitlab|
allow(learn_gitlab).to receive(:available?).and_return(learn_gitlab_available?)
allow(learn_gitlab).to receive(:project).and_return(project)
allow(learn_gitlab).to receive(:board).and_return(issues_board)
allow(learn_gitlab).to receive(:label).and_return(double(id: 1))
end
end
context 'when namespace_path param is missing' do
let(:params) { super().merge(namespace_path: nil) }
context 'redirection' do
context 'when namespace_path param is missing' do
let(:params) { super().merge(namespace_path: nil) }
where(
default_to_issues_board_xp?: [true, false],
learn_gitlab_available?: [true, false]
)
where(
learn_gitlab_available?: [true, false]
)
with_them do
it { is_expected.to redirect_to('/') }
end
end
context 'when we have a namespace_path param' do
using RSpec::Parameterized::TableSyntax
where(:default_to_issues_board_xp?, :learn_gitlab_available?, :path) do
true | true | '/group-path/project-path/-/boards/123'
true | false | '/group-path'
false | true | '/group-path'
false | false | '/group-path'
end
with_them do
it { is_expected.to redirect_to(path) }
end
end
end
describe 'applying the chosen level' do
context 'when a "Learn GitLab" project is available' do
before do
allow_next_instance_of(LearnGitlab) do |learn_gitlab|
allow(learn_gitlab).to receive(:available?).and_return(true)
allow(learn_gitlab).to receive(:label).and_return(double(id: 1))
with_them do
it { is_expected.to redirect_to('/') }
end
end
context 'when novice' do
let(:params) { super().merge(experience_level: :novice) }
context 'when we have a namespace_path param' do
using RSpec::Parameterized::TableSyntax
it 'adds a BoardLabel' do
expect_next_instance_of(Boards::UpdateService) do |service|
expect(service).to receive(:execute)
end
subject
where(:learn_gitlab_available?, :path) do
true | '/group-path/project-path/-/boards/123'
false | '/group-path'
end
end
context 'when experienced' do
let(:params) { super().merge(experience_level: :experienced) }
it 'does not add a BoardLabel' do
expect(Boards::UpdateService).not_to receive(:new)
subject
with_them do
it { is_expected.to redirect_to(path) }
end
end
end
context 'when no "Learn GitLab" project exists' do
context 'when novice' do
let(:params) { super().merge(experience_level: :novice) }
before do
allow_next_instance_of(LearnGitlab) do |learn_gitlab|
allow(learn_gitlab).to receive(:available?).and_return(false)
end
it 'adds a BoardLabel' do
expect_next(Boards::UpdateService).to receive(:execute)
subject
end
end
context 'when experienced' do
let(:params) { super().merge(experience_level: :experienced) }
it 'does not add a BoardLabel' do
expect(Boards::UpdateService).not_to receive(:new)
@ -178,6 +149,20 @@ RSpec.describe Registrations::ExperienceLevelsController do
end
end
end
context 'when no "Learn GitLab" project exists' do
let(:params) { super().merge(experience_level: :novice) }
before do
allow_next(LearnGitlab).to receive(:available?).and_return(false)
end
it 'does not add a BoardLabel' do
expect(Boards::UpdateService).not_to receive(:new)
subject
end
end
end
context 'when user update fails' do

View File

@ -308,12 +308,6 @@ FactoryBot.define do
end
end
trait :codequality_report do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :codequality, job: build)
end
end
trait :test_reports do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :junit, job: build)

View File

@ -4,18 +4,30 @@ FactoryBot.define do
factory :ci_pipeline_artifact, class: 'Ci::PipelineArtifact' do
pipeline factory: :ci_pipeline
project { pipeline.project }
file_type { :code_coverage }
file_format { :raw }
file_store { ObjectStorage::SUPPORTED_STORES.first }
size { 1.megabytes }
size { 1.megabyte }
file_type { :code_coverage }
after(:build) do |artifact, _evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/pipeline_artifacts/code_coverage.json'), 'application/json')
end
trait :with_multibyte_characters do
trait :with_coverage_report do
file_type { :code_coverage }
after(:build) do |artifact, _evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/pipeline_artifacts/code_coverage.json'), 'application/json')
end
size { file.size }
end
trait :with_coverage_multibyte_characters do
file_type { :code_coverage }
size { { "utf8" => "" }.to_json.bytesize }
after(:build) do |artifact, _evaluator|
artifact.file = CarrierWaveStringFile.new_file(
file_content: { "utf8" => "" }.to_json,
@ -26,23 +38,26 @@ FactoryBot.define do
end
trait :with_code_coverage_with_multiple_files do
file_type { :code_coverage }
after(:build) do |artifact, _evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/pipeline_artifacts/code_coverage_with_multiple_files.json'), 'application/json'
)
end
size { file.size }
size { 1.megabyte }
end
trait :codequality_report do
trait :with_codequality_report do
file_type { :code_quality }
size { 2.megabytes }
after(:build) do |artifact, _evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/pipeline_artifacts/code_quality.json'), 'application/json')
end
size { file.size }
end
end
end

View File

@ -93,14 +93,6 @@ FactoryBot.define do
end
end
trait :with_codequality_report do
status { :success }
after(:build) do |pipeline, evaluator|
pipeline.builds << build(:ci_build, :codequality_report, pipeline: pipeline, project: pipeline.project)
end
end
trait :with_test_reports do
status { :success }
@ -159,13 +151,13 @@ FactoryBot.define do
trait :with_coverage_report_artifact do
after(:build) do |pipeline, evaluator|
pipeline.pipeline_artifacts << build(:ci_pipeline_artifact, pipeline: pipeline, project: pipeline.project)
pipeline.pipeline_artifacts << build(:ci_pipeline_artifact, :with_coverage_report, pipeline: pipeline, project: pipeline.project)
end
end
trait :with_codequality_report_artifact do
trait :with_quality_report_artifact do
after(:build) do |pipeline, evaluator|
pipeline.pipeline_artifacts << build(:ci_pipeline_artifact, :codequality_report, pipeline: pipeline, project: pipeline.project)
pipeline.pipeline_artifacts << build(:ci_pipeline_artifact, :with_codequality_report, pipeline: pipeline, project: pipeline.project)
end
end

View File

@ -51,6 +51,20 @@ RSpec.describe UserRecentEventsFinder do
end
end
describe 'issue activity events' do
let(:issue) { create(:issue, project: public_project) }
let(:note) { create(:note_on_issue, noteable: issue, project: public_project) }
let!(:event_a) { create(:event, :commented, target: note, author: project_owner) }
let!(:event_b) { create(:event, :closed, target: issue, author: project_owner) }
it 'includes all issue related events', :aggregate_failures do
events = finder.execute
expect(events).to include(event_a)
expect(events).to include(event_b)
end
end
context 'limits' do
before do
stub_const("#{described_class}::DEFAULT_LIMIT", 1)

View File

@ -1,7 +1,10 @@
import { GlAvatarLink, GlAvatarLabeled, GlBadge } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { GlAvatarLink, GlAvatarLabeled, GlBadge, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import AdminUserAvatar from '~/admin/users/components/user_avatar.vue';
import { LENGTH_OF_USER_NOTE_TOOLTIP } from '~/admin/users/constants';
import { truncate } from '~/lib/utils/text_utility';
import { users, paths } from '../mock_data';
describe('AdminUserAvatar component', () => {
@ -9,17 +12,25 @@ describe('AdminUserAvatar component', () => {
const user = users[0];
const adminUserPath = paths.adminUser;
const findNote = () => wrapper.find(GlIcon);
const findAvatar = () => wrapper.find(GlAvatarLabeled);
const findAvatarLink = () => wrapper.find(GlAvatarLink);
const findAllBadges = () => wrapper.findAll(GlBadge);
const findTooltip = () => getBinding(findNote().element, 'gl-tooltip');
const initComponent = (props = {}) => {
wrapper = mount(AdminUserAvatar, {
wrapper = shallowMount(AdminUserAvatar, {
propsData: {
user,
adminUserPath,
...props,
},
directives: {
GlTooltip: createMockDirective(),
},
stubs: {
GlAvatarLabeled,
},
});
};
@ -53,11 +64,58 @@ describe('AdminUserAvatar component', () => {
expect(findAvatar().attributes('src')).toBe(user.avatarUrl);
});
it('renders a user note icon', () => {
expect(findNote().exists()).toBe(true);
expect(findNote().props('name')).toBe('document');
});
it("renders the user's note tooltip", () => {
const tooltip = findTooltip();
expect(tooltip).toBeDefined();
expect(tooltip.value).toBe(user.note);
});
it("renders the user's badges", () => {
findAllBadges().wrappers.forEach((badge, idx) => {
expect(badge.text()).toBe(user.badges[idx].text);
expect(badge.props('variant')).toBe(user.badges[idx].variant);
});
});
describe('and the user note is very long', () => {
const noteText = new Array(LENGTH_OF_USER_NOTE_TOOLTIP + 1).join('a');
beforeEach(() => {
initComponent({
user: {
...user,
note: noteText,
},
});
});
it("renders a truncated user's note tooltip", () => {
const tooltip = findTooltip();
expect(tooltip).toBeDefined();
expect(tooltip.value).toBe(truncate(noteText, LENGTH_OF_USER_NOTE_TOOLTIP));
});
});
describe('and the user does not have a note', () => {
beforeEach(() => {
initComponent({
user: {
...user,
note: null,
},
});
});
it('does not render a user note', () => {
expect(findNote().exists()).toBe(false);
});
});
});
});

View File

@ -14,6 +14,7 @@ export const users = [
],
projectsCount: 0,
actions: [],
note: 'Create per issue #999',
},
];

View File

@ -15,8 +15,7 @@ RSpec.describe Gitlab::Experimentation::EXPERIMENTS do
:invite_members_empty_group_version_a,
:contact_sales_btn_in_app,
:customize_homepage,
:group_only_trials,
:default_to_issues_board
:group_only_trials
]
backwards_compatible_experiment_keys = described_class.filter { |_, v| v[:use_backwards_compatible_subject_index] }.keys

View File

@ -255,8 +255,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
for_defined_days_back do
user = create(:user)
create(:bulk_import, user: user)
%w(gitlab_project gitlab github bitbucket bitbucket_server gitea git manifest fogbugz phabricator).each do |type|
create(:project, import_type: type, creator_id: user.id)
end
@ -265,72 +263,113 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
create(:jira_import_state, :finished, project: jira_project)
create(:issue_csv_import, user: user)
group = create(:group)
group.add_owner(user)
create(:group_import_state, group: group, user: user)
bulk_import = create(:bulk_import, user: user)
create(:bulk_import_entity, :group_entity, bulk_import: bulk_import)
create(:bulk_import_entity, :project_entity, bulk_import: bulk_import)
end
expect(described_class.usage_activity_by_stage_manage({})).to include(
{
bulk_imports: {
gitlab: 2
gitlab_v1: 2,
gitlab: Gitlab::UsageData::DEPRECATED_VALUE
},
projects_imported: {
total: 2,
gitlab_project: 2,
gitlab: 2,
github: 2,
project_imports: {
bitbucket: 2,
bitbucket_server: 2,
gitea: 2,
git: 2,
gitea: 2,
github: 2,
gitlab: 2,
gitlab_migration: 2,
gitlab_project: 2,
manifest: 2
},
issues_imported: {
issue_imports: {
jira: 2,
fogbugz: 2,
phabricator: 2,
csv: 2
}
},
group_imports: {
group_import: 2,
gitlab_migration: 2
},
projects_imported: {
total: Gitlab::UsageData::DEPRECATED_VALUE,
gitlab_project: Gitlab::UsageData::DEPRECATED_VALUE,
gitlab: Gitlab::UsageData::DEPRECATED_VALUE,
github: Gitlab::UsageData::DEPRECATED_VALUE,
bitbucket: Gitlab::UsageData::DEPRECATED_VALUE,
bitbucket_server: Gitlab::UsageData::DEPRECATED_VALUE,
gitea: Gitlab::UsageData::DEPRECATED_VALUE,
git: Gitlab::UsageData::DEPRECATED_VALUE,
manifest: Gitlab::UsageData::DEPRECATED_VALUE
},
issues_imported: {
jira: Gitlab::UsageData::DEPRECATED_VALUE,
fogbugz: Gitlab::UsageData::DEPRECATED_VALUE,
phabricator: Gitlab::UsageData::DEPRECATED_VALUE,
csv: Gitlab::UsageData::DEPRECATED_VALUE
},
groups_imported: Gitlab::UsageData::DEPRECATED_VALUE
}
)
expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period)).to include(
{
bulk_imports: {
gitlab: 1
gitlab_v1: 1,
gitlab: Gitlab::UsageData::DEPRECATED_VALUE
},
projects_imported: {
total: 1,
gitlab_project: 1,
gitlab: 1,
github: 1,
project_imports: {
bitbucket: 1,
bitbucket_server: 1,
gitea: 1,
git: 1,
gitea: 1,
github: 1,
gitlab: 1,
gitlab_migration: 1,
gitlab_project: 1,
manifest: 1
},
issues_imported: {
issue_imports: {
jira: 1,
fogbugz: 1,
phabricator: 1,
csv: 1
}
},
group_imports: {
group_import: 1,
gitlab_migration: 1
},
projects_imported: {
total: Gitlab::UsageData::DEPRECATED_VALUE,
gitlab_project: Gitlab::UsageData::DEPRECATED_VALUE,
gitlab: Gitlab::UsageData::DEPRECATED_VALUE,
github: Gitlab::UsageData::DEPRECATED_VALUE,
bitbucket: Gitlab::UsageData::DEPRECATED_VALUE,
bitbucket_server: Gitlab::UsageData::DEPRECATED_VALUE,
gitea: Gitlab::UsageData::DEPRECATED_VALUE,
git: Gitlab::UsageData::DEPRECATED_VALUE,
manifest: Gitlab::UsageData::DEPRECATED_VALUE
},
issues_imported: {
jira: Gitlab::UsageData::DEPRECATED_VALUE,
fogbugz: Gitlab::UsageData::DEPRECATED_VALUE,
phabricator: Gitlab::UsageData::DEPRECATED_VALUE,
csv: Gitlab::UsageData::DEPRECATED_VALUE
},
groups_imported: Gitlab::UsageData::DEPRECATED_VALUE
}
)
end
it 'includes group imports usage data' do
for_defined_days_back do
user = create(:user)
group = create(:group)
group.add_owner(user)
create(:group_import_state, group: group, user: user)
end
expect(described_class.usage_activity_by_stage_manage({}))
.to include(groups_imported: 2)
expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period))
.to include(groups_imported: 1)
end
def omniauth_providers
[
OpenStruct.new(name: 'google_oauth2'),

View File

@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::PipelineArtifact, type: :model do
let(:coverage_report) { create(:ci_pipeline_artifact) }
let(:coverage_report) { create(:ci_pipeline_artifact, :with_coverage_report) }
describe 'associations' do
it { is_expected.to belong_to(:pipeline) }
@ -15,7 +15,7 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
it_behaves_like 'UpdateProjectStatistics' do
let_it_be(:pipeline, reload: true) { create(:ci_pipeline) }
subject { build(:ci_pipeline_artifact, pipeline: pipeline) }
subject { build(:ci_pipeline_artifact, :with_code_coverage_with_multiple_files, pipeline: pipeline) }
end
describe 'validations' do
@ -51,7 +51,7 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
end
describe 'file is being stored' do
subject { create(:ci_pipeline_artifact) }
subject { create(:ci_pipeline_artifact, :with_coverage_report) }
context 'when existing object has local store' do
it_behaves_like 'mounted file in local store'
@ -68,7 +68,7 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
end
context 'when file contains multi-byte characters' do
let(:coverage_report_multibyte) { create(:ci_pipeline_artifact, :with_multibyte_characters) }
let(:coverage_report_multibyte) { create(:ci_pipeline_artifact, :with_coverage_multibyte_characters) }
it 'sets the size in bytesize' do
expect(coverage_report_multibyte.size).to eq(14)
@ -83,7 +83,7 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
let(:file_type) { :code_coverage }
context 'when pipeline artifact has a coverage report' do
let!(:pipeline_artifact) { create(:ci_pipeline_artifact) }
let!(:pipeline_artifact) { create(:ci_pipeline_artifact, :with_coverage_report) }
it 'returns true' do
expect(pipeline_artifact).to be_truthy
@ -101,7 +101,7 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
let(:file_type) { :code_quality }
context 'when pipeline artifact has a quality report' do
let!(:pipeline_artifact) { create(:ci_pipeline_artifact, :codequality_report) }
let!(:pipeline_artifact) { create(:ci_pipeline_artifact, :with_codequality_report) }
it 'returns true' do
expect(pipeline_artifact).to be_truthy
@ -131,7 +131,7 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
let(:file_type) { :code_coverage }
context 'when pipeline artifact has a coverage report' do
let!(:coverage_report) { create(:ci_pipeline_artifact) }
let!(:coverage_report) { create(:ci_pipeline_artifact, :with_coverage_report) }
it 'returns a pipeline artifact with a coverage report' do
expect(pipeline_artifact.file_type).to eq('code_coverage')
@ -149,7 +149,7 @@ RSpec.describe Ci::PipelineArtifact, type: :model do
let(:file_type) { :code_quality }
context 'when pipeline artifact has a quality report' do
let!(:coverage_report) { create(:ci_pipeline_artifact, :codequality_report) }
let!(:coverage_report) { create(:ci_pipeline_artifact, :with_codequality_report) }
it 'returns a pipeline artifact with a quality report' do
expect(pipeline_artifact.file_type).to eq('code_quality')

View File

@ -3388,7 +3388,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#batch_lookup_report_artifact_for_file_type' do
context 'with code quality report artifact' do
let(:pipeline) { create(:ci_pipeline, :with_codequality_report, project: project) }
let(:pipeline) { create(:ci_pipeline, :with_codequality_reports, project: project) }
it "returns the code quality artifact" do
expect(pipeline.batch_lookup_report_artifact_for_file_type(:codequality)).to eq(pipeline.job_artifacts.sample)
@ -3514,7 +3514,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject { pipeline.has_codequality_reports? }
context 'when pipeline has a codequality artifact' do
let(:pipeline) { create(:ci_pipeline, :with_codequality_report_artifact, :running, project: project) }
let(:pipeline) { create(:ci_pipeline, :with_quality_report_artifact, :running, project: project) }
it { expect(subject).to be_truthy }
end

View File

@ -22,6 +22,7 @@ RSpec.describe Admin::UserEntity do
:username,
:last_activity_on,
:avatar_url,
:note,
:badges,
:projects_count,
:actions

View File

@ -17,6 +17,7 @@ RSpec.describe Admin::UserSerializer do
:username,
:last_activity_on,
:avatar_url,
:note,
:badges,
:projects_count,
:actions

View File

@ -77,7 +77,7 @@ RSpec.describe MergeRequestWidgetEntity do
end
describe 'codequality report artifacts', :request_store do
let(:merge_base_pipeline) { create(:ci_pipeline, :with_codequality_report, project: project) }
let(:merge_base_pipeline) { create(:ci_pipeline, :with_codequality_reports, project: project) }
before do
project.add_developer(user)
@ -90,7 +90,7 @@ RSpec.describe MergeRequestWidgetEntity do
end
context 'with report artifacts' do
let(:pipeline) { create(:ci_pipeline, :with_codequality_report, project: project) }
let(:pipeline) { create(:ci_pipeline, :with_codequality_reports, project: project) }
let(:generic_job_id) { pipeline.builds.first.id }
let(:merge_base_job_id) { merge_base_pipeline.builds.first.id }
@ -100,7 +100,7 @@ RSpec.describe MergeRequestWidgetEntity do
end
context 'on pipelines for merged results' do
let(:pipeline) { create(:ci_pipeline, :merged_result_pipeline, :with_codequality_report, project: project) }
let(:pipeline) { create(:ci_pipeline, :merged_result_pipeline, :with_codequality_reports, project: project) }
it 'returns URLs from the head_pipeline and merge_base_pipeline' do
expect(subject[:codeclimate][:head_path]).to include("/jobs/#{generic_job_id}/artifacts/download?file_type=codequality")

View File

@ -7,7 +7,7 @@ RSpec.describe Ci::PipelineArtifacts::ExpireArtifactsWorker do
describe '#perform' do
let_it_be(:pipeline_artifact) do
create(:ci_pipeline_artifact, expire_at: 1.week.ago)
create(:ci_pipeline_artifact, :with_coverage_report, expire_at: 1.week.ago)
end
it 'executes a service' do