Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-05-24 12:09:04 +00:00
parent 43c14d2d92
commit 4b4c254b2c
57 changed files with 301 additions and 226 deletions

View File

@ -1 +1 @@
94055b253d05bc04f533c977be892b0cd6f225ea
803b179a6834fbebcc7886083731bb0f4a67c796

View File

@ -1,6 +1,7 @@
import { spriteIcon } from '~/lib/utils/common_utils';
import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
import { s__ } from '~/locale';
import { unrestrictedPages } from './constants';
// Renders math using KaTeX in any element with the
// `js-render-math` class
@ -48,6 +49,7 @@ class SafeMathRenderer {
this.renderElement = this.renderElement.bind(this);
this.render = this.render.bind(this);
this.attachEvents = this.attachEvents.bind(this);
this.pageName = document.querySelector('body').dataset.page;
}
renderElement(chosenEl) {
@ -56,7 +58,7 @@ class SafeMathRenderer {
}
const el = chosenEl || this.queue.shift();
const forceRender = Boolean(chosenEl);
const forceRender = Boolean(chosenEl) || unrestrictedPages.includes(this.pageName);
const text = el.textContent;
el.removeAttribute('style');

View File

@ -8,6 +8,7 @@ import { __ } from '~/locale';
import '~/behaviors/markdown/render_gfm';
import Suggestions from '~/vue_shared/components/markdown/suggestions.vue';
import autosave from '../mixins/autosave';
import { CONFIDENTIAL_CLASSES } from '../constants';
import noteAttachment from './note_attachment.vue';
import noteAwardsList from './note_awards_list.vue';
import noteEditedText from './note_edited_text.vue';
@ -54,6 +55,11 @@ export default {
required: false,
default: '',
},
isConfidential: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
...mapGetters(['getDiscussion', 'suggestionsCount', 'getSuggestionsFilePaths']),
@ -95,6 +101,12 @@ export default {
return escape(suggestion);
},
confidentialContainerClasses() {
if (this.isConfidential && !this.isEditing) {
return CONFIDENTIAL_CLASSES;
}
return '';
},
},
mounted() {
this.renderGFM();
@ -160,53 +172,61 @@ export default {
</script>
<template>
<div ref="note-body" :class="{ 'js-task-list-container': canEdit }" class="note-body">
<suggestions
v-if="hasSuggestion && !isEditing"
:suggestions="note.suggestions"
:suggestions-count="suggestionsCount"
:batch-suggestions-info="batchSuggestionsInfo"
:note-html="note.note_html"
:line-type="lineType"
:help-page-path="helpPagePath"
:default-commit-message="commitMessage"
:failed-to-load-metadata="failedToLoadMetadata"
@apply="applySuggestion"
@applyBatch="applySuggestionBatch"
@addToBatch="addSuggestionToBatch"
@removeFromBatch="removeSuggestionFromBatch"
/>
<div v-else v-safe-html:[$options.safeHtmlConfig]="note.note_html" class="note-text md"></div>
<note-form
v-if="isEditing"
ref="noteForm"
:note-body="noteBody"
:note-id="note.id"
:line="line"
:note="note"
:save-button-title="saveButtonTitle"
:help-page-path="helpPagePath"
:discussion="discussion"
:resolve-discussion="note.resolve_discussion"
@handleFormUpdate="handleFormUpdate"
@cancelForm="formCancelHandler"
/>
<!-- eslint-disable vue/no-mutating-props -->
<textarea
v-if="canEdit"
v-model="note.note"
:data-update-url="note.path"
class="hidden js-task-list-field"
dir="auto"
></textarea>
<!-- eslint-enable vue/no-mutating-props -->
<note-edited-text
v-if="note.last_edited_at"
:edited-at="note.last_edited_at"
:edited-by="note.last_edited_by"
action-text="Edited"
class="note_edited_ago"
/>
<div
ref="note-body"
:class="{
'js-task-list-container': canEdit,
}"
class="note-body"
>
<div :class="confidentialContainerClasses" data-testid="note-confidential-container">
<suggestions
v-if="hasSuggestion && !isEditing"
:suggestions="note.suggestions"
:suggestions-count="suggestionsCount"
:batch-suggestions-info="batchSuggestionsInfo"
:note-html="note.note_html"
:line-type="lineType"
:help-page-path="helpPagePath"
:default-commit-message="commitMessage"
:failed-to-load-metadata="failedToLoadMetadata"
@apply="applySuggestion"
@applyBatch="applySuggestionBatch"
@addToBatch="addSuggestionToBatch"
@removeFromBatch="removeSuggestionFromBatch"
/>
<div v-else v-safe-html:[$options.safeHtmlConfig]="note.note_html" class="note-text md"></div>
<note-form
v-if="isEditing"
ref="noteForm"
:note-body="noteBody"
:note-id="note.id"
:line="line"
:note="note"
:save-button-title="saveButtonTitle"
:help-page-path="helpPagePath"
:discussion="discussion"
:resolve-discussion="note.resolve_discussion"
@handleFormUpdate="handleFormUpdate"
@cancelForm="formCancelHandler"
/>
<!-- eslint-disable vue/no-mutating-props -->
<textarea
v-if="canEdit"
v-model="note.note"
:data-update-url="note.path"
class="hidden js-task-list-field"
dir="auto"
></textarea>
<!-- eslint-enable vue/no-mutating-props -->
<note-edited-text
v-if="note.last_edited_at"
:edited-at="note.last_edited_at"
:edited-by="note.last_edited_by"
action-text="Edited"
class="note_edited_ago"
/>
</div>
<note-awards-list
v-if="note.award_emoji && note.award_emoji.length"
:note-id="note.id"

View File

@ -236,6 +236,7 @@ export default {
data-testid="internalNoteIndicator"
variant="warning"
size="sm"
class="gl-mb-3 gl-ml-2"
:title="noteConfidentialityTooltip"
>
{{ __('Internal note') }}

View File

@ -493,9 +493,10 @@ export default {
<note-body
ref="noteBody"
:note="note"
:can-edit="note.current_user.can_edit"
:is-confidential="note.confidential"
:line="line"
:file="diffFile"
:can-edit="note.current_user.can_edit"
:is-editing="isEditing"
:help-page-path="helpPagePath"
@handleFormUpdate="formUpdateHandler"

View File

@ -51,3 +51,5 @@ export const toggleStateErrorMessage = {
[REOPENED]: __('Something went wrong while closing the merge request. Please try again later.'),
},
};
export const CONFIDENTIAL_CLASSES = ['gl-bg-orange-50', 'gl-px-4', 'gl-py-2'];

View File

@ -168,7 +168,7 @@ export default {
if (data || operator) {
this.searchKey = data;
if (!this.suggestionsLoading && !this.activeTokenValue) {
if (!this.activeTokenValue) {
let search = this.searchTerm ? this.searchTerm : data;
if (search.startsWith('"') && search.endsWith('"')) {

View File

@ -568,6 +568,10 @@ module Ci
options&.dig(:environment, :on_stop)
end
def stop_action_successful?
Feature.disabled?(:env_stopped_on_stop_success, project) || success?
end
##
# All variables, including persisted environment variables.
#

View File

@ -132,10 +132,16 @@ class Environment < ApplicationRecord
end
event :stop do
transition available: :stopped
transition available: :stopping, if: :wait_for_stop?
transition available: :stopped, unless: :wait_for_stop?
end
event :stop_complete do
transition %i(available stopping) => :stopped
end
state :available
state :stopping
state :stopped
before_transition any => :stopped do |environment|
@ -293,6 +299,10 @@ class Environment < ApplicationRecord
end
end
def wait_for_stop?
stop_actions.present? && Feature.enabled?(:env_stopped_on_stop_success, project)
end
def stop_with_actions!(current_user)
return unless available?

View File

@ -7,7 +7,11 @@ module Environments
def execute(environment)
return unless can?(current_user, :stop_environment, environment)
environment.stop_with_actions!(current_user)
if params[:force]
environment.stop_complete!
else
environment.stop_with_actions!(current_user)
end
end
def execute_for_branch(branch_name)

View File

@ -32,7 +32,7 @@
- if impersonation_enabled? && @user.can?(:log_in)
= link_to _('Impersonate'), impersonate_admin_user_path(@user), method: :post, class: "btn btn-default gl-button", data: { qa_selector: 'impersonate_user_link' }
- if can_force_email_confirmation?(@user)
%button.btn.gl-button.btn-info.js-confirm-modal-button{ data: confirm_user_data(@user) }
%button.btn.gl-button.btn-confirm.js-confirm-modal-button{ data: confirm_user_data(@user) }
= _('Confirm user')
.gl-p-2
#js-admin-user-actions{ data: admin_user_actions_data_attributes(@user) }

View File

@ -23,7 +23,7 @@
title: group_url_error_message,
maxlength: ::Namespace::URL_MAX_LENGTH,
"data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
= f.submit s_('GroupSettings|Change group URL'), class: 'btn gl-button btn-warning'
= f.submit s_('GroupSettings|Change group URL'), class: 'btn gl-button btn-danger'
= render 'groups/settings/transfer', group: @group
= render 'groups/settings/remove', group: @group, remove_form_id: remove_form_id

View File

@ -2983,15 +2983,6 @@
:weight: 1
:idempotent:
:tags: []
- :name: repository_remove_remote
:worker_name: RepositoryRemoveRemoteWorker
:feature_category: :source_code_management
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent:
:tags: []
- :name: repository_update_remote_mirror
:worker_name: RepositoryUpdateRemoteMirrorWorker
:feature_category: :source_code_management

View File

@ -13,13 +13,13 @@ class BuildSuccessWorker # rubocop:disable Scalability/IdempotentWorker
def perform(build_id)
Ci::Build.find_by_id(build_id).try do |build|
stop_environment(build) if build.stops_environment?
stop_environment(build) if build.stops_environment? && build.stop_action_successful?
end
end
private
def stop_environment(build)
build.persisted_environment.fire_state_event(:stop)
build.persisted_environment.fire_state_event(:stop_complete)
end
end

View File

@ -1,35 +0,0 @@
# frozen_string_literal: true
class RepositoryRemoveRemoteWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
data_consistency :always
sidekiq_options retry: 3
include ExclusiveLeaseGuard
feature_category :source_code_management
loggable_arguments 1
LEASE_TIMEOUT = 1.hour
attr_reader :project, :remote_name
def perform(project_id, remote_name)
# On-disk remotes are slated for removal, and GitLab doesn't create any of
# them anymore. For backwards compatibility, we need to keep the worker
# though such that we can be sure to drain all jobs on an update. Making
# this a no-op is fine though: the worst that can happen is that we still
# have old remotes lingering in the repository's config, but Gitaly will
# start to clean these up in repository maintenance.
# https://gitlab.com/gitlab-org/gitlab/-/issues/336745
end
def lease_timeout
LEASE_TIMEOUT
end
def lease_key
"remove_remote_#{project.id}_#{remote_name}"
end
end

View File

@ -0,0 +1,8 @@
---
name: env_stopped_on_stop_success
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86478
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/361473
milestone: '15.0'
type: development
group: group::release
default_enabled: false

View File

@ -407,8 +407,6 @@
- 1
- - repository_push_audit_event
- 1
- - repository_remove_remote
- 1
- - repository_update_mirror
- 1
- - repository_update_remote_mirror

View File

@ -3,7 +3,7 @@ table_name: ci_builds_runner_session
classes:
- Ci::BuildRunnerSession
feature_categories:
- continuous_integration
description: TODO
- runner
description: Store build-related runner session. Data is removed after the respective job transitions from running to any state.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6208
milestone: '11.1'

View File

@ -120,7 +120,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Creating users](../user/profile/account/create_accounts.md): Create users manually or through authentication integrations.
- [Libravatar](libravatar.md): Use Libravatar instead of Gravatar for user avatars.
- [Sign-up restrictions](../user/admin_area/settings/sign_up_restrictions.md): block email addresses of specific domains, or whitelist only specific domains.
- [Sign-up restrictions](../user/admin_area/settings/sign_up_restrictions.md): block email addresses of specific domains, or allow only specific domains.
- [Access restrictions](../user/admin_area/settings/visibility_and_access_controls.md#configure-enabled-git-access-protocols): Define which Git access protocols can be used to talk to GitLab (SSH, HTTP, HTTPS).
- [Authentication and Authorization](auth/index.md): Configure external authentication with LDAP, SAML, CAS, and additional providers.
- [Sync LDAP](auth/ldap/index.md)

View File

@ -1170,7 +1170,7 @@ The flow described by the diagram above:
1. A user runs `docker login registry.gitlab.example` on their client. This reaches the web server (or LB) on port 443.
1. Web server connects to the Registry backend pool (by default, using port 5000). Since the user
didnt provide a valid token, the Registry returns a 401 HTTP code and the URL (`token_realm` from
didn't provide a valid token, the Registry returns a 401 HTTP code and the URL (`token_realm` from
Registry configuration) where to get one. This points to the GitLab API.
1. The Docker client then connects to the GitLab API and obtains a token.
1. The API signs the token with the registry key and hands it to the Docker client

View File

@ -1187,7 +1187,8 @@ Rate limits are enforced using the following:
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
important to describe those, too. Think of things that may go wrong and include them here.
important to describe those, too. Think of things that may go wrong and include them in
the section below.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
@ -1541,7 +1542,7 @@ In GitLab 14.0-14.2 you can temporarily enable legacy storage and configuration
To do that:
1. Please describe the issue you're seeing in [here](https://gitlab.com/gitlab-org/gitlab/-/issues/331699).
1. Please describe the issue you're seeing in the [migration feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/331699).
1. Edit `/etc/gitlab/gitlab.rb`:

View File

@ -62,7 +62,7 @@ monitor .[#7FFFD4,norank]--> redis
@enduml
```
The diagram above shows that while GitLab can be installed on a single server, it is internally composed of multiple services. As a GitLab instance is scaled, each of these services are broken out and independently scaled according to the demands placed on them. In some cases PaaS can be leveraged for some services (e.g. Cloud Object Storage for some file systems). For the sake of redundancy some of the services become clusters of nodes storing the same data. In a horizontal configuration of GitLab there are various ancillary services required to coordinate clusters or discover of resources (e.g. PgBouncer for PostgreSQL connection management, Consul for Prometheus end point discovery).
The diagram above shows that while GitLab can be installed on a single server, it is internally composed of multiple services. As a GitLab instance is scaled, each of these services are broken out and independently scaled according to the demands placed on them. In some cases PaaS can be leveraged for some services (for example, Cloud Object Storage for some file systems). For the sake of redundancy some of the services become clusters of nodes storing the same data. In a horizontal configuration of GitLab there are various ancillary services required to coordinate clusters or discover of resources (for example, PgBouncer for PostgreSQL connection management, Consul for Prometheus end point discovery).
## Requirements

View File

@ -116,7 +116,7 @@ per 1,000 users:
### How to interpret the results
NOTE:
Read our blog post on [how our QA team leverages GitLabs performance testing tool](https://about.gitlab.com/blog/2020/02/18/how-were-building-up-performance-testing-of-gitlab/).
Read our blog post on [how our QA team leverages GitLab performance testing tool](https://about.gitlab.com/blog/2020/02/18/how-were-building-up-performance-testing-of-gitlab/).
Testing is done publicly and all results are shared.

View File

@ -15,12 +15,12 @@ Get all environments for a given project.
GET /projects/:id/environments
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `name` | string | no | Return the environment with this name. Mutually exclusive with `search` |
| `search` | string | no | Return list of environments matching the search criteria. Mutually exclusive with `name` |
| `states` | string | no | List all environments that match a specific state. Accepted values: `available` or `stopped`. If no state value given, returns all environments. |
| Attribute | Type | Required | Description |
| --------- | ------- | -------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `name` | string | no | Return the environment with this name. Mutually exclusive with `search` |
| `search` | string | no | Return list of environments matching the search criteria. Mutually exclusive with `name` |
| `states` | string | no | List all environments that match a specific state. Accepted values: `available`, `stopping` or `stopped`. If no state value given, returns all environments. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments?name=review%2Ffix-foo"
@ -382,10 +382,11 @@ It returns `200` if the environment was successfully stopped, and `404` if the e
POST /projects/:id/environments/:environment_id/stop
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `environment_id` | integer | yes | The ID of the environment |
| Attribute | Type | Required | Description |
|------------------|----------------|----------|----------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `environment_id` | integer | yes | The ID of the environment |
| `force` | boolean | no | Force environment to stop even when `on_stop` action fails |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments/1/stop"

View File

@ -234,8 +234,8 @@ Parameters:
|:-------------|:---------------|:---------|:----------------------------------------------------------------------------------------------------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `snippet_id` | integer | yes | The ID of a project's snippet |
| `ref` | string | yes | The name of a branch, tag or commit e.g. master |
| `file_path` | string | yes | The URL-encoded path to the file, e.g. snippet%2Erb |
| `ref` | string | yes | The name of a branch, tag or commit, for example, main |
| `file_path` | string | yes | The URL-encoded path to the file, for example, snippet%2Erb |
Example request:

View File

@ -90,6 +90,10 @@ To view CI/CD minutes being used for your group:
![Group CI/CD minutes quota](img/group_cicd_minutes_quota.png)
The projects list shows projects with CI/CD minute usage or shared runners usage
in the current month only. The list includes all projects in the namespace and its
subgroups, sorted in descending order of CI/CD minute usage.
## View CI/CD minutes used by a personal namespace
> Displaying shared runners duration [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345795) in GitLab 15.0.
@ -100,6 +104,10 @@ You can view the number of CI/CD minutes being used by a personal namespace:
1. Select **Edit profile**.
1. On the left sidebar, select **Usage Quotas**.
The projects list shows [personal projects](../../user/project/working_with_projects.md#view-personal-projects)
with CI/CD minutes usage or shared runners usage in the current month only. The list
is sorted in descending order of CI/CD minute usage.
## Purchase additional CI/CD minutes **(FREE SAAS)**
If you're using GitLab SaaS, you can purchase additional packs of CI/CD minutes.

View File

@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9186) in GitLab 12.0.
> - [Squash and merge](../../user/project/merge_requests/squash_and_merge.md) support [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13001) in GitLab 12.6.
For more information about why you might want to use merge trains, read [How merge trains keep your master green](https://about.gitlab.com/blog/2020/01/30/all-aboard-merge-trains/).
For more information about why you might want to use merge trains, read [How starting merge trains improve efficiency for DevOps](https://about.gitlab.com/blog/2020/01/30/all-aboard-merge-trains/).
When [merged results pipelines](merged_results_pipelines.md) are
enabled, the pipeline jobs run as if the changes from your source branch have already

View File

@ -53,7 +53,7 @@ and they serve us and our users well. Some examples of these principles are that
- The feedback delivered by GitLab CI/CD and data produced by the platform should be accurate.
If a job fails and we notify a user that it was successful, it can have severe negative consequences.
- Feedback needs to be available when a user needs it and data can not disappear unexpectedly when engineers need it.
- It all doesnt matter if the platform is not secure and we
- It all doesn't matter if the platform is not secure and we
are leaking credentials or secrets.
- When a user provides a set of preconditions in a form of CI/CD configuration, the result should be deterministic each time a pipeline runs, because otherwise the platform might not be trustworthy.
- If it is fast, simple to use and has a great UX it will serve our users well.

View File

@ -67,9 +67,9 @@ In the `detect-tests` job, we use this mapping to identify the minimal tests nee
In addition, there are a few circumstances where we would always run the full RSpec tests:
- when the `pipeline:run-all-rspec` label is set on the merge request
- when the merge request is created by an automation (e.g. Gitaly update or MR targeting a stable branch)
- when the merge request is created by an automation (for example, Gitaly update or MR targeting a stable branch)
- when the merge request is created in a security mirror
- when any CI configuration file is changed (i.e. `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
### Jest minimal jobs
@ -83,11 +83,11 @@ In this mode, `jest` would resolve all the dependencies of related to the change
In addition, there are a few circumstances where we would always run the full Jest tests:
- when the `pipeline:run-all-jest` label is set on the merge request
- when the merge request is created by an automation (e.g. Gitaly update or MR targeting a stable branch)
- when the merge request is created by an automation (for example, Gitaly update or MR targeting a stable branch)
- when the merge request is created in a security mirror
- when any CI configuration file is changed (i.e. `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
- when any frontend "core" file is changed (i.e. `package.json`, `yarn.lock`, `babel.config.js`, `jest.config.*.js`, `config/helpers/**/*.js`)
- when any vendored JavaScript file is changed (i.e. `vendor/assets/javascripts/**/*`)
- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
- when any frontend "core" file is changed (for example, `package.json`, `yarn.lock`, `babel.config.js`, `jest.config.*.js`, `config/helpers/**/*.js`)
- when any vendored JavaScript file is changed (for example, `vendor/assets/javascripts/**/*`)
- when any backend file is changed ([see the patterns list for details](https://gitlab.com/gitlab-org/gitlab/-/blob/3616946936c1adbd9e754c1bd06f86ba670796d8/.gitlab/ci/rules.gitlab-ci.yml#L205-216))
### Fork pipelines
@ -226,7 +226,7 @@ of `gitlab-org/gitlab-foss`. These jobs are only created in the following cases:
- when the `pipeline:run-as-if-foss` label is set on the merge request
- when the merge request is created in the `gitlab-org/security/gitlab` project
- when any CI configuration file is changed (i.e. `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
The `* as-if-foss` jobs are run in addition to the regular EE-context jobs. They have the `FOSS_ONLY='1'` variable
set and get the `ee/` folder removed before the tests start running.
@ -339,7 +339,7 @@ In general, pipelines for an MR fall into one of the following types (from short
- [Frontend pipeline](#frontend-pipeline): For MRs that touch frontend code.
- [End-to-end pipeline](#end-to-end-pipeline): For MRs that touch code in the `qa/` folder.
A "pipeline type" is an abstract term that mostly describes the "critical path" (i.e. the chain of jobs for which the sum
A "pipeline type" is an abstract term that mostly describes the "critical path" (for example, the chain of jobs for which the sum
of individual duration equals the pipeline's duration).
We use these "pipeline types" in [metrics dashboards](https://app.periscopedata.com/app/gitlab/858266/GitLab-Pipeline-Durations)
in order to detect what types and jobs need to be optimized first.
@ -719,11 +719,11 @@ This job tries to download a generic package that contains GitLab Workhorse bina
We also changed the `setup-test-env` job to:
1. First download the GitLab Workhorse generic package build and uploaded by `build-components`.
1. If the package is retrieved successfully, its content is placed in the right folder (i.e. `tmp/tests/gitlab-workhorse`), preventing the building of the binaries when `scripts/setup-test-env` is run later on.
1. If the package is retrieved successfully, its content is placed in the right folder (for example, `tmp/tests/gitlab-workhorse`), preventing the building of the binaries when `scripts/setup-test-env` is run later on.
1. If the package URL returns a 404, the behavior doesn't change compared to the current one: the GitLab Workhorse binaries are built as part of `scripts/setup-test-env`.
NOTE:
The version of the package is the workhorse tree SHA (i.e. `git rev-parse HEAD:workhorse`).
The version of the package is the workhorse tree SHA (for example, `git rev-parse HEAD:workhorse`).
### Pre-clone step

View File

@ -58,7 +58,7 @@ By using a `before_action` you don't have to modify the controller method in
question, reducing the likelihood of merge conflicts.
For Grape API endpoints there unfortunately is not a reliable way of running a
hook before a specific endpoint. This means that you have to add the whitelist
hook before a specific endpoint. This means that you have to add the allowlist
call directly into the endpoint like so:
```ruby

View File

@ -24,7 +24,7 @@ Some examples where you would need to do this are:
## Database connections in initializers
Ideally, database connections are not opened from Rails initializers. Opening a
database connection (e.g. checking the database exists, or making a database
database connection (for example, checking the database exists, or making a database
query) from an initializer means that tasks like `db:drop`, and
`db:test:prepare` will fail because an active session prevents the database from
being dropped.

View File

@ -104,6 +104,6 @@ To get started, see an [example merge request](https://gitlab.com/gitlab-org/git
## Useful links
- [Routing improvements master plan](https://gitlab.com/gitlab-org/gitlab/-/issues/215362)
- [Routing improvements main plan](https://gitlab.com/gitlab-org/gitlab/-/issues/215362)
- [Scoped routing explained](https://gitlab.com/gitlab-org/gitlab/-/issues/214217)
- [Removal of deprecated routes](https://gitlab.com/gitlab-org/gitlab/-/issues/28848)

View File

@ -698,7 +698,7 @@ tls.Config{
}
```
This example was taken [here](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/871b52dc700f1a66f6644fbb1e78a6d463a6ff83/internal/tool/tlstool/tlstool.go#L72).
This example was taken [from the GitLab Agent](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/871b52dc700f1a66f6644fbb1e78a6d463a6ff83/internal/tool/tlstool/tlstool.go#L72).
For **Ruby**, you can use again [`HTTParty`](https://github.com/jnunemaker/httparty) and specify this time TLS 1.2 version alongside with the recommended ciphers:

View File

@ -464,7 +464,7 @@ To generate Service Ping, use [Teleport](https://goteleport.com/docs/) or a deta
1. Get the metrics duration from logs:
Search in Google Console logs for `time_elapsed`. Query example [here](https://cloudlogging.app.goo.gl/nWheZvD8D3nWazNe6).
Search in Google Console logs for `time_elapsed`. [Query example](https://cloudlogging.app.goo.gl/nWheZvD8D3nWazNe6).
### Verification (After approx 30 hours)

View File

@ -531,7 +531,7 @@ When you implement a new type of reusable resource there are two `private` metho
can be validated. They are:
- `reference_resource`: creates a new instance of the resource that can be compared with the one that was used during the tests.
- `unique_identifiers`: returns an array of attributes that allow the resource to be identified (e.g., name) and that are therefore
- `unique_identifiers`: returns an array of attributes that allow the resource to be identified (for example, name) and that are therefore
expected to differ when comparing the reference resource with the resource reused in the tests.
The following example shows the implementation of those two methods in `QA::Resource::ReusableProject`.

View File

@ -211,7 +211,7 @@ sudo apt-get install -y libimage-exiftool-perl
## 2. Ruby
The Ruby interpreter is required to run GitLab.
See the [requirements section of this page](#software-requirements) for the minimum
See the [requirements section](#software-requirements) for the minimum
Ruby requirements.
The use of Ruby version managers such as [`RVM`](https://rvm.io/), [`rbenv`](https://github.com/rbenv/rbenv) or [`chruby`](https://github.com/postmodern/chruby) with GitLab

View File

@ -192,9 +192,9 @@ If you have any questions, send an email to `opensource@gitlab.com` for assistan
GitLab for Open Source Program benefits apply to an entire GitLab namespace. To qualify for the GitLab for Open Source Program, **all projects in an applicant's namespace** must carry an [OSI-approved license](https://opensource.org/licenses/).
To add a license:
To add a license:
1. On the top bar, select **Menu > Projects** and find your project.
1. On the top bar, select **Menu > Projects** and find your project.
1. On the overview page, select **Add LICENSE**. If the license you want is not available as a license template, manually copy the entire, unaltered [text of your chosen license](https://opensource.org/licenses/alphabetical) into the `LICENSE` file. Note that GitLab defaults to **All rights reserved** if users do not perform this action.
Applicants must add the correct license to each project in their respective groups or namespaces When you're sure you're using OSI-approved licenses for your projects, you can take your screenshots.
@ -229,7 +229,7 @@ Benefits of the GitLab Open Source Program apply to all projects in a GitLab nam
To be eligible for the GitLab Open Source Program, projects must be publicly visible. To check your project's public visibility settings:
1. On the top bar, select **Menu > Projects** and find your project.
1. On the top bar, select **Menu > Projects** and find your project.
1. From the left sidebar, select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. From the **Project visibility** dropdown list, select **Public**.

View File

@ -589,7 +589,7 @@ You can only upgrade one minor release at a time.
This section describes the steps required to upgrade a multi-node / HA
deployment with Geo. Some steps must be performed on a particular node. This
node is known as the “deploy node” and is noted through the following
node is known as the "deploy node" and is noted through the following
instructions.
Updates must be performed in the following order:

View File

@ -95,7 +95,7 @@ is **not** `19.03.0`. See [troubleshooting information](#error-response-from-dae
WARNING:
Dependency Scanning does not support run-time installation of compilers and interpreters.
If you have need of this, please explain why by filling out the survey [here](https://docs.google.com/forms/d/e/1FAIpQLScKo7xEYA65rOjPTGIufAyfjPGnCALSJZoTxBlvskfFMEOZMw/viewform).
If you need it, please explain why by filling out [the survey](https://docs.google.com/forms/d/e/1FAIpQLScKo7xEYA65rOjPTGIufAyfjPGnCALSJZoTxBlvskfFMEOZMw/viewform).
## Supported languages and package managers
@ -1225,7 +1225,7 @@ version `58.1.0+`, which doesn't support `2to3`. Therefore, a `setuptools` depen
error in <dependency name> setup command: use_2to3 is invalid
```
To work around this error, downgrade the analyzer's version of `setuptools` (e.g. `v57.5.0`):
To work around this error, downgrade the analyzer's version of `setuptools` (for example, `v57.5.0`):
```yaml
gemnasium-python-dependency_scanning:

View File

@ -136,13 +136,13 @@ GitLab also provides a [KPT package for the agent](https://gitlab.com/gitlab-org
To install a second agent in your cluster, you can follow the [previous steps](#register-the-agent-with-gitlab) a second time. To avoid resource name collisions within the cluster, you must either:
- Use a different release name for the agent, e.g. `second-gitlab-agent`:
- Use a different release name for the agent, for example, `second-gitlab-agent`:
```shell
helm upgrade --install second-gitlab-agent gitlab/gitlab-agent ...
```
- Or, install the agent in a different namespace, e.g. `different-namespace`:
- Or, install the agent in a different namespace, for example, `different-namespace`:
```shell
helm upgrade --install gitlab-agent gitlab/gitlab-agent \
@ -163,7 +163,7 @@ The following example projects can help you get started with the agent.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340882) in GitLab 14.8, GitLab warns you on the agent's list page to update the agent version installed on your cluster.
For the best experience, the version of the agent installed in your cluster should match the GitLab major and minor version. The previous minor version is also supported. For example, if your GitLab version is v14.9.4 (major version 14, minor version 9), then versions v14.9.0 and v14.9.1 of the agent are ideal, but any v14.8.x version of the agent is also supported. See [this page](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/releases) of releases of the GitLab agent.
For the best experience, the version of the agent installed in your cluster should match the GitLab major and minor version. The previous minor version is also supported. For example, if your GitLab version is v14.9.4 (major version 14, minor version 9), then versions v14.9.0 and v14.9.1 of the agent are ideal, but any v14.8.x version of the agent is also supported. See [the release page](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/releases) of the GitLab agent.
### Update the agent version

View File

@ -91,7 +91,7 @@ Introduced in GitLab 13.6, the themes [Solarized](https://gitlab.com/gitlab-org/
## Diff colors
A diff compares the old/removed content with the new/added content (e.g. when
A diff compares the old/removed content with the new/added content (for example, when
[reviewing a merge request](../project/merge_requests/reviews/index.md#review-a-merge-request) or in a
[Markdown inline diff](../markdown.md#inline-diff)).
Typically, the colors red and green are used for removed and added lines in diffs.

View File

@ -128,14 +128,14 @@ module API
end
params do
requires :environment_id, type: Integer, desc: 'The environment ID'
optional :force, type: Boolean, default: false
end
post ':id/environments/:environment_id/stop' do
authorize! :read_environment, user_project
environment = user_project.environments.find(params[:environment_id])
authorize! :stop_environment, environment
environment.stop_with_actions!(current_user)
::Environments::StopService.new(user_project, current_user, declared_params(include_missing: false))
.execute(environment)
status 200
present environment, with: Entities::Environment, current_user: current_user

View File

@ -24,7 +24,7 @@ module QA
end
def enable_ff_only
choose_element(:merge_ff_radio)
choose_element(:merge_ff_radio, true)
click_save_changes
end

View File

@ -67,7 +67,7 @@ RSpec.describe "User comments on issue", :js do
it "edits comment" do
add_note("# Comment with a header")
page.within(".note-body > .note-text") do
page.within(".note-body .note-text") do
expect(page).to have_content("Comment with a header").and have_no_css("#comment-with-a-header")
end

View File

@ -67,4 +67,24 @@ RSpec.describe 'Math rendering', :js do
expect(page).to have_selector('.js-lazy-render-math')
end
end
it 'renders without any limits on wiki page', :js do
description = <<~MATH
```math
\Huge \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
```
MATH
wiki_page = build(:wiki_page, { container: project, content: description })
wiki_page.create message: 'math test commit' # rubocop:disable Rails/SaveBang
wiki_page = project.wiki.find_page(wiki_page.slug)
visit project_wiki_path(project, wiki_page)
wait_for_requests
page.within '.js-wiki-page-content' do
expect(page).not_to have_selector('.js-lazy-render-math')
end
end
end

View File

@ -158,7 +158,7 @@ RSpec.describe 'Merge request > User posts notes', :js do
page.within("#note_#{note.id}") do
expect(find('.current-note-edit-form', visible: true)).to be_visible
expect(find('.note-edit-form', visible: true)).to be_visible
expect(find(:css, '.note-body > .note-text', visible: false)).not_to be_visible
expect(find(:css, '.note-body .note-text', visible: false)).not_to be_visible
end
end

View File

@ -284,7 +284,6 @@ RSpec.describe 'Environment' do
click_button('Stop')
click_button('Stop environment') # confirm modal
wait_for_all_requests
expect(page).to have_button('Delete')
end
end
@ -362,8 +361,6 @@ RSpec.describe 'Environment' do
end
visit_environment(environment)
expect(page).not_to have_button('Stop')
end
##

View File

@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { suggestionCommitMessage } from '~/diffs/store/getters';
import NoteBody from '~/notes/components/note_body.vue';
@ -7,6 +7,7 @@ import NoteAwardsList from '~/notes/components/note_awards_list.vue';
import NoteForm from '~/notes/components/note_form.vue';
import createStore from '~/notes/stores';
import notes from '~/notes/stores/modules/index';
import { CONFIDENTIAL_CLASSES } from '~/notes/constants';
import Suggestions from '~/vue_shared/components/markdown/suggestions.vue';
@ -27,7 +28,7 @@ const createComponent = ({
mockStore.dispatch('setNotesData', notesData);
}
return shallowMount(NoteBody, {
return shallowMountExtended(NoteBody, {
store: mockStore || store,
propsData: {
note,
@ -58,6 +59,24 @@ describe('issue_note_body component', () => {
expect(wrapper.findComponent(NoteAwardsList).exists()).toBe(true);
});
it('should not have confidential classes', () => {
expect(wrapper.findByTestId('note-confidential-container').classes()).not.toEqual(
CONFIDENTIAL_CLASSES,
);
});
describe('isConfidential', () => {
beforeEach(() => {
wrapper = createComponent({ props: { isConfidential: true } });
});
it('should have confidential classes', () => {
expect(wrapper.findByTestId('note-confidential-container').classes()).toEqual(
CONFIDENTIAL_CLASSES,
);
});
});
describe('isEditing', () => {
beforeEach(() => {
wrapper = createComponent({ props: { isEditing: true } });
@ -86,6 +105,18 @@ describe('issue_note_body component', () => {
// which is defined in `app/assets/javascripts/notes/mixins/autosave.js`
expect(wrapper.vm.autosave.key).toEqual(autosaveKey);
});
describe('isConfidential', () => {
beforeEach(() => {
wrapper.setProps({ isConfidential: true });
});
it('should not have confidential classes', () => {
expect(wrapper.findByTestId('note-confidential-container').classes()).not.toEqual(
CONFIDENTIAL_CLASSES,
);
});
});
});
describe('commitMessage', () => {

View File

@ -586,6 +586,24 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
expect(action).to eq(close_action)
expect(action.user).to eq(user)
end
context 'env_stopped_on_stop_success feature flag' do
it 'environment is not stopped when flag is enabled' do
stub_feature_flags(env_stopped_on_stop_success: true)
subject
expect(environment).not_to be_stopped
end
it 'environment is stopped when flag is disabled' do
stub_feature_flags(env_stopped_on_stop_success: false)
subject
expect(environment).to be_stopped
end
end
end
context 'if action did finish' do
@ -1730,17 +1748,17 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
let!(:environment3) { create(:environment, project: project, state: 'stopped') }
it 'returns the environments count grouped by state' do
expect(project.environments.count_by_state).to eq({ stopped: 2, available: 1 })
expect(project.environments.count_by_state).to eq({ stopped: 2, available: 1, stopping: 0 })
end
it 'returns the environments count grouped by state with zero value' do
environment2.update!(state: 'stopped')
expect(project.environments.count_by_state).to eq({ stopped: 3, available: 0 })
expect(project.environments.count_by_state).to eq({ stopped: 3, available: 0, stopping: 0 })
end
end
it 'returns zero state counts when environments are empty' do
expect(project.environments.count_by_state).to eq({ stopped: 0, available: 0 })
expect(project.environments.count_by_state).to eq({ stopped: 0, available: 0, stopping: 0 })
end
end

View File

@ -254,8 +254,6 @@ RSpec.describe RemoteMirror, :mailer do
it 'does not remove the remote' do
mirror = create_mirror(url: 'http://foo:bar@test.com')
expect(RepositoryRemoveRemoteWorker).not_to receive(:perform_async)
mirror.destroy!
end
end

View File

@ -84,7 +84,7 @@ RSpec.describe Deployments::UpdateEnvironmentService do
context 'and environment is stopped' do
before do
environment.stop
environment.stop_complete
end
it 'makes environment available' do

View File

@ -37,7 +37,7 @@ RSpec.describe Environments::AutoStopService, :clean_gitlab_redis_shared_state,
it 'stops environments and play stop jobs' do
expect { subject }
.to change { Environment.all.map(&:state).uniq }
.from(['available']).to(['stopped'])
.from(['available']).to(['stopping'])
expect(Ci::Build.where(name: 'stop_review_app').map(&:status).uniq).to eq(['pending'])
end

View File

@ -29,14 +29,27 @@ RSpec.describe Environments::StopService do
review_job.success!
end
it 'stops the environment' do
expect { subject }.to change { environment.reload.state }.from('available').to('stopped')
context 'without stop action' do
let!(:environment) { create(:environment, :available, project: project) }
it 'stops the environment' do
expect { subject }.to change { environment.reload.state }.from('available').to('stopped')
end
end
it 'plays the stop action' do
expect { subject }.to change { stop_review_job.reload.status }.from('manual').to('pending')
end
context 'force option' do
let(:service) { described_class.new(project, user, { force: true }) }
it 'does not play the stop action when forced' do
expect { subject }.to change { environment.reload.state }.from('available').to('stopped')
expect(stop_review_job.reload.status).to eq('manual')
end
end
context 'when an environment has already been stopped' do
let!(:environment) { create(:environment, :stopped, project: project) }
@ -77,7 +90,7 @@ RSpec.describe Environments::StopService do
context 'when environment is associated with removed branch' do
it 'stops environment' do
expect_environment_stopped_on('feature')
expect_environment_stopping_on('feature')
end
end
@ -195,8 +208,7 @@ RSpec.describe Environments::StopService do
it 'stops the active environment' do
subject
expect(pipeline.environments_in_self_and_descendants.first).to be_stopped
expect(pipeline.environments_in_self_and_descendants.first).to be_stopping
end
context 'when pipeline is a branch pipeline for merge request' do
@ -268,6 +280,11 @@ RSpec.describe Environments::StopService do
.to change { Environment.last.state }.from('available').to('stopped')
end
def expect_environment_stopping_on(branch)
expect { service.execute_for_branch(branch) }
.to change { Environment.last.state }.from('available').to('stopping')
end
def expect_environment_not_stopped_on(branch)
expect { service.execute_for_branch(branch) }
.not_to change { Environment.last.state }

View File

@ -8,7 +8,7 @@ RSpec.describe BuildSuccessWorker do
context 'when build exists' do
context 'when the build will stop an environment' do
let!(:build) { create(:ci_build, :stop_review_app, environment: environment.name, project: environment.project) }
let!(:build) { create(:ci_build, :stop_review_app, environment: environment.name, project: environment.project, status: :success) }
let(:environment) { create(:environment, state: :available) }
it 'stops the environment' do
@ -18,6 +18,33 @@ RSpec.describe BuildSuccessWorker do
expect(environment.reload).to be_stopped
end
context 'when the build fails' do
before do
build.update!(status: :failed)
environment.update!(state: :available)
end
it 'does not stop the environment' do
expect(environment).to be_available
stub_feature_flags(env_stopped_on_stop_success: true)
subject
expect(environment.reload).not_to be_stopped
end
it 'does stop the environment when feature flag is disabled' do
expect(environment).to be_available
stub_feature_flags(env_stopped_on_stop_success: false)
subject
expect(environment.reload).to be_stopped
end
end
end
end

View File

@ -23,7 +23,7 @@ RSpec.describe Environments::AutoStopWorker do
it 'stops the environment' do
expect { subject }
.to change { Environment.find_by_name('review/feature').state }
.from('available').to('stopped')
.from('available').to('stopping')
end
it 'executes the stop action' do

View File

@ -410,7 +410,6 @@ RSpec.describe 'Every Sidekiq worker' do
'RepositoryCleanupWorker' => 3,
'RepositoryForkWorker' => 5,
'RepositoryImportWorker' => false,
'RepositoryRemoveRemoteWorker' => 3,
'RepositoryUpdateMirrorWorker' => false,
'RepositoryPushAuditEventWorker' => 3,
'RepositoryUpdateRemoteMirrorWorker' => 3,

View File

@ -1,48 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe RepositoryRemoveRemoteWorker do
include ExclusiveLeaseHelpers
include GitHelpers
describe '#perform' do
let!(:project) { create(:project, :repository) }
let(:remote_name) { 'joe'}
let(:lease_key) { "remove_remote_#{project.id}_#{remote_name}" }
let(:lease_timeout) { RepositoryRemoveRemoteWorker::LEASE_TIMEOUT }
it 'returns nil when project does not exist' do
expect(subject.perform(-1, 'remote_name')).to be_nil
end
context 'when project exists' do
before do
allow(Project)
.to receive(:find_by)
.with(id: project.id)
.and_return(project)
end
it 'does nothing when cannot obtain lease' do
stub_exclusive_lease_taken(lease_key, timeout: lease_timeout)
expect(project.repository)
.not_to receive(:remove_remote)
expect(subject)
.not_to receive(:log_error)
subject.perform(project.id, remote_name)
end
it 'does nothing when obtain a lease' do
stub_exclusive_lease(lease_key, timeout: lease_timeout)
expect(project.repository)
.not_to receive(:remove_remote)
subject.perform(project.id, remote_name)
end
end
end
end