This instance will be upgraded to Heptapod 0.26.0rc1 on 2021-10-26 at 14:30 UTC+2 (a few minutes of down time)

Commit 6bc40f22 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 76ea7a86f302
......@@ -111,15 +111,22 @@ export const fetchDiffFilesBatch = ({ commit, state }) => {
commit(types.SET_BATCH_LOADING, true);
commit(types.SET_RETRIEVING_BATCHES, true);
const getBatch = page =>
const getBatch = (page = 1) =>
axios
.get(state.endpointBatch, {
params: { ...urlParams, page },
params: {
...urlParams,
page,
},
})
.then(({ data: { pagination, diff_files } }) => {
commit(types.SET_DIFF_DATA_BATCH, { diff_files });
commit(types.SET_BATCH_LOADING, false);
if (!pagination.next_page) commit(types.SET_RETRIEVING_BATCHES, false);
if (!pagination.next_page) {
commit(types.SET_RETRIEVING_BATCHES, false);
}
return pagination.next_page;
})
.then(nextPage => nextPage && getBatch(nextPage))
......@@ -132,6 +139,11 @@ export const fetchDiffFilesBatch = ({ commit, state }) => {
export const fetchDiffFilesMeta = ({ commit, state }) => {
const worker = new TreeWorker();
const urlParams = {};
if (state.useSingleDiffStyle) {
urlParams.view = state.diffViewType;
}
commit(types.SET_LOADING, true);
......@@ -142,16 +154,17 @@ export const fetchDiffFilesMeta = ({ commit, state }) => {
});
return axios
.get(state.endpointMetadata)
.get(mergeUrlParams(urlParams, state.endpointMetadata))
.then(({ data }) => {
const strippedData = { ...data };
delete strippedData.diff_files;
commit(types.SET_LOADING, false);
commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []);
commit(types.SET_DIFF_DATA, strippedData);
prepareDiffData(data);
worker.postMessage(data.diff_files);
worker.postMessage(prepareDiffData(data, state.diffFiles));
return data;
})
.catch(() => worker.terminate());
......@@ -226,7 +239,7 @@ export const startRenderDiffsQueue = ({ state, commit }) => {
const nextFile = state.diffFiles.find(
file =>
!file.renderIt &&
(file.viewer && (!file.viewer.collapsed || !file.viewer.name === diffViewerModes.text)),
(file.viewer && (!file.viewer.collapsed || file.viewer.name !== diffViewerModes.text)),
);
if (nextFile) {
......
......@@ -148,8 +148,8 @@ export default {
},
[types.ADD_COLLAPSED_DIFFS](state, { file, data }) {
prepareDiffData(data);
const [newFileData] = data.diff_files.filter(f => f.file_hash === file.file_hash);
const files = prepareDiffData(data);
const [newFileData] = files.filter(f => f.file_hash === file.file_hash);
const selectedFile = state.diffFiles.find(f => f.file_hash === file.file_hash);
Object.assign(selectedFile, { ...newFileData });
},
......
......@@ -217,30 +217,19 @@ function diffFileUniqueId(file) {
return `${file.content_sha}-${file.file_hash}`;
}
function combineDiffFilesWithPriorFiles(files, prior = []) {
files.forEach(file => {
const id = diffFileUniqueId(file);
const oldMatch = prior.find(oldFile => diffFileUniqueId(oldFile) === id);
if (oldMatch) {
const missingInline = !file.highlighted_diff_lines;
const missingParallel = !file.parallel_diff_lines;
if (missingInline) {
Object.assign(file, {
highlighted_diff_lines: oldMatch.highlighted_diff_lines,
});
}
function mergeTwoFiles(target, source) {
const originalInline = target.highlighted_diff_lines;
const originalParallel = target.parallel_diff_lines;
const missingInline = !originalInline.length;
const missingParallel = !originalParallel.length;
if (missingParallel) {
Object.assign(file, {
parallel_diff_lines: oldMatch.parallel_diff_lines,
});
}
}
});
return files;
return {
...target,
highlighted_diff_lines: missingInline ? source.highlighted_diff_lines : originalInline,
parallel_diff_lines: missingParallel ? source.parallel_diff_lines : originalParallel,
renderIt: source.renderIt,
collapsed: source.collapsed,
};
}
function ensureBasicDiffFileLines(file) {
......@@ -260,13 +249,16 @@ function cleanRichText(text) {
}
function prepareLine(line) {
return Object.assign(line, {
rich_text: cleanRichText(line.rich_text),
discussionsExpanded: true,
discussions: [],
hasForm: false,
text: undefined,
});
if (!line.alreadyPrepared) {
Object.assign(line, {
rich_text: cleanRichText(line.rich_text),
discussionsExpanded: true,
discussions: [],
hasForm: false,
text: undefined,
alreadyPrepared: true,
});
}
}
function prepareDiffFileLines(file) {
......@@ -288,11 +280,11 @@ function prepareDiffFileLines(file) {
parallelLinesCount += 1;
prepareLine(line.right);
}
});
Object.assign(file, {
inlineLinesCount: inlineLines.length,
parallelLinesCount,
});
Object.assign(file, {
inlineLinesCount: inlineLines.length,
parallelLinesCount,
});
return file;
......@@ -318,11 +310,26 @@ function finalizeDiffFile(file) {
return file;
}
export function prepareDiffData(diffData, priorFiles) {
return combineDiffFilesWithPriorFiles(diffData.diff_files, priorFiles)
function deduplicateFilesList(files) {
const dedupedFiles = files.reduce((newList, file) => {
const id = diffFileUniqueId(file);
return {
...newList,
[id]: newList[id] ? mergeTwoFiles(newList[id], file) : file,
};
}, {});
return Object.values(dedupedFiles);
}
export function prepareDiffData(diff, priorFiles = []) {
const cleanedFiles = (diff.diff_files || [])
.map(ensureBasicDiffFileLines)
.map(prepareDiffFileLines)
.map(finalizeDiffFile);
return deduplicateFilesList([...priorFiles, ...cleanedFiles]);
}
export function getDiffPositionByLineCode(diffFiles, useSingleDiffStyle) {
......
......@@ -19,8 +19,21 @@ export default {
queryInfo() {
return this.graphData.metrics[0];
},
engineeringNotation() {
return `${roundOffFloat(this.queryInfo.result[0].value[1], 1)}${this.queryInfo.unit}`;
queryResult() {
return this.queryInfo.result[0]?.value[1];
},
/**
* This method formats the query result from a promQL expression
* allowing a user to format the data in percentile values
* by using the `max_value` inner property from the graphData prop
* @returns {(String)}
*/
statValue() {
const chartValue = this.graphData?.max_value
? (this.queryResult / Number(this.graphData.max_value)) * 100
: this.queryResult;
return `${roundOffFloat(chartValue, 1)}${this.queryInfo.unit}`;
},
graphTitle() {
return this.queryInfo.label;
......@@ -33,6 +46,6 @@ export default {
<div class="prometheus-graph-header">
<h5 ref="graphTitle" class="prometheus-graph-title">{{ graphTitle }}</h5>
</div>
<gl-single-stat :value="engineeringNotation" :title="graphTitle" variant="success" />
<gl-single-stat :value="statValue" :title="graphTitle" variant="success" />
</div>
</template>
......@@ -60,7 +60,7 @@ def update_params
# overridden in EE
def permitted_project_params
{
project_params = {
metrics_setting_attributes: [:external_dashboard_url],
error_tracking_setting_attributes: [
......@@ -72,6 +72,12 @@ def permitted_project_params
grafana_integration_attributes: [:token, :grafana_url, :enabled]
}
if Feature.enabled?(:settings_operations_prometheus_service, project)
project_params[:prometheus_integration_attributes] = [:manual_configuration, :api_url]
end
project_params
end
end
end
......
......@@ -322,6 +322,7 @@ class Project < ApplicationRecord
accepts_nested_attributes_for :error_tracking_setting, update_only: true
accepts_nested_attributes_for :metrics_setting, update_only: true, allow_destroy: true
accepts_nested_attributes_for :grafana_integration, update_only: true, allow_destroy: true
accepts_nested_attributes_for :prometheus_service, update_only: true
delegate :feature_available?, :builds_enabled?, :wiki_enabled?,
:merge_requests_enabled?, :forking_enabled?, :issues_enabled?,
......
......@@ -15,6 +15,7 @@ def project_update_params
error_tracking_params
.merge(metrics_setting_params)
.merge(grafana_integration_params)
.merge(prometheus_integration_params)
end
def metrics_setting_params
......@@ -77,6 +78,15 @@ def grafana_integration_params
{ grafana_integration_attributes: attrs.merge(_destroy: destroy) }
end
def prometheus_integration_params
return {} unless attrs = params[:prometheus_integration_attributes]
service = project.find_or_initialize_service(::PrometheusService.to_param)
service.assign_attributes(attrs)
{ prometheus_service_attributes: service.attributes.except(*%w(id project_id created_at updated_at)) }
end
end
end
end
......
---
title: Fix backup restoration with pre-existing wiki
merge_request: 24394
author:
type: fixed
---
title: Add percentile value support to single stat panel types
merge_request: 24813
author:
type: changed
---
title: Separate label entities into own class files
merge_request: 24938
author: Rajendra Kadam
type: added
---
title: Separate entities into own class files
merge_request: 24941
author: Rajendra Kadam
type: added
---
title: Separate job entities into own class files
merge_request: 24948
author: Rajendra Kadam
type: added
---
title: Separate token and template entities into own class files
merge_request: 24955
author: Rajendra Kadam
type: added
---
title: Update handlebars to remove issues from dependency dashboard
merge_request:
author:
type: security
......@@ -143,6 +143,11 @@ their node under pressure.
## How to
### Get access to the GCP Review Apps cluster
You need to [open an access request (internal link)](https://gitlab.com/gitlab-com/access-requests/issues/new)
for the `gcp-review-apps-sg` GCP group.
### Log into my Review App
The default username is `root` and its password can be found in the 1Password
......@@ -163,6 +168,7 @@ secure note named `gitlab-{ce,ee} Review App's root password`.
### Run a Rails console
1. Make sure you [have access to the cluster](#get-access-to-the-gcp-review-apps-cluster) first.
1. [Filter Workloads by your Review App slug](https://console.cloud.google.com/kubernetes/workload?project=gitlab-review-apps),
e.g. `review-qa-raise-e-12chm0`.
1. Find and open the `task-runner` Deployment, e.g. `review-qa-raise-e-12chm0-task-runner`.
......@@ -178,6 +184,7 @@ secure note named `gitlab-{ce,ee} Review App's root password`.
### Dig into a Pod's logs
1. Make sure you [have access to the cluster](#get-access-to-the-gcp-review-apps-cluster) first.
1. [Filter Workloads by your Review App slug](https://console.cloud.google.com/kubernetes/workload?project=gitlab-review-apps),
e.g. `review-qa-raise-e-12chm0`.
1. Find and open the `migrations` Deployment, e.g.
......
......@@ -163,42 +163,6 @@ class NotificationSetting < Grape::Entity
end
end
class LabelBasic < Grape::Entity
expose :id, :name, :color, :description, :description_html, :text_color
end
class Label < LabelBasic
with_options if: lambda { |_, options| options[:with_counts] } do
expose :open_issues_count do |label, options|
label.open_issues_count(options[:current_user])
end
expose :closed_issues_count do |label, options|
label.closed_issues_count(options[:current_user])
end
expose :open_merge_requests_count do |label, options|
label.open_merge_requests_count(options[:current_user])
end
end
expose :subscribed do |label, options|
label.subscribed?(options[:current_user], options[:parent])
end
end
class GroupLabel < Label
end
class ProjectLabel < Label
expose :priority do |label, options|
label.priority(options[:parent])
end
expose :is_project_label do |label, options|
label.is_a?(::ProjectLabel)
end
end
class List < Grape::Entity
expose :id
expose :label, using: Entities::LabelBasic
......@@ -242,130 +206,6 @@ class BroadcastMessage < Grape::Entity
expose :message, :starts_at, :ends_at, :color, :font, :target_path, :broadcast_type
end
class ApplicationStatistics < Grape::Entity
include ActionView::Helpers::NumberHelper
include CountHelper
expose :forks do |counts|
approximate_fork_count_with_delimiters(counts)
end
expose :issues do |counts|
approximate_count_with_delimiters(counts, ::Issue)
end
expose :merge_requests do |counts|
approximate_count_with_delimiters(counts, ::MergeRequest)
end
expose :notes do |counts|
approximate_count_with_delimiters(counts, ::Note)
end
expose :snippets do |counts|
approximate_count_with_delimiters(counts, ::Snippet)
end
expose :ssh_keys do |counts|
approximate_count_with_delimiters(counts, ::Key)
end
expose :milestones do |counts|
approximate_count_with_delimiters(counts, ::Milestone)
end
expose :users do |counts|
approximate_count_with_delimiters(counts, ::User)
end
expose :projects do |counts|
approximate_count_with_delimiters(counts, ::Project)
end
expose :groups do |counts|
approximate_count_with_delimiters(counts, ::Group)
end
expose :active_users do |_|
number_with_delimiter(::User.active.count)
end
end
class ApplicationSetting < Grape::Entity
def self.exposed_attributes
attributes = ::ApplicationSettingsHelper.visible_attributes
attributes.delete(:performance_bar_allowed_group_path)
attributes.delete(:performance_bar_enabled)
attributes.delete(:allow_local_requests_from_hooks_and_services)
# let's not expose the secret key in a response
attributes.delete(:asset_proxy_secret_key)
attributes.delete(:eks_secret_access_key)
attributes
end
expose :id, :performance_bar_allowed_group_id
expose(*exposed_attributes)
expose(:restricted_visibility_levels) do |setting, _options|
setting.restricted_visibility_levels.map { |level| Gitlab::VisibilityLevel.string_level(level) }
end
expose(:default_project_visibility) { |setting, _options| Gitlab::VisibilityLevel.string_level(setting.default_project_visibility) }
expose(:default_snippet_visibility) { |setting, _options| Gitlab::VisibilityLevel.string_level(setting.default_snippet_visibility) }
expose(:default_group_visibility) { |setting, _options| Gitlab::VisibilityLevel.string_level(setting.default_group_visibility) }
expose(*::ApplicationSettingsHelper.external_authorization_service_attributes)
# support legacy names, can be removed in v5
expose :password_authentication_enabled_for_web, as: :password_authentication_enabled
expose :password_authentication_enabled_for_web, as: :signin_enabled
expose :allow_local_requests_from_web_hooks_and_services, as: :allow_local_requests_from_hooks_and_services
end
class Appearance < Grape::Entity
expose :title
expose :description
expose :logo do |appearance, options|
appearance.logo.url
end
expose :header_logo do |appearance, options|
appearance.header_logo.url
end
expose :favicon do |appearance, options|
appearance.favicon.url
end
expose :new_project_guidelines
expose :header_message
expose :footer_message
expose :message_background_color
expose :message_font_color
expose :email_header_and_footer_enabled
end
# deprecated old Release representation
class TagRelease < Grape::Entity
expose :tag, as: :tag_name
expose :description
end
module Releases
class Link < Grape::Entity
expose :id
expose :name
expose :url
expose :external?, as: :external
end
class Source < Grape::Entity
expose :format
expose :url
end
end
class Release < Grape::Entity
include ::API::Helpers::Presentable
......@@ -477,40 +317,6 @@ class RunnerRegistrationDetails < Grape::Entity
expose :id, :token
end
class JobArtifactFile < Grape::Entity
expose :filename
expose :cached_size, as: :size
end
class JobArtifact < Grape::Entity
expose :file_type, :size, :filename, :file_format
end
class JobBasic < Grape::Entity
expose :id, :status, :stage, :name, :ref, :tag, :coverage, :allow_failure
expose :created_at, :started_at, :finished_at
expose :duration
expose :user, with: Entities::User
expose :commit, with: Entities::Commit
expose :pipeline, with: Entities::PipelineBasic
expose :web_url do |job, _options|
Gitlab::Routing.url_helpers.project_job_url(job.project, job)
end
end
class Job < JobBasic
# artifacts_file is included in job_artifacts, but kept for backward compatibility (remove in api/v5)
expose :artifacts_file, using: JobArtifactFile, if: -> (job, opts) { job.artifacts? }
expose :job_artifacts, as: :artifacts, using: JobArtifact
expose :runner, with: Runner
expose :artifacts_expire_at
end
class JobBasicWithProject < JobBasic
expose :project, with: Entities::ProjectIdentity
end
class Trigger < Grape::Entity
include ::API::Helpers::Presentable
......@@ -585,32 +391,6 @@ class License < LicenseBasic
expose :content
end
class TemplatesList < Grape::Entity
expose :key
expose :name
end
class Template < Grape::Entity
expose :name, :content
end
class BroadcastMessage < Grape::Entity
expose :id, :message, :starts_at, :ends_at, :color, :font
expose :active?, as: :active
end
class PersonalAccessToken < Grape::Entity
expose :id, :name, :revoked, :created_at, :scopes
expose :active?, as: :active
expose :expires_at do |personal_access_token|
personal_access_token.expires_at ? personal_access_token.expires_at.strftime("%Y-%m-%d") : nil
end
end
class PersonalAccessTokenWithToken < PersonalAccessToken
expose :token
end
class ImpersonationToken < PersonalAccessToken
expose :impersonation
end
......
# frozen_string_literal: true