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: ...@@ -582,9 +582,8 @@ danger-review:
- retry gem install danger --no-ri --no-rdoc - retry gem install danger --no-ri --no-rdoc
cache: {} cache: {}
only: only:
refs: variables:
- branches@gitlab-org/gitlab-ce - $DANGER_GITLAB_API_TOKEN
- branches@gitlab-org/gitlab-ee
except: except:
refs: refs:
- master - master
......
...@@ -4,3 +4,4 @@ danger.import_dangerfile(path: 'danger/changelog') ...@@ -4,3 +4,4 @@ danger.import_dangerfile(path: 'danger/changelog')
danger.import_dangerfile(path: 'danger/specs') danger.import_dangerfile(path: 'danger/specs')
danger.import_dangerfile(path: 'danger/gemfile') danger.import_dangerfile(path: 'danger/gemfile')
danger.import_dangerfile(path: 'danger/database') danger.import_dangerfile(path: 'danger/database')
danger.import_dangerfile(path: 'danger/frozen_string')
...@@ -243,7 +243,7 @@ gem 'ruby-fogbugz', '~> 0.2.1' ...@@ -243,7 +243,7 @@ gem 'ruby-fogbugz', '~> 0.2.1'
gem 'kubeclient', '~> 3.1.0' gem 'kubeclient', '~> 3.1.0'
# Sanitize user input # Sanitize user input
gem 'sanitize', '~> 4.6.5' gem 'sanitize', '~> 4.6'
gem 'babosa', '~> 1.0.2' gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input # Sanitizes SVG input
......
...@@ -543,7 +543,7 @@ GEM ...@@ -543,7 +543,7 @@ GEM
net-ntp (2.1.3) net-ntp (2.1.3)
net-ssh (5.0.1) net-ssh (5.0.1)
netrc (0.11.0) netrc (0.11.0)
nokogiri (1.8.3) nokogiri (1.8.4)
mini_portile2 (~> 2.3.0) mini_portile2 (~> 2.3.0)
nokogumbo (1.5.0) nokogumbo (1.5.0)
nokogiri nokogiri
...@@ -837,7 +837,7 @@ GEM ...@@ -837,7 +837,7 @@ GEM
et-orbi (~> 1.0) et-orbi (~> 1.0)
rugged (0.27.2) rugged (0.27.2)
safe_yaml (1.0.4) safe_yaml (1.0.4)
sanitize (4.6.5) sanitize (4.6.6)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
nokogumbo (~> 1.4) nokogumbo (~> 1.4)
...@@ -1194,7 +1194,7 @@ DEPENDENCIES ...@@ -1194,7 +1194,7 @@ DEPENDENCIES
ruby_parser (~> 3.8) ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4) rufus-scheduler (~> 3.4)
rugged (~> 0.27) rugged (~> 0.27)
sanitize (~> 4.6.5) sanitize (~> 4.6)
sass-rails (~> 5.0.6) sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7) seed-fu (~> 2.3.7)
......
...@@ -1205,7 +1205,7 @@ DEPENDENCIES ...@@ -1205,7 +1205,7 @@ DEPENDENCIES
ruby_parser (~> 3.8) ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4) rufus-scheduler (~> 3.4)
rugged (~> 0.27) rugged (~> 0.27)
sanitize (~> 4.6.5) sanitize (~> 4.6)
sass-rails (~> 5.0.6) sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7) seed-fu (~> 2.3.7)
......
...@@ -562,6 +562,26 @@ export const addSelectOnFocusBehaviour = (selector = '.js-select-on-focus') => { ...@@ -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 = window.gl || {};
window.gl.utils = { window.gl.utils = {
...(window.gl.utils || {}), ...(window.gl.utils || {}),
......
...@@ -15,7 +15,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -15,7 +15,7 @@ document.addEventListener('DOMContentLoaded', () => {
const notesDataset = document.getElementById('js-vue-notes').dataset; const notesDataset = document.getElementById('js-vue-notes').dataset;
const parsedUserData = JSON.parse(notesDataset.currentUserData); const parsedUserData = JSON.parse(notesDataset.currentUserData);
const noteableData = JSON.parse(notesDataset.noteableData); const noteableData = JSON.parse(notesDataset.noteableData);
const { markdownVersion } = notesDataset; const markdownVersion = parseInt(notesDataset.markdownVersion, 10);
let currentUserData = {}; let currentUserData = {};
noteableData.noteableType = notesDataset.noteableType; noteableData.noteableType = notesDataset.noteableType;
......
<script> <script>
import { roundOffFloat } from '~/lib/utils/common_utils';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
...@@ -70,7 +71,7 @@ export default { ...@@ -70,7 +71,7 @@ export default {
}, },
methods: { methods: {
getPercent(count) { getPercent(count) {
return Math.ceil((count / this.totalCount) * 100); return roundOffFloat((count / this.totalCount) * 100, 1);
}, },
barStyle(percent) { barStyle(percent) {
return `width: ${percent}%;`; return `width: ${percent}%;`;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
.status-neutral, .status-neutral,
.status-red, { .status-red, {
height: 100%; height: 100%;
min-width: 30px; min-width: 40px;
padding: 0 5px; padding: 0 5px;
font-size: $tooltip-font-size; font-size: $tooltip-font-size;
font-weight: normal; font-weight: normal;
......
# frozen_string_literal: true
class AnalyticsBuildEntity < Grape::Entity class AnalyticsBuildEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
include EntityDateHelper include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsBuildSerializer < BaseSerializer class AnalyticsBuildSerializer < BaseSerializer
entity AnalyticsBuildEntity entity AnalyticsBuildEntity
end end
# frozen_string_literal: true
class AnalyticsCommitEntity < CommitEntity class AnalyticsCommitEntity < CommitEntity
include EntityDateHelper include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsCommitSerializer < BaseSerializer class AnalyticsCommitSerializer < BaseSerializer
entity AnalyticsCommitEntity entity AnalyticsCommitEntity
end end
# frozen_string_literal: true
class AnalyticsGenericSerializer < BaseSerializer class AnalyticsGenericSerializer < BaseSerializer
def represent(resource, opts = {}) def represent(resource, opts = {})
resource.symbolize_keys! resource.symbolize_keys!
......
# frozen_string_literal: true
class AnalyticsIssueEntity < Grape::Entity class AnalyticsIssueEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
include EntityDateHelper include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsIssueSerializer < AnalyticsGenericSerializer class AnalyticsIssueSerializer < AnalyticsGenericSerializer
entity AnalyticsIssueEntity entity AnalyticsIssueEntity
end end
# frozen_string_literal: true
class AnalyticsMergeRequestEntity < AnalyticsIssueEntity class AnalyticsMergeRequestEntity < AnalyticsIssueEntity
expose :state expose :state
......
# frozen_string_literal: true
class AnalyticsMergeRequestSerializer < AnalyticsGenericSerializer class AnalyticsMergeRequestSerializer < AnalyticsGenericSerializer
entity AnalyticsMergeRequestEntity entity AnalyticsMergeRequestEntity
end end
# frozen_string_literal: true
class AnalyticsStageEntity < Grape::Entity class AnalyticsStageEntity < Grape::Entity
include EntityDateHelper include EntityDateHelper
......
# frozen_string_literal: true
class AnalyticsStageSerializer < BaseSerializer class AnalyticsStageSerializer < BaseSerializer
entity AnalyticsStageEntity entity AnalyticsStageEntity
end end
# frozen_string_literal: true
class AnalyticsSummaryEntity < Grape::Entity class AnalyticsSummaryEntity < Grape::Entity
expose :value, safe: true expose :value, safe: true
expose :title expose :title
......
# frozen_string_literal: true
class AnalyticsSummarySerializer < BaseSerializer class AnalyticsSummarySerializer < BaseSerializer
entity AnalyticsSummaryEntity entity AnalyticsSummaryEntity
end end
# frozen_string_literal: true
class AwardEmojiEntity < Grape::Entity class AwardEmojiEntity < Grape::Entity
expose :name expose :name
expose :user, using: API::Entities::UserSafe expose :user, using: API::Entities::UserSafe
......
# frozen_string_literal: true
class BaseSerializer class BaseSerializer
attr_reader :params attr_reader :params
......
# frozen_string_literal: true
class BlobEntity < Grape::Entity class BlobEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class BuildActionEntity < Grape::Entity class BuildActionEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class BuildArtifactEntity < Grape::Entity class BuildArtifactEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class BuildDetailsEntity < JobEntity class BuildDetailsEntity < JobEntity
expose :coverage, :erased_at, :duration expose :coverage, :erased_at, :duration
expose :tag_list, as: :tags expose :tag_list, as: :tags
......
# frozen_string_literal: true
class BuildMetadataEntity < Grape::Entity class BuildMetadataEntity < Grape::Entity
expose :timeout_human_readable expose :timeout_human_readable
expose :timeout_source do |metadata| expose :timeout_source do |metadata|
......
# frozen_string_literal: true
class BuildSerializer < BaseSerializer class BuildSerializer < BaseSerializer
entity JobEntity entity JobEntity
......
# frozen_string_literal: true
class ClusterApplicationEntity < Grape::Entity class ClusterApplicationEntity < Grape::Entity
expose :name expose :name
expose :status_name, as: :status expose :status_name, as: :status
......
# frozen_string_literal: true
class ClusterEntity < Grape::Entity class ClusterEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class ClusterSerializer < BaseSerializer class ClusterSerializer < BaseSerializer
entity ClusterEntity entity ClusterEntity
......
# frozen_string_literal: true
class CohortActivityMonthEntity < Grape::Entity class CohortActivityMonthEntity < Grape::Entity
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
......
# frozen_string_literal: true
class CohortEntity < Grape::Entity class CohortEntity < Grape::Entity
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
......
# frozen_string_literal: true
class CohortsEntity < Grape::Entity class CohortsEntity < Grape::Entity
expose :months_included expose :months_included
expose :cohorts, using: CohortEntity expose :cohorts, using: CohortEntity
......
# frozen_string_literal: true
class CohortsSerializer < AnalyticsGenericSerializer class CohortsSerializer < AnalyticsGenericSerializer
entity CohortsEntity entity CohortsEntity
end end
# frozen_string_literal: true
class CommitEntity < API::Entities::Commit class CommitEntity < API::Entities::Commit
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
module WithPagination module WithPagination
attr_accessor :paginator attr_accessor :paginator
......
# frozen_string_literal: true
class ContainerRepositoriesSerializer < BaseSerializer class ContainerRepositoriesSerializer < BaseSerializer
entity ContainerRepositoryEntity entity ContainerRepositoryEntity
end end
# frozen_string_literal: true
class ContainerRepositoryEntity < Grape::Entity class ContainerRepositoryEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class ContainerTagEntity < Grape::Entity class ContainerTagEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class ContainerTagsSerializer < BaseSerializer class ContainerTagsSerializer < BaseSerializer
entity ContainerTagEntity entity ContainerTagEntity
......
# frozen_string_literal: true
class DeployKeyEntity < Grape::Entity class DeployKeyEntity < Grape::Entity
expose :id expose :id
expose :user_id expose :user_id
......
# frozen_string_literal: true
class DeployKeySerializer < BaseSerializer class DeployKeySerializer < BaseSerializer
entity DeployKeyEntity entity DeployKeyEntity
end end
# frozen_string_literal: true
class DeployKeysProjectEntity < Grape::Entity class DeployKeysProjectEntity < Grape::Entity
expose :can_push expose :can_push
expose :project, using: ProjectEntity expose :project, using: ProjectEntity
......
# frozen_string_literal: true
class DeploymentEntity < Grape::Entity class DeploymentEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class DeploymentSerializer < BaseSerializer class DeploymentSerializer < BaseSerializer
entity DeploymentEntity entity DeploymentEntity
......
# frozen_string_literal: true
class DiffFileEntity < Grape::Entity class DiffFileEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
include BlobHelper include BlobHelper
......
# frozen_string_literal: true
class DiffsEntity < Grape::Entity class DiffsEntity < Grape::Entity
include DiffHelper include DiffHelper
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class DiffsSerializer < BaseSerializer class DiffsSerializer < BaseSerializer
entity DiffsEntity entity DiffsEntity
end end
# frozen_string_literal: true
class DiscussionEntity < Grape::Entity class DiscussionEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
include NotesHelper include NotesHelper
......
# frozen_string_literal: true
class DiscussionSerializer < BaseSerializer class DiscussionSerializer < BaseSerializer
entity DiscussionEntity entity DiscussionEntity
end end
# frozen_string_literal: true
module EntityDateHelper module EntityDateHelper
include ActionView::Helpers::DateHelper include ActionView::Helpers::DateHelper
include ActionView::Helpers::TagHelper include ActionView::Helpers::TagHelper
...@@ -50,15 +52,20 @@ module EntityDateHelper ...@@ -50,15 +52,20 @@ module EntityDateHelper
elsif entity.due_date elsif entity.due_date
is_upcoming = (entity.due_date - Date.today).to_i > 0 is_upcoming = (entity.due_date - Date.today).to_i > 0
time_ago = time_ago_in_words(entity.due_date) time_ago = time_ago_in_words(entity.due_date)
content = time_ago.gsub(/\d+/) { |match| "<strong>#{match}</strong>" }
content.slice!("about ") # https://gitlab.com/gitlab-org/gitlab-ce/issues/49440
content << " " + (is_upcoming ? _("remaining") : _("ago")) #
content.html_safe # 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? elsif entity.start_date && entity.start_date.past?
days = entity.elapsed_days days = entity.elapsed_days
content = content_tag(:strong, days) "#{content_tag(:strong, days)} #{'day'.pluralize(days)} elapsed".html_safe
content << " #{'day'.pluralize(days)} elapsed"
content.html_safe
end end
end end
end end
# frozen_string_literal: true
class EntityRequest class EntityRequest
# We use EntityRequest object to collect parameters and variables # We use EntityRequest object to collect parameters and variables
# from the controller. Because options that are being passed to the entity # from the controller. Because options that are being passed to the entity
......
# frozen_string_literal: true
class EnvironmentEntity < Grape::Entity class EnvironmentEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class EnvironmentSerializer < BaseSerializer class EnvironmentSerializer < BaseSerializer
include WithPagination include WithPagination
......
# frozen_string_literal: true
class GroupChildEntity < Grape::Entity class GroupChildEntity < Grape::Entity
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class GroupChildSerializer < BaseSerializer class GroupChildSerializer < BaseSerializer
include WithPagination include WithPagination
......
# frozen_string_literal: true
class GroupEntity < Grape::Entity class GroupEntity < Grape::Entity
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class GroupSerializer < BaseSerializer class GroupSerializer < BaseSerializer
include WithPagination include WithPagination
......
# frozen_string_literal: true
class GroupVariableEntity < Grape::Entity class GroupVariableEntity < Grape::Entity
expose :id expose :id
expose :key expose :key
......
# frozen_string_literal: true
class GroupVariableSerializer < BaseSerializer class GroupVariableSerializer < BaseSerializer
entity GroupVariableEntity entity GroupVariableEntity
end end
# frozen_string_literal: true
class IssuableEntity < Grape::Entity class IssuableEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class IssuableSidebarEntity < Grape::Entity class IssuableSidebarEntity < Grape::Entity
include TimeTrackableEntity include TimeTrackableEntity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class IssueEntity < IssuableEntity class IssueEntity < IssuableEntity
include TimeTrackableEntity include TimeTrackableEntity
......
# frozen_string_literal: true
class IssueSerializer < BaseSerializer class IssueSerializer < BaseSerializer
# This overrided method takes care of which entity should be used # This overrided method takes care of which entity should be used
# to serialize the `issue` based on `basic` key in `opts` param. # to serialize the `issue` based on `basic` key in `opts` param.
......
# frozen_string_literal: true
class IssueSidebarEntity < IssuableSidebarEntity class IssueSidebarEntity < IssuableSidebarEntity
prepend ::EE::IssueSidebarEntity prepend ::EE::IssueSidebarEntity
......
# frozen_string_literal: true
class JobEntity < Grape::Entity class JobEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class JobGroupEntity < Grape::Entity class JobGroupEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class LabelEntity < Grape::Entity class LabelEntity < Grape::Entity
expose :id, if: ->(label, _) { !label.is_a?(GlobalLabel) } expose :id, if: ->(label, _) { !label.is_a?(GlobalLabel) }
......
# frozen_string_literal: true
class LabelSerializer < BaseSerializer class LabelSerializer < BaseSerializer
entity LabelEntity entity LabelEntity
......
# frozen_string_literal: true
class LfsFileLockEntity < Grape::Entity class LfsFileLockEntity < Grape::Entity
root 'locks', 'lock' root 'locks', 'lock'
......
# frozen_string_literal: true
class LfsFileLockSerializer < BaseSerializer class LfsFileLockSerializer < BaseSerializer
entity LfsFileLockEntity entity LfsFileLockEntity
end end
# frozen_string_literal: true
class MergeRequestBasicEntity < IssuableSidebarEntity class MergeRequestBasicEntity < IssuableSidebarEntity
expose :assignee_id expose :assignee_id
expose :merge_status expose :merge_status
......
# frozen_string_literal: true
class MergeRequestBasicSerializer < BaseSerializer class MergeRequestBasicSerializer < BaseSerializer
entity MergeRequestBasicEntity entity MergeRequestBasicEntity
end end
# frozen_string_literal: true
class MergeRequestCreateEntity < Grape::Entity class MergeRequestCreateEntity < Grape::Entity
expose :iid expose :iid
......
# frozen_string_literal: true
class MergeRequestCreateSerializer < BaseSerializer class MergeRequestCreateSerializer < BaseSerializer
entity MergeRequestCreateEntity entity MergeRequestCreateEntity
end end
# frozen_string_literal: true
class MergeRequestDiffEntity < Grape::Entity class MergeRequestDiffEntity < Grape::Entity
include Gitlab::Routing include Gitlab::Routing
include GitHelper include GitHelper
......
# frozen_string_literal: true
class MergeRequestMetricsEntity < Grape::Entity class MergeRequestMetricsEntity < Grape::Entity
expose :latest_closed_at, as: :closed_at expose :latest_closed_at, as: :closed_at
expose :merged_at expose :merged_at
......
# frozen_string_literal: true
class MergeRequestSerializer < BaseSerializer class MergeRequestSerializer < BaseSerializer
# This overrided method takes care of which entity should be used # This overrided method takes care of which entity should be used
# to serialize the `merge_request` based on `serializer` key in `opts` param. # to serialize the `merge_request` based on `serializer` key in `opts` param.
......
# frozen_string_literal: true
class MergeRequestUserEntity < UserEntity class MergeRequestUserEntity < UserEntity
include RequestAwareEntity include RequestAwareEntity
include BlobHelper include BlobHelper
......
# frozen_string_literal: true
class MergeRequestWidgetEntity < IssuableEntity class MergeRequestWidgetEntity < IssuableEntity
prepend ::EE::MergeRequestWidgetEntity prepend ::EE::MergeRequestWidgetEntity
......
# frozen_string_literal: true
class NoteAttachmentEntity < Grape::Entity class NoteAttachmentEntity < Grape::Entity
expose :url expose :url
expose :filename expose :filename
......
# frozen_string_literal: true
class NoteEntity < API::Entities::Note class NoteEntity < API::Entities::Note
include RequestAwareEntity include RequestAwareEntity
include NotesHelper include NotesHelper
......
# frozen_string_literal: true
class NoteUserEntity < UserEntity class NoteUserEntity < UserEntity
unexpose :web_url unexpose :web_url
end end
# frozen_string_literal: true
class PipelineDetailsEntity < PipelineEntity class PipelineDetailsEntity < PipelineEntity
expose :details do expose :details do
expose :ordered_stages, as: :stages, using: StageEntity expose :ordered_stages, as: :stages, using: StageEntity
......
# frozen_string_literal: true
class PipelineEntity < Grape::Entity class PipelineEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class PipelineSerializer < BaseSerializer class PipelineSerializer < BaseSerializer
include WithPagination include WithPagination
entity PipelineDetailsEntity entity PipelineDetailsEntity
......
# frozen_string_literal: true
class ProjectEntity < Grape::Entity class ProjectEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class ProjectMirrorEntity < Grape::Entity class ProjectMirrorEntity < Grape::Entity
prepend ::EE::ProjectMirrorEntity prepend ::EE::ProjectMirrorEntity
......
# frozen_string_literal: true
class ProjectNoteEntity < NoteEntity class ProjectNoteEntity < NoteEntity
expose :human_access do |note| expose :human_access do |note|
note.project.team.human_max_access(note.author_id) note.project.team.human_max_access(note.author_id)
......
# frozen_string_literal: true
class ProjectNoteSerializer < BaseSerializer class ProjectNoteSerializer < BaseSerializer
entity ProjectNoteEntity entity ProjectNoteEntity
end end
# frozen_string_literal: true
class ProjectSerializer < BaseSerializer class ProjectSerializer < BaseSerializer
entity ProjectEntity entity ProjectEntity
end end
# frozen_string_literal: true
module RequestAwareEntity module RequestAwareEntity
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
# frozen_string_literal: true
class RunnerEntity < Grape::Entity class RunnerEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class StageEntity < Grape::Entity class StageEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class StageSerializer < BaseSerializer class StageSerializer < BaseSerializer
include WithPagination include WithPagination
......
# frozen_string_literal: true
class StatusEntity < Grape::Entity class StatusEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class SubmoduleEntity < Grape::Entity class SubmoduleEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
module TimeTrackableEntity module TimeTrackableEntity
extend ActiveSupport::Concern extend ActiveSupport::Concern
extend Grape extend Grape
......
# frozen_string_literal: true
class TreeEntity < Grape::Entity class TreeEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
# TODO: Inherit from TreeEntity, when `Tree` implements `id` and `name` like `Gitlab::Git::Tree`. # TODO: Inherit from TreeEntity, when `Tree` implements `id` and `name` like `Gitlab::Git::Tree`.
class TreeRootEntity < Grape::Entity class TreeRootEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class TreeSerializer < BaseSerializer class TreeSerializer < BaseSerializer
entity TreeRootEntity entity TreeRootEntity
end end
# frozen_string_literal: true
class UserEntity < API::Entities::UserBasic class UserEntity < API::Entities::UserBasic
include RequestAwareEntity include RequestAwareEntity
......
# frozen_string_literal: true
class UserSerializer < BaseSerializer class UserSerializer < BaseSerializer
entity UserEntity entity UserEntity
end end
# frozen_string_literal: true
class VariableEntity < Grape::Entity class VariableEntity < Grape::Entity
prepend ::EE::VariableEntity prepend ::EE::VariableEntity
......
# frozen_string_literal: true
class VariableSerializer < BaseSerializer class VariableSerializer < BaseSerializer
entity VariableEntity entity VariableEntity
end 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 '../settings'
require_relative '../object_store_settings'
# Default settings # Default settings
Settings['ldap'] ||= Settingslogic.new({}) Settings['ldap'] ||= Settingslogic.new({})
...@@ -196,14 +197,7 @@ Settings.artifacts['storage_path'] = Settings.absolute(Settings.artifacts.values ...@@ -196,14 +197,7 @@ Settings.artifacts['storage_path'] = Settings.absolute(Settings.artifacts.values
# Settings.artifact['path'] is deprecated, use `storage_path` instead # Settings.artifact['path'] is deprecated, use `storage_path` instead
Settings.artifacts['path'] = Settings.artifacts['storage_path'] Settings.artifacts['path'] = Settings.artifacts['storage_path']
Settings.artifacts['max_size'] ||= 100 # in megabytes Settings.artifacts['max_size'] ||= 100 # in megabytes
Settings.artifacts['object_store'] ||= Settingslogic.new({}) Settings.artifacts['object_store'] = ObjectStoreSettings.parse(Settings.artifacts['object_store'])
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!
# #
# Registry # Registry
...@@ -247,14 +241,7 @@ Settings.gitlab['geo_status_timeout'] ||= 10 ...@@ -247,14 +241,7 @@ Settings.gitlab['geo_status_timeout'] ||= 10
Settings['lfs'] ||= Settingslogic.new({}) Settings['lfs'] ||= Settingslogic.new({})
Settings.lfs['enabled'] = true if Settings.lfs['enabled'].nil? 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['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'] = ObjectStoreSettings.parse(Settings.lfs['object_store'])
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!
# #
# Uploads # Uploads
...@@ -262,14 +249,8 @@ Settings.lfs['object_store']['connection']&.deep_stringify_keys! ...@@ -262,14 +249,8 @@ Settings.lfs['object_store']['connection']&.deep_stringify_keys!
Settings['uploads'] ||= Settingslogic.new({}) Settings['uploads'] ||= Settingslogic.new({})
Settings.uploads['storage_path'] = Settings.absolute(Settings.uploads['storage_path'] || 'public') Settings.uploads['storage_path'] = Settings.absolute(Settings.uploads['storage_path'] || 'public')
Settings.uploads['base_dir'] = Settings.uploads['base_dir'] || 'uploads/-/system' Settings.uploads['base_dir'] = Settings.uploads['base_dir'] || 'uploads/-/system'
Settings.uploads['object_store'] ||= Settingslogic.new({}) Settings.uploads['object_store'] = ObjectStoreSettings.parse(Settings.uploads['object_store'])
Settings.uploads['object_store']['enabled'] = false if Settings.uploads['object_store']['enabled'].nil?
Settings.uploads['object_store']['remote_directory'] ||= 'uploads' 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 # 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 @@ ...@@ -11,7 +11,11 @@
# #
# It's strongly recommended that you check this file into your version control system. # 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: 20180718100455) do
=======
ActiveRecord::Schema.define(version: 20180722103201) do
>>>>>>> upstream/master
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
......
...@@ -253,8 +253,12 @@ Parameters: ...@@ -253,8 +253,12 @@ Parameters:
"can_create_project": true, "can_create_project": true,
"two_factor_enabled": true, "two_factor_enabled": true,
"external": false, "external": false,
<<<<<<< HEAD
"private_profile": false, "private_profile": false,
"shared_runners_minutes_limit": 133 "shared_runners_minutes_limit": 133
=======
"private_profile": false
>>>>>>> upstream/master
} }
``` ```
...@@ -294,8 +298,12 @@ Parameters: ...@@ -294,8 +298,12 @@ Parameters:
- `skip_confirmation` (optional) - Skip confirmation - true or false (default) - `skip_confirmation` (optional) - Skip confirmation - true or false (default)
- `external` (optional) - Flags the user as external - true or false(default) - `external` (optional) - Flags the user as external - true or false(default)
- `avatar` (optional) - Image file for user's avatar - `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
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user - `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 ## User modification
...@@ -327,7 +335,11 @@ Parameters: ...@@ -327,7 +335,11 @@ Parameters:
- `external` (optional) - Flags the user as external - true or false(default) - `external` (optional) - Flags the user as external - true or false(default)
- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user - `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user
- `avatar` (optional) - Image file for user's avatar - `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
=======
- `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. 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, Note, at the moment this method does only return a `404` error,
......
...@@ -48,6 +48,7 @@ the following table. ...@@ -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. | | `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). | | `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). | | `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 [2fa]: ../account/two_factor_authentication.md
[api]: ../../api/README.md [api]: ../../api/README.md
......
...@@ -353,8 +353,6 @@ module Gitlab ...@@ -353,8 +353,6 @@ module Gitlab
# offset: 5, # offset: 5,
# after: Time.new(2016, 4, 21, 14, 32, 10) # after: Time.new(2016, 4, 21, 14, 32, 10)
# ) # )
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/446
def log(options) def log(options)
default_options = { default_options = {
limit: 10, limit: 10,
...@@ -1029,8 +1027,8 @@ module Gitlab ...@@ -1029,8 +1027,8 @@ module Gitlab
end end
def clean_stale_repository_files def clean_stale_repository_files
gitaly_migrate(:repository_cleanup, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| wrapped_gitaly_errors do
gitaly_repository_client.cleanup if is_enabled && exists? gitaly_repository_client.cleanup if exists?
end end
rescue Gitlab::Git::CommandError => e # Don't fail if we can't cleanup 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}") Rails.logger.error("Unable to clean repository on storage #{storage} with relative path #{relative_path}: #{e.message}")
......
...@@ -407,7 +407,7 @@ module Gitlab ...@@ -407,7 +407,7 @@ module Gitlab
# The default timeout on all Gitaly calls # The default timeout on all Gitaly calls
def self.default_timeout def self.default_timeout
return 0 if Sidekiq.server? return no_timeout if Sidekiq.server?
timeout(:gitaly_timeout_default) timeout(:gitaly_timeout_default)
end end
...@@ -420,6 +420,10 @@ module Gitlab ...@@ -420,6 +420,10 @@ module Gitlab
timeout(:gitaly_timeout_medium) timeout(:gitaly_timeout_medium)
end end
def self.no_timeout
0
end
def self.timeout(timeout_name) def self.timeout(timeout_name)
Gitlab::CurrentSettings.current_application_settings[timeout_name] Gitlab::CurrentSettings.current_application_settings[timeout_name]
end end
......
...@@ -202,7 +202,7 @@ module Gitlab ...@@ -202,7 +202,7 @@ module Gitlab
save_path, save_path,
:create_bundle, :create_bundle,
Gitaly::CreateBundleRequest, Gitaly::CreateBundleRequest,
GitalyClient.default_timeout GitalyClient.no_timeout
) )
end end
...@@ -220,7 +220,7 @@ module Gitlab ...@@ -220,7 +220,7 @@ module Gitlab
bundle_path, bundle_path,
:create_repository_from_bundle, :create_repository_from_bundle,
Gitaly::CreateRepositoryFromBundleRequest, Gitaly::CreateRepositoryFromBundleRequest,
GitalyClient.default_timeout GitalyClient.no_timeout
) )
end end
...@@ -245,7 +245,7 @@ module Gitlab ...@@ -245,7 +245,7 @@ module Gitlab
:repository_service, :repository_service,
:create_repository_from_snapshot, :create_repository_from_snapshot,
request, request,
timeout: GitalyClient.default_timeout timeout: GitalyClient.no_timeout
) )
end 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', () => { ...@@ -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) => { ...@@ -10,9 +10,9 @@ const createComponent = (config) => {
successLabel: 'Synced', successLabel: 'Synced',
failureLabel: 'Failed', failureLabel: 'Failed',
neutralLabel: 'Out of sync', neutralLabel: 'Out of sync',
successCount: 10, successCount: 25,
failureCount: 5, failureCount: 10,
totalCount: 20, totalCount: 5000,
}, config); }, config);
return mountComponent(Component, defaultConfig); return mountComponent(Component, defaultConfig);
...@@ -32,7 +32,7 @@ describe('StackedProgressBarComponent', () => { ...@@ -32,7 +32,7 @@ describe('StackedProgressBarComponent', () => {
describe('computed', () => { describe('computed', () => {
describe('neutralCount', () => { describe('neutralCount', () => {
it('returns neutralCount based on totalCount, successCount and failureCount', () => { 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', () => { ...@@ -40,7 +40,11 @@ describe('StackedProgressBarComponent', () => {
describe('methods', () => { describe('methods', () => {
describe('getPercent', () => { describe('getPercent', () => {
it('returns percentage from provided count based on `totalCount`', () => { 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 ...@@ -638,6 +638,7 @@ describe API::Users do
expect(user.reload.private_profile).to eq(true) expect(user.reload.private_profile).to eq(true)
end end
<<<<<<< HEAD
# EE # EE
it "updates shared_runners_minutes_limit" do it "updates shared_runners_minutes_limit" do
expect do expect do
...@@ -649,6 +650,8 @@ describe API::Users do ...@@ -649,6 +650,8 @@ describe API::Users do
expect(json_response['shared_runners_minutes_limit']).to eq(133) expect(json_response['shared_runners_minutes_limit']).to eq(133)
end end
=======
>>>>>>> upstream/master
it "does not update admin status" do it "does not update admin status" do
put api("/users/#{admin_user.id}", admin), { can_create_group: false } 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