Commit 8b1228b0 authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖

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

parent 96b0c124
......@@ -61,8 +61,10 @@ export const getFileData = (
{ path, makeFileActive = true, openFile = makeFileActive },
) => {
const file = state.entries[path];
const fileDeletedAndReadded = getters.isFileDeletedAndReadded(path);
if (file.raw || (file.tempFile && !file.prevPath)) return Promise.resolve();
if (file.raw || (file.tempFile && !file.prevPath && !fileDeletedAndReadded))
return Promise.resolve();
commit(types.TOGGLE_LOADING, { entry: file });
......@@ -102,11 +104,16 @@ export const setFileMrChange = ({ commit }, { file, mrChange }) => {
export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) => {
const file = state.entries[path];
const stagedFile = state.stagedFiles.find(f => f.path === path);
return new Promise((resolve, reject) => {
const fileDeletedAndReadded = getters.isFileDeletedAndReadded(path);
service
.getRawFileData(file)
.getRawFileData(fileDeletedAndReadded ? stagedFile : file)
.then(raw => {
if (!(file.tempFile && !file.prevPath)) commit(types.SET_FILE_RAW_DATA, { file, raw });
if (!(file.tempFile && !file.prevPath && !fileDeletedAndReadded))
commit(types.SET_FILE_RAW_DATA, { file, raw, fileDeletedAndReadded });
if (file.mrChange && file.mrChange.new_file === false) {
const baseSha =
(getters.currentMergeRequest && getters.currentMergeRequest.baseCommitSha) || '';
......@@ -151,7 +158,7 @@ export const changeFileContent = ({ commit, dispatch, state }, { path, content }
if (file.changed && indexOfChangedFile === -1) {
commit(types.ADD_FILE_TO_CHANGED, path);
} else if (!file.changed && indexOfChangedFile !== -1) {
} else if (!file.changed && !file.tempFile && indexOfChangedFile !== -1) {
commit(types.REMOVE_FILE_FROM_CHANGED, path);
}
......
......@@ -54,27 +54,29 @@ export default {
}
});
},
[types.SET_FILE_RAW_DATA](state, { file, raw }) {
[types.SET_FILE_RAW_DATA](state, { file, raw, fileDeletedAndReadded = false }) {
const openPendingFile = state.openFiles.find(
f => f.path === file.path && f.pending && !(f.tempFile && !f.prevPath),
f =>
f.path === file.path && f.pending && !(f.tempFile && !f.prevPath && !fileDeletedAndReadded),
);
const stagedFile = state.stagedFiles.find(f => f.path === file.path);
if (file.tempFile && file.content === '') {
Object.assign(state.entries[file.path], {
content: raw,
});
if (file.tempFile && file.content === '' && !fileDeletedAndReadded) {
Object.assign(state.entries[file.path], { content: raw });
} else if (fileDeletedAndReadded) {
Object.assign(stagedFile, { raw });
} else {
Object.assign(state.entries[file.path], {
raw,
});
Object.assign(state.entries[file.path], { raw });
}
if (!openPendingFile) return;
if (!openPendingFile.tempFile) {
openPendingFile.raw = raw;
} else if (openPendingFile.tempFile) {
} else if (openPendingFile.tempFile && !fileDeletedAndReadded) {
openPendingFile.content = raw;
} else if (fileDeletedAndReadded) {
Object.assign(stagedFile, { raw });
}
},
[types.SET_FILE_BASE_RAW_DATA](state, { file, baseRaw }) {
......
const MARKDOWN_EXTENSIONS = ['mdown', 'mkd', 'mkdn', 'md', 'markdown'];
const ASCIIDOC_EXTENSIONS = ['adoc', 'ad', 'asciidoc'];
const OTHER_EXTENSIONS = ['textile', 'rdoc', 'org', 'creole', 'wiki', 'mediawiki', 'rst'];
const EXTENSIONS = [...MARKDOWN_EXTENSIONS, ...ASCIIDOC_EXTENSIONS, ...OTHER_EXTENSIONS];
const PLAIN_FILENAMES = ['readme', 'index'];
const FILE_REGEXP = new RegExp(
`^(${PLAIN_FILENAMES.join('|')})(.(${EXTENSIONS.join('|')}))?$`,
'i',
);
const PLAIN_FILE_REGEXP = new RegExp(`^(${PLAIN_FILENAMES.join('|')})`, 'i');
const EXTENSIONS_REGEXP = new RegExp(`.(${EXTENSIONS.join('|')})$`, 'i');
const FILENAMES = ['index', 'readme'];
// eslint-disable-next-line import/prefer-default-export
export const readmeFile = blobs => {
const readMeFiles = blobs.filter(f => f.name.search(FILE_REGEXP) !== -1);
const MARKUP_EXTENSIONS = [
'ad',
'adoc',
'asciidoc',
'creole',
'markdown',
'md',
'mdown',
'mediawiki',
'mkd',
'mkdn',
'org',
'rdoc',
'rst',
'textile',
'wiki',
];
const previewableReadme = readMeFiles.find(f => f.name.search(EXTENSIONS_REGEXP) !== -1);
const plainReadme = readMeFiles.find(f => f.name.search(PLAIN_FILE_REGEXP) !== -1);
const isRichReadme = file => {
const re = new RegExp(`^(${FILENAMES.join('|')})\\.(${MARKUP_EXTENSIONS.join('|')})$`, 'i');
return re.test(file.name);
};
return previewableReadme || plainReadme;
const isPlainReadme = file => {
const re = new RegExp(`^(${FILENAMES.join('|')})$`, 'i');
return re.test(file.name);
};
// eslint-disable-next-line import/prefer-default-export
export const readmeFile = blobs => blobs.find(isRichReadme) || blobs.find(isPlainReadme);
......@@ -4,7 +4,6 @@ class ProjectCiCdSetting < ApplicationRecord
include IgnorableColumns
# https://gitlab.com/gitlab-org/gitlab/issues/36651
ignore_column :merge_trains_enabled, remove_with: '12.7', remove_after: '2019-12-22'
belongs_to :project, inverse_of: :ci_cd_settings
# The version of the schema that first introduced this model/table.
......
# frozen_string_literal: true
# SpamCheckService
# SpamCheckMethods
#
# Provide helper methods for checking if a given spammable object has
# potential spam data.
#
# Dependencies:
# - params with :request
#
module SpamCheckService
module SpamCheckMethods
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def filter_spam_check_params
@request = params.delete(:request)
......
# frozen_string_literal: true
class CreateSnippetService < BaseService
include SpamCheckService
include SpamCheckMethods
def execute
filter_spam_check_params
......
......@@ -2,7 +2,7 @@
module Issues
class CreateService < Issues::BaseService
include SpamCheckService
include SpamCheckMethods
include ResolveDiscussions
def execute
......
......@@ -2,7 +2,7 @@
module Issues
class UpdateService < Issues::BaseService
include SpamCheckService
include SpamCheckMethods
def execute(issue)
handle_move_between_ids(issue)
......
# frozen_string_literal: true
class UpdateSnippetService < BaseService
include SpamCheckService
include SpamCheckMethods
attr_accessor :snippet
......
---
title: "Web IDE: Fix Incorrect diff of deletion and addition of the same file"
merge_request: 21680
author:
type: fixed
# frozen_string_literal: true
class DropProjectCiCdSettingsMergeTrainsEnabled < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_column :project_ci_cd_settings, :merge_trains_enabled
end
def down
add_column_with_default :project_ci_cd_settings, :merge_trains_enabled, :boolean, default: false, allow_null: true
end
end
......@@ -3098,7 +3098,6 @@ ActiveRecord::Schema.define(version: 2020_01_08_155731) do
t.integer "project_id", null: false
t.boolean "group_runners_enabled", default: true, null: false
t.boolean "merge_pipelines_enabled"
t.boolean "merge_trains_enabled", default: false, null: false
t.integer "default_git_depth"
t.index ["project_id"], name: "index_project_ci_cd_settings_on_project_id", unique: true
end
......
......@@ -32,11 +32,11 @@ In the case of [custom domains](#custom-domains) (but not
ports `80` and/or `443`. For that reason, there is some flexibility in the way
which you can set it up:
1. Run the Pages daemon in the same server as GitLab, listening on a secondary IP.
1. Run the Pages daemon in a separate server. In that case, the
- Run the Pages daemon in the same server as GitLab, listening on a **secondary IP**.
- Run the Pages daemon in a [separate server](#running-gitlab-pages-on-a-separate-server). In that case, the
[Pages path](#change-storage-path) must also be present in the server that
the Pages daemon is installed, so you will have to share it via network.
1. Run the Pages daemon in the same server as GitLab, listening on the same IP
- Run the Pages daemon in the same server as GitLab, listening on the same IP
but on different ports. In that case, you will have to proxy the traffic with
a loadbalancer. If you choose that route note that you should use TCP load
balancing for HTTPS. If you use TLS-termination (HTTPS-load balancing) the
......@@ -182,7 +182,7 @@ The [GitLab Pages README](https://gitlab.com/gitlab-org/gitlab-pages#caveats) ha
In addition to the wildcard domains, you can also have the option to configure
GitLab Pages to work with custom domains. Again, there are two options here:
support custom domains with and without TLS certificates. The easiest setup is
that without TLS certificates. In either case, you'll need a secondary IP. If
that without TLS certificates. In either case, you'll need a **secondary IP**. If
you have IPv6 as well as IPv4 addresses, you can use them both.
### Custom domains
......
......@@ -426,7 +426,7 @@ Status: 200 OK
The link to the next page contains an additional filter `id_after=42` which excludes records we have retrieved already.
Note the type of filter depends on the `order_by` option used and we may have more than one additional filter.
The `Link` header is absent when the end of the collection has been reached and there are no additional records to retrieve.
When the end of the collection has been reached and there are no additional records to retrieve, the `Link` header is absent and the resulting array is empty.
We recommend using only the given link to retrieve the next page instead of building your own URL. Apart from the headers shown,
we don't expose additional pagination headers.
......
......@@ -4,6 +4,7 @@ module API
module Helpers
include Gitlab::Utils
include Helpers::Pagination
include Helpers::PaginationStrategies
SUDO_HEADER = "HTTP_SUDO"
GITLAB_SHARED_SECRET_HEADER = "Gitlab-Shared-Secret"
......
......@@ -3,34 +3,9 @@
module API
module Helpers
module Pagination
# This returns an ActiveRecord relation
def paginate(relation)
Gitlab::Pagination::OffsetPagination.new(self).paginate(relation)
end
# This applies pagination and executes the query
# It always returns an array instead of an ActiveRecord relation
def paginate_and_retrieve!(relation)
offset_or_keyset_pagination(relation).to_a
end
private
def offset_or_keyset_pagination(relation)
return paginate(relation) unless keyset_pagination_enabled?
request_context = Gitlab::Pagination::Keyset::RequestContext.new(self)
unless Gitlab::Pagination::Keyset.available?(request_context, relation)
return error!('Keyset pagination is not yet available for this type of request', 405)
end
Gitlab::Pagination::Keyset.paginate(request_context, relation)
end
def keyset_pagination_enabled?
params[:pagination] == 'keyset' && Feature.enabled?(:api_keyset_pagination, default_enabled: true)
end
end
end
end
# frozen_string_literal: true
module API
module Helpers
module PaginationStrategies
def paginate_with_strategies(relation)
paginator = paginator(relation)
yield(paginator.paginate(relation)).tap do |records, _|
paginator.finalize(records)
end
end
def paginator(relation)
return Gitlab::Pagination::OffsetPagination.new(self) unless keyset_pagination_enabled?
request_context = Gitlab::Pagination::Keyset::RequestContext.new(self)
unless Gitlab::Pagination::Keyset.available?(request_context, relation)
return error!('Keyset pagination is not yet available for this type of request', 405)
end
Gitlab::Pagination::Keyset::Pager.new(request_context)
end
private
def keyset_pagination_enabled?
params[:pagination] == 'keyset' && Feature.enabled?(:api_keyset_pagination, default_enabled: true)
end
end
end
end
......@@ -90,18 +90,22 @@ module API
def present_projects(projects, options = {})
projects = reorder_projects(projects)
projects = apply_filters(projects)
projects = paginate(projects)
projects, options = with_custom_attributes(projects, options)
options = options.reverse_merge(
with: current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails,
statistics: params[:statistics],
current_user: current_user,
license: false
)
options[:with] = Entities::BasicProjectDetails if params[:simple]
records, options = paginate_with_strategies(projects) do |projects|
projects, options = with_custom_attributes(projects, options)
options = options.reverse_merge(
with: current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails,
statistics: params[:statistics],
current_user: current_user,
license: false
)
options[:with] = Entities::BasicProjectDetails if params[:simple]
[options[:with].prepare_relation(projects, options), options]
end
present options[:with].prepare_relation(projects, options), options
present records, options
end
def translate_params_for_compatibility(params)
......
......@@ -17,7 +17,7 @@ module Gitlab
allow_failure type stage when start_in artifacts cache
dependencies before_script needs after_script variables
environment coverage retry parallel extends interruptible timeout
resource_group].freeze
resource_group release].freeze
REQUIRED_BY_NEEDS = %i[stage].freeze
......@@ -151,14 +151,18 @@ module Gitlab
description: 'Coverage configuration for this job.',
inherit: false
entry :release, Entry::Release,
description: 'This job will produce a release.',
inherit: false
helpers :before_script, :script, :stage, :type, :after_script,
:cache, :image, :services, :only, :except, :variables,
:artifacts, :environment, :coverage, :retry, :rules,
:parallel, :needs, :interruptible
:parallel, :needs, :interruptible, :release
attributes :script, :tags, :allow_failure, :when, :dependencies,
:needs, :retry, :parallel, :extends, :start_in, :rules,
:interruptible, :timeout, :resource_group
:interruptible, :timeout, :resource_group, :release
def self.matching?(name, config)
!name.to_s.start_with?('.') &&
......@@ -243,6 +247,7 @@ module Gitlab
interruptible: interruptible_defined? ? interruptible_value : nil,
timeout: has_timeout? ? ChronicDuration.parse(timeout.to_s) : nil,
artifacts: artifacts_value,
release: release_value,
after_script: after_script_value,
ignore: ignored?,
needs: needs_defined? ? needs_value : nil,
......
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
##
# Entry that represents a release configuration.
#
class Release < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Configurable
include ::Gitlab::Config::Entry::Validatable
include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[tag_name name description assets].freeze
attributes %i[tag_name name assets].freeze
# Attributable description conflicts with
# ::Gitlab::Config::Entry::Node.description
def has_description?
true
end
def description
config[:description]
end
entry :assets, Entry::Release::Assets, description: 'Release assets.'
validations do
validates :config, allowed_keys: ALLOWED_KEYS
validates :tag_name, presence: true
validates :description, type: String, presence: true
end
helpers :assets
def value
@config[:assets] = assets_value if @config.key?(:assets)
@config
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
##
# Entry that represents a configuration of release assets.
#
class Release
class Assets < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Configurable
include ::Gitlab::Config::Entry::Validatable
include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[links].freeze
attributes ALLOWED_KEYS
entry :links, Entry::Release::Assets::Links, description: 'Release assets:links.'
validations do
validates :config, allowed_keys: ALLOWED_KEYS
validates :links, array_of_hashes: true, presence: true
end
helpers :links
def value
@config[:links] = links_value if @config.key?(:links)
@config
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
##
# Entry that represents a configuration of release:assets:links.
#
class Release
class Assets
class Link < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[name url].freeze
attributes ALLOWED_KEYS
validations do
validates :config, allowed_keys: ALLOWED_KEYS
validates :name, type: String, presence: true
validates :url, presence: true, addressable_url: true
end
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
##
# Entry that represents a configuration of release:assets:links.
#
class Release
class Assets
class Links < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Configurable
include ::Gitlab::Config::Entry::Validatable
entry :link, Entry::Release::Assets::Link, description: 'Release assets:links:link.'
validations do
validates :config, type: Array, presence: true
end
def skip_config_hash_validation?
true
end
end
end
end
end
end
end
end
......@@ -81,10 +81,15 @@ module Gitlab
instance: job[:instance],
start_in: job[:start_in],
trigger: job[:trigger],
bridge_needs: job.dig(:needs, :bridge)&.first
bridge_needs: job.dig(:needs, :bridge)&.first,
release: release(job)
}.compact }.compact
end
def release(job)
job[:release] if Feature.enabled?(:ci_release_generation, default_enabled: false)
end
def stage_builds_attributes(stage)
@jobs.values
.select { |job| job[:stage] == stage }
......@@ -133,7 +138,6 @@ module Gitlab
@jobs.each do |name, job|
# logical validation for job
validate_job_stage!(name, job)
validate_job_dependencies!(name, job)
validate_job_needs!(name, job)
......
......@@ -10,7 +10,7 @@ module Gitlab
def attributes(*attributes)
attributes.flatten.each do |attribute|
if method_defined?(attribute)
raise ArgumentError, 'Method already defined!'
raise ArgumentError, "Method already defined: #{attribute}"
end
define_method(attribute) do
......
......@@ -5,7 +5,7 @@ module Gitlab
module Entry
##
# This mixin is responsible for adding DSL, which purpose is to
# simplifly process of adding child nodes.
# simplify the process of adding child nodes.
#
# This can be used only if parent node is a configuration entry that
# holds a hash as a configuration value, for example:
......
......@@ -8,9 +8,17 @@ module Gitlab
feature = Feature.get(feature_key)
return feature.enabled? if Feature.persisted?(feature)
# Disable Rugged auto-detect(can_use_disk?) when Puma threads>1
# https://gitlab.com/gitlab-org/gitlab/issues/119326
return false if running_puma_with_multiple_threads?
Gitlab::GitalyClient.can_use_disk?(repo.storage)
end
def running_puma_with_multiple_threads?
Gitlab::Runtime.puma? && ::Puma.cli_config.options[:max_threads] > 1
end
def execute_rugged_call(method_name, *args)
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
start = Gitlab::Metrics::System.monotonic_time
......
......@@ -3,6 +3,14 @@
module Gitlab
module Pagination
class Base
def paginate(relation)
raise NotImplementedError
end