Commit 074d013e authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖

Add latest changes from gitlab-org/[email protected]

parent 8f9beefa
Pipeline #128882297 passed with stages
in 67 minutes and 27 seconds
......@@ -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
......
......@@ -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:
......
<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)
......
# 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
......
# 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
# 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:
......
# 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)
......
---
title: Update More Pages button on Wiki Page
merge_request: 27499
author:
type: changed
---
title: Fix OpenAPI file detector
merge_request: 27321
author: Roger Meier
type: fixed
---
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
# 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
# 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 ""