Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8f9beefac3
commit
074d013e1e
|
@ -163,7 +163,7 @@ frontend-fixtures:
|
|||
frontend-fixtures-as-if-foss:
|
||||
extends:
|
||||
- .frontend-fixtures-base
|
||||
- .frontend:rules:default-frontend-jobs-as-if-foss
|
||||
- .frontend:rules:default-frontend-jobs-no-foss
|
||||
- .as-if-foss
|
||||
|
||||
.frontend-job-base:
|
||||
|
@ -206,7 +206,7 @@ karma:
|
|||
karma-as-if-foss:
|
||||
extends:
|
||||
- .karma-base
|
||||
- .frontend:rules:default-frontend-jobs-as-if-foss
|
||||
- .frontend:rules:default-frontend-jobs-no-foss
|
||||
- .as-if-foss
|
||||
needs: ["frontend-fixtures-as-if-foss"]
|
||||
|
||||
|
@ -241,7 +241,7 @@ jest:
|
|||
jest-as-if-foss:
|
||||
extends:
|
||||
- .jest-base
|
||||
- .frontend:rules:default-frontend-jobs-as-if-foss
|
||||
- .frontend:rules:default-frontend-jobs-no-foss
|
||||
- .as-if-foss
|
||||
needs: ["frontend-fixtures-as-if-foss"]
|
||||
cache:
|
||||
|
@ -250,7 +250,7 @@ jest-as-if-foss:
|
|||
coverage-frontend:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .frontend:rules:default-frontend-jobs
|
||||
- .frontend:rules:default-frontend-jobs-no-foss
|
||||
needs: ["jest"]
|
||||
stage: post-test
|
||||
before_script:
|
||||
|
|
|
@ -273,7 +273,7 @@
|
|||
changes: *code-backstage-patterns
|
||||
when: on_success
|
||||
|
||||
.frontend:rules:default-frontend-jobs-as-if-foss:
|
||||
.frontend:rules:default-frontend-jobs-no-foss:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
|
|
29
.rubocop.yml
29
.rubocop.yml
|
@ -200,6 +200,35 @@ GitlabSecurity/PublicSend:
|
|||
- 'ee/lib/**/*.rake'
|
||||
- 'ee/spec/**/*'
|
||||
|
||||
Gitlab/DuplicateSpecLocation:
|
||||
Exclude:
|
||||
- ee/spec/controllers/groups_controller_spec.rb
|
||||
- ee/spec/controllers/projects/jobs_controller_spec.rb
|
||||
- ee/spec/helpers/auth_helper_spec.rb
|
||||
- ee/spec/lib/gitlab/gl_repository_spec.rb
|
||||
- ee/spec/lib/gitlab/usage_data_spec.rb
|
||||
- ee/spec/models/namespace_spec.rb
|
||||
- ee/spec/models/note_spec.rb
|
||||
- ee/spec/serializers/environment_entity_spec.rb
|
||||
- ee/spec/services/issues/create_service_spec.rb
|
||||
- ee/spec/services/merge_requests/create_service_spec.rb
|
||||
- ee/spec/services/merge_requests/refresh_service_spec.rb
|
||||
- ee/spec/services/merge_requests/update_service_spec.rb
|
||||
- ee/spec/services/system_hooks_service_spec.rb
|
||||
- ee/spec/controllers/ee/groups_controller_spec.rb
|
||||
- ee/spec/controllers/ee/projects/jobs_controller_spec.rb
|
||||
- ee/spec/helpers/ee/auth_helper_spec.rb
|
||||
- ee/spec/lib/ee/gitlab/gl_repository_spec.rb
|
||||
- ee/spec/lib/ee/gitlab/usage_data_spec.rb
|
||||
- ee/spec/models/ee/namespace_spec.rb
|
||||
- ee/spec/models/ee/note_spec.rb
|
||||
- ee/spec/serializers/ee/environment_entity_spec.rb
|
||||
- ee/spec/services/ee/issues/create_service_spec.rb
|
||||
- ee/spec/services/ee/merge_requests/create_service_spec.rb
|
||||
- ee/spec/services/ee/merge_requests/refresh_service_spec.rb
|
||||
- ee/spec/services/ee/merge_requests/update_service_spec.rb
|
||||
- ee/spec/services/ee/system_hooks_service_spec.rb
|
||||
|
||||
Cop/InjectEnterpriseEditionModule:
|
||||
Enabled: true
|
||||
Exclude:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { escapeRegExp } from 'lodash';
|
||||
import { GlBadge, GlLink, GlSkeletonLoading, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { visitUrl, escapeFileUrl } from '~/lib/utils/url_utility';
|
||||
import { escapeFileUrl } from '~/lib/utils/url_utility';
|
||||
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
import { getIconName } from '../../utils/icon';
|
||||
|
@ -117,39 +117,37 @@ export default {
|
|||
return this.commit && this.commit.lockLabel;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openRow(e) {
|
||||
if (e.target.tagName === 'A') return;
|
||||
|
||||
if (this.isFolder && !e.metaKey) {
|
||||
this.$router.push(this.routerLinkTo);
|
||||
} else {
|
||||
visitUrl(this.url, e.metaKey);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr :class="`file_${id}`" class="tree-item" @click="openRow">
|
||||
<td class="tree-item-file-name">
|
||||
<tr class="tree-item">
|
||||
<td class="tree-item-file-name cursor-default position-relative">
|
||||
<gl-loading-icon
|
||||
v-if="path === loadingPath"
|
||||
size="sm"
|
||||
inline
|
||||
class="d-inline-block align-text-bottom fa-fw"
|
||||
/>
|
||||
<i v-else :aria-label="type" role="img" :class="iconName" class="fa fa-fw"></i>
|
||||
<component
|
||||
:is="linkComponent"
|
||||
ref="link"
|
||||
:to="routerLinkTo"
|
||||
:href="url"
|
||||
class="str-truncated"
|
||||
:class="{
|
||||
'is-submodule': isSubmodule,
|
||||
}"
|
||||
class="tree-item-link str-truncated"
|
||||
data-qa-selector="file_name_link"
|
||||
>
|
||||
{{ fullPath }}
|
||||
<i
|
||||
v-if="!loadingPath"
|
||||
:aria-label="type"
|
||||
role="img"
|
||||
:class="iconName"
|
||||
class="fa fa-fw mr-1"
|
||||
></i
|
||||
><span class="position-relative">{{ fullPath }}</span>
|
||||
</component>
|
||||
<!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
|
||||
<gl-badge v-if="lfsOid" variant="default" class="label-lfs ml-1">LFS</gl-badge>
|
||||
|
@ -165,7 +163,7 @@ export default {
|
|||
class="ml-2 vertical-align-middle"
|
||||
/>
|
||||
</td>
|
||||
<td class="d-none d-sm-table-cell tree-commit">
|
||||
<td class="d-none d-sm-table-cell tree-commit cursor-default">
|
||||
<gl-link
|
||||
v-if="commit"
|
||||
:href="commit.commitPath"
|
||||
|
@ -176,7 +174,7 @@ export default {
|
|||
</gl-link>
|
||||
<gl-skeleton-loading v-else :lines="1" class="h-auto" />
|
||||
</td>
|
||||
<td class="tree-time-ago text-right">
|
||||
<td class="tree-time-ago text-right cursor-default">
|
||||
<timeago-tooltip v-if="commit" :time="commit.committedDate" />
|
||||
<gl-skeleton-loading v-else :lines="1" class="ml-auto h-auto w-50" />
|
||||
</td>
|
||||
|
|
|
@ -511,3 +511,21 @@ span.idiff {
|
|||
.code-navigation-popover {
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.tree-item-link {
|
||||
&:not(.is-submodule) {
|
||||
span {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
|
|||
options = additional_attributes.merge(diff_view: diff_view)
|
||||
|
||||
if @merge_request.project.context_commits_enabled?
|
||||
options[:context_commits] = @merge_request.context_commits
|
||||
options[:context_commits] = @merge_request.recent_context_commits
|
||||
end
|
||||
|
||||
render json: DiffsSerializer.new(request).represent(diffs, options)
|
||||
|
|
|
@ -9,7 +9,7 @@ module Resolvers
|
|||
|
||||
def resolve(**args)
|
||||
current_user = context[:current_user]
|
||||
issue_id = GlobalID.parse(args[:id]).model_id
|
||||
issue_id = GlobalID.parse(args[:id])&.model_id
|
||||
|
||||
# Get data from Sentry
|
||||
response = ::ErrorTracking::IssueDetailsService.new(
|
||||
|
|
|
@ -8,7 +8,7 @@ module Resolvers
|
|||
description: 'ID of the Sentry issue'
|
||||
|
||||
def resolve(**args)
|
||||
issue_id = GlobalID.parse(args[:id]).model_id
|
||||
issue_id = GlobalID.parse(args[:id])&.model_id
|
||||
|
||||
# Get data from Sentry
|
||||
response = ::ErrorTracking::IssueLatestEventService.new(
|
||||
|
|
|
@ -410,8 +410,16 @@ class MergeRequest < ApplicationRecord
|
|||
"#{project.to_reference_base(from, full: full)}#{reference}"
|
||||
end
|
||||
|
||||
def context_commits
|
||||
@context_commits ||= merge_request_context_commits.map(&:to_commit)
|
||||
def context_commits(limit: nil)
|
||||
@context_commits ||= merge_request_context_commits.limit(limit).map(&:to_commit)
|
||||
end
|
||||
|
||||
def recent_context_commits
|
||||
context_commits(limit: MergeRequestDiff::COMMITS_SAFE_SIZE)
|
||||
end
|
||||
|
||||
def context_commits_count
|
||||
context_commits.count
|
||||
end
|
||||
|
||||
def commits(limit: nil)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ResourceMilestoneEvent < ResourceEvent
|
||||
include IgnorableColumns
|
||||
|
||||
belongs_to :issue
|
||||
belongs_to :merge_request
|
||||
belongs_to :milestone
|
||||
|
@ -18,6 +20,8 @@ class ResourceMilestoneEvent < ResourceEvent
|
|||
# state is used for issue and merge request states.
|
||||
enum state: Issue.available_states.merge(MergeRequest.available_states)
|
||||
|
||||
ignore_columns %i[reference reference_html cached_markdown_version], remove_with: '13.1', remove_after: '2020-06-22'
|
||||
|
||||
def self.issuable_attrs
|
||||
%i(issue merge_request).freeze
|
||||
end
|
||||
|
|
|
@ -1,49 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CommitEntity < API::Entities::Commit
|
||||
include MarkupHelper
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :author, using: UserEntity
|
||||
|
||||
expose :author_gravatar_url do |commit|
|
||||
GravatarService.new.execute(commit.author_email) # rubocop: disable CodeReuse/ServiceClass
|
||||
end
|
||||
|
||||
expose :commit_url do |commit, options|
|
||||
project_commit_url(request.project, commit, params: options.fetch(:commit_url_params, {}))
|
||||
end
|
||||
|
||||
expose :commit_path do |commit, options|
|
||||
project_commit_path(request.project, commit, params: options.fetch(:commit_url_params, {}))
|
||||
end
|
||||
|
||||
expose :description_html, if: { type: :full } do |commit|
|
||||
markdown_field(commit, :description)
|
||||
end
|
||||
|
||||
expose :title_html, if: { type: :full } do |commit|
|
||||
markdown_field(commit, :title)
|
||||
end
|
||||
|
||||
expose :signature_html, if: { type: :full } do |commit|
|
||||
render('projects/commit/_signature', signature: commit.signature) if commit.has_signature?
|
||||
end
|
||||
|
||||
expose :pipeline_status_path, if: { type: :full } do |commit, options|
|
||||
pipeline_ref = options[:pipeline_ref]
|
||||
pipeline_project = options[:pipeline_project] || commit.project
|
||||
next unless pipeline_ref && pipeline_project
|
||||
|
||||
pipeline = commit.latest_pipeline_for_project(pipeline_ref, pipeline_project)
|
||||
next unless pipeline&.status
|
||||
|
||||
pipelines_project_commit_path(pipeline_project, commit.id, ref: pipeline_ref)
|
||||
end
|
||||
|
||||
def render(*args)
|
||||
return unless request.respond_to?(:render) && request.render.respond_to?(:call)
|
||||
|
||||
request.render.call(*args)
|
||||
end
|
||||
class CommitEntity < API::Entities::CommitWithLink
|
||||
end
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UserEntity < API::Entities::UserBasic
|
||||
include RequestAwareEntity
|
||||
include UserStatusTooltip
|
||||
|
||||
expose :path do |user|
|
||||
user_path(user)
|
||||
end
|
||||
class UserEntity < API::Entities::UserPath
|
||||
end
|
||||
|
|
|
@ -74,7 +74,7 @@ module Issuable
|
|||
|
||||
if matching_destination_milestone.present?
|
||||
event.attributes
|
||||
.except('id', 'reference', 'reference_html')
|
||||
.except('id')
|
||||
.merge(entity_key => new_entity.id,
|
||||
'milestone_id' => matching_destination_milestone.id,
|
||||
'action' => ResourceMilestoneEvent.actions[event.action],
|
||||
|
|
|
@ -6,7 +6,7 @@ module Metrics
|
|||
module Dashboard
|
||||
class CloneDashboardService < ::BaseService
|
||||
ALLOWED_FILE_TYPE = '.yml'
|
||||
USER_DASHBOARDS_DIR = ::Metrics::Dashboard::ProjectDashboardService::DASHBOARD_ROOT
|
||||
USER_DASHBOARDS_DIR = ::Metrics::Dashboard::CustomDashboardService::DASHBOARD_ROOT
|
||||
|
||||
class << self
|
||||
def allowed_dashboard_templates
|
||||
|
@ -52,7 +52,7 @@ module Metrics
|
|||
def dashboard_details
|
||||
{
|
||||
path: new_dashboard_path,
|
||||
display_name: ::Metrics::Dashboard::ProjectDashboardService.name_for_path(new_dashboard_path),
|
||||
display_name: ::Metrics::Dashboard::CustomDashboardService.name_for_path(new_dashboard_path),
|
||||
default: false,
|
||||
system_dashboard: false
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards.
|
||||
module Metrics
|
||||
module Dashboard
|
||||
class ProjectDashboardService < ::Metrics::Dashboard::BaseService
|
||||
class CustomDashboardService < ::Metrics::Dashboard::BaseService
|
||||
DASHBOARD_ROOT = ".gitlab/dashboards"
|
||||
|
||||
class << self
|
|
@ -7,7 +7,7 @@ module Metrics
|
|||
include Stepable
|
||||
|
||||
ALLOWED_FILE_TYPE = '.yml'
|
||||
USER_DASHBOARDS_DIR = ::Metrics::Dashboard::ProjectDashboardService::DASHBOARD_ROOT
|
||||
USER_DASHBOARDS_DIR = ::Metrics::Dashboard::CustomDashboardService::DASHBOARD_ROOT
|
||||
|
||||
steps :check_push_authorized,
|
||||
:check_branch_name,
|
||||
|
@ -117,7 +117,7 @@ module Metrics
|
|||
def dashboard_details
|
||||
{
|
||||
path: update_dashboard_path,
|
||||
display_name: ::Metrics::Dashboard::ProjectDashboardService.name_for_path(update_dashboard_path),
|
||||
display_name: ::Metrics::Dashboard::CustomDashboardService.name_for_path(update_dashboard_path),
|
||||
default: false,
|
||||
system_dashboard: false
|
||||
}
|
||||
|
|
|
@ -17,5 +17,6 @@
|
|||
%ul.wiki-pages
|
||||
= render @sidebar_wiki_entries, context: 'sidebar'
|
||||
.block.w-100
|
||||
= link_to project_wikis_pages_path(@project), class: 'btn btn-block' do
|
||||
= s_("Wiki|More Pages")
|
||||
- if @sidebar_wiki_entries&.length.to_i >= 15
|
||||
= link_to project_wikis_pages_path(@project), class: 'btn btn-block' do
|
||||
= s_("Wiki|View All Pages")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
.card-header
|
||||
%h5
|
||||
= hook_class.underscore.humanize.titleize.pluralize
|
||||
(#{hooks.count})
|
||||
(#{hooks.load.size})
|
||||
|
||||
- if hooks.any?
|
||||
%ul.content-list
|
||||
|
|
|
@ -891,7 +891,7 @@
|
|||
:urgency: :low
|
||||
:resource_boundary: :unknown
|
||||
:weight: 1
|
||||
:idempotent:
|
||||
:idempotent: true
|
||||
- :name: update_namespace_statistics:namespaces_schedule_aggregation
|
||||
:feature_category: :source_code_management
|
||||
:has_external_dependencies:
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Namespaces
|
||||
class RootStatisticsWorker # rubocop:disable Scalability/IdempotentWorker
|
||||
class RootStatisticsWorker
|
||||
include ApplicationWorker
|
||||
|
||||
queue_namespace :update_namespace_statistics
|
||||
feature_category :source_code_management
|
||||
idempotent!
|
||||
|
||||
def perform(namespace_id)
|
||||
namespace = Namespace.find(namespace_id)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update More Pages button on Wiki Page
|
||||
merge_request: 27499
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix OpenAPI file detector
|
||||
merge_request: 27321
|
||||
author: Roger Meier
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Reduce SQL queries when rendering webhook settings
|
||||
merge_request: 27359
|
||||
author:
|
||||
type: performance
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
require 'yaml'
|
||||
|
||||
SEE_DOC = "See [the documentation](https://docs.gitlab.com/ce/development/changelog.html)."
|
||||
SEE_DOC = "See [the documentation](https://docs.gitlab.com/ee/development/changelog.html)."
|
||||
CREATE_CHANGELOG_MESSAGE = <<~MSG
|
||||
You can create one with:
|
||||
If you want to create a changelog entry for GitLab FOSS, run the following:
|
||||
|
||||
```
|
||||
bin/changelog -m %<mr_iid>s "%<mr_title>s"
|
||||
|
@ -20,7 +20,7 @@ bin/changelog --ee -m %<mr_iid>s "%<mr_title>s"
|
|||
Note: Merge requests with %<labels>s do not trigger this check.
|
||||
MSG
|
||||
|
||||
def check_changelog(path)
|
||||
def check_changelog_yaml(path)
|
||||
yaml = YAML.safe_load(File.read(path))
|
||||
|
||||
fail "`title` should be set, in #{gitlab.html_link(path)}! #{SEE_DOC}" if yaml["title"].nil?
|
||||
|
@ -28,8 +28,6 @@ def check_changelog(path)
|
|||
|
||||
if yaml["merge_request"].nil? && !helper.security_mr?
|
||||
message "Consider setting `merge_request` to #{gitlab.mr_json["iid"]} in #{gitlab.html_link(path)}. #{SEE_DOC}"
|
||||
elsif yaml["merge_request"] != gitlab.mr_json["iid"] && !changelog.ce_port_changelog?(path)
|
||||
fail "Merge request ID was not set to #{gitlab.mr_json["iid"]}! #{SEE_DOC}"
|
||||
end
|
||||
rescue Psych::SyntaxError, Psych::DisallowedClass, Psych::BadAlias
|
||||
# YAML could not be parsed, fail the build.
|
||||
|
@ -38,6 +36,19 @@ rescue StandardError => e
|
|||
warn "There was a problem trying to check the Changelog. Exception: #{e.name} - #{e.message}"
|
||||
end
|
||||
|
||||
def check_changelog_path(path)
|
||||
ee_changes = helper.all_ee_changes.dup
|
||||
ee_changes.delete(path)
|
||||
|
||||
if ee_changes.any? && !changelog.ee_changelog?
|
||||
warn "This MR has a Changelog file outside `ee/`, but code changes in `ee/`. Consider moving the Changelog file into `ee/`."
|
||||
end
|
||||
|
||||
if ee_changes.empty? && changelog.ee_changelog?
|
||||
warn "This MR has a Changelog file in `ee/`, but no code changes in `ee/`. Consider moving the Changelog file outside `ee/`."
|
||||
end
|
||||
end
|
||||
|
||||
def sanitized_mr_title
|
||||
helper.sanitize_mr_title(gitlab.mr_json["title"])
|
||||
end
|
||||
|
@ -49,11 +60,10 @@ end
|
|||
|
||||
changelog_found = changelog.found
|
||||
|
||||
if changelog.needed?
|
||||
if changelog_found
|
||||
check_changelog(changelog_found)
|
||||
else
|
||||
message "**[CHANGELOG missing](https://docs.gitlab.com/ce/development/changelog.html)**: If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry), feel free to ignore this message.\n\n" +
|
||||
format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: sanitized_mr_title, labels: changelog.presented_no_changelog_labels)
|
||||
end
|
||||
if changelog_found
|
||||
check_changelog_yaml(changelog_found)
|
||||
check_changelog_path(changelog_found)
|
||||
elsif changelog.needed?
|
||||
message "**[CHANGELOG missing](https://docs.gitlab.com/ee/development/changelog.html)**: If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry), feel free to ignore this message.\n\n" +
|
||||
format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: sanitized_mr_title, labels: changelog.presented_no_changelog_labels)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Entities
|
||||
class CommitWithLink < Commit
|
||||
include MarkupHelper
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :author, using: Entities::UserPath
|
||||
|
||||
expose :author_gravatar_url do |commit|
|
||||
GravatarService.new.execute(commit.author_email)
|
||||
end
|
||||
|
||||
expose :commit_url do |commit, options|
|
||||
project_commit_url(request.project, commit, params: options.fetch(:commit_url_params, {}))
|
||||
end
|
||||
|
||||
expose :commit_path do |commit, options|
|
||||
project_commit_path(request.project, commit, params: options.fetch(:commit_url_params, {}))
|
||||
end
|
||||
|
||||
expose :description_html, if: { type: :full } do |commit|
|
||||
markdown_field(commit, :description)
|
||||
end
|
||||
|
||||
expose :title_html, if: { type: :full } do |commit|
|
||||
markdown_field(commit, :title)
|
||||
end
|
||||
|
||||
expose :signature_html, if: { type: :full } do |commit|
|
||||
render('projects/commit/_signature', signature: commit.signature) if commit.has_signature?
|
||||
end
|
||||
|
||||
expose :pipeline_status_path, if: { type: :full } do |commit, options|
|
||||
pipeline_ref = options[:pipeline_ref]
|
||||
pipeline_project = options[:pipeline_project] || commit.project
|
||||
next unless pipeline_ref && pipeline_project
|
||||
|
||||
pipeline = commit.latest_pipeline_for_project(pipeline_ref, pipeline_project)
|
||||
next unless pipeline&.status
|
||||
|
||||
pipelines_project_commit_path(pipeline_project, commit.id, ref: pipeline_ref)
|
||||
end
|
||||
|
||||
def render(*args)
|
||||
return unless request.respond_to?(:render) && request.render.respond_to?(:call)
|
||||
|
||||
request.render.call(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Entities
|
||||
class UserPath < UserBasic
|
||||
include RequestAwareEntity
|
||||
include UserStatusTooltip
|
||||
|
||||
expose :path do |user|
|
||||
user_path(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -306,7 +306,7 @@ module API
|
|||
context_commits =
|
||||
paginate(merge_request.merge_request_context_commits).map(&:to_commit)
|
||||
|
||||
present context_commits, with: Entities::Commit
|
||||
present context_commits, with: Entities::CommitWithLink, type: :full, request: merge_request
|
||||
end
|
||||
|
||||
params do
|
||||
|
|
|
@ -11,7 +11,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def found
|
||||
git.added_files.find { |path| path =~ %r{\A(ee/)?(changelogs/unreleased)(-ee)?/} }
|
||||
@found ||= git.added_files.find { |path| path =~ %r{\A(ee/)?(changelogs/unreleased)(-ee)?/} }
|
||||
end
|
||||
|
||||
def presented_no_changelog_labels
|
||||
|
@ -22,12 +22,8 @@ module Gitlab
|
|||
gitlab.mr_json["title"].gsub(/^WIP: */, '').gsub(/`/, '\\\`')
|
||||
end
|
||||
|
||||
def ee_changelog?(changelog_path)
|
||||
changelog_path =~ /unreleased-ee/
|
||||
end
|
||||
|
||||
def ce_port_changelog?(changelog_path)
|
||||
helper.ee? && !ee_changelog?(changelog_path)
|
||||
def ee_changelog?
|
||||
found.start_with?('ee/')
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -34,6 +34,10 @@ module Gitlab
|
|||
.sort
|
||||
end
|
||||
|
||||
def all_ee_changes
|
||||
all_changed_files.grep(%r{\Aee/})
|
||||
end
|
||||
|
||||
def ee?
|
||||
# Support former project name for `dev` and support local Danger run
|
||||
%w[gitlab gitlab-ee].include?(ENV['CI_PROJECT_NAME']) || Dir.exist?('../../ee')
|
||||
|
|
|
@ -40,7 +40,7 @@ module Gitlab
|
|||
yarn_lock: 'yarn.lock',
|
||||
|
||||
# OpenAPI Specification files
|
||||
openapi: %r{.*(openapi|swagger).*\.(yaml|yml|json)\z}i
|
||||
openapi: %r{[^/]*(openapi|swagger)[^/]*\.(yaml|yml|json)\z}i
|
||||
}.freeze
|
||||
|
||||
# Returns an Array of file types based on the given paths.
|
||||
|
|
|
@ -78,7 +78,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def project_service
|
||||
::Metrics::Dashboard::ProjectDashboardService
|
||||
::Metrics::Dashboard::CustomDashboardService
|
||||
end
|
||||
|
||||
def self_monitoring_service
|
||||
|
|
|
@ -20,7 +20,7 @@ module Gitlab
|
|||
::Metrics::Dashboard::SystemDashboardService,
|
||||
::Metrics::Dashboard::PodDashboardService,
|
||||
::Metrics::Dashboard::SelfMonitoringDashboardService,
|
||||
::Metrics::Dashboard::ProjectDashboardService
|
||||
::Metrics::Dashboard::CustomDashboardService
|
||||
].freeze
|
||||
|
||||
# Returns a class which inherits from the BaseService
|
||||
|
|
|
@ -5,8 +5,18 @@ require 'digest'
|
|||
module Gitlab
|
||||
module SidekiqMiddleware
|
||||
module DuplicateJobs
|
||||
def self.drop_duplicates?
|
||||
Feature.enabled?(:drop_duplicate_sidekiq_jobs)
|
||||
DROPPABLE_QUEUES = Set.new([
|
||||
Namespaces::RootStatisticsWorker.queue
|
||||
]).freeze
|
||||
|
||||
def self.drop_duplicates?(queue_name)
|
||||
Feature.enabled?(:drop_duplicate_sidekiq_jobs) ||
|
||||
drop_duplicates_for_queue?(queue_name)
|
||||
end
|
||||
|
||||
private_class_method def self.drop_duplicates_for_queue?(queue_name)
|
||||
DROPPABLE_QUEUES.include?(queue_name) &&
|
||||
Feature.enabled?(:drop_duplicate_sidekiq_jobs_for_queue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -67,7 +67,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def droppable?
|
||||
idempotent? && duplicate? && DuplicateJobs.drop_duplicates?
|
||||
idempotent? && duplicate? && DuplicateJobs.drop_duplicates?(queue_name)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -9166,18 +9166,6 @@ msgstr ""
|
|||
msgid "GeoNodes|Last event ID seen from primary"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Learn more about Repository checksum progress"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Learn more about Repository verification"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Learn more about Wiki checksum progress"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Learn more about Wiki verification"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Loading nodes"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9208,6 +9196,9 @@ msgstr ""
|
|||
msgid "GeoNodes|Removing a Geo secondary node stops the synchronization to that node. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Replicated data is verified with the %{nodeText} using checksums"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Replication slot WAL"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9217,12 +9208,6 @@ msgstr ""
|
|||
msgid "GeoNodes|Repositories"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Repositories checksummed for verification with their counterparts on Secondary nodes"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Repositories verified with their counterparts on the Primary node"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Repository checksum progress"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9274,18 +9259,18 @@ msgstr ""
|
|||
msgid "GeoNodes|Wikis"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Wikis checksummed for verification with their counterparts on Secondary nodes"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|Wikis verified with their counterparts on the Primary node"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|With %{geo} you can install a special read-only and replicated instance anywhere. Before you add nodes, follow the %{instructions} in the exact order they appear."
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS."
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|primary node"
|
||||
msgstr ""
|
||||
|
||||
msgid "GeoNodes|secondary nodes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|%{name} is scheduled for forced re-download"
|
||||
msgstr ""
|
||||
|
||||
|
@ -22762,9 +22747,6 @@ msgstr ""
|
|||
msgid "Wiki|Edit Page"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wiki|More Pages"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wiki|New page"
|
||||
msgstr ""
|
||||
|
||||
|
@ -22783,6 +22765,9 @@ msgstr ""
|
|||
msgid "Wiki|Title"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wiki|View All Pages"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wiki|Wiki Pages"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@ module QA
|
|||
create_many_branches
|
||||
create_many_new_files
|
||||
create_mr_with_many_commits
|
||||
create_many_issues
|
||||
|
||||
methods_arr = [
|
||||
method(:create_many_issues),
|
||||
method(:create_many_labels),
|
||||
method(:create_many_todos),
|
||||
method(:create_many_merge_requests),
|
||||
|
@ -104,6 +104,7 @@ module QA
|
|||
def create_many_new_files
|
||||
create_a_new_file_api_req("hello.txt", "master", "#{@group_name}%2F#{@project_name}", "hello", "my new content")
|
||||
30.times do |i|
|
||||
create_a_new_file_api_req("hello#{i}.txt", "master", "#{@group_name}%2F#{@project_name}", "hello", "my new content")
|
||||
create_a_new_file_api_req("hello#{i}.txt", "branch#{i}", "#{@group_name}%2F#{@project_name}", "hello", "my new content")
|
||||
end
|
||||
|
||||
|
@ -137,7 +138,7 @@ module QA
|
|||
16.times do |i|
|
||||
faker_line_arr = Faker::Lorem.sentences(1500)
|
||||
content = faker_line_arr.join("\n\r")
|
||||
create_a_new_file_api_req("hello#{i}.txt", "master", "#{@group_name}%2F#{@project_name}", "Add hello#{i}.txt", content)
|
||||
create_a_new_file_api_req("hello#{i + 100}.txt", "master", "#{@group_name}%2F#{@project_name}", "Add hello#{i + 100}.txt", content)
|
||||
content_arr[i] = faker_line_arr
|
||||
end
|
||||
|
||||
|
@ -147,7 +148,7 @@ module QA
|
|||
missed_line_array = content_arr[i].each_slice(2).map(&:first)
|
||||
content = missed_line_array.join("\n\rIm new!:D \n\r ")
|
||||
|
||||
update_file_api_req("hello#{i}.txt", "performance", "#{@group_name}%2F#{@project_name}", "Update hello#{i}.txt", content)
|
||||
update_file_api_req("hello#{i + 100}.txt", "performance", "#{@group_name}%2F#{@project_name}", "Update hello#{i + 100}.txt", content)
|
||||
end
|
||||
|
||||
create_mr_response = create_a_merge_request_api_req("#{@group_name}%2F#{@project_name}", "performance", "master", "Large_MR")
|
||||
|
@ -182,7 +183,7 @@ module QA
|
|||
|
||||
def create_diff_note(iid, file_count, line_count, head_sha, start_sha, base_sha, line_type)
|
||||
post Runtime::API::Request.new(@api_client, "/projects/#{@group_name}%2F#{@project_name}/merge_requests/#{iid}/discussions").url,
|
||||
"" "body=\"Let us discuss\"&
|
||||
"" "body=\"Let us discuss\"&
|
||||
position[position_type]=text&
|
||||
position[new_path]=hello#{file_count}.txt&
|
||||
position[old_path]=hello#{file_count}.txt&
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rubocop/rspec/top_level_describe'
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Gitlab
|
||||
# Cop that detects duplicate EE spec files
|
||||
#
|
||||
# There should not be files in both ee/spec/*/ee/my_spec.rb and ee/spec/*/my_spec.rb
|
||||
#
|
||||
# # bad
|
||||
# ee/spec/controllers/my_spec.rb # describe MyClass
|
||||
# ee/spec/controllers/ee/my_spec.rb # describe MyClass
|
||||
#
|
||||
# # good, spec for EE extension code
|
||||
# ee/spec/controllers/ee/my_spec.rb # describe MyClass
|
||||
#
|
||||
# # good, spec for EE only code
|
||||
# ee/spec/controllers/my_spec.rb # describe MyClass
|
||||
#
|
||||
class DuplicateSpecLocation < RuboCop::Cop::Cop
|
||||
include RuboCop::RSpec::TopLevelDescribe
|
||||
|
||||
MSG = 'Duplicate spec location in `%<path>s`.'
|
||||
|
||||
def on_top_level_describe(node, _args)
|
||||
path = file_path_for_node(node).sub(/\A#{rails_root}\//, '')
|
||||
duplicate_path = find_duplicate_path(path)
|
||||
|
||||
if duplicate_path && File.exist?(File.join(rails_root, duplicate_path))
|
||||
add_offense(node, message: format(MSG, path: duplicate_path))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ee_spec?(path)
|
||||
File.fnmatch?('ee/spec/**/*.rb', path, File::FNM_PATHNAME)
|
||||
end
|
||||
|
||||
def find_duplicate_path(path)
|
||||
return unless ee_spec?(path)
|
||||
|
||||
if File.fnmatch?('ee/spec/**/ee/**', path)
|
||||
path.match('\A(ee/spec/[^/]+)/ee/(.+)') do |match|
|
||||
File.join(match[1], match[2])
|
||||
end
|
||||
else
|
||||
path.match('\A(ee/spec/[^/]+)/(.+)') do |match|
|
||||
File.join(match[1], 'ee', match[2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def file_path_for_node(node)
|
||||
node.location.expression.source_buffer.name
|
||||
end
|
||||
|
||||
def rails_root
|
||||
File.expand_path('../../..', __dir__)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,7 +21,13 @@ GITLAB_DOCS_REPO = 'gitlab-org/gitlab-docs'.freeze
|
|||
# kicked the review app.
|
||||
#
|
||||
def docs_branch
|
||||
"docs-preview-#{slug}-#{ENV["CI_MERGE_REQUEST_IID"]}"
|
||||
# Check if CI_MERGE_REQUEST_IID is present. This requires pipelines
|
||||
# for merge requests to be enabled.
|
||||
if ENV["CI_MERGE_REQUEST_IID"].nil?
|
||||
"docs-preview-#{slug}-#{ENV["CI_COMMIT_REF_SLUG"]}"
|
||||
else
|
||||
"docs-preview-#{slug}-#{ENV["CI_MERGE_REQUEST_IID"]}"
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -312,7 +312,6 @@ describe "User creates wiki page" do
|
|||
visit(project_wikis_path(project))
|
||||
|
||||
expect(page).to have_content('another')
|
||||
expect(page).to have_content('More Pages')
|
||||
end
|
||||
|
||||
context 'when there is a customized sidebar' do
|
||||
|
@ -324,10 +323,23 @@ describe "User creates wiki page" do
|
|||
visit(project_wikis_path(project))
|
||||
|
||||
expect(page).to have_content('My customized sidebar')
|
||||
expect(page).to have_content('More Pages')
|
||||
expect(page).not_to have_content('Another')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are more than 15 existing pages' do
|
||||
before do
|
||||
create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'home' })
|
||||
(1..14).each { |i| create(:wiki_page, wiki: wiki, attrs: { title: "page-#{i}", content: "page #{i}" }) }
|
||||
end
|
||||
|
||||
it 'renders a default sidebar when there is no customized sidebar' do
|
||||
visit(project_wikis_path(project))
|
||||
|
||||
expect(page).to have_content('View All Pages')
|
||||
expect(page).to have_content('page 1')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Element.prototype.scrollBy = jest.fn();
|
|
@ -1,4 +1,5 @@
|
|||
import './element_scroll_into_view';
|
||||
import './element_scroll_by';
|
||||
import './form_element';
|
||||
import './get_client_rects';
|
||||
import './inner_text';
|
||||
|
|
|
@ -2,25 +2,28 @@
|
|||
|
||||
exports[`Repository table row component renders table row 1`] = `
|
||||
<tr
|
||||
class="tree-item file_1"
|
||||
class="tree-item"
|
||||
>
|
||||
<td
|
||||
class="tree-item-file-name"
|
||||
class="tree-item-file-name cursor-default position-relative"
|
||||
>
|
||||
<i
|
||||
aria-label="file"
|
||||
class="fa fa-fw fa-file-text-o"
|
||||
role="img"
|
||||
/>
|
||||
<!---->
|
||||
|
||||
<a
|
||||
class="str-truncated"
|
||||
class="tree-item-link str-truncated"
|
||||
data-qa-selector="file_name_link"
|
||||
href="https://test.com"
|
||||
>
|
||||
|
||||
test
|
||||
|
||||
<i
|
||||
aria-label="file"
|
||||
class="fa fa-fw mr-1 fa-file-text-o"
|
||||
role="img"
|
||||
/>
|
||||
<span
|
||||
class="position-relative"
|
||||
>
|
||||
test
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!---->
|
||||
|
@ -31,7 +34,7 @@ exports[`Repository table row component renders table row 1`] = `
|
|||
</td>
|
||||
|
||||
<td
|
||||
class="d-none d-sm-table-cell tree-commit"
|
||||
class="d-none d-sm-table-cell tree-commit cursor-default"
|
||||
>
|
||||
<gl-skeleton-loading-stub
|
||||
class="h-auto"
|
||||
|
@ -40,7 +43,7 @@ exports[`Repository table row component renders table row 1`] = `
|
|||
</td>
|
||||
|
||||
<td
|
||||
class="tree-time-ago text-right"
|
||||
class="tree-time-ago text-right cursor-default"
|
||||
>
|
||||
<gl-skeleton-loading-stub
|
||||
class="ml-auto h-auto w-50"
|
||||
|
@ -52,25 +55,28 @@ exports[`Repository table row component renders table row 1`] = `
|
|||
|
||||
exports[`Repository table row component renders table row for path with special character 1`] = `
|
||||
<tr
|
||||
class="tree-item file_1"
|
||||
class="tree-item"
|
||||
>
|
||||
<td
|
||||
class="tree-item-file-name"
|
||||
class="tree-item-file-name cursor-default position-relative"
|
||||
>
|
||||
<i
|
||||
aria-label="file"
|
||||
class="fa fa-fw fa-file-text-o"
|
||||
role="img"
|
||||
/>
|
||||
<!---->
|
||||
|
||||
<a
|
||||
class="str-truncated"
|
||||
class="tree-item-link str-truncated"
|
||||
data-qa-selector="file_name_link"
|
||||
href="https://test.com"
|
||||
>
|
||||
|
||||
test
|
||||
|
||||
<i
|
||||
aria-label="file"
|
||||
class="fa fa-fw mr-1 fa-file-text-o"
|
||||
role="img"
|
||||
/>
|
||||
<span
|
||||
class="position-relative"
|
||||
>
|
||||
test
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!---->
|
||||
|
@ -81,7 +87,7 @@ exports[`Repository table row component renders table row for path with special
|
|||
</td>
|
||||
|
||||
<td
|
||||
class="d-none d-sm-table-cell tree-commit"
|
||||
class="d-none d-sm-table-cell tree-commit cursor-default"
|
||||
>
|
||||
<gl-skeleton-loading-stub
|
||||
class="h-auto"
|
||||
|
@ -90,7 +96,7 @@ exports[`Repository table row component renders table row for path with special
|
|||
</td>
|
||||
|
||||
<td
|
||||
class="tree-time-ago text-right"
|
||||
class="tree-time-ago text-right cursor-default"
|
||||
>
|
||||
<gl-skeleton-loading-stub
|
||||
class="ml-auto h-auto w-50"
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
import { shallowMount, RouterLinkStub } from '@vue/test-utils';
|
||||
import { GlBadge, GlLink, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import TableRow from '~/repository/components/table/row.vue';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility', () => ({
|
||||
...jest.requireActual('~/lib/utils/url_utility'),
|
||||
visitUrl: jest.fn(),
|
||||
}));
|
||||
|
||||
let vm;
|
||||
let $router;
|
||||
|
||||
|
@ -87,31 +81,6 @@ describe('Repository table row component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it.each`
|
||||
type | pushes
|
||||
${'tree'} | ${true}
|
||||
${'file'} | ${false}
|
||||
${'commit'} | ${false}
|
||||
`('pushes new router if type $type is tree', ({ type, pushes }) => {
|
||||
factory({
|
||||
id: '1',
|
||||
sha: '123',
|
||||
path: 'test',
|
||||
type,
|
||||
currentPath: '/',
|
||||
});
|
||||
|
||||
return vm.vm.$nextTick().then(() => {
|
||||
vm.trigger('click');
|
||||
|
||||
if (pushes) {
|
||||
expect($router.push).toHaveBeenCalledWith({ path: '/-/tree/master/test' });
|
||||
} else {
|
||||
expect($router.push).not.toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it.each`
|
||||
path
|
||||
${'test#'}
|
||||
|
@ -132,7 +101,7 @@ describe('Repository table row component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('pushes new route for directory with hash', () => {
|
||||
it('renders link for directory with hash', () => {
|
||||
factory({
|
||||
id: '1',
|
||||
sha: '123',
|
||||
|
@ -142,36 +111,7 @@ describe('Repository table row component', () => {
|
|||
});
|
||||
|
||||
return vm.vm.$nextTick().then(() => {
|
||||
vm.trigger('click');
|
||||
|
||||
expect($router.push).toHaveBeenCalledWith({ path: '/-/tree/master/test%23' });
|
||||
});
|
||||
});
|
||||
|
||||
it.each`
|
||||
type | pushes
|
||||
${'tree'} | ${true}
|
||||
${'file'} | ${false}
|
||||
${'commit'} | ${false}
|
||||
`('calls visitUrl if $type is not tree', ({ type, pushes }) => {
|
||||
factory({
|
||||
id: '1',
|
||||
sha: '123',
|
||||
path: 'test',
|
||||
type,
|
||||
currentPath: '/',
|
||||
});
|
||||
|
||||
return vm.vm.$nextTick().then(() => {
|
||||
vm.trigger('click');
|
||||
|
||||
if (pushes) {
|
||||
expect(visitUrl).not.toHaveBeenCalled();
|
||||
} else {
|
||||
const [url, external] = visitUrl.mock.calls[0];
|
||||
expect(url).toBe('https://test.com');
|
||||
expect(external).toBeFalsy();
|
||||
}
|
||||
expect(vm.find('.tree-item-link').props('to')).toEqual({ path: '/-/tree/master/test%23' });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -18,6 +18,16 @@ describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
|
|||
.and_return issue_details_service
|
||||
end
|
||||
|
||||
shared_examples 'it resolves to nil' do
|
||||
it 'resolves to nil' do
|
||||
allow(issue_details_service).to receive(:execute)
|
||||
.and_return(issue: nil)
|
||||
|
||||
result = resolve_error(args)
|
||||
expect(result).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#resolve' do
|
||||
let(:args) { { id: issue_global_id(1234) } }
|
||||
|
||||
|
@ -32,7 +42,7 @@ describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
|
|||
|
||||
before do
|
||||
allow(issue_details_service).to receive(:execute)
|
||||
.and_return({ issue: detailed_error })
|
||||
.and_return(issue: detailed_error)
|
||||
end
|
||||
|
||||
it 'resolves to a detailed error' do
|
||||
|
@ -44,12 +54,14 @@ describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do
|
|||
end
|
||||
end
|
||||
|
||||
it 'resolves to nil if no match' do
|
||||
allow(issue_details_service).to receive(:execute)
|
||||
.and_return({ issue: nil })
|
||||
context 'if id does not match issue' do
|
||||
it_behaves_like 'it resolves to nil'
|
||||
end
|
||||
|
||||
result = resolve_error(args)
|
||||
expect(result).to eq nil
|
||||
context 'blank id' do
|
||||
let(:args) { { id: '' } }
|
||||
|
||||
it_behaves_like 'it resolves to nil'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -76,10 +76,10 @@ describe Gitlab::Danger::Changelog do
|
|||
|
||||
context 'added files contain a changelog' do
|
||||
[
|
||||
'changelogs/unreleased/entry.md',
|
||||
'ee/changelogs/unreleased/entry.md',
|
||||
'changelogs/unreleased-ee/entry.md',
|
||||
'ee/changelogs/unreleased-ee/entry.md'
|
||||
'changelogs/unreleased/entry.yml',
|
||||
'ee/changelogs/unreleased/entry.yml',
|
||||
'changelogs/unreleased-ee/entry.yml',
|
||||
'ee/changelogs/unreleased-ee/entry.yml'
|
||||
].each do |file_path|
|
||||
let(:added_files) { [file_path] }
|
||||
|
||||
|
@ -107,46 +107,22 @@ describe Gitlab::Danger::Changelog do
|
|||
end
|
||||
|
||||
describe '#ee_changelog?' do
|
||||
context 'is ee changelog' do
|
||||
[
|
||||
'changelogs/unreleased-ee/entry.md',
|
||||
'ee/changelogs/unreleased-ee/entry.md'
|
||||
].each do |file_path|
|
||||
subject { changelog.ee_changelog?(file_path) }
|
||||
subject { changelog.ee_changelog? }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
before do
|
||||
allow(changelog).to receive(:found).and_return(file_path)
|
||||
end
|
||||
|
||||
context 'is ee changelog' do
|
||||
let(:file_path) { 'ee/changelogs/unreleased/entry.yml' }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
|
||||
context 'is not ee changelog' do
|
||||
[
|
||||
'changelogs/unreleased/entry.md',
|
||||
'ee/changelogs/unreleased/entry.md'
|
||||
].each do |file_path|
|
||||
subject { changelog.ee_changelog?(file_path) }
|
||||
let(:file_path) { 'changelogs/unreleased/entry.yml' }
|
||||
|
||||
it { is_expected.to be_falsy }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ce_port_changelog?' do
|
||||
where(:helper_ee?, :file_path, :expected) do
|
||||
true | 'changelogs/unreleased-ee/entry.md' | false
|
||||
true | 'ee/changelogs/unreleased-ee/entry.md' | false
|
||||
false | 'changelogs/unreleased-ee/entry.md' | false
|
||||
false | 'ee/changelogs/unreleased-ee/entry.md' | false
|
||||
true | 'changelogs/unreleased/entry.md' | true
|
||||
true | 'ee/changelogs/unreleased/entry.md' | true
|
||||
false | 'changelogs/unreleased/entry.md' | false
|
||||
false | 'ee/changelogs/unreleased/entry.md' | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:ee?) { helper_ee? }
|
||||
subject { changelog.ce_port_changelog?(file_path) }
|
||||
|
||||
it { is_expected.to eq(expected) }
|
||||
it { is_expected.to be_falsy }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -76,6 +76,16 @@ describe Gitlab::Danger::Helper do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#all_ee_changes' do
|
||||
subject { helper.all_ee_changes }
|
||||
|
||||
it 'returns all changed files starting with ee/' do
|
||||
expect(helper).to receive(:all_changed_files).and_return(%w[fr/ee/beer.rb ee/wine.rb ee/lib/ido.rb ee.k])
|
||||
|
||||
is_expected.to match_array(%w[ee/wine.rb ee/lib/ido.rb])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ee?' do
|
||||
subject { helper.ee? }
|
||||
|
||||
|
|
|
@ -96,14 +96,25 @@ describe Gitlab::FileDetector do
|
|||
'swagger.yml', 'swagger.yaml', 'swagger.json',
|
||||
'gitlab_swagger.yml', 'openapi_gitlab.yml',
|
||||
'OpenAPI.YML', 'openapi.Yaml', 'openapi.JSON',
|
||||
'openapi.gitlab.yml', 'gitlab.openapi.yml'
|
||||
'openapi.gitlab.yml', 'gitlab.openapi.yml',
|
||||
'attention/openapi.yml', 'attention/swagger.yml',
|
||||
'attention/gitlab_swagger.yml', 'attention/openapi_gitlab.yml',
|
||||
'openapi/openapi.yml', 'openapi/swagger.yml',
|
||||
'openapi/my_openapi.yml', 'openapi/swagger_one.yml'
|
||||
]
|
||||
|
||||
openapi_types.each do |type_name|
|
||||
expect(described_class.type_of(type_name)).to eq(:openapi)
|
||||
end
|
||||
|
||||
expect(described_class.type_of('openapiyml')).to be_nil
|
||||
openapi_bad_types = [
|
||||
'openapiyml',
|
||||
'openapi/attention.yaml', 'swagger/attention.yaml'
|
||||
]
|
||||
|
||||
openapi_bad_types.each do |type_name|
|
||||
expect(described_class.type_of(type_name)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ describe Gitlab::Metrics::Dashboard::ServiceSelector do
|
|||
context 'when just the dashboard path is provided' do
|
||||
let(:arguments) { { dashboard_path: '.gitlab/dashboards/test.yml' } }
|
||||
|
||||
it { is_expected.to be Metrics::Dashboard::ProjectDashboardService }
|
||||
it { is_expected.to be Metrics::Dashboard::CustomDashboardService }
|
||||
|
||||
context 'when the path is for the system dashboard' do
|
||||
let(:arguments) { { dashboard_path: system_dashboard_path } }
|
||||
|
|
|
@ -129,7 +129,8 @@ describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gitlab_r
|
|||
before do
|
||||
allow(AuthorizedProjectsWorker).to receive(:idempotent?).and_return(idempotent)
|
||||
allow(duplicate_job).to receive(:duplicate?).and_return(duplicate)
|
||||
stub_feature_flags(drop_duplicate_sidekiq_jobs: feature_enabled)
|
||||
allow(Gitlab::SidekiqMiddleware::DuplicateJobs)
|
||||
.to receive(:drop_duplicates?).with(queue).and_return(feature_enabled)
|
||||
end
|
||||
|
||||
it 'is droppable when all conditions are met' do
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::SidekiqMiddleware::DuplicateJobs do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
describe '.drop_duplicates?' do
|
||||
where(:global_feature_enabled, :selected_queue_enabled, :queue, :expected) do
|
||||
true | true | described_class::DROPPABLE_QUEUES.first | true
|
||||
true | true | "other_queue" | true
|
||||
true | false | described_class::DROPPABLE_QUEUES.first | true
|
||||
true | false | "other_queue" | true
|
||||
false | true | described_class::DROPPABLE_QUEUES.first | true
|
||||
false | true | "other_queue" | false
|
||||
false | false | described_class::DROPPABLE_QUEUES.first | false
|
||||
false | false | "other_queue" | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
stub_feature_flags(drop_duplicate_sidekiq_jobs: global_feature_enabled,
|
||||
drop_duplicate_sidekiq_jobs_for_queue: selected_queue_enabled)
|
||||
end
|
||||
|
||||
it "allows dropping jobs when expected" do
|
||||
expect(described_class.drop_duplicates?(queue)).to be(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,105 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'fast_spec_helper'
|
||||
require 'rubocop'
|
||||
require 'rubocop/rspec/support'
|
||||
|
||||
require_relative '../../../../rubocop/cop/gitlab/duplicate_spec_location'
|
||||
|
||||
describe RuboCop::Cop::Gitlab::DuplicateSpecLocation do
|
||||
include RuboCop::RSpec::ExpectOffense
|
||||
include CopHelper
|
||||
|
||||
subject(:cop) { described_class.new }
|
||||
|
||||
let(:rails_root) { '../../../../' }
|
||||
|
||||
def full_path(path)
|
||||
File.expand_path(File.join(rails_root, path), __dir__)
|
||||
end
|
||||
|
||||
context 'Non-EE spec file' do
|
||||
it 'registers no offenses' do
|
||||
expect_no_offenses(<<~SOURCE.strip_indent, full_path('spec/foo_spec.rb'))
|
||||
describe 'Foo' do
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
|
||||
context 'Non-EE application file' do
|
||||
it 'registers no offenses' do
|
||||
expect_no_offenses(<<~SOURCE.strip_indent, full_path('app/models/blog_post.rb'))
|
||||
class BlogPost
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
|
||||
context 'EE application file' do
|
||||
it 'registers no offenses' do
|
||||
expect_no_offenses(<<~SOURCE.strip_indent, full_path('ee/app/models/blog_post.rb'))
|
||||
class BlogPost
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
|
||||
context 'EE spec file for EE only code' do
|
||||
let(:spec_file_path) { full_path('ee/spec/controllers/foo_spec.rb') }
|
||||
|
||||
it 'registers no offenses' do
|
||||
expect_no_offenses(<<~SOURCE.strip_indent, spec_file_path)
|
||||
describe 'Foo' do
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
|
||||
context 'there is a duplicate file' do
|
||||
before do
|
||||
allow(File).to receive(:exist?).and_call_original
|
||||
|
||||
allow(File).to receive(:exist?)
|
||||
.with(full_path('ee/spec/controllers/ee/foo_spec.rb'))
|
||||
.and_return(true)
|
||||
end
|
||||
|
||||
it 'marks the describe as offending' do
|
||||
expect_offense(<<~SOURCE.strip_indent, spec_file_path)
|
||||
describe 'Foo' do
|
||||
^^^^^^^^^^^^^^ Duplicate spec location in `ee/spec/controllers/ee/foo_spec.rb`.
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'EE spec file for EE extension' do
|
||||
let(:spec_file_path) { full_path('ee/spec/controllers/ee/foo_spec.rb') }
|
||||
|
||||
it 'registers no offenses' do
|
||||
expect_no_offenses(<<~SOURCE.strip_indent, spec_file_path)
|
||||
describe 'Foo' do
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
|
||||
context 'there is a duplicate file' do
|
||||
before do
|
||||
allow(File).to receive(:exist?).and_call_original
|
||||
|
||||
allow(File).to receive(:exist?)
|
||||
.with(full_path('ee/spec/controllers/foo_spec.rb'))
|
||||
.and_return(true)
|
||||
end
|
||||
|
||||
it 'marks the describe as offending' do
|
||||
expect_offense(<<~SOURCE.strip_indent, spec_file_path)
|
||||
describe 'Foo' do
|
||||
^^^^^^^^^^^^^^ Duplicate spec location in `ee/spec/controllers/foo_spec.rb`.
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -112,9 +112,6 @@ describe Issuable::Clone::AttributesRewriter do
|
|||
expect(event.milestone_id).to eq(expected_attrs[:milestone].id)
|
||||
expect(event.action).to eq(expected_attrs[:action])
|
||||
expect(event.state).to eq(expected_attrs[:state])
|
||||
|
||||
expect(event.reference).to be_nil
|
||||
expect(event.reference_html).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Metrics::Dashboard::ProjectDashboardService, :use_clean_rails_memory_store_caching do
|
||||
describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memory_store_caching do
|
||||
include MetricsDashboardHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
|
@ -74,4 +74,19 @@ describe Namespaces::RootStatisticsWorker, '#perform' do
|
|||
worker.perform(group.id)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'an idempotent worker' do
|
||||
let(:job_args) { [group.id] }
|
||||
|
||||
it 'deletes one aggregation schedule' do
|
||||
# Make sure the group and it's aggregation schedule are created before
|
||||
# counting
|
||||
group
|
||||
|
||||
expect { worker.perform(*job_args) }
|
||||
.to change { Namespace::AggregationSchedule.count }.by(-1)
|
||||
expect { worker.perform(*job_args) }
|
||||
.not_to change { Namespace::AggregationSchedule.count }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue