Skip to content
Snippets Groups Projects
Commit 20d564f1 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 26384c9a
No related branches found
No related tags found
No related merge requests found
Showing
with 328 additions and 24 deletions
Loading
Loading
@@ -29,7 +29,7 @@
extends:
- .default-tags
- .default-retry
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.6
services:
- docker:19.03.0-dind
tags:
Loading
Loading
<script>
import { GlResizeObserverDirective } from '@gitlab/ui';
import { GlStackedColumnChart } from '@gitlab/ui/dist/charts';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import { chartHeight } from '../../constants';
import { graphDataValidatorForValues } from '../../utils';
export default {
components: {
GlStackedColumnChart,
},
directives: {
GlResizeObserverDirective,
},
props: {
graphData: {
type: Object,
required: true,
validator: graphDataValidatorForValues.bind(null, false),
},
},
data() {
return {
width: 0,
height: chartHeight,
svgs: {},
};
},
computed: {
chartData() {
return this.graphData.metrics.map(metric => metric.result[0].values.map(val => val[1]));
},
xAxisTitle() {
return this.graphData.x_label !== undefined ? this.graphData.x_label : '';
},
yAxisTitle() {
return this.graphData.y_label !== undefined ? this.graphData.y_label : '';
},
xAxisType() {
return this.graphData.x_type !== undefined ? this.graphData.x_type : 'category';
},
groupBy() {
return this.graphData.metrics[0].result[0].values.map(val => val[0]);
},
dataZoomConfig() {
const handleIcon = this.svgs['scroll-handle'];
return handleIcon ? { handleIcon } : {};
},
chartOptions() {
return {
dataZoom: this.dataZoomConfig,
};
},
seriesNames() {
return this.graphData.metrics.map(metric => metric.series_name);
},
},
created() {
this.setSvg('scroll-handle');
},
methods: {
setSvg(name) {
getSvgIconPathContent(name)
.then(path => {
if (path) {
this.$set(this.svgs, name, `path://${path}`);
}
})
.catch(e => {
// eslint-disable-next-line no-console, @gitlab/i18n/no-non-i18n-strings
console.error('SVG could not be rendered correctly: ', e);
});
},
onResize() {
if (!this.$refs.chart) return;
const { width } = this.$refs.chart.$el.getBoundingClientRect();
this.width = width;
},
},
};
</script>
<template>
<div v-gl-resize-observer-directive="onResize" class="prometheus-graph">
<div class="prometheus-graph-header">
<h5 ref="graphTitle" class="prometheus-graph-title">{{ graphData.title }}</h5>
<div ref="graphWidgets" class="prometheus-graph-widgets"><slot></slot></div>
</div>
<gl-stacked-column-chart
ref="chart"
v-bind="$attrs"
:data="chartData"
:option="chartOptions"
:x-axis-title="xAxisTitle"
:y-axis-title="yAxisTitle"
:x-axis-type="xAxisType"
:group-by="groupBy"
:width="width"
:height="height"
:series-names="seriesNames"
/>
</div>
</template>
Loading
Loading
@@ -15,6 +15,7 @@ import MonitorAnomalyChart from './charts/anomaly.vue';
import MonitorSingleStatChart from './charts/single_stat.vue';
import MonitorHeatmapChart from './charts/heatmap.vue';
import MonitorColumnChart from './charts/column.vue';
import MonitorStackedColumnChart from './charts/stacked_column.vue';
import MonitorEmptyChart from './charts/empty_chart.vue';
import TrackEventDirective from '~/vue_shared/directives/track_event';
import { downloadCSVOptions, generateLinkToChartOptions } from '../utils';
Loading
Loading
@@ -24,6 +25,7 @@ export default {
MonitorSingleStatChart,
MonitorColumnChart,
MonitorHeatmapChart,
MonitorStackedColumnChart,
MonitorEmptyChart,
Icon,
GlDropdown,
Loading
Loading
@@ -121,6 +123,10 @@ export default {
v-else-if="isPanelType('column') && graphDataHasMetrics"
:graph-data="graphData"
/>
<monitor-stacked-column-chart
v-else-if="isPanelType('stacked-column') && graphDataHasMetrics"
:graph-data="graphData"
/>
<component
:is="monitorChartComponent"
v-else-if="graphDataHasMetrics"
Loading
Loading
Loading
Loading
@@ -160,6 +160,11 @@ $ide-commit-header-height: 48px;
height: 0;
}
 
// stylelint-disable selector-class-pattern
// stylelint-disable selector-max-compound-selectors
// stylelint-disable stylelint-gitlab/duplicate-selectors
// stylelint-disable stylelint-gitlab/utility-classes
.blob-editor-container {
flex: 1;
height: 0;
Loading
Loading
@@ -301,6 +306,11 @@ $ide-commit-header-height: 48px;
}
}
 
