...@@ -112,9 +112,7 @@ export default { ...@@ -112,9 +112,7 @@ export default {
const truncatedContentSha = _.escape(truncateSha(this.diffFile.content_sha)); const truncatedContentSha = _.escape(truncateSha(this.diffFile.content_sha));
return sprintf( return sprintf(
s__('MergeRequests|View file @ %{commitId}'), s__('MergeRequests|View file @ %{commitId}'),
{ { commitId: truncatedContentSha },
commitId: `<span class="commit-sha">${truncatedContentSha}</span>`,
},
false, false,
); );
}, },
... ...
......
<script>
import { GlLink } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { WARNING, DANGER, WARNING_MESSAGE_CLASS, DANGER_MESSAGE_CLASS } from '../constants';
export default {
name: 'MrWidgetAlertMessage',
components: {
GlLink,
Icon,
},
props: {
type: {
type: String,
required: false,
default: DANGER,
validator: value => [WARNING, DANGER].includes(value),
},
helpPath: {
type: String,
required: false,
default: undefined,
},
},
computed: {
messageClass() {
if (this.type === WARNING) {
return WARNING_MESSAGE_CLASS;
} else if (this.type === DANGER) {
return DANGER_MESSAGE_CLASS;
}
return '';
},
},
};
</script>
<template>
<div class="m-3 ml-5" :class="messageClass">
<slot></slot>
<gl-link v-if="helpPath" :href="helpPath" target="_blank">
<icon :size="16" name="question-o" class="align-middle" />
</gl-link>
</div>
</template>
export const WARNING = 'warning';
export const DANGER = 'danger';
export const WARNING_MESSAGE_CLASS = 'warning_message';
export const DANGER_MESSAGE_CLASS = 'danger_message';
...@@ -12,6 +12,7 @@ import WidgetMergeHelp from './components/mr_widget_merge_help.vue'; ...@@ -12,6 +12,7 @@ import WidgetMergeHelp from './components/mr_widget_merge_help.vue';
import MrWidgetPipelineContainer from './components/mr_widget_pipeline_container.vue'; import MrWidgetPipelineContainer from './components/mr_widget_pipeline_container.vue';
import Deployment from './components/deployment.vue'; import Deployment from './components/deployment.vue';
import WidgetRelatedLinks from './components/mr_widget_related_links.vue'; import WidgetRelatedLinks from './components/mr_widget_related_links.vue';
import MrWidgetAlertMessage from './components/mr_widget_alert_message.vue';
import MergedState from './components/states/mr_widget_merged.vue'; import MergedState from './components/states/mr_widget_merged.vue';
import ClosedState from './components/states/mr_widget_closed.vue'; import ClosedState from './components/states/mr_widget_closed.vue';
import MergingState from './components/states/mr_widget_merging.vue'; import MergingState from './components/states/mr_widget_merging.vue';
...@@ -46,6 +47,7 @@ export default { ...@@ -46,6 +47,7 @@ export default {
MrWidgetPipelineContainer, MrWidgetPipelineContainer,
Deployment, Deployment,
'mr-widget-related-links': WidgetRelatedLinks, 'mr-widget-related-links': WidgetRelatedLinks,
MrWidgetAlertMessage,
'mr-widget-merged': MergedState, 'mr-widget-merged': MergedState,
'mr-widget-closed': ClosedState, 'mr-widget-closed': ClosedState,
'mr-widget-merging': MergingState, 'mr-widget-merging': MergingState,
...@@ -110,6 +112,18 @@ export default { ...@@ -110,6 +112,18 @@ export default {
shouldRenderMergedPipeline() { shouldRenderMergedPipeline() {
return this.mr.state === 'merged' && !_.isEmpty(this.mr.mergePipeline); return this.mr.state === 'merged' && !_.isEmpty(this.mr.mergePipeline);
}, },
showMergePipelineForkWarning() {
return Boolean(
this.mr.mergePipelinesEnabled && this.mr.sourceProjectId !== this.mr.targetProjectId,
);
},
showTargetBranchAdvancedError() {
return Boolean(
this.mr.pipeline &&
this.mr.pipeline.target_sha &&
this.mr.pipeline.target_sha !== this.mr.targetBranchSha,
);
},
}, },
watch: { watch: {
state(newVal, oldVal) { state(newVal, oldVal) {
...@@ -328,6 +342,30 @@ export default { ...@@ -328,6 +342,30 @@ export default {
:related-links="mr.relatedLinks" :related-links="mr.relatedLinks"
/> />
<mr-widget-alert-message
v-if="showMergePipelineForkWarning"
type="warning"
:help-path="mr.mergeRequestPipelinesHelpPath"
>
{{
s__(
'mrWidget|Fork merge requests do not create merge request pipelines which validate a post merge result',
)
}}
</mr-widget-alert-message>
<mr-widget-alert-message
v-if="showTargetBranchAdvancedError"
type="danger"
:help-path="mr.mergeRequestPipelinesHelpPath"
>
{{
s__(
'mrWidget|The target branch has advanced, which invalidates the merge request pipeline. Please update the source branch and retry merging',
)
}}
</mr-widget-alert-message>
<source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" /> <source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" />
</div> </div>
<div v-if="shouldRenderMergeHelp" class="mr-widget-footer"><mr-widget-merge-help /></div> <div v-if="shouldRenderMergeHelp" class="mr-widget-footer"><mr-widget-merge-help /></div>
... ...
......
...@@ -28,9 +28,11 @@ export default class MergeRequestStore { ...@@ -28,9 +28,11 @@ export default class MergeRequestStore {
this.iid = data.iid; this.iid = data.iid;
this.title = data.title; this.title = data.title;
this.targetBranch = data.target_branch; this.targetBranch = data.target_branch;
this.targetBranchSha = data.target_branch_sha;
this.sourceBranch = data.source_branch; this.sourceBranch = data.source_branch;
this.sourceBranchProtected = data.source_branch_protected; this.sourceBranchProtected = data.source_branch_protected;
this.conflictsDocsPath = data.conflicts_docs_path; this.conflictsDocsPath = data.conflicts_docs_path;
this.mergeRequestPipelinesHelpPath = data.merge_request_pipelines_docs_path;
this.mergeStatus = data.merge_status; this.mergeStatus = data.merge_status;
this.commitMessage = data.default_merge_commit_message; this.commitMessage = data.default_merge_commit_message;
this.shortMergeCommitSha = data.short_merge_commit_sha; this.shortMergeCommitSha = data.short_merge_commit_sha;
...@@ -99,6 +101,9 @@ export default class MergeRequestStore { ...@@ -99,6 +101,9 @@ export default class MergeRequestStore {
this.allowCollaboration = data.allow_collaboration; this.allowCollaboration = data.allow_collaboration;
this.targetProjectFullPath = data.target_project_full_path; this.targetProjectFullPath = data.target_project_full_path;
this.sourceProjectFullPath = data.source_project_full_path; this.sourceProjectFullPath = data.source_project_full_path;
this.sourceProjectId = data.source_project_id;
this.targetProjectId = data.target_project_id;
this.mergePipelinesEnabled = data.merge_pipelines_enabled;
// Cherry-pick and Revert actions related // Cherry-pick and Revert actions related
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false; this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
... ...
......
...@@ -205,12 +205,12 @@ li.note { ...@@ -205,12 +205,12 @@ li.note {
} }
} }
.warning_message { @mixin message($background-color, $border-color, $text-color) {
border-left: 4px solid $orange-200; border-left: 4px solid $border-color;
color: $orange-700; color: $text-color;
padding: 10px; padding: 10px;
margin-bottom: 10px; margin-bottom: 10px;
background: $orange-100; background: $background-color;
padding-left: 20px; padding-left: 20px;
&.centered { &.centered {
...@@ -218,6 +218,14 @@ li.note { ...@@ -218,6 +218,14 @@ li.note {
} }
} }
.warning_message {
@include message($orange-100, $orange-200, $orange-700);
}
.danger_message {
@include message($red-100, $red-200, $red-900);
}
.gitlab-promo { .gitlab-promo {
a { a {
color: $gl-gray-350; color: $gl-gray-350;
... ...
......
...@@ -112,6 +112,10 @@ ...@@ -112,6 +112,10 @@
} }
.scoped-label-wrapper { .scoped-label-wrapper {
> a {
max-width: 100%;
}
.color-label { .color-label {
padding-right: $gl-padding-24; padding-right: $gl-padding-24;
} }
... ...
......
...@@ -408,12 +408,21 @@ ...@@ -408,12 +408,21 @@
} }
.scoped-label-wrapper { .scoped-label-wrapper {
max-width: 100%;
vertical-align: top;
.badge {
text-overflow: ellipsis;
overflow-x: hidden;
}
&.label-link .color-label a { &.label-link .color-label a {
color: inherit; color: inherit;
} }
.color-label { .color-label {
padding-right: $gl-padding-24; padding-right: $gl-padding-24;
max-width: 100%;
} }
.scoped-label { .scoped-label {
...@@ -438,3 +447,13 @@ ...@@ -438,3 +447,13 @@
} }
} }
} }
// Don't hide the overflow in system messages
.system-note-message,
.issuable-detail {
.scoped-label-wrapper {
.badge {
overflow: initial;
}
}
}
...@@ -98,20 +98,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -98,20 +98,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end end
def test_reports def test_reports
result = @merge_request.compare_test_reports reports_response(@merge_request.compare_test_reports)
case result[:status]
when :parsing
Gitlab::PollingInterval.set_header(response, interval: 3000)
render json: '', status: :no_content
when :parsed
render json: result[:data].to_json, status: :ok
when :error
render json: { status_reason: result[:status_reason] }, status: :bad_request
else
render json: { status_reason: 'Unknown error' }, status: :internal_server_error
end
end end
def edit def edit
...@@ -353,4 +340,19 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -353,4 +340,19 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
# Also see https://gitlab.com/gitlab-org/gitlab-ce/issues/42441 # Also see https://gitlab.com/gitlab-org/gitlab-ce/issues/42441
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42438') Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42438')
end end
def reports_response(report_comparison)
case report_comparison[:status]
when :parsing
::Gitlab::PollingInterval.set_header(response, interval: 3000)
render json: '', status: :no_content
when :parsed
render json: report_comparison[:data].to_json, status: :ok
when :error
render json: { status_reason: report_comparison[:status_reason] }, status: :bad_request
else
render json: { status_reason: 'Unknown error' }, status: :internal_server_error
end
end
end end
...@@ -89,7 +89,7 @@ module LabelsHelper ...@@ -89,7 +89,7 @@ module LabelsHelper
def render_colored_label(label, label_suffix: '', tooltip: true, title: nil) def render_colored_label(label, label_suffix: '', tooltip: true, title: nil)
text_color = text_color_for_bg(label.color) text_color = text_color_for_bg(label.color)
title ||= tooltip ? label_tooltip_title(label) : '' title ||= tooltip ? label_tooltip_title(label) : label.name
# Intentionally not using content_tag here so that this method can be called # Intentionally not using content_tag here so that this method can be called
# by LabelReferenceFilter # by LabelReferenceFilter
... ...
......
...@@ -104,8 +104,8 @@ module Ci ...@@ -104,8 +104,8 @@ module Ci
where('NOT EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace) where('NOT EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace)
end end
scope :with_test_reports, ->() do scope :with_reports, ->(reports_scope) do
with_existing_job_artifacts(Ci::JobArtifact.test_reports) with_existing_job_artifacts(reports_scope)
.eager_load_job_artifacts .eager_load_job_artifacts
end end
... ...
......
...@@ -21,7 +21,8 @@ module Ci ...@@ -21,7 +21,8 @@ module Ci
container_scanning: 'gl-container-scanning-report.json', container_scanning: 'gl-container-scanning-report.json',
dast: 'gl-dast-report.json', dast: 'gl-dast-report.json',
license_management: 'gl-license-management-report.json', license_management: 'gl-license-management-report.json',
performance: 'performance.json' performance: 'performance.json',
metrics: 'metrics.txt'
}.freeze }.freeze
TYPE_AND_FORMAT_PAIRS = { TYPE_AND_FORMAT_PAIRS = {
...@@ -29,6 +30,7 @@ module Ci ...@@ -29,6 +30,7 @@ module Ci
metadata: :gzip, metadata: :gzip,
trace: :raw, trace: :raw,
junit: :gzip, junit: :gzip,
metrics: :gzip,
# All these file formats use `raw` as we need to store them uncompressed # All these file formats use `raw` as we need to store them uncompressed
# for Frontend to fetch the files and do analysis # for Frontend to fetch the files and do analysis
...@@ -88,7 +90,8 @@ module Ci ...@@ -88,7 +90,8 @@ module Ci
dast: 8, ## EE-specific dast: 8, ## EE-specific
codequality: 9, ## EE-specific codequality: 9, ## EE-specific
license_management: 10, ## EE-specific license_management: 10, ## EE-specific
performance: 11 ## EE-specific performance: 11, ## EE-specific
metrics: 12 ## EE-specific
} }
enum file_format: { enum file_format: {
... ...
......
...@@ -210,6 +210,10 @@ module Ci ...@@ -210,6 +210,10 @@ module Ci
where(source: branch_pipeline_sources).where(ref: ref, tag: false) where(source: branch_pipeline_sources).where(ref: ref, tag: false)
end end
scope :with_reports, -> (reports_scope) do
where('EXISTS (?)', ::Ci::Build.latest.with_reports(reports_scope).where('ci_pipelines.id=ci_builds.commit_id').select(1))
end
# Returns the pipelines in descending order (= newest first), optionally # Returns the pipelines in descending order (= newest first), optionally
# limited to a number of references. # limited to a number of references.
# #
...@@ -689,13 +693,13 @@ module Ci ...@@ -689,13 +693,13 @@ module Ci
@latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a @latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a
end end
def has_test_reports? def has_reports?(reports_scope)
complete? && builds.latest.with_test_reports.any? complete? && builds.latest.with_reports(reports_scope).exists?
end end
def test_reports def test_reports
Gitlab::Ci::Reports::TestReports.new.tap do |test_reports| Gitlab::Ci::Reports::TestReports.new.tap do |test_reports|
builds.latest.with_test_reports.each do |build| builds.latest.with_reports(Ci::JobArtifact.test_reports).each do |build|
build.collect_test_reports!(test_reports) build.collect_test_reports!(test_reports)
end end
end end
... ...
......
...@@ -1195,7 +1195,7 @@ class MergeRequest < ApplicationRecord ...@@ -1195,7 +1195,7 @@ class MergeRequest < ApplicationRecord
end end
def has_test_reports? def has_test_reports?
actual_head_pipeline&.has_test_reports? actual_head_pipeline&.has_reports?(Ci::JobArtifact.test_reports)
end end
def predefined_variables def predefined_variables
... ...
......
...@@ -209,6 +209,10 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated ...@@ -209,6 +209,10 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
help_page_path('user/project/merge_requests/resolve_conflicts.md') help_page_path('user/project/merge_requests/resolve_conflicts.md')
end end
def merge_request_pipelines_docs_path
help_page_path('ci/merge_request_pipelines/index.md')
end
private private
def cached_can_be_reverted? def cached_can_be_reverted?
... ...
......
...@@ -256,6 +256,10 @@ class MergeRequestWidgetEntity < IssuableEntity ...@@ -256,6 +256,10 @@ class MergeRequestWidgetEntity < IssuableEntity
presenter(merge_request).conflicts_docs_path presenter(merge_request).conflicts_docs_path
end end
expose :merge_request_pipelines_docs_path do |merge_request|
presenter(merge_request).merge_request_pipelines_docs_path
end
private private
delegate :current_user, to: :request delegate :current_user, to: :request
... ...
......
...@@ -11,9 +11,11 @@ module Ci ...@@ -11,9 +11,11 @@ module Ci
def execute def execute
prerequisites.each(&:complete!) prerequisites.each(&:complete!)
unless build.enqueue build.enqueue!
build.drop!(:unmet_prerequisites) rescue => e
end Gitlab::Sentry.track_acceptable_exception(e, extra: { build_id: build.id })
build.drop(:unmet_prerequisites)
end end
private private
... ...
......
...@@ -16,7 +16,7 @@ module MergeRequests ...@@ -16,7 +16,7 @@ module MergeRequests
params.delete(:force_remove_source_branch) params.delete(:force_remove_source_branch)
end end
if params[:force_remove_source_branch].present? if params.has_key?(:force_remove_source_branch)
merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch) merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch)
end end
... ...
......
---
title: Add two new warning messages to the MR widget about merge request pipelines
merge_request: 25983
author:
type: added
---
title: Fix remove_source_branch merge request API handling
merge_request: 27392
author:
type: fixed