diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-17 18:07:44 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-17 18:07:44 +0300 |
commit | 6c41e447edac3453ae0df99fb9232ec71b679b75 (patch) | |
tree | 125416ba49222f7c0deb44950e451e39d45c433b /app | |
parent | 77ee26b43bda4b092f356d5185f424bad232af36 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
15 files changed, 222 insertions, 58 deletions
diff --git a/app/assets/javascripts/reports/codequality_report/constants.js b/app/assets/javascripts/reports/codequality_report/constants.js index 502977e714c..0c472b24471 100644 --- a/app/assets/javascripts/reports/codequality_report/constants.js +++ b/app/assets/javascripts/reports/codequality_report/constants.js @@ -15,3 +15,17 @@ export const SEVERITY_ICONS = { blocker: 'severity-critical', unknown: 'severity-unknown', }; + +// This is the icons mapping for the code Quality Merge-Request Widget Extension +// once the refactor_mr_widgets_extensions flag is activated the above SEVERITY_ICONS +// need be removed and this variable needs to be rename to SEVERITY_ICONS +// Rollout Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/341759 + +export const SEVERITY_ICONS_EXTENSION = { + info: 'severityInfo', + minor: 'severityLow', + major: 'severityMedium', + critical: 'severityHigh', + blocker: 'severityCritical', + unknown: 'severityUnknown', +}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue index 1621b6831a2..7435f578852 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue @@ -82,17 +82,8 @@ export default { return this.mr.shouldBeRebased; }, - sourceBranchProtected() { - if (this.glFeatures.mergeRequestWidgetGraphql) { - return this.stateData.sourceBranchProtected; - } - - return this.mr.sourceBranchProtected; - }, showResolveButton() { - return ( - this.mr.conflictResolutionPath && this.canPushToSourceBranch && !this.sourceBranchProtected - ); + return this.mr.conflictResolutionPath && this.canPushToSourceBranch; }, }, }; diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js new file mode 100644 index 00000000000..d32db50874c --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js @@ -0,0 +1,123 @@ +import { n__, s__, sprintf } from '~/locale'; +import axios from '~/lib/utils/axios_utils'; +import { EXTENSION_ICONS } from '~/vue_merge_request_widget/constants'; +import { SEVERITY_ICONS_EXTENSION } from '~/reports/codequality_report/constants'; +import { parseCodeclimateMetrics } from '~/reports/codequality_report/store/utils/codequality_parser'; +import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; + +export default { + name: 'WidgetCodeQuality', + props: ['codeQuality', 'blobPath'], + i18n: { + label: s__('ciReport|Code Quality'), + loading: s__('ciReport|Code Quality test metrics results are being parsed'), + error: s__('ciReport|Code Quality failed loading results'), + }, + expandEvent: 'i_testing_code_quality_widget_total', + computed: { + summary() { + const { newErrors, resolvedErrors, errorSummary } = this.collapsedData; + if (errorSummary.errored >= 1 && errorSummary.resolved >= 1) { + const improvements = sprintf( + n__( + '%{strongOpen}%{errors}%{strongClose} point', + '%{strongOpen}%{errors}%{strongClose} points', + resolvedErrors.length, + ), + { + errors: resolvedErrors.length, + strongOpen: '<strong>', + strongClose: '</strong>', + }, + false, + ); + + const degradations = sprintf( + n__( + '%{strongOpen}%{errors}%{strongClose} point', + '%{strongOpen}%{errors}%{strongClose} points', + newErrors.length, + ), + { errors: newErrors.length, strongOpen: '<strong>', strongClose: '</strong>' }, + false, + ); + return sprintf( + s__(`ciReport|Code Quality improved on ${improvements} and degraded on ${degradations}.`), + ); + } else if (errorSummary.resolved >= 1) { + const improvements = n__('%d point', '%d points', resolvedErrors.length); + return sprintf(s__(`ciReport|Code Quality improved on ${improvements}.`)); + } else if (errorSummary.errored >= 1) { + const degradations = n__('%d point', '%d points', newErrors.length); + return sprintf(s__(`ciReport|Code Quality degraded on ${degradations}.`)); + } + return s__(`ciReport|No changes to Code Quality.`); + }, + statusIcon() { + if (this.collapsedData.errorSummary?.errored >= 1) { + return EXTENSION_ICONS.warning; + } + return EXTENSION_ICONS.success; + }, + }, + methods: { + fetchCollapsedData() { + return Promise.all([this.fetchReport(this.codeQuality)]).then((values) => { + return { + resolvedErrors: parseCodeclimateMetrics( + values[0].resolved_errors, + this.blobPath.head_path, + ), + newErrors: parseCodeclimateMetrics(values[0].new_errors, this.blobPath.head_path), + existingErrors: parseCodeclimateMetrics( + values[0].existing_errors, + this.blobPath.head_path, + ), + errorSummary: values[0].summary, + }; + }); + }, + fetchFullData() { + const fullData = []; + + this.collapsedData.newErrors.map((e) => { + return fullData.push({ + text: `${capitalizeFirstCharacter(e.severity)} - ${e.description}`, + subtext: sprintf( + s__(`ciReport|in %{open_link}${e.file_path}:${e.line}%{close_link}`), + { + open_link: `<a class="gl-text-decoration-underline" href="${e.urlPath}">`, + close_link: '</a>', + }, + false, + ), + icon: { + name: SEVERITY_ICONS_EXTENSION[e.severity], + }, + }); + }); + + this.collapsedData.resolvedErrors.map((e) => { + return fullData.push({ + text: `${capitalizeFirstCharacter(e.severity)} - ${e.description}`, + subtext: sprintf( + s__(`ciReport|in %{open_link}${e.file_path}:${e.line}%{close_link}`), + { + open_link: `<a class="gl-text-decoration-underline" href="${e.urlPath}">`, + close_link: '</a>', + }, + false, + ), + icon: { + name: SEVERITY_ICONS_EXTENSION[e.severity], + }, + }); + }); + + return Promise.resolve(fullData); + }, + fetchReport(endpoint) { + return axios.get(endpoint).then((res) => res.data); + }, + }, +}; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index cd4d9398899..965746e79fb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -46,6 +46,7 @@ import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variab import getStateQuery from './queries/get_state.query.graphql'; import terraformExtension from './extensions/terraform'; import accessibilityExtension from './extensions/accessibility'; +import codeQualityExtension from './extensions/code_quality'; export default { // False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25 @@ -241,6 +242,11 @@ export default { this.registerTerraformPlans(); } }, + shouldRenderCodeQuality(newVal) { + if (newVal) { + this.registerCodeQualityExtension(); + } + }, shouldShowAccessibilityReport(newVal) { if (newVal) { this.registerAccessibilityExtension(); @@ -491,6 +497,11 @@ export default { registerExtension(accessibilityExtension); } }, + registerCodeQualityExtension() { + if (this.shouldRenderCodeQuality && this.shouldShowExtension) { + registerExtension(codeQualityExtension); + } + }, }, }; </script> @@ -546,7 +557,7 @@ export default { </div> <extensions-container :mr="mr" /> <grouped-codequality-reports-app - v-if="shouldRenderCodeQuality" + v-if="shouldRenderCodeQuality && !shouldShowExtension" :head-blob-path="mr.headBlobPath" :base-blob-path="mr.baseBlobPath" :codequality-reports-path="mr.codequalityReportsPath" diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index 994e0c23b44..eb07609d5d6 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -32,9 +32,15 @@ export default class MergeRequestStore { this.setPaths(data); this.setData(data); + this.initCodeQualityReport(data); this.setGitpodData(data); } + initCodeQualityReport(data) { + this.blobPath = data.blob_path; + this.codeQuality = data.codequality_reports_path; + } + setData(data, isRebased) { this.initApprovals(); diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb new file mode 100644 index 00000000000..03296d6b233 --- /dev/null +++ b/app/controllers/concerns/product_analytics_tracking.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module ProductAnalyticsTracking + include Gitlab::Tracking::Helpers + include RedisTracking + extend ActiveSupport::Concern + + class_methods do + def track_event(*controller_actions, name:, conditions: nil, destinations: [:redis_hll], &block) + custom_conditions = [:trackable_html_request?, *conditions] + + after_action only: controller_actions, if: custom_conditions do + route_events_to(destinations, name, &block) + end + end + end + + private + + def route_events_to(destinations, name, &block) + track_unique_redis_hll_event(name, &block) if destinations.include?(:redis_hll) + + if destinations.include?(:snowplow) && Feature.enabled?(:route_hll_to_snowplow, tracking_namespace_source, default_enabled: :yaml) + Gitlab::Tracking.event(self.class.to_s, name, namespace: tracking_namespace_source, user: current_user) + end + end +end diff --git a/app/controllers/jira_connect/events_controller.rb b/app/controllers/jira_connect/events_controller.rb index 1ea0a92662b..327192857f6 100644 --- a/app/controllers/jira_connect/events_controller.rb +++ b/app/controllers/jira_connect/events_controller.rb @@ -7,11 +7,13 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController before_action :verify_asymmetric_atlassian_jwt! def installed - return head :ok if current_jira_installation + unless Feature.enabled?(:jira_connect_installation_update, default_enabled: :yaml) + return head :ok if current_jira_installation + end - installation = JiraConnectInstallation.new(event_params) + success = current_jira_installation ? update_installation : create_installation - if installation.save + if success head :ok else head :unprocessable_entity @@ -28,8 +30,24 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController private - def event_params - params.permit(:clientKey, :sharedSecret, :baseUrl).transform_keys(&:underscore) + def create_installation + JiraConnectInstallation.new(create_params).save + end + + def update_installation + current_jira_installation.update(update_params) + end + + def create_params + transformed_params.permit(:client_key, :shared_secret, :base_url) + end + + def update_params + transformed_params.permit(:shared_secret, :base_url) + end + + def transformed_params + @transformed_params ||= params.transform_keys(&:underscore) end def verify_asymmetric_atlassian_jwt! @@ -43,7 +61,7 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController def jwt_verification_claims { aud: jira_connect_base_url(protocol: 'https'), - iss: event_params[:client_key], + iss: transformed_params[:client_key], qsh: Atlassian::Jwt.create_query_string_hash(request.url, request.method, jira_connect_base_url) } end diff --git a/app/models/project.rb b/app/models/project.rb index 3ca719101d2..155ebe88d33 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -498,7 +498,10 @@ class Project < ApplicationRecord presence: true, project_path: true, length: { maximum: 255 } - validate :container_registry_project_path_validation + validates :path, + format: { with: Gitlab::Regex.oci_repository_path_regex, + message: Gitlab::Regex.oci_repository_path_regex_message }, + if: :path_changed? validates :project_feature, presence: true @@ -889,14 +892,6 @@ class Project < ApplicationRecord super end - def container_registry_project_path_validation - if Feature.enabled?(:restrict_special_characters_in_project_path, self, default_enabled: :yaml) && - path_changed? && - !path.match?(Gitlab::Regex.oci_repository_path_regex) - errors.add(:path, Gitlab::Regex.oci_repository_path_regex_message) - end - end - def parent_loaded? association(:namespace).loaded? end diff --git a/app/models/user.rb b/app/models/user.rb index 2905db7ce6c..b3bdc2c1c42 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -291,21 +291,7 @@ class User < ApplicationRecord end end after_commit(on: :update) do - if previous_changes.key?('email') - # Add the old primary email to Emails if not added already - this should be removed - # after the background migration for MR https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70872/ has completed, - # as the primary email is now added to Emails upon confirmation - # Issue to remove that: https://gitlab.com/gitlab-org/gitlab/-/issues/344134 - previous_confirmed_at = previous_changes.key?('confirmed_at') ? previous_changes['confirmed_at'][0] : confirmed_at - previous_email = previous_changes[:email][0] - if previous_confirmed_at && !emails.exists?(email: previous_email) - # rubocop: disable CodeReuse/ServiceClass - Emails::CreateService.new(self, user: self, email: previous_email).execute(confirmed_at: previous_confirmed_at) - # rubocop: enable CodeReuse/ServiceClass - end - - update_invalid_gpg_signatures - end + update_invalid_gpg_signatures if previous_changes.key?('email') end after_initialize :set_projects_limit diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml index 91a018121c0..0c3ce1f3fa4 100644 --- a/app/views/admin/groups/_form.html.haml +++ b/app/views/admin/groups/_form.html.haml @@ -27,12 +27,9 @@ - if @group.new_record? .form-group.row .offset-sm-2.col-sm-10 - .gl-alert.gl-alert- - .gl-alert-container - = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') - .gl-alert-content - .gl-alert-body - = render 'shared/group_tips' + = render 'shared/global_alert', dismissible: false do + .gl-alert-body + = render 'shared/group_tips' .form-actions = f.submit _('Create group'), class: "gl-button btn btn-confirm" = link_to _('Cancel'), admin_groups_path, class: "gl-button btn btn-default btn-cancel" diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index cd177db3ed0..1d711f366c4 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -2,6 +2,7 @@ - page_title _("To-Do List") - header_title _("To-Do List"), dashboard_todos_path += render_two_factor_auth_recovery_settings_check = render_dashboard_ultimate_trial(current_user) - add_page_specific_style 'page_bundles/todos' diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 133083f1103..a656b61dc8f 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -14,7 +14,6 @@ = dispensable_render "layouts/nav/classification_level_banner" = yield :flash_message = dispensable_render "shared/service_ping_consent" - = render_two_factor_auth_recovery_settings_check = dispensable_render_if_exists "layouts/header/ee_subscribable_banner" = dispensable_render_if_exists "layouts/header/seats_count_alert" = dispensable_render_if_exists "shared/namespace_storage_limit_alert" diff --git a/app/views/projects/_deletion_failed.html.haml b/app/views/projects/_deletion_failed.html.haml index 21c799f5bb6..b713b805009 100644 --- a/app/views/projects/_deletion_failed.html.haml +++ b/app/views/projects/_deletion_failed.html.haml @@ -1,10 +1,7 @@ - project = local_assigns.fetch(:project) - return unless project.delete_error.present? -.project-deletion-failed-message.gl-alert.gl-alert-warning - .gl-alert-container - = sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') - .gl-alert-content - .gl-alert-body - This project was scheduled for deletion, but failed with the following message: - = project.delete_error += render 'shared/global_alert', variant: :warning, dismissible: false, alert_class: 'project-deletion-failed-message' do + .gl-alert-body + This project was scheduled for deletion, but failed with the following message: + = project.delete_error diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index 2d0a4ae8605..1fb045544aa 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -35,8 +35,7 @@ - link_start_group_path = '<a href="%{path}">' % { path: new_group_path } - project_tip = s_('ProjectsNew|Want to house several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}') % { link_start: link_start_group_path, link_end: '</a>' } = project_tip.html_safe -.gl-alert.gl-alert-success.gl-mb-4.gl-display-none.js-user-readme-repo - = sprite_icon('check-circle', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') += render 'shared/global_alert', alert_class: "gl-mb-4 gl-display-none js-user-readme-repo", dismissible: false, variant: :success do .gl-alert-body - help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/profile/index', anchor: 'add-details-to-your-profile-with-a-readme') } = html_escape(_('%{project_path} is a project that you can use to add a README to your GitLab profile. Create a public project and initialize the repository with a README to get started. %{help_link_start}Learn more.%{help_link_end}')) % { project_path: "<strong>#{current_user.username} / #{current_user.username}</strong>".html_safe, help_link_start: help_link_start, help_link_end: '</a>'.html_safe } diff --git a/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml b/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml index e7239661313..f21acd26ada 100644 --- a/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml +++ b/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml @@ -1,6 +1,6 @@ = render 'shared/global_alert', variant: :warning, - alert_class: 'js-recovery-settings-callout', + alert_class: 'js-recovery-settings-callout gl-mt-5', alert_data: { feature_id: Users::CalloutsHelper::TWO_FACTOR_AUTH_RECOVERY_SETTINGS_CHECK, dismiss_endpoint: callouts_path, defer_links: 'true' }, close_button_data: { testid: 'close-account-recovery-regular-check-callout' } do .gl-alert-body |