// stylelint-enable selector-class-pattern
// stylelint-enable selector-max-compound-selectors
// stylelint-enable stylelint-gitlab/duplicate-selectors
// stylelint-enable stylelint-gitlab/utility-classes
.preview-container {
flex-grow: 1;
position: relative;
Loading
Loading
# frozen_string_literal: true
module TimeFrameFilter
def by_timeframe(items)
return items unless params[:start_date] && params[:start_date]
start_date = params[:start_date].to_date
end_date = params[:end_date].to_date
items.within_timeframe(start_date, end_date)
rescue ArgumentError
items
end
end
Loading
Loading
@@ -11,6 +11,7 @@
 
class MilestonesFinder
include FinderMethods
include TimeFrameFilter
 
attr_reader :params
 
Loading
Loading
@@ -24,6 +25,7 @@ class MilestonesFinder
items = by_title(items)
items = by_search_title(items)
items = by_state(items)
items = by_timeframe(items)
 
order(items)
end
Loading
Loading
# frozen_string_literal: true
module TimeFrameArguments
extend ActiveSupport::Concern
included do
argument :start_date, Types::TimeType,
required: false,
description: 'List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)'
argument :end_date, Types::TimeType,
required: false,
description: 'List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)'
end
def validate_timeframe_params!(args)
return unless args[:start_date].present? || args[:end_date].present?
error_message =
if args[:start_date].nil? || args[:end_date].nil?
"Both startDate and endDate must be present."
elsif args[:start_date] > args[:end_date]
"startDate is after endDate"
end
if error_message
raise Gitlab::Graphql::Errors::ArgumentError, error_message
end
end
end
# frozen_string_literal: true
module Resolvers
class MilestoneResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
include TimeFrameArguments
argument :state, Types::MilestoneStateEnum,
required: false,
description: 'Filter milestones by state'
type Types::MilestoneType, null: true
def resolve(**args)
validate_timeframe_params!(args)
authorize!
MilestonesFinder.new(milestones_finder_params(args)).execute
end
private
def milestones_finder_params(args)
{
state: args[:state] || 'all',
start_date: args[:start_date],
end_date: args[:end_date]
}.merge(parent_id_parameter)
end
def parent
@parent ||= object.respond_to?(:sync) ? object.sync : object
end
def parent_id_parameter
if parent.is_a?(Group)
{ group_ids: parent.id }
elsif parent.is_a?(Project)
{ project_ids: parent.id }
end
end
# MilestonesFinder does not check for current_user permissions,
# so for now we need to keep it here.
def authorize!
Ability.allowed?(context[:current_user], :read_milestone, parent) || raise_resource_not_available_error!
end
end
end
Loading
Loading
@@ -42,6 +42,10 @@ module Types
field :parent, GroupType, null: true,
description: 'Parent group',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find }
field :milestones, Types::MilestoneType.connection_type, null: true,
description: 'Find milestones',
resolver: Resolvers::MilestoneResolver
end
end
 
Loading
Loading
# frozen_string_literal: true
module Types
class MilestoneStateEnum < BaseEnum
value 'active'
value 'closed'
end
end
Loading
Loading
@@ -3,25 +3,36 @@
module Types
class MilestoneType < BaseObject
graphql_name 'Milestone'
description 'Represents a milestone.'
present_using MilestonePresenter
 
authorize :read_milestone
 
field :id, GraphQL::ID_TYPE, null: false,
description: 'ID of the milestone'
field :description, GraphQL::STRING_TYPE, null: true,
description: 'Description of the milestone'
field :title, GraphQL::STRING_TYPE, null: false,
description: 'Title of the milestone'
field :state, GraphQL::STRING_TYPE, null: false,
field :description, GraphQL::STRING_TYPE, null: true,
description: 'Description of the milestone'
field :state, Types::MilestoneStateEnum, null: false,
description: 'State of the milestone'
 
