Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-01 15:10:18 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-01 15:10:18 +0300
commit3a5bee787984a139396c64372b6e14c4cb26efc1 (patch)
tree495ae8868be3aa62c7446bd81c398ee7e098cc64
parent58c42f2f454c5223062b08a47c5add4e52ad677f (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum2
-rw-r--r--Gemfile.lock6
-rw-r--r--app/assets/javascripts/integrations/constants.js2
-rw-r--r--app/assets/javascripts/integrations/edit/components/trigger_fields.vue4
-rw-r--r--app/views/projects/_merge_request_merge_checks_settings.html.haml1
-rw-r--r--config/feature_flags/development/integration_slack_app_notifications.yml2
-rw-r--r--config/initializers/database_query_analyzers.rb19
-rw-r--r--config/open_api.yml4
-rw-r--r--doc/api/environments.md4
-rw-r--r--doc/ci/jobs/job_control.md27
-rw-r--r--doc/ci/yaml/index.md8
-rw-r--r--lib/api/api.rb4
-rw-r--r--lib/api/entities/environment.rb4
-rw-r--r--lib/api/entities/environment_basic.rb7
-rw-r--r--lib/api/entities/feature_flag/user_list.rb14
-rw-r--r--lib/api/environments.rb100
-rw-r--r--lib/api/feature_flags_user_lists.rb31
-rw-r--r--lib/gitlab/database/query_analyzer.rb6
-rw-r--r--lib/gitlab/database/query_analyzers/base.rb4
-rw-r--r--lib/gitlab/database/query_analyzers/query_recorder.rb45
-rw-r--r--locale/gitlab.pot9
-rw-r--r--spec/frontend/integrations/edit/components/trigger_fields_spec.js45
-rw-r--r--spec/lib/gitlab/database/query_analyzer_spec.rb8
-rw-r--r--spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb38
-rw-r--r--spec/support/database/query_recorder.rb9
26 files changed, 327 insertions, 78 deletions
diff --git a/Gemfile b/Gemfile
index 68bb8c7d171..82e5bababc3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -246,7 +246,7 @@ gem 're2', '~> 1.6.0'
gem 'version_sorter', '~> 2.2.4'
# Export Ruby Regex to Javascript
-gem 'js_regex', '~> 3.7'
+gem 'js_regex', '~> 3.8'
# User agent parsing
gem 'device_detector'
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 8103a29a20d..5a7956df3d9 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -286,7 +286,7 @@
{"name":"jaro_winkler","version":"1.5.4","platform":"ruby","checksum":"50c3e83c5a9e8769c1cf5b73c8b51bb6eebbf8852a0ee53bf6ad6e4dc63414f9"},
{"name":"jira-ruby","version":"2.1.4","platform":"ruby","checksum":"4267c095cac8323b9eef3ba866eb28bb1388b7623a5abb60c1e7caf12d4adb9e"},
{"name":"jmespath","version":"1.6.1","platform":"ruby","checksum":"40ca83f4141bdd1e503db5485de68b84237183d84cf7a159fbeebcc6005adbd6"},
-{"name":"js_regex","version":"3.7.0","platform":"ruby","checksum":"b13fac68c4416d1a5f21c3bab8a71b4530f424b7c4ff9f46d8e62b895dc05975"},
+{"name":"js_regex","version":"3.8.0","platform":"ruby","checksum":"7934bcdd5a0e6d5af4a520288fd4684a02a472ae55831d9178ccaf82356344b5"},
{"name":"json","version":"2.5.1","platform":"java","checksum":"be284a0c4a9d0373e81b0d5dfe71ed5b18d0479f05970e60a77be89a2978ce6c"},
{"name":"json","version":"2.5.1","platform":"ruby","checksum":"918d8c41dacb7cfdbe0c7bbd6014a5372f0cf1c454ca150e9f4010fe80cc3153"},
{"name":"json-jwt","version":"1.15.3","platform":"ruby","checksum":"66db4f14e538a774c15502a5b5b26b1f3e7585481bbb96df490aa74b5c2d6110"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 30063886ff8..31ec54a5347 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -758,9 +758,9 @@ GEM
multipart-post
oauth (~> 0.5, >= 0.5.0)
jmespath (1.6.1)
- js_regex (3.7.0)
+ js_regex (3.8.0)
character_set (~> 1.4)
- regexp_parser (~> 2.1)
+ regexp_parser (~> 2.5)
regexp_property_values (~> 1.0)
json (2.5.1)
json-jwt (1.15.3)
@@ -1673,7 +1673,7 @@ DEPENDENCIES
ipaddress (~> 0.8.3)
ipynbdiff!
jira-ruby (~> 2.1.4)
- js_regex (~> 3.7)
+ js_regex (~> 3.8)
json (~> 2.5.1)
json_schemer (~> 0.2.18)
jwt (~> 2.1.0)
diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js
index 2806b785816..392dd63b089 100644
--- a/app/assets/javascripts/integrations/constants.js
+++ b/app/assets/javascripts/integrations/constants.js
@@ -85,10 +85,12 @@ export const billingPlanNames = {
};
const INTEGRATION_TYPE_SLACK = 'slack';
+const INTEGRATION_TYPE_SLACK_APPLICATION = 'gitlab_slack_application';
const INTEGRATION_TYPE_MATTERMOST = 'mattermost';
export const placeholderForType = {
[INTEGRATION_TYPE_SLACK]: __('#general, #development'),
+ [INTEGRATION_TYPE_SLACK_APPLICATION]: __('#general, #development'),
[INTEGRATION_TYPE_MATTERMOST]: __('my-channel'),
};
diff --git a/app/assets/javascripts/integrations/edit/components/trigger_fields.vue b/app/assets/javascripts/integrations/edit/components/trigger_fields.vue
index 67647cadf19..3820a87e5ad 100644
--- a/app/assets/javascripts/integrations/edit/components/trigger_fields.vue
+++ b/app/assets/javascripts/integrations/edit/components/trigger_fields.vue
@@ -23,7 +23,7 @@ export default {
},
computed: {
...mapGetters(['isInheriting']),
- placeholder() {
+ defaultPlaceholder() {
return placeholderForType[this.type];
},
},
@@ -55,7 +55,7 @@ export default {
v-if="event.field"
v-model="event.field.value"
:name="fieldName(event.field.name)"
- :placeholder="placeholder"
+ :placeholder="event.field.placeholder || defaultPlaceholder"
:readonly="isInheriting"
/>
</gl-form-group>
diff --git a/app/views/projects/_merge_request_merge_checks_settings.html.haml b/app/views/projects/_merge_request_merge_checks_settings.html.haml
index 3345b3043b8..8c12399fdbb 100644
--- a/app/views/projects/_merge_request_merge_checks_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_checks_settings.html.haml
@@ -12,6 +12,7 @@
s_('ProjectSettings|Skipped pipelines are considered successful'),
help_text: s_('ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline.'),
checkbox_options: { class: 'gl-pl-6' }
+ = render_if_exists 'projects/merge_request_merge_checks_status_checks', form: form, project: @project
= form.gitlab_ui_checkbox_component :only_allow_merge_if_all_discussions_are_resolved,
s_('ProjectSettings|All threads must be resolved'),
checkbox_options: { data: { qa_selector: 'allow_merge_if_all_discussions_are_resolved_checkbox' } }
diff --git a/config/feature_flags/development/integration_slack_app_notifications.yml b/config/feature_flags/development/integration_slack_app_notifications.yml
index d233194c6d4..4b9903b25c9 100644
--- a/config/feature_flags/development/integration_slack_app_notifications.yml
+++ b/config/feature_flags/development/integration_slack_app_notifications.yml
@@ -1,7 +1,7 @@
---
name: integration_slack_app_notifications
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98663
-rollout_issue_url:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381012
milestone: '15.5'
type: development
group: group::integrations
diff --git a/config/initializers/database_query_analyzers.rb b/config/initializers/database_query_analyzers.rb
index 2e73fbb79a2..fcfc75341df 100644
--- a/config/initializers/database_query_analyzers.rb
+++ b/config/initializers/database_query_analyzers.rb
@@ -1,15 +1,18 @@
# frozen_string_literal: true
# Currently we register validator only for `dev` or `test` environment
-Gitlab::Database::QueryAnalyzer.instance.hook!
-Gitlab::Database::QueryAnalyzer.instance.all_analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics)
-Gitlab::Database::QueryAnalyzer.instance.all_analyzers.append(
- ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification
-)
+Gitlab::Database::QueryAnalyzer.instance.tap do |query_analyzer|
+ query_analyzer.hook!
-if Gitlab.dev_or_test_env?
- query_analyzer = ::Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection
- Gitlab::Database::QueryAnalyzer.instance.all_analyzers.append(query_analyzer)
+ query_analyzer.all_analyzers.tap do |analyzers|
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics)
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification)
+
+ if Gitlab.dev_or_test_env?
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection)
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::QueryRecorder)
+ end
+ end
end
Gitlab::Application.configure do |config|
diff --git a/config/open_api.yml b/config/open_api.yml
index cd0b64ba1fd..f45691ea9f5 100644
--- a/config/open_api.yml
+++ b/config/open_api.yml
@@ -26,6 +26,10 @@ metadata:
description: Operations related to deploy tokens
- name: deployments
description: Operations related to deployments
+ - name: environments
+ description: Operations related to environments
+ - name: feature_flags_user_lists
+ description: Operations related to accessing GitLab feature flag user lists
- name: features
description: Operations related to managing Flipper-based feature flags
- name: freeze_periods
diff --git a/doc/api/environments.md b/doc/api/environments.md
index 0f969ea4fd3..89b4bb6a1de 100644
--- a/doc/api/environments.md
+++ b/doc/api/environments.md
@@ -20,7 +20,7 @@ GET /projects/:id/environments
| `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. |
+| `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"
@@ -279,7 +279,7 @@ Example response:
}
```
-## Edit an existing environment
+## Update an existing environment
Updates an existing environment's name and/or `external_url`.
diff --git a/doc/ci/jobs/job_control.md b/doc/ci/jobs/job_control.md
index fc3b106aa18..d26c698af89 100644
--- a/doc/ci/jobs/job_control.md
+++ b/doc/ci/jobs/job_control.md
@@ -107,6 +107,33 @@ job:
- make build
```
+#### Skip job if the branch is empty
+
+Use [`rules:changes:compare_to`](../yaml/index.md#ruleschangescompare_to) to avoid
+running a job when the branch is empty, which saves CI/CD resources. Compare the
+branch to the default branch, and if the branch:
+
+- Doesn't have changed files, the job doesn't run.
+- Has changed files, the job runs.
+
+For example, in a project with `main` as the default branch:
+
+```yaml
+job:
+ script:
+ - echo "This job only runs for branches that are not empty"
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ changes:
+ compare_to: refs/heads/main
+ paths:
+ - '*'
+```
+
+The rule for this job compares all files and paths (`*`) in the current branch against
+the default branch `main`. The rule matches and the job runs only when there are
+changes to the files in the branch.
+
### Complex rules
You can use all `rules` keywords, like `if`, `changes`, and `exists`, in the same
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 47ad2655710..a32ba9751c4 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -1155,7 +1155,7 @@ that use the same cache key use the same cache, including in different pipelines
If not set, the default key is `default`. All jobs with the `cache` keyword but
no `cache:key` share the `default` cache.
-Must be used with `cache: path`, or nothing is cached.
+Must be used with `cache: paths`, or nothing is cached.
**Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default).
@@ -1325,7 +1325,7 @@ rspec:
Use `cache:when` to define when to save the cache, based on the status of the job.
-Must be used with `cache: path`, or nothing is cached.
+Must be used with `cache: paths`, or nothing is cached.
**Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default).
@@ -1365,7 +1365,7 @@ Use the `pull` policy when you have many jobs executing in parallel that use the
This policy speeds up job execution and reduces load on the cache server. You can
use a job with the `push` policy to build the cache.
-Must be used with `cache: path`, or nothing is cached.
+Must be used with `cache: paths`, or nothing is cached.
**Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default).
@@ -1773,7 +1773,7 @@ deploy:
**Additional details**:
- Enviroments created from this job definition are assigned a [tier](../environments/index.md#deployment-tier-of-environments) based on this value.
-- Existing environments don't have their tier updated if this value is added later. Existing enviroments must have their tier updated via the [Environments API](../../api/environments.md#edit-an-existing-environment).
+- Existing environments don't have their tier updated if this value is added later. Existing enviroments must have their tier updated via the [Environments API](../../api/environments.md#update-an-existing-environment).
**Related topics**:
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 38c20e80d14..35d96efec5c 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -176,6 +176,8 @@ module API
mount ::API::DeployKeys
mount ::API::DeployTokens
mount ::API::Deployments
+ mount ::API::Environments
+ mount ::API::FeatureFlagsUserLists
mount ::API::Features
mount ::API::FreezePeriods
mount ::API::Metadata
@@ -225,13 +227,11 @@ module API
mount ::API::DebianProjectPackages
mount ::API::DependencyProxy
mount ::API::Discussions
- mount ::API::Environments
mount ::API::ErrorTracking::ClientKeys
mount ::API::ErrorTracking::Collector
mount ::API::ErrorTracking::ProjectSettings
mount ::API::Events
mount ::API::FeatureFlags
- mount ::API::FeatureFlagsUserLists
mount ::API::Files
mount ::API::GenericPackages
mount ::API::Geo
diff --git a/lib/api/entities/environment.rb b/lib/api/entities/environment.rb
index 3b6ed94c3f1..dc9911d5acb 100644
--- a/lib/api/entities/environment.rb
+++ b/lib/api/entities/environment.rb
@@ -5,10 +5,10 @@ module API
class Environment < Entities::EnvironmentBasic
include RequestAwareEntity
- expose :tier
+ expose :tier, documentation: { type: 'string', example: 'development' }
expose :project, using: Entities::BasicProjectDetails
expose :last_deployment, using: Entities::Deployment, if: { last_deployment: true }
- expose :state
+ expose :state, documentation: { type: 'string', example: 'available' }
end
end
end
diff --git a/lib/api/entities/environment_basic.rb b/lib/api/entities/environment_basic.rb
index d9894eac147..1b4a9371820 100644
--- a/lib/api/entities/environment_basic.rb
+++ b/lib/api/entities/environment_basic.rb
@@ -3,7 +3,12 @@
module API
module Entities
class EnvironmentBasic < Grape::Entity
- expose :id, :name, :slug, :external_url, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'deploy' }
+ expose :slug, documentation: { type: 'string', example: 'deploy' }
+ expose :external_url, documentation: { type: 'string', example: 'https://deploy.gitlab.example.com' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-05-25T18:55:13.252Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-05-25T18:55:13.252Z' }
end
end
end
diff --git a/lib/api/entities/feature_flag/user_list.rb b/lib/api/entities/feature_flag/user_list.rb
index bc8b12ea22e..efb3261658a 100644
--- a/lib/api/entities/feature_flag/user_list.rb
+++ b/lib/api/entities/feature_flag/user_list.rb
@@ -6,13 +6,13 @@ module API
class UserList < Grape::Entity
include RequestAwareEntity
- expose :id
- expose :iid
- expose :project_id
- expose :created_at
- expose :updated_at
- expose :name
- expose :user_xids
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :iid, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 2 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
+ expose :name, documentation: { type: 'string', example: 'user_list' }
+ expose :user_xids, documentation: { type: 'string', example: 'user1,user2' }
expose :path do |list|
project_feature_flags_user_list_path(list.project, list)
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index 42d5e6a73b3..33f27f4dace 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -11,18 +11,27 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all environments of the project' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'List environments' do
+ detail 'Get all environments for a given project. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ is_array true
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
use :pagination
- optional :name, type: String, desc: 'Returns the environment with this name'
- optional :search, type: String, desc: 'Returns list of environments matching the search criteria'
- optional :states, type: String, values: Environment.valid_states.map(&:to_s), desc: 'List all environments that match a specific state'
+ optional :name, type: String, desc: 'Return the environment with this name. Mutually exclusive with search'
+ optional :search, type: String, desc: 'Return list of environments matching the search criteria. Mutually exclusive with name'
+ optional :states,
+ type: String,
+ values: Environment.valid_states.map(&:to_s),
+ desc: 'List all environments that match a specific state. Accepted values: `available`, `stopping`, or `stopped`. If no state value given, returns all environments'
mutually_exclusive :name, :search, message: 'cannot be used together'
end
get ':id/environments' do
@@ -33,15 +42,21 @@ module API
present paginate(environments), with: Entities::Environment, current_user: current_user
end
- desc 'Creates a new environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Create a new environment' do
+ detail 'Creates a new environment with the given name and `external_url`. It returns `201` if the environment was successfully created, `400` for wrong parameters. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[environments]
end
params do
- requires :name, type: String, desc: 'The name of the environment to be created'
- optional :external_url, type: String, desc: 'URL on which this deployment is viewable'
+ requires :name, type: String, desc: 'The name of the environment'
+ optional :external_url, type: String, desc: 'Place to link to for this environment'
optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true }
- optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the environment to be created'
+ optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`'
end
post ':id/environments' do
authorize! :create_environment, user_project
@@ -55,17 +70,23 @@ module API
end
end
- desc 'Updates an existing environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Update an existing environment' do
+ detail 'Updates an existing environment name and/or `external_url`. It returns `200` if the environment was successfully updated. In case of an error, a status code `400` is returned. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
# TODO: disallow renaming via the API https://gitlab.com/gitlab-org/gitlab/-/issues/338897
optional :name, type: String, desc: 'DEPRECATED: Renaming environment can lead to errors, this will be removed in 15.0'
optional :external_url, type: String, desc: 'The new URL on which this deployment is viewable'
optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true }
- optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the environment to be created'
+ optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`'
end
put ':id/environments/:environment_id' do
authorize! :update_environment, user_project
@@ -80,14 +101,21 @@ module API
end
end
- desc "Delete multiple stopped review apps" do
- detail "Remove multiple stopped review environments older than a specific age"
+ desc 'Delete multiple stopped review apps' do
+ detail 'It schedules for deletion multiple environments that have already been stopped and are in the review app folder. The actual deletion is performed after 1 week from the time of execution. By default, it only deletes environments 30 days or older. You can change this default using the `before` parameter.'
success Entities::EnvironmentBasic
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' }
+ ]
+ tags %w[environments]
end
params do
- optional :before, type: Time, desc: "The timestamp before which environments can be deleted. Defaults to 30 days ago.", default: -> { 30.days.ago }
- optional :limit, type: Integer, desc: "Maximum number of environments to delete. Defaults to 100.", default: 100, values: 1..1000
- optional :dry_run, type: Boolean, desc: "If set, perform a dry run where no actual deletions will be performed. Defaults to true.", default: true
+ optional :before, type: Time, desc: "The date before which environments can be deleted. Defaults to 30 days ago. Expected in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`)", default: -> { 30.days.ago }
+ optional :limit, type: Integer, desc: "Maximum number of environments to delete. Defaults to 100", default: 100, values: 1..1000
+ optional :dry_run, type: Boolean, desc: "Defaults to true for safety reasons. It performs a dry run where no actual deletion will be performed. Set to false to actually delete the environment", default: true
end
delete ":id/environments/review_apps" do
authorize! :read_environment, user_project
@@ -107,12 +135,17 @@ module API
end
end
- desc 'Deletes an existing environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Delete an environment' do
+ detail 'It returns 204 if the environment was successfully deleted, and 404 if the environment does not exist. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
delete ':id/environments/:environment_id' do
authorize! :read_environment, user_project
@@ -123,12 +156,18 @@ module API
destroy_conditionally!(environment)
end
- desc 'Stops an existing environment' do
+ desc 'Stop an environment' do
+ detail 'It returns 200 if the environment was successfully stopped, and 404 if the environment does not exist.'
success Entities::Environment
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
- optional :force, type: Boolean, default: false
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
+ optional :force, type: Boolean, default: false, desc: 'Force environment to stop without executing `on_stop` actions'
end
post ':id/environments/:environment_id/stop' do
authorize! :read_environment, user_project
@@ -141,11 +180,16 @@ module API
present environment, with: Entities::Environment, current_user: current_user
end
- desc 'Get a single environment' do
+ desc 'Get a specific environment' do
success Entities::Environment
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
get ':id/environments/:environment_id' do
authorize! :read_environment, user_project
diff --git a/lib/api/feature_flags_user_lists.rb b/lib/api/feature_flags_user_lists.rb
index f4771c07260..c5060eae763 100644
--- a/lib/api/feature_flags_user_lists.rb
+++ b/lib/api/feature_flags_user_lists.rb
@@ -16,16 +16,19 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags_user_lists do
- desc 'Get all feature flags user lists of a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'List all feature flag user lists for a project' do
+ detail 'Gets all feature flag user lists for the requested project. ' \
+ 'This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ is_array true
+ tags %w[feature_flags_user_lists]
end
params do
- optional :search, type: String, desc: 'Returns the list of user lists matching the search critiera'
+ optional :search, type: String, desc: 'Return user lists matching the search criteria'
use :pagination
end
@@ -35,9 +38,10 @@ module API
with: ::API::Entities::FeatureFlag::UserList
end
- desc 'Create a feature flags user list for a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Create a feature flag user list' do
+ detail 'Creates a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ tags %w[feature_flags_user_lists]
end
params do
requires :name, type: String, desc: 'The name of the list'
@@ -59,12 +63,13 @@ module API
end
params do
- requires :iid, type: String, desc: 'The internal ID of the user list'
+ requires :iid, types: [String, Integer], desc: "The internal ID of the project's feature flag user list"
end
resource 'feature_flags_user_lists/:iid' do
- desc 'Get a single feature flag user list belonging to a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Get a feature flag user list' do
+ detail 'Gets a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ tags %w[feature_flags_user_lists]
end
get do
present user_project.operations_feature_flags_user_lists.find_by_iid!(params[:iid]),
@@ -72,8 +77,9 @@ module API
end
desc 'Update a feature flag user list' do
- detail 'This feature was introduced in GitLab 12.10'
+ detail 'Updates a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ tags %w[feature_flags_user_lists]
end
params do
optional :name, type: String, desc: 'The name of the list'
@@ -93,8 +99,9 @@ module API
end
end
- desc 'Delete a feature flag user list' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Delete feature flag user list' do
+ detail 'Deletes a feature flag user list. This feature was introduced in GitLab 12.10.'
+ tags %w[feature_flags_user_lists]
end
delete do
# TODO: Move the business logic to a service class in app/services/feature_flags.
diff --git a/lib/gitlab/database/query_analyzer.rb b/lib/gitlab/database/query_analyzer.rb
index 6f64d04270f..1280789b30c 100644
--- a/lib/gitlab/database/query_analyzer.rb
+++ b/lib/gitlab/database/query_analyzer.rb
@@ -86,7 +86,11 @@ module Gitlab
analyzers.each do |analyzer|
next if analyzer.suppressed? && !analyzer.requires_tracking?(parsed)
- analyzer.analyze(parsed)
+ if analyzer.raw?
+ analyzer.analyze(sql)
+ else
+ analyzer.analyze(parsed)
+ end
rescue StandardError, ::Gitlab::Database::QueryAnalyzers::Base::QueryAnalyzerError => e
# We catch all standard errors to prevent validation errors to introduce fatal errors in production
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
diff --git a/lib/gitlab/database/query_analyzers/base.rb b/lib/gitlab/database/query_analyzers/base.rb
index 9a52a4f6e23..9c2c228f869 100644
--- a/lib/gitlab/database/query_analyzers/base.rb
+++ b/lib/gitlab/database/query_analyzers/base.rb
@@ -53,6 +53,10 @@ module Gitlab
Thread.current[self.context_key]
end
+ def self.raw?
+ false
+ end
+
def self.enabled?
raise NotImplementedError
end
diff --git a/lib/gitlab/database/query_analyzers/query_recorder.rb b/lib/gitlab/database/query_analyzers/query_recorder.rb
new file mode 100644
index 00000000000..88fe829c3d2
--- /dev/null
+++ b/lib/gitlab/database/query_analyzers/query_recorder.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module QueryAnalyzers
+ class QueryRecorder < Base
+ LOG_FILE = 'rspec/query_recorder.ndjson'
+
+ class << self
+ def raw?
+ true
+ end
+
+ def enabled?
+ # Only enable QueryRecorder in CI
+ ENV['CI'].present?
+ end
+
+ def analyze(sql)
+ payload = {
+ sql: sql
+ }
+
+ log_query(payload)
+ end
+
+ private
+
+ def log_query(payload)
+ log_path = Rails.root.join(LOG_FILE)
+ log_dir = File.dirname(log_path)
+
+ # Create log directory if it does not exist since it is only created
+ # ahead of time by certain CI jobs
+ FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
+
+ log_line = "#{Gitlab::Json.dump(payload)}\n"
+
+ File.write(log_path, log_line, mode: 'a')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e86ce08a1ce..4d73fcd48fa 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4548,9 +4548,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -25468,6 +25465,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -32060,6 +32060,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
diff --git a/spec/frontend/integrations/edit/components/trigger_fields_spec.js b/spec/frontend/integrations/edit/components/trigger_fields_spec.js
index c329ca8522f..082eeea30f1 100644
--- a/spec/frontend/integrations/edit/components/trigger_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/trigger_fields_spec.js
@@ -1,5 +1,6 @@
import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { placeholderForType } from 'jh_else_ce/integrations/constants';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
@@ -28,6 +29,50 @@ describe('TriggerFields', () => {
const findAllGlFormCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
const findAllGlFormInputs = () => wrapper.findAllComponents(GlFormInput);
+ describe('placeholder text on the event fields and default values', () => {
+ const dummyFieldPlaceholder = '#foo';
+ const integrationTypes = {
+ INTEGRATION_TYPE_SLACK: 'slack',
+ INTEGRATION_TYPE_SLACK_APPLICATION: 'gitlab_slack_application',
+ INTEGRATION_TYPE_MATTERMOST: 'mattermost',
+ INTEGRATION_TYPE_NON_EXISTING: 'non_existing',
+ };
+ it.each`
+ integrationType | fieldPlaceholder | expectedPlaceholder
+ ${integrationTypes.INTEGRATION_TYPE_SLACK} | ${undefined} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK} | ${''} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION} | ${undefined} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION} | ${''} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ ${integrationTypes.INTEGRATION_TYPE_MATTERMOST} | ${undefined} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_MATTERMOST]}
+ ${integrationTypes.INTEGRATION_TYPE_MATTERMOST} | ${''} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_MATTERMOST]}
+ ${integrationTypes.INTEGRATION_TYPE_MATTERMOST} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ ${integrationTypes.INTEGRATION_TYPE_NON_EXISTING} | ${undefined} | ${undefined}
+ ${integrationTypes.INTEGRATION_TYPE_NON_EXISTING} | ${''} | ${undefined}
+ ${integrationTypes.INTEGRATION_TYPE_NON_EXISTING} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ `(
+ 'passed down correct placeholder for "$integrationType" type and "$fieldPlaceholder" placeholder on the field',
+ ({ integrationType, fieldPlaceholder, expectedPlaceholder }) => {
+ createComponent({
+ type: integrationType,
+ events: [
+ {
+ field: {
+ name: 'foo',
+ value: '',
+ placeholder: fieldPlaceholder,
+ },
+ },
+ ],
+ });
+ const field = wrapper.findComponent(GlFormInput);
+
+ expect(field.attributes('placeholder')).toBe(expectedPlaceholder);
+ },
+ );
+ });
+
describe.each([true, false])('template, isInheriting = `%p`', (isInheriting) => {
it('renders a label with text "Trigger"', () => {
createComponent();
diff --git a/spec/lib/gitlab/database/query_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzer_spec.rb
index 0b849063562..6dc9ffc4aba 100644
--- a/spec/lib/gitlab/database/query_analyzer_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzer_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzer, query_analyzers: false do
before do
allow(described_class.instance).to receive(:all_analyzers).and_return([analyzer, disabled_analyzer])
allow(analyzer).to receive(:enabled?).and_return(true)
+ allow(analyzer).to receive(:raw?).and_return(false)
allow(analyzer).to receive(:suppressed?).and_return(false)
allow(analyzer).to receive(:begin!)
allow(analyzer).to receive(:end!)
@@ -181,6 +182,13 @@ RSpec.describe Gitlab::Database::QueryAnalyzer, query_analyzers: false do
expect { process_sql("SELECT 1 FROM projects") }.not_to raise_error
end
+ it 'does call analyze with raw sql when raw? is true' do
+ expect(analyzer).to receive(:raw?).and_return(true)
+ expect(analyzer).to receive(:analyze).with('SELECT 1 FROM projects')
+
+ expect { process_sql("SELECT 1 FROM projects") }.not_to raise_error
+ end
+
def process_sql(sql)
described_class.instance.within do
ApplicationRecord.load_balancer.read_write do |connection|
diff --git a/spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb b/spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb
new file mode 100644
index 00000000000..ec01ae623ae
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::QueryRecorder, query_analyzers: false do
+ # We keep only the QueryRecorder analyzer running
+ around do |example|
+ described_class.with_suppressed(false) do
+ example.run
+ end
+ end
+
+ context 'when analyzer is enabled for tests' do
+ let(:query) { 'SELECT 1 FROM projects' }
+ let(:log_path) { Rails.root.join(described_class::LOG_FILE) }
+
+ before do
+ stub_env('CI', 'true')
+
+ # This is needed to be able to stub_env the CI variable
+ ::Gitlab::Database::QueryAnalyzer.instance.begin!([described_class])
+ end
+
+ after do
+ ::Gitlab::Database::QueryAnalyzer.instance.end!([described_class])
+ end
+
+ it 'logs queries to a file' do
+ allow(FileUtils).to receive(:mkdir_p)
+ .with(File.dirname(log_path))
+ expect(File).to receive(:write)
+ .with(log_path, /^{"sql":"#{query}/, mode: 'a')
+ expect(described_class).to receive(:analyze).with(/^#{query}/).and_call_original
+
+ expect { ApplicationRecord.connection.execute(query) }.not_to raise_error
+ end
+ end
+end
diff --git a/spec/support/database/query_recorder.rb b/spec/support/database/query_recorder.rb
new file mode 100644
index 00000000000..1050120e528
--- /dev/null
+++ b/spec/support/database/query_recorder.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+RSpec.configure do |config|
+ # Truncate the query_recorder log file before starting the suite
+ config.before(:suite) do
+ log_path = Rails.root.join(Gitlab::Database::QueryAnalyzers::QueryRecorder::LOG_FILE)
+ File.write(log_path, '') if File.exist?(log_path)
+ end
+end