diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-24 18:09:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-24 18:09:51 +0300 |
commit | a17eb314cff10a779ef550b1eb203ec9a61afdb9 (patch) | |
tree | a0dca3d550ff6d4bafb25093277861ed3ba47c88 /app | |
parent | 6f15c2c2723dbe14e907379b75201e2ef70a48d3 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
20 files changed, 160 insertions, 25 deletions
diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/jobs/store/utils.js index 8d6e5aac566..ea9c214de32 100644 --- a/app/assets/javascripts/jobs/store/utils.js +++ b/app/assets/javascripts/jobs/store/utils.js @@ -1,3 +1,5 @@ +import { parseBoolean } from '../../lib/utils/common_utils'; + /** * Adds the line number property * @param Object line @@ -17,7 +19,7 @@ export const parseLine = (line = {}, lineNumber) => ({ * @param Number lineNumber */ export const parseHeaderLine = (line = {}, lineNumber) => ({ - isClosed: false, + isClosed: parseBoolean(line.section_options?.collapsed), isHeader: true, line: parseLine(line, lineNumber), lines: [], diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue index e237db2cc6f..422d8bf630d 100644 --- a/app/assets/javascripts/releases/components/app_index.vue +++ b/app/assets/javascripts/releases/components/app_index.vue @@ -1,25 +1,21 @@ <script> import { mapState, mapActions } from 'vuex'; -import { - GlDeprecatedSkeletonLoading as GlSkeletonLoading, - GlEmptyState, - GlLink, - GlButton, -} from '@gitlab/ui'; +import { GlEmptyState, GlLink, GlButton } from '@gitlab/ui'; import { getParameterByName } from '~/lib/utils/common_utils'; import { __ } from '~/locale'; import ReleaseBlock from './release_block.vue'; import ReleasesPagination from './releases_pagination.vue'; +import ReleaseSkeletonLoader from './release_skeleton_loader.vue'; export default { name: 'ReleasesApp', components: { - GlSkeletonLoading, GlEmptyState, - ReleaseBlock, - ReleasesPagination, GlLink, GlButton, + ReleaseBlock, + ReleasesPagination, + ReleaseSkeletonLoader, }, computed: { ...mapState('list', [ @@ -77,7 +73,7 @@ export default { {{ __('New release') }} </gl-button> - <gl-skeleton-loading v-if="isLoading" class="js-loading" /> + <release-skeleton-loader v-if="isLoading" class="js-loading" /> <gl-empty-state v-else-if="shouldRenderEmptyState" diff --git a/app/assets/javascripts/releases/components/app_show.vue b/app/assets/javascripts/releases/components/app_show.vue index 8b89f0cf3fc..9ef38503c10 100644 --- a/app/assets/javascripts/releases/components/app_show.vue +++ b/app/assets/javascripts/releases/components/app_show.vue @@ -1,13 +1,13 @@ <script> import { mapState, mapActions } from 'vuex'; -import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; import ReleaseBlock from './release_block.vue'; +import ReleaseSkeletonLoader from './release_skeleton_loader.vue'; export default { name: 'ReleaseShowApp', components: { - GlSkeletonLoading, ReleaseBlock, + ReleaseSkeletonLoader, }, computed: { ...mapState('detail', ['isFetchingRelease', 'fetchError', 'release']), @@ -22,7 +22,7 @@ export default { </script> <template> <div class="gl-mt-3"> - <gl-skeleton-loading v-if="isFetchingRelease" /> + <release-skeleton-loader v-if="isFetchingRelease" /> <release-block v-else-if="!fetchError" :release="release" /> </div> diff --git a/app/assets/javascripts/releases/components/release_skeleton_loader.vue b/app/assets/javascripts/releases/components/release_skeleton_loader.vue new file mode 100644 index 00000000000..054620af636 --- /dev/null +++ b/app/assets/javascripts/releases/components/release_skeleton_loader.vue @@ -0,0 +1,51 @@ +<script> +import { GlSkeletonLoader } from '@gitlab/ui'; + +export default { + name: 'ReleaseSkeletonLoader', + components: { GlSkeletonLoader }, +}; +</script> +<template> + <gl-skeleton-loader :width="1248" :height="420"> + <!-- Outside border --> + <path + d="M 4.5 0 C 2.0156486 0 0 2.0156486 0 4.5 L 0 415.5 C 0 417.98435 2.0156486 420 4.5 420 L 1243.5 420 C 1245.9844 420 1248 417.98435 1248 415.5 L 1248 4.5 C 1248 2.0156486 1245.9844 0 1243.5 0 L 4.5 0 z M 4.5 1 L 1243.5 1 C 1245.4476 1 1247 2.5523514 1247 4.5 L 1247 415.5 C 1247 417.44765 1245.4476 419 1243.5 419 L 4.5 419 C 2.5523514 419 1 417.44765 1 415.5 L 1 4.5 C 1 2.5523514 2.5523514 1 4.5 1 z " + /> + + <!-- Header bottom border --> + <rect x="0" y="63.5" width="1248" height="1" /> + + <!-- Release title --> + <rect x="16" y="20" width="293" height="24" /> + + <!-- Edit (pencil) button --> + <rect x="1207" y="16" rx="4" width="32" height="32" /> + + <!-- Asset link 1 --> + <rect x="40" y="121" rx="4" width="16" height="16" /> + <rect x="60" y="125" width="116" height="8" /> + + <!-- Asset link 2 --> + <rect x="40" y="145" rx="4" width="16" height="16" /> + <rect x="60" y="149" width="132" height="8" /> + + <!-- Asset link 3 --> + <rect x="40" y="169" rx="4" width="16" height="16" /> + <rect x="60" y="173" width="140" height="8" /> + + <!-- Asset link 4 --> + <rect x="40" y="193" rx="4" width="16" height="16" /> + <rect x="60" y="197" width="112" height="8" /> + + <!-- Release notes --> + <rect x="16" y="228" width="480" height="8" /> + <rect x="16" y="252" width="560" height="8" /> + <rect x="16" y="276" width="480" height="8" /> + <rect x="16" y="300" width="560" height="8" /> + <rect x="16" y="324" width="320" height="8" /> + + <!-- Footer top border --> + <rect x="0" y="373" width="1248" height="1" /> + </gl-skeleton-loader> +</template> diff --git a/app/assets/javascripts/releases/stores/modules/detail/actions.js b/app/assets/javascripts/releases/stores/modules/detail/actions.js index 5b682a0ab0f..2f298faf37e 100644 --- a/app/assets/javascripts/releases/stores/modules/detail/actions.js +++ b/app/assets/javascripts/releases/stores/modules/detail/actions.js @@ -45,6 +45,9 @@ export const updateReleaseNotes = ({ commit }, notes) => commit(types.UPDATE_REL export const updateReleaseMilestones = ({ commit }, milestones) => commit(types.UPDATE_RELEASE_MILESTONES, milestones); +export const updateReleaseGroupMilestones = ({ commit }, groupMilestones) => + commit(types.UPDATE_RELEASE_GROUP_MILESTONES, groupMilestones); + export const addEmptyAssetLink = ({ commit }) => { commit(types.ADD_EMPTY_ASSET_LINK); }; diff --git a/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js b/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js index 7784e0cc741..1b2f5f33f02 100644 --- a/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js +++ b/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js @@ -9,6 +9,7 @@ export const UPDATE_CREATE_FROM = 'UPDATE_CREATE_FROM'; export const UPDATE_RELEASE_TITLE = 'UPDATE_RELEASE_TITLE'; export const UPDATE_RELEASE_NOTES = 'UPDATE_RELEASE_NOTES'; export const UPDATE_RELEASE_MILESTONES = 'UPDATE_RELEASE_MILESTONES'; +export const UPDATE_RELEASE_GROUP_MILESTONES = 'UPDATE_RELEASE_GROUP_MILESTONES'; export const REQUEST_SAVE_RELEASE = 'REQUEST_SAVE_RELEASE'; export const RECEIVE_SAVE_RELEASE_SUCCESS = 'RECEIVE_SAVE_RELEASE_SUCCESS'; diff --git a/app/assets/javascripts/releases/stores/modules/detail/mutations.js b/app/assets/javascripts/releases/stores/modules/detail/mutations.js index 750f496665d..58a1958c5e2 100644 --- a/app/assets/javascripts/releases/stores/modules/detail/mutations.js +++ b/app/assets/javascripts/releases/stores/modules/detail/mutations.js @@ -13,6 +13,7 @@ export default { name: '', description: '', milestones: [], + groupMilestones: [], assets: { links: [], }, @@ -51,6 +52,10 @@ export default { state.release.milestones = milestones; }, + [types.UPDATE_RELEASE_GROUP_MILESTONES](state, groupMilestones) { + state.release.groupMilestones = groupMilestones; + }, + [types.REQUEST_SAVE_RELEASE](state) { state.isUpdatingRelease = true; }, diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb index 0c0bbaf4d93..e0bee6f48ea 100644 --- a/app/controllers/admin/sessions_controller.rb +++ b/app/controllers/admin/sessions_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Admin::SessionsController < ApplicationController - include Authenticates2FAForAdminMode + include AuthenticatesWithTwoFactorForAdminMode include InternalRedirect include RendersLdapServers diff --git a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb index 03783cd75a3..b7d2ce1eeb0 100644 --- a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb +++ b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Authenticates2FAForAdminMode +module AuthenticatesWithTwoFactorForAdminMode extend ActiveSupport::Concern included do diff --git a/app/controllers/concerns/enforces_two_factor_authentication.rb b/app/controllers/concerns/enforces_two_factor_authentication.rb index 02082f81598..bf38e4ad117 100644 --- a/app/controllers/concerns/enforces_two_factor_authentication.rb +++ b/app/controllers/concerns/enforces_two_factor_authentication.rb @@ -11,7 +11,7 @@ module EnforcesTwoFactorAuthentication extend ActiveSupport::Concern included do - before_action :check_two_factor_requirement + before_action :check_two_factor_requirement, except: [:route_not_found] # to include this in controllers inheriting from `ActionController::Metal` # we need to add this block diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index b798d6680bc..2708e6669e7 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -1,8 +1,7 @@ # frozen_string_literal: true class OmniauthCallbacksController < Devise::OmniauthCallbacksController - include AuthenticatesWithTwoFactor - include Authenticates2FAForAdminMode + include AuthenticatesWithTwoFactorForAdminMode include Devise::Controllers::Rememberable include AuthHelper include InitializesCurrentUserMode diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 0b092d2622b..9510734bc9b 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -19,6 +19,7 @@ class UploadsController < ApplicationController rescue_from UnknownUploadModelError, with: :render_404 skip_before_action :authenticate_user! + skip_before_action :check_two_factor_requirement, only: [:show] before_action :upload_mount_satisfied? before_action :authorize_access!, only: [:show] before_action :authorize_create_access!, only: [:create, :authorize] diff --git a/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb index 13c67442c2e..b9f7f616e13 100644 --- a/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb +++ b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb @@ -14,6 +14,10 @@ module Types value 'MERGE_REQUESTS', 'Merge request count', value: :merge_requests value 'GROUPS', 'Group count', value: :groups value 'PIPELINES', 'Pipeline count', value: :pipelines + value 'PIPELINES_SUCCEEDED', 'Pipeline count with success status', value: :pipelines_succeeded + value 'PIPELINES_FAILED', 'Pipeline count with failed status', value: :pipelines_failed + value 'PIPELINES_CANCELED', 'Pipeline count with canceled status', value: :pipelines_canceled + value 'PIPELINES_SKIPPED', 'Pipeline count with skipped status', value: :pipelines_skipped end end end diff --git a/app/models/analytics/instance_statistics/measurement.rb b/app/models/analytics/instance_statistics/measurement.rb index eaaf9e999b3..c724cdf22a5 100644 --- a/app/models/analytics/instance_statistics/measurement.rb +++ b/app/models/analytics/instance_statistics/measurement.rb @@ -3,13 +3,19 @@ module Analytics module InstanceStatistics class Measurement < ApplicationRecord + EXPERIMENTAL_IDENTIFIERS = %i[pipelines_succeeded pipelines_failed pipelines_canceled pipelines_skipped].freeze + enum identifier: { projects: 1, users: 2, issues: 3, merge_requests: 4, groups: 5, - pipelines: 6 + pipelines: 6, + pipelines_succeeded: 7, + pipelines_failed: 8, + pipelines_canceled: 9, + pipelines_skipped: 10 } IDENTIFIER_QUERY_MAPPING = { @@ -18,7 +24,11 @@ module Analytics identifiers[:issues] => -> { Issue }, identifiers[:merge_requests] => -> { MergeRequest }, identifiers[:groups] => -> { Group }, - identifiers[:pipelines] => -> { Ci::Pipeline } + identifiers[:pipelines] => -> { Ci::Pipeline }, + identifiers[:pipelines_succeeded] => -> { Ci::Pipeline.success }, + identifiers[:pipelines_failed] => -> { Ci::Pipeline.failed }, + identifiers[:pipelines_canceled] => -> { Ci::Pipeline.canceled }, + identifiers[:pipelines_skipped] => -> { Ci::Pipeline.skipped } }.freeze validates :recorded_at, :identifier, :count, presence: true @@ -26,6 +36,14 @@ module Analytics scope :order_by_latest, -> { order(recorded_at: :desc) } scope :with_identifier, -> (identifier) { where(identifier: identifier) } + + def self.measurement_identifier_values + if Feature.enabled?(:store_ci_pipeline_counts_by_status) + identifiers.values + else + identifiers.values - EXPERIMENTAL_IDENTIFIERS.map { |identifier| identifiers[identifier] } + end + end end end end diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb index 628103f25d3..0f171f90634 100644 --- a/app/models/audit_event.rb +++ b/app/models/audit_event.rb @@ -22,6 +22,7 @@ class AuditEvent < ApplicationRecord validates :author_id, presence: true validates :entity_id, presence: true validates :entity_type, presence: true + validates :ip_address, ip_address: true scope :by_entity_type, -> (entity_type) { where(entity_type: entity_type) } scope :by_entity_id, -> (entity_id) { where(entity_id: entity_id) } diff --git a/app/models/authentication_event.rb b/app/models/authentication_event.rb index 16b132c7ed5..ac6e08caf50 100644 --- a/app/models/authentication_event.rb +++ b/app/models/authentication_event.rb @@ -6,6 +6,7 @@ class AuthenticationEvent < ApplicationRecord belongs_to :user, optional: true validates :provider, :user_name, :result, presence: true + validates :ip_address, ip_address: true enum result: { failed: 0, diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb index 9802f48ae7e..3c21844ec62 100644 --- a/app/services/audit_event_service.rb +++ b/app/services/audit_event_service.rb @@ -108,13 +108,25 @@ class AuditEventService def log_security_event_to_database return if Gitlab::Database.read_only? - AuditEvent.create(base_payload.merge(details: @details)) + event = AuditEvent.new(base_payload.merge(details: @details)) + save_or_track event + + event end def log_authentication_event_to_database return unless Gitlab::Database.read_write? && authentication_event? - AuthenticationEvent.create(authentication_event_payload) + event = AuthenticationEvent.new(authentication_event_payload) + save_or_track event + + event + end + + def save_or_track(event) + event.save! + rescue => e + Gitlab::ErrorTracking.track_exception(e, audit_event_type: event.class.to_s) end end diff --git a/app/validators/ip_address_validator.rb b/app/validators/ip_address_validator.rb new file mode 100644 index 00000000000..0acf2bdf4fc --- /dev/null +++ b/app/validators/ip_address_validator.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# IpAddressValidator +# +# Validates that an IP address is a valid IPv4 or IPv6 address. +# This should be coupled with a database column of type `inet` +# +# When using column type `inet` Rails will silently return the value +# as `nil` when the value is not valid according to its type cast +# using `IpAddr`. It's not very user friendly to return an error +# "IP Address can't be blank" when a value was clearly given but +# was not the right format. This validator will look at the value +# before Rails type casts it when the value itself is `nil`. +# This enables the validator to return a specific and useful error message. +# +# This validator allows `nil` values by default since the database +# allows null values by default. To disallow `nil` values, use in conjunction +# with `presence: true`. +# +# Do not use this validator with `allow_nil: true` or `allow_blank: true`. +# Because of Rails type casting, when an invalid value is set the attribute +# will return `nil` and Rails won't run this validator. +# +# Example: +# +# class Group < ActiveRecord::Base +# validates :ip_address, presence: true, ip_address: true +# end +# +class IpAddressValidator < ActiveModel::EachValidator + def validate_each(record, attribute, _) + value = record.public_send("#{attribute}_before_type_cast") # rubocop:disable GitlabSecurity/PublicSend + return if value.blank? + + IPAddress.parse(value.to_s) + rescue ArgumentError + record.errors.add(attribute, _('must be a valid IPv4 or IPv6 address')) + end +end diff --git a/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb b/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb index a9976c6e5cb..01bddfea7de 100644 --- a/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb +++ b/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb @@ -17,10 +17,9 @@ module Analytics return if Feature.disabled?(:store_instance_statistics_measurements, default_enabled: true) recorded_at = Time.zone.now - measurement_identifiers = Analytics::InstanceStatistics::Measurement.identifiers worker_arguments = Gitlab::Analytics::InstanceStatistics::WorkersArgumentBuilder.new( - measurement_identifiers: measurement_identifiers.values, + measurement_identifiers: ::Analytics::InstanceStatistics::Measurement.measurement_identifier_values, recorded_at: recorded_at ).execute diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb index b0307571448..97db116bfb4 100644 --- a/app/workers/git_garbage_collect_worker.rb +++ b/app/workers/git_garbage_collect_worker.rb @@ -95,6 +95,9 @@ class GitGarbageCollectWorker # rubocop:disable Scalability/IdempotentWorker return if Gitlab::Database.read_only? # GitGarbageCollectWorker may be run on a Geo secondary ::Gitlab::Cleanup::OrphanLfsFileReferences.new(project, dry_run: false, logger: logger).run! + rescue => err + Gitlab::GitLogger.warn(message: "Cleaning up orphan LFS objects files failed", error: err.message) + Gitlab::ErrorTracking.track_and_raise_for_dev_exception(err) end def flush_ref_caches(project) |