diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-07 00:10:00 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-07 00:10:00 +0300 |
commit | 5f0e3773e9695fd0c9e92ea9180c8a1f5cfaa5c5 (patch) | |
tree | 64fc0ecbf508a24345ffe11d856fd13124c2e464 /app | |
parent | 73886079f3f877ffb8f8938d700643a5e99bc849 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/integrations/edit/components/integration_form.vue | 42 | ||||
-rw-r--r-- | app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue | 99 | ||||
-rw-r--r-- | app/assets/javascripts/integrations/edit/index.js | 37 | ||||
-rw-r--r-- | app/controllers/admin/application_settings_controller.rb | 2 | ||||
-rw-r--r-- | app/helpers/x509_helper.rb | 4 | ||||
-rw-r--r-- | app/models/application_setting.rb | 2 | ||||
-rw-r--r-- | app/models/merge_request_diff.rb | 8 | ||||
-rw-r--r-- | app/models/project_services/jira_service.rb | 61 | ||||
-rw-r--r-- | app/models/snippet_repository.rb | 18 | ||||
-rw-r--r-- | app/models/x509_commit_signature.rb | 4 | ||||
-rw-r--r-- | app/views/projects/commit/_signature.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/commit/_signature_badge.html.haml | 6 | ||||
-rw-r--r-- | app/views/projects/commit/x509/_signature_badge_user.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/tags/_tag.html.haml | 3 | ||||
-rw-r--r-- | app/views/projects/tags/show.html.haml | 2 | ||||
-rw-r--r-- | app/views/shared/_service_settings.html.haml | 21 |
16 files changed, 268 insertions, 45 deletions
diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue new file mode 100644 index 00000000000..ab6a3f97bfd --- /dev/null +++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue @@ -0,0 +1,42 @@ +<script> +import ActiveToggle from './active_toggle.vue'; +import JiraTriggerFields from './jira_trigger_fields.vue'; + +export default { + name: 'IntegrationForm', + components: { + ActiveToggle, + JiraTriggerFields, + }, + props: { + activeToggleProps: { + type: Object, + required: true, + }, + showActive: { + type: Boolean, + required: true, + }, + triggerFieldsProps: { + type: Object, + required: true, + }, + type: { + type: String, + required: true, + }, + }, + computed: { + isJira() { + return this.type === 'jira'; + }, + }, +}; +</script> + +<template> + <div> + <active-toggle v-if="showActive" v-bind="activeToggleProps" /> + <jira-trigger-fields v-if="isJira" v-bind="triggerFieldsProps" /> + </div> +</template> diff --git a/app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue b/app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue new file mode 100644 index 00000000000..70278e401ce --- /dev/null +++ b/app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue @@ -0,0 +1,99 @@ +<script> +import { GlFormCheckbox, GlFormRadio } from '@gitlab/ui'; + +export default { + name: 'JiraTriggerFields', + components: { + GlFormCheckbox, + GlFormRadio, + }, + props: { + initialTriggerCommit: { + type: Boolean, + required: true, + }, + initialTriggerMergeRequest: { + type: Boolean, + required: true, + }, + initialEnableComments: { + type: Boolean, + required: true, + }, + initialCommentDetail: { + type: String, + required: false, + default: 'standard', + }, + }, + data() { + return { + triggerCommit: this.initialTriggerCommit, + triggerMergeRequest: this.initialTriggerMergeRequest, + enableComments: this.initialEnableComments, + commentDetail: this.initialCommentDetail, + }; + }, +}; +</script> + +<template> + <div class="form-group row pt-2" role="group"> + <label for="service[trigger]" class="col-form-label col-sm-2 pt-0">{{ __('Trigger') }}</label> + <div class="col-sm-10"> + <label class="weight-normal mb-2"> + {{ + s__( + 'Integrations|When a Jira issue is mentioned in a commit or merge request a remote link and comment (if enabled) will be created.', + ) + }} + </label> + + <input name="service[commit_events]" type="hidden" value="false" /> + <gl-form-checkbox v-model="triggerCommit" name="service[commit_events]"> + {{ __('Commit') }} + </gl-form-checkbox> + + <input name="service[merge_requests_events]" type="hidden" value="false" /> + <gl-form-checkbox v-model="triggerMergeRequest" name="service[merge_requests_events]"> + {{ __('Merge request') }} + </gl-form-checkbox> + + <div + v-show="triggerCommit || triggerMergeRequest" + class="mt-4" + data-testid="comment-settings" + > + <label> + {{ s__('Integrations|Comment settings:') }} + </label> + <input name="service[comment_on_event_enabled]" type="hidden" value="false" /> + <gl-form-checkbox v-model="enableComments" name="service[comment_on_event_enabled]"> + {{ s__('Integrations|Enable comments') }} + </gl-form-checkbox> + + <div v-show="enableComments" class="mt-4" data-testid="comment-detail"> + <label> + {{ s__('Integrations|Comment detail:') }} + </label> + <gl-form-radio v-model="commentDetail" value="standard" name="service[comment_detail]"> + {{ s__('Integrations|Standard') }} + <template #help> + {{ s__('Integrations|Includes commit title and branch') }} + </template> + </gl-form-radio> + <gl-form-radio v-model="commentDetail" value="all_details" name="service[comment_detail]"> + {{ s__('Integrations|All details') }} + <template #help> + {{ + s__( + 'Integrations|Includes Standard plus entire commit message, commit hash, and issue IDs', + ) + }} + </template> + </gl-form-radio> + </div> + </div> + </div> + </div> +</template> diff --git a/app/assets/javascripts/integrations/edit/index.js b/app/assets/javascripts/integrations/edit/index.js index 25ae6015f1d..7b476528a33 100644 --- a/app/assets/javascripts/integrations/edit/index.js +++ b/app/assets/javascripts/integrations/edit/index.js @@ -1,26 +1,45 @@ import Vue from 'vue'; import { parseBoolean } from '~/lib/utils/common_utils'; -import ActiveToggle from './components/active_toggle.vue'; +import IntegrationForm from './components/integration_form.vue'; export default el => { if (!el) { return null; } - const { showActive: showActiveStr, activated: activatedStr } = el.dataset; - const showActive = parseBoolean(showActiveStr); - const activated = parseBoolean(activatedStr); - - if (!showActive) { - return null; + function parseBooleanInData(data) { + const result = {}; + Object.entries(data).forEach(([key, value]) => { + result[key] = parseBoolean(value); + }); + return result; } + const { type, commentDetail, ...booleanAttributes } = el.dataset; + const { + showActive, + activated, + commitEvents, + mergeRequestEvents, + enableComments, + } = parseBooleanInData(booleanAttributes); + return new Vue({ el, render(createElement) { - return createElement(ActiveToggle, { + return createElement(IntegrationForm, { props: { - initialActivated: activated, + activeToggleProps: { + initialActivated: activated, + }, + showActive, + type, + triggerFieldsProps: { + initialTriggerCommit: commitEvents, + initialTriggerMergeRequest: mergeRequestEvents, + initialEnableComments: enableComments, + initialCommentDetail: commentDetail, + }, }, }); }, diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 942bb4b6b0e..355662bbb38 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -5,7 +5,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController # NOTE: Use @application_setting in this controller when you need to access # application_settings after it has been modified. This is because the - # ApplicationSetting model uses Gitlab::ThreadMemoryCache for caching and the + # ApplicationSetting model uses Gitlab::ProcessMemoryCache for caching and the # cache might be stale immediately after an update. # https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30233 before_action :set_application_setting, except: :integrations diff --git a/app/helpers/x509_helper.rb b/app/helpers/x509_helper.rb index c330b599d74..009635fb629 100644 --- a/app/helpers/x509_helper.rb +++ b/app/helpers/x509_helper.rb @@ -16,4 +16,8 @@ module X509Helper rescue {} end + + def x509_signature?(sig) + sig.is_a?(X509CommitSignature) || sig.is_a?(Gitlab::X509::Signature) + end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index f9481db2268..d13f0a1a000 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -421,7 +421,7 @@ class ApplicationSetting < ApplicationRecord # can cause a significant amount of load on Redis, let's cache it in # memory. def self.cache_backend - Gitlab::ThreadMemoryCache.cache_backend + Gitlab::ProcessMemoryCache.cache_backend end def recaptcha_or_login_protection_enabled diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 7b15d21c095..ea3e00d9cd3 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -141,7 +141,7 @@ class MergeRequestDiff < ApplicationRecord after_create :save_git_content, unless: :importing? after_create_commit :set_as_latest_diff, unless: :importing? - after_save :update_external_diff_store, if: -> { !importing? && saved_change_to_external_diff? } + after_save :update_external_diff_store def self.find_by_diff_refs(diff_refs) find_by(start_commit_sha: diff_refs.start_sha, head_commit_sha: diff_refs.head_sha, base_commit_sha: diff_refs.base_sha) @@ -401,8 +401,10 @@ class MergeRequestDiff < ApplicationRecord end def update_external_diff_store - update_column(:external_diff_store, external_diff.object_store) if - has_attribute?(:external_diff_store) + return unless has_attribute?(:external_diff_store) + return unless saved_change_to_external_diff? || saved_change_to_stored_externally? + + update_column(:external_diff_store, external_diff.object_store) end def saved_change_to_external_diff? diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index f0a5d8e8cdd..53da874ede8 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -177,6 +177,7 @@ class JiraService < IssueTrackerService noteable_id = noteable.respond_to?(:iid) ? noteable.iid : noteable.id noteable_type = noteable_name(noteable) entity_url = build_entity_url(noteable_type, noteable_id) + entity_meta = build_entity_meta(noteable) data = { user: { @@ -185,12 +186,15 @@ class JiraService < IssueTrackerService }, project: { name: project.full_path, - url: resource_url(namespace_project_path(project.namespace, project)) # rubocop:disable Cop/ProjectPathHelper + url: resource_url(project_path(project)) }, entity: { + id: entity_meta[:id], name: noteable_type.humanize.downcase, url: entity_url, - title: noteable.title + title: noteable.title, + description: entity_meta[:description], + branch: entity_meta[:branch] } } @@ -264,14 +268,11 @@ class JiraService < IssueTrackerService end def add_comment(data, issue) - user_name = data[:user][:name] - user_url = data[:user][:url] entity_name = data[:entity][:name] entity_url = data[:entity][:url] entity_title = data[:entity][:title] - project_name = data[:project][:name] - message = "[#{user_name}|#{user_url}] mentioned this issue in [a #{entity_name} of #{project_name}|#{entity_url}]:\n'#{entity_title.chomp}'" + message = comment_message(data) link_title = "#{entity_name.capitalize} - #{entity_title}" link_props = build_remote_link_props(url: entity_url, title: link_title) @@ -280,6 +281,37 @@ class JiraService < IssueTrackerService end end + def comment_message(data) + user_link = build_jira_link(data[:user][:name], data[:user][:url]) + + entity = data[:entity] + entity_ref = all_details? ? "#{entity[:name]} #{entity[:id]}" : "a #{entity[:name]}" + entity_link = build_jira_link(entity_ref, entity[:url]) + + project_link = build_jira_link(project.full_name, Gitlab::Routing.url_helpers.project_url(project)) + branch = + if entity[:branch].present? + s_('JiraService| on branch %{branch_link}') % { + branch_link: build_jira_link(entity[:branch], project_tree_url(project, entity[:branch])) + } + end + + entity_message = entity[:description].presence if all_details? + entity_message ||= entity[:title].chomp + + s_('JiraService|%{user_link} mentioned this issue in %{entity_link} of %{project_link}%{branch}:{quote}%{entity_message}{quote}') % { + user_link: user_link, + entity_link: entity_link, + project_link: project_link, + branch: branch, + entity_message: entity_message + } + end + + def build_jira_link(title, url) + "[#{title}|#{url}]" + end + def has_resolution?(issue) issue.respond_to?(:resolution) && issue.resolution.present? end @@ -353,6 +385,23 @@ class JiraService < IssueTrackerService ) end + def build_entity_meta(noteable) + if noteable.is_a?(Commit) + { + id: noteable.short_id, + description: noteable.safe_message, + branch: noteable.ref_names(project.repository).first + } + elsif noteable.is_a?(MergeRequest) + { + id: noteable.to_reference, + branch: noteable.source_branch + } + else + {} + end + end + def noteable_name(noteable) name = noteable.model_name.singular diff --git a/app/models/snippet_repository.rb b/app/models/snippet_repository.rb index e60dbb4d141..1e7c069cfaa 100644 --- a/app/models/snippet_repository.rb +++ b/app/models/snippet_repository.rb @@ -7,6 +7,7 @@ class SnippetRepository < ApplicationRecord EMPTY_FILE_PATTERN = /^#{DEFAULT_EMPTY_FILE_NAME}(\d+)\.txt$/.freeze CommitError = Class.new(StandardError) + InvalidPathError = Class.new(CommitError) belongs_to :snippet, inverse_of: :snippet_repository @@ -40,8 +41,9 @@ class SnippetRepository < ApplicationRecord rescue Gitlab::Git::Index::IndexError, Gitlab::Git::CommitError, Gitlab::Git::PreReceiveError, - Gitlab::Git::CommandError => e - raise CommitError, e.message + Gitlab::Git::CommandError => error + + raise commit_error_exception(error) end def transform_file_entries(files) @@ -85,4 +87,16 @@ class SnippetRepository < ApplicationRecord def build_empty_file_name(index) "#{DEFAULT_EMPTY_FILE_NAME}#{index}.txt" end + + def commit_error_exception(error) + if error.is_a?(Gitlab::Git::Index::IndexError) && invalid_path_error?(error.message) + InvalidPathError.new('Invalid Path') # To avoid returning the message with the path included + else + CommitError.new(error.message) + end + end + + def invalid_path_error?(message) + message.downcase.start_with?('invalid path', 'path cannot include directory traversal') + end end diff --git a/app/models/x509_commit_signature.rb b/app/models/x509_commit_signature.rb index ed7c638cecc..57d809f7cfb 100644 --- a/app/models/x509_commit_signature.rb +++ b/app/models/x509_commit_signature.rb @@ -41,4 +41,8 @@ class X509CommitSignature < ApplicationRecord Gitlab::X509::Commit.new(commit) end + + def user + commit.committer + end end diff --git a/app/views/projects/commit/_signature.html.haml b/app/views/projects/commit/_signature.html.haml index aa7c90bad66..fb31ac44118 100644 --- a/app/views/projects/commit/_signature.html.haml +++ b/app/views/projects/commit/_signature.html.haml @@ -1,3 +1,3 @@ - if signature - - uri = "projects/commit/#{"x509/" if signature.instance_of?(X509CommitSignature)}" + - uri = "projects/commit/#{"x509/" if x509_signature?(signature)}" = render partial: "#{uri}#{signature.verification_status}_signature_badge", locals: { signature: signature } diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml index 8ecaa1329fd..8004a5facd7 100644 --- a/app/views/projects/commit/_signature_badge.html.haml +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -17,13 +17,13 @@ - content = capture do - if show_user .clearfix - - uri_signature_badge_user = "projects/commit/#{"x509/" if signature.instance_of?(X509CommitSignature)}signature_badge_user" + - uri_signature_badge_user = "projects/commit/#{"x509/" if x509_signature?(signature)}signature_badge_user" = render partial: "#{uri_signature_badge_user}", locals: { signature: signature } - - if signature.instance_of?(X509CommitSignature) + - if x509_signature?(signature) = render partial: "projects/commit/x509/certificate_details", locals: { signature: signature } - = link_to(_('Learn more about x509 signed commits'), help_page_path('user/project/repository/x509_signed_commits/index.md'), class: 'gpg-popover-help-link') + = link_to(_('Learn more about X.509 signed commits'), help_page_path('user/project/repository/x509_signed_commits/index.md'), class: 'gpg-popover-help-link') - else = _('GPG Key ID:') %span.monospace= signature.gpg_key_primary_keyid diff --git a/app/views/projects/commit/x509/_signature_badge_user.html.haml b/app/views/projects/commit/x509/_signature_badge_user.html.haml index b64ccba2a18..f3d39b21ec2 100644 --- a/app/views/projects/commit/x509/_signature_badge_user.html.haml +++ b/app/views/projects/commit/x509/_signature_badge_user.html.haml @@ -1,5 +1,5 @@ -- user = signature.commit.committer - user_email = signature.x509_certificate.email +- user = signature.user - if user = link_to user_path(user), class: 'gpg-popover-user-link' do diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml index 75805192a61..da693a15ec2 100644 --- a/app/views/projects/tags/_tag.html.haml +++ b/app/views/projects/tags/_tag.html.haml @@ -30,6 +30,9 @@ = markdown_field(release, :description) .row-fixed-content.controls.flex-row + - if tag.has_signature? + = render partial: 'projects/commit/signature', object: tag.signature + = render 'projects/buttons/download', project: @project, ref: tag.name, pipeline: @tags_pipelines[tag.name] - if can?(current_user, :admin_tag, @project) diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index 8086d47479d..6f53a687fb9 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -39,6 +39,8 @@ = s_("TagsPage|Can't find HEAD commit for this tag") .nav-controls + - if @tag.has_signature? + = render partial: 'projects/commit/signature', object: @tag.signature - if can?(current_user, :admin_tag, @project) = link_to edit_project_tag_release_path(@project, @tag.name), class: 'btn btn-edit controls-item has-tooltip', title: s_('TagsPage|Edit release notes') do = icon("pencil") diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml index 7262c47f9d3..cb298459dc7 100644 --- a/app/views/shared/_service_settings.html.haml +++ b/app/views/shared/_service_settings.html.haml @@ -8,9 +8,10 @@ = markdown @service.help .service-settings - .js-vue-integration-settings{ data: { show_active: @service.show_active_box?.to_s, activated: (@service.active || @service.new_record?).to_s } } + .js-vue-integration-settings{ data: { show_active: @service.show_active_box?.to_s, activated: (@service.active || @service.new_record?).to_s, type: @service.to_param, merge_request_events: @service.merge_requests_events.to_s, +commit_events: @service.commit_events.to_s, enable_comments: @service.comment_on_event_enabled.to_s, comment_detail: @service.comment_detail } } - - if @service.configurable_events.present? + - if @service.configurable_events.present? && !@service.is_a?(JiraService) .form-group.row %label.col-form-label.col-sm-2= _('Trigger') @@ -31,22 +32,6 @@ %p.text-muted = @service.class.event_description(event) - - if @service.configurable_event_actions.present? - .form-group.row - %label.col-form-label.col-sm-2= _('Event Actions') - - .col-sm-10 - - @service.configurable_event_actions.each do |action| - .form-group - .form-check - = form.check_box service_event_action_field_name(action), class: 'form-check-input' - = form.label service_event_action_field_name(action), class: 'form-check-label' do - %strong - = event_action_description(action) - - %p.text-muted - = event_action_description(action) - - @service.global_fields.each do |field| - type = field[:type] |