Commit f5abc9f6 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into ce_upstream

parents b99e3ca2 b5b4054d
<<<<<<< HEAD
5.1.0
=======
5.1.1
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
import autosize from 'vendor/autosize';
$(() => {
const $fields = $('.js-autosize');
document.addEventListener('DOMContentLoaded', () => {
const autosizeEls = document.querySelectorAll('.js-autosize');
$fields.on('autosize:resized', function resized() {
const $field = $(this);
$field.data('height', $field.outerHeight());
});
$fields.on('resize.autosize', function resize() {
const $field = $(this);
if ($field.data('height') !== $field.outerHeight()) {
$field.data('height', $field.outerHeight());
autosize.destroy($field);
$field.css('max-height', window.outerHeight);
}
});
autosize($fields);
autosize.update($fields);
$fields.css('resize', 'vertical');
autosize(autosizeEls);
autosize.update(autosizeEls);
});
......@@ -33,3 +33,20 @@
font-weight: normal;
}
}
.admin-runner-btn-group-cell {
min-width: 150px;
.btn-sm {
padding: 4px 9px;
}
.btn-default {
color: $gl-text-color-secondary;
}
.fa-pause,
.fa-play {
font-size: 11px;
}
}
......@@ -5,7 +5,7 @@ module Ci
belongs_to :project
validates :key, uniqueness: { scope: :project_id }
validates :key, uniqueness: { scope: [:project_id, :environment_scope] }
scope :unprotected, -> { where(protected: false) }
end
......
......@@ -103,8 +103,12 @@ module Routable
def full_path
return uncached_full_path unless RequestStore.active?
key = "routable/full_path/#{self.class.name}/#{self.id}"
RequestStore[key] ||= uncached_full_path
RequestStore[full_path_key] ||= uncached_full_path
end
def expires_full_path_cache
RequestStore.delete(full_path_key) if RequestStore.active?
@full_path = nil
end
def build_full_path
......@@ -135,6 +139,10 @@ module Routable
path_changed? || parent_changed?
end
def full_path_key
@full_path_key ||= "routable/full_path/#{self.class.name}/#{self.id}"
end
def build_full_name
if parent && name
parent.human_name + ' / ' + name
......
......@@ -964,6 +964,7 @@ class Project < ActiveRecord::Base
begin
gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
send_move_instructions(old_path_with_namespace)
expires_full_path_cache
@old_path_with_namespace = old_path_with_namespace
......@@ -1074,21 +1075,21 @@ class Project < ActiveRecord::Base
merge_requests.where(source_project_id: self.id)
end
def create_repository
def create_repository(force: false)
# Forked import is handled asynchronously
unless forked?
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
repository.after_create
true
else
errors.add(:base, 'Failed to create repository via gitlab-shell')
false
end
return if forked? && !force
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
repository.after_create
true
else
errors.add(:base, 'Failed to create repository via gitlab-shell')
false
end
end
def ensure_repository
create_repository unless repository_exists?
create_repository(force: true) unless repository_exists?
end
def repository_exists?
......
......@@ -78,6 +78,7 @@ module Projects
Gitlab::PagesTransfer.new.move_project(project.path, @old_namespace.full_path, @new_namespace.full_path)
project.old_path_with_namespace = @old_path
project.expires_full_path_cache
execute_system_hooks
end
......
......@@ -32,13 +32,16 @@
#{time_ago_in_words(runner.contacted_at)} ago
- else
Never
%td
.pull-right
= link_to 'Edit', admin_runner_path(runner), class: 'btn btn-sm'
%td.admin-runner-btn-group-cell
.pull-right.btn-group
= link_to admin_runner_path(runner), class: 'btn btn-sm btn-default has-tooltip', title: 'Edit', ref: 'tooltip', aria: { label: 'Edit' }, data: { placement: 'top', container: 'body'} do
= icon('pencil')
&nbsp;
- if runner.active?
= link_to 'Pause', [:pause, :admin, runner], data: { confirm: "Are you sure?" }, method: :get, class: 'btn btn-danger btn-sm'
= link_to [:pause, :admin, runner], method: :get, class: 'btn btn-sm btn-default has-tooltip', title: 'Pause', ref: 'tooltip', aria: { label: 'Pause' }, data: { placement: 'top', container: 'body', confirm: "Are you sure?" } do
= icon('pause')
- else
= link_to 'Resume', [:resume, :admin, runner], method: :get, class: 'btn btn-success btn-sm'
= link_to 'Remove', [:admin, runner], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
= link_to [:resume, :admin, runner], method: :get, class: 'btn btn-default btn-sm has-tooltip', title: 'Resume', ref: 'tooltip', aria: { label: 'Resume' }, data: { placement: 'top', container: 'body'} do
= icon('play')
= link_to [:admin, runner], method: :delete, class: 'btn btn-danger btn-sm has-tooltip', title: 'Remove', ref: 'tooltip', aria: { label: 'Remove' }, data: { placement: 'top', container: 'body', confirm: "Are you sure?" } do
= icon('remove')
......@@ -25,7 +25,7 @@
%div
- if Gitlab::Recaptcha.enabled?
= recaptcha_tags
%div
.submit-container
= f.submit "Register", class: "btn-register btn"
.clearfix.submit-container
%p
......
......@@ -7,10 +7,9 @@
.form-group
.col-sm-10.col-sm-offset-2
.checkbox
- initial_checkbox_value = issuable.merge_params.key?('force_remove_source_branch') ? issuable.force_remove_source_branch? : true
= label_tag 'merge_request[force_remove_source_branch]' do
= hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil
= check_box_tag 'merge_request[force_remove_source_branch]', '1', initial_checkbox_value
= check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch?
Remove source branch when merge request is accepted.
= render 'shared/issuable/form/ee/squash_merge_param', issuable: issuable
---
title: Fix spacing on runner buttons.
merge_request: !12535
author:
---
title: Set default for Remove source branch to false.
merge_request: !12576
author:
---
title: Rename duplicated variables with the same key for projects. Add environment_scope
column to variables and add unique constraint to make sure that no variables could
be created with the same key within a project
merge_request: 12363
author:
---
title: Expires full_path cache after a repository is renamed/transferred
merge_request:
author:
---
title: Make Project#ensure_repository force create a repo
merge_request:
author:
class RenameDuplicatedVariableKey < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
execute(<<~SQL)
UPDATE ci_variables
SET #{key} = CONCAT(#{key}, #{underscore}, id)
WHERE id IN (
SELECT *
FROM ( -- MySQL requires an extra layer
SELECT dup.id
FROM ci_variables dup
INNER JOIN (SELECT max(id) AS id, #{key}, project_id
FROM ci_variables tmp
GROUP BY #{key}, project_id) var
USING (#{key}, project_id) where dup.id <> var.id
) dummy
)
SQL
end
def down
# noop
end
def key
# key needs to be quoted in MySQL
quote_column_name('key')
end
def underscore
quote('_')
end
end
class AddEnvironmentScopeToCiVariables < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:ci_variables, :environment_scope, :string, default: '*')
end
def down
remove_column(:ci_variables, :environment_scope)
end
end
class AddUniqueConstraintToCiVariables < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
unless this_index_exists?
add_concurrent_index(:ci_variables, columns, name: index_name, unique: true)
end
end
def down
if this_index_exists?
if Gitlab::Database.mysql? && !index_exists?(:ci_variables, :project_id)
# Need to add this index for MySQL project_id foreign key constraint
add_concurrent_index(:ci_variables, :project_id)
end
remove_concurrent_index(:ci_variables, columns, name: index_name)
end
end
private
def this_index_exists?
index_exists?(:ci_variables, columns, name: index_name)
end
def columns
@columns ||= [:project_id, :key, :environment_scope]
end
def index_name
'index_ci_variables_on_project_id_and_key_and_environment_scope'
end
end
class RemoveCiVariablesProjectIdIndex < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
if index_exists?(:ci_variables, :project_id)
remove_concurrent_index(:ci_variables, :project_id)
end
end
def down
unless index_exists?(:ci_variables, :project_id)
add_concurrent_index(:ci_variables, :project_id)
end
end
end
......@@ -11,7 +11,11 @@
#
# It's strongly recommended that you check this file into your version control system.
<<<<<<< HEAD
ActiveRecord::Schema.define(version: 20170627211700) do
=======
ActiveRecord::Schema.define(version: 20170623080805) do
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -442,9 +446,10 @@ ActiveRecord::Schema.define(version: 20170627211700) do
t.string "encrypted_value_iv"
t.integer "project_id", null: false
t.boolean "protected", default: false, null: false
t.string "environment_scope", default: "*", null: false
end
add_index "ci_variables", ["project_id"], name: "index_ci_variables_on_project_id", using: :btree
add_index "ci_variables", ["project_id", "key", "environment_scope"], name: "index_ci_variables_on_project_id_and_key_and_environment_scope", unique: true, using: :btree
create_table "container_repositories", force: :cascade do |t|
t.integer "project_id", null: false
......
......@@ -31,7 +31,11 @@ You create issues, host code, perform reviews, build, test,
and deploy from one single platform. Issue Boards help you to visualize
and manage the entire process _in_ GitLab.
<<<<<<< HEAD
With [Multiple Issue Boards](#multiple-issue-boards), available
=======
With [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards), available
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
only in [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/),
you go even further, as you can not only keep yourself and your project
organized from a broader perspective with one Issue Board per project,
......@@ -40,10 +44,13 @@ multiple Issue Boards within the same project.
## Use cases
<<<<<<< HEAD
You can see below a few different use cases for GitLab's Issue Boards.
### Use cases for a single Issue Board
=======
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
GitLab Workflow allows you to discuss proposals in issues, categorize them
with labels, and from there organize and prioritize them with Issue Boards.
......@@ -67,6 +74,7 @@ beginning of the development lifecycle until deployed to production
![issue card moving](img/issue_board_move_issue_card_list.png)
<<<<<<< HEAD
### Use cases for Multiple Issue Boards
With [Multiple Issue Boards](#multiple-issue-boards), available only in
......@@ -101,6 +109,8 @@ When done with something, they move the card to **Frontend**. The Frontend team'
Cards finished by the UX team will automatically appear in the **Frontend** column when they're ready for them.
=======
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
> **Notes:**
>
>- For a broader use case, please check the blog post
......@@ -108,8 +118,12 @@ Cards finished by the UX team will automatically appear in the **Frontend** colu
>
>- For a real use case, please check why
[Codepen decided to adopt Issue Boards](https://about.gitlab.com/2017/01/27/codepen-welcome-to-gitlab/#project-management-everything-in-one-place)
<<<<<<< HEAD
to improve their workflow with
multiple boards.
=======
to improve their workflow with [multiple boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards).
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
## Issue Board terminology
......
......@@ -2,6 +2,8 @@ require 'securerandom'
module Gitlab
class Shell
GITLAB_SHELL_ENV_VARS = %w(GIT_TERMINAL_PROMPT).freeze
Error = Class.new(StandardError)
KeyAdder = Struct.new(:io) do
......@@ -67,8 +69,8 @@ module Gitlab
# add_repository("/path/to/storage", "gitlab/gitlab-ci")
#
def add_repository(storage, name)
Gitlab::Utils.system_silent([gitlab_shell_projects_path,
'add-project', storage, "#{name}.git"])
gitlab_shell_fast_execute([gitlab_shell_projects_path,
'add-project', storage, "#{name}.git"])
end
# Import repository
......@@ -82,10 +84,9 @@ module Gitlab
def import_repository(storage, name, url)
# Timeout should be less than 900 ideally, to prevent the memory killer
# to silently kill the process without knowing we are timing out here.
output, status = Popen.popen([gitlab_shell_projects_path, 'import-project',
storage, "#{name}.git", url, "#{Gitlab.config.gitlab_shell.git_timeout}"])
raise Error, output unless status.zero?
true
cmd = [gitlab_shell_projects_path, 'import-project',
storage, "#{name}.git", url, "#{Gitlab.config.gitlab_shell.git_timeout}"]
gitlab_shell_fast_execute_raise_error(cmd)
end
def list_remote_tags(storage, name, remote)
......@@ -131,9 +132,7 @@ module Gitlab
args << '--force' if forced
args << '--no-tags' if no_tags
output, status = Popen.popen(args)
raise Error, output unless status.zero?
true
gitlab_shell_fast_execute_raise_error(args)
end
# Move repository
......@@ -145,8 +144,8 @@ module Gitlab
# mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new")
#
def mv_repository(storage, path, new_path)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'mv-project',
storage, "#{path}.git", "#{new_path}.git"])
gitlab_shell_fast_execute([gitlab_shell_projects_path, 'mv-project',
storage, "#{path}.git", "#{new_path}.git"])
end
# Move repository storage
......@@ -173,9 +172,9 @@ module Gitlab
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx")
#
def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project',
forked_from_storage, "#{path}.git", forked_to_storage,
fork_namespace])
gitlab_shell_fast_execute([gitlab_shell_projects_path, 'fork-project',
forked_from_storage, "#{path}.git", forked_to_storage,
fork_namespace])
end
# Remove repository from file system
......@@ -187,8 +186,8 @@ module Gitlab
# remove_repository("/path/to/storage", "gitlab/gitlab-ci")
#
def remove_repository(storage, name)
Gitlab::Utils.system_silent([gitlab_shell_projects_path,
'rm-project', storage, "#{name}.git"])
gitlab_shell_fast_execute([gitlab_shell_projects_path,
'rm-project', storage, "#{name}.git"])
end
# Add new key to gitlab-shell
......@@ -197,10 +196,15 @@ module Gitlab
# add_key("key-42", "sha-rsa ...")
#
def add_key(key_id, key_content)
<<<<<<< HEAD
return unless self.authorized_keys_enabled?
Gitlab::Utils.system_silent([gitlab_shell_keys_path,
'add-key', key_id, self.class.strip_key(key_content)])
=======
gitlab_shell_fast_execute([gitlab_shell_keys_path,
'add-key', key_id, self.class.strip_key(key_content)])
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
end
# Batch-add keys to authorized_keys
......@@ -220,12 +224,20 @@ module Gitlab
# Ex.
# remove_key("key-342", "sha-rsa ...")
#
<<<<<<< HEAD
def remove_key(key_id, key_content = nil)
return unless self.authorized_keys_enabled?
args = [gitlab_shell_keys_path, 'rm-key', key_id]
args << key_content if key_content
Gitlab::Utils.system_silent(args)
=======
def remove_key(key_id, key_content)
args = [gitlab_shell_keys_path, 'rm-key', key_id]
args << key_content if key_content
gitlab_shell_fast_execute(args)
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
end
# Remove all ssh keys from gitlab shell
......@@ -234,9 +246,13 @@ module Gitlab
# remove_all_keys
#
def remove_all_keys
<<<<<<< HEAD
return unless self.authorized_keys_enabled?
Gitlab::Utils.system_silent([gitlab_shell_keys_path, 'clear'])
=======
gitlab_shell_fast_execute([gitlab_shell_keys_path, 'clear'])
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
end
# Remove ssh keys from gitlab shell that are not in the DB
......@@ -417,12 +433,39 @@ module Gitlab
File.join(gitlab_shell_path, 'bin', 'gitlab-keys')
end
<<<<<<< HEAD
def authorized_keys_enabled?
# Return true if nil to ensure the authorized_keys methods work while
# fixing the authorized_keys file during migration.
return true if current_application_settings.authorized_keys_enabled.nil?
current_application_settings.authorized_keys_enabled
=======
private
def gitlab_shell_fast_execute(cmd)
output, status = gitlab_shell_fast_execute_helper(cmd)
return true if status.zero?
Rails.logger.error("gitlab-shell failed with error #{status}: #{output}")
false
end
def gitlab_shell_fast_execute_raise_error(cmd)
output, status = gitlab_shell_fast_execute_helper(cmd)
raise Error, output unless status.zero?
true
end
def gitlab_shell_fast_execute_helper(cmd)
vars = ENV.to_h.slice(*GITLAB_SHELL_ENV_VARS)
# Don't pass along the entire parent environment to prevent gitlab-shell
# from wasting I/O by searching through GEM_PATH
Bundler.with_original_env { Popen.popen(cmd, nil, vars) }
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
end
end
end
......@@ -32,6 +32,17 @@ describe 'Gitlab::Popen', lib: true, no_db: true do
end
end
context 'with custom options' do
let(:vars) { { 'foobar' => 123, 'PWD' => path } }
let(:options) { { chdir: path } }
it 'calls popen3 with the provided environment variables' do
expect(Open3).to receive(:popen3).with(vars, 'ls', options)
@output, @status = @klass.new.popen(%w(ls), path, { 'foobar' => 123 })
end
end
context 'without a directory argument' do
before do
@output, @status = @klass.new.popen(%w(ls))
......@@ -45,7 +56,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do
before do
@output, @status = @klass.new.popen(%w[cat]) { |stdin| stdin.write 'hello' }
end
it { expect(@status).to be_zero }
it { expect(@output).to eq('hello') }
end
......
......@@ -4,6 +4,7 @@ require 'stringio'
describe Gitlab::Shell, lib: true do
let(:project) { double('Project', id: 7, path: 'diaspora') }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } }
before do
allow(Project).to receive(:find).and_return(project)
......@@ -104,6 +105,7 @@ describe Gitlab::Shell, lib: true do
end
describe '#add_key' do
<<<<<<< HEAD
context 'when authorized_keys_enabled is true' do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
......@@ -167,6 +169,13 @@ describe Gitlab::Shell, lib: true do
end
end
end
=======
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
)
>>>>>>> b5b4054d5882782892d0a860c7e95db9a22bfdec
context 'when authorized_keys_enabled is nil' do
before do
......@@ -448,17 +457,91 @@ describe Gitlab::Shell, lib: true do
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
end
describe '#add_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'add-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be true
end
it 'returns false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'add-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be false
end
end
describe '#remove_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be true
end
it 'returns false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be false
end
end
describe '#mv_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be true
end
it 'returns false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be false
end
end
describe '#fork_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be true
end
it 'return false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be false
end
end
describe '#fetch_remote' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800']).and_return([nil, 0])
.with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage')).to be true
end
it 'raises an exception when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800']).and_return(["error", 1])
.with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'],
nil, popen_vars).and_return(["error", 1])
expect { gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage') }.to raise_error(Gitlab::Shell::Error, "error")
end
......@@ -467,14 +550,16 @@ describe Gitlab::Shell, lib: true do
describe '#import_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"]).and_return([nil, 0])
.with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git')).to be true
end
it 'raises an exception when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"]).and_return(["error", 1])
.with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
nil, popen_vars).and_return(["error", 1])
expect { gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git') }.to raise_error(Gitlab::Shell::Error, "error")
end
......
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20170622135451_rename_duplicated_variable_key.rb')
describe RenameDuplicatedVariableKey, :migration do
let(:variables) { table(:ci_variables) }
let(:projects) { table(:projects) }
before do
projects.create!(id: 1)
variables.create!(id: 1, key: 'key1', project_id: 1)
variables.create!(id: 2, key: 'key2', project_id: 1)
variables.create!(id: 3, key: 'keyX', project_id: 1)
variables.create!(id: 4, key: 'keyX', project_id: 1)
variables.create!(id: 5, key: 'keyY', project_id: 1)
variables.create!(id: 6, key: 'keyX', project_id: 1)
variables.create!(id: 7, key: 'key7', project_id: 1)
variables.create!(id: 8, key: 'keyY', project_id: 1)
end
it 'correctly remove duplicated records with smaller id' do
migrate!
expect(variables.pluck(:id, :key)).to contain_exactly(
[1, 'key1'],
[2, 'key2'],
[3, 'keyX_3'],
[4, 'keyX_4'],
[5, 'keyY_5'],
[6, 'keyX'],
[7, 'key7'],
[8, 'keyY']
)
end
end
......@@ -3,8 +3,16 @@ require 'spec_helper'
describe Ci::Variable, models: true do
subject { build(:ci_variable) }
it { is_expected.to include_module(HasVariable) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id) }
let(:secret_value) { 'secret' }
describe 'validations' do
it { is_expected.to include_module(HasVariable) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope) }
it { is_expected.to validate_length_of(:key).is_at_most(255) }
it { is_expected.to allow_value('foo').for(:key) }
it { is_expected.not_to allow_value('foo bar').for(:key) }
it { is_expected.not_to allow_value('foo/bar').for(:key) }
end
describe '.unprotected' do
subject { described_class.unprotected }
......
......@@ -142,6 +142,19 @@ describe Group, 'Routable' do
end
end
describe '#expires_full_path_cache' do
context 'with RequestStore active', :request_store do
it 'expires the full_path cache' do
expect(group.full_path).to eq('foo')
group.route.update(path: 'bar', name: 'bar')
group.expires_full_path_cache
expect(group.full_path).to eq('bar')
end
end
end
describe '#full_name' do
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
......
......@@ -1458,6 +1458,8 @@ describe Project, models: true do
expect(project).to receive(:expire_caches_before_rename)
expect(project).to receive(:expires_full_path_cache)
project.rename_repo
end
......@@ -1586,7 +1588,7 @@ describe Project, models: true do
.with(project.repository_storage_path, project.path_with_namespace)
.and_return(true)
expect(project).to receive(:create_repository)
expect(project).to receive(:create_repository).with(force: true)
project.ensure_repository
end
......@@ -1599,6 +1601,19 @@ describe Project, models: true do
project.ensure_repository
end
it 'creates the repository if it is a fork' do
expect(project).to receive(:forked?).and_return(true)
allow(project).to receive(:repository_exists?)
.and_return(false)
expect(shell).to receive(:add_repository)
.with(project.repository_storage_path, project.path_with_namespace)
.and_return(true)
project.ensure_repository
end
end
describe 'handling import URL' do
......
......@@ -30,6 +30,12 @@ describe Projects::TransferService, services: true do
transfer_project(project, user, group)
end
it 'expires full_path cache' do
expect(project).to receive(:expires_full_path_cache)
transfer_project(project, user, group)
end
it 'executes system hooks' do
expect_any_instance_of(Projects::TransferService).to receive(:execute_system_hooks)
......
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