field :web_path, GraphQL::STRING_TYPE, null: false, method: :milestone_path,
description: 'Web path of the milestone'
field :due_date, Types::TimeType, null: true,
description: 'Timestamp of the milestone due date'
field :start_date, Types::TimeType, null: true,
description: 'Timestamp of the milestone start date'
 
field :created_at, Types::TimeType, null: false,
description: 'Timestamp of milestone creation'
field :updated_at, Types::TimeType, null: false,
description: 'Timestamp of last milestone update'
end
Loading
Loading
Loading
Loading
@@ -86,19 +86,6 @@ module SearchHelper
}).html_safe
end
 
def find_project_for_result_blob(projects, result)
@project
end
# Used in EE
def blob_projects(results)
nil
end
def parse_search_result(result)
result
end
# Overriden in EE
def search_blob_title(project, path)
path
Loading
Loading
Loading
Loading
@@ -59,6 +59,12 @@ class Milestone < ApplicationRecord
where(project_id: projects).or(where(group_id: groups))
end
 
scope :within_timeframe, -> (start_date, end_date) do
where('start_date is not NULL or due_date is not NULL')
.where('start_date is NULL or start_date <= ?', end_date)
.where('due_date is NULL or due_date >= ?', start_date)
end
scope :order_by_name_asc, -> { order(Arel::Nodes::Ascending.new(arel_table[:title].lower)) }
scope :reorder_by_due_date_asc, -> { reorder(Gitlab::Database.nulls_last_order('due_date', 'ASC')) }
 
Loading
Loading
# frozen_string_literal: true
class MilestonePresenter < Gitlab::View::Presenter::Delegated
presents :milestone
def milestone_path
url_builder.milestone_path(milestone)
end
private
def url_builder
@url_builder ||= Gitlab::UrlBuilder.new(milestone)
end
end
# frozen_string_literal: true
module Ci
class CreateJobArtifactsService
ArtifactsExistError = Class.new(StandardError)
def execute(job, artifacts_file, params, metadata_file: nil)
expire_in = params['expire_in'] ||
Gitlab::CurrentSettings.current_application_settings.default_artifacts_expire_in
job.job_artifacts.build(
project: job.project,
file: artifacts_file,
file_type: params['artifact_type'],
file_format: params['artifact_format'],
file_sha256: artifacts_file.sha256,
expire_in: expire_in)
if metadata_file
job.job_artifacts.build(
project: job.project,
file: metadata_file,
file_type: :metadata,
file_format: :gzip,
file_sha256: metadata_file.sha256,
expire_in: expire_in)
end
job.update(artifacts_expire_in: expire_in)
rescue ActiveRecord::RecordNotUnique => error
return true if sha256_matches_existing_artifact?(job, params['artifact_type'], artifacts_file)
Gitlab::ErrorTracking.track_exception(error,
job_id: job.id,
project_id: job.project_id,
uploading_type: params['artifact_type']
)
job.errors.add(:base, 'another artifact of the same type already exists')
false
end
private
def sha256_matches_existing_artifact?(job, artifact_type, artifacts_file)
existing_artifact = job.job_artifacts.find_by_file_type(artifact_type)
return false unless existing_artifact
existing_artifact.file_sha256 == artifacts_file.sha256
end
end
end
Loading
Loading
@@ -32,8 +32,7 @@
.term
= render 'shared/projects/list', projects: @search_objects, pipeline_status: false
- else
- locals = { projects: blob_projects(@search_objects) } if %w[blobs wiki_blobs].include?(@scope)
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects, locals: locals
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects
 
- if @scope != 'projects'
= paginate_collection(@search_objects)
- project = find_project_for_result_blob(projects, blob)
- project = blob.project
- return unless project
- blob = parse_search_result(blob)
- blob_link = project_blob_path(project, tree_join(blob.ref, blob.path))
 
= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, path: blob.path, blob_link: blob_link }
- project = find_project_for_result_blob(projects, wiki_blob)
- wiki_blob = parse_search_result(wiki_blob)
- project = wiki_blob.project
- wiki_blob_link = project_wiki_path(project, wiki_blob.basename)
 
= render partial: 'search/results/blob_data', locals: { blob: wiki_blob, project: project, path: wiki_blob.path, blob_link: wiki_blob_link }
---
title: Add emails_disabled to projects API
merge_request: 23616
author: Mathieu Parent
type: added
---
title: Replace artifacts via Runner API if already exist
merge_request: 24165
author:
type: fixed
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment