Commit 7d7d4bcb authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-07-24

# Conflicts:
#	db/schema.rb
#	doc/api/users.md
#	spec/requests/api/users_spec.rb

[ci skip]
parents f33a2bf2 abae261b
......@@ -582,9 +582,8 @@ danger-review:
- retry gem install danger --no-ri --no-rdoc
cache: {}
only:
refs:
- branches@gitlab-org/gitlab-ce
- branches@gitlab-org/gitlab-ee
variables:
- $DANGER_GITLAB_API_TOKEN
except:
refs:
- master
......
......@@ -4,3 +4,4 @@ danger.import_dangerfile(path: 'danger/changelog')
danger.import_dangerfile(path: 'danger/specs')
danger.import_dangerfile(path: 'danger/gemfile')
danger.import_dangerfile(path: 'danger/database')
danger.import_dangerfile(path: 'danger/frozen_string')
......@@ -243,7 +243,7 @@ gem 'ruby-fogbugz', '~> 0.2.1'
gem 'kubeclient', '~> 3.1.0'
# Sanitize user input
gem 'sanitize', '~> 4.6.5'
gem 'sanitize', '~> 4.6'
gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input
......
......@@ -543,7 +543,7 @@ GEM
net-ntp (2.1.3)
net-ssh (5.0.1)
netrc (0.11.0)
nokogiri (1.8.3)
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
nokogumbo (1.5.0)
nokogiri
......@@ -837,7 +837,7 @@ GEM
et-orbi (~> 1.0)
rugged (0.27.2)
safe_yaml (1.0.4)
sanitize (4.6.5)
sanitize (4.6.6)
crass (~> 1.0.2)
nokogiri (>= 1.4.4)
nokogumbo (~> 1.4)
......@@ -1194,7 +1194,7 @@ DEPENDENCIES
ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4)
rugged (~> 0.27)
sanitize (~> 4.6.5)
sanitize (~> 4.6)
sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7)
......
......@@ -1205,7 +1205,7 @@ DEPENDENCIES
ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4)
rugged (~> 0.27)
sanitize (~> 4.6.5)
sanitize (~> 4.6)
sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7)
......
......@@ -562,6 +562,26 @@ export const addSelectOnFocusBehaviour = (selector = '.js-select-on-focus') => {
});
};
/**
* Method to round of values with decimal places
* with provided precision.
*
* Taken from https://stackoverflow.com/a/7343013/414749
*
* Eg; roundOffFloat(3.141592, 3) = 3.142
*
* Refer to spec/javascripts/lib/utils/common_utils_spec.js for
* more supported examples.
*
* @param {Float} number
* @param {Number} precision
*/
export const roundOffFloat = (number, precision = 0) => {
// eslint-disable-next-line no-restricted-properties
const multiplier = Math.pow(10, precision);
return Math.round(number * multiplier) / multiplier;
};
window.gl = window.gl || {};
window.gl.utils = {
...(window.gl.utils || {}),
......
......@@ -15,7 +15,7 @@ document.addEventListener('DOMContentLoaded', () => {
const notesDataset = document.getElementById('js-vue-notes').dataset;
const parsedUserData = JSON.parse(notesDataset.currentUserData);
const noteableData = JSON.parse(notesDataset.noteableData);
const { markdownVersion } = notesDataset;
const markdownVersion = parseInt(notesDataset.markdownVersion, 10);
let currentUserData = {};
noteableData.noteableType = notesDataset.noteableType;
......
<script>
import { roundOffFloat } from '~/lib/utils/common_utils';
import tooltip from '~/vue_shared/directives/tooltip';
export default {
......@@ -70,7 +71,7 @@ export default {
},
methods: {
getPercent(count) {
return Math.ceil((count / this.totalCount) * 100);
return roundOffFloat((count / this.totalCount) * 100, 1);
},
barStyle(percent) {
return `width: ${percent}%;`;
......
......@@ -10,7 +10,7 @@
.status-neutral,
.status-red, {
height: 100%;
min-width: 30px;
min-width: 40px;
padding: 0 5px;
font-size: $tooltip-font-size;
font-weight: normal;
......
# frozen_string_literal: true
class AnalyticsBuildEntity < Grape::Entity
include RequestAwareEntity
include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsBuildSerializer < BaseSerializer
entity AnalyticsBuildEntity
end
# frozen_string_literal: true
class AnalyticsCommitEntity < CommitEntity
include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsCommitSerializer < BaseSerializer
entity AnalyticsCommitEntity
end
# frozen_string_literal: true
class AnalyticsGenericSerializer < BaseSerializer
def represent(resource, opts = {})
resource.symbolize_keys!
......
# frozen_string_literal: true
class AnalyticsIssueEntity < Grape::Entity
include RequestAwareEntity
include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsIssueSerializer < AnalyticsGenericSerializer
entity AnalyticsIssueEntity
end
# frozen_string_literal: true
class AnalyticsMergeRequestEntity < AnalyticsIssueEntity
expose :state
......
# frozen_string_literal: true
class AnalyticsMergeRequestSerializer < AnalyticsGenericSerializer
entity AnalyticsMergeRequestEntity
end
# frozen_string_literal: true
class AnalyticsStageEntity < Grape::Entity
include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsStageSerializer < BaseSerializer
entity AnalyticsStageEntity
end
# frozen_string_literal: true
class AnalyticsSummaryEntity < Grape::Entity
expose :value, safe: true
expose :title
......
# frozen_string_literal: true
class AnalyticsSummarySerializer < BaseSerializer
entity AnalyticsSummaryEntity
end
# frozen_string_literal: true
class AwardEmojiEntity < Grape::Entity
expose :name
expose :user, using: API::Entities::UserSafe
......
# frozen_string_literal: true
class BaseSerializer
attr_reader :params
......
# frozen_string_literal: true
class BlobEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class BuildActionEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class BuildArtifactEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class BuildDetailsEntity < JobEntity
expose :coverage, :erased_at, :duration
expose :tag_list, as: :tags
......
# frozen_string_literal: true
class BuildMetadataEntity < Grape::Entity
expose :timeout_human_readable
expose :timeout_source do |metadata|
......
# frozen_string_literal: true
class BuildSerializer < BaseSerializer
entity JobEntity
......
# frozen_string_literal: true
class ClusterApplicationEntity < Grape::Entity
expose :name
expose :status_name, as: :status
......
# frozen_string_literal: true
class ClusterEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class ClusterSerializer < BaseSerializer
entity ClusterEntity
......
# frozen_string_literal: true
class CohortActivityMonthEntity < Grape::Entity
include ActionView::Helpers::NumberHelper
......
# frozen_string_literal: true
class CohortEntity < Grape::Entity
include ActionView::Helpers::NumberHelper
......
# frozen_string_literal: true
class CohortsEntity < Grape::Entity
expose :months_included
expose :cohorts, using: CohortEntity
......
# frozen_string_literal: true
class CohortsSerializer < AnalyticsGenericSerializer
entity CohortsEntity
end
# frozen_string_literal: true
class CommitEntity < API::Entities::Commit
include RequestAwareEntity
......
# frozen_string_literal: true
module WithPagination
attr_accessor :paginator
......
# frozen_string_literal: true
class ContainerRepositoriesSerializer < BaseSerializer
entity ContainerRepositoryEntity
end
# frozen_string_literal: true
class ContainerRepositoryEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class ContainerTagEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class ContainerTagsSerializer < BaseSerializer
entity ContainerTagEntity
......
# frozen_string_literal: true
class DeployKeyEntity < Grape::Entity
expose :id
expose :user_id
......
# frozen_string_literal: true
class DeployKeySerializer < BaseSerializer
entity DeployKeyEntity
end
# frozen_string_literal: true
class DeployKeysProjectEntity < Grape::Entity
expose :can_push
expose :project, using: ProjectEntity
......
# frozen_string_literal: true
class DeploymentEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class DeploymentSerializer < BaseSerializer
entity DeploymentEntity
......
# frozen_string_literal: true
class DiffFileEntity < Grape::Entity
include RequestAwareEntity
include BlobHelper
......
# frozen_string_literal: true
class DiffsEntity < Grape::Entity
include DiffHelper
include RequestAwareEntity
......
# frozen_string_literal: true
class DiffsSerializer < BaseSerializer
entity DiffsEntity
end
# frozen_string_literal: true
class DiscussionEntity < Grape::Entity
include RequestAwareEntity
include NotesHelper
......
# frozen_string_literal: true
class DiscussionSerializer < BaseSerializer
entity DiscussionEntity
end
# frozen_string_literal: true
module EntityDateHelper
include ActionView::Helpers::DateHelper
include ActionView::Helpers::TagHelper
......@@ -50,15 +52,20 @@ module EntityDateHelper
elsif entity.due_date
is_upcoming = (entity.due_date - Date.today).to_i > 0
time_ago = time_ago_in_words(entity.due_date)
content = time_ago.gsub(/\d+/) { |match| "<strong>#{match}</strong>" }
content.slice!("about ")
content << " " + (is_upcoming ? _("remaining") : _("ago"))
content.html_safe
# https://gitlab.com/gitlab-org/gitlab-ce/issues/49440
#
# Need to improve the i18n here and do a full translation
# of the string instead of piecewise translations.
content = time_ago
.gsub(/\d+/) { |match| "<strong>#{match}</strong>" }
.remove("about ")
remaining_or_ago = is_upcoming ? _("remaining") : _("ago")
"#{content} #{remaining_or_ago}".html_safe
elsif entity.start_date && entity.start_date.past?
days = entity.elapsed_days
content = content_tag(:strong, days)
content << " #{'day'.pluralize(days)} elapsed"
content.html_safe
days = entity.elapsed_days
"#{content_tag(:strong, days)} #{'day'.pluralize(days)} elapsed".html_safe
end
end
end
# frozen_string_literal: true
class EntityRequest
# We use EntityRequest object to collect parameters and variables
# from the controller. Because options that are being passed to the entity
......
# frozen_string_literal: true
class EnvironmentEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class EnvironmentSerializer < BaseSerializer
include WithPagination
......
# frozen_string_literal: true
class GroupChildEntity < Grape::Entity
include ActionView::Helpers::NumberHelper
include RequestAwareEntity
......
# frozen_string_literal: true
class GroupChildSerializer < BaseSerializer
include WithPagination
......
# frozen_string_literal: true
class GroupEntity < Grape::Entity
include ActionView::Helpers::NumberHelper
include RequestAwareEntity
......
# frozen_string_literal: true
class GroupSerializer < BaseSerializer
include WithPagination
......
# frozen_string_literal: true
class GroupVariableEntity < Grape::Entity
expose :id
expose :key
......
# frozen_string_literal: true
class GroupVariableSerializer < BaseSerializer
entity GroupVariableEntity
end
# frozen_string_literal: true
class IssuableEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class IssuableSidebarEntity < Grape::Entity
include TimeTrackableEntity
include RequestAwareEntity
......
# frozen_string_literal: true
class IssueEntity < IssuableEntity
include TimeTrackableEntity
......
# frozen_string_literal: true
class IssueSerializer < BaseSerializer
# This overrided method takes care of which entity should be used
# to serialize the `issue` based on `basic` key in `opts` param.
......
# frozen_string_literal: true
class IssueSidebarEntity < IssuableSidebarEntity
prepend ::EE::IssueSidebarEntity
......
# frozen_string_literal: true
class JobEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class JobGroupEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class LabelEntity < Grape::Entity
expose :id, if: ->(label, _) { !label.is_a?(GlobalLabel) }
......
# frozen_string_literal: true
class LabelSerializer < BaseSerializer
entity LabelEntity
......
# frozen_string_literal: true
class LfsFileLockEntity < Grape::Entity
root 'locks', 'lock'
......
# frozen_string_literal: true
class LfsFileLockSerializer < BaseSerializer
entity LfsFileLockEntity
end
# frozen_string_literal: true
class MergeRequestBasicEntity < IssuableSidebarEntity
expose :assignee_id
expose :merge_status
......
# frozen_string_literal: true
class MergeRequestBasicSerializer < BaseSerializer
entity MergeRequestBasicEntity
end
# frozen_string_literal: true
class MergeRequestCreateEntity < Grape::Entity
expose :iid
......
# frozen_string_literal: true
class MergeRequestCreateSerializer < BaseSerializer
entity MergeRequestCreateEntity
end
# frozen_string_literal: true
class MergeRequestDiffEntity < Grape::Entity
include Gitlab::Routing
include GitHelper
......
# frozen_string_literal: true
class MergeRequestMetricsEntity < Grape::Entity
expose :latest_closed_at, as: :closed_at
expose :merged_at
......
# frozen_string_literal: true
class MergeRequestSerializer < BaseSerializer
# This overrided method takes care of which entity should be used
# to serialize the `merge_request` based on `serializer` key in `opts` param.
......
# frozen_string_literal: true
class MergeRequestUserEntity < UserEntity
include RequestAwareEntity
include BlobHelper
......
# frozen_string_literal: true
class MergeRequestWidgetEntity < IssuableEntity
prepend ::EE::MergeRequestWidgetEntity
......
# frozen_string_literal: true
class NoteAttachmentEntity < Grape::Entity
expose :url
expose :filename
......
# frozen_string_literal: true
class NoteEntity < API::Entities::Note
include RequestAwareEntity
include NotesHelper
......
# frozen_string_literal: true
class NoteUserEntity < UserEntity
unexpose :web_url
end
# frozen_string_literal: true
class PipelineDetailsEntity < PipelineEntity
expose :details do
expose :ordered_stages, as: :stages, using: StageEntity
......
# frozen_string_literal: true
class PipelineEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class PipelineSerializer < BaseSerializer
include WithPagination
entity PipelineDetailsEntity
......
# frozen_string_literal: true
class ProjectEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class ProjectMirrorEntity < Grape::Entity
prepend ::EE::ProjectMirrorEntity
......
# frozen_string_literal: true
class ProjectNoteEntity < NoteEntity
expose :human_access do |note|
note.project.team.human_max_access(note.author_id)
......
# frozen_string_literal: true
class ProjectNoteSerializer < BaseSerializer
entity ProjectNoteEntity
end
# frozen_string_literal: true
class ProjectSerializer < BaseSerializer
entity ProjectEntity
end
# frozen_string_literal: true
module RequestAwareEntity
extend ActiveSupport::Concern
......
# frozen_string_literal: true
class RunnerEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class StageEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class StageSerializer < BaseSerializer
include WithPagination
......
# frozen_string_literal: true
class StatusEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class SubmoduleEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
module TimeTrackableEntity
extend ActiveSupport::Concern
extend Grape
......
# frozen_string_literal: true
class TreeEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
# TODO: Inherit from TreeEntity, when `Tree` implements `id` and `name` like `Gitlab::Git::Tree`.
class TreeRootEntity < Grape::Entity
include RequestAwareEntity
......
# frozen_string_literal: true
class TreeSerializer < BaseSerializer
entity TreeRootEntity
end
# frozen_string_literal: true
class UserEntity < API::Entities::UserBasic
include RequestAwareEntity
......
# frozen_string_literal: true
class UserSerializer < BaseSerializer
entity UserEntity
end
# frozen_string_literal: true
class VariableEntity < Grape::Entity
prepend ::EE::VariableEntity
......
# frozen_string_literal: true
class VariableSerializer < BaseSerializer
entity VariableEntity
end
---
title: Fix Vue datatype errors for markdownVersion parsing
merge_request: 20800
author:
type: fixed
---
title: Add Dangerfile for frozen_string_literal
merge_request: 20767
author: gfyoung
type: performance
---
title: Enable frozen string in app/serializers/**/*.rb
merge_request: 20726
author: gfyoung
type: performance
---
title: Show decimal place up to single digit in Stacked Progress Bar
merge_request: 20776
author:
type: changed
---
title: Bump nokogiri to 1.8.4 and sanitize to 4.6.6 for performance
merge_request: 20795
author:
type: performance
---
title: Disable Gitaly timeouts when creating or restoring backups
merge_request: 20810
author:
type: fixed
require_relative '../settings'
require_relative '../object_store_settings'
# Default settings
Settings['ldap'] ||= Settingslogic.new({})
......@@ -196,14 +197,7 @@ Settings.artifacts['storage_path'] = Settings.absolute(Settings.artifacts.values
# Settings.artifact['path'] is deprecated, use `storage_path` instead
Settings.artifacts['path'] = Settings.artifacts['storage_path']
Settings.artifacts['max_size'] ||= 100 # in megabytes
Settings.artifacts['object_store'] ||= Settingslogic.new({})
Settings.artifacts['object_store']['enabled'] = false if Settings.artifacts['object_store']['enabled'].nil?
Settings.artifacts['object_store']['remote_directory'] ||= nil
Settings.artifacts['object_store']['direct_upload'] = false if Settings.artifacts['object_store']['direct_upload'].nil?
Settings.artifacts['object_store']['background_upload'] = true if Settings.artifacts['object_store']['background_upload'].nil?
Settings.artifacts['object_store']['proxy_download'] = false if Settings.artifacts['object_store']['proxy_download'].nil?
# Convert upload connection settings to use string keys, to make Fog happy
Settings.artifacts['object_store']['connection']&.deep_stringify_keys!
Settings.artifacts['object_store'] = ObjectStoreSettings.parse(Settings.artifacts['object_store'])
#
# Registry
......@@ -247,14 +241,7 @@ Settings.gitlab['geo_status_timeout'] ||= 10
Settings['lfs'] ||= Settingslogic.new({})
Settings.lfs['enabled'] = true if Settings.lfs['enabled'].nil?
Settings.lfs['storage_path'] = Settings.absolute(Settings.lfs['storage_path'] || File.join(Settings.shared['path'], "lfs-objects"))
Settings.lfs['object_store'] ||= Settingslogic.new({})
Settings.lfs['object_store']['enabled'] = false if Settings.lfs['object_store']['enabled'].nil?
Settings.lfs['object_store']['remote_directory'] ||= nil
Settings.lfs['object_store']['direct_upload'] = false if Settings.lfs['object_store']['direct_upload'].nil?
Settings.lfs['object_store']['background_upload'] = true if Settings.lfs['object_store']['background_upload'].nil?
Settings.lfs['object_store']['proxy_download'] = false if Settings.lfs['object_store']['proxy_download'].nil?
# Convert upload connection settings to use string keys, to make Fog happy
Settings.lfs['object_store']['connection']&.deep_stringify_keys!
Settings.lfs['object_store'] = ObjectStoreSettings.parse(Settings.lfs['object_store'])
#
# Uploads
......@@ -262,14 +249,8 @@ Settings.lfs['object_store']['connection']&.deep_stringify_keys!
Settings['uploads'] ||= Settingslogic.new({})
Settings.uploads['storage_path'] = Settings.absolute(Settings.uploads['storage_path'] || 'public')
Settings.uploads['base_dir'] = Settings.uploads['base_dir'] || 'uploads/-/system'
Settings.uploads['object_store'] ||= Settingslogic.new({})
Settings.uploads['object_store']['enabled'] = false if Settings.uploads['object_store']['enabled'].nil?
Settings.uploads['object_store'] = ObjectStoreSettings.parse(Settings.uploads['object_store'])
Settings.uploads['object_store']['remote_directory'] ||= 'uploads'
Settings.uploads['object_store']['direct_upload'] = false if Settings.uploads['object_store']['direct_upload'].nil?
Settings.uploads['object_store']['background_upload'] = true if Settings.uploads['object_store']['background_upload'].nil?
Settings.uploads['object_store']['proxy_download'] = false if Settings.uploads['object_store']['proxy_download'].nil?
# Convert upload connection settings to use string keys, to make Fog happy
Settings.uploads['object_store']['connection']&.deep_stringify_keys!
#
# Mattermost
......
# Set default values for object_store settings
class ObjectStoreSettings
def self.parse(object_store)
object_store ||= Settingslogic.new({})
object_store['enabled'] = false if object_store['enabled'].nil?
object_store['remote_directory'] ||= nil
object_store['direct_upload'] = false if object_store['direct_upload'].nil?
object_store['background_upload'] = true if object_store['background_upload'].nil?
object_store['proxy_download'] = false if object_store['proxy_download'].nil?
# Convert upload connection settings to use string keys, to make Fog happy
object_store['connection']&.deep_stringify_keys!
object_store
end
end
# frozen_string_literal: true
FILE_EXTENSION = ".rb"
MAGIC_COMMENT = "# frozen_string_literal: true"
def get_files_with_no_magic_comment(files)
files.select do |file|
file.end_with?(FILE_EXTENSION) &&
!File.open(file, &:gets).start_with?(MAGIC_COMMENT)
end
end
files_to_check = git.added_files
files_to_fix = get_files_with_no_magic_comment(files_to_check)
if files_to_fix.any?
warn 'This merge request adds files that do not enforce frozen string literal. ' \
'See https://gitlab.com/gitlab-org/gitlab-ce/issues/47424 for more information.'
markdown(<<~MARKDOWN)
## Enable Frozen String Literal
The following files should have `#{MAGIC_COMMENT}` in the first line:
* #{files_to_fix.map { |path| "`#{path}`" }.join("\n* ")}
MARKDOWN
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPrivateProfileToUsers < ActiveRecord::Migration
DOWNTIME = false
def change
add_column :users, :private_profile, :boolean
end
end
......@@ -11,7 +11,11 @@
#
# It's strongly recommended that you check this file into your version control system.
<<<<<<< HEAD
ActiveRecord::Schema.define(version: 20180718100455) do
=======
ActiveRecord::Schema.define(version: 20180722103201) do
>>>>>>> upstream/master
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......
......@@ -253,8 +253,12 @@ Parameters:
"can_create_project": true,
"two_factor_enabled": true,
"external": false,
<<<<<<< HEAD
"private_profile": false,
"shared_runners_minutes_limit": 133
=======
"private_profile": false
>>>>>>> upstream/master
}
```
......@@ -294,8 +298,12 @@ Parameters:
- `skip_confirmation` (optional) - Skip confirmation - true or false (default)
- `external` (optional) - Flags the user as external - true or false(default)
- `avatar` (optional) - Image file for user's avatar
<<<<<<< HEAD
- `private_profile` (optional) - User's profile is private - true or false
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user
=======
- `private_profile (optional) - User's profile is private - true or false
>>>>>>> upstream/master
## User modification
......@@ -327,7 +335,11 @@ Parameters:
- `external` (optional) - Flags the user as external - true or false(default)
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user
- `avatar` (optional) - Image file for user's avatar
<<<<<<< HEAD
- `private_profile` (optional) - User's profile is private - true or false
=======
- `private_profile (optional) - User's profile is private - true or false
>>>>>>> upstream/master
On password update, user will be forced to change it upon next login.
Note, at the moment this method does only return a `404` error,
......
......@@ -48,6 +48,7 @@ the following table.
| `api` | Grants complete access to the API (read/write) ([introduced][ce-5951] in GitLab 8.15). Required for accessing Git repositories over HTTP when 2FA is enabled. |
| `read_registry` | Allows to read [container registry] images if a project is private and authorization is required ([introduced][ce-11845] in GitLab 9.3). |
| `sudo` | Allows performing API actions as any user in the system (if the authenticated user is an admin) ([introduced][ce-14838] in GitLab 10.2). |
| `read_repository` | Allows read-access to the repository through git clone). |
[2fa]: ../account/two_factor_authentication.md
[api]: ../../api/README.md
......
......@@ -353,8 +353,6 @@ module Gitlab
# offset: 5,
# after: Time.new(2016, 4, 21, 14, 32, 10)
# )
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/446
def log(options)
default_options = {
limit: 10,
......@@ -1029,8 +1027,8 @@ module Gitlab
end
def clean_stale_repository_files
gitaly_migrate(:repository_cleanup, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
gitaly_repository_client.cleanup if is_enabled && exists?
wrapped_gitaly_errors do
gitaly_repository_client.cleanup if exists?
end
rescue Gitlab::Git::CommandError => e # Don't fail if we can't cleanup
Rails.logger.error("Unable to clean repository on storage #{storage} with relative path #{relative_path}: #{e.message}")
......
......@@ -407,7 +407,7 @@ module Gitlab
# The default timeout on all Gitaly calls
def self.default_timeout
return 0 if Sidekiq.server?
return no_timeout if Sidekiq.server?
timeout(:gitaly_timeout_default)
end
......@@ -420,6 +420,10 @@ module Gitlab
timeout(:gitaly_timeout_medium)
end
def self.no_timeout
0
end
def self.timeout(timeout_name)
Gitlab::CurrentSettings.current_application_settings[timeout_name]
end
......
......@@ -202,7 +202,7 @@ module Gitlab
save_path,
:create_bundle,
Gitaly::CreateBundleRequest,
GitalyClient.default_timeout
GitalyClient.no_timeout
)
end
......@@ -220,7 +220,7 @@ module Gitlab
bundle_path,
:create_repository_from_bundle,
Gitaly::CreateRepositoryFromBundleRequest,
GitalyClient.default_timeout
GitalyClient.no_timeout
)
end
......@@ -245,7 +245,7 @@ module Gitlab
:repository_service,
:create_repository_from_snapshot,
request,
timeout: GitalyClient.default_timeout
timeout: GitalyClient.no_timeout
)
end
......
require 'spec_helper'
require Rails.root.join('config', 'object_store_settings.rb')
describe ObjectStoreSettings do
describe '.parse' do
it 'should set correct default values' do
settings = described_class.parse(nil)
expect(settings['enabled']).to be false
expect(settings['direct_upload']).to be false
expect(settings['background_upload']).to be true
expect(settings['remote_directory']).to be nil
end
it 'respects original values' do
original_settings = Settingslogic.new({
'enabled' => true,
'remote_directory' => 'artifacts'
})
settings = described_class.parse(original_settings)
expect(settings['enabled']).to be true
expect(settings['direct_upload']).to be false
expect(settings['background_upload']).to be true
expect(settings['remote_directory']).to eq 'artifacts'
end
end
end
......@@ -627,4 +627,23 @@ describe('common_utils', () => {
});
});
});
describe('roundOffFloat', () => {
it('Rounds off decimal places of a float number with provided precision', () => {
expect(commonUtils.roundOffFloat(3.141592, 3)).toBe(3.142);
});
it('Rounds off a float number to a whole number when provided precision is zero', () => {
expect(commonUtils.roundOffFloat(3.141592, 0)).toBe(3);
expect(commonUtils.roundOffFloat(3.5, 0)).toBe(4);
});
it('Rounds off float number to nearest 0, 10, 100, 1000 and so on when provided precision is below 0', () => {
expect(commonUtils.roundOffFloat(34567.14159, -1)).toBe(34570);
expect(commonUtils.roundOffFloat(34567.14159, -2)).toBe(34600);
expect(commonUtils.roundOffFloat(34567.14159, -3)).toBe(35000);
expect(commonUtils.roundOffFloat(34567.14159, -4)).toBe(30000);
expect(commonUtils.roundOffFloat(34567.14159, -5)).toBe(0);
});
});
});
......@@ -10,9 +10,9 @@ const createComponent = (config) => {
successLabel: 'Synced',
failureLabel: 'Failed',
neutralLabel: 'Out of sync',
successCount: 10,
failureCount: 5,
totalCount: 20,
successCount: 25,
failureCount: 10,
totalCount: 5000,
}, config);
return mountComponent(Component, defaultConfig);
......@@ -32,7 +32,7 @@ describe('StackedProgressBarComponent', () => {
describe('computed', () => {
describe('neutralCount', () => {
it('returns neutralCount based on totalCount, successCount and failureCount', () => {
expect(vm.neutralCount).toBe(5); // 20 - 10 - 5
expect(vm.neutralCount).toBe(4965); // 5000 - 25 - 10
});
});
});
......@@ -40,7 +40,11 @@ describe('StackedProgressBarComponent', () => {
describe('methods', () => {
describe('getPercent', () => {
it('returns percentage from provided count based on `totalCount`', () => {
expect(vm.getPercent(10)).toBe(50);
expect(vm.getPercent(500)).toBe(10);
});
it('returns percentage with decimal place from provided count based on `totalCount`', () => {
expect(vm.getPercent(10)).toBe(0.2);
});
});
......
......@@ -638,6 +638,7 @@ describe API::Users do
expect(user.reload.private_profile).to eq(true)
end
<<<<<<< HEAD
# EE
it "updates shared_runners_minutes_limit" do
expect do
......@@ -649,6 +650,8 @@ describe API::Users do
expect(json_response['shared_runners_minutes_limit']).to eq(133)
end
=======
>>>>>>> upstream/master
it "does not update admin status" do
put api("/users/#{admin_user.id}", admin), { can_create_group: false }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment