Skip to content

Commit f0471bf

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent 4abd579 commit f0471bf

File tree

90 files changed

+1775
-475
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+1775
-475
lines changed

.gitlab/ci/review.gitlab-ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
review-cleanup:
2-
timeout: 15min
2+
timeout: 30min
33
extends:
44
- .default-retry
55
- .review:rules:review-cleanup

app/assets/javascripts/boards/components/board_list_header.vue

-11
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
1515
import { n__, s__ } from '~/locale';
1616
import Tracking from '~/tracking';
1717
import { TYPE_ISSUE } from '~/issues/constants';
18-
import { formatDate } from '~/lib/utils/datetime_utility';
1918
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
2019
import setActiveBoardItemMutation from 'ee_else_ce/boards/graphql/client/set_active_board_item.mutation.graphql';
2120
import AccessorUtilities from '~/lib/utils/accessor';
@@ -302,16 +301,6 @@ export default {
302301
});
303302
}
304303
},
305-
/**
306-
* TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/344619
307-
* This method also exists as a utility function in ee/../iterations/utils.js
308-
* Remove the duplication when the EE code is separated from this compoment.
309-
*/
310-
getIterationPeriod({ startDate, dueDate }) {
311-
const start = formatDate(startDate, 'mmm d, yyyy', true);
312-
const due = formatDate(dueDate, 'mmm d, yyyy', true);
313-
return `${start} - ${due}`;
314-
},
315304
updateLocalCollapsedStatus(collapsed) {
316305
this.$apollo.mutate({
317306
mutation: toggleCollapsedMutations[this.issuableType].mutation,

app/assets/javascripts/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stage_jobs.query.graphql

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ query getPipelineStageJobs($id: CiStageID!) {
88
id
99
action {
1010
id
11+
confirmationMessage
1112
icon
1213
path
1314
title
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<script>
2+
import { GlButton, GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
3+
4+
export default {
5+
name: 'JobActionButton',
6+
components: {
7+
GlButton,
8+
GlIcon,
9+
GlLoadingIcon,
10+
},
11+
directives: {
12+
GlTooltip: GlTooltipDirective,
13+
},
14+
props: {
15+
jobId: {
16+
type: String,
17+
required: true,
18+
},
19+
jobAction: {
20+
type: Object,
21+
required: true,
22+
},
23+
jobName: {
24+
type: String,
25+
required: true,
26+
},
27+
},
28+
data() {
29+
return {
30+
isLoading: false,
31+
showConfirmationModal: false,
32+
};
33+
},
34+
};
35+
</script>
36+
37+
<template>
38+
<div>
39+
<gl-button
40+
v-gl-tooltip.viewport.right
41+
:title="jobAction.title"
42+
:aria-label="jobAction.title"
43+
:disabled="isLoading"
44+
class="gl-rounded-full! gl-p-0! gl-w-6 gl-h-6"
45+
>
46+
<gl-loading-icon v-if="isLoading" size="sm" class="gl-m-2" />
47+
<gl-icon v-else :name="jobAction.icon" :size="12" />
48+
</gl-button>
49+
</div>
50+
</template>

app/assets/javascripts/ci/pipeline_mini_graph/job_item.vue

+22-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
<script>
22
import { GlDisclosureDropdownItem, GlTooltipDirective } from '@gitlab/ui';
33
import { sprintf } from '~/locale';
4+
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
45
import delayedJobMixin from '~/ci/mixins/delayed_job_mixin';
56
import JobNameComponent from '~/ci/common/private/job_name_component.vue';
7+
import JobActionButton from './job_action_button.vue';
68
79
export default {
810
name: 'JobItem',
911
components: {
12+
JobActionButton,
1013
JobNameComponent,
1114
GlDisclosureDropdownItem,
1215
},
@@ -21,6 +24,9 @@ export default {
2124
},
2225
},
2326
computed: {
27+
hasJobAction() {
28+
return Boolean(this.status?.action?.id);
29+
},
2430
item() {
2531
return {
2632
text: this.job.name,
@@ -36,21 +42,29 @@ export default {
3642
if (this.isDelayedJob) {
3743
return sprintf(statusTooltip, { remainingTime: this.remainingTime });
3844
}
39-
return statusTooltip;
45+
return capitalizeFirstCharacter(statusTooltip);
4046
},
4147
},
4248
};
4349
</script>
4450
<template>
4551
<gl-disclosure-dropdown-item :item="item">
4652
<template #list-item>
47-
<job-name-component
48-
v-gl-tooltip.viewport.left
49-
class="-gl-my-2"
50-
:title="tooltipText"
51-
:name="job.name"
52-
:status="status"
53-
/>
53+
<div class="gl-flex -gl-my-2 gl-h-6">
54+
<job-name-component
55+
v-gl-tooltip.viewport.left
56+
class="-gl-my-2"
57+
:title="tooltipText"
58+
:name="job.name"
59+
:status="status"
60+
/>
61+
<job-action-button
62+
v-if="hasJobAction"
63+
:job-id="job.id"
64+
:job-action="status.action"
65+
:job-name="job.name"
66+
/>
67+
</div>
5468
</template>
5569
</gl-disclosure-dropdown-item>
5670
</template>

app/assets/javascripts/ci/runner/components/runner_job_status_badge.vue

-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
I18N_JOB_STATUS_ACTIVE,
55
I18N_JOB_STATUS_IDLE,
66
JOB_STATUS_ACTIVE,
7-
JOB_STATUS_RUNNING,
87
JOB_STATUS_IDLE,
98
} from '../constants';
109
@@ -26,7 +25,6 @@ export default {
2625
badge() {
2726
switch (this.jobStatus) {
2827
case JOB_STATUS_ACTIVE:
29-
case JOB_STATUS_RUNNING:
3028
return {
3129
classes: 'gl-text-blue-600! gl-shadow-inner-1-gray-400 gl-border-blue-600!',
3230
label: I18N_JOB_STATUS_ACTIVE,

app/assets/javascripts/ci/runner/constants.js

-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ export const STATUS_STALE = 'STALE';
164164
// CiRunnerJobExecutionStatus
165165

166166
export const JOB_STATUS_ACTIVE = 'ACTIVE';
167-
export const JOB_STATUS_RUNNING = 'RUNNING';
168167
export const JOB_STATUS_IDLE = 'IDLE';
169168

170169
// CiRunnerAccessLevel

app/models/import/source_user_placeholder_reference.rb

+32
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
module Import
44
class SourceUserPlaceholderReference < ApplicationRecord
5+
include BulkInsertSafe
6+
57
self.table_name = 'import_source_user_placeholder_references'
68

79
belongs_to :source_user, class_name: 'Import::SourceUser'
@@ -16,6 +18,36 @@ class SourceUserPlaceholderReference < ApplicationRecord
1618

1719
attribute :composite_key, :ind_jsonb
1820

21+
# If an element is ever added to this array, ensure that `.from_serialized` handles receiving
22+
# older versions of the array by filling in missing values with defaults. We'd keep that in place
23+
# for at least one release cycle to ensure backward compatibility.
24+
SERIALIZABLE_ATTRIBUTES = %w[
25+
composite_key
26+
model
27+
namespace_id
28+
numeric_key
29+
source_user_id
30+
user_reference_column
31+
].freeze
32+
33+
SerializationError = Class.new(StandardError)
34+
35+
def to_serialized
36+
Gitlab::Json.dump(attributes.slice(*SERIALIZABLE_ATTRIBUTES).to_h.values)
37+
end
38+
39+
class << self
40+
def from_serialized(serialized_reference)
41+
deserialized = Gitlab::Json.parse(serialized_reference)
42+
43+
raise SerializationError if deserialized.size != SERIALIZABLE_ATTRIBUTES.size
44+
45+
attributes = SERIALIZABLE_ATTRIBUTES.zip(deserialized).to_h
46+
47+
new(attributes.merge(created_at: Time.zone.now))
48+
end
49+
end
50+
1951
private
2052

2153
def validate_numeric_or_composite_key_present

app/models/namespace_setting.rb

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class NamespaceSetting < ApplicationRecord
2020

2121
enum jobs_to_be_done: { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5 }, _suffix: true
2222
enum enabled_git_access_protocol: { all: 0, ssh: 1, http: 2 }, _suffix: true
23+
enum seat_control: { off: 0, user_cap: 1 }, _prefix: true
2324

2425
attribute :default_branch_protection_defaults, default: -> { {} }
2526

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# frozen_string_literal: true
2+
3+
module Import
4+
module PlaceholderReferences
5+
class BaseService
6+
include Services::ReturnServiceResponses
7+
8+
def initialize(import_source:, import_uid:)
9+
@import_source = import_source
10+
@import_uid = import_uid
11+
end
12+
13+
private
14+
15+
attr_reader :import_source, :import_uid, :reference
16+
17+
def cache
18+
Gitlab::Cache::Import::Caching
19+
end
20+
21+
def cache_key
22+
@cache_key ||= [:'placeholder-reference', import_source, import_uid].join(':')
23+
end
24+
25+
def logger
26+
Framework::Logger
27+
end
28+
29+
def log_info(...)
30+
logger.info(logger_params(...))
31+
end
32+
33+
def log_error(...)
34+
logger.error(logger_params(...))
35+
end
36+
37+
def logger_params(message:, **params)
38+
params.merge(
39+
message: message,
40+
import_source: import_source,
41+
import_uid: import_uid
42+
)
43+
end
44+
end
45+
end
46+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# frozen_string_literal: true
2+
3+
module Import
4+
module PlaceholderReferences
5+
class LoadService < BaseService
6+
BATCH_LIMIT = 500
7+
8+
def initialize(import_source:, import_uid:)
9+
super(import_source: import_source, import_uid: import_uid)
10+
11+
@processed_count = 0
12+
@error_count = 0
13+
end
14+
15+
def execute
16+
log_info(message: 'Processing placeholder references')
17+
18+
while (batch = next_batch).present?
19+
load!(batch)
20+
21+
# End this loop if we know that we cleared the set earlier.
22+
# This prevents processing just a few records at a time if an import is simultaneously writing data to Redis.
23+
break if batch.size < BATCH_LIMIT
24+
end
25+
26+
log_info(
27+
message: 'Processed placeholder references',
28+
processed_count: processed_count,
29+
error_count: error_count
30+
)
31+
32+
success(processed_count: processed_count, error_count: error_count)
33+
end
34+
35+
private
36+
37+
attr_accessor :error_count, :processed_count
38+
39+
def next_batch
40+
cache.limited_values_from_set(cache_key, limit: BATCH_LIMIT)
41+
end
42+
43+
def load!(batch)
44+
to_load = batch.filter_map do |item|
45+
SourceUserPlaceholderReference.from_serialized(item)
46+
rescue JSON::ParserError, SourceUserPlaceholderReference::SerializationError => e
47+
log_error(item, e)
48+
nil
49+
end
50+
51+
begin
52+
bulk_insert!(to_load)
53+
rescue ActiveRecord::RecordInvalid => e
54+
# We optimise for all records being valid and only filter for validity
55+
# when there was a problem
56+
to_load.reject! do |item|
57+
next false if item.valid?
58+
59+
log_error(item.attributes, e)
60+
true
61+
end
62+
63+
# Try again
64+
bulk_insert!(to_load)
65+
rescue ActiveRecord::InvalidForeignKey => e
66+
# This is an unrecoverable situation where we allow the error to clear the batch
67+
log_error(to_load, e)
68+
end
69+
70+
clear_batch!(batch)
71+
end
72+
73+
def bulk_insert!(to_load)
74+
Import::SourceUserPlaceholderReference.bulk_insert!(to_load)
75+
end
76+
77+
def clear_batch!(batch)
78+
processed_count = batch.size
79+
80+
self.processed_count += processed_count
81+
82+
cache.set_remove(cache_key, batch)
83+
end
84+
85+
def log_error(item, exception)
86+
super(
87+
message: 'Error processing placeholder reference',
88+
item: item,
89+
exception: {
90+
class: exception.class,
91+
message: exception.message
92+
}
93+
)
94+
95+
self.error_count += 1
96+
end
97+
end
98+
end
99+
end

0 commit comments

Comments
 (0)