diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-10 18:09:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-10 18:09:11 +0300 |
commit | d2091d1e924e2887eb9db4fad761965a24d024f1 (patch) | |
tree | 482fe37d97a4169895ae3ddf6d6f42e6f632cbb9 /app | |
parent | 152b3268d701b54cac9b615a0e29e0e5726bfd99 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
18 files changed, 133 insertions, 64 deletions
diff --git a/app/assets/javascripts/access_tokens/components/projects_token_selector.vue b/app/assets/javascripts/access_tokens/components/projects_token_selector.vue index 37ef3f28236..cc5532696c7 100644 --- a/app/assets/javascripts/access_tokens/components/projects_token_selector.vue +++ b/app/assets/javascripts/access_tokens/components/projects_token_selector.vue @@ -8,7 +8,7 @@ import { } from '@gitlab/ui'; import produce from 'immer'; -import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils'; +import { convertToGraphQLIds, convertNodeIdsFromGraphQLIds } from '~/graphql_shared/utils'; import getProjectsQuery from '../graphql/queries/get_projects.query.graphql'; @@ -51,7 +51,7 @@ export default { }, update({ projects }) { return { - list: this.formatProjectNodes(projects), + list: convertNodeIdsFromGraphQLIds(projects.nodes), pageInfo: projects.pageInfo, }; }, @@ -64,7 +64,7 @@ export default { query: getProjectsQuery, variables() { return { - ids: this.initialProjectIds.map((id) => convertToGraphQLId(GRAPHQL_ENTITY_TYPE, id)), + ids: convertToGraphQLIds(GRAPHQL_ENTITY_TYPE, this.initialProjectIds), }; }, manual: true, @@ -72,7 +72,7 @@ export default { return !this.initialProjectIds.length; }, result({ data: { projects } }) { - this.$emit('input', this.formatProjectNodes(projects)); + this.$emit('input', convertNodeIdsFromGraphQLIds(projects.nodes)); }, }, }, @@ -88,12 +88,6 @@ export default { }; }, methods: { - formatProjectNodes(projects) { - return projects.nodes.map((project) => ({ - ...project, - id: getIdFromGraphQLId(project.id), - })); - }, handleSearch(query) { this.isSearching = true; this.searchQuery = query; diff --git a/app/assets/javascripts/experimentation/constants.js b/app/assets/javascripts/experimentation/constants.js new file mode 100644 index 00000000000..b7e61d43b11 --- /dev/null +++ b/app/assets/javascripts/experimentation/constants.js @@ -0,0 +1 @@ +export const TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0'; diff --git a/app/assets/javascripts/experiment_tracking.js b/app/assets/javascripts/experimentation/experiment_tracking.js index 2a725886679..c721828036e 100644 --- a/app/assets/javascripts/experiment_tracking.js +++ b/app/assets/javascripts/experimentation/experiment_tracking.js @@ -1,16 +1,15 @@ -import { get } from 'lodash'; import Tracking from '~/tracking'; - -const TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0'; +import { TRACKING_CONTEXT_SCHEMA } from './constants'; +import { getExperimentData } from './utils'; export default class ExperimentTracking { constructor(experimentName, trackingArgs = {}) { this.trackingArgs = trackingArgs; - this.experimentData = get(window, ['gon', 'global', 'experiment', experimentName]); + this.data = getExperimentData(experimentName); } event(action) { - if (!this.experimentData) { + if (!this.data) { return false; } @@ -18,7 +17,7 @@ export default class ExperimentTracking { ...this.trackingArgs, context: { schema: TRACKING_CONTEXT_SCHEMA, - data: this.experimentData, + data: this.data, }, }); } diff --git a/app/assets/javascripts/experimentation/utils.js b/app/assets/javascripts/experimentation/utils.js new file mode 100644 index 00000000000..d3e7800f643 --- /dev/null +++ b/app/assets/javascripts/experimentation/utils.js @@ -0,0 +1,10 @@ +// This file only applies to use of experiments through https://gitlab.com/gitlab-org/gitlab-experiment +import { get } from 'lodash'; + +export function getExperimentData(experimentName) { + return get(window, ['gon', 'experiment', experimentName]); +} + +export function isExperimentVariant(experimentName, variantName) { + return getExperimentData(experimentName)?.variant === variantName; +} diff --git a/app/assets/javascripts/graphql_shared/utils.js b/app/assets/javascripts/graphql_shared/utils.js index 4715bbc94f6..e64e8009a5f 100644 --- a/app/assets/javascripts/graphql_shared/utils.js +++ b/app/assets/javascripts/graphql_shared/utils.js @@ -1,3 +1,5 @@ +import { isArray } from 'lodash'; + /** * Ids generated by GraphQL endpoints are usually in the format * gid://gitlab/Environments/123. This method extracts Id number @@ -52,3 +54,35 @@ export const convertToGraphQLId = (type, id) => { * @returns {Array} */ export const convertToGraphQLIds = (type, ids) => ids.map((id) => convertToGraphQLId(type, id)); + +/** + * Ids generated by GraphQL endpoints are usually in the format + * gid://gitlab/Groups/123. This method takes an array of + * GraphQL Ids and converts them to a number. + * + * @param {Array} ids An array of GraphQL IDs + * @returns {Array} + */ +export const convertFromGraphQLIds = (ids) => { + if (!isArray(ids)) { + throw new TypeError(`ids must be an array; got ${typeof ids}`); + } + + return ids.map((id) => getIdFromGraphQLId(id)); +}; + +/** + * Ids generated by GraphQL endpoints are usually in the format + * gid://gitlab/Groups/123. This method takes an array of nodes + * and converts the `id` properties from a GraphQL Id to a number. + * + * @param {Array} nodes An array of nodes with an `id` property + * @returns {Array} + */ +export const convertNodeIdsFromGraphQLIds = (nodes) => { + if (!isArray(nodes)) { + throw new TypeError(`nodes must be an array; got ${typeof nodes}`); + } + + return nodes.map((node) => (node.id ? { ...node, id: getIdFromGraphQLId(node.id) } : node)); +}; diff --git a/app/assets/javascripts/lib/utils/experimentation.js b/app/assets/javascripts/lib/utils/experimentation.js deleted file mode 100644 index 555e76055e0..00000000000 --- a/app/assets/javascripts/lib/utils/experimentation.js +++ /dev/null @@ -1,3 +0,0 @@ -export function isExperimentEnabled(experimentKey) { - return Boolean(window.gon?.experiments?.[experimentKey]); -} diff --git a/app/assets/javascripts/projects/upload_file_experiment.js b/app/assets/javascripts/projects/upload_file_experiment.js index e4e4c609f0a..7d61df36a75 100644 --- a/app/assets/javascripts/projects/upload_file_experiment.js +++ b/app/assets/javascripts/projects/upload_file_experiment.js @@ -1,4 +1,4 @@ -import ExperimentTracking from '~/experiment_tracking'; +import ExperimentTracking from '~/experimentation/experiment_tracking'; function trackEvent(eventName) { const isEmpty = Boolean(document.querySelector('.project-home-panel.empty-project')); diff --git a/app/assets/javascripts/tracking.js b/app/assets/javascripts/tracking.js index 008eda5e505..01de034417e 100644 --- a/app/assets/javascripts/tracking.js +++ b/app/assets/javascripts/tracking.js @@ -1,4 +1,6 @@ -import { omitBy, isUndefined, get } from 'lodash'; +import { omitBy, isUndefined } from 'lodash'; +import { TRACKING_CONTEXT_SCHEMA } from '~/experimentation/constants'; +import { getExperimentData } from '~/experimentation/utils'; const standardContext = { ...window.gl?.snowplowStandardContext }; @@ -32,8 +34,8 @@ const createEventPayload = (el, { suffix = '' } = {}) => { let context = el.dataset.trackContext; if (el.dataset.trackExperiment) { - const data = get(window, ['gon', 'global', 'experiment', el.dataset.trackExperiment]); - if (data) context = { schema: 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0', data }; + const data = getExperimentData(el.dataset.trackExperiment); + if (data) context = { schema: TRACKING_CONTEXT_SCHEMA, data }; } const data = { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue index f0259a975db..01e0b91bd4a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue @@ -1,12 +1,15 @@ <script> /* eslint-disable vue/no-v-html */ -import { GlButton } from '@gitlab/ui'; +import { GlButton, GlSprintf, GlLink } from '@gitlab/ui'; import emptyStateSVG from 'icons/_mr_widget_empty_state.svg'; +import { helpPagePath } from '~/helpers/help_page_helper'; export default { name: 'MRWidgetNothingToMerge', components: { GlButton, + GlSprintf, + GlLink, }, props: { mr: { @@ -17,6 +20,7 @@ export default { data() { return { emptyStateSVG }; }, + ciHelpPage: helpPagePath('/ci/quick_start/index.html'), }; </script> @@ -30,25 +34,20 @@ export default { </div> <div class="text col-md-7 order-md-first col-12"> <p class="highlight"> - {{ - s__( - 'mrWidgetNothingToMerge|Merge requests are a place to propose changes you have made to a project and discuss those changes with others.', - ) - }} + {{ s__('mrWidgetNothingToMerge|This merge request contains no changes.') }} </p> <p> - {{ - s__( - 'mrWidgetNothingToMerge|Interested parties can even contribute by pushing commits if they want to.', - ) - }} - </p> - <p> - {{ - s__( - "mrWidgetNothingToMerge|Currently there are no changes in this merge request's source branch. Please push new commits or use a different branch.", - ) - }} + <gl-sprintf + :message=" + s__( + 'mrWidgetNothingToMerge|Use merge requests to propose changes to your project and discuss them with your team. To make changes, push a commit or edit this merge request to use a different branch. With %{linkStart}CI/CD%{linkEnd}, automatically test your changes before merging.', + ) + " + > + <template #link="{ content }"> + <gl-link :href="$options.ciHelpPage" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> </p> <div> <gl-button @@ -56,6 +55,7 @@ export default { :href="mr.newBlobPath" category="secondary" variant="success" + data-testid="createFileButton" > {{ __('Create file') }} </gl-button> diff --git a/app/experiments/application_experiment.rb b/app/experiments/application_experiment.rb index ec73382ed3b..6ba851fbc8b 100644 --- a/app/experiments/application_experiment.rb +++ b/app/experiments/application_experiment.rb @@ -11,7 +11,9 @@ class ApplicationExperiment < Gitlab::Experiment # rubocop:disable Gitlab/Namesp def publish(_result) track(:assignment) # track that we've assigned a variant for this context - Gon.global.push({ experiment: { name => signature } }, true) # push the experiment data to the client + + # push the experiment data to the client + Gon.push({ experiment: { name => signature } }, true) if in_request_cycle? end def track(action, **event_args) @@ -47,6 +49,12 @@ class ApplicationExperiment < Gitlab::Experiment # rubocop:disable Gitlab/Namesp name.tr('/', '_') end + def in_request_cycle? + # Gon is only accessible when having a request. This will be fixed with + # https://gitlab.com/gitlab-org/gitlab/-/issues/323352 + context.instance_variable_defined?(:@request) + end + def resolve_variant_name case rollout_strategy when :round_robin diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index ba09c0a9dd8..3fe31a64984 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -310,10 +310,28 @@ class MergeRequest < ApplicationRecord end scope :by_target_branch, ->(branch_name) { where(target_branch: branch_name) } scope :order_merged_at, ->(direction) do - query = join_metrics.order(Gitlab::Database.nulls_last_order('merge_request_metrics.merged_at', direction)) - - # Add `merge_request_metrics.merged_at` to the `SELECT` in order to make the keyset pagination work. - query.select(*query.arel.projections, MergeRequest::Metrics.arel_table[:merged_at].as('"merge_request_metrics.merged_at"')) + reverse_direction = { 'ASC' => 'DESC', 'DESC' => 'ASC' } + reversed_direction = reverse_direction[direction] || raise("Unknown sort direction was given: #{direction}") + + order = Gitlab::Pagination::Keyset::Order.build([ + Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: 'merge_request_metrics_merged_at', + column_expression: MergeRequest::Metrics.arel_table[:merged_at], + order_expression: Gitlab::Database.nulls_last_order('merge_request_metrics.merged_at', direction), + reversed_order_expression: Gitlab::Database.nulls_first_order('merge_request_metrics.merged_at', reversed_direction), + order_direction: direction, + nullable: :nulls_last, + distinct: false, + add_to_projections: true + ), + Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: 'merge_request_metrics_id', + order_expression: MergeRequest::Metrics.arel_table[:id].desc, + add_to_projections: true + ) + ]) + + order.apply_cursor_conditions(join_metrics).order(order) end scope :order_merged_at_asc, -> { order_merged_at('ASC') } scope :order_merged_at_desc, -> { order_merged_at('DESC') } @@ -411,8 +429,8 @@ class MergeRequest < ApplicationRecord def self.sort_by_attribute(method, excluded_labels: []) case method.to_s - when 'merged_at', 'merged_at_asc' then order_merged_at_asc.with_order_id_desc - when 'merged_at_desc' then order_merged_at_desc.with_order_id_desc + when 'merged_at', 'merged_at_asc' then order_merged_at_asc + when 'merged_at_desc' then order_merged_at_desc else super end diff --git a/app/models/project.rb b/app/models/project.rb index d960732b16f..ef92dda443a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -493,10 +493,22 @@ class Project < ApplicationRecord { column: arel_table["description"], multiplier: 0.2 } ]) - query = reorder(order_expression.desc, arel_table['id'].desc) + order = Gitlab::Pagination::Keyset::Order.build([ + Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: 'similarity', + column_expression: order_expression, + order_expression: order_expression.desc, + order_direction: :desc, + distinct: false, + add_to_projections: true + ), + Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: 'id', + order_expression: Project.arel_table[:id].desc + ) + ]) - query = query.select(*query.arel.projections, order_expression.as('similarity')) if include_in_select - query + order.apply_cursor_conditions(reorder(order)) end scope :with_packages, -> { joins(:packages) } diff --git a/app/models/project_services/discord_service.rb b/app/models/project_services/discord_service.rb index 941b7f64263..37bbb9b8752 100644 --- a/app/models/project_services/discord_service.rb +++ b/app/models/project_services/discord_service.rb @@ -59,6 +59,9 @@ class DiscordService < ChatNotificationService embed.description = (message.pretext + "\n" + Array.wrap(message.attachments).join("\n")).gsub(ATTACHMENT_REGEX, " \\k<entry> - \\k<name>\n") end end + rescue RestClient::Exception => error + log_error(error.message) + false end def custom_data(data) diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 20e1636b2fa..f6ea1828ab6 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -1106,8 +1106,7 @@ :resource_boundary: :unknown :weight: 1 :idempotent: - :tags: - - :requires_disk_io + :tags: [] - :name: pipeline_background:ci_build_trace_chunk_flush :feature_category: :continuous_integration :has_external_dependencies: @@ -1251,8 +1250,7 @@ :resource_boundary: :cpu :weight: 5 :idempotent: - :tags: - - :requires_disk_io + :tags: [] - :name: pipeline_processing:build_queue :feature_category: :continuous_integration :has_external_dependencies: @@ -1484,8 +1482,7 @@ :resource_boundary: :unknown :weight: 2 :idempotent: - :tags: - - :requires_disk_io + :tags: [] - :name: ci_delete_objects :feature_category: :continuous_integration :has_external_dependencies: @@ -1645,8 +1642,7 @@ :resource_boundary: :unknown :weight: 1 :idempotent: - :tags: - - :requires_disk_io + :tags: [] - :name: export_csv :feature_category: :issue_tracking :has_external_dependencies: diff --git a/app/workers/archive_trace_worker.rb b/app/workers/archive_trace_worker.rb index b0c5bef336a..3ddb5686bf2 100644 --- a/app/workers/archive_trace_worker.rb +++ b/app/workers/archive_trace_worker.rb @@ -4,8 +4,6 @@ class ArchiveTraceWorker # rubocop:disable Scalability/IdempotentWorker include ApplicationWorker include PipelineBackgroundQueue - tags :requires_disk_io - # rubocop: disable CodeReuse/ActiveRecord def perform(job_id) Ci::Build.without_archived_trace.find_by(id: job_id).try do |job| diff --git a/app/workers/build_finished_worker.rb b/app/workers/build_finished_worker.rb index 1f4ebe58638..3f99b30fdf7 100644 --- a/app/workers/build_finished_worker.rb +++ b/app/workers/build_finished_worker.rb @@ -7,7 +7,6 @@ class BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker queue_namespace :pipeline_processing urgency :high worker_resource_boundary :cpu - tags :requires_disk_io ARCHIVE_TRACES_IN = 2.minutes.freeze diff --git a/app/workers/chat_notification_worker.rb b/app/workers/chat_notification_worker.rb index 94a0197b862..5fab437f49f 100644 --- a/app/workers/chat_notification_worker.rb +++ b/app/workers/chat_notification_worker.rb @@ -7,7 +7,6 @@ class ChatNotificationWorker # rubocop:disable Scalability/IdempotentWorker sidekiq_options retry: false feature_category :chatops - tags :requires_disk_io urgency :low # Can't be high as it has external dependencies weight 2 worker_has_external_dependencies! diff --git a/app/workers/expire_build_instance_artifacts_worker.rb b/app/workers/expire_build_instance_artifacts_worker.rb index a5571473b43..e6cd60a3e47 100644 --- a/app/workers/expire_build_instance_artifacts_worker.rb +++ b/app/workers/expire_build_instance_artifacts_worker.rb @@ -4,7 +4,6 @@ class ExpireBuildInstanceArtifactsWorker # rubocop:disable Scalability/Idempoten include ApplicationWorker feature_category :continuous_integration - tags :requires_disk_io # rubocop: disable CodeReuse/ActiveRecord def perform(build_id) |