summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-03-27 12:07:43 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-27 12:07:43 +0000
commit39fa7d1eeb2dba52f0601128f3ac91f57d19866e (patch)
treeda042d34ff762dd1957e51666a34202295a081b9 /app
parent6ac4a6713ed3196af899011f7e18658e16ebaac0 (diff)
downloadgitlab-ce-39fa7d1eeb2dba52f0601128f3ac91f57d19866e.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/monitoring/components/charts/bar.vue97
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue6
-rw-r--r--app/assets/javascripts/monitoring/constants.js1
-rw-r--r--app/assets/javascripts/monitoring/stores/utils.js32
-rw-r--r--app/assets/javascripts/monitoring/utils.js59
-rw-r--r--app/assets/stylesheets/pages/prometheus.scss5
-rw-r--r--app/helpers/auth_helper.rb3
-rw-r--r--app/models/concerns/services/data_fields.rb26
-rw-r--r--app/models/project_services/data_fields.rb1
-rw-r--r--app/models/project_services/issue_tracker_data.rb15
-rw-r--r--app/models/project_services/jira_tracker_data.rb15
-rw-r--r--app/models/project_services/open_project_service.rb18
-rw-r--r--app/models/project_services/open_project_tracker_data.rb16
-rw-r--r--app/models/terraform.rb7
-rw-r--r--app/models/terraform/state.rb23
-rw-r--r--app/services/merge_requests/after_create_service.rb7
-rw-r--r--app/services/merge_requests/create_service.rb6
-rw-r--r--app/uploaders/terraform/state_uploader.rb44
-rw-r--r--app/views/kaminari/gitlab/_gap.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/shared/snippets/show.js.haml4
-rw-r--r--app/workers/irker_worker.rb2
22 files changed, 339 insertions, 52 deletions
diff --git a/app/assets/javascripts/monitoring/components/charts/bar.vue b/app/assets/javascripts/monitoring/components/charts/bar.vue
new file mode 100644
index 00000000000..01fd8940dad
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/charts/bar.vue
@@ -0,0 +1,97 @@
+<script>
+import { GlResizeObserverDirective } from '@gitlab/ui';
+import { GlBarChart } from '@gitlab/ui/dist/charts';
+import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
+import { chartHeight } from '../../constants';
+import { barChartsDataParser, graphDataValidatorForValues } from '../../utils';
+
+export default {
+ components: {
+ GlBarChart,
+ },
+ directives: {
+ GlResizeObserverDirective,
+ },
+ props: {
+ graphData: {
+ type: Object,
+ required: true,
+ validator: graphDataValidatorForValues.bind(null, false),
+ },
+ },
+ data() {
+ return {
+ width: 0,
+ height: chartHeight,
+ svgs: {},
+ };
+ },
+ computed: {
+ chartData() {
+ return barChartsDataParser(this.graphData.metrics);
+ },
+ chartOptions() {
+ return {
+ dataZoom: [this.dataZoomConfig],
+ };
+ },
+ xAxisTitle() {
+ const { xLabel = '' } = this.graphData;
+ return xLabel;
+ },
+ yAxisTitle() {
+ const { y_label = '' } = this.graphData;
+ return y_label; // eslint-disable-line babel/camelcase
+ },
+ xAxisType() {
+ const { x_type = 'value' } = this.graphData;
+ return x_type; // eslint-disable-line babel/camelcase
+ },
+ dataZoomConfig() {
+ const handleIcon = this.svgs['scroll-handle'];
+
+ return handleIcon ? { handleIcon } : {};
+ },
+ },
+ created() {
+ this.setSvg('scroll-handle');
+ },
+ methods: {
+ formatLegendLabel(query) {
+ return `${query.label}`;
+ },
+ onResize() {
+ if (!this.$refs.barChart) return;
+ const { width } = this.$refs.barChart.$el.getBoundingClientRect();
+ this.width = width;
+ },
+ setSvg(name) {
+ getSvgIconPathContent(name)
+ .then(path => {
+ if (path) {
+ this.$set(this.svgs, name, `path://${path}`);
+ }
+ })
+ .catch(e => {
+ // eslint-disable-next-line no-console, @gitlab/require-i18n-strings
+ console.error('SVG could not be rendered correctly: ', e);
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div v-gl-resize-observer-directive="onResize">
+ <gl-bar-chart
+ ref="barChart"
+ v-bind="$attrs"
+ :data="chartData"
+ :option="chartOptions"
+ :width="width"
+ :height="height"
+ :x-axis-title="xAxisTitle"
+ :y-axis-title="yAxisTitle"
+ :x-axis-type="xAxisType"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index 79f2c8ad41f..da305c7dda3 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -18,6 +18,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 MonitorBarChart from './charts/bar.vue';
import MonitorStackedColumnChart from './charts/stacked_column.vue';
import MonitorEmptyChart from './charts/empty_chart.vue';
import TrackEventDirective from '~/vue_shared/directives/track_event';
@@ -31,6 +32,7 @@ export default {
components: {
MonitorSingleStatChart,
MonitorColumnChart,
+ MonitorBarChart,
MonitorHeatmapChart,
MonitorStackedColumnChart,
MonitorEmptyChart,
@@ -259,6 +261,10 @@ export default {
v-else-if="isPanelType('heatmap') && graphDataHasMetrics"
:graph-data="graphData"
/>
+ <monitor-bar-chart
+ v-else-if="isPanelType('bar') && graphDataHasMetrics"
+ :graph-data="graphData"
+ />
<monitor-column-chart
v-else-if="isPanelType('column') && graphDataHasMetrics"
:graph-data="graphData"
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index cc7f5af2259..4fd6903d566 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -46,7 +46,6 @@ export const metricStates = {
};
export const sidebarAnimationDuration = 300; // milliseconds.
-
export const chartHeight = 300;
export const graphTypes = {
diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js
index 066d0bf7676..48ed2259a51 100644
--- a/app/assets/javascripts/monitoring/stores/utils.js
+++ b/app/assets/javascripts/monitoring/stores/utils.js
@@ -73,14 +73,21 @@ const mapToMetricsViewModel = (metrics, defaultLabel) =>
}));
/**
- * Maps an axis view model
+ * Maps X-axis view model
+ *
+ * @param {Object} axis
+ */
+const mapXAxisToViewModel = ({ name = '' }) => ({ name });
+
+/**
+ * Maps Y-axis view model
*
* Defaults to a 2 digit precision and `number` format. It only allows
* formats in the SUPPORTED_FORMATS array.
*
* @param {Object} axis
*/
-const mapToAxisViewModel = ({ name = '', format = SUPPORTED_FORMATS.number, precision = 2 }) => {
+const mapYAxisToViewModel = ({ name = '', format = SUPPORTED_FORMATS.number, precision = 2 }) => {
return {
name,
format: SUPPORTED_FORMATS[format] || SUPPORTED_FORMATS.number,
@@ -94,15 +101,30 @@ const mapToAxisViewModel = ({ name = '', format = SUPPORTED_FORMATS.number, prec
* @param {Object} panel - Metrics panel
* @returns {Object}
*/
-const mapToPanelViewModel = ({ title = '', type, y_label, y_axis = {}, metrics = [] }) => {
+const mapPanelToViewModel = ({
+ title = '',
+ type,
+ x_axis = {},
+ x_label,
+ y_label,
+ y_axis = {},
+ metrics = [],
+}) => {
+ // Both `x_axis.name` and `x_label` are supported for now
+ // https://gitlab.com/gitlab-org/gitlab/issues/210521
+ const xAxis = mapXAxisToViewModel({ name: x_label, ...x_axis }); // eslint-disable-line babel/camelcase
+
// Both `y_axis.name` and `y_label` are supported for now
// https://gitlab.com/gitlab-org/gitlab/issues/208385
- const yAxis = mapToAxisViewModel({ name: y_label, ...y_axis }); // eslint-disable-line babel/camelcase
+ const yAxis = mapYAxisToViewModel({ name: y_label, ...y_axis }); // eslint-disable-line babel/camelcase
+
return {
title,
type,
+ xLabel: xAxis.name,
y_label: yAxis.name, // Changing y_label to yLabel is pending https://gitlab.com/gitlab-org/gitlab/issues/207198
yAxis,
+ xAxis,
metrics: mapToMetricsViewModel(metrics, yAxis.name),
};
};
@@ -117,7 +139,7 @@ const mapToPanelGroupViewModel = ({ group = '', panels = [] }, i) => {
return {
key: `${slugify(group || 'default')}-${i}`,
group,
- panels: panels.map(mapToPanelViewModel),
+ panels: panels.map(mapPanelToViewModel),
};
};
diff --git a/app/assets/javascripts/monitoring/utils.js b/app/assets/javascripts/monitoring/utils.js
index 6a46c7e67e4..7c6cd19eb7b 100644
--- a/app/assets/javascripts/monitoring/utils.js
+++ b/app/assets/javascripts/monitoring/utils.js
@@ -132,4 +132,63 @@ export const timeRangeToUrl = (timeRange, url = window.location.href) => {
return mergeUrlParams(params, toUrl);
};
+/**
+ * Get the metric value from first data point.
+ * Currently only used for bar charts
+ *
+ * @param {Array} values data points
+ * @returns {Number}
+ */
+const metricValueMapper = values => values[0]?.[1];
+
+/**
+ * Get the metric name from metric object
+ * Currently only used for bar charts
+ * e.g. { handler: '/query' }
+ * { method: 'get' }
+ *
+ * @param {Object} metric metric object
+ * @returns {String}
+ */
+const metricNameMapper = metric => Object.values(metric)?.[0];
+
+/**
+ * Parse metric object to extract metric value and name in
+ * [<metric-value>, <metric-name>] format.
+ * Currently only used for bar charts
+ *
+ * @param {Object} param0 metric object
+ * @returns {Array}
+ */
+const resultMapper = ({ metric, values = [] }) => [
+ metricValueMapper(values),
+ metricNameMapper(metric),
+];
+
+/**
+ * Bar charts graph data parser to massage data from
+ * backend to a format acceptable by bar charts component
+ * in GitLab UI
+ *
+ * e.g.
+ * {
+ * SLO: [
+ * [98, 'api'],
+ * [99, 'web'],
+ * [99, 'database']
+ * ]
+ * }
+ *
+ * @param {Array} data series information
+ * @returns {Object}
+ */
+export const barChartsDataParser = (data = []) =>
+ data?.reduce(
+ (acc, { result = [], label }) => ({
+ ...acc,
+ [label]: result.map(resultMapper),
+ }),
+ {},
+ );
+
export default {};
diff --git a/app/assets/stylesheets/pages/prometheus.scss b/app/assets/stylesheets/pages/prometheus.scss
index 30ef047bf04..5872c90a25e 100644
--- a/app/assets/stylesheets/pages/prometheus.scss
+++ b/app/assets/stylesheets/pages/prometheus.scss
@@ -93,6 +93,11 @@
.alert-current-setting {
max-width: 240px;
+
+ .badge.badge-danger {
+ color: $red-500;
+ background-color: $red-100;
+ }
}
.prometheus-graph-cursor {
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index 26d73007e65..1f1ff75359d 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -30,8 +30,7 @@ module AuthHelper
def qa_class_for_provider(provider)
{
- saml: 'qa-saml-login-button',
- github: 'qa-github-login-button'
+ saml: 'qa-saml-login-button'
}[provider.to_sym]
end
diff --git a/app/models/concerns/services/data_fields.rb b/app/models/concerns/services/data_fields.rb
new file mode 100644
index 00000000000..10963e4e7d8
--- /dev/null
+++ b/app/models/concerns/services/data_fields.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Services
+ module DataFields
+ extend ActiveSupport::Concern
+
+ included do
+ belongs_to :service
+
+ delegate :activated?, to: :service, allow_nil: true
+
+ validates :service, presence: true
+ end
+
+ class_methods do
+ def encryption_options
+ {
+ key: Settings.attr_encrypted_db_key_base_32,
+ encode: true,
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm'
+ }
+ end
+ end
+ end
+end
diff --git a/app/models/project_services/data_fields.rb b/app/models/project_services/data_fields.rb
index cf406a784ce..12ebf260e08 100644
--- a/app/models/project_services/data_fields.rb
+++ b/app/models/project_services/data_fields.rb
@@ -44,6 +44,7 @@ module DataFields
included do
has_one :issue_tracker_data, autosave: true
has_one :jira_tracker_data, autosave: true
+ has_one :open_project_tracker_data, autosave: true
def data_fields
raise NotImplementedError
diff --git a/app/models/project_services/issue_tracker_data.rb b/app/models/project_services/issue_tracker_data.rb
index b1d67657fe6..414f2c1da4d 100644
--- a/app/models/project_services/issue_tracker_data.rb
+++ b/app/models/project_services/issue_tracker_data.rb
@@ -1,20 +1,7 @@
# frozen_string_literal: true
class IssueTrackerData < ApplicationRecord
- belongs_to :service
-
- delegate :activated?, to: :service, allow_nil: true
-
- validates :service, presence: true
-
- def self.encryption_options
- {
- key: Settings.attr_encrypted_db_key_base_32,
- encode: true,
- mode: :per_attribute_iv,
- algorithm: 'aes-256-gcm'
- }
- end
+ include Services::DataFields
attr_encrypted :project_url, encryption_options
attr_encrypted :issues_url, encryption_options
diff --git a/app/models/project_services/jira_tracker_data.rb b/app/models/project_services/jira_tracker_data.rb
index e4e0f64150a..f24ba8877d2 100644
--- a/app/models/project_services/jira_tracker_data.rb
+++ b/app/models/project_services/jira_tracker_data.rb
@@ -1,20 +1,7 @@
# frozen_string_literal: true
class JiraTrackerData < ApplicationRecord
- belongs_to :service
-
- delegate :activated?, to: :service, allow_nil: true
-
- validates :service, presence: true
-
- def self.encryption_options
- {
- key: Settings.attr_encrypted_db_key_base_32,
- encode: true,
- mode: :per_attribute_iv,
- algorithm: 'aes-256-gcm'
- }
- end
+ include Services::DataFields
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
diff --git a/app/models/project_services/open_project_service.rb b/app/models/project_services/open_project_service.rb
new file mode 100644
index 00000000000..a24fbc1611d
--- /dev/null
+++ b/app/models/project_services/open_project_service.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class OpenProjectService < IssueTrackerService
+ validates :url, public_url: true, presence: true, if: :activated?
+ validates :api_url, public_url: true, allow_blank: true, if: :activated?
+ validates :token, presence: true, if: :activated?
+ validates :project_identifier_code, presence: true, if: :activated?
+
+ data_field :url, :api_url, :token, :closed_status_id, :project_identifier_code
+
+ def data_fields
+ open_project_tracker_data || self.build_open_project_tracker_data
+ end
+
+ def self.to_param
+ 'open_project'
+ end
+end
diff --git a/app/models/project_services/open_project_tracker_data.rb b/app/models/project_services/open_project_tracker_data.rb
new file mode 100644
index 00000000000..20de60e40c1
--- /dev/null
+++ b/app/models/project_services/open_project_tracker_data.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class OpenProjectTrackerData < ApplicationRecord
+ include Services::DataFields
+
+ # When the Open Project is fresh installed, the default closed status id is "13" based on current version: v8.
+ DEFAULT_CLOSED_STATUS_ID = "13"
+
+ attr_encrypted :url, encryption_options
+ attr_encrypted :api_url, encryption_options
+ attr_encrypted :token, encryption_options
+
+ def closed_status_id
+ super || DEFAULT_CLOSED_STATUS_ID
+ end
+end
diff --git a/app/models/terraform.rb b/app/models/terraform.rb
new file mode 100644
index 00000000000..3d974ffe051
--- /dev/null
+++ b/app/models/terraform.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Terraform
+ def self.table_name_prefix
+ 'terraform_'
+ end
+end
diff --git a/app/models/terraform/state.rb b/app/models/terraform/state.rb
new file mode 100644
index 00000000000..8ca4ee9239a
--- /dev/null
+++ b/app/models/terraform/state.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Terraform
+ class State < ApplicationRecord
+ belongs_to :project
+
+ validates :project_id, presence: true
+
+ after_save :update_file_store, if: :saved_change_to_file?
+
+ mount_uploader :file, StateUploader
+
+ def update_file_store
+ # The file.object_store is set during `uploader.store!`
+ # which happens after object is inserted/updated
+ self.update_column(:file_store, file.object_store)
+ end
+
+ def file_store
+ super || StateUploader.default_store
+ end
+ end
+end
diff --git a/app/services/merge_requests/after_create_service.rb b/app/services/merge_requests/after_create_service.rb
index 6da30f8af16..bc681397039 100644
--- a/app/services/merge_requests/after_create_service.rb
+++ b/app/services/merge_requests/after_create_service.rb
@@ -6,11 +6,8 @@ module MergeRequests
event_service.open_mr(merge_request, current_user)
notification_service.new_merge_request(merge_request, current_user)
- # https://gitlab.com/gitlab-org/gitlab/issues/208813
- if ::Feature.enabled?(:create_merge_request_pipelines_in_sidekiq, project)
- create_pipeline_for(merge_request, current_user)
- merge_request.update_head_pipeline
- end
+ create_pipeline_for(merge_request, current_user)
+ merge_request.update_head_pipeline
merge_request.diffs(include_stats: false).write_cache
merge_request.create_cross_references!(current_user)
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index d957a6425b2..1cdfba41432 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -21,12 +21,6 @@ module MergeRequests
todo_service.new_merge_request(issuable, current_user)
issuable.cache_merge_request_closes_issues!(current_user)
- # https://gitlab.com/gitlab-org/gitlab/issues/208813
- unless ::Feature.enabled?(:create_merge_request_pipelines_in_sidekiq, project)
- create_pipeline_for(issuable, current_user)
- issuable.update_head_pipeline
- end
-
Gitlab::UsageDataCounters::MergeRequestCounter.count(:create)
link_lfs_objects(issuable)
diff --git a/app/uploaders/terraform/state_uploader.rb b/app/uploaders/terraform/state_uploader.rb
new file mode 100644
index 00000000000..9c5ae8a8bdc
--- /dev/null
+++ b/app/uploaders/terraform/state_uploader.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Terraform
+ class StateUploader < GitlabUploader
+ include ObjectStorage::Concern
+
+ storage_options Gitlab.config.terraform_state
+
+ delegate :project_id, to: :model
+
+ # Use Lockbox to encrypt/decrypt the stored file (registers CarrierWave callbacks)
+ encrypt(key: :key)
+
+ def filename
+ "#{model.id}.tfstate"
+ end
+
+ def store_dir
+ project_id.to_s
+ end
+
+ def key
+ OpenSSL::HMAC.digest('SHA256', Gitlab::Application.secrets.db_key_base, project_id.to_s)
+ end
+
+ class << self
+ def direct_upload_enabled?
+ false
+ end
+
+ def background_upload_enabled?
+ false
+ end
+
+ def proxy_download_enabled?
+ true
+ end
+
+ def default_store
+ object_store_enabled? ? ObjectStorage::Store::REMOTE : ObjectStorage::Store::LOCAL
+ end
+ end
+ end
+end
diff --git a/app/views/kaminari/gitlab/_gap.html.haml b/app/views/kaminari/gitlab/_gap.html.haml
index 849f92fdc95..c47a8891fd5 100644
--- a/app/views/kaminari/gitlab/_gap.html.haml
+++ b/app/views/kaminari/gitlab/_gap.html.haml
@@ -5,4 +5,4 @@
-# per_page: number of items to fetch per page
-# remote: data-remote
%li.page-item.disabled.d-none.d-md-block
- = link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link'
+ = link_to raw(t('views.pagination.truncate')), '#', class: 'page-link'
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 1a1da6b3801..e20573ed3a7 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -129,7 +129,7 @@
= render_if_exists 'shared/issuable/sidebar_weight', issuable_sidebar: issuable_sidebar
- - if Feature.enabled?(:save_issuable_health_status, @project.group) && issuable_sidebar[:type] == "issue"
+ - if issuable_sidebar.dig(:features_available, :health_status)
.js-sidebar-status-entry-point
- if issuable_sidebar.has_key?(:confidential)
diff --git a/app/views/shared/snippets/show.js.haml b/app/views/shared/snippets/show.js.haml
index a9af732bbb5..d552c1a723b 100644
--- a/app/views/shared/snippets/show.js.haml
+++ b/app/views/shared/snippets/show.js.haml
@@ -1,2 +1,2 @@
-document.write('#{escape_javascript(stylesheet_link_tag "#{stylesheet_url 'snippets'}")}');
-document.write('#{escape_javascript(render 'shared/snippets/embed')}');
+document.write('#{escape_javascript(stylesheet_link_tag("#{stylesheet_url 'snippets'}"))}');
+document.write('#{escape_javascript(render('shared/snippets/embed'))}');
diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb
index 91ab0d69ad1..73bc050d7be 100644
--- a/app/workers/irker_worker.rb
+++ b/app/workers/irker_worker.rb
@@ -133,7 +133,7 @@ class IrkerWorker # rubocop:disable Scalability/IdempotentWorker
commit = commit_from_id project, hook_attrs['id']
sha = colorize_sha Commit.truncate_sha(hook_attrs['id'])
author = hook_attrs['author']['name']
- files = colorize_nb_files(files_count commit)
+ files = colorize_nb_files(files_count(commit))
title = commit.title
sendtoirker "#{repo_name}/#{branch} #{sha} #{author} (#{files}): #{title}"