Merge branch 'master' into fix-edit-notes-on-merge-request-diff
This commit is contained in:
commit
4a29669dec
232 changed files with 453 additions and 233 deletions
|
@ -24,6 +24,27 @@ spec:api:
|
|||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:models:
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:lib:
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:services:
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:benchmark:
|
||||
script:
|
||||
- RAILS_ENV=test bundle exec rake spec:benchmark
|
||||
|
@ -39,9 +60,16 @@ spec:other:
|
|||
- ruby
|
||||
- mysql
|
||||
|
||||
spinach:project:
|
||||
spinach:project:half:
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spinach:project:rest:
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
@ -89,10 +117,9 @@ flay:
|
|||
- mysql
|
||||
|
||||
bundler:audit:
|
||||
script:
|
||||
script:
|
||||
- "bundle exec bundle-audit update"
|
||||
- "bundle exec bundle-audit check"
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
allow_failure: true
|
||||
|
|
|
@ -27,6 +27,7 @@ v 8.3.0 (unreleased)
|
|||
- Block LDAP user when they are no longer found in the LDAP server
|
||||
- Improve wording on project visibility levels (Zeger-Jan van de Weg)
|
||||
- Fix editing notes on a merge request diff
|
||||
- Automatically select default clone protocol based on user preferences (Eirik Lygre)
|
||||
|
||||
v 8.2.3
|
||||
- Fix application settings cache not expiring after changes (Stan Hu)
|
||||
|
@ -41,6 +42,7 @@ v 8.2.2
|
|||
- Fix Error 500 when viewing user's personal projects from admin page (Stan Hu)
|
||||
- Fix: Raw private snippets access workflow
|
||||
- Prevent "413 Request entity too large" errors when pushing large files with LFS
|
||||
- Fix: As an admin, cannot add oneself as a member to a group/project
|
||||
- Fix invalid links within projects dashboard header
|
||||
- Make current user the first user in assignee dropdown in issues detail page (Stan Hu)
|
||||
- Fix: duplicate email notifications on issue comments
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -93,7 +93,6 @@ gem 'html-pipeline', '~> 1.11.0'
|
|||
gem 'task_list', '~> 1.0.2', require: 'task_list/railtie'
|
||||
gem 'github-markup', '~> 1.3.1'
|
||||
gem 'redcarpet', '~> 3.3.3'
|
||||
gem 'RedCloth', '~> 4.2.9'
|
||||
gem 'rdoc', '~>3.6'
|
||||
gem 'org-ruby', '~> 0.9.12'
|
||||
gem 'creole', '~> 0.5.0'
|
||||
|
|
|
@ -2,7 +2,6 @@ GEM
|
|||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (2.3.2)
|
||||
RedCloth (4.2.9)
|
||||
ace-rails-ap (2.0.1)
|
||||
actionmailer (4.2.4)
|
||||
actionpack (= 4.2.4)
|
||||
|
@ -826,7 +825,6 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
RedCloth (~> 4.2.9)
|
||||
ace-rails-ap (~> 2.0.1)
|
||||
activerecord-deprecated_finders (~> 1.0.3)
|
||||
activerecord-session_store (~> 0.1.0)
|
||||
|
|
|
@ -88,8 +88,14 @@ ul.bordered-list {
|
|||
}
|
||||
}
|
||||
|
||||
li.task-list-item {
|
||||
list-style-type: none;
|
||||
ul.task-list {
|
||||
li.task-list-item {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
ul:not(.task-list) {
|
||||
padding-left: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
ul.content-list {
|
||||
|
|
|
@ -109,13 +109,9 @@ ul.notes {
|
|||
}
|
||||
}
|
||||
|
||||
// Reduce left padding of first task list ul element
|
||||
ul.task-list:first-child {
|
||||
padding-left: 10px;
|
||||
|
||||
// sub-tasks should be padded normally
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
ul.task-list {
|
||||
ul:not(.task-list) {
|
||||
padding-left: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -175,11 +175,19 @@ module ProjectsHelper
|
|||
end
|
||||
|
||||
def default_url_to_repo(project = @project)
|
||||
current_user ? project.url_to_repo : project.http_url_to_repo
|
||||
if default_clone_protocol == "ssh"
|
||||
project.ssh_url_to_repo
|
||||
else
|
||||
project.http_url_to_repo
|
||||
end
|
||||
end
|
||||
|
||||
def default_clone_protocol
|
||||
current_user ? "ssh" : "http"
|
||||
if !current_user || current_user.require_ssh_key?
|
||||
"http"
|
||||
else
|
||||
"ssh"
|
||||
end
|
||||
end
|
||||
|
||||
def project_last_activity(project)
|
||||
|
|
|
@ -346,12 +346,10 @@ class Ability
|
|||
unless group.last_owner?(target_user)
|
||||
can_manage = group_abilities(user, group).include?(:admin_group_member)
|
||||
|
||||
if can_manage && user != target_user
|
||||
if can_manage
|
||||
rules << :update_group_member
|
||||
rules << :destroy_group_member
|
||||
end
|
||||
|
||||
if user == target_user
|
||||
elsif user == target_user
|
||||
rules << :destroy_group_member
|
||||
end
|
||||
end
|
||||
|
@ -367,12 +365,10 @@ class Ability
|
|||
unless target_user == project.owner
|
||||
can_manage = project_abilities(user, project).include?(:admin_project_member)
|
||||
|
||||
if can_manage && user != target_user
|
||||
if can_manage
|
||||
rules << :update_project_member
|
||||
rules << :destroy_project_member
|
||||
end
|
||||
|
||||
if user == target_user
|
||||
elsif user == target_user
|
||||
rules << :destroy_project_member
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,5 +32,5 @@
|
|||
New directory
|
||||
- elsif !on_top_of_branch?
|
||||
%li
|
||||
%span.btn.add-to-tree.disabled.has_tooltip{title: "You can only add files when you are on a branch.", data: {container: 'body'}}
|
||||
%span.btn.btn-sm.add-to-tree.disabled.has_tooltip{title: "You can only add files when you are on a branch.", data: {container: 'body'}}
|
||||
= icon('plus')
|
||||
|
|
|
@ -398,7 +398,6 @@ Parameters:
|
|||
- `user_id` (required) - user_id of owner
|
||||
- `name` (required) - new project name
|
||||
- `description` (optional) - short project description
|
||||
- `default_branch` (optional) - 'master' by default
|
||||
- `issues_enabled` (optional)
|
||||
- `merge_requests_enabled` (optional)
|
||||
- `builds_enabled` (optional)
|
||||
|
|
|
@ -85,11 +85,10 @@ sudo -u git -H git checkout 0.4.2
|
|||
sudo -u git -H make
|
||||
```
|
||||
|
||||
Update the GitLab init script and 'default' file.
|
||||
Update the GitLab 'default' file.
|
||||
|
||||
```
|
||||
cd /home/git/gitlab
|
||||
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
|
||||
test -e /etc/default/gitlab && \
|
||||
sudo sed -i.pre-8.2 's/^\([^=]*\)gitlab_git_http_server/\1gitlab_workhorse/' /etc/default/gitlab
|
||||
```
|
||||
|
|
|
@ -33,3 +33,19 @@ Feature: Admin Groups
|
|||
When I visit admin group page
|
||||
When I select user "johndoe@gitlab.com" from user list as "Reporter"
|
||||
Then I should see "johndoe@gitlab.com" in team list in every project as "Reporter"
|
||||
|
||||
@javascript
|
||||
Scenario: Signed in admin should be able to add himself to a group
|
||||
Given "John Doe" is owner of group "Owned"
|
||||
When I visit group "Owned" members page
|
||||
When I select current user as "Developer"
|
||||
Then I should see current user as "Developer"
|
||||
|
||||
@javascript
|
||||
Scenario: Signed in admin should be able to remove himself from group
|
||||
Given current user is developer of group "Owned"
|
||||
When I visit group "Owned" members page
|
||||
Then I should see current user as "Developer"
|
||||
When I click on the "Remove User From Group" button for current user
|
||||
When I visit group "Owned" members page
|
||||
Then I should not see current user as "Developer"
|
||||
|
|
|
@ -27,3 +27,19 @@ Feature: Admin Projects
|
|||
And I visit admin project page
|
||||
When I transfer project to group 'Web'
|
||||
Then I should see project transfered
|
||||
|
||||
@javascript
|
||||
Scenario: Signed in admin should be able to add himself to a project
|
||||
Given "John Doe" owns private project "Enterprise"
|
||||
When I visit project "Enterprise" members page
|
||||
When I select current user as "Developer"
|
||||
Then I should see current user as "Developer"
|
||||
|
||||
@javascript
|
||||
Scenario: Signed in admin should be able to remove himself from a project
|
||||
Given "John Doe" owns private project "Enterprise"
|
||||
And current user is developer of project "Enterprise"
|
||||
When I visit project "Enterprise" members page
|
||||
Then I should see current user as "Developer"
|
||||
When I click on the "Remove User From Project" button for current user
|
||||
Then I should not see current user as "Developer"
|
||||
|
|
|
@ -31,8 +31,17 @@ Feature: Explore Projects
|
|||
Then I should see empty public project details
|
||||
And I should see empty public project details with http clone info
|
||||
|
||||
Scenario: I visit an empty public project page as user
|
||||
Scenario: I visit an empty public project page as user with no ssh-keys
|
||||
Given I sign in as a user
|
||||
And I have no ssh keys
|
||||
And public empty project "Empty Public Project"
|
||||
When I visit empty project page
|
||||
Then I should see empty public project details
|
||||
And I should see empty public project details with http clone info
|
||||
|
||||
Scenario: I visit an empty public project page as user with an ssh-key
|
||||
Given I sign in as a user
|
||||
And I have an ssh key
|
||||
And public empty project "Empty Public Project"
|
||||
When I visit empty project page
|
||||
Then I should see empty public project details
|
||||
|
@ -57,8 +66,16 @@ Feature: Explore Projects
|
|||
Then I should see project "Community" home page
|
||||
And I should see an http link to the repository
|
||||
|
||||
Scenario: I visit public project page as user
|
||||
Scenario: I visit public project page as user with no ssh-keys
|
||||
Given I sign in as a user
|
||||
And I have no ssh keys
|
||||
When I visit project "Community" page
|
||||
Then I should see project "Community" home page
|
||||
And I should see an http link to the repository
|
||||
|
||||
Scenario: I visit public project page as user with an ssh-key
|
||||
Given I sign in as a user
|
||||
And I have an ssh key
|
||||
When I visit project "Community" page
|
||||
Then I should see project "Community" home page
|
||||
And I should see an ssh link to the repository
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_commits
|
||||
Feature: Project Commits Branches
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_commits
|
||||
Feature: Project Commits Comments
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_commits
|
||||
Feature: Project Commits
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_commits
|
||||
Feature: Project Commits Diff Comments
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_commits
|
||||
Feature: Project Commits Tags
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_commits
|
||||
Feature: Project Commits User Lookup
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -7,6 +7,7 @@ Feature: Project Create
|
|||
Scenario: User create a project
|
||||
Given I sign in as a user
|
||||
When I visit new project page
|
||||
And I have an ssh key
|
||||
And fill project form with valid data
|
||||
Then I should see project page
|
||||
And I should see empty project instuctions
|
||||
|
@ -14,6 +15,7 @@ Feature: Project Create
|
|||
@javascript
|
||||
Scenario: Empty project instructions
|
||||
Given I sign in as a user
|
||||
And I have an ssh key
|
||||
When I visit new project page
|
||||
And fill project form with valid data
|
||||
Then I see empty project instuctions
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_issues
|
||||
Feature: Award Emoji
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_issues
|
||||
Feature: Project Issues Filter Labels
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_issues
|
||||
Feature: Project Issues
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
@ -196,4 +197,3 @@ Feature: Project Issues
|
|||
And I should not see labels field
|
||||
And I submit new issue "500 error on profile"
|
||||
Then I should see issue "500 error on profile"
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_issues
|
||||
Feature: Project Issues Labels
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_issues
|
||||
Feature: Project Issues Milestones
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_merge_requests
|
||||
Feature: Project Merge Requests
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@project_merge_requests
|
||||
Feature: Project Merge Requests Acceptance
|
||||
Background:
|
||||
Given There is an open Merge Request
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class Spinach::Features::AdminGroups < Spinach::FeatureSteps
|
||||
include SharedAuthentication
|
||||
include SharedGroup
|
||||
include SharedPaths
|
||||
include SharedUser
|
||||
include SharedActiveTab
|
||||
|
@ -88,6 +89,34 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
|
|||
end
|
||||
end
|
||||
|
||||
step 'I select current user as "Developer"' do
|
||||
page.within ".users-group-form" do
|
||||
select2(current_user.id, from: "#user_ids", multiple: true)
|
||||
select "Developer", from: "access_level"
|
||||
end
|
||||
|
||||
click_button "Add users to group"
|
||||
end
|
||||
|
||||
step 'I should see current user as "Developer"' do
|
||||
page.within '.content-list' do
|
||||
expect(page).to have_content(current_user.name)
|
||||
expect(page).to have_content('Developer')
|
||||
end
|
||||
end
|
||||
|
||||
step 'I click on the "Remove User From Group" button for current user' do
|
||||
find(:css, 'li', text: current_user.name).find(:css, 'a.btn-remove').click
|
||||
# poltergeist always confirms popups.
|
||||
end
|
||||
|
||||
step 'I should not see current user as "Developer"' do
|
||||
page.within '.content-list' do
|
||||
expect(page).not_to have_content(current_user.name)
|
||||
expect(page).not_to have_content('Developer')
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def current_group
|
||||
|
|
|
@ -3,6 +3,8 @@ class Spinach::Features::AdminProjects < Spinach::FeatureSteps
|
|||
include SharedPaths
|
||||
include SharedAdmin
|
||||
include SharedProject
|
||||
include SharedUser
|
||||
include Select2Helper
|
||||
|
||||
step 'I should see all non-archived projects' do
|
||||
Project.non_archived.each do |p|
|
||||
|
@ -56,6 +58,41 @@ class Spinach::Features::AdminProjects < Spinach::FeatureSteps
|
|||
expect(page).to have_content 'Namespace: Web'
|
||||
end
|
||||
|
||||
step 'I visit project "Enterprise" members page' do
|
||||
project = Project.find_by!(name: "Enterprise")
|
||||
visit namespace_project_project_members_path(project.namespace, project)
|
||||
end
|
||||
|
||||
step 'I select current user as "Developer"' do
|
||||
page.within ".users-project-form" do
|
||||
select2(current_user.id, from: "#user_ids", multiple: true)
|
||||
select "Developer", from: "access_level"
|
||||
end
|
||||
|
||||
click_button "Add users to project"
|
||||
end
|
||||
|
||||
step 'I should see current user as "Developer"' do
|
||||
page.within '.content-list' do
|
||||
expect(page).to have_content(current_user.name)
|
||||
expect(page).to have_content('Developer')
|
||||
end
|
||||
end
|
||||
|
||||
step 'current user is developer of project "Enterprise"' do
|
||||
project = Project.find_by!(name: "Enterprise")
|
||||
project.team << [current_user, :developer]
|
||||
end
|
||||
|
||||
step 'I click on the "Remove User From Project" button for current user' do
|
||||
find(:css, 'li', text: current_user.name).find(:css, 'a.btn-remove').click
|
||||
# poltergeist always confirms popups.
|
||||
end
|
||||
|
||||
step 'I should not see current_user as "Developer"' do
|
||||
expect(page).not_to have_selector(:css, '.content-list')
|
||||
end
|
||||
|
||||
def project
|
||||
@project ||= Project.first
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
|
|||
include SharedAuthentication
|
||||
include SharedPaths
|
||||
include SharedProject
|
||||
include SharedUser
|
||||
|
||||
step 'I should see project "Empty Public Project"' do
|
||||
expect(page).to have_content "Empty Public Project"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
|
||||
include SharedAuthentication
|
||||
include SharedPaths
|
||||
include SharedUser
|
||||
|
||||
step 'fill project form with valid data' do
|
||||
fill_in 'project_path', with: 'Empty'
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
module SharedGroup
|
||||
include Spinach::DSL
|
||||
|
||||
step 'current user is developer of group "Owned"' do
|
||||
is_member_of(current_user.name, "Owned", Gitlab::Access::DEVELOPER)
|
||||
end
|
||||
|
||||
step '"John Doe" is owner of group "Owned"' do
|
||||
is_member_of("John Doe", "Owned", Gitlab::Access::OWNER)
|
||||
end
|
||||
|
|
|
@ -18,4 +18,12 @@ module SharedUser
|
|||
def user_exists(name, options = {})
|
||||
User.find_by(name: name) || create(:user, { name: name, admin: false }.merge(options))
|
||||
end
|
||||
|
||||
step 'I have an ssh key' do
|
||||
create(:personal_key, user: @user)
|
||||
end
|
||||
|
||||
step 'I have no ssh keys' do
|
||||
@user.keys.delete_all
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,6 +19,33 @@ namespace :spec do
|
|||
run_commands(cmds)
|
||||
end
|
||||
|
||||
desc 'GitLab | Rspec | Run model specs'
|
||||
task :models do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(rspec spec --tag @models)
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
|
||||
desc 'GitLab | Rspec | Run service specs'
|
||||
task :services do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(rspec spec --tag @services)
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
|
||||
desc 'GitLab | Rspec | Run lib specs'
|
||||
task :lib do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(rspec spec --tag @lib)
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
|
||||
desc 'GitLab | Rspec | Run benchmark specs'
|
||||
task :benchmark do
|
||||
cmds = [
|
||||
|
@ -32,7 +59,7 @@ namespace :spec do
|
|||
task :other do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(rspec spec --tag ~@api --tag ~@feature --tag ~@benchmark)
|
||||
%W(rspec spec --tag ~@api --tag ~@feature --tag ~@models --tag ~@lib --tag ~@services --tag ~@benchmark)
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
|
|
|
@ -1,11 +1,31 @@
|
|||
Rake::Task["spinach"].clear if Rake::Task.task_defined?('spinach')
|
||||
|
||||
namespace :spinach do
|
||||
namespace :project do
|
||||
desc "GitLab | Spinach | Run project commits, issues and merge requests spinach features"
|
||||
task :half do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(spinach --tags @project_commits,@project_issues,@project_merge_requests),
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
|
||||
desc "GitLab | Spinach | Run remaining project spinach features"
|
||||
task :rest do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets,~@project_commits,~@project_issues,~@project_merge_requests),
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
end
|
||||
|
||||
desc "GitLab | Spinach | Run project spinach features"
|
||||
task :project do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets,~@commits),
|
||||
%W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets),
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
|
@ -14,7 +34,7 @@ namespace :spinach do
|
|||
task :other do
|
||||
cmds = [
|
||||
%W(rake gitlab:setup),
|
||||
%W(spinach --tags @admin,@dashboard,@profile,@public,@snippets,@commits),
|
||||
%W(spinach --tags @admin,@dashboard,@profile,@public,@snippets),
|
||||
]
|
||||
run_commands(cmds)
|
||||
end
|
||||
|
@ -33,4 +53,4 @@ def run_commands(cmds)
|
|||
cmds.each do |cmd|
|
||||
system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
0
shared/lfs-objects/.gitkeep
Normal file
0
shared/lfs-objects/.gitkeep
Normal file
|
@ -79,6 +79,6 @@ describe "User Feed", feature: true do
|
|||
end
|
||||
|
||||
def safe_name
|
||||
html_escape(user.name)
|
||||
CGI.escapeHTML(user.name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Ci::Ansi2html do
|
||||
describe Ci::Ansi2html, lib: true do
|
||||
subject { Ci::Ansi2html }
|
||||
|
||||
it "prints non-ansi as-is" do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Charts" do
|
||||
describe Ci::Charts, lib: true do
|
||||
|
||||
context "build_times" do
|
||||
before do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Ci
|
||||
describe GitlabCiYamlProcessor do
|
||||
describe GitlabCiYamlProcessor, lib: true do
|
||||
let(:path) { 'path' }
|
||||
|
||||
describe "#builds_for_ref" do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe DisableEmailInterceptor do
|
||||
describe DisableEmailInterceptor, lib: true do
|
||||
before do
|
||||
ActionMailer::Base.register_interceptor(DisableEmailInterceptor)
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ExtractsPath do
|
||||
describe ExtractsPath, lib: true do
|
||||
include ExtractsPath
|
||||
include RepoHelpers
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Gitlab::FileSizeValidatorSpec' do
|
||||
describe FileSizeValidator, lib: true do
|
||||
let(:validator) { FileSizeValidator.new(options) }
|
||||
let(:attachment) { AttachmentUploader.new }
|
||||
let(:note) { create(:note) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitRefValidator do
|
||||
describe Gitlab::GitRefValidator, lib: true do
|
||||
it { expect(Gitlab::GitRefValidator.validate('feature/new')).to be_truthy }
|
||||
it { expect(Gitlab::GitRefValidator.validate('implement_@all')).to be_truthy }
|
||||
it { expect(Gitlab::GitRefValidator.validate('my_new_feature')).to be_truthy }
|
||||
|
|
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
|||
require 'nokogiri'
|
||||
|
||||
module Gitlab
|
||||
describe Asciidoc do
|
||||
describe Asciidoc, lib: true do
|
||||
|
||||
let(:input) { '<b>ascii</b>' }
|
||||
let(:context) { {} }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Auth do
|
||||
describe Gitlab::Auth, lib: true do
|
||||
let(:gl_auth) { Gitlab::Auth.new }
|
||||
|
||||
describe :find do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Grack::Auth do
|
||||
describe Grack::Auth, lib: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Shell do
|
||||
describe Gitlab::Shell, lib: true do
|
||||
let(:project) { double('Project', id: 7, path: 'diaspora') }
|
||||
let(:gitlab_shell) { Gitlab::Shell.new }
|
||||
|
||||
|
@ -16,7 +16,7 @@ describe Gitlab::Shell do
|
|||
|
||||
it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") }
|
||||
|
||||
describe Gitlab::Shell::KeyAdder do
|
||||
describe Gitlab::Shell::KeyAdder, lib: true do
|
||||
describe '#add_key' do
|
||||
it 'normalizes space characters in the key' do
|
||||
io = spy
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::BitbucketImport::Client do
|
||||
describe Gitlab::BitbucketImport::Client, lib: true do
|
||||
let(:token) { '123456' }
|
||||
let(:secret) { 'secret' }
|
||||
let(:client) { Gitlab::BitbucketImport::Client.new(token, secret) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::BitbucketImport::ProjectCreator do
|
||||
describe Gitlab::BitbucketImport::ProjectCreator, lib: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:repo) do
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::ClosingIssueExtractor do
|
||||
describe Gitlab::ClosingIssueExtractor, lib: true do
|
||||
let(:project) { create(:project) }
|
||||
let(:project2) { create(:project) }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::ColorSchemes do
|
||||
describe Gitlab::ColorSchemes, lib: true do
|
||||
describe '.body_classes' do
|
||||
it 'returns a space-separated list of class names' do
|
||||
css = described_class.body_classes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Database do
|
||||
describe Gitlab::Database, lib: true do
|
||||
# These are just simple smoke tests to check if the methods work (regardless
|
||||
# of what they may return).
|
||||
describe '.mysql?' do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Diff::File do
|
||||
describe Gitlab::Diff::File, lib: true do
|
||||
include RepoHelpers
|
||||
|
||||
let(:project) { create(:project) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Diff::Parser do
|
||||
describe Gitlab::Diff::Parser, lib: true do
|
||||
include RepoHelpers
|
||||
|
||||
let(:project) { create(:project) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Gitlab::Email::AttachmentUploader do
|
||||
describe Gitlab::Email::AttachmentUploader, lib: true do
|
||||
describe "#execute" do
|
||||
let(:project) { build(:project) }
|
||||
let(:message_raw) { fixture_file("emails/attachment.eml") }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Gitlab::Email::Receiver do
|
||||
describe Gitlab::Email::Receiver, lib: true do
|
||||
before do
|
||||
stub_incoming_email_setting(enabled: true, address: "reply+%{key}@appmail.adventuretime.ooo")
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require "spec_helper"
|
||||
|
||||
# Inspired in great part by Discourse's Email::Receiver
|
||||
describe Gitlab::Email::ReplyParser do
|
||||
describe Gitlab::Email::ReplyParser, lib: true do
|
||||
describe '#execute' do
|
||||
def test_parse_body(mail_string)
|
||||
described_class.new(Mail::Message.new(mail_string)).execute
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitAccess do
|
||||
describe Gitlab::GitAccess, lib: true do
|
||||
let(:access) { Gitlab::GitAccess.new(actor, project) }
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { create(:user) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitAccessWiki do
|
||||
describe Gitlab::GitAccessWiki, lib: true do
|
||||
let(:access) { Gitlab::GitAccessWiki.new(user, project) }
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { create(:user) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GithubImport::Client do
|
||||
describe Gitlab::GithubImport::Client, lib: true do
|
||||
let(:token) { '123456' }
|
||||
let(:client) { Gitlab::GithubImport::Client.new(token) }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GithubImport::ProjectCreator do
|
||||
describe Gitlab::GithubImport::ProjectCreator, lib: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:repo) do
|
||||
OpenStruct.new(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitlabImport::Client do
|
||||
describe Gitlab::GitlabImport::Client, lib: true do
|
||||
let(:token) { '123456' }
|
||||
let(:client) { Gitlab::GitlabImport::Client.new(token) }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitlabImport::ProjectCreator do
|
||||
describe Gitlab::GitlabImport::ProjectCreator, lib: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:repo) do
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitoriousImport::ProjectCreator do
|
||||
describe Gitlab::GitoriousImport::ProjectCreator, lib: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:repo) { Gitlab::GitoriousImport::Repository.new('foo/bar-baz-qux') }
|
||||
let(:namespace){ create(:group, owner: user) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Gitlab::GoogleCodeImport::Client do
|
||||
describe Gitlab::GoogleCodeImport::Client, lib: true do
|
||||
let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) }
|
||||
subject { described_class.new(raw_data) }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Gitlab::GoogleCodeImport::Importer do
|
||||
describe Gitlab::GoogleCodeImport::Importer, lib: true do
|
||||
let(:mapped_user) { create(:user, username: "thilo123") }
|
||||
let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) }
|
||||
let(:client) { Gitlab::GoogleCodeImport::Client.new(raw_data) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GoogleCodeImport::ProjectCreator do
|
||||
describe Gitlab::GoogleCodeImport::ProjectCreator, lib: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:repo) do
|
||||
Gitlab::GoogleCodeImport::Repository.new(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Gitlab::IncomingEmail do
|
||||
describe Gitlab::IncomingEmail, lib: true do
|
||||
describe "self.enabled?" do
|
||||
context "when reply by email is enabled" do
|
||||
before do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::InlineDiff do
|
||||
describe Gitlab::InlineDiff, lib: true do
|
||||
describe '#processing' do
|
||||
let(:diff) do
|
||||
<<eos
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe Gitlab::KeyFingerprint do
|
||||
describe Gitlab::KeyFingerprint, lib: true do
|
||||
let(:key) { "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" }
|
||||
let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::LDAP::Access do
|
||||
describe Gitlab::LDAP::Access, lib: true do
|
||||
let(:access) { Gitlab::LDAP::Access.new user }
|
||||
let(:user) { create(:omniauth_user) }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::LDAP::Adapter do
|
||||
describe Gitlab::LDAP::Adapter, lib: true do
|
||||
let(:adapter) { Gitlab::LDAP::Adapter.new 'ldapmain' }
|
||||
|
||||
describe '#dn_matches_filter?' do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::LDAP::AuthHash do
|
||||
describe Gitlab::LDAP::AuthHash, lib: true do
|
||||
let(:auth_hash) do
|
||||
Gitlab::LDAP::AuthHash.new(
|
||||
OmniAuth::AuthHash.new(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::LDAP::Authentication do
|
||||
describe Gitlab::LDAP::Authentication, lib: true do
|
||||
let(:user) { create(:omniauth_user, extern_uid: dn) }
|
||||
let(:dn) { 'uid=john,ou=people,dc=example,dc=com' }
|
||||
let(:login) { 'john' }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::LDAP::Config do
|
||||
describe Gitlab::LDAP::Config, lib: true do
|
||||
let(:config) { Gitlab::LDAP::Config.new provider }
|
||||
let(:provider) { 'ldapmain' }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::LDAP::User do
|
||||
describe Gitlab::LDAP::User, lib: true do
|
||||
let(:ldap_user) { Gitlab::LDAP::User.new(auth_hash) }
|
||||
let(:gl_user) { ldap_user.gl_user }
|
||||
let(:info) do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Lfs::Router do
|
||||
describe Gitlab::Lfs::Router, lib: true do
|
||||
let(:project) { create(:project) }
|
||||
let(:public_project) { create(:project, :public) }
|
||||
let(:forked_project) { fork_project(public_project, user) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe AutolinkFilter do
|
||||
describe AutolinkFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:link) { 'http://about.gitlab.com/' }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe CommitRangeReferenceFilter do
|
||||
describe CommitRangeReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:project, :public) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe CommitReferenceFilter do
|
||||
describe CommitReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:project, :public) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe CrossProjectReference do
|
||||
describe CrossProjectReference, lib: true do
|
||||
include described_class
|
||||
|
||||
describe '#project_from_ref' do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe EmojiFilter do
|
||||
describe EmojiFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
before do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe ExternalIssueReferenceFilter do
|
||||
describe ExternalIssueReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
def helper
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe ExternalLinkFilter do
|
||||
describe ExternalLinkFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
it 'ignores elements without an href attribute' do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe IssueReferenceFilter do
|
||||
describe IssueReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
def helper
|
||||
|
|
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
|||
require 'html/pipeline'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe LabelReferenceFilter do
|
||||
describe LabelReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:empty_project, :public) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe MergeRequestReferenceFilter do
|
||||
describe MergeRequestReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:project, :public) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe RedactorFilter do
|
||||
describe RedactorFilter, lib: true do
|
||||
include ActionView::Helpers::UrlHelper
|
||||
include FilterSpecHelper
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe ReferenceGathererFilter do
|
||||
describe ReferenceGathererFilter, lib: true do
|
||||
include ActionView::Helpers::UrlHelper
|
||||
include FilterSpecHelper
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe RelativeLinkFilter do
|
||||
describe RelativeLinkFilter, lib: true do
|
||||
def filter(doc, contexts = {})
|
||||
contexts.reverse_merge!({
|
||||
commit: project.commit,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe SanitizationFilter do
|
||||
describe SanitizationFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
describe 'default whitelist' do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe SnippetReferenceFilter do
|
||||
describe SnippetReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:empty_project, :public) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe SyntaxHighlightFilter do
|
||||
describe SyntaxHighlightFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
it 'highlights valid code blocks' do
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe TableOfContentsFilter do
|
||||
describe TableOfContentsFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
def header(level, text)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe TaskListFilter do
|
||||
describe TaskListFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
it 'does not apply `task-list` class to non-task lists' do
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe UploadLinkFilter do
|
||||
describe UploadLinkFilter, lib: true do
|
||||
def filter(doc, contexts = {})
|
||||
contexts.reverse_merge!({
|
||||
project: project
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Gitlab::Markdown
|
||||
describe UserReferenceFilter do
|
||||
describe UserReferenceFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:empty_project, :public) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::MarkupHelper do
|
||||
describe Gitlab::MarkupHelper, lib: true do
|
||||
describe '#markup?' do
|
||||
%w(textile rdoc org creole wiki
|
||||
mediawiki rst adoc ad asciidoc mdown md markdown).each do |type|
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue