Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9877050db1
commit
516b939c44
|
|
@ -10,7 +10,10 @@ Please link to the respective test case in the testcases project
|
|||
- [ ] Note if the test is intended to run in specific scenarios. If a scenario is new, add a link to the MR that adds the new scenario.
|
||||
- [ ] Follow the end-to-end tests [style guide](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/style_guide.html) and [best practices](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/best_practices.html).
|
||||
- [ ] Use the appropriate [RSpec metadata tag(s)](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/rspec_metadata_tests.html#rspec-metadata-for-end-to-end-tests).
|
||||
- [ ] Ensure that a created resource is removed after test execution. A `Group` resource can be shared between multiple tests. Do not remove it unless it has a unique path. Note that we have a cleanup job that periodically removes groups under `gitlab-qa-sandbox-group`.
|
||||
- Most resources will be cleaned up via the general [cleanup task](https://gitlab.com/gitlab-org/gitlab/-/blob/44345381e89d6bbd440f7b4c680d03e8b75b86de/qa/qa/tools/test_resources_handler.rb#L44). Check that is successful, or ensure resources are cleaned up in the test:
|
||||
- [ ] New resources have `api_get_path` and `api_delete_path` implemented if possible.
|
||||
- [ ] If any resource cannot be deleted in the general delete task, make sure it is [ignored](https://gitlab.com/gitlab-org/gitlab/-/blob/44345381e89d6bbd440f7b4c680d03e8b75b86de/qa/qa/tools/test_resources_handler.rb#L29).
|
||||
- [ ] If any resource cannot be deleted in the general delete task, remove it in the test (e.g., in an `after` block).
|
||||
- [ ] Ensure that no [transient bugs](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#transient-bugs) are hidden accidentally due to the usage of `waits` and `reloads`.
|
||||
- [ ] Verify the tags to ensure it runs on the desired test environments.
|
||||
- [ ] If this MR has a dependency on another MR, such as a GitLab QA MR, specify the order in which the MRs should be merged.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
c54d613d0eb9c573d79f5da0975655f11f007932
|
||||
0c72a4ba3de2125098d72fce52b99df3d4ad5475
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
track_redis_hll_event :charts, name: 'p_analytics_ci_cd_pipelines', if: -> { should_track_ci_cd_pipelines? }
|
||||
track_redis_hll_event :charts, name: 'p_analytics_ci_cd_deployment_frequency', if: -> { should_track_ci_cd_deployment_frequency? }
|
||||
track_redis_hll_event :charts, name: 'p_analytics_ci_cd_lead_time', if: -> { should_track_ci_cd_lead_time? }
|
||||
track_redis_hll_event :charts, name: 'p_analytics_ci_cd_time_to_restore_service', if: -> { should_track_ci_cd_time_to_restore_service? }
|
||||
|
||||
wrap_parameters Ci::Pipeline
|
||||
|
||||
|
|
@ -361,6 +362,10 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
def should_track_ci_cd_lead_time?
|
||||
params[:chart] == 'lead-time'
|
||||
end
|
||||
|
||||
def should_track_ci_cd_time_to_restore_service?
|
||||
params[:chart] == 'time-to-restore-service'
|
||||
end
|
||||
end
|
||||
|
||||
Projects::PipelinesController.prepend_mod_with('Projects::PipelinesController')
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ module Types
|
|||
class RunnerUpgradeStatusTypeEnum < BaseEnum
|
||||
graphql_name 'CiRunnerUpgradeStatusType'
|
||||
|
||||
value 'UNKNOWN', description: 'Upgrade status is unknown.', value: :unknown
|
||||
::Ci::RunnerVersion::STATUS_DESCRIPTIONS.each do |status, description|
|
||||
status = :invalid if status == :invalid_version
|
||||
|
||||
Gitlab::Ci::RunnerUpgradeCheck::STATUSES.each do |status, description|
|
||||
value status.to_s.upcase, description: description, value: status
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class RunnerVersion < Ci::ApplicationRecord
|
||||
include EnumWithNil
|
||||
|
||||
enum_with_nil status: {
|
||||
not_processed: nil,
|
||||
invalid_version: -1,
|
||||
unknown: 0,
|
||||
not_available: 1,
|
||||
available: 2,
|
||||
recommended: 3
|
||||
}
|
||||
|
||||
STATUS_DESCRIPTIONS = {
|
||||
invalid_version: 'Runner version is not valid.',
|
||||
unknown: 'Upgrade status is unknown.',
|
||||
not_available: 'Upgrade is not available for the runner.',
|
||||
available: 'Upgrade is available for the runner.',
|
||||
recommended: 'Upgrade is available and recommended for the runner.'
|
||||
}.freeze
|
||||
|
||||
# Override auto generated negative scope (from available) so the scope has expected behavior
|
||||
scope :not_available, -> { where(status: :not_available) }
|
||||
|
||||
validates :version, length: { maximum: 2048 }
|
||||
end
|
||||
end
|
||||
|
|
@ -476,8 +476,8 @@ class User < ApplicationRecord
|
|||
end
|
||||
scope :order_recent_sign_in, -> { reorder(arel_table[:current_sign_in_at].desc.nulls_last) }
|
||||
scope :order_oldest_sign_in, -> { reorder(arel_table[:current_sign_in_at].asc.nulls_last) }
|
||||
scope :order_recent_last_activity, -> { reorder(arel_table[:last_activity_on].desc.nulls_last) }
|
||||
scope :order_oldest_last_activity, -> { reorder(arel_table[:last_activity_on].asc.nulls_first) }
|
||||
scope :order_recent_last_activity, -> { reorder(arel_table[:last_activity_on].desc.nulls_last, arel_table[:id].asc) }
|
||||
scope :order_oldest_last_activity, -> { reorder(arel_table[:last_activity_on].asc.nulls_first, arel_table[:id].desc) }
|
||||
scope :by_id_and_login, ->(id, login) { where(id: id).where('username = LOWER(:login) OR email = LOWER(:login)', login: login) }
|
||||
scope :dormant, -> { with_state(:active).human_or_service_user.where('last_activity_on <= ?', MINIMUM_INACTIVE_DAYS.day.ago.to_date) }
|
||||
scope :with_no_activity, -> { with_state(:active).human_or_service_user.where(last_activity_on: nil).where('created_at <= ?', MINIMUM_DAYS_CREATED.day.ago.to_date) }
|
||||
|
|
|
|||
|
|
@ -15,3 +15,36 @@ raise "Counter cache is not disabled" if
|
|||
model.connection_specification_name = Ci::ApplicationRecord.connection_specification_name
|
||||
model.singleton_class.delegate :connection, :sticking, to: '::Ci::ApplicationRecord'
|
||||
end
|
||||
|
||||
# Modified from https://github.com/mbleigh/acts-as-taggable-on/pull/1081
|
||||
# with insert_all, which is not supported in MySQL
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/338346#note_996969960
|
||||
module ActsAsTaggableOnTagPatch
|
||||
def find_or_create_all_with_like_by_name(*list)
|
||||
list = Array(list).flatten
|
||||
|
||||
return [] if list.empty?
|
||||
|
||||
existing_tags = named_any(list)
|
||||
|
||||
missing = list.reject do |tag_name|
|
||||
comparable_tag_name = comparable_name(tag_name)
|
||||
existing_tags.find { |tag| comparable_name(tag.name) == comparable_tag_name }
|
||||
end
|
||||
|
||||
if missing.empty?
|
||||
new_tags = []
|
||||
else
|
||||
attributes_to_add = missing.map do |tag_name|
|
||||
{ name: tag_name }
|
||||
end
|
||||
|
||||
insert_all(attributes_to_add, unique_by: :name)
|
||||
new_tags = named_any(missing)
|
||||
end
|
||||
|
||||
existing_tags + new_tags
|
||||
end
|
||||
end
|
||||
|
||||
::ActsAsTaggableOn::Tag.singleton_class.prepend(ActsAsTaggableOnTagPatch)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ options:
|
|||
- p_analytics_ci_cd_pipelines
|
||||
- p_analytics_ci_cd_deployment_frequency
|
||||
- p_analytics_ci_cd_lead_time
|
||||
- p_analytics_ci_cd_time_to_restore_service
|
||||
- g_analytics_ci_cd_release_statistics
|
||||
- g_analytics_ci_cd_deployment_frequency
|
||||
- g_analytics_ci_cd_lead_time
|
||||
- g_analytics_ci_cd_time_to_restore_service
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.analytics.p_analytics_ci_cd_time_to_restore_service_monthly
|
||||
name: p_analytics_ci_cd_time_to_restore_service_monthly
|
||||
description: Count of unique visits to the project level CI/CD Analytics Time to restore service tab
|
||||
product_section: dev
|
||||
product_stage: manage
|
||||
product_group: optimize
|
||||
product_category:
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.2"
|
||||
introduced_by_url:
|
||||
time_frame: 28d
|
||||
data_source: redis_hll
|
||||
data_category: operational
|
||||
instrumentation_class: RedisHLLMetric
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- p_analytics_ci_cd_time_to_restore_service
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.analytics.p_analytics_ci_cd_time_to_restore_service_weekly
|
||||
name: p_analytics_ci_cd_time_to_restore_service_weekly
|
||||
description: Count of unique visits to the project level CI/CD Analytics Time to restore service tab
|
||||
product_section: dev
|
||||
product_stage: manage
|
||||
product_group: optimize
|
||||
product_category:
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.2"
|
||||
introduced_by_url:
|
||||
time_frame: 7d
|
||||
data_source: redis_hll
|
||||
data_category: operational
|
||||
instrumentation_class: RedisHLLMetric
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- p_analytics_ci_cd_time_to_restore_service
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
table_name: ci_runner_versions
|
||||
classes:
|
||||
- Ci::RunnerVersion
|
||||
feature_categories:
|
||||
- runner_fleet
|
||||
description: Information about used Ci::Runner versions
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90982
|
||||
milestone: '15.2'
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddCiRunnerVersionsTable < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def up
|
||||
create_table :ci_runner_versions, id: false do |t|
|
||||
t.text :version, primary_key: true, index: true, null: false, limit: 2048
|
||||
t.integer :status, null: true, limit: 2, index: true
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :ci_runner_versions, if_exists: true
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexOnRunnerVersion < Gitlab::Database::Migration[2.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAME = 'index_ci_runners_on_version'
|
||||
|
||||
def up
|
||||
add_concurrent_index :ci_runners, :version, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :ci_runners, INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
3245905956e4781629bbf6398c9534cf35eab469e8a703f755ed26de90dee0e1
|
||||
|
|
@ -0,0 +1 @@
|
|||
cf3c6e8d720ce48272b8b9658d3c240e8fe3c9a26284a9e169f7bb6a40c862bc
|
||||
|
|
@ -13080,6 +13080,12 @@ CREATE SEQUENCE ci_runner_projects_id_seq
|
|||
|
||||
ALTER SEQUENCE ci_runner_projects_id_seq OWNED BY ci_runner_projects.id;
|
||||
|
||||
CREATE TABLE ci_runner_versions (
|
||||
version text NOT NULL,
|
||||
status smallint,
|
||||
CONSTRAINT check_b5a3714594 CHECK ((char_length(version) <= 2048))
|
||||
);
|
||||
|
||||
CREATE TABLE ci_runners (
|
||||
id integer NOT NULL,
|
||||
token character varying,
|
||||
|
|
@ -24577,6 +24583,9 @@ ALTER TABLE ONLY ci_runner_namespaces
|
|||
ALTER TABLE ONLY ci_runner_projects
|
||||
ADD CONSTRAINT ci_runner_projects_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY ci_runner_versions
|
||||
ADD CONSTRAINT ci_runner_versions_pkey PRIMARY KEY (version);
|
||||
|
||||
ALTER TABLE ONLY ci_runners
|
||||
ADD CONSTRAINT ci_runners_pkey PRIMARY KEY (id);
|
||||
|
||||
|
|
@ -27633,6 +27642,10 @@ CREATE UNIQUE INDEX index_ci_runner_namespaces_on_runner_id_and_namespace_id ON
|
|||
|
||||
CREATE INDEX index_ci_runner_projects_on_project_id ON ci_runner_projects USING btree (project_id);
|
||||
|
||||
CREATE INDEX index_ci_runner_versions_on_status ON ci_runner_versions USING btree (status);
|
||||
|
||||
CREATE INDEX index_ci_runner_versions_on_version ON ci_runner_versions USING btree (version);
|
||||
|
||||
CREATE INDEX index_ci_runners_on_active ON ci_runners USING btree (active, id);
|
||||
|
||||
CREATE INDEX index_ci_runners_on_contacted_at_and_id_desc ON ci_runners USING btree (contacted_at, id DESC);
|
||||
|
|
@ -27663,6 +27676,8 @@ CREATE INDEX index_ci_runners_on_token_expires_at_and_id_desc ON ci_runners USIN
|
|||
|
||||
CREATE INDEX index_ci_runners_on_token_expires_at_desc_and_id_desc ON ci_runners USING btree (token_expires_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX index_ci_runners_on_version ON ci_runners USING btree (version);
|
||||
|
||||
CREATE UNIQUE INDEX index_ci_running_builds_on_build_id ON ci_running_builds USING btree (build_id);
|
||||
|
||||
CREATE INDEX index_ci_running_builds_on_project_id ON ci_running_builds USING btree (project_id);
|
||||
|
|
|
|||
|
|
@ -1063,23 +1063,23 @@ For Omnibus GitLab installations, Mattermost logs are in these locations:
|
|||
|
||||
## Workhorse Logs
|
||||
|
||||
For Omnibus GitLab installations, Workhorse logs are in `/var/log/gitlab/gitlab-workhorse/`.
|
||||
For Omnibus GitLab installations, Workhorse logs are in `/var/log/gitlab/gitlab-workhorse/current`.
|
||||
|
||||
## PostgreSQL Logs
|
||||
|
||||
For Omnibus GitLab installations, PostgreSQL logs are in `/var/log/gitlab/postgresql/`.
|
||||
For Omnibus GitLab installations, PostgreSQL logs are in `/var/log/gitlab/postgresql/current`.
|
||||
|
||||
## Prometheus Logs
|
||||
|
||||
For Omnibus GitLab installations, Prometheus logs are in `/var/log/gitlab/prometheus/`.
|
||||
For Omnibus GitLab installations, Prometheus logs are in `/var/log/gitlab/prometheus/current`.
|
||||
|
||||
## Redis Logs
|
||||
|
||||
For Omnibus GitLab installations, Redis logs are in `/var/log/gitlab/redis/`.
|
||||
For Omnibus GitLab installations, Redis logs are in `/var/log/gitlab/redis/current`.
|
||||
|
||||
## Alertmanager Logs
|
||||
|
||||
For Omnibus GitLab installations, Alertmanager logs are in `/var/log/gitlab/alertmanager/`.
|
||||
For Omnibus GitLab installations, Alertmanager logs are in `/var/log/gitlab/alertmanager/current`.
|
||||
|
||||
<!-- vale gitlab.Spelling = NO -->
|
||||
|
||||
|
|
@ -1091,11 +1091,11 @@ For Omnibus GitLab installations, crond logs are in `/var/log/gitlab/crond/`.
|
|||
|
||||
## Grafana Logs
|
||||
|
||||
For Omnibus GitLab installations, Grafana logs are in `/var/log/gitlab/grafana/`.
|
||||
For Omnibus GitLab installations, Grafana logs are in `/var/log/gitlab/grafana/current`.
|
||||
|
||||
## LogRotate Logs
|
||||
|
||||
For Omnibus GitLab installations, `logrotate` logs are in `/var/log/gitlab/logrotate/`.
|
||||
For Omnibus GitLab installations, `logrotate` logs are in `/var/log/gitlab/logrotate/current`.
|
||||
|
||||
## GitLab Monitor Logs
|
||||
|
||||
|
|
@ -1103,12 +1103,12 @@ For Omnibus GitLab installations, GitLab Monitor logs are in `/var/log/gitlab/gi
|
|||
|
||||
## GitLab Exporter
|
||||
|
||||
For Omnibus GitLab installations, GitLab Exporter logs are in `/var/log/gitlab/gitlab-exporter/`.
|
||||
For Omnibus GitLab installations, GitLab Exporter logs are in `/var/log/gitlab/gitlab-exporter/current`.
|
||||
|
||||
## GitLab agent server
|
||||
|
||||
For Omnibus GitLab installations, GitLab agent server logs are
|
||||
in `/var/log/gitlab/gitlab-kas/`.
|
||||
in `/var/log/gitlab/gitlab-kas/current`.
|
||||
|
||||
## Praefect Logs
|
||||
|
||||
|
|
|
|||
|
|
@ -411,6 +411,56 @@ use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make sure to
|
|||
// => When x == 2: 'Last 2 days'
|
||||
```
|
||||
|
||||
- In Vue:
|
||||
|
||||
One of [the recommended ways to organize translated strings for Vue files](#vue-files) is to extract them into a `constants.js` file.
|
||||
That can be difficult to do when there are pluralized strings because the `count` variable won't be known inside the constants file.
|
||||
To overcome this, we recommend creating a function which takes a `count` argument:
|
||||
|
||||
```javascript
|
||||
// .../feature/constants.js
|
||||
import { n__ } from '~/locale';
|
||||
|
||||
export const I18N = {
|
||||
// Strings that are only singular don't need to be a function
|
||||
someDaysRemain: __('Some days remain'),
|
||||
daysRemaining(count) { return n__('%d day remaining', '%d days remaining', count); },
|
||||
};
|
||||
```
|
||||
|
||||
Then within a Vue component the function can be used to retrieve the correct pluralization form of the string:
|
||||
|
||||
```javascript
|
||||
// .../feature/components/days_remaining.vue
|
||||
import { sprintf } from '~/locale';
|
||||
import { I18N } from '../constants';
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
days: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
i18n: I18N,
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<span>
|
||||
A singular string:
|
||||
{{ $options.i18n.someDaysRemain }}
|
||||
</span>
|
||||
<span>
|
||||
A plural string:
|
||||
{{ $options.i18n.daysRemaining(days) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
The `n_` and `n__` methods should only be used to fetch pluralized translations of the same
|
||||
string, not to control the logic of showing different strings for different
|
||||
quantities. Some languages have different quantities of target plural forms.
|
||||
|
|
|
|||
|
|
@ -568,6 +568,16 @@ def unique_identifiers
|
|||
end
|
||||
```
|
||||
|
||||
### Resources cleanup
|
||||
|
||||
We have a mechanism to [collect](https://gitlab.com/gitlab-org/gitlab/-/blob/44345381e89d6bbd440f7b4c680d03e8b75b86de/qa/qa/tools/test_resource_data_processor.rb#L32)
|
||||
all resources created during test executions, and another to [handle](https://gitlab.com/gitlab-org/gitlab/-/blob/44345381e89d6bbd440f7b4c680d03e8b75b86de/qa/qa/tools/test_resources_handler.rb#L44)
|
||||
these resources. On [dotcom environments](https://about.gitlab.com/handbook/engineering/infrastructure/environments/#environments), after a test suite finishes in the [QA pipelines](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#scheduled-qa-test-pipelines), resources from all passing test are
|
||||
automatically deleted in the same pipeline run. Resources from all failed tests are reserved for investigation,
|
||||
and won't be deleted until the following Saturday by a scheduled pipeline. When introducing new resources, please
|
||||
also make sure to add any resource that cannot be deleted to the [IGNORED_RESOURCES](https://gitlab.com/gitlab-org/gitlab/-/blob/44345381e89d6bbd440f7b4c680d03e8b75b86de/qa/qa/tools/test_resources_handler.rb#L29)
|
||||
list.
|
||||
|
||||
## Where to ask for help?
|
||||
|
||||
If you need more information, ask for help on `#quality` channel on Slack
|
||||
|
|
|
|||
|
|
@ -397,11 +397,10 @@ To support the following package managers, the GitLab analyzers proceed in two s
|
|||
If your project <i>does not use</i> a <code>gradlew</code> file, then the analyzer automatically switches to one of the
|
||||
pre-installed Gradle versions, based on the version of Java specified by the
|
||||
<a href="#configuring-specific-analyzers-used-by-dependency-scanning"><code>DS_JAVA_VERSION</code></a> variable.
|
||||
By default, the analyzer uses Java 17 and Gradle 7.3.3.
|
||||
</p>
|
||||
<p>You can view the
|
||||
<a href="https://docs.gradle.org/current/userguide/compatibility.html#java">Gradle Java compatibility matrix</a> to see which version
|
||||
of Gradle is selected for each Java version. Note that we only support switching to one of these pre-installed Gradle versions
|
||||
for Java versions 13 to 17.
|
||||
<p>
|
||||
For Java versions <code>8</code> and <code>11</code>, Gradle <code>6.7.1</code> is automatically selected, and for Java versions <code>13</code> to <code>17</code>, Gradle <code>7.3.3</code> is automatically selected.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module Gitlab
|
|||
|
||||
def initialize(params, context)
|
||||
@location = params[:file]
|
||||
@project_name = params[:project]
|
||||
@project_name = get_project_name(params[:project])
|
||||
@ref_name = params[:ref] || 'HEAD'
|
||||
|
||||
super
|
||||
|
|
@ -122,6 +122,16 @@ module Gitlab
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: To be removed after we deprecate usage of array in `project` keyword.
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/365975
|
||||
def get_project_name(project_name)
|
||||
if project_name.is_a?(Array)
|
||||
project_name.first
|
||||
else
|
||||
project_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,13 +5,6 @@ module Gitlab
|
|||
class RunnerUpgradeCheck
|
||||
include Singleton
|
||||
|
||||
STATUSES = {
|
||||
invalid: 'Runner version is not valid.',
|
||||
not_available: 'Upgrade is not available for the runner.',
|
||||
available: 'Upgrade is available for the runner.',
|
||||
recommended: 'Upgrade is available and recommended for the runner.'
|
||||
}.freeze
|
||||
|
||||
def check_runner_upgrade_status(runner_version)
|
||||
runner_version = ::Gitlab::VersionInfo.parse(runner_version, parse_suffix: true)
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ ci_resource_groups: :gitlab_ci
|
|||
ci_resources: :gitlab_ci
|
||||
ci_runner_namespaces: :gitlab_ci
|
||||
ci_runner_projects: :gitlab_ci
|
||||
ci_runner_versions: :gitlab_ci
|
||||
ci_runners: :gitlab_ci
|
||||
ci_running_builds: :gitlab_ci
|
||||
ci_sources_pipelines: :gitlab_ci
|
||||
|
|
|
|||
|
|
@ -78,3 +78,23 @@
|
|||
category: analytics
|
||||
redis_slot: analytics
|
||||
aggregation: weekly
|
||||
- name: p_analytics_ci_cd_time_to_restore_service
|
||||
category: analytics
|
||||
redis_slot: analytics
|
||||
aggregation: weekly
|
||||
- name: g_analytics_ci_cd_release_statistics
|
||||
category: analytics
|
||||
redis_slot: analytics
|
||||
aggregation: weekly
|
||||
- name: g_analytics_ci_cd_deployment_frequency
|
||||
category: analytics
|
||||
redis_slot: analytics
|
||||
aggregation: weekly
|
||||
- name: g_analytics_ci_cd_lead_time
|
||||
category: analytics
|
||||
redis_slot: analytics
|
||||
aggregation: weekly
|
||||
- name: g_analytics_ci_cd_time_to_restore_service
|
||||
category: analytics
|
||||
redis_slot: analytics
|
||||
aggregation: weekly
|
||||
|
|
|
|||
|
|
@ -7734,6 +7734,12 @@ msgstr ""
|
|||
msgid "Checkout|Group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
|
||||
msgstr ""
|
||||
|
||||
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use, plus all over limit members) or more. To buy fewer seats, remove members from the group."
|
||||
msgstr ""
|
||||
|
||||
msgid "Checkout|Name of company or organization using GitLab"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7785,9 +7791,6 @@ msgstr ""
|
|||
msgid "Checkout|Tax"
|
||||
msgstr ""
|
||||
|
||||
msgid "Checkout|This number must be %{minimumNumberOfUsers} (your seats in use) or more."
|
||||
msgstr ""
|
||||
|
||||
msgid "Checkout|Total"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ module QA
|
|||
'QA::Resource::CiVariable',
|
||||
'QA::Resource::Repository::Commit',
|
||||
'QA::EE::Resource::GroupIteration',
|
||||
'QA::EE::Resource::Settings::Elasticsearch'
|
||||
'QA::EE::Resource::Settings::Elasticsearch',
|
||||
'QA::EE::Resource::VulnerabilityItem'
|
||||
].freeze
|
||||
|
||||
PROJECT = 'gitlab-qa-resources'
|
||||
|
|
|
|||
|
|
@ -827,6 +827,10 @@ RSpec.describe Projects::PipelinesController do
|
|||
{
|
||||
chart_param: 'lead-time',
|
||||
event: 'p_analytics_ci_cd_lead_time'
|
||||
},
|
||||
{
|
||||
chart_param: 'time-to-restore-service',
|
||||
event: 'p_analytics_ci_cd_time_to_restore_service'
|
||||
}
|
||||
].each do |tab|
|
||||
it_behaves_like 'tracking unique visits', :charts do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :ci_runner_version, class: 'Ci::RunnerVersion' do
|
||||
sequence(:version) { |n| "1.0.#{n}" }
|
||||
end
|
||||
end
|
||||
|
|
@ -5,9 +5,12 @@ require 'spec_helper'
|
|||
RSpec.describe Types::Ci::RunnerUpgradeStatusTypeEnum do
|
||||
specify { expect(described_class.graphql_name).to eq('CiRunnerUpgradeStatusType') }
|
||||
|
||||
it 'exposes all upgrade status values' do
|
||||
expect(described_class.values.keys).to eq(
|
||||
['UNKNOWN'] + ::Gitlab::Ci::RunnerUpgradeCheck::STATUSES.map { |sym, _| sym.to_s.upcase }
|
||||
it 'exposes all upgrade status values except not_processed' do
|
||||
expect(described_class.values.keys).to match_array(
|
||||
Ci::RunnerVersion.statuses.keys
|
||||
.reject { |k| k == 'not_processed' }
|
||||
.map { |k| k.upcase }
|
||||
.map { |v| v == 'INVALID_VERSION' ? 'INVALID' : v }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'ActsAsTaggableOn::Tag' do
|
||||
describe '.find_or_create_all_with_like_by_name' do
|
||||
let(:tags) { %w[tag] }
|
||||
|
||||
subject(:find_or_create) { ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(tags) }
|
||||
|
||||
it 'creates a tag' do
|
||||
expect { find_or_create }.to change(ActsAsTaggableOn::Tag, :count).by(1)
|
||||
end
|
||||
|
||||
it 'returns the Tag record' do
|
||||
results = find_or_create
|
||||
|
||||
expect(results.size).to eq(1)
|
||||
expect(results.first).to be_an_instance_of(ActsAsTaggableOn::Tag)
|
||||
expect(results.first.name).to eq('tag')
|
||||
end
|
||||
|
||||
context 'some tags already existing' do
|
||||
let(:tags) { %w[tag preexisting_tag tag2] }
|
||||
|
||||
before_all do
|
||||
ActsAsTaggableOn::Tag.create!(name: 'preexisting_tag')
|
||||
end
|
||||
|
||||
it 'creates only the missing tag' do
|
||||
expect(ActsAsTaggableOn::Tag).to receive(:insert_all)
|
||||
.with([{ name: 'tag' }, { name: 'tag2' }], unique_by: :name)
|
||||
.and_call_original
|
||||
|
||||
expect { find_or_create }.to change(ActsAsTaggableOn::Tag, :count).by(2)
|
||||
end
|
||||
|
||||
it 'returns the Tag records' do
|
||||
results = find_or_create
|
||||
|
||||
expect(results.map(&:name)).to match_array(tags)
|
||||
end
|
||||
end
|
||||
|
||||
context 'all tags already existing' do
|
||||
let(:tags) { %w[preexisting_tag preexisting_tag2] }
|
||||
|
||||
before_all do
|
||||
ActsAsTaggableOn::Tag.create!(name: 'preexisting_tag')
|
||||
ActsAsTaggableOn::Tag.create!(name: 'preexisting_tag2')
|
||||
end
|
||||
|
||||
it 'does not create new tags' do
|
||||
expect { find_or_create }.not_to change(ActsAsTaggableOn::Tag, :count)
|
||||
end
|
||||
|
||||
it 'returns the Tag records' do
|
||||
results = find_or_create
|
||||
|
||||
expect(results.map(&:name)).to match_array(tags)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -177,6 +177,22 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
|
|||
expect(project_file.error_message).to include("Project `xxxxxxxxxxxxxxxxxxxxxxx` not found or access denied!")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a project contained in an array is used with a masked variable' do
|
||||
let(:variables) do
|
||||
Gitlab::Ci::Variables::Collection.new([
|
||||
{ key: 'VAR1', value: 'a_secret_variable_value', masked: true }
|
||||
])
|
||||
end
|
||||
|
||||
let(:params) do
|
||||
{ project: ['a_secret_variable_value'], file: '/file.yml' }
|
||||
end
|
||||
|
||||
it 'does not raise an error' do
|
||||
expect { valid? }.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#expand_context' do
|
||||
|
|
|
|||
|
|
@ -35,6 +35,46 @@ RSpec.describe Ci::Runner do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'acts_as_taggable' do
|
||||
let(:tag_name) { 'tag123' }
|
||||
|
||||
context 'on save' do
|
||||
let_it_be_with_reload(:runner) { create(:ci_runner) }
|
||||
|
||||
before do
|
||||
runner.tag_list = [tag_name]
|
||||
end
|
||||
|
||||
context 'tag does not exist' do
|
||||
it 'creates a tag' do
|
||||
expect { runner.save! }.to change(ActsAsTaggableOn::Tag, :count).by(1)
|
||||
end
|
||||
|
||||
it 'creates an association to the tag' do
|
||||
runner.save!
|
||||
|
||||
expect(described_class.tagged_with(tag_name)).to include(runner)
|
||||
end
|
||||
end
|
||||
|
||||
context 'tag already exists' do
|
||||
before do
|
||||
ActsAsTaggableOn::Tag.create!(name: tag_name)
|
||||
end
|
||||
|
||||
it 'does not create a tag' do
|
||||
expect { runner.save! }.not_to change(ActsAsTaggableOn::Tag, :count)
|
||||
end
|
||||
|
||||
it 'creates an association to the tag' do
|
||||
runner.save!
|
||||
|
||||
expect(described_class.tagged_with(tag_name)).to include(runner)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validation' do
|
||||
it { is_expected.to validate_presence_of(:access_level) }
|
||||
it { is_expected.to validate_presence_of(:runner_type) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::RunnerVersion do
|
||||
it_behaves_like 'having unique enum values'
|
||||
|
||||
describe '.not_available' do
|
||||
subject { described_class.not_available }
|
||||
|
||||
let!(:runner_version1) { create(:ci_runner_version, version: 'abc123', status: :not_available) }
|
||||
let!(:runner_version2) { create(:ci_runner_version, version: 'abc234', status: :recommended) }
|
||||
|
||||
it { is_expected.to match_array([runner_version1]) }
|
||||
end
|
||||
|
||||
describe 'validation' do
|
||||
context 'when runner version is too long' do
|
||||
let(:runner_version) { build(:ci_runner_version, version: 'a' * 2049) }
|
||||
|
||||
it 'is not valid' do
|
||||
expect(runner_version).to be_invalid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1109,6 +1109,20 @@ RSpec.describe User do
|
|||
.to contain_exactly(user1, user2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.order_recent_last_activity' do
|
||||
it 'sorts users by activity and id to make the ordes deterministic' do
|
||||
expect(described_class.order_recent_last_activity.to_sql).to include(
|
||||
'ORDER BY "users"."last_activity_on" DESC NULLS LAST, "users"."id" ASC')
|
||||
end
|
||||
end
|
||||
|
||||
describe '.order_oldest_last_activity' do
|
||||
it 'sorts users by activity and id to make the ordes deterministic' do
|
||||
expect(described_class.order_oldest_last_activity.to_sql).to include(
|
||||
'ORDER BY "users"."last_activity_on" ASC NULLS FIRST, "users"."id" DESC')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'strip attributes' do
|
||||
|
|
@ -3518,49 +3532,45 @@ RSpec.describe User do
|
|||
end
|
||||
|
||||
describe '#sort_by_attribute' do
|
||||
before do
|
||||
described_class.delete_all
|
||||
@user = create :user, created_at: Date.today, current_sign_in_at: Date.today, name: 'Alpha'
|
||||
@user1 = create :user, created_at: Date.today - 1, current_sign_in_at: Date.today - 1, name: 'Omega'
|
||||
@user2 = create :user, created_at: Date.today - 2, name: 'Beta'
|
||||
end
|
||||
let_it_be(:user) { create :user, created_at: Date.today, current_sign_in_at: Date.today, username: 'user0' }
|
||||
let_it_be(:user1) { create :user, created_at: Date.today - 1, last_activity_on: Date.today - 1, current_sign_in_at: Date.today - 1, username: 'user1' }
|
||||
let_it_be(:user2) { create :user, created_at: Date.today - 2, username: 'user2' }
|
||||
let_it_be(:user3) { create :user, created_at: Date.today - 3, last_activity_on: Date.today, username: "user3" }
|
||||
|
||||
context 'when sort by recent_sign_in' do
|
||||
let(:users) { described_class.sort_by_attribute('recent_sign_in') }
|
||||
|
||||
it 'sorts users by recent sign-in time' do
|
||||
expect(users.first).to eq(@user)
|
||||
expect(users.second).to eq(@user1)
|
||||
end
|
||||
|
||||
it 'pushes users who never signed in to the end' do
|
||||
expect(users.third).to eq(@user2)
|
||||
it 'sorts users by recent sign-in time with user that never signed in at the end' do
|
||||
expect(users).to eq([user, user1, user2, user3])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sort by oldest_sign_in' do
|
||||
let(:users) { described_class.sort_by_attribute('oldest_sign_in') }
|
||||
|
||||
it 'sorts users by the oldest sign-in time' do
|
||||
expect(users.first).to eq(@user1)
|
||||
expect(users.second).to eq(@user)
|
||||
end
|
||||
|
||||
it 'pushes users who never signed in to the end' do
|
||||
expect(users.third).to eq(@user2)
|
||||
it 'sorts users by the oldest sign-in time with users that never signed in at the end' do
|
||||
expect(users).to eq([user1, user, user2, user3])
|
||||
end
|
||||
end
|
||||
|
||||
it 'sorts users in descending order by their creation time' do
|
||||
expect(described_class.sort_by_attribute('created_desc').first).to eq(@user)
|
||||
expect(described_class.sort_by_attribute('created_desc')).to eq([user, user1, user2, user3])
|
||||
end
|
||||
|
||||
it 'sorts users in ascending order by their creation time' do
|
||||
expect(described_class.sort_by_attribute('created_asc').first).to eq(@user2)
|
||||
expect(described_class.sort_by_attribute('created_asc')).to eq([user3, user2, user1, user])
|
||||
end
|
||||
|
||||
it 'sorts users by id in descending order when nil is passed' do
|
||||
expect(described_class.sort_by_attribute(nil).first).to eq(@user2)
|
||||
expect(described_class.sort_by_attribute(nil)).to eq([user3, user2, user1, user])
|
||||
end
|
||||
|
||||
it 'sorts user by latest activity descending, nulls last ordered by ascending id' do
|
||||
expect(described_class.sort_by_attribute('last_activity_on_desc')).to eq([user3, user1, user, user2])
|
||||
end
|
||||
|
||||
it 'sorts user by latest activity ascending, nulls first ordered by descending id' do
|
||||
expect(described_class.sort_by_attribute('last_activity_on_asc')).to eq([user2, user, user1, user3])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue