Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-01 00:09:48 +00:00
parent 9877050db1
commit 516b939c44
34 changed files with 498 additions and 57 deletions

View File

@ -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.

View File

@ -1 +1 @@
c54d613d0eb9c573d79f5da0975655f11f007932
0c72a4ba3de2125098d72fce52b99df3d4ad5475

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
3245905956e4781629bbf6398c9534cf35eab469e8a703f755ed26de90dee0e1

View File

@ -0,0 +1 @@
cf3c6e8d720ce48272b8b9658d3c240e8fe3c9a26284a9e169f7bb6a40c862bc

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -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