diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 9fbb089d973..afe900f39a6 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -1001,6 +1001,7 @@
- <<: *if-merge-request-targeting-stable-branch
allow_failure: true
- <<: *if-ruby3-branch
+ allow_failure: true
- <<: *if-dot-com-gitlab-org-and-security-merge-request-manual-ff-package-and-e2e
changes: *feature-flag-development-config-patterns
when: manual
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js b/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js
index 1fd87b9897c..264c2629433 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js
@@ -19,9 +19,14 @@ export const I18N = {
),
disallowForcePushDescription: s__('BranchRules|Force push is not allowed.'),
approvalsTitle: s__('BranchRules|Approvals'),
+ manageApprovalsLinkTitle: s__('BranchRules|Manage in Merge Request Approvals'),
+ approvalsDescription: s__(
+ 'BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Lean more.%{linkEnd}',
+ ),
statusChecksTitle: s__('BranchRules|Status checks'),
allowedToPushHeader: s__('BranchRules|Allowed to push (%{total})'),
allowedToMergeHeader: s__('BranchRules|Allowed to merge (%{total})'),
+ approvalsHeader: s__('BranchRules|Required approvals (%{total})'),
noData: s__('BranchRules|No data to display'),
};
@@ -33,3 +38,5 @@ export const WILDCARDS_HELP_PATH =
'user/project/protected_branches#configure-multiple-protected-branches-by-using-a-wildcard';
export const PROTECTED_BRANCHES_HELP_PATH = 'user/project/protected_branches';
+
+export const APPROVALS_HELP_PATH = 'user/project/merge_requests/approvals/index.md';
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
index 6534ff883a6..318940478a8 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
@@ -11,16 +11,19 @@ import {
BRANCH_PARAM_NAME,
WILDCARDS_HELP_PATH,
PROTECTED_BRANCHES_HELP_PATH,
+ APPROVALS_HELP_PATH,
} from './constants';
const wildcardsHelpDocLink = helpPagePath(WILDCARDS_HELP_PATH);
const protectedBranchesHelpDocLink = helpPagePath(PROTECTED_BRANCHES_HELP_PATH);
+const approvalsHelpDocLink = helpPagePath(APPROVALS_HELP_PATH);
export default {
name: 'RuleView',
i18n: I18N,
wildcardsHelpDocLink,
protectedBranchesHelpDocLink,
+ approvalsHelpDocLink,
components: { Protection, GlSprintf, GlLink, GlLoadingIcon },
inject: {
projectPath: {
@@ -29,6 +32,9 @@ export default {
protectedBranchesPath: {
default: '',
},
+ approvalRulesPath: {
+ default: '',
+ },
},
apollo: {
project: {
@@ -48,7 +54,9 @@ export default {
data() {
return {
branch: getParameterByName(BRANCH_PARAM_NAME),
- branchProtection: {},
+ branchProtection: {
+ approvalRules: {},
+ },
};
},
computed: {
@@ -75,6 +83,15 @@ export default {
total: this.pushAccessLevels.total,
});
},
+ approvalsHeader() {
+ const total = this.approvals.reduce(
+ (sum, { approvalsRequired }) => sum + approvalsRequired,
+ 0,
+ );
+ return sprintf(this.$options.i18n.approvalsHeader, {
+ total,
+ });
+ },
allBranches() {
return this.branch === ALL_BRANCHES_WILDCARD;
},
@@ -86,6 +103,9 @@ export default {
? this.$options.i18n.targetBranch
: this.$options.i18n.branchNameOrPattern;
},
+ approvals() {
+ return this.branchProtection?.approvalRules?.nodes || [];
+ },
},
methods: {
getAccessLevels(accessLevels = {}) {
@@ -164,7 +184,22 @@ export default {
/>
-
+
{{ $options.i18n.approvalsTitle }}
+
+
+
+ {{ content }}
+
+
+
+
+
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue
index 8434b7bfce5..cfe2df0dbda 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue
@@ -41,6 +41,11 @@ export default {
required: false,
default: () => [],
},
+ approvals: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
},
computed: {
showUsersDivider() {
@@ -80,5 +85,15 @@ export default {
:title="$options.i18n.groupsTitle"
:access-levels="groups"
/>
+
+
+
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue
index 2509c2538b2..28a1c09fa82 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue
@@ -36,6 +36,11 @@ export default {
required: false,
default: () => [],
},
+ approvalsRequired: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
computed: {
avatarBadgeSrOnlyText() {
@@ -48,6 +53,11 @@ export default {
commaSeparateList() {
return this.accessLevels.length > 1;
},
+ approvalsRequiredTitle() {
+ return this.approvalsRequired
+ ? n__('%d approval required', '%d approvals required', this.approvalsRequired)
+ : null;
+ },
},
};
@@ -57,34 +67,44 @@ export default {
class="gl-display-flex gl-align-items-center gl-border-gray-100 gl-mb-4 gl-pt-4"
:class="{ 'gl-border-t-solid': showDivider }"
>
- {{ title }}
+
+
{{ title }}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
,
- {{ item.accessLevelDescription }}
+
+ ,
+ {{ item.accessLevelDescription }}
+
+
+
{{ approvalsRequiredTitle }}
diff --git a/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js b/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js
index 39164063d05..07fd0a7080f 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js
+++ b/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js
@@ -14,7 +14,7 @@ export default function mountBranchRules(el) {
defaultClient: createDefaultClient(),
});
- const { projectPath, protectedBranchesPath } = el.dataset;
+ const { projectPath, protectedBranchesPath, approvalRulesPath } = el.dataset;
return new Vue({
el,
@@ -22,6 +22,7 @@ export default function mountBranchRules(el) {
provide: {
projectPath,
protectedBranchesPath,
+ approvalRulesPath,
},
render(h) {
return h(View);
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
index e34c51bc11f..ad061dd2e6b 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
@@ -85,7 +85,7 @@ export default {
return this.loading || this.$apollo.queries.issuable.loading;
},
canUpdate() {
- return this.issuable.userPermissions?.updateMergeRequest || false;
+ return this.issuable.userPermissions?.adminMergeRequest || false;
},
},
created() {
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
index b61996cdcdb..e6c29e24f0c 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
@@ -53,6 +53,11 @@ export default {
required: false,
default: false,
},
+ allowMultipleScopedLabels: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
variant: {
type: String,
required: false,
@@ -164,6 +169,7 @@ export default {
allowLabelCreate: this.allowLabelCreate,
allowMultiselect: this.allowMultiselect,
allowScopedLabels: this.allowScopedLabels,
+ allowMultipleScopedLabels: this.allowMultipleScopedLabels,
dropdownButtonText: this.dropdownButtonText,
selectedLabels: this.selectedLabels,
labelsFetchPath: this.labelsFetchPath,
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
index 43b23994cdf..c85d9befcbb 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
@@ -94,14 +94,13 @@ export default {
candidateLabel.indeterminate = false;
}
- if (isScopedLabel(candidateLabel)) {
+ if (isScopedLabel(candidateLabel) && !state.allowMultipleScopedLabels) {
const currentActiveScopedLabel = state.labels.find(
({ set, title }) =>
set &&
title !== candidateLabel.title &&
scopedLabelKey({ title }) === scopedLabelKey(candidateLabel),
);
-
if (currentActiveScopedLabel) {
currentActiveScopedLabel.set = false;
}
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_merge_request_reviewers.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_merge_request_reviewers.query.graphql
index 05de680ab05..f087ca6c982 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_merge_request_reviewers.query.graphql
+++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_merge_request_reviewers.query.graphql
@@ -19,7 +19,7 @@ query mergeRequestReviewers($fullPath: ID!, $iid: String!) {
}
}
userPermissions {
- updateMergeRequest
+ adminMergeRequest
}
}
}
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 282622c792e..e05a32ccb5b 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -455,8 +455,7 @@ module Ci
def prevent_rollback_deployment?
strong_memoize(:prevent_rollback_deployment) do
- Feature.enabled?(:prevent_outdated_deployment_jobs, project) &&
- starts_environment? &&
+ starts_environment? &&
project.ci_forward_deployment_enabled? &&
deployment&.older_than_last_successful_deployment?
end
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index dafcbc593be..4d10499f48d 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -105,6 +105,7 @@ class Deployment < ApplicationRecord
after_transition any => :running do |deployment|
next unless deployment.project.ci_forward_deployment_enabled?
+ next if Feature.enabled?(:prevent_outdated_deployment_jobs, deployment.project)
deployment.run_after_commit do
Deployments::DropOlderDeploymentsWorker.perform_async(id)
diff --git a/app/models/namespace/aggregation_schedule.rb b/app/models/namespace/aggregation_schedule.rb
index 72f5ab11060..cd7d4fc409a 100644
--- a/app/models/namespace/aggregation_schedule.rb
+++ b/app/models/namespace/aggregation_schedule.rb
@@ -14,9 +14,9 @@ class Namespace::AggregationSchedule < ApplicationRecord
def self.default_lease_timeout
if Feature.enabled?(:remove_namespace_aggregator_delay)
- 1.hour.to_i
+ 30.minutes.to_i
else
- 1.5.hours.to_i
+ 1.hour.to_i
end
end
diff --git a/app/services/ci/process_build_service.rb b/app/services/ci/process_build_service.rb
index e6ec65fcc91..22cd267806d 100644
--- a/app/services/ci/process_build_service.rb
+++ b/app/services/ci/process_build_service.rb
@@ -25,6 +25,8 @@ module Ci
end
def enqueue(build)
+ return build.drop!(:failed_outdated_deployment_job) if build.prevent_rollback_deployment?
+
build.enqueue
end
diff --git a/app/views/projects/settings/branch_rules/index.html.haml b/app/views/projects/settings/branch_rules/index.html.haml
index ab692a23e44..a7e80101a88 100644
--- a/app/views/projects/settings/branch_rules/index.html.haml
+++ b/app/views/projects/settings/branch_rules/index.html.haml
@@ -3,4 +3,4 @@
%h3.gl-mb-5= s_('BranchRules|Branch rules details')
-#js-branch-rules{ data: { project_path: @project.full_path, protected_branches_path: project_settings_repository_path(@project, anchor: 'js-protected-branches-settings') } }
+#js-branch-rules{ data: { project_path: @project.full_path, protected_branches_path: project_settings_repository_path(@project, anchor: 'js-protected-branches-settings'), approval_rules_path: project_settings_merge_requests_path(@project, anchor: 'js-merge-request-approval-settings') } }
diff --git a/config/metrics/counts_28d/20220222215951_xmau_plan.yml b/config/metrics/counts_28d/20220222215951_xmau_plan.yml
index 587f34e90c3..c254ad942c2 100644
--- a/config/metrics/counts_28d/20220222215951_xmau_plan.yml
+++ b/config/metrics/counts_28d/20220222215951_xmau_plan.yml
@@ -21,6 +21,7 @@ options:
- users_updating_work_item_title
- users_updating_work_item_dates
- users_updating_work_item_labels
+ - users_updating_work_item_iteration
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_28d/20220222215952_xmau_project_management.yml b/config/metrics/counts_28d/20220222215952_xmau_project_management.yml
index 542f8a13118..0dad4fd0979 100644
--- a/config/metrics/counts_28d/20220222215952_xmau_project_management.yml
+++ b/config/metrics/counts_28d/20220222215952_xmau_project_management.yml
@@ -21,6 +21,7 @@ options:
- users_updating_work_item_title
- users_updating_work_item_dates
- users_updating_work_item_labels
+ - users_updating_work_item_iteration
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_28d/20220222215955_users_work_items.yml b/config/metrics/counts_28d/20220222215955_users_work_items.yml
index e7a95c9d335..ec07fb25f11 100644
--- a/config/metrics/counts_28d/20220222215955_users_work_items.yml
+++ b/config/metrics/counts_28d/20220222215955_users_work_items.yml
@@ -21,6 +21,7 @@ options:
- users_updating_work_item_title
- users_updating_work_item_dates
- users_updating_work_item_labels
+ - users_updating_work_item_iteration
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_28d/20220922042106_users_updating_work_item_iteration_monthly.yml b/config/metrics/counts_28d/20220922042106_users_updating_work_item_iteration_monthly.yml
new file mode 100644
index 00000000000..4c19e4e3261
--- /dev/null
+++ b/config/metrics/counts_28d/20220922042106_users_updating_work_item_iteration_monthly.yml
@@ -0,0 +1,24 @@
+---
+key_path: redis_hll_counters.work_items.users_updating_work_item_iteration_monthly
+description: Unique users updating a work item's iteration
+product_section: team planning
+product_stage: dev
+product_group: plan
+product_category: project_management
+value_type: number
+status: active
+milestone: "15.5"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98539
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - users_updating_work_item_iteration
+distribution:
+- ce
+- ee
+tier:
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220222215851_xmau_plan.yml b/config/metrics/counts_7d/20220222215851_xmau_plan.yml
index 4fb302d67ac..77325a205ee 100644
--- a/config/metrics/counts_7d/20220222215851_xmau_plan.yml
+++ b/config/metrics/counts_7d/20220222215851_xmau_plan.yml
@@ -21,6 +21,7 @@ options:
- users_updating_work_item_title
- users_updating_work_item_dates
- users_updating_work_item_labels
+ - users_updating_work_item_iteration
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_7d/20220222215852_xmau_project_management.yml b/config/metrics/counts_7d/20220222215852_xmau_project_management.yml
index a63adfab8aa..c7e712cf92a 100644
--- a/config/metrics/counts_7d/20220222215852_xmau_project_management.yml
+++ b/config/metrics/counts_7d/20220222215852_xmau_project_management.yml
@@ -21,6 +21,7 @@ options:
- users_updating_work_item_title
- users_updating_work_item_dates
- users_updating_work_item_labels
+ - users_updating_work_item_iteration
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_7d/20220222215855_users_work_items.yml b/config/metrics/counts_7d/20220222215855_users_work_items.yml
index cb312022192..0985f38c83b 100644
--- a/config/metrics/counts_7d/20220222215855_users_work_items.yml
+++ b/config/metrics/counts_7d/20220222215855_users_work_items.yml
@@ -21,6 +21,7 @@ options:
- users_updating_work_item_title
- users_updating_work_item_dates
- users_updating_work_item_labels
+ - users_updating_work_item_iteration
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_7d/20220922042528_users_updating_work_item_iteration_weekly.yml b/config/metrics/counts_7d/20220922042528_users_updating_work_item_iteration_weekly.yml
new file mode 100644
index 00000000000..aad949867cf
--- /dev/null
+++ b/config/metrics/counts_7d/20220922042528_users_updating_work_item_iteration_weekly.yml
@@ -0,0 +1,24 @@
+---
+key_path: redis_hll_counters.work_items.users_updating_work_item_iteration_weekly
+description: Unique users updating a work item's iteration
+product_section: team planning
+product_stage: dev
+product_group: plan
+product_category: project_management
+value_type: number
+status: active
+milestone: "15.5"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98539
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - users_updating_work_item_iteration
+distribution:
+- ce
+- ee
+tier:
+- premium
+- ultimate
diff --git a/db/migrate/20221014031033_add_temp_index_to_project_features_where_releases_access_level_gt_repository.rb b/db/migrate/20221014031033_add_temp_index_to_project_features_where_releases_access_level_gt_repository.rb
new file mode 100644
index 00000000000..14077e30780
--- /dev/null
+++ b/db/migrate/20221014031033_add_temp_index_to_project_features_where_releases_access_level_gt_repository.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddTempIndexToProjectFeaturesWhereReleasesAccessLevelGtRepository < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'tmp_idx_project_features_on_releases_al_and_repo_al_partial'
+
+ # Temporary index to be removed in 15.6 https://gitlab.com/gitlab-org/gitlab/-/issues/377915
+ def up
+ add_concurrent_index :project_features,
+ [:releases_access_level, :repository_access_level],
+ name: INDEX_NAME,
+ where: 'releases_access_level > repository_access_level'
+ end
+
+ def down
+ remove_concurrent_index_by_name :project_features, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221014034338_populate_releases_access_level_from_repository.rb b/db/migrate/20221014034338_populate_releases_access_level_from_repository.rb
new file mode 100644
index 00000000000..6e61d972bf6
--- /dev/null
+++ b/db/migrate/20221014034338_populate_releases_access_level_from_repository.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class PopulateReleasesAccessLevelFromRepository < Gitlab::Database::Migration[2.0]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ disable_ddl_transaction!
+
+ def up
+ update_column_in_batches(
+ :project_features,
+ :releases_access_level,
+ Arel.sql('repository_access_level')
+ ) do |table, query|
+ query.where(table[:releases_access_level].gt(table[:repository_access_level]))
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20221014031033 b/db/schema_migrations/20221014031033
new file mode 100644
index 00000000000..6a24a2027c7
--- /dev/null
+++ b/db/schema_migrations/20221014031033
@@ -0,0 +1 @@
+bc05939dc672c078161cd9b7dbd7f92601edb6888a77c62adb014964e30c6ae8
\ No newline at end of file
diff --git a/db/schema_migrations/20221014034338 b/db/schema_migrations/20221014034338
new file mode 100644
index 00000000000..c90dfebb72b
--- /dev/null
+++ b/db/schema_migrations/20221014034338
@@ -0,0 +1 @@
+58ee7f51a0da4ee4ec471d4492106d1fc3124419ba83591913967d6bd38105e5
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index e95f93982fa..b8779dd9416 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -30993,6 +30993,8 @@ CREATE UNIQUE INDEX taggings_idx ON taggings USING btree (tag_id, taggable_id, t
CREATE UNIQUE INDEX term_agreements_unique_index ON term_agreements USING btree (user_id, term_id);
+CREATE INDEX tmp_idx_project_features_on_releases_al_and_repo_al_partial ON project_features USING btree (releases_access_level, repository_access_level) WHERE (releases_access_level > repository_access_level);
+
CREATE INDEX tmp_idx_vulnerabilities_on_id_where_report_type_7_99 ON vulnerabilities USING btree (id) WHERE (report_type = ANY (ARRAY[7, 99]));
CREATE INDEX tmp_index_approval_merge_request_rules_on_report_type_equal_one ON approval_merge_request_rules USING btree (id, report_type) WHERE (report_type = 1);
diff --git a/doc/ci/pipelines/cicd_minutes.md b/doc/ci/pipelines/cicd_minutes.md
index 14a8ad7f59a..a5946607128 100644
--- a/doc/ci/pipelines/cicd_minutes.md
+++ b/doc/ci/pipelines/cicd_minutes.md
@@ -248,7 +248,6 @@ GitLab SaaS runners have different cost factors, depending on the runner type (L
| Linux OS + Docker executor| Small |1|
| Linux OS + Docker executor| Medium |2|
| Linux OS + Docker executor| Large |3|
-| macOS + shell executor | Large| 6 |
### Monthly reset of CI/CD minutes
diff --git a/doc/ci/pipelines/schedules.md b/doc/ci/pipelines/schedules.md
index d9f4cf3aaef..0eeb0eada87 100644
--- a/doc/ci/pipelines/schedules.md
+++ b/doc/ci/pipelines/schedules.md
@@ -39,6 +39,9 @@ To add a pipeline schedule:
These variables are available only when the scheduled pipeline runs,
and not in any other pipeline run.
+If the project already has the [maximum number of pipeline schedules](../../administration/instance_limits.md#number-of-pipeline-schedules),
+you must delete unused schedules before you can add another.
+
## Edit a pipeline schedule
> Introduced in GitLab 14.8, only a pipeline schedule owner can edit the schedule.
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index bc362b07385..2f23ebbfd9f 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -95,9 +95,14 @@ after a given period of time.
The following are example projects that demonstrate Review App configuration:
-- [NGINX](https://gitlab.com/gitlab-examples/review-apps-nginx).
-- [OpenShift](https://gitlab.com/gitlab-examples/review-apps-openshift).
-- [HashiCorp Nomad](https://gitlab.com/gitlab-examples/review-apps-nomad).
+| Project | Configuration file |
+|-------------------------------------------------------------------------|--------------------|
+| [NGINX](https://gitlab.com/gitlab-examples/review-apps-nginx) | [`.gitlab-ci.yml`](https://gitlab.com/gitlab-examples/review-apps-nginx/-/blob/b9c1f6a8a7a0dfd9c8784cbf233c0a7b6a28ff27/.gitlab-ci.yml#L20) |
+| [OpenShift](https://gitlab.com/gitlab-examples/review-apps-openshift) | [`.gitlab-ci.yml`](https://gitlab.com/gitlab-examples/review-apps-openshift/-/blob/82ebd572334793deef2d5ddc379f38942f3488be/.gitlab-ci.yml#L42) |
+| [HashiCorp Nomad](https://gitlab.com/gitlab-examples/review-apps-nomad) | [`.gitlab-ci.yml`](https://gitlab.com/gitlab-examples/review-apps-nomad/-/blob/ca372c778be7aaed5e82d3be24e98c3f10a465af/.gitlab-ci.yml#L110) |
+| [GitLab Documentation](https://gitlab.com/gitlab-org/gitlab-docs/) | [`build-and-deploy.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/a715625496303cbd90ff89f3d3658ea8d36ce0f3/.gitlab/ci/build-and-deploy.gitlab-ci.yml#L59) |
+| [`https://about.gitlab.com/`](https://gitlab.com/gitlab-com/www-gitlab-com/) | [`.gitlab-ci.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/6ffcdc3cb9af2abed490cbe5b7417df3e83cd76c/.gitlab-ci.yml#L332) |
+| [GitLab Insights](https://gitlab.com/gitlab-org/gitlab-insights/) | [`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab-insights/-/blob/9e63f44ac2a5a4defc965d0d61d411a768e20546/.gitlab-ci.yml#L234) |
Other examples of Review Apps:
diff --git a/lib/gitlab/usage_data_counters/known_events/work_items.yml b/lib/gitlab/usage_data_counters/known_events/work_items.yml
index 94b7a37e67e..ee828fc0f72 100644
--- a/lib/gitlab/usage_data_counters/known_events/work_items.yml
+++ b/lib/gitlab/usage_data_counters/known_events/work_items.yml
@@ -19,3 +19,11 @@
redis_slot: users
aggregation: weekly
feature_flag: track_work_items_activity
+- name: users_updating_work_item_iteration
+ # The event tracks an EE feature.
+ # It's added here so it can be aggregated into the CE/EE 'OR' aggregate metrics.
+ # It will report 0 for CE instances and should not be used with 'AND' aggregators.
+ category: work_items
+ redis_slot: users
+ aggregation: weekly
+ feature_flag: track_work_items_activity
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 915c3271ff9..34cdc9c4553 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -6826,6 +6831,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Lean more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6853,6 +6861,9 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
@@ -6874,6 +6885,9 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -9841,6 +9855,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -12572,6 +12589,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -21985,6 +22005,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -30441,6 +30464,27 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
msgid "Preferences"
msgstr ""
diff --git a/qa/Gemfile b/qa/Gemfile
index 5817dcd2f90..01a32a7bfb2 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -16,9 +16,9 @@ gem 'rspec-retry', '~> 0.6.1', require: 'rspec/retry'
gem 'rspec_junit_formatter', '~> 0.4.1'
gem 'faker', '~> 2.19', '>= 2.19.0'
gem 'knapsack', '~> 4.0'
-gem 'parallel_tests', '~> 2.29'
+gem 'parallel_tests', '~> 2.32'
gem 'rotp', '~> 3.1.0'
-gem 'timecop', '~> 0.9.1'
+gem 'timecop', '~> 0.9.5'
gem 'parallel', '~> 1.19'
gem 'rainbow', '~> 3.0.0'
gem 'rspec-parameterized', '~> 0.4.2'
@@ -45,5 +45,5 @@ gem 'deprecation_toolkit', '~> 1.5.1', require: false
group :development do
gem 'pry-byebug', '~> 3.5.1', platform: :mri
- gem "ruby-debug-ide", "~> 0.7.0"
+ gem "ruby-debug-ide", "~> 0.7.3"
end
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 9917df25a65..ec5d7063182 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -196,7 +196,7 @@ GEM
oj (3.13.11)
os (1.1.4)
parallel (1.19.2)
- parallel_tests (2.29.0)
+ parallel_tests (2.32.0)
parallel
parser (3.1.2.1)
ast (~> 2.4.1)
@@ -255,7 +255,7 @@ GEM
rspec-support (3.10.2)
rspec_junit_formatter (0.4.1)
rspec-core (>= 2, < 4, != 2.12.0)
- ruby-debug-ide (0.7.2)
+ ruby-debug-ide (0.7.3)
rake (>= 0.8.1)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
@@ -277,7 +277,7 @@ GEM
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
thread_safe (0.3.6)
- timecop (0.9.1)
+ timecop (0.9.5)
trailblazer-option (0.1.2)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
@@ -332,7 +332,7 @@ DEPENDENCIES
nokogiri (~> 1.13, >= 1.13.8)
octokit (~> 5.6.1)
parallel (~> 1.19)
- parallel_tests (~> 2.29)
+ parallel_tests (~> 2.32)
pry-byebug (~> 3.5.1)
rainbow (~> 3.0.0)
rake (~> 13)
@@ -342,11 +342,11 @@ DEPENDENCIES
rspec-parameterized (~> 0.4.2)
rspec-retry (~> 0.6.1)
rspec_junit_formatter (~> 0.4.1)
- ruby-debug-ide (~> 0.7.0)
+ ruby-debug-ide (~> 0.7.3)
selenium-webdriver (~> 4.0)
slack-notifier (~> 2.4)
terminal-table (~> 3.0.0)
- timecop (~> 0.9.1)
+ timecop (~> 0.9.5)
warning (~> 1.3)
webdrivers (~> 5.2)
zeitwerk (~> 2.4)
diff --git a/scripts/api/pipeline_failed_jobs.rb b/scripts/api/pipeline_failed_jobs.rb
index 3c29e8842d3..c25567af698 100644
--- a/scripts/api/pipeline_failed_jobs.rb
+++ b/scripts/api/pipeline_failed_jobs.rb
@@ -31,6 +31,13 @@ class PipelineFailedJobs
failed_jobs << job
end
+ client.pipeline_bridges(project, pipeline_id, scope: 'failed', per_page: 100).auto_paginate do |job|
+ next if exclude_allowed_to_fail_jobs && job.allow_failure
+
+ job.web_url = job.downstream_pipeline.web_url # job.web_url is linking to an invalid page
+ failed_jobs << job
+ end
+
failed_jobs
end
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js
index 3176b28d547..bf4026b65db 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js
@@ -33,6 +33,7 @@ describe('View branch rules', () => {
let fakeApollo;
const projectPath = 'test/testing';
const protectedBranchesPath = 'protected/branches';
+ const approvalRulesPath = 'approval/rules';
const branchProtectionsMockRequestHandler = jest
.fn()
.mockResolvedValue(branchProtectionsMockResponse);
@@ -42,7 +43,7 @@ describe('View branch rules', () => {
wrapper = shallowMountExtended(RuleView, {
apolloProvider: fakeApollo,
- provide: { projectPath, protectedBranchesPath },
+ provide: { projectPath, protectedBranchesPath, approvalRulesPath },
});
await waitForPromises();
@@ -57,6 +58,7 @@ describe('View branch rules', () => {
const findBranchProtectionTitle = () => wrapper.findByText(I18N.protectBranchTitle);
const findBranchProtections = () => wrapper.findAllComponents(Protection);
const findForcePushTitle = () => wrapper.findByText(I18N.allowForcePushDescription);
+ const findApprovalsTitle = () => wrapper.findByText(I18N.approvalsTitle);
it('gets the branch param from url and renders it in the view', () => {
expect(util.getParameterByName).toHaveBeenCalledWith('branch');
@@ -98,4 +100,14 @@ describe('View branch rules', () => {
...protectionMockProps,
});
});
+
+ it('renders a branch protection component for approvals', () => {
+ expect(findApprovalsTitle().exists()).toBe(true);
+
+ expect(findBranchProtections().at(2).props()).toMatchObject({
+ header: sprintf(I18N.approvalsHeader, { total: 0 }),
+ headerLinkHref: approvalRulesPath,
+ headerLinkTitle: I18N.manageApprovalsLinkTitle,
+ });
+ });
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js b/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js
index c5774977205..c3f573061da 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js
@@ -36,6 +36,8 @@ const accessLevelsMock = [
{ accessLevelDescription: 'Maintainer' },
];
+const approvalsRequired = 3;
+
const groupsMock = [{ name: 'test_group_1' }, { name: 'test_group_2' }];
export const protectionPropsMock = {
@@ -45,12 +47,20 @@ export const protectionPropsMock = {
roles: accessLevelsMock,
users: usersMock,
groups: groupsMock,
+ approvals: [
+ {
+ name: 'test',
+ eligibleApprovers: { nodes: usersMock },
+ approvalsRequired,
+ },
+ ],
};
export const protectionRowPropsMock = {
title: 'Test title',
users: usersMock,
accessLevels: accessLevelsMock,
+ approvalsRequired,
};
export const accessLevelsMockResponse = [
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js
index 7770e1fb2aa..b0a69bedd3e 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js
@@ -25,6 +25,8 @@ describe('Branch rule protection row', () => {
const findAvatarLinks = () => wrapper.findAllComponents(GlAvatarLink);
const findAvatars = () => wrapper.findAllComponents(GlAvatar);
const findAccessLevels = () => wrapper.findAllByTestId('access-level');
+ const findApprovalsRequired = () =>
+ wrapper.findByText(`${protectionRowPropsMock.approvalsRequired} approvals required`);
it('renders a title', () => {
expect(findTitle().exists()).toBe(true);
@@ -62,4 +64,8 @@ describe('Branch rule protection row', () => {
protectionRowPropsMock.accessLevels[1].accessLevelDescription,
);
});
+
+ it('renders the number of approvals required', () => {
+ expect(findApprovalsRequired().exists()).toBe(true);
+ });
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js
index 91d16fd86a6..e2fbb4f5bbb 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js
@@ -56,4 +56,13 @@ describe('Branch rule protection', () => {
title: i18n.groupsTitle,
});
});
+
+ it('renders a protection row for approvals', () => {
+ const approval = protectionPropsMock.approvals[0];
+ expect(findProtectionRows().at(3).props()).toMatchObject({
+ title: approval.name,
+ users: approval.eligibleApprovers.nodes,
+ approvalsRequired: approval.approvalsRequired,
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
index 99034e360a1..2b2508b5e11 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
@@ -193,6 +193,16 @@ describe('LabelsSelect Mutations', () => {
expect(state.labels[l.id - 1].set).toBe(false);
});
});
+ it('allows selection of multiple scoped labels', () => {
+ const state = { labels: cloneDeep(labels), allowMultipleScopedLabels: true };
+
+ mutations[types.UPDATE_SELECTED_LABELS](state, { labels: [{ id: labels[4].id }] });
+ mutations[types.UPDATE_SELECTED_LABELS](state, { labels: [{ id: labels[5].id }] });
+
+ expect(state.labels[4].set).toBe(true);
+ expect(state.labels[5].set).toBe(true);
+ expect(state.labels[6].set).toBe(true);
+ });
});
describe(`${types.UPDATE_LABELS_SET_STATE}`, () => {
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
index c13a5ba4d72..3e315692d0a 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::WorkItemsActivityAggreg
let(:metric_definition) do
{
data_source: 'redis_hll',
- time_frame: '7d',
+ time_frame: time_frame,
options: {
aggregate: {
operator: 'OR'
@@ -15,6 +15,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::WorkItemsActivityAggreg
users_creating_work_items
users_updating_work_item_title
users_updating_work_item_dates
+ users_updating_work_item_iteration
]
}
}
@@ -24,31 +25,36 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::WorkItemsActivityAggreg
freeze_time { example.run }
end
- describe '#available?' do
- it 'returns false without track_work_items_activity feature' do
- stub_feature_flags(track_work_items_activity: false)
+ where(:time_frame) { [['28d'], ['7d']] }
- expect(described_class.new(metric_definition).available?).to eq(false)
+ with_them do
+ describe '#available?' do
+ it 'returns false without track_work_items_activity feature' do
+ stub_feature_flags(track_work_items_activity: false)
+
+ expect(described_class.new(metric_definition).available?).to eq(false)
+ end
+
+ it 'returns true with track_work_items_activity feature' do
+ stub_feature_flags(track_work_items_activity: true)
+
+ expect(described_class.new(metric_definition).available?).to eq(true)
+ end
end
- it 'returns true with track_work_items_activity feature' do
- stub_feature_flags(track_work_items_activity: true)
+ describe '#value', :clean_gitlab_redis_shared_state do
+ let(:counter) { Gitlab::UsageDataCounters::HLLRedisCounter }
- expect(described_class.new(metric_definition).available?).to eq(true)
- end
- end
+ before do
+ counter.track_event(:users_creating_work_items, values: 1, time: 1.week.ago)
+ counter.track_event(:users_updating_work_item_title, values: 1, time: 1.week.ago)
+ counter.track_event(:users_updating_work_item_dates, values: 2, time: 1.week.ago)
+ counter.track_event(:users_updating_work_item_iteration, values: 2, time: 1.week.ago)
+ end
- describe '#value', :clean_gitlab_redis_shared_state do
- let(:counter) { Gitlab::UsageDataCounters::HLLRedisCounter }
-
- before do
- counter.track_event(:users_creating_work_items, values: 1, time: 1.week.ago)
- counter.track_event(:users_updating_work_item_title, values: 1, time: 1.week.ago)
- counter.track_event(:users_updating_work_item_dates, values: 2, time: 1.week.ago)
- end
-
- it 'has correct value' do
- expect(described_class.new(metric_definition).value).to eq 2
+ it 'has correct value' do
+ expect(described_class.new(metric_definition).value).to eq 2
+ end
end
end
end
diff --git a/spec/migrations/populate_releases_access_level_from_repository_spec.rb b/spec/migrations/populate_releases_access_level_from_repository_spec.rb
new file mode 100644
index 00000000000..2bb97662923
--- /dev/null
+++ b/spec/migrations/populate_releases_access_level_from_repository_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe PopulateReleasesAccessLevelFromRepository, :migration do
+ let(:projects) { table(:projects) }
+ let(:groups) { table(:namespaces) }
+ let(:project_features) { table(:project_features) }
+
+ let(:group) { groups.create!(name: 'test-group', path: 'test-group') }
+ let(:project) { projects.create!(namespace_id: group.id, project_namespace_id: group.id) }
+ let(:project_feature) do
+ project_features.create!(project_id: project.id, pages_access_level: 20, **project_feature_attributes)
+ end
+
+ # repository_access_level and releases_access_level default to ENABLED
+ describe '#up' do
+ context 'when releases_access_level is greater than repository_access_level' do
+ let(:project_feature_attributes) { { repository_access_level: ProjectFeature::PRIVATE } }
+
+ it 'reduces releases_access_level to match repository_access_level' do
+ expect { migrate! }.to change { project_feature.reload.releases_access_level }
+ .from(ProjectFeature::ENABLED)
+ .to(ProjectFeature::PRIVATE)
+ end
+ end
+
+ context 'when releases_access_level is less than repository_access_level' do
+ let(:project_feature_attributes) { { releases_access_level: ProjectFeature::DISABLED } }
+
+ it 'does not change releases_access_level' do
+ expect { migrate! }.not_to change { project_feature.reload.releases_access_level }
+ .from(ProjectFeature::DISABLED)
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index ec0fe456d99..9713734e97a 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -632,15 +632,6 @@ RSpec.describe Ci::Build do
it { expect(subject).to be_falsey }
end
- context 'when prevent_outdated_deployment_jobs FF is disabled' do
- before do
- stub_feature_flags(prevent_outdated_deployment_jobs: false)
- expect(build.deployment).not_to receive(:rollback?)
- end
-
- it { expect(subject).to be_falsey }
- end
-
context 'when build can prevent rollback deployment' do
before do
expect(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 87fa5289795..bf1cf9856a0 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -171,11 +171,22 @@ RSpec.describe Deployment do
end
it 'executes Deployments::DropOlderDeploymentsWorker asynchronously' do
+ stub_feature_flags(prevent_outdated_deployment_jobs: false)
+
expect(Deployments::DropOlderDeploymentsWorker)
.to receive(:perform_async).once.with(deployment.id)
deployment.run!
end
+
+ it 'does not execute Deployments::DropOlderDeploymentsWorker when FF enabled' do
+ stub_feature_flags(prevent_outdated_deployment_jobs: true)
+
+ expect(Deployments::DropOlderDeploymentsWorker)
+ .not_to receive(:perform_async).with(deployment.id)
+
+ deployment.run!
+ end
end
context 'when deployment succeeded' do
diff --git a/spec/models/namespace/aggregation_schedule_spec.rb b/spec/models/namespace/aggregation_schedule_spec.rb
index 3f6a890654a..45b66fa12dd 100644
--- a/spec/models/namespace/aggregation_schedule_spec.rb
+++ b/spec/models/namespace/aggregation_schedule_spec.rb
@@ -12,14 +12,14 @@ RSpec.describe Namespace::AggregationSchedule, :clean_gitlab_redis_shared_state,
describe "#default_lease_timeout" do
subject(:default_lease_timeout) { default_timeout }
- it { is_expected.to eq 1.hour.to_i }
+ it { is_expected.to eq 30.minutes.to_i }
context 'when remove_namespace_aggregator_delay FF is disabled' do
before do
stub_feature_flags(remove_namespace_aggregator_delay: false)
end
- it { is_expected.to eq 1.5.hours.to_i }
+ it { is_expected.to eq 1.hour.to_i }
end
end
diff --git a/workhorse/go.mod b/workhorse/go.mod
index d2d5e4b44f9..0843fe48130 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -34,7 +34,7 @@ require (
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
golang.org/x/tools v0.1.12
- google.golang.org/grpc v1.50.0
+ google.golang.org/grpc v1.50.1
google.golang.org/protobuf v1.28.1
honnef.co/go/tools v0.3.3
)
diff --git a/workhorse/go.sum b/workhorse/go.sum
index 3795e8aae7a..9515f7d0384 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -1550,8 +1550,8 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
-google.golang.org/grpc v1.50.0 h1:fPVVDxY9w++VjTZsYvXWqEf9Rqar/e+9zYfxKK+W+YU=
-google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
+google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=