Commit 69b4b270 authored by Marin Jankovski's avatar Marin Jankovski

Merge branch '11-11-stable-prepare-rc3' into '11-11-stable'

Prepare 11.11.0-rc3 release

See merge request gitlab-org/gitlab-ce!28313
parents 4b358114 abac5047
......@@ -147,7 +147,7 @@ function deferredInitialisation() {
const canaryBadge = document.querySelector('.js-canary-badge');
const canaryLink = document.querySelector('.js-canary-link');
if (canaryBadge) {
canaryBadge.classList.remove('hidden');
canaryBadge.classList.add('hidden');
}
if (canaryLink) {
canaryLink.classList.add('hidden');
......
......@@ -47,6 +47,7 @@
display: flex;
align-items: flex-start;
width: 100%;
padding-bottom: $gl-padding;
@include media-breakpoint-down(xs) {
display: block;
......
......@@ -337,8 +337,8 @@ class Project < ApplicationRecord
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_personal_projects_limit, on: :create
validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? }
validate :visibility_level_allowed_by_group, if: -> { changes.has_key?(:visibility_level) }
validate :visibility_level_allowed_as_fork, if: -> { changes.has_key?(:visibility_level) }
validate :visibility_level_allowed_by_group, if: :should_validate_visibility_level?
validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level?
validate :check_wiki_path_conflict
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
validates :repository_storage,
......@@ -892,6 +892,10 @@ class Project < ApplicationRecord
self.errors.add(:limit_reached, error % { limit: limit })
end
def should_validate_visibility_level?
new_record? || changes.has_key?(:visibility_level)
end
def visibility_level_allowed_by_group
return if visibility_level_allowed_by_group?
......
......@@ -488,6 +488,10 @@ class ProjectPolicy < BasePolicy
def team_access_level
return -1 if @user.nil?
lookup_access_level!
end
def lookup_access_level!
# NOTE: max_member_access has its own cache
project.team.max_member_access(@user.id)
end
......
......@@ -9,7 +9,7 @@ module Projects
end
def execute
Projects::HousekeepingService.new(@project, :gc).execute do
Projects::HousekeepingService.new(@project).execute do
repository.delete_all_refs_except(RESERVED_REF_PREFIXES)
end
rescue Projects::HousekeepingService::LeaseTaken => e
......
......@@ -37,7 +37,17 @@ module Projects
raise DownloadLinksError, response.message unless response.success?
parse_response_links(response['objects'])
# Since the LFS Batch API may return a Content-Ttpe of
# application/vnd.git-lfs+json
# (https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md#requests),
# HTTParty does not know this is actually JSON.
data = JSON.parse(response.body)
raise DownloadLinksError, "LFS Batch API did return any objects" unless data.is_a?(Hash) && data.key?('objects')
parse_response_links(data['objects'])
rescue JSON::ParserError
raise DownloadLinksError, "LFS Batch API response is not JSON"
end
def parse_response_links(objects_response)
......
......@@ -10,6 +10,7 @@
.hide.alert.alert-danger.js-ci-variable-error-box
%ul.ci-variable-list
= render 'ci/variables/variable_header'
- @variables.each.each do |variable|
= render 'ci/variables/variable_row', form_field: 'variables', variable: variable
= render 'ci/variables/variable_row', form_field: 'variables'
......
- only_key_value = local_assigns.fetch(:only_key_value, false)
%li.ci-variable-row.m-0.d-none.d-sm-block
.d-flex.w-100.align-items-center.pb-2
.bold.table-section.section-15.append-right-10
= s_('CiVariables|Type')
.bold.table-section.section-15.append-right-10
= s_('CiVariables|Key')
.bold.table-section.section-15.append-right-10
= s_('CiVariables|Value')
- unless only_key_value
.bold.table-section.section-20
= s_('CiVariables|State')
.bold.table-section.section-20
= s_('CiVariables|Masked')
= render_if_exists 'ci/variables/environment_scope_header'
......@@ -20,18 +20,18 @@
- masked_input_name = "#{form_field}[variables_attributes][][masked]"
%li.js-row.ci-variable-row{ data: { is_persisted: "#{!id.nil?}" } }
.ci-variable-row-body
.ci-variable-row-body.border-bottom
%input.js-ci-variable-input-id{ type: "hidden", name: id_input_name, value: id }
%input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name }
%select.js-ci-variable-input-variable-type.ci-variable-body-item.form-control.select-control{ name: variable_type_input_name }
%select.js-ci-variable-input-variable-type.ci-variable-body-item.form-control.select-control.table-section.section-15{ name: variable_type_input_name }
= options_for_select(ci_variable_type_options, variable_type)
%input.js-ci-variable-input-key.ci-variable-body-item.qa-ci-variable-input-key.form-control{ type: "text",
%input.js-ci-variable-input-key.ci-variable-body-item.qa-ci-variable-input-key.form-control.table-section.section-15{ type: "text",
name: key_input_name,
value: key,
placeholder: s_('CiVariables|Input variable key') }
.ci-variable-body-item.gl-show-field-errors
.ci-variable-body-item.gl-show-field-errors.table-section.section-15.border-top-0.p-0
.form-control.js-secret-value-placeholder.qa-ci-variable-input-value{ class: ('hide' unless id) }
= '*' * 20
= '*' * 17
%textarea.js-ci-variable-input-value.js-secret-value.qa-ci-variable-input-value.form-control{ class: ('hide' if id),
rows: 1,
name: value_input_name,
......@@ -41,7 +41,7 @@
= s_("CiVariables|Cannot use Masked Variable with current value")
= link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'masked-variables'), target: '_blank', rel: 'noopener noreferrer'
- unless only_key_value
.ci-variable-body-item.ci-variable-protected-item
.ci-variable-body-item.ci-variable-protected-item.table-section.section-20.mr-0.border-top-0
.append-right-default
= s_("CiVariable|Protected")
%button{ type: 'button',
......@@ -55,7 +55,7 @@
%span.toggle-icon
= sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked')
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
.ci-variable-body-item.ci-variable-masked-item
.ci-variable-body-item.ci-variable-masked-item.table-section.section-20.mr-0.border-top-0
.append-right-default
= s_("CiVariable|Masked")
%button{ type: 'button',
......@@ -70,5 +70,5 @@
= sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked')
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
= render_if_exists 'ci/variables/environment_scope', form_field: form_field, variable: variable
%button.js-row-remove-button.ci-variable-row-remove-button{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') }
= icon('minus-circle')
%button.js-row-remove-button.ci-variable-row-remove-button.table-section.section-5.border-top-0{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') }
= icon('minus-circle')
......@@ -10,7 +10,7 @@
.branch-info
.branch-title
= sprite_icon('fork', size: 12)
= link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name prepend-left-8' do
= link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name prepend-left-8 qa-branch-name' do
= branch.name
- if branch.name == @repository.root_ref
%span.badge.badge-primary.prepend-left-5 default
......
......@@ -53,7 +53,7 @@
= time_ago_with_tooltip(member.created_at)
- if show_roles
- current_resource = @project || @group
.controls.member-controls.row
.controls.member-controls
- if show_controls && member.source == current_resource
- if member.can_resend_invite?
......
---
title: Fixes next badge being always visible
merge_request:
author:
type: fixed
---
title: Remove non-semantic use of `.row` in member listing controls
merge_request: 28204
author:
type: fixed
---
title: Fix project visibility level validation
merge_request: 28305
author: Peter Marko
type: fixed
---
title: Add EE fixtures to SeedFu list
merge_request: 28241
author:
type: other
---
title: Properly handle LFS Batch API response in project import
merge_request: 28223
author:
type: fixed
# frozen_string_literal: true
if Gitlab.ee?
SeedFu.fixture_paths += %W[ee/db/fixtures ee/db/fixtures/#{Rails.env}]
end
......@@ -157,6 +157,42 @@ For wikis:
sudo -u git -H bundle exec rake geo:verification:wiki:reset RAILS_ENV=production
```
## Reconcile differences with checksum mismatches
If the **primary** and **secondary** nodes have a checksum verification mismatch, the cause may not be apparent. To find the cause of a checksum mismatch:
1. Navigate to the **Admin Area > Projects** dashboard on the **primary** node, find the
project that you want to check the checksum differences and click on the
**Edit** button:
![Projects dashboard](img/checksum-differences-admin-projects.png)
1. On the project admin page get the **Gitaly storage name**, and **Gitaly relative path**:
![Project admin page](img/checksum-differences-admin-project-page.png)
1. Navigate to the project's repository directory on both **primary** and **secondary** nodes. For an installation from source, the path is usually `/home/git/repositories`. For Omnibus installs, the path is usually `/var/opt/gitlab/git-data/repositories`. Note that if `git_data_dirs` is customized, check the directory layout on your server to be sure.
```sh
cd /var/opt/gitlab/git-data/repositories
```
1. Run the following command on the **primary** node, redirecting the output to a file:
```sh
git show-ref --head | grep -E "HEAD|(refs/(heads|tags|keep-around|merge-requests|environments|notes)/)" > primary-node-refs
```
1. Run the following command on the **secondary** node, redirecting the output to a file:
```sh
git show-ref --head | grep -E "HEAD|(refs/(heads|tags|keep-around|merge-requests|environments|notes)/)" > secondary-node-refs
```
1. Copy the files from the previous steps on the same system, and do a diff between the contents:
```sh
diff primary-node-refs secondary-node-refs
```
## Current limitations
Until [issue #5064][ee-5064] is completed, background verification doesn't cover
......
......@@ -44,6 +44,7 @@ description: 'Learn how to contribute to GitLab.'
- [`Gemfile` guidelines](gemfile.md)
- [Pry debugging](pry_debugging.md)
- [Sidekiq debugging](sidekiq_debugging.md)
- [Accessing session data](session.md)
- [Gotchas](gotchas.md) to avoid
- [Avoid modules with instance variables](module_with_instance_variables.md) if possible
- [How to dump production data to staging](db_dump.md)
......
# Accessing session data
Session data in GitLab is stored in Redis and can be accessed in a variety of ways.
During a web request, for example:
- Rails provides access to the session from within controllers through [`ActionDispatch::Session`](https://guides.rubyonrails.org/action_controller_overview.html#session).
- Outside of controllers, it is possible to access the session through `Gitlab::Session`.
Outside of a web request it is still possible to access sessions stored in Redis. For example:
- Session IDs and contents can be [looked up directly in Redis](#redis).
- Data about the UserAgent associated with the session can be accessed through `ActiveSession`.
When storing values in a session it is best to:
- Use simple primitives and avoid storing objects to avoid marshaling complications.
- Clean up after unneeded variables to keep memory usage in Redis down.
## Gitlab::Session
Sometimes you might want to persist data in the session instead of another store like the database. `Gitlab::Session` lets you access this without passing the session around extensively. For example, you could access it from within a policy without having to pass the session through to each place permissions are checked from.
The session has a hash-like interface, just like when using it from a controller. There is also `NamespacedSessionStore` for storing key-value data in a hash.
```ruby
# Lookup a value stored in the current session
Gitlab::Session.current[:my_feature]
# Modify the current session stored in redis
Gitlab::Session.current[:my_feature] = value
# Store key-value data namespaced under a key
Gitlab::NamespacedSessionStore.new(:my_feature)[some_key] = value
# Set the session for a block of code, such as for tests
Gitlab::Session.with_session(my_feature: value) do
# Code that uses Session.current[:my_feature]
end
```
## Redis
Session data can be accessed directly through Redis. This can let you check up on a browser session when debugging.
```ruby
# Get a list of sessions
session_ids = Gitlab::Redis::SharedState.with do |redis|
redis.smembers("#{Gitlab::Redis::SharedState::USER_SESSIONS_LOOKUP_NAMESPACE}:#{user.id}")
end
# Retrieve a specific session
session_data = Gitlab::Redis::SharedState.with { |redis| redis.get("#{Gitlab::Redis::SharedState::SESSION_NAMESPACE}:#{session_id}") }
Marshal.load(session_data)
```
## Getting device information with ActiveSession
The [**Active Sessions** page on a user's profile](../user/profile/active_sessions.md) displays information about the device used to access each session. The methods used there to list sessions can also be useful for development.
```ruby
# Get list of sessions for a given user
# Includes session_id and data from the UserAgent
ActiveSession.list(user)
```
......@@ -448,6 +448,18 @@ sudo -u git cp config/database.yml.postgresql config/database.yml
# MySQL only:
sudo -u git cp config/database.yml.mysql config/database.yml
# PostgreSQL only:
# Remove host, username, and password lines from config/database.yml.
# Once modified, the `production` settings will be as follows:
#
# production:
# adapter: postgresql
# encoding: unicode
# database: gitlabhq_production
# pool: 10
#
sudo -u git -H editor config/database.yml
# MySQL and remote PostgreSQL only:
# Update username/password in config/database.yml.
# You only need to adapt the production settings (first part).
......@@ -565,6 +577,18 @@ sudo -u git -H editor config.toml
For more information about configuring Gitaly see
[doc/administration/gitaly](../administration/gitaly).
### Start Gitaly
Gitaly must be running for the next section.
```sh
gitlab_path=/home/git/gitlab
gitaly_path=/home/git/gitaly
sudo -u git -H $gitlab_path/bin/daemon_with_pidfile $gitlab_path/tmp/pids/gitaly.pid \
$gitaly_path/gitaly $gitaly_path/config.toml >> $gitlab_path/log/gitaly.log 2>&1 &
```
### Initialize Database and Activate Advanced Features
```sh
......@@ -640,6 +664,12 @@ sudo -u git -H yarn install --production --pure-lockfile
sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
```
If `rake` fails with `JavaScript heap out of memory` error, try to run it with `NODE_OPTIONS` set as follows.
```sh
sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production NODE_OPTIONS="--max_old_space_size=4096"
```
### Start Your GitLab Instance
```sh
......
# SalesForce OmniAuth Provider
You can integrate your GitLab instance with [SalesForce](https://www.salesforce.com/) to enable users to login to your GitLab instance with their SalesForce account.
You can integrate your GitLab instance with [SalesForce](https://www.salesforce.com/) to enable users to login to your GitLab instance with their SalesForce account.
## Create SalesForce Application
To enable SalesForce OmniAuth provider, you must use SalesForce's credentials for your GitLab instance.
To get the credentials (a pair of Client ID and Client Secret), you must register an application on UltraAuth.
To get the credentials (a pair of Client ID and Client Secret), you must register an application on SalesForces.
1. Sign in to [SalesForce](https://www.salesforce.com/).
1. Navigate to **Platform Tools/Apps** and click on **New Connected App**.
1. Navigate to **Platform Tools/Apps/App Manager** and click on **New Connected App**.
1. Fill in the application details into the following fields:
- **Connected App Name** and **API Name**: Set to any value but consider something like `<Organization>'s GitLab`, `<Your Name>'s GitLab`, or something else that is descriptive.
......@@ -64,7 +64,7 @@ To get the credentials (a pair of Client ID and Client Secret), you must registe
}
```
1. Change `SALESFORCE_CLIENT_ID` to the Consumer Key from the SalesForce connected application page.
1. Change `SALESFORCE_CLIENT_SECRET` to the Client Secret from the SalesForce connected application page.
1. Change `SALESFORCE_CLIENT_SECRET` to the Consumer Secret from the SalesForce connected application page.
![SalesForce App Secret Details](img/salesforce_app_secret_details.png)
1. Save the configuration file.
......
......@@ -98,8 +98,7 @@ the group.
NOTE: **Note:**
Only available on GitLab.com.
If you have a Group with a [paid plan](https://about.gitlab.com/pricing/#gitlab-com) on GitLab.com,
then you can purchase additional CI minutes so your pipelines will not be blocked after you have
You can purchase additional CI minutes so your pipelines will not be blocked after you have
used all your CI minutes from your main quota.
In order to purchase additional minutes, you should follow these steps:
......
......@@ -1894,9 +1894,24 @@ msgstr ""
msgid "CiVariables|Input variable value"
msgstr ""
msgid "CiVariables|Key"
msgstr ""
msgid "CiVariables|Masked"
msgstr ""
msgid "CiVariables|Remove variable row"
msgstr ""
msgid "CiVariables|State"
msgstr ""
msgid "CiVariables|Type"
msgstr ""
msgid "CiVariables|Value"
msgstr ""
msgid "CiVariable|* (All environments)"
msgstr ""
......
......@@ -113,8 +113,8 @@ module QA
has_css?(element_selector_css(name), wait: wait, text: text)
end
def has_no_element?(name, wait: Capybara.default_max_wait_time)
has_no_css?(element_selector_css(name), wait: wait)
def has_no_element?(name, text: nil, wait: Capybara.default_max_wait_time)
has_no_css?(element_selector_css(name), wait: wait, text: text)
end
def has_text?(text)
......@@ -129,8 +129,8 @@ module QA
has_no_css?('.fa-spinner', wait: Capybara.default_max_wait_time)
end
def within_element(name)
page.within(element_selector_css(name)) do
def within_element(name, text: nil)
page.within(element_selector_css(name), text: text) do
yield
end
end
......
......@@ -7,6 +7,7 @@ module QA
class Show < Page::Base
view 'app/views/projects/branches/_branch.html.haml' do
element :remove_btn
element :branch_name
end
view 'app/views/projects/branches/_panel.html.haml' do
element :all_branches
......@@ -27,11 +28,9 @@ module QA
finished_loading?
end
def has_branch_title?(branch_title)
def has_no_branch?(branch_name)
within_element(:all_branches) do
within(".item-title") do
has_text?(branch_title)
end
has_no_element?(:branch_name, text: branch_name, wait: Support::Waiter::DEFAULT_MAX_WAIT_TIME)
end
end
......@@ -48,15 +47,6 @@ module QA
click_element(:delete_merged_branches)
end
end
def wait_for_texts_not_to_be_visible(texts)
text_not_visible = wait do
texts.all? do |text|
has_no_text?(text)
end
end
raise "Expected text(s) #{texts} not to be visible" unless text_not_visible
end
end
end
end
......
......@@ -73,10 +73,9 @@ module QA
Page::Project::Branches::Show.perform do |branches_view|
branches_view.delete_branch(third_branch)
expect(branches_view).to have_no_branch(third_branch)
end
expect(page).not_to have_content(third_branch)
Page::Project::Branches::Show.perform(&:delete_merged_branches)
expect(page).to have_content(
......@@ -85,8 +84,7 @@ module QA
page.refresh
Page::Project::Branches::Show.perform do |branches_view|
branches_view.wait_for_texts_not_to_be_visible([commit_message_of_second_branch])
expect(branches_view).not_to have_branch_title(second_branch)
expect(branches_view).to have_no_branch(second_branch)
end
end
end
......
......@@ -76,23 +76,18 @@ module QA
super
end
def has_element?(name, text: nil, wait: Capybara.default_max_wait_time)
def has_element?(name, **kwargs)
found = super
msg = ["has_element? :#{name}"]
msg << %Q(with text "#{text}") if text
msg << "(wait: #{wait})"
msg << "returned: #{found}"
log(msg.compact.join(' '))
log_has_element_or_not('has_element?', name, found, **kwargs)
found
end
def has_no_element?(name, wait: Capybara.default_max_wait_time)
def has_no_element?(name, **kwargs)
found = super
log("has_no_element? :#{name} returned #{found}")
log_has_element_or_not('has_no_element?', name, found, **kwargs)
found
end
......@@ -149,6 +144,15 @@ module QA
def log(msg)
QA::Runtime::Logger.debug(msg)
end
def log_has_element_or_not(method, name, found, **kwargs)
msg = ["#{method} :#{name}"]
msg << %Q(with text "#{kwargs[:text]}") if kwargs[:text]
msg << "(wait: #{kwargs[:wait] || Capybara.default_max_wait_time})"
msg << "returned: #{found}"
log(msg.compact.join(' '))
end
end
end
end
......
......@@ -3,9 +3,11 @@
module QA
module Support
module Waiter
DEFAULT_MAX_WAIT_TIME = 60
module_function
def wait(max: 60, interval: 0.1)
def wait(max: DEFAULT_MAX_WAIT_TIME, interval: 0.1)
QA::Runtime::Logger.debug("with wait: max #{max}; interval #{interval}")
start = Time.now
......
......@@ -93,7 +93,14 @@ describe QA::Support::Page::Logging do
allow(page).to receive(:has_no_css?).and_return(true)
expect { subject.has_no_element?(:element) }
.to output(/has_no_element\? :element returned true/).to_stdout_from_any_process
.to output(/has_no_element\? :element \(wait: 2\) returned: true/).to_stdout_from_any_process
end
it 'logs has_no_element? with text' do
allow(page).to receive(:has_no_css?).and_return(true)
expect { subject.has_no_element?(:element, text: "more text") }
.to output(/has_no_element\? :element with text \"more text\" \(wait: 2\) returned: true/).to_stdout_from_any_process
end
it 'logs has_text?' do
......
......@@ -113,7 +113,7 @@ describe('AjaxFormVariableList', () => {
it('hides secret values', done => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200, {});
const row = container.querySelector('.js-row:first-child');
const row = container.querySelector('.js-row');
const valueInput = row.querySelector('.js-ci-variable-input-value');
const valuePlaceholder = row.querySelector('.js-secret-value-placeholder');
......
......@@ -214,6 +214,13 @@ describe Project do
expect(project2).not_to be_valid
end
it 'validates the visibility' do
expect_any_instance_of(described_class).to receive(:visibility_level_allowed_as_fork).and_call_original
expect_any_instance_of(described_class).to receive(:visibility_level_allowed_by_group).and_call_original
create(:project)
end
describe 'wiki path conflict' do
context "when the new path has been used by the wiki of other Project" do
it 'has an error on the name attribute' do
......
......@@ -15,7 +15,7 @@ describe Projects::AfterImportService do
describe '#execute' do
before do
allow(Projects::HousekeepingService)
.to receive(:new).with(project, :gc).and_return(housekeeping_service)
.to receive(:new).with(project).and_return(housekeeping_service)
allow(housekeeping_service)
.to receive(:execute).and_yield
......
......@@ -33,7 +33,10 @@ describe Projects::LfsPointers::LfsDownloadLinkListService do
before do
allow(project).to receive(:lfs_enabled?).and_return(true)
allow(Gitlab::HTTP).to receive(:post).and_return(objects_response)
response = instance_double(HTTParty::Response)
allow(response).to receive(:body).and_return(objects_response.to_json)
allow(response).to receive(:success?).and_return(true)
allow(Gitlab::HTTP).to receive(:post).and_return(response)
end
describe '#execute' do
......@@ -89,6 +92,21 @@ describe Projects::LfsPointers::LfsDownloadLinkListService do
expect { subject.send(:get_download_links, new_oids) }.to raise_error(described_class::DownloadLinksError)
end
shared_examples 'JSON parse errors' do |body|
it 'raises error' do
response = instance_double(HTTParty::Response)
allow(response).to receive(:body).and_return(body)
allow(response).to receive(:success?).and_return(true)
allow(Gitlab::HTTP).to receive(:post).and_return(response)
expect { subject.send(:get_download_links, new_oids) }.to raise_error(described_class::DownloadLinksError)
end
end
it_behaves_like 'JSON parse errors', '{'
it_behaves_like 'JSON parse errors', '{}'
it_behaves_like 'JSON parse errors', '{ foo: 123 }'
end
describe '#parse_response_links' do
......
......@@ -17,7 +17,7 @@ shared_examples 'variable list' do
visit page_path
# We check the first row because it re-sorts to alphabetical order on refresh
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq('key')
expect(find('.js-ci-variable-input-value', visible: false).value).to eq('key_value')
end
......@@ -38,7 +38,7 @@ shared_examples 'variable list' do
visit page_path
# We check the first row because it re-sorts to alphabetical order on refresh
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq('key')
expect(find('.js-ci-variable-input-value', visible: false).value).to eq('key_value')
expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
......@@ -59,7 +59,7 @@ shared_examples 'variable list' do
visit page_path
# We check the first row because it re-sorts to alphabetical order on refresh
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq('key')
expect(find('.js-ci-variable-input-value', visible: false).value).to eq('key_value')
expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
......@@ -116,19 +116,19 @@ shared_examples 'variable list' do
page.within('.js-ci-variable-list-section') do
expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
expect(first('.js-ci-variable-input-value', visible: false).value).to eq(variable.value)
expect(page).to have_content('*' * 20)
expect(page).to have_content('*' * 17)
click_button('Reveal value')
expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
expect(first('.js-ci-variable-input-value').value).to eq(variable.value)
expect(page).not_to have_content('*' * 20)
expect(page).not_to have_content('*' * 17)
click_button('Hide value')
expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
expect(first('.js-ci-variable-input-value', visible: false).value).to eq(variable.value)
expect(page).to have_content('*' * 20)
expect(page).to have_content('*' * 17)
end
end
......@@ -149,7 +149,7 @@ shared_examples 'variable list' do
page.within('.js-ci-variable-list-section') do
click_button('Reveal value')
page.within('.js-row:nth-child(1)') do
page.within('.js-row:nth-child(2)') do
find('.js-ci-variable-input-key').set('new_key')
find('.js-ci-variable-input-value').set('new_value')
end
......@@ -159,7 +159,7 @@ shared_examples 'variable list' do
visit page_path
page.within('.js-row:nth-child(1)') do
page.within('.js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq('new_key')
expect(find('.js-ci-variable-input-value', visible: false).value).to eq('new_value')
end
......@@ -181,7 +181,7 @@ shared_examples 'variable list' do
visit page_path
# We check the first row because it re-sorts to alphabetical order on refresh
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(3)') do
find('.ci-variable-protected-item .js-project-feature-toggle').click
expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
......@@ -193,7 +193,7 @@ shared_examples 'variable list' do
visit page_path
# We check the first row because it re-sorts to alphabetical order on refresh
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(3)') do
expect(find('.js-ci-variable-input-key').value).to eq('unprotected_key')
expect(find('.js-ci-variable-input-value', visible: false).value).to eq('unprotected_value')
expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
......@@ -215,7 +215,7 @@ shared_examples 'variable list' do
visit page_path
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
find('.ci-variable-protected-item .js-project-feature-toggle').click
expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
......@@ -226,7 +226,7 @@ shared_examples 'variable list' do
visit page_path
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq('protected_key')
expect(find('.js-ci-variable-input-value', visible: false).value).to eq('protected_value')
expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
......@@ -234,7 +234,7 @@ shared_examples 'variable list' do
end
it 'edits variable to be unmasked' do
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
find('.ci-variable-masked-item .js-project-feature-toggle').click
......@@ -247,13 +247,13 @@ shared_examples 'variable list' do
visit page_path
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
end
end
it 'edits variable to be masked' do
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
find('.ci-variable-masked-item .js-project-feature-toggle').click
......@@ -266,7 +266,7 @@ shared_examples 'variable list' do
visit page_path
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('false')
find('.ci-variable-masked-item .js-project-feature-toggle').click
......@@ -279,7 +279,7 @@ shared_examples 'variable list' do
visit page_path
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-masked', visible: false).value).to eq('true')
end
end
......@@ -302,7 +302,7 @@ shared_examples 'variable list' do
expect(page).to have_selector('.js-row', count: 4)
# Remove the `akey` variable
page.within('.js-row:nth-child(2)') do
page.within('.js-row:nth-child(3)') do
first('.js-row-remove-button').click
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment