Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
0ead22f9db
commit
75c2755b05
32 changed files with 617 additions and 89 deletions
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlFormGroup, GlFormCheckbox } from '@gitlab/ui';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'ActiveCheckbox',
|
||||
|
@ -15,6 +15,10 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapGetters(['isInheriting', 'propsSource']),
|
||||
...mapState(['customState']),
|
||||
disabled() {
|
||||
return this.isInheriting || this.customState.activateDisabled;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.activated = this.propsSource.initialActivated;
|
||||
|
@ -34,7 +38,7 @@ export default {
|
|||
<gl-form-checkbox
|
||||
v-model="activated"
|
||||
class="gl-display-block"
|
||||
:disabled="isInheriting"
|
||||
:disabled="disabled"
|
||||
@change="onChange"
|
||||
>
|
||||
{{ __('Active') }}
|
||||
|
|
|
@ -39,6 +39,7 @@ function parseDatasetToProps(data) {
|
|||
const {
|
||||
showActive,
|
||||
activated,
|
||||
activateDisabled,
|
||||
editable,
|
||||
canTest,
|
||||
commitEvents,
|
||||
|
@ -54,6 +55,7 @@ function parseDatasetToProps(data) {
|
|||
return {
|
||||
initialActivated: activated,
|
||||
showActive,
|
||||
activateDisabled,
|
||||
type,
|
||||
cancelPath,
|
||||
editable,
|
||||
|
|
|
@ -104,7 +104,8 @@ module IntegrationsHelper
|
|||
form_data = {
|
||||
id: integration.id,
|
||||
show_active: integration.show_active_box?.to_s,
|
||||
activated: (integration.active || integration.new_record?).to_s,
|
||||
activated: (integration.active || (integration.new_record? && integration.activate_disabled_reason.nil?)).to_s,
|
||||
activate_disabled: integration.activate_disabled_reason.present?.to_s,
|
||||
type: integration.to_param,
|
||||
merge_request_events: integration.merge_requests_events.to_s,
|
||||
commit_events: integration.commit_events.to_s,
|
||||
|
|
|
@ -8,7 +8,6 @@ class Deployment < ApplicationRecord
|
|||
include Importable
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
include FastDestroyAll
|
||||
include FromUnion
|
||||
|
||||
StatusUpdateError = Class.new(StandardError)
|
||||
StatusSyncError = Class.new(StandardError)
|
||||
|
|
|
@ -360,6 +360,10 @@ class Integration < ApplicationRecord
|
|||
true
|
||||
end
|
||||
|
||||
def activate_disabled_reason
|
||||
nil
|
||||
end
|
||||
|
||||
def category
|
||||
read_attribute(:category).to_sym
|
||||
end
|
||||
|
|
|
@ -132,8 +132,18 @@ module Integrations
|
|||
# implement inside child
|
||||
end
|
||||
|
||||
def activate_disabled_reason
|
||||
{ trackers: other_external_issue_trackers } if other_external_issue_trackers.any?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def other_external_issue_trackers
|
||||
return [] unless project_level?
|
||||
|
||||
@other_external_issue_trackers ||= project.integrations.external_issue_trackers.where.not(id: id)
|
||||
end
|
||||
|
||||
def enabled_in_gitlab_config
|
||||
Gitlab.config.issues_tracker &&
|
||||
Gitlab.config.issues_tracker.values.any? &&
|
||||
|
@ -148,7 +158,7 @@ module Integrations
|
|||
return if instance?
|
||||
return if project.blank?
|
||||
|
||||
if project.integrations.external_issue_trackers.where.not(id: id).any?
|
||||
if other_external_issue_trackers.any?
|
||||
errors.add(:base, _('Another issue tracker is already in use. Only one issue tracker service can be active at a time'))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1154,7 +1154,6 @@ class MergeRequest < ApplicationRecord
|
|||
def mergeable_state?(skip_ci_check: false, skip_discussions_check: false)
|
||||
return false unless open?
|
||||
return false if work_in_progress?
|
||||
return false if broken?
|
||||
|
||||
if Feature.enabled?(:improved_mergeability_checks, self.project, default_enabled: :yaml)
|
||||
additional_checks = MergeRequests::Mergeability::RunChecksService.new(
|
||||
|
@ -1166,6 +1165,7 @@ class MergeRequest < ApplicationRecord
|
|||
)
|
||||
additional_checks.execute.all?(&:success?)
|
||||
else
|
||||
return false if broken?
|
||||
return false unless skip_discussions_check || mergeable_discussions_state?
|
||||
return false unless skip_ci_check || mergeable_ci_state?
|
||||
|
||||
|
|
|
@ -21,11 +21,13 @@ module Preloaders
|
|||
def load_deployment_association(association_name, association_attributes)
|
||||
return unless environments.present?
|
||||
|
||||
union_arg = environments.inject([]) do |result, environment|
|
||||
result << environment.association(association_name).scope
|
||||
end
|
||||
|
||||
union_sql = Deployment.from_union(union_arg).to_sql
|
||||
# Not using Gitlab::SQL::Union as `order_by` in the SQL constructed is ignored.
|
||||
# See:
|
||||
# 1) https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/sql/union.rb#L7
|
||||
# 2) https://gitlab.com/gitlab-org/gitlab/-/issues/353966#note_860928647
|
||||
union_sql = environments.map do |environment|
|
||||
"(#{environment.association(association_name).scope.to_sql})"
|
||||
end.join(' UNION ')
|
||||
|
||||
deployments = Deployment
|
||||
.from("(#{union_sql}) #{::Deployment.table_name}")
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
module MergeRequests
|
||||
module Mergeability
|
||||
class CheckBrokenStatusService < CheckBaseService
|
||||
def execute
|
||||
if merge_request.broken?
|
||||
failure
|
||||
else
|
||||
success
|
||||
end
|
||||
end
|
||||
|
||||
def skip?
|
||||
false
|
||||
end
|
||||
|
||||
def cacheable?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,6 +7,7 @@ module MergeRequests
|
|||
# We want to have the cheapest checks first in the list,
|
||||
# that way we can fail fast before running the more expensive ones
|
||||
CHECKS = [
|
||||
CheckBrokenStatusService,
|
||||
CheckDiscussionsStatusService,
|
||||
CheckCiStatusService
|
||||
].freeze
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
- if lookup_context.template_exists?('top', "projects/services/#{integration.to_param}", true)
|
||||
= render "projects/services/#{integration.to_param}/top", integration: integration
|
||||
|
||||
- if integration.activate_disabled_reason.present? && integration.activate_disabled_reason[:trackers].any?
|
||||
-# When using integration.activate_disabled_reason[:trackers], it's potentially insecure to use the raw records
|
||||
-# when passed directly to the frontend. Only use specific fields that are needed for render.
|
||||
-# For example, we can get the link to each tracker with scoped_edit_integration_path(tracker, tracker.project)
|
||||
= render 'shared/global_alert',
|
||||
title: s_('ExternalIssueIntegration|Another issue tracker is already in use'),
|
||||
variant: :warning,
|
||||
dismissible: false do
|
||||
.gl-alert-body
|
||||
= s_('ExternalIssueIntegration|Only one issue tracker integration can be active at a time. Please disable the active tracker first and try again.')
|
||||
|
||||
%h3.page-title
|
||||
= integration.title
|
||||
- if integration.operating?
|
||||
|
|
6
data/deprecations/distribution_deprecations_14-4.yml
Normal file
6
data/deprecations/distribution_deprecations_14-4.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
- name: "Move `custom_hooks_dir` setting from GitLab Shell to Gitaly" # The name of the feature to be deprecated
|
||||
announcement_milestone: "14.9" # The milestone when this feature was first announced as deprecated.
|
||||
announcement_date: "2021-10-22"
|
||||
removal_milestone: "15.0" # the milestone when this feature is planned to be removed
|
||||
body: | # Do not modify this line, instead modify the lines below.
|
||||
The [`custom_hooks_dir`](https://docs.gitlab.com/ee/administration/server_hooks.html#create-a-global-server-hook-for-all-repositories) setting is now configured in Gitaly, and will be removed from GitLab Shell in GitLab 15.0.
|
|
@ -32,7 +32,7 @@ If you are using GDK, you can follow the following steps:
|
|||
1. On the GDK root directory, run:
|
||||
|
||||
```shell
|
||||
gdk config set gitlab.rails.multiple_databases true
|
||||
gdk config set gitlab.rails.databases.ci.enabled true
|
||||
```
|
||||
|
||||
1. Open your `gdk.yml`, and confirm that it has the following lines:
|
||||
|
|
|
@ -438,3 +438,61 @@ old method:
|
|||
|
||||
If you want to add easy Geo replication of a resource you're working
|
||||
on, check out our [self-service framework](geo/framework.md).
|
||||
|
||||
## Geo development workflow
|
||||
|
||||
### GET:Geo pipeline
|
||||
|
||||
As part of the [package-and-qa](testing_guide/end_to_end/index.md#using-the-package-and-qa-job) pipeline, there is an option to manually trigger a job named `GET:Geo`. This
|
||||
pipeline uses [GET](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) to spin up a
|
||||
[1k](../administration/reference_architectures/1k_users.md) Geo installation,
|
||||
and run the [`gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa) Geo scenario against the instance.
|
||||
When working on Geo features, it is a good idea to ensure the `qa-geo` job passes in a triggered `GET:Geo pipeline`.
|
||||
|
||||
The pipelines that control the provisioning and teardown of the instance are included in The GitLab Environment Toolkit Configs
|
||||
[Geo subproject](https://gitlab.com/gitlab-org/quality/gitlab-environment-toolkit-configs/Geo).
|
||||
|
||||
When adding new functionality, consider adding new tests to verify the behavior. For steps,
|
||||
see the [QA documentation](https://gitlab.com/gitlab-org/gitlab/-/tree/master/qa#writing-tests).
|
||||
|
||||
#### Architecture
|
||||
|
||||
The pipeline involves the interaction of multiple different projects:
|
||||
|
||||
- [GitLab](https://gitlab.com/gitlab-org/gitlab) - The [package-and-qa job](testing_guide/end_to_end/index.md#using-the-package-and-qa-job) is launched from merge requests in this project.
|
||||
- [`omnibus-gitlab`](https://gitlab.com/gitlab-org/omnibus-gitlab) - Builds relevant artifacts containing the changes from the triggering merge request pipeline.
|
||||
- [GET-Configs/Geo](https://gitlab.com/gitlab-org/quality/gitlab-environment-toolkit-configs/Geo) - Coordinates the lifecycle of a short-lived Geo installation that can be evaluated.
|
||||
- [GET](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) - Contains the necessary logic for creating and destroying Geo installations. Used by `GET-Configs/Geo`.
|
||||
- [`gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa) - Tool for running automated tests against a GitLab instance.
|
||||
|
||||
```mermaid
|
||||
flowchart TD;
|
||||
GET:Geo-->getcg
|
||||
Provision-->Terraform
|
||||
Configure-->Ansible
|
||||
Geo-->Ansible
|
||||
QA-->gagq
|
||||
|
||||
subgraph "omnibus-gitlab-mirror"
|
||||
GET:Geo
|
||||
end
|
||||
|
||||
subgraph getcg [GitLab-environment-toolkit-configs/Geo]
|
||||
direction LR
|
||||
Generate-terraform-config-->Provision
|
||||
Provision-->Generate-ansible-config
|
||||
Generate-ansible-config-->Configure
|
||||
Configure-->Geo
|
||||
Geo-->QA
|
||||
QA-->Destroy-geo
|
||||
end
|
||||
|
||||
subgraph get [GitLab Environment Toolkit]
|
||||
Terraform
|
||||
Ansible
|
||||
end
|
||||
|
||||
subgraph GitLab QA
|
||||
gagq[GitLab QA Geo Scenario]
|
||||
end
|
||||
```
|
||||
|
|
|
@ -50,6 +50,12 @@ GitLab self-monitoring gives administrators of self-hosted GitLab instances the
|
|||
|
||||
**Planned removal milestone: 15.0 (2022-05-22)**
|
||||
|
||||
### Move `custom_hooks_dir` setting from GitLab Shell to Gitaly
|
||||
|
||||
The [`custom_hooks_dir`](https://docs.gitlab.com/ee/administration/server_hooks.html#create-a-global-server-hook-for-all-repositories) setting is now configured in Gitaly, and will be removed from GitLab Shell in GitLab 15.0.
|
||||
|
||||
**Planned removal milestone: 15.0 ()**
|
||||
|
||||
## 14.8
|
||||
|
||||
### Changes to the `CI_JOB_JWT`
|
||||
|
|
|
@ -148,9 +148,22 @@ If you get this error, [check the batched background migration options](../user/
|
|||
### What do I do if my background migrations are stuck?
|
||||
|
||||
WARNING:
|
||||
The following operations can disrupt your GitLab performance.
|
||||
The following operations can disrupt your GitLab performance. They run a number of Sidekiq jobs that perform various database or file updates.
|
||||
|
||||
It is safe to re-execute these commands, especially if you have 1000+ pending jobs which would likely overflow your runtime memory.
|
||||
#### Background migrations remain in the Sidekiq queue
|
||||
|
||||
Run the following check. If it returns non-zero and the count does not decrease over time, follow the rest of the steps in this section.
|
||||
|
||||
```shell
|
||||
# For Omnibus installations:
|
||||
sudo gitlab-rails runner -e production 'puts Gitlab::BackgroundMigration.remaining'
|
||||
|
||||
# For installations from source:
|
||||
cd /home/git/gitlab
|
||||
sudo -u git -H bundle exec rails runner -e production 'puts Gitlab::BackgroundMigration.remaining'
|
||||
```
|
||||
|
||||
It is safe to re-execute the following commands, especially if you have 1000+ pending jobs which would likely overflow your runtime memory.
|
||||
|
||||
**For Omnibus installations**
|
||||
|
||||
|
@ -176,7 +189,52 @@ pending_job_classes = scheduled_queue.select { |job| job["class"] == "Background
|
|||
pending_job_classes.each { |job_class| Gitlab::BackgroundMigration.steal(job_class) }
|
||||
```
|
||||
|
||||
**Batched migrations (GitLab 14.0 and newer):**
|
||||
#### Background migrations stuck in 'pending' state
|
||||
|
||||
GitLab 13.6 introduced an issue where a background migration named `BackfillJiraTrackerDeploymentType2` can be permanently stuck in a **pending** state across upgrades. To clean up this stuck migration, see the [13.6.0 version-specific instructions](#1360).
|
||||
|
||||
For other background migrations stuck in pending, run the following check. If it returns non-zero and the count does not decrease over time, follow the rest of the steps in this section.
|
||||
|
||||
```shell
|
||||
# For Omnibus installations:
|
||||
sudo gitlab-rails runner -e production 'puts Gitlab::Database::BackgroundMigrationJob.pending.count'
|
||||
|
||||
# For installations from source:
|
||||
cd /home/git/gitlab
|
||||
sudo -u git -H bundle exec rails runner -e production 'puts Gitlab::Database::BackgroundMigrationJob.pending.count'
|
||||
```
|
||||
|
||||
It is safe to re-attempt these migrations to clear them out from a pending status:
|
||||
|
||||
**For Omnibus installations**
|
||||
|
||||
```shell
|
||||
# Start the rails console
|
||||
sudo gitlab-rails c
|
||||
|
||||
# Execute the following in the rails console
|
||||
Gitlab::Database::BackgroundMigrationJob.pending.find_each do |job|
|
||||
puts "Running pending job '#{job.class_name}' with arguments #{job.arguments}"
|
||||
result = Gitlab::BackgroundMigration.perform(job.class_name, job.arguments)
|
||||
puts "Result: #{result}"
|
||||
end
|
||||
```
|
||||
|
||||
**For installations from source**
|
||||
|
||||
```shell
|
||||
# Start the rails console
|
||||
sudo -u git -H bundle exec rails RAILS_ENV=production
|
||||
|
||||
# Execute the following in the rails console
|
||||
Gitlab::Database::BackgroundMigrationJob.pending.find_each do |job|
|
||||
puts "Running pending job '#{job.class_name}' with arguments #{job.arguments}"
|
||||
result = Gitlab::BackgroundMigration.perform(job.class_name, job.arguments)
|
||||
puts "Result: #{result}"
|
||||
end
|
||||
```
|
||||
|
||||
#### Batched migrations (GitLab 14.0 and later)
|
||||
|
||||
See [troubleshooting batched background migrations](../user/admin_area/monitoring/background_migrations.md#troubleshooting).
|
||||
|
||||
|
@ -622,6 +680,19 @@ Ruby 2.7.2 is required. GitLab does not start with Ruby 2.6.6 or older versions.
|
|||
|
||||
The required Git version is Git v2.29 or higher.
|
||||
|
||||
GitLab 13.6 includes a
|
||||
[background migration `BackfillJiraTrackerDeploymentType2`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46368)
|
||||
that may remain stuck permanently in a **pending** state despite completion of work
|
||||
due to a bug.
|
||||
|
||||
To clean up this stuck job, run the following in the [GitLab Rails Console](../administration/operations/rails_console.md):
|
||||
|
||||
```ruby
|
||||
Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "BackfillJiraTrackerDeploymentType2").find_each do |job|
|
||||
puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("BackfillJiraTrackerDeploymentType2", job.arguments)
|
||||
end
|
||||
```
|
||||
|
||||
### 13.4.0
|
||||
|
||||
GitLab 13.4.0 includes a background migration to [move all remaining repositories in legacy storage to hashed storage](../administration/raketasks/storage.md#migrate-to-hashed-storage). There are [known issues with this migration](https://gitlab.com/gitlab-org/gitlab/-/issues/259605) which are fixed in GitLab 13.5.4 and later. If possible, skip 13.4.0 and upgrade to 13.5.4 or higher instead. Note that the migration can take quite a while to run, depending on how many repositories must be moved. Be sure to check that all background migrations have completed before upgrading further.
|
||||
|
|
|
@ -55,8 +55,8 @@ Users with the at least the Maintainer role on a group can create subgroups imme
|
|||
|
||||
To create a subgroup:
|
||||
|
||||
1. On the top bar, select **Menu > Groups** and find the parent group.
|
||||
1. In the top right, select **New subgroup**.
|
||||
1. On the top bar, select **Menu > Groups** and find and select the parent group to add a subgroup to.
|
||||
1. On the parent group's overview page, in the top right, select **New subgroup**.
|
||||
1. Select **Create group**.
|
||||
1. Fill in the fields. View a list of [reserved names](../../reserved_names.md) that cannot be used as group names.
|
||||
1. Select **Create group**.
|
||||
|
|
|
@ -50,34 +50,41 @@ module Gitlab
|
|||
Gitlab::Database::SharedModel.using_connection(connection, &block)
|
||||
end
|
||||
|
||||
def steal(steal_class, retry_dead_jobs: false)
|
||||
with_shared_connection do
|
||||
def pending_jobs(include_dead_jobs: false)
|
||||
Enumerator.new do |y|
|
||||
queues = [
|
||||
Sidekiq::ScheduledSet.new,
|
||||
Sidekiq::Queue.new(self.queue)
|
||||
]
|
||||
|
||||
if retry_dead_jobs
|
||||
if include_dead_jobs
|
||||
queues << Sidekiq::RetrySet.new
|
||||
queues << Sidekiq::DeadSet.new
|
||||
end
|
||||
|
||||
queues.each do |queue|
|
||||
queue.each do |job|
|
||||
migration_class, migration_args = job.args
|
||||
y << job if job.klass == worker_class.name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
next unless job.klass == worker_class.name
|
||||
next unless migration_class == steal_class
|
||||
next if block_given? && !(yield job)
|
||||
def steal(steal_class, retry_dead_jobs: false)
|
||||
with_shared_connection do
|
||||
pending_jobs(include_dead_jobs: retry_dead_jobs).each do |job|
|
||||
migration_class, migration_args = job.args
|
||||
|
||||
begin
|
||||
perform(migration_class, migration_args) if job.delete
|
||||
rescue Exception # rubocop:disable Lint/RescueException
|
||||
worker_class # enqueue this migration again
|
||||
.perform_async(migration_class, migration_args)
|
||||
next unless migration_class == steal_class
|
||||
next if block_given? && !(yield job)
|
||||
|
||||
raise
|
||||
end
|
||||
begin
|
||||
perform(migration_class, migration_args) if job.delete
|
||||
rescue Exception # rubocop:disable Lint/RescueException
|
||||
worker_class # enqueue this migration again
|
||||
.perform_async(migration_class, migration_args)
|
||||
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
49
lib/gitlab/database/migrations/test_background_runner.rb
Normal file
49
lib/gitlab/database/migrations/test_background_runner.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Database
|
||||
module Migrations
|
||||
class TestBackgroundRunner
|
||||
# TODO - build a rake task to call this method, and support it in the gitlab-com-database-testing project.
|
||||
# Until then, we will inject a migration with a very high timestamp during database testing
|
||||
# that calls this class to run jobs
|
||||
# See https://gitlab.com/gitlab-org/database-team/gitlab-com-database-testing/-/issues/41 for details
|
||||
|
||||
def initialize
|
||||
@job_coordinator = Gitlab::BackgroundMigration.coordinator_for_database(Gitlab::Database::MAIN_DATABASE_NAME)
|
||||
end
|
||||
|
||||
def traditional_background_migrations
|
||||
@job_coordinator.pending_jobs
|
||||
end
|
||||
|
||||
def run_jobs(for_duration:)
|
||||
jobs_to_run = traditional_background_migrations.group_by { |j| class_name_for_job(j) }
|
||||
return if jobs_to_run.empty?
|
||||
|
||||
# without .to_f, we do integer division
|
||||
# For example, 3.minutes / 2 == 1.minute whereas 3.minutes / 2.to_f == (1.minute + 30.seconds)
|
||||
duration_per_migration_type = for_duration / jobs_to_run.count.to_f
|
||||
jobs_to_run.each do |_migration_name, jobs|
|
||||
run_until = duration_per_migration_type.from_now
|
||||
jobs.shuffle.each do |j|
|
||||
break if run_until <= Time.current
|
||||
|
||||
run_job(j)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run_job(job)
|
||||
Gitlab::BackgroundMigration.perform(job.args[0], job.args[1])
|
||||
end
|
||||
|
||||
def class_name_for_job(job)
|
||||
job.args[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -17,21 +17,13 @@ module Gitlab
|
|||
|
||||
strong_memoize(:generic_keyset_pagination_has_next_page) do
|
||||
if before
|
||||
# If `before` is specified, that points to a specific record,
|
||||
# even if it's the last one. Since we're asking for `before`,
|
||||
# then the specific record we're pointing to is in the
|
||||
# next page
|
||||
true
|
||||
elsif first
|
||||
case sliced_nodes
|
||||
when Array
|
||||
sliced_nodes.size > limit_value
|
||||
else
|
||||
# If we count the number of requested items plus one (`limit_value + 1`),
|
||||
# then if we get `limit_value + 1` then we know there is a next page
|
||||
sliced_nodes.limit(1).offset(limit_value).exists?
|
||||
# replacing relation count
|
||||
# relation_count(set_limit(sliced_nodes, limit_value + 1)) == limit_value + 1
|
||||
end
|
||||
else
|
||||
false
|
||||
|
|
|
@ -14955,9 +14955,15 @@ msgstr ""
|
|||
msgid "ExternalAuthorization|URL to which the projects make authorization requests. If the URL is blank, cross-project features are available and can still specify classification labels for projects."
|
||||
msgstr ""
|
||||
|
||||
msgid "ExternalIssueIntegration|Another issue tracker is already in use"
|
||||
msgstr ""
|
||||
|
||||
msgid "ExternalIssueIntegration|Not all data may be displayed here. To view more details or make changes to this issue, go to %{linkStart}%{trackerName}%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "ExternalIssueIntegration|Only one issue tracker integration can be active at a time. Please disable the active tracker first and try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "ExternalIssueIntegration|This issue is synchronized with %{trackerName}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe Projects::EnvironmentsController do
|
|||
include MetricsDashboardHelpers
|
||||
include KubernetesHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:maintainer) { create(:user, name: 'main-dos').tap { |u| project.add_maintainer(u) } }
|
||||
let_it_be(:reporter) { create(:user, name: 'repo-dos').tap { |u| project.add_reporter(u) } }
|
||||
|
||||
|
@ -55,11 +55,11 @@ RSpec.describe Projects::EnvironmentsController do
|
|||
let(:environments) { json_response['environments'] }
|
||||
|
||||
context 'with default parameters' do
|
||||
before do
|
||||
get :index, params: environment_params(format: :json)
|
||||
end
|
||||
subject { get :index, params: environment_params(format: :json) }
|
||||
|
||||
it 'responds with a flat payload describing available environments' do
|
||||
subject
|
||||
|
||||
expect(environments.count).to eq 3
|
||||
expect(environments.first).to include('name' => 'production', 'name_without_type' => 'production')
|
||||
expect(environments.second).to include('name' => 'staging/review-1', 'name_without_type' => 'review-1')
|
||||
|
@ -69,9 +69,28 @@ RSpec.describe Projects::EnvironmentsController do
|
|||
end
|
||||
|
||||
it 'sets the polling interval header' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response.headers['Poll-Interval']).to eq("3000")
|
||||
end
|
||||
|
||||
context 'validates latest deployment' do
|
||||
let_it_be(:test_environment) do
|
||||
create(:environment, project: project, name: 'staging/review-4', state: :available)
|
||||
end
|
||||
|
||||
before do
|
||||
create_list(:deployment, 2, :success, environment: test_environment, project: project)
|
||||
end
|
||||
|
||||
it 'responds with the latest deployment for the environment' do
|
||||
subject
|
||||
|
||||
environment = environments.find { |env| env['id'] == test_environment.id }
|
||||
expect(environment['last_deployment']['id']).to eq(test_environment.deployments.last.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a folder-based nested structure is requested' do
|
||||
|
|
|
@ -224,6 +224,12 @@ FactoryBot.define do
|
|||
recipients { 'test@example.com' }
|
||||
end
|
||||
|
||||
factory :pivotaltracker_integration, class: 'Integrations::Pivotaltracker' do
|
||||
project
|
||||
active { true }
|
||||
token { 'test' }
|
||||
end
|
||||
|
||||
# this is for testing storing values inside properties, which is deprecated and will be removed in
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||
trait :without_properties_callback do
|
||||
|
|
|
@ -35,6 +35,15 @@ describe('ActiveCheckbox', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('when activateDisabled is true', () => {
|
||||
it('renders GlFormCheckbox as disabled', () => {
|
||||
createComponent({ activateDisabled: true });
|
||||
|
||||
expect(findGlFormCheckbox().exists()).toBe(true);
|
||||
expect(findInputInCheckbox().attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialActivated is `false`', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
|
|
|
@ -55,6 +55,7 @@ RSpec.describe IntegrationsHelper do
|
|||
:id,
|
||||
:show_active,
|
||||
:activated,
|
||||
:activate_disabled,
|
||||
:type,
|
||||
:merge_request_events,
|
||||
:commit_events,
|
||||
|
|
|
@ -38,13 +38,67 @@ RSpec.describe Gitlab::BackgroundMigration::JobCoordinator do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#pending_jobs' do
|
||||
context 'when there are enqueued jobs' do
|
||||
let(:queue) do
|
||||
[
|
||||
instance_double(Sidekiq::JobRecord, args: [1, 'queue'], klass: worker_class.name),
|
||||
instance_double(Sidekiq::JobRecord, args: [2, 'queue'], klass: worker_class.name)
|
||||
]
|
||||
end
|
||||
|
||||
let(:queue_incorrect_job_class) do
|
||||
[
|
||||
instance_double(Sidekiq::JobRecord, args: [1, 'queue'], klass: 'SomeOtherClass')
|
||||
]
|
||||
end
|
||||
|
||||
let(:scheduled_set) do
|
||||
[instance_double(Sidekiq::JobRecord, args: [3, 'scheduled'], klass: worker_class.name)]
|
||||
end
|
||||
|
||||
let(:retry_set) do
|
||||
[instance_double(Sidekiq::JobRecord, args: [4, 'retry'], klass: worker_class.name)]
|
||||
end
|
||||
|
||||
let(:dead_set) do
|
||||
[instance_double(Sidekiq::JobRecord, args: [5, 'dead'], klass: worker_class.name)]
|
||||
end
|
||||
|
||||
before do
|
||||
allow(Sidekiq::Queue).to receive(:new)
|
||||
.with(coordinator.queue)
|
||||
.and_return(queue + queue_incorrect_job_class)
|
||||
allow(Sidekiq::ScheduledSet).to receive(:new).and_return(scheduled_set)
|
||||
allow(Sidekiq::RetrySet).to receive(:new).and_return(retry_set)
|
||||
allow(Sidekiq::DeadSet).to receive(:new).and_return(dead_set)
|
||||
end
|
||||
|
||||
it 'does not include jobs for other workers' do
|
||||
expect(coordinator.pending_jobs).not_to include(queue_incorrect_job_class.first)
|
||||
end
|
||||
|
||||
context 'when not including dead jobs' do
|
||||
it 'includes current and future jobs' do
|
||||
expect(coordinator.pending_jobs(include_dead_jobs: false).to_a).to match_array(queue + scheduled_set)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when including dead jobs' do
|
||||
it 'includes current and future jobs, and also dead and retry jobs' do
|
||||
expect(coordinator.pending_jobs(include_dead_jobs: true).to_a).to match_array(queue + scheduled_set + retry_set + dead_set)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#steal' do
|
||||
context 'when there are enqueued jobs present' do
|
||||
let(:queue) do
|
||||
[
|
||||
double(args: ['Foo', [10, 20]], klass: worker_class.name),
|
||||
double(args: ['Bar', [20, 30]], klass: worker_class.name),
|
||||
double(args: ['Foo', [20, 30]], klass: 'MergeWorker')
|
||||
instance_double(Sidekiq::JobRecord, args: ['Foo', [10, 20]], klass: worker_class.name),
|
||||
instance_double(Sidekiq::JobRecord, args: ['Bar', [20, 30]], klass: worker_class.name),
|
||||
instance_double(Sidekiq::JobRecord, args: ['Foo', [20, 30]], klass: 'MergeWorker')
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Database::Migrations::TestBackgroundRunner, :redis do
|
||||
include Gitlab::Database::Migrations::BackgroundMigrationHelpers
|
||||
|
||||
# In order to test the interaction between queueing sidekiq jobs and seeing those jobs in queues,
|
||||
# we need to disable sidekiq's testing mode and actually send our jobs to redis
|
||||
around do |ex|
|
||||
Sidekiq::Testing.disable! { ex.run }
|
||||
end
|
||||
|
||||
context 'without jobs to run' do
|
||||
it 'returns immediately' do
|
||||
runner = described_class.new
|
||||
expect(runner).not_to receive(:run_job)
|
||||
described_class.new.run_jobs(for_duration: 1.second)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with jobs to run' do
|
||||
let(:migration_name) { 'TestBackgroundMigration' }
|
||||
|
||||
before do
|
||||
(1..5).each do |i|
|
||||
migrate_in(i.minutes, migration_name, [i])
|
||||
end
|
||||
end
|
||||
|
||||
context 'finding pending background jobs' do
|
||||
it 'finds all the migrations' do
|
||||
expect(described_class.new.traditional_background_migrations.to_a.size).to eq(5)
|
||||
end
|
||||
end
|
||||
|
||||
context 'running migrations', :freeze_time do
|
||||
def define_background_migration(name)
|
||||
klass = Class.new do
|
||||
# Can't simply def perform here as we won't have access to the block,
|
||||
# similarly can't define_method(:perform, &block) here as it would change the block receiver
|
||||
define_method(:perform) { |*args| yield(*args) }
|
||||
end
|
||||
stub_const("Gitlab::BackgroundMigration::#{name}", klass)
|
||||
klass
|
||||
end
|
||||
|
||||
def expect_migration_call_counts(migrations_to_calls)
|
||||
migrations_to_calls.each do |migration, calls|
|
||||
expect_next_instances_of(migration, calls) do |m|
|
||||
expect(m).to receive(:perform).and_call_original
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'runs the migration class correctly' do
|
||||
calls = []
|
||||
define_background_migration(migration_name) do |i|
|
||||
calls << i
|
||||
end
|
||||
described_class.new.run_jobs(for_duration: 1.second) # Any time would work here as we do not advance time
|
||||
expect(calls).to contain_exactly(1, 2, 3, 4, 5)
|
||||
end
|
||||
|
||||
it 'runs the migration for a uniform amount of time' do
|
||||
migration = define_background_migration(migration_name) do |i|
|
||||
travel(1.minute)
|
||||
end
|
||||
|
||||
expect_migration_call_counts(migration => 3)
|
||||
|
||||
described_class.new.run_jobs(for_duration: 3.minutes)
|
||||
end
|
||||
|
||||
context 'with multiple migrations to run' do
|
||||
let(:other_migration_name) { 'OtherBackgroundMigration' }
|
||||
|
||||
before do
|
||||
(1..5).each do |i|
|
||||
migrate_in(i.minutes, other_migration_name, [i])
|
||||
end
|
||||
end
|
||||
|
||||
it 'splits the time between migrations when all migrations use all their time' do
|
||||
migration = define_background_migration(migration_name) do |i|
|
||||
travel(1.minute)
|
||||
end
|
||||
|
||||
other_migration = define_background_migration(other_migration_name) do |i|
|
||||
travel(2.minutes)
|
||||
end
|
||||
|
||||
expect_migration_call_counts(
|
||||
migration => 2, # 1 minute jobs for 90 seconds, can finish the first and start the second
|
||||
other_migration => 1 # 2 minute jobs for 90 seconds, past deadline after a single job
|
||||
)
|
||||
|
||||
described_class.new.run_jobs(for_duration: 3.minutes)
|
||||
end
|
||||
|
||||
it 'does not give leftover time to extra migrations' do
|
||||
# This is currently implemented this way for simplicity, but it could make sense to change this behavior.
|
||||
|
||||
migration = define_background_migration(migration_name) do
|
||||
travel(1.second)
|
||||
end
|
||||
other_migration = define_background_migration(other_migration_name) do
|
||||
travel(1.minute)
|
||||
end
|
||||
expect_migration_call_counts(
|
||||
migration => 5,
|
||||
other_migration => 2
|
||||
)
|
||||
|
||||
described_class.new.run_jobs(for_duration: 3.minutes)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,12 +3,12 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Integrations::BaseIssueTracker do
|
||||
let(:integration) { Integrations::Redmine.new(project: project, active: true, issue_tracker_data: build(:issue_tracker_data)) }
|
||||
|
||||
let_it_be_with_refind(:project) { create :project }
|
||||
|
||||
describe 'Validations' do
|
||||
let(:project) { create :project }
|
||||
|
||||
describe 'only one issue tracker per project' do
|
||||
let(:integration) { Integrations::Redmine.new(project: project, active: true, issue_tracker_data: build(:issue_tracker_data)) }
|
||||
|
||||
before do
|
||||
create(:custom_issue_tracker_integration, project: project)
|
||||
end
|
||||
|
@ -31,4 +31,18 @@ RSpec.describe Integrations::BaseIssueTracker do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#activate_disabled_reason' do
|
||||
subject { integration.activate_disabled_reason }
|
||||
|
||||
context 'when there is an existing issue tracker integration' do
|
||||
let_it_be(:custom_tracker) { create(:custom_issue_tracker_integration, project: project) }
|
||||
|
||||
it { is_expected.to eq(trackers: [custom_tracker]) }
|
||||
end
|
||||
|
||||
context 'when there is no existing issue tracker integration' do
|
||||
it { is_expected.to be(nil) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3225,52 +3225,44 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
context 'when failed' do
|
||||
shared_examples 'failed skip_ci_check' do
|
||||
context 'when #mergeable_ci_state? is false' do
|
||||
before do
|
||||
allow(subject).to receive(:mergeable_ci_state?) { false }
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.mergeable_state?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns true when skipping ci check' do
|
||||
expect(subject.mergeable_state?(skip_ci_check: true)).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when #mergeable_discussions_state? is false' do
|
||||
before do
|
||||
allow(subject).to receive(:mergeable_discussions_state?) { false }
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.mergeable_state?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns true when skipping discussions check' do
|
||||
expect(subject.mergeable_state?(skip_discussions_check: true)).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when improved_mergeability_checks is on' do
|
||||
it_behaves_like 'failed skip_ci_check'
|
||||
end
|
||||
|
||||
context 'when improved_mergeability_checks is off' do
|
||||
context 'when #mergeable_ci_state? is false' do
|
||||
before do
|
||||
stub_feature_flags(improved_mergeability_checks: false)
|
||||
allow(subject).to receive(:mergeable_ci_state?) { false }
|
||||
end
|
||||
|
||||
it_behaves_like 'failed skip_ci_check'
|
||||
it 'returns false' do
|
||||
expect(subject.mergeable_state?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns true when skipping ci check' do
|
||||
expect(subject.mergeable_state?(skip_ci_check: true)).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when #mergeable_discussions_state? is false' do
|
||||
before do
|
||||
allow(subject).to receive(:mergeable_discussions_state?) { false }
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.mergeable_state?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns true when skipping discussions check' do
|
||||
expect(subject.mergeable_state?(skip_discussions_check: true)).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#mergeable_state?' do
|
||||
context 'when merge state caching is on' do
|
||||
it_behaves_like 'for mergeable_state'
|
||||
|
||||
context 'when improved_mergeability_checks is off' do
|
||||
before do
|
||||
stub_feature_flags(improved_mergeability_checks: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'for mergeable_state'
|
||||
end
|
||||
|
||||
|
|
|
@ -204,6 +204,25 @@ RSpec.describe EnvironmentSerializer do
|
|||
|
||||
json
|
||||
end
|
||||
|
||||
# Validates possible bug that can arise when order_by is not honoured in the preloader.
|
||||
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/353966#note_861381504
|
||||
it 'fetches the last and upcoming deployment correctly' do
|
||||
last_deployment = nil
|
||||
upcoming_deployment = nil
|
||||
create(:environment, project: project).tap do |environment|
|
||||
create(:deployment, :success, environment: environment, project: project)
|
||||
last_deployment = create(:deployment, :success, environment: environment, project: project)
|
||||
|
||||
create(:deployment, :running, environment: environment, project: project)
|
||||
upcoming_deployment = create(:deployment, :running, environment: environment, project: project)
|
||||
end
|
||||
|
||||
response_json = json
|
||||
|
||||
expect(response_json.last[:last_deployment][:id]).to eq(last_deployment.id)
|
||||
expect(response_json.last[:upcoming_deployment][:id]).to eq(upcoming_deployment.id)
|
||||
end
|
||||
end
|
||||
|
||||
def create_environment_with_associations(project)
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe MergeRequests::Mergeability::CheckBrokenStatusService do
|
||||
subject(:check_broken_status) { described_class.new(merge_request: merge_request, params: {}) }
|
||||
|
||||
let(:merge_request) { build(:merge_request) }
|
||||
|
||||
describe '#execute' do
|
||||
before do
|
||||
expect(merge_request).to receive(:broken?).and_return(broken)
|
||||
end
|
||||
|
||||
context 'when the merge request is broken' do
|
||||
let(:broken) { true }
|
||||
|
||||
it 'returns a check result with status failed' do
|
||||
expect(check_broken_status.execute.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::FAILED_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the merge request is not broken' do
|
||||
let(:broken) { false }
|
||||
|
||||
it 'returns a check result with status success' do
|
||||
expect(check_broken_status.execute.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::SUCCESS_STATUS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#skip?' do
|
||||
it 'returns false' do
|
||||
expect(check_broken_status.skip?).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cacheable?' do
|
||||
it 'returns false' do
|
||||
expect(check_broken_status.cacheable?).to eq false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -47,7 +47,7 @@ RSpec.describe MergeRequests::Mergeability::RunChecksService do
|
|||
expect(service).not_to receive(:execute)
|
||||
end
|
||||
|
||||
expect(execute).to match_array([success_result])
|
||||
expect(execute).to match_array([success_result, success_result])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue