Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-17 15:09:20 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-17 15:09:20 +0300
commitb84eeb256c4a780d902faee1f99ca9a711b3214a (patch)
tree32918aadbea9210eace50efbce9afbfb8cd3ba84 /app
parent53ae6b7e3f83591ad251a3f771f5bf3b8cf087ba (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/issuables_list/components/issuable.vue9
-rw-r--r--app/assets/javascripts/reports/components/grouped_test_reports_app.vue20
-rw-r--r--app/assets/javascripts/reports/store/mutations.js2
-rw-r--r--app/assets/javascripts/reports/store/state.js5
-rw-r--r--app/assets/javascripts/reports/store/utils.js9
-rw-r--r--app/controllers/boards/issues_controller.rb12
-rw-r--r--app/graphql/mutations/notes/update.rb38
-rw-r--r--app/graphql/mutations/notes/update/base.rb48
-rw-r--r--app/graphql/mutations/notes/update/image_diff_note.rb60
-rw-r--r--app/graphql/mutations/notes/update/note.rb22
-rw-r--r--app/graphql/types/mutation_type.rb11
-rw-r--r--app/graphql/types/notes/diff_position_type.rb4
-rw-r--r--app/graphql/types/notes/update_diff_image_position_input_type.rb29
-rw-r--r--app/helpers/projects_helper.rb3
-rw-r--r--app/mailers/emails/pipelines.rb8
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stage.rb8
-rw-r--r--app/serializers/test_reports_comparer_entity.rb1
-rw-r--r--app/serializers/test_suite_comparer_entity.rb15
-rw-r--r--app/services/snippets/create_service.rb10
-rw-r--r--app/views/projects/wikis/_form.html.haml4
20 files changed, 250 insertions, 68 deletions
diff --git a/app/assets/javascripts/issuables_list/components/issuable.vue b/app/assets/javascripts/issuables_list/components/issuable.vue
index eb924609a8a..2fd92e009eb 100644
--- a/app/assets/javascripts/issuables_list/components/issuable.vue
+++ b/app/assets/javascripts/issuables_list/components/issuable.vue
@@ -3,7 +3,7 @@
* This is tightly coupled to projects/issues/_issue.html.haml,
* any changes done to the haml need to be reflected here.
*/
-import { escape, isNumber } from 'underscore';
+import { escape, isNumber } from 'lodash';
import { GlLink, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
import {
dateInWords,
@@ -19,8 +19,6 @@ import { mergeUrlParams } from '~/lib/utils/url_utility';
import Icon from '~/vue_shared/components/icon.vue';
import IssueAssignees from '~/vue_shared/components/issue/issue_assignees.vue';
-const ISSUE_TOKEN = '#';
-
export default {
components: {
Icon,
@@ -119,8 +117,7 @@ export default {
);
},
referencePath() {
- // TODO: The API should return the reference path (it doesn't now) https://gitlab.com/gitlab-org/gitlab/issues/31301
- return `${ISSUE_TOKEN}${this.issuable.iid}`;
+ return this.issuable.references.relative;
},
updatedDateString() {
return formatDate(new Date(this.issuable.updated_at), 'mmm d, yyyy h:MMtt');
@@ -230,7 +227,7 @@ export default {
</div>
<div class="issuable-info">
- <span>{{ referencePath }}</span>
+ <span class="js-ref-path">{{ referencePath }}</span>
<span class="d-none d-sm-inline-block mr-1">
&middot;
diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
index 82601363aa4..88d174f96ed 100644
--- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
+++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
@@ -62,9 +62,21 @@ export default {
return (
report.existing_failures.length > 0 ||
report.new_failures.length > 0 ||
- report.resolved_failures.length > 0
+ report.resolved_failures.length > 0 ||
+ report.existing_errors.length > 0 ||
+ report.new_errors.length > 0 ||
+ report.resolved_errors.length > 0
);
},
+ unresolvedIssues(report) {
+ return report.existing_failures.concat(report.existing_errors);
+ },
+ newIssues(report) {
+ return report.new_failures.concat(report.new_errors);
+ },
+ resolvedIssues(report) {
+ return report.resolved_failures.concat(report.resolved_errors);
+ },
},
};
</script>
@@ -87,9 +99,9 @@ export default {
<issues-list
v-if="shouldRenderIssuesList(report)"
:key="`issues-list-${i}`"
- :unresolved-issues="report.existing_failures"
- :new-issues="report.new_failures"
- :resolved-issues="report.resolved_failures"
+ :unresolved-issues="unresolvedIssues(report)"
+ :new-issues="newIssues(report)"
+ :resolved-issues="resolvedIssues(report)"
:component="$options.componentNames.TestIssueBody"
class="report-block-group-list"
/>
diff --git a/app/assets/javascripts/reports/store/mutations.js b/app/assets/javascripts/reports/store/mutations.js
index 2a37f5b74fa..68f6de3a7ee 100644
--- a/app/assets/javascripts/reports/store/mutations.js
+++ b/app/assets/javascripts/reports/store/mutations.js
@@ -16,6 +16,7 @@ export default {
state.summary.total = response.summary.total;
state.summary.resolved = response.summary.resolved;
state.summary.failed = response.summary.failed;
+ state.summary.errored = response.summary.errored;
state.status = response.status;
state.reports = response.suites;
@@ -29,6 +30,7 @@ export default {
total: 0,
resolved: 0,
failed: 0,
+ errored: 0,
};
state.status = null;
},
diff --git a/app/assets/javascripts/reports/store/state.js b/app/assets/javascripts/reports/store/state.js
index d0b2d0a37f5..4f9eb53e787 100644
--- a/app/assets/javascripts/reports/store/state.js
+++ b/app/assets/javascripts/reports/store/state.js
@@ -13,6 +13,7 @@ export default () => ({
total: 0,
resolved: 0,
failed: 0,
+ errored: 0,
},
/**
@@ -23,10 +24,14 @@ export default () => ({
* total: {Number},
* resolved: {Number},
* failed: {Number},
+ * errored: {Number},
* },
* new_failures: {Array.<Object>},
* resolved_failures: {Array.<Object>},
* existing_failures: {Array.<Object>},
+ * new_errors: {Array.<Object>},
+ * resolved_errors: {Array.<Object>},
+ * existing_errors: {Array.<Object>},
* }
*/
reports: [],
diff --git a/app/assets/javascripts/reports/store/utils.js b/app/assets/javascripts/reports/store/utils.js
index 7381f038eaf..ce3ffaae703 100644
--- a/app/assets/javascripts/reports/store/utils.js
+++ b/app/assets/javascripts/reports/store/utils.js
@@ -8,10 +8,11 @@ import {
} from '../constants';
const textBuilder = results => {
- const { failed, resolved, total } = results;
+ const { failed, errored, resolved, total } = results;
- const failedString = failed
- ? n__('%d failed/error test result', '%d failed/error test results', failed)
+ const failedOrErrored = (failed || 0) + (errored || 0);
+ const failedString = failedOrErrored
+ ? n__('%d failed/error test result', '%d failed/error test results', failedOrErrored)
: null;
const resolvedString = resolved
? n__('%d fixed test result', '%d fixed test results', resolved)
@@ -20,7 +21,7 @@ const textBuilder = results => {
let resultsString = s__('Reports|no changed test results');
- if (failed) {
+ if (failedOrErrored) {
if (resolved) {
resultsString = sprintf(s__('Reports|%{failedString} and %{resolvedString}'), {
failedString,
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index ed2c39e3fd3..5e14339bb07 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -86,8 +86,12 @@ module Boards
head(:forbidden) unless can?(current_user, :admin_issue, board)
end
+ def serializer_options(issues)
+ {}
+ end
+
def render_issues(issues, metadata)
- data = { issues: serialize_as_json(issues) }
+ data = { issues: serialize_as_json(issues, opts: serializer_options(issues)) }
data.merge!(metadata)
render json: data
@@ -133,8 +137,10 @@ module Boards
IssueSerializer.new(current_user: current_user)
end
- def serialize_as_json(resource)
- serializer.represent(resource, serializer: 'board', include_full_project_path: board.group_board?)
+ def serialize_as_json(resource, opts: {})
+ opts.merge!(include_full_project_path: board.group_board?, serializer: 'board')
+
+ serializer.represent(resource, opts)
end
def whitelist_query_limiting
diff --git a/app/graphql/mutations/notes/update.rb b/app/graphql/mutations/notes/update.rb
deleted file mode 100644
index ebf57b800c0..00000000000
--- a/app/graphql/mutations/notes/update.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Mutations
- module Notes
- class Update < Base
- graphql_name 'UpdateNote'
-
- authorize :admin_note
-
- argument :id,
- GraphQL::ID_TYPE,
- required: true,
- description: 'The global id of the note to update'
-
- argument :body,
- GraphQL::STRING_TYPE,
- required: true,
- description: copy_field_description(Types::Notes::NoteType, :body)
-
- def resolve(args)
- note = authorized_find!(id: args[:id])
-
- check_object_is_note!(note)
-
- note = ::Notes::UpdateService.new(
- note.project,
- current_user,
- { note: args[:body] }
- ).execute(note)
-
- {
- note: note.reset,
- errors: errors_on_object(note)
- }
- end
- end
- end
-end
diff --git a/app/graphql/mutations/notes/update/base.rb b/app/graphql/mutations/notes/update/base.rb
new file mode 100644
index 00000000000..9a53337f253
--- /dev/null
+++ b/app/graphql/mutations/notes/update/base.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Notes
+ module Update
+ # This is a Base class for the Note update mutations and is not
+ # mounted as a GraphQL mutation itself.
+ class Base < Mutations::Notes::Base
+ authorize :admin_note
+
+ argument :id,
+ GraphQL::ID_TYPE,
+ required: true,
+ description: 'The global id of the note to update'
+
+ def resolve(args)
+ note = authorized_find!(id: args[:id])
+
+ pre_update_checks!(note, args)
+
+ updated_note = ::Notes::UpdateService.new(
+ note.project,
+ current_user,
+ note_params(note, args)
+ ).execute(note)
+
+ # It's possible for updated_note to be `nil`, in the situation
+ # where the note is deleted within `Notes::UpdateService` due to
+ # the body of the note only containing Quick Actions.
+ {
+ note: updated_note&.reset,
+ errors: updated_note ? errors_on_object(updated_note) : []
+ }
+ end
+
+ private
+
+ def pre_update_checks!(_note, _args)
+ raise NotImplementedError
+ end
+
+ def note_params(_note, args)
+ { note: args[:body] }.compact
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/notes/update/image_diff_note.rb b/app/graphql/mutations/notes/update/image_diff_note.rb
new file mode 100644
index 00000000000..7aad3af1e04
--- /dev/null
+++ b/app/graphql/mutations/notes/update/image_diff_note.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Notes
+ module Update
+ class ImageDiffNote < Mutations::Notes::Update::Base
+ graphql_name 'UpdateImageDiffNote'
+
+ argument :body,
+ GraphQL::STRING_TYPE,
+ required: false,
+ description: copy_field_description(Types::Notes::NoteType, :body)
+
+ argument :position,
+ Types::Notes::UpdateDiffImagePositionInputType,
+ required: false,
+ description: copy_field_description(Types::Notes::NoteType, :position)
+
+ def ready?(**args)
+ # As both arguments are optional, validate here that one of the
+ # arguments are present.
+ #
+ # This may be able to be done using InputUnions in the future
+ # if this RFC is merged:
+ # https://github.com/graphql/graphql-spec/blob/master/rfcs/InputUnion.md
+ if args.values_at(:body, :position).compact.blank?
+ raise Gitlab::Graphql::Errors::ArgumentError,
+ 'body or position arguments are required'
+ end
+
+ super(args)
+ end
+
+ private
+
+ def pre_update_checks!(note, args)
+ unless note.is_a?(DiffNote) && note.position.on_image?
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable,
+ 'Resource is not an ImageDiffNote'
+ end
+ end
+
+ def note_params(note, args)
+ super(note, args).merge(
+ position: position_params(note, args)
+ ).compact
+ end
+
+ def position_params(note, args)
+ new_position = args[:position]&.to_h&.compact
+ return unless new_position
+
+ original_position = note.position.to_h
+
+ Gitlab::Diff::Position.new(original_position.merge(new_position))
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/notes/update/note.rb b/app/graphql/mutations/notes/update/note.rb
new file mode 100644
index 00000000000..03a174fc8d9
--- /dev/null
+++ b/app/graphql/mutations/notes/update/note.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Notes
+ module Update
+ class Note < Mutations::Notes::Update::Base
+ graphql_name 'UpdateNote'
+
+ argument :body,
+ GraphQL::STRING_TYPE,
+ required: true,
+ description: copy_field_description(Types::Notes::NoteType, :body)
+
+ private
+
+ def pre_update_checks!(note, _args)
+ check_object_is_note!(note)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index fc0a2a099df..ee0f4dbb05f 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -4,7 +4,7 @@ module Types
class MutationType < BaseObject
include Gitlab::Graphql::MountMutation
- graphql_name "Mutation"
+ graphql_name 'Mutation'
mount_mutation Mutations::AwardEmojis::Add
mount_mutation Mutations::AwardEmojis::Remove
@@ -20,7 +20,14 @@ module Types
mount_mutation Mutations::Notes::Create::Note, calls_gitaly: true
mount_mutation Mutations::Notes::Create::DiffNote, calls_gitaly: true
mount_mutation Mutations::Notes::Create::ImageDiffNote, calls_gitaly: true
- mount_mutation Mutations::Notes::Update
+ mount_mutation Mutations::Notes::Update::Note,
+ description: 'Updates a Note. If the body of the Note contains only quick actions, ' \
+ 'the Note will be destroyed during the update, and no Note will be ' \
+ 'returned'
+ mount_mutation Mutations::Notes::Update::ImageDiffNote,
+ description: 'Updates a DiffNote on an image (a `Note` where the `position.positionType` is `"image"`). ' \
+ 'If the body of the Note contains only quick actions, the Note will be ' \
+ 'destroyed during the update, and no Note will be returned'
mount_mutation Mutations::Notes::Destroy
mount_mutation Mutations::Todos::MarkDone
mount_mutation Mutations::Todos::Restore
diff --git a/app/graphql/types/notes/diff_position_type.rb b/app/graphql/types/notes/diff_position_type.rb
index 654562da0a7..cc00feba2e6 100644
--- a/app/graphql/types/notes/diff_position_type.rb
+++ b/app/graphql/types/notes/diff_position_type.rb
@@ -29,10 +29,10 @@ module Types
# Fields for image positions
field :x, GraphQL::INT_TYPE, null: true,
- description: 'X position on which the comment was made',
+ description: 'X position of the note',
resolve: -> (position, _args, _ctx) { position.x if position.on_image? }
field :y, GraphQL::INT_TYPE, null: true,
- description: 'Y position on which the comment was made',
+ description: 'Y position of the note',
resolve: -> (position, _args, _ctx) { position.y if position.on_image? }
field :width, GraphQL::INT_TYPE, null: true,
description: 'Total width of the image',
diff --git a/app/graphql/types/notes/update_diff_image_position_input_type.rb b/app/graphql/types/notes/update_diff_image_position_input_type.rb
new file mode 100644
index 00000000000..af99764f9f2
--- /dev/null
+++ b/app/graphql/types/notes/update_diff_image_position_input_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Types
+ module Notes
+ # InputType used for updateImageDiffNote mutation.
+ #
+ # rubocop: disable Graphql/AuthorizeTypes
+ class UpdateDiffImagePositionInputType < BaseInputObject
+ graphql_name 'UpdateDiffImagePositionInput'
+
+ argument :x, GraphQL::INT_TYPE,
+ required: false,
+ description: copy_field_description(Types::Notes::DiffPositionType, :x)
+
+ argument :y, GraphQL::INT_TYPE,
+ required: false,
+ description: copy_field_description(Types::Notes::DiffPositionType, :y)
+
+ argument :width, GraphQL::INT_TYPE,
+ required: false,
+ description: copy_field_description(Types::Notes::DiffPositionType, :width)
+
+ argument :height, GraphQL::INT_TYPE,
+ required: false,
+ description: copy_field_description(Types::Notes::DiffPositionType, :height)
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 4ed99b229b5..023790f7d87 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -720,8 +720,7 @@ module ProjectsHelper
end
def settings_container_registry_expiration_policy_available?(project)
- Feature.enabled?(:registry_retention_policies_settings, project) &&
- Gitlab.config.registry.enabled &&
+ Gitlab.config.registry.enabled &&
can?(current_user, :destroy_container_image, project)
end
end
diff --git a/app/mailers/emails/pipelines.rb b/app/mailers/emails/pipelines.rb
index 95bb52d8f97..773b9fead3a 100644
--- a/app/mailers/emails/pipelines.rb
+++ b/app/mailers/emails/pipelines.rb
@@ -15,7 +15,13 @@ module Emails
def pipeline_mail(pipeline, recipients, status)
@project = pipeline.project
@pipeline = pipeline
- @merge_request = pipeline.all_merge_requests.first
+
+ @merge_request = if pipeline.merge_request?
+ pipeline.merge_request
+ else
+ pipeline.merge_requests_as_head_pipeline.first
+ end
+
add_headers
# We use bcc here because we don't want to generate these emails for a
diff --git a/app/models/concerns/analytics/cycle_analytics/stage.rb b/app/models/concerns/analytics/cycle_analytics/stage.rb
index dde73b567db..39e8408f794 100644
--- a/app/models/concerns/analytics/cycle_analytics/stage.rb
+++ b/app/models/concerns/analytics/cycle_analytics/stage.rb
@@ -15,8 +15,8 @@ module Analytics
validates :name, exclusion: { in: Gitlab::Analytics::CycleAnalytics::DefaultStages.names }, if: :custom?
validates :start_event_identifier, presence: true
validates :end_event_identifier, presence: true
- validates :start_event_label, presence: true, if: :start_event_label_based?
- validates :end_event_label, presence: true, if: :end_event_label_based?
+ validates :start_event_label_id, presence: true, if: :start_event_label_based?
+ validates :end_event_label_id, presence: true, if: :end_event_label_based?
validate :validate_stage_event_pairs
validate :validate_labels
@@ -109,8 +109,8 @@ module Analytics
end
def validate_labels
- validate_label_within_group(:start_event_label, start_event_label_id) if start_event_label_id_changed?
- validate_label_within_group(:end_event_label, end_event_label_id) if end_event_label_id_changed?
+ validate_label_within_group(:start_event_label_id, start_event_label_id) if start_event_label_id_changed?
+ validate_label_within_group(:end_event_label_id, end_event_label_id) if end_event_label_id_changed?
end
def validate_label_within_group(association_name, label_id)
diff --git a/app/serializers/test_reports_comparer_entity.rb b/app/serializers/test_reports_comparer_entity.rb
index d7a3dd34fdc..5f8a68338cc 100644
--- a/app/serializers/test_reports_comparer_entity.rb
+++ b/app/serializers/test_reports_comparer_entity.rb
@@ -7,6 +7,7 @@ class TestReportsComparerEntity < Grape::Entity
expose :total_count, as: :total
expose :resolved_count, as: :resolved
expose :failed_count, as: :failed
+ expose :error_count, as: :errored
end
expose :suite_comparers, as: :suites, using: TestSuiteComparerEntity
diff --git a/app/serializers/test_suite_comparer_entity.rb b/app/serializers/test_suite_comparer_entity.rb
index d402a4d5718..78c243f75b8 100644
--- a/app/serializers/test_suite_comparer_entity.rb
+++ b/app/serializers/test_suite_comparer_entity.rb
@@ -11,6 +11,7 @@ class TestSuiteComparerEntity < Grape::Entity
expose :total_count, as: :total
expose :resolved_count, as: :resolved
expose :failed_count, as: :failed
+ expose :error_count, as: :errored
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -28,6 +29,20 @@ class TestSuiteComparerEntity < Grape::Entity
max_tests(suite.new_failures, suite.existing_failures))
end
+ expose :new_errors, using: TestCaseEntity do |suite|
+ suite.new_errors.take(max_tests)
+ end
+
+ expose :existing_errors, using: TestCaseEntity do |suite|
+ suite.existing_errors.take(
+ max_tests(suite.new_errors))
+ end
+
+ expose :resolved_errors, using: TestCaseEntity do |suite|
+ suite.resolved_errors.take(
+ max_tests(suite.new_errors, suite.existing_errors))
+ end
+
private
def max_tests(*used)
diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb
index 51860adca77..9e87bebbe4e 100644
--- a/app/services/snippets/create_service.rb
+++ b/app/services/snippets/create_service.rb
@@ -24,7 +24,9 @@ module Snippets
spam_check(snippet, current_user)
snippet_saved = snippet.with_transaction_returning_status do
- snippet.save
+ if snippet.save && snippet.store_mentions!
+ create_repository_for(snippet, current_user)
+ end
end
if snippet_saved
@@ -36,5 +38,11 @@ module Snippets
snippet_error_response(snippet, 400)
end
end
+
+ private
+
+ def create_repository_for(snippet, user)
+ snippet.create_repository if Feature.enabled?(:version_snippets, user)
+ end
end
end
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index 0affd9f0e6f..438d390389c 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -27,7 +27,9 @@
.form-group.row
.col-sm-12= f.label :format, class: 'control-label-full-width'
.col-sm-12
- = f.select :format, options_for_select(ProjectWiki::MARKUPS, {selected: @page.format}), {}, class: 'form-control'
+ .select-wrapper
+ = f.select :format, options_for_select(ProjectWiki::MARKUPS, {selected: @page.format}), {}, class: 'form-control select-control'
+ = icon('chevron-down')
.form-group.row
.col-sm-12= f.label :content, class: 'control-label-full-width'