Merge branch 'master' into 'fix/gb/improve-stage-id-foreign-key-migration'
# Conflicts: # db/schema.rb
This commit is contained in:
commit
f5641dcf7d
29 changed files with 383 additions and 72 deletions
|
@ -2,6 +2,10 @@
|
||||||
documentation](doc/development/changelog.md) for instructions on adding your own
|
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||||
entry.
|
entry.
|
||||||
|
|
||||||
|
## 9.3.4 (2017-07-03)
|
||||||
|
|
||||||
|
- No changes.
|
||||||
|
|
||||||
## 9.3.3 (2017-06-30)
|
## 9.3.3 (2017-06-30)
|
||||||
|
|
||||||
- Fix head pipeline stored in merge request for external pipelines. !12478
|
- Fix head pipeline stored in merge request for external pipelines. !12478
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
5.0.6
|
5.1.1
|
||||||
|
|
|
@ -1,23 +1,8 @@
|
||||||
import autosize from 'vendor/autosize';
|
import autosize from 'vendor/autosize';
|
||||||
|
|
||||||
$(() => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const $fields = $('.js-autosize');
|
const autosizeEls = document.querySelectorAll('.js-autosize');
|
||||||
|
|
||||||
$fields.on('autosize:resized', function resized() {
|
autosize(autosizeEls);
|
||||||
const $field = $(this);
|
autosize.update(autosizeEls);
|
||||||
$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');
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
}
|
}
|
||||||
this.data = query.result[0].values;
|
this.data = query.result[0].values;
|
||||||
this.unitOfDisplay = query.unit || 'N/A';
|
this.unitOfDisplay = query.unit || 'N/A';
|
||||||
this.yAxisLabel = this.columnData.y_axis || 'Values';
|
this.yAxisLabel = this.columnData.y_label || 'Values';
|
||||||
this.legendTitle = query.legend || 'Average';
|
this.legendTitle = query.legend || 'Average';
|
||||||
this.graphWidth = this.$refs.baseSvg.clientWidth -
|
this.graphWidth = this.$refs.baseSvg.clientWidth -
|
||||||
this.margin.left - this.margin.right;
|
this.margin.left - this.margin.right;
|
||||||
|
|
|
@ -83,7 +83,12 @@ class LabelsFinder < UnionFinder
|
||||||
def projects
|
def projects
|
||||||
return @projects if defined?(@projects)
|
return @projects if defined?(@projects)
|
||||||
|
|
||||||
@projects = skip_authorization ? Project.all : ProjectsFinder.new(current_user: current_user).execute
|
@projects = if skip_authorization
|
||||||
|
Project.all
|
||||||
|
else
|
||||||
|
ProjectsFinder.new(params: { non_archived: true }, current_user: current_user).execute
|
||||||
|
end
|
||||||
|
|
||||||
@projects = @projects.in_namespace(params[:group_id]) if group?
|
@projects = @projects.in_namespace(params[:group_id]) if group?
|
||||||
@projects = @projects.where(id: params[:project_ids]) if projects?
|
@projects = @projects.where(id: params[:project_ids]) if projects?
|
||||||
@projects = @projects.reorder(nil)
|
@projects = @projects.reorder(nil)
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Ci
|
||||||
|
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
|
|
||||||
validates :key, uniqueness: { scope: :project_id }
|
validates :key, uniqueness: { scope: [:project_id, :environment_scope] }
|
||||||
|
|
||||||
scope :unprotected, -> { where(protected: false) }
|
scope :unprotected, -> { where(protected: false) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -1074,9 +1074,10 @@ class Project < ActiveRecord::Base
|
||||||
merge_requests.where(source_project_id: self.id)
|
merge_requests.where(source_project_id: self.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_repository
|
def create_repository(force: false)
|
||||||
# Forked import is handled asynchronously
|
# Forked import is handled asynchronously
|
||||||
unless forked?
|
return if forked? && !force
|
||||||
|
|
||||||
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
|
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
|
||||||
repository.after_create
|
repository.after_create
|
||||||
true
|
true
|
||||||
|
@ -1085,10 +1086,9 @@ class Project < ActiveRecord::Base
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_repository
|
def ensure_repository
|
||||||
create_repository unless repository_exists?
|
create_repository(force: true) unless repository_exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def repository_exists?
|
def repository_exists?
|
||||||
|
|
|
@ -11,8 +11,7 @@
|
||||||
.col-sm-10.col-sm-offset-2
|
.col-sm-10.col-sm-offset-2
|
||||||
- if issuable.can_remove_source_branch?(current_user)
|
- if issuable.can_remove_source_branch?(current_user)
|
||||||
.checkbox
|
.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
|
= label_tag 'merge_request[force_remove_source_branch]' do
|
||||||
= hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil
|
= 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.
|
Remove source branch when merge request is accepted.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Set default for Remove source branch to false.
|
||||||
|
merge_request: !12576
|
||||||
|
author:
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
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:
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Hide archived project labels from group issue tracker
|
||||||
|
merge_request: 12547
|
||||||
|
author: Horacio Bertorello
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Fixed the y_label not setting correctly for each graph on the monitoring dashboard
|
||||||
|
merge_request:
|
||||||
|
author:
|
4
changelogs/unreleased/sh-allow-force-repo-create.yml
Normal file
4
changelogs/unreleased/sh-allow-force-repo-create.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Make Project#ensure_repository force create a repo
|
||||||
|
merge_request:
|
||||||
|
author:
|
4
changelogs/unreleased/sh-optimize-project-commit-api.yml
Normal file
4
changelogs/unreleased/sh-optimize-project-commit-api.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Optimize creation of commit API by using Repository#commit instead of Repository#commits
|
||||||
|
merge_request:
|
||||||
|
author:
|
38
db/migrate/20170622135451_rename_duplicated_variable_key.rb
Normal file
38
db/migrate/20170622135451_rename_duplicated_variable_key.rb
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
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
|
|
@ -0,0 +1,15 @@
|
||||||
|
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
|
|
@ -0,0 +1,38 @@
|
||||||
|
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
|
|
@ -0,0 +1,19 @@
|
||||||
|
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
|
|
@ -374,9 +374,10 @@ ActiveRecord::Schema.define(version: 20170703102400) do
|
||||||
t.string "encrypted_value_iv"
|
t.string "encrypted_value_iv"
|
||||||
t.integer "project_id", null: false
|
t.integer "project_id", null: false
|
||||||
t.boolean "protected", default: false, null: false
|
t.boolean "protected", default: false, null: false
|
||||||
|
t.string "environment_scope", default: "*", null: false
|
||||||
end
|
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|
|
create_table "container_repositories", force: :cascade do |t|
|
||||||
t.integer "project_id", null: false
|
t.integer "project_id", null: false
|
||||||
|
|
|
@ -67,7 +67,7 @@ module API
|
||||||
result = ::Files::MultiService.new(user_project, current_user, attrs).execute
|
result = ::Files::MultiService.new(user_project, current_user, attrs).execute
|
||||||
|
|
||||||
if result[:status] == :success
|
if result[:status] == :success
|
||||||
commit_detail = user_project.repository.commits(result[:result], limit: 1).first
|
commit_detail = user_project.repository.commit(result[:result])
|
||||||
present commit_detail, with: Entities::RepoCommitDetail
|
present commit_detail, with: Entities::RepoCommitDetail
|
||||||
else
|
else
|
||||||
render_api_error!(result[:message], 400)
|
render_api_error!(result[:message], 400)
|
||||||
|
|
|
@ -2,6 +2,8 @@ require 'securerandom'
|
||||||
|
|
||||||
module Gitlab
|
module Gitlab
|
||||||
class Shell
|
class Shell
|
||||||
|
GITLAB_SHELL_ENV_VARS = %w(GIT_TERMINAL_PROMPT).freeze
|
||||||
|
|
||||||
Error = Class.new(StandardError)
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
KeyAdder = Struct.new(:io) do
|
KeyAdder = Struct.new(:io) do
|
||||||
|
@ -67,7 +69,7 @@ module Gitlab
|
||||||
# add_repository("/path/to/storage", "gitlab/gitlab-ci")
|
# add_repository("/path/to/storage", "gitlab/gitlab-ci")
|
||||||
#
|
#
|
||||||
def add_repository(storage, name)
|
def add_repository(storage, name)
|
||||||
Gitlab::Utils.system_silent([gitlab_shell_projects_path,
|
gitlab_shell_fast_execute([gitlab_shell_projects_path,
|
||||||
'add-project', storage, "#{name}.git"])
|
'add-project', storage, "#{name}.git"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,10 +84,9 @@ module Gitlab
|
||||||
def import_repository(storage, name, url)
|
def import_repository(storage, name, url)
|
||||||
# Timeout should be less than 900 ideally, to prevent the memory killer
|
# Timeout should be less than 900 ideally, to prevent the memory killer
|
||||||
# to silently kill the process without knowing we are timing out here.
|
# to silently kill the process without knowing we are timing out here.
|
||||||
output, status = Popen.popen([gitlab_shell_projects_path, 'import-project',
|
cmd = [gitlab_shell_projects_path, 'import-project',
|
||||||
storage, "#{name}.git", url, "#{Gitlab.config.gitlab_shell.git_timeout}"])
|
storage, "#{name}.git", url, "#{Gitlab.config.gitlab_shell.git_timeout}"]
|
||||||
raise Error, output unless status.zero?
|
gitlab_shell_fast_execute_raise_error(cmd)
|
||||||
true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fetch remote for repository
|
# Fetch remote for repository
|
||||||
|
@ -103,9 +104,7 @@ module Gitlab
|
||||||
args << '--force' if forced
|
args << '--force' if forced
|
||||||
args << '--no-tags' if no_tags
|
args << '--no-tags' if no_tags
|
||||||
|
|
||||||
output, status = Popen.popen(args)
|
gitlab_shell_fast_execute_raise_error(args)
|
||||||
raise Error, output unless status.zero?
|
|
||||||
true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Move repository
|
# Move repository
|
||||||
|
@ -117,7 +116,7 @@ module Gitlab
|
||||||
# mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new")
|
# mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new")
|
||||||
#
|
#
|
||||||
def mv_repository(storage, path, new_path)
|
def mv_repository(storage, path, new_path)
|
||||||
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'mv-project',
|
gitlab_shell_fast_execute([gitlab_shell_projects_path, 'mv-project',
|
||||||
storage, "#{path}.git", "#{new_path}.git"])
|
storage, "#{path}.git", "#{new_path}.git"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -131,7 +130,7 @@ module Gitlab
|
||||||
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx")
|
# 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)
|
def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace)
|
||||||
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project',
|
gitlab_shell_fast_execute([gitlab_shell_projects_path, 'fork-project',
|
||||||
forked_from_storage, "#{path}.git", forked_to_storage,
|
forked_from_storage, "#{path}.git", forked_to_storage,
|
||||||
fork_namespace])
|
fork_namespace])
|
||||||
end
|
end
|
||||||
|
@ -145,7 +144,7 @@ module Gitlab
|
||||||
# remove_repository("/path/to/storage", "gitlab/gitlab-ci")
|
# remove_repository("/path/to/storage", "gitlab/gitlab-ci")
|
||||||
#
|
#
|
||||||
def remove_repository(storage, name)
|
def remove_repository(storage, name)
|
||||||
Gitlab::Utils.system_silent([gitlab_shell_projects_path,
|
gitlab_shell_fast_execute([gitlab_shell_projects_path,
|
||||||
'rm-project', storage, "#{name}.git"])
|
'rm-project', storage, "#{name}.git"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -155,7 +154,7 @@ module Gitlab
|
||||||
# add_key("key-42", "sha-rsa ...")
|
# add_key("key-42", "sha-rsa ...")
|
||||||
#
|
#
|
||||||
def add_key(key_id, key_content)
|
def add_key(key_id, key_content)
|
||||||
Gitlab::Utils.system_silent([gitlab_shell_keys_path,
|
gitlab_shell_fast_execute([gitlab_shell_keys_path,
|
||||||
'add-key', key_id, self.class.strip_key(key_content)])
|
'add-key', key_id, self.class.strip_key(key_content)])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -175,8 +174,10 @@ module Gitlab
|
||||||
# remove_key("key-342", "sha-rsa ...")
|
# remove_key("key-342", "sha-rsa ...")
|
||||||
#
|
#
|
||||||
def remove_key(key_id, key_content)
|
def remove_key(key_id, key_content)
|
||||||
Gitlab::Utils.system_silent([gitlab_shell_keys_path,
|
args = [gitlab_shell_keys_path, 'rm-key', key_id]
|
||||||
'rm-key', key_id, key_content])
|
args << key_content if key_content
|
||||||
|
|
||||||
|
gitlab_shell_fast_execute(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove all ssh keys from gitlab shell
|
# Remove all ssh keys from gitlab shell
|
||||||
|
@ -185,7 +186,7 @@ module Gitlab
|
||||||
# remove_all_keys
|
# remove_all_keys
|
||||||
#
|
#
|
||||||
def remove_all_keys
|
def remove_all_keys
|
||||||
Gitlab::Utils.system_silent([gitlab_shell_keys_path, 'clear'])
|
gitlab_shell_fast_execute([gitlab_shell_keys_path, 'clear'])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add empty directory for storing repositories
|
# Add empty directory for storing repositories
|
||||||
|
@ -267,5 +268,31 @@ module Gitlab
|
||||||
def gitlab_shell_keys_path
|
def gitlab_shell_keys_path
|
||||||
File.join(gitlab_shell_path, 'bin', 'gitlab-keys')
|
File.join(gitlab_shell_path, 'bin', 'gitlab-keys')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -49,12 +49,12 @@ describe LabelsFinder do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'filtering by group_id' do
|
context 'filtering by group_id' do
|
||||||
it 'returns labels available for any project within the group' do
|
it 'returns labels available for any non-archived project within the group' do
|
||||||
group_1.add_developer(user)
|
group_1.add_developer(user)
|
||||||
|
project_1.archive!
|
||||||
finder = described_class.new(user, group_id: group_1.id)
|
finder = described_class.new(user, group_id: group_1.id)
|
||||||
|
|
||||||
expect(finder.execute).to eq [group_label_2, project_label_1, group_label_1, project_label_5]
|
expect(finder.execute).to eq [group_label_2, group_label_1, project_label_5]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const metricsGroupsAPIResponse = {
|
||||||
'queries': [
|
'queries': [
|
||||||
{
|
{
|
||||||
'query_range': 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20',
|
'query_range': 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20',
|
||||||
'label': 'Container memory',
|
'y_label': 'Memory',
|
||||||
'unit': 'MiB',
|
'unit': 'MiB',
|
||||||
'result': [
|
'result': [
|
||||||
{
|
{
|
||||||
|
@ -2477,7 +2477,7 @@ export const singleRowMetrics = [
|
||||||
{
|
{
|
||||||
'title': 'CPU usage',
|
'title': 'CPU usage',
|
||||||
'weight': 1,
|
'weight': 1,
|
||||||
'y_label': 'Values',
|
'y_label': 'Memory',
|
||||||
'queries': [
|
'queries': [
|
||||||
{
|
{
|
||||||
'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100',
|
'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100',
|
||||||
|
|
|
@ -94,4 +94,15 @@ describe('MonitoringColumn', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('has a title for the y-axis that comes from the backend', () => {
|
||||||
|
const component = createComponent({
|
||||||
|
columnData: singleRowMetrics[0],
|
||||||
|
classType: 'col-md-6',
|
||||||
|
updateAspectRatio: false,
|
||||||
|
deploymentData,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(component.yAxisLabel).toEqual(component.columnData.y_label);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,6 +32,17 @@ describe 'Gitlab::Popen', lib: true, no_db: true do
|
||||||
end
|
end
|
||||||
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
|
context 'without a directory argument' do
|
||||||
before do
|
before do
|
||||||
@output, @status = @klass.new.popen(%w(ls))
|
@output, @status = @klass.new.popen(%w(ls))
|
||||||
|
|
|
@ -4,6 +4,7 @@ require 'stringio'
|
||||||
describe Gitlab::Shell, lib: true do
|
describe Gitlab::Shell, lib: true do
|
||||||
let(:project) { double('Project', id: 7, path: 'diaspora') }
|
let(:project) { double('Project', id: 7, path: 'diaspora') }
|
||||||
let(:gitlab_shell) { Gitlab::Shell.new }
|
let(:gitlab_shell) { Gitlab::Shell.new }
|
||||||
|
let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(Project).to receive(:find).and_return(project)
|
allow(Project).to receive(:find).and_return(project)
|
||||||
|
@ -50,7 +51,7 @@ describe Gitlab::Shell, lib: true do
|
||||||
describe '#add_key' do
|
describe '#add_key' do
|
||||||
it 'removes trailing garbage' do
|
it 'removes trailing garbage' do
|
||||||
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
|
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
|
||||||
expect(Gitlab::Utils).to receive(:system_silent).with(
|
expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
|
||||||
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
|
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -100,17 +101,91 @@ describe Gitlab::Shell, lib: true do
|
||||||
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
|
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
|
||||||
end
|
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
|
describe '#fetch_remote' do
|
||||||
it 'returns true when the command succeeds' do
|
it 'returns true when the command succeeds' do
|
||||||
expect(Gitlab::Popen).to receive(:popen)
|
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
|
expect(gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage')).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an exception when the command fails' do
|
it 'raises an exception when the command fails' do
|
||||||
expect(Gitlab::Popen).to receive(:popen)
|
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")
|
expect { gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage') }.to raise_error(Gitlab::Shell::Error, "error")
|
||||||
end
|
end
|
||||||
|
@ -119,14 +194,16 @@ describe Gitlab::Shell, lib: true do
|
||||||
describe '#import_repository' do
|
describe '#import_repository' do
|
||||||
it 'returns true when the command succeeds' do
|
it 'returns true when the command succeeds' do
|
||||||
expect(Gitlab::Popen).to receive(:popen)
|
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
|
expect(gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git')).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an exception when the command fails' do
|
it 'raises an exception when the command fails' do
|
||||||
expect(Gitlab::Popen).to receive(:popen)
|
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")
|
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
|
end
|
||||||
|
|
34
spec/migrations/rename_duplicated_variable_key_spec.rb
Normal file
34
spec/migrations/rename_duplicated_variable_key_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
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
|
describe Ci::Variable, models: true do
|
||||||
subject { build(:ci_variable) }
|
subject { build(:ci_variable) }
|
||||||
|
|
||||||
|
let(:secret_value) { 'secret' }
|
||||||
|
|
||||||
|
describe 'validations' do
|
||||||
it { is_expected.to include_module(HasVariable) }
|
it { is_expected.to include_module(HasVariable) }
|
||||||
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id) }
|
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
|
describe '.unprotected' do
|
||||||
subject { described_class.unprotected }
|
subject { described_class.unprotected }
|
||||||
|
|
|
@ -1346,7 +1346,7 @@ describe Project, models: true do
|
||||||
.with(project.repository_storage_path, project.path_with_namespace)
|
.with(project.repository_storage_path, project.path_with_namespace)
|
||||||
.and_return(true)
|
.and_return(true)
|
||||||
|
|
||||||
expect(project).to receive(:create_repository)
|
expect(project).to receive(:create_repository).with(force: true)
|
||||||
|
|
||||||
project.ensure_repository
|
project.ensure_repository
|
||||||
end
|
end
|
||||||
|
@ -1359,6 +1359,19 @@ describe Project, models: true do
|
||||||
|
|
||||||
project.ensure_repository
|
project.ensure_repository
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe '#user_can_push_to_empty_repo?' do
|
describe '#user_can_push_to_empty_repo?' do
|
||||||
|
|
Loading…
Reference in a new issue