Commit 93278597 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-11-05

# Conflicts:
#	app/assets/javascripts/notes/stores/getters.js
#	app/models/application_setting.rb
#	app/models/commit_status.rb
#	db/schema.rb

[ci skip]
parents bf184d1f ec37e707
import Vue from 'vue';
import { GlLoadingIcon, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
Vue.component('gl-loading-icon', GlLoadingIcon);
Vue.directive('gl-tooltip', GlTooltipDirective);
......@@ -3,6 +3,7 @@ import { mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { pluralize, truncate } from '~/lib/utils/text_utility';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants';
export default {
......@@ -10,6 +11,9 @@ export default {
Icon,
UserAvatarImage,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
discussions: {
type: Array,
......
......@@ -192,9 +192,12 @@ export const firstUnresolvedDiscussionId = (state, getters) => diffOrder => {
return getters.unresolvedDiscussionsIdsByDate[0];
};
<<<<<<< HEAD
export const getDiscussion = state => discussionId =>
state.discussions.find(discussion => discussion.id === discussionId);
=======
>>>>>>> upstream/master
export const commentsDisabled = state => state.commentsDisabled;
// prevent babel-plugin-rewire from generating an invalid default during karma tests
......
......@@ -5,7 +5,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import GfmAutoComplete from '~/gfm_auto_complete';
import { __, s__ } from '~/locale';
import Api from '~/api';
import { GlModal } from '@gitlab-org/gitlab-ui';
import { GlModal, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
import eventHub from './event_hub';
import EmojiMenuInModal from './emoji_menu_in_modal';
......@@ -16,6 +16,9 @@ export default {
Icon,
GlModal,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
currentEmoji: {
type: String,
......
<script>
import { calculateRemainingMilliseconds, formatTime } from '~/lib/utils/datetime_utility';
import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
/**
* Counts down to a given end date.
*/
export default {
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
endDateString: {
type: String,
......
......@@ -348,6 +348,7 @@
@include media-breakpoint-down(xs) {
width: 100%;
margin: $btn-side-margin 0;
}
}
}
......
......@@ -147,3 +147,9 @@ table {
}
}
}
.top-area + .content-list {
th {
border-top: 0;
}
}
......@@ -39,10 +39,6 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
svg {
vertical-align: middle;
}
}
.next-run-cell {
......@@ -52,6 +48,10 @@
a {
color: $text-color;
}
svg {
vertical-align: middle;
}
}
.pipeline-schedules-user-callout {
......
......@@ -3,7 +3,7 @@
class PersonalAccessTokensFinder
attr_accessor :params
delegate :build, :find, :find_by, :find_by_token, to: :execute
delegate :build, :find, :find_by_id, :find_by_token, to: :execute
def initialize(params = {})
@params = params
......
......@@ -6,7 +6,10 @@ class ApplicationSetting < ActiveRecord::Base
include TokenAuthenticatable
include IgnorableColumn
include ChronicDurationAttribute
<<<<<<< HEAD
prepend EE::ApplicationSetting
=======
>>>>>>> upstream/master
add_authentication_token_field :runners_registration_token
add_authentication_token_field :health_check_access_token
......
......@@ -17,7 +17,7 @@ module Ci
metadata: nil,
trace: nil,
junit: 'junit.xml',
codequality: 'codequality.json',
codequality: 'gl-code-quality-report.json',
sast: 'gl-sast-report.json',
dependency_scanning: 'gl-dependency-scanning-report.json',
container_scanning: 'gl-container-scanning-report.json',
......
......@@ -55,7 +55,11 @@ class CommitStatus < ActiveRecord::Base
stale_schedule: 7,
job_execution_timeout: 8,
archived_failure: 9
<<<<<<< HEAD
}.merge(EE_FAILURE_REASONS)
=======
}
>>>>>>> upstream/master
##
# We still create some CommitStatuses outside of CreatePipelineService.
......
......@@ -4,6 +4,7 @@ class DeployToken < ActiveRecord::Base
include Expirable
include TokenAuthenticatable
include PolicyActor
include Gitlab::Utils::StrongMemoize
add_authentication_token_field :token
AVAILABLE_SCOPES = %i(read_repository read_registry).freeze
......@@ -49,7 +50,9 @@ class DeployToken < ActiveRecord::Base
# to a single project, later we're going to extend
# that to be for multiple projects and namespaces.
def project
projects.first
strong_memoize(:project) do
projects.first
end
end
def expires_at
......
# frozen_string_literal: true
class PoolRepository < ActiveRecord::Base
POOL_PREFIX = '@pools'
belongs_to :shard
validates :shard, presence: true
# For now, only pool repositories are tracked in the database. However, we may
# want to add other repository types in the future
self.table_name = 'repositories'
has_many :pool_member_projects, class_name: 'Project', foreign_key: :pool_repository_id
def shard_name
shard&.name
end
def shard_name=(name)
self.shard = Shard.by_name(name)
end
end
......@@ -4,6 +4,15 @@ module Postgresql
class ReplicationSlot < ActiveRecord::Base
self.table_name = 'pg_replication_slots'
# Returns true if there are any replication slots in use.
# PostgreSQL-compatible databases such as Aurora don't support
# replication slots, so this will return false as well.
def self.in_use?
transaction { exists? }
rescue ActiveRecord::StatementInvalid
false
end
# Returns true if the lag observed across all replication slots exceeds a
# given threshold.
#
......@@ -11,6 +20,8 @@ module Postgresql
# statistics it takes between 1 and 5 seconds to replicate around
# 100 MB of data.
def self.lag_too_great?(max = 100.megabytes)
return false unless in_use?
lag_function = "#{Gitlab::Database.pg_wal_lsn_diff}" \
"(#{Gitlab::Database.pg_current_wal_insert_lsn}(), restart_lsn)::bigint"
......
......@@ -98,8 +98,7 @@ class Project < ActiveRecord::Base
unless: :ci_cd_settings,
if: proc { ProjectCiCdSetting.available? }
after_create :set_last_activity_at
after_create :set_last_repository_updated_at
after_create :set_timestamps_for_create
after_update :update_forks_visibility_level
before_destroy :remove_private_deploy_keys
......@@ -127,6 +126,7 @@ class Project < ActiveRecord::Base
alias_attribute :title, :name
# Relations
belongs_to :pool_repository
belongs_to :creator, class_name: 'User'
belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id'
belongs_to :namespace
......@@ -2101,13 +2101,8 @@ class Project < ActiveRecord::Base
gitlab_shell.exists?(repository_storage, "#{disk_path}.git")
end
# set last_activity_at to the same as created_at
def set_last_activity_at
update_column(:last_activity_at, self.created_at)
end
def set_last_repository_updated_at
update_column(:last_repository_updated_at, self.created_at)
def set_timestamps_for_create
update_columns(last_activity_at: self.created_at, last_repository_updated_at: self.created_at)
end
def cross_namespace_reference?(from)
......
# frozen_string_literal: true
class Shard < ActiveRecord::Base
# Store shard names from the configuration file in the database. This is not a
# list of active shards - we just want to assign an immutable, unique ID to
# every shard name for easy indexing / referencing.
def self.populate!
return unless table_exists?
# The GitLab config does not change for the lifecycle of the process
in_config = Gitlab.config.repositories.storages.keys.map(&:to_s)
transaction do
in_db = all.pluck(:name)
missing = in_config - in_db
missing.map { |name| by_name(name) }
end
end
def self.by_name(name)
find_or_create_by(name: name)
rescue ActiveRecord::RecordNotUnique
retry
end
end
......@@ -460,12 +460,6 @@ class User < ActiveRecord::Base
by_username(username).take!
end
def find_by_personal_access_token(token_string)
return unless token_string
PersonalAccessTokensFinder.new(state: 'active').find_by_token(token_string)&.user # rubocop: disable CodeReuse/Finder
end
# Returns a user for the given SSH key.
def find_by_ssh_key_id(key_id)
Key.find_by(id: key_id)&.user
......
......@@ -5,7 +5,7 @@
- subscribed = params[:subscribed]
- labels_or_filters = @labels.exists? || search.present? || subscribed.present?
- if can_admin_label
- if @labels.present? && can_admin_label
- content_for(:header_content) do
.nav-controls
= link_to _('New label'), new_group_label_path(@group), class: "btn btn-success"
......
......@@ -5,7 +5,7 @@
- subscribed = params[:subscribed]
- labels_or_filters = @labels.exists? || @prioritized_labels.exists? || search.present? || subscribed.present?
- if can_admin_label
- if @labels.present? && can_admin_label
- content_for(:header_content) do
.nav-controls
= link_to _('New label'), new_project_label_path(@project), class: "btn btn-success qa-label-create-new"
......
......@@ -6,6 +6,9 @@
.text-content
%h4= _("Labels can be applied to issues and merge requests to categorize them.")
%p= _("You can also star a label to make it a priority label.")
- if can?(current_user, :admin_label, @project)
= link_to _('New label'), new_project_label_path(@project), class: 'btn btn-success', title: _('New label'), id: 'new_label_link'
= link_to _('Generate a default set of labels'), generate_project_labels_path(@project), method: :post, class: 'btn btn-success btn-inverted', title: _('Generate a default set of labels'), id: 'generate_labels_link'
.text-center
- if can?(current_user, :admin_label, @project)
= link_to _('New label'), new_project_label_path(@project), class: 'btn btn-success', title: _('New label'), id: 'new_label_link'
= link_to _('Generate a default set of labels'), generate_project_labels_path(@project), method: :post, class: 'btn btn-success btn-inverted', title: _('Generate a default set of labels'), id: 'generate_labels_link'
- if can?(current_user, :admin_label, @group)
= link_to _('New label'), new_group_label_path(@group), class: 'btn btn-success', title: _('New label'), id: 'new_label_link'
---
title: Start tracking shards and pool repositories in the database
merge_request: 22482
author:
type: other
---
title: Fixing styling issues on the scheduled pipelines page
merge_request:
author:
type: fixed
---
title: Remove PersonalAccessTokensFinder#find_by method
merge_request: 22617
author:
type: fixed
---
title: Allow Rails concurrency when running in Puma
merge_request: 22751
author:
type: performance
---
title: Remove gitlab-ui's tooltip from global
merge_request:
author:
type: performance
---
title: Update project and group labels empty state
merge_request: 22745
author: George Tsiolis
type: changed
---
title: Disable replication lag check for Aurora PostgreSQL databases
merge_request: 22786
author:
type: fixed
......@@ -45,4 +45,6 @@ Rails.application.configure do
# Do not log asset requests
config.assets.quiet = true
config.allow_concurrency = defined?(::Puma)
end
......@@ -83,5 +83,5 @@ Rails.application.configure do
config.eager_load = true
config.allow_concurrency = false
config.allow_concurrency = defined?(::Puma)
end
return unless Shard.connected?
return if Gitlab::Database.read_only?
Shard.populate!
# frozen_string_literal: true
class AddIndexToProjectDeployTokensDeployTokenId < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# MySQL already has index inserted
add_concurrent_index :project_deploy_tokens, :deploy_token_id if Gitlab::Database.postgresql?
end
def down
remove_concurrent_index(:project_deploy_tokens, :deploy_token_id) if Gitlab::Database.postgresql?
end
end
# frozen_string_literal: true
class AddShardsTable < ActiveRecord::Migration
DOWNTIME = false
def change
create_table :shards do |t|
t.string :name, null: false, index: { unique: true }
end
end
end
# frozen_string_literal: true
class AddRepositoriesTable < ActiveRecord::Migration
DOWNTIME = false
def change
create_table :repositories, id: :bigserial do |t|
t.references :shard, null: false, index: true, foreign_key: { on_delete: :restrict }
t.string :disk_path, null: false, index: { unique: true }
end
add_column :projects, :pool_repository_id, :bigint
add_index :projects, :pool_repository_id, where: 'pool_repository_id IS NOT NULL'
end
end
# frozen_string_literal: true
class AddProjectsPoolRepositoryIdForeignKey < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key(
:projects,
:repositories,
column: :pool_repository_id,
on_delete: :nullify
)
end
def down
remove_foreign_key(:projects, column: :pool_repository_id)
end
end
......@@ -212,6 +212,7 @@ ActiveRecord::Schema.define(version: 20181101144347) do
t.integer "receive_max_input_size"
t.integer "diff_max_patch_bytes", default: 102400, null: false
t.integer "archive_builds_in_seconds"
<<<<<<< HEAD
end
create_table "approvals", force: :cascade do |t|
......@@ -240,6 +241,8 @@ ActiveRecord::Schema.define(version: 20181101144347) do
t.integer "user_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
=======
>>>>>>> upstream/master
end
add_index "approvers", ["target_id", "target_type"], name: "index_approvers_on_target_id_and_target_type", using: :btree
......@@ -2156,6 +2159,7 @@ ActiveRecord::Schema.define(version: 20181101144347) do
t.datetime_with_timezone "created_at", null: false
end
add_index "project_deploy_tokens", ["deploy_token_id"], name: "index_project_deploy_tokens_on_deploy_token_id", using: :btree
add_index "project_deploy_tokens", ["project_id", "deploy_token_id"], name: "index_project_deploy_tokens_on_project_id_and_deploy_token_id", unique: true, using: :btree
create_table "project_features", force: :cascade do |t|
......@@ -2314,9 +2318,14 @@ ActiveRecord::Schema.define(version: 20181101144347) do
t.string "external_authorization_classification_label"
t.boolean "mirror_overwrites_diverged_branches"
t.boolean "pages_https_only", default: true
<<<<<<< HEAD
t.string "external_webhook_token"
t.boolean "packages_enabled"
t.boolean "merge_requests_author_approval"
=======
t.boolean "remote_mirror_available_overridden"
t.integer "pool_repository_id", limit: 8
>>>>>>> upstream/master
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
......@@ -2336,6 +2345,7 @@ ActiveRecord::Schema.define(version: 20181101144347) do
add_index "projects", ["path"], name: "index_projects_on_path", using: :btree
add_index "projects", ["path"], name: "index_projects_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"}
add_index "projects", ["pending_delete"], name: "index_projects_on_pending_delete", using: :btree
add_index "projects", ["pool_repository_id"], name: "index_projects_on_pool_repository_id", where: "(pool_repository_id IS NOT NULL)", using: :btree
add_index "projects", ["repository_storage", "created_at"], name: "idx_project_repository_check_partial", where: "(last_repository_check_at IS NULL)", using: :btree
add_index "projects", ["repository_storage"], name: "index_projects_on_repository_storage", using: :btree
add_index "projects", ["runners_token"], name: "index_projects_on_runners_token", using: :btree
......@@ -2558,6 +2568,14 @@ ActiveRecord::Schema.define(version: 20181101144347) do
add_index "remote_mirrors", ["last_successful_update_at"], name: "index_remote_mirrors_on_last_successful_update_at", using: :btree
add_index "remote_mirrors", ["project_id"], name: "index_remote_mirrors_on_project_id", using: :btree
create_table "repositories", id: :bigserial, force: :cascade do |t|
t.integer "shard_id", null: false
t.string "disk_path", null: false
end
add_index "repositories", ["disk_path"], name: "index_repositories_on_disk_path", unique: true, using: :btree
add_index "repositories", ["shard_id"], name: "index_repositories_on_shard_id", using: :btree
create_table "repository_languages", id: false, force: :cascade do |t|
t.integer "project_id", null: false
t.integer "programming_language_id", null: false
......@@ -2649,6 +2667,12 @@ ActiveRecord::Schema.define(version: 20181101144347) do
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
add_index "services", ["template"], name: "index_services_on_template", using: :btree
create_table "shards", force: :cascade do |t|
t.string "name", null: false
end
add_index "shards", ["name"], name: "index_shards_on_name", unique: true, using: :btree
create_table "site_statistics", force: :cascade do |t|
t.integer "repositories_count", default: 0, null: false
end
......@@ -3363,11 +3387,15 @@ ActiveRecord::Schema.define(version: 20181101144347) do
add_foreign_key "project_mirror_data", "projects", name: "fk_d1aad367d7", on_delete: :cascade
add_foreign_key "project_repository_states", "projects", on_delete: :cascade
add_foreign_key "project_statistics", "projects", on_delete: :cascade
<<<<<<< HEAD
add_foreign_key "prometheus_alert_events", "projects", on_delete: :cascade
add_foreign_key "prometheus_alert_events", "prometheus_alerts", on_delete: :cascade
add_foreign_key "prometheus_alerts", "environments", on_delete: :cascade
add_foreign_key "prometheus_alerts", "projects", on_delete: :cascade
add_foreign_key "prometheus_alerts", "prometheus_metrics", on_delete: :cascade
=======
add_foreign_key "projects", "repositories", column: "pool_repository_id", name: "fk_6e5c14658a", on_delete: :nullify
>>>>>>> upstream/master
add_foreign_key "prometheus_metrics", "projects", on_delete: :cascade
add_foreign_key "protected_branch_merge_access_levels", "namespaces", column: "group_id", name: "fk_98f3d044fe", on_delete: :cascade
add_foreign_key "protected_branch_merge_access_levels", "protected_branches", name: "fk_8a3072ccb3", on_delete: :cascade
......@@ -3390,7 +3418,12 @@ ActiveRecord::Schema.define(version: 20181101144347) do
add_foreign_key "push_event_payloads", "events", name: "fk_36c74129da", on_delete: :cascade
add_foreign_key "push_rules", "projects", name: "fk_83b29894de", on_delete: :cascade
add_foreign_key "releases", "projects", name: "fk_47fe2a0596", on_delete: :cascade
<<<<<<< HEAD
add_foreign_key "remote_mirrors", "projects", name: "fk_43a9aa4ca8", on_delete: :cascade
=======
add_foreign_key "remote_mirrors", "projects", on_delete: :cascade
add_foreign_key "repositories", "shards", on_delete: :restrict
>>>>>>> upstream/master
add_foreign_key "repository_languages", "projects", on_delete: :cascade
add_foreign_key "resource_label_events", "epics", on_delete: :cascade
add_foreign_key "resource_label_events", "issues", on_delete: :cascade
......
......@@ -518,11 +518,9 @@ module API
PersonalAccessTokensFinder.new({ user: user, impersonation: true }.merge(options))
end
# rubocop: disable CodeReuse/ActiveRecord
def find_impersonation_token
finder.find_by(id: declared_params[:impersonation_token_id]) || not_found!('Impersonation Token')
finder.find_by_id(declared_params[:impersonation_token_id]) || not_found!('Impersonation Token')
end
# rubocop: enable CodeReuse/ActiveRecord
end
before { authenticated_as_admin! }
......
......@@ -95,6 +95,7 @@ excluded_attributes:
- :path
- :namespace_id
- :creator_id
- :pool_repository_id
- :import_url
- :import_status
- :avatar
......
......@@ -92,7 +92,7 @@ describe PersonalAccessTokensFinder do
end
describe 'with id' do
subject { finder(params).find_by(id: active_personal_access_token.id) }
subject { finder(params).find_by_id(active_personal_access_token.id) }
it { is_expected.to eq(active_personal_access_token) }
......@@ -106,7 +106,7 @@ describe PersonalAccessTokensFinder do
end
describe 'with token' do
subject { finder(params).find_by(token: active_personal_access_token.token) }
subject { finder(params).find_by_token(active_personal_access_token.token) }
it { is_expected.to eq(active_personal_access_token) }
......@@ -207,7 +207,7 @@ describe PersonalAccessTokensFinder do
end
describe 'with id' do
subject { finder(params).find_by(id: active_personal_access_token.id) }
subject { finder(params).find_by_id(active_personal_access_token.id) }
it { is_expected.to eq(active_personal_access_token) }
......@@ -221,7 +221,7 @@ describe PersonalAccessTokensFinder do
end
describe 'with token' do
subject { finder(params).find_by(token: active_personal_access_token.token) }
subject { finder(params).find_by_token(active_personal_access_token.token) }
it { is_expected.to eq(active_personal_access_token) }
......
......@@ -33,7 +33,7 @@ describe Gitlab::Ci::Config::Entry::Reports do
where(:keyword, :file) do
:junit | 'junit.xml'
:codequality | 'codequality.json'
:codequality | 'gl-code-quality-report.json'
:sast | 'gl-sast-report.json'
:dependency_scanning | 'gl-dependency-scanning-report.json'
:container_scanning | 'gl-container-scanning-report.json'
......
......@@ -298,6 +298,7 @@ project:
- ci_cd_settings
- import_export_upload
- repository_languages
- pool_repository
award_emoji:
- awardable
- user
......
......@@ -3,7 +3,27 @@
require 'spec_helper'
describe Postgresql::ReplicationSlot, :postgresql do
describe '.in_use?' do
it 'returns true when replication slots are present' do
expect(described_class).to receive(:exists?).and_return(true)
expect(described_class.in_use?).to be_truthy
end
it 'returns false when replication slots are not present' do
expect(described_class.in_use?).to be_falsey
end
it 'returns false if the existence check is invalid' do
expect(described_class).to receive(:exists?).and_raise(ActiveRecord::StatementInvalid.new('PG::FeatureNotSupported'))
expect(described_class.in_use?).to be_falsey
end
end
describe '.lag_too_great?' do
before do
expect(described_class).to receive(:in_use?).and_return(true)
end
it 'returns true when replication lag is too great' do
expect(described_class)
.to receive(:pluck)
......
......@@ -8,6 +8,7 @@ describe Project do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to belong_to(:pool_repository) }
it { is_expected.to have_many(:users) }
it { is_expected.to have_many(:services) }
it { is_expected.to have_many(:events) }
......
# frozen_string_literals: true
require 'spec_helper'
describe Shard do
describe '.populate!' do
it 'creates shards based on the config file' do
expect(described_class.all).to be_empty
stub_storage_settings(foo: {}, bar: {}, baz: {})
described_class.populate!
expect(described_class.all.map(&:name)).to match_array(%w[default foo bar baz])
end
end
describe '.by_name' do
let(:default_shard) { described_class.find_by(name: 'default') }
before do
described_class.populate!
end
it 'returns an existing shard' do
expect(described_class.by_name('default')).to eq(default_shard)
end
it 'creates a new shard' do
result = described_class.by_name('foo')
expect(result).not_to eq(default_shard)
expect(result.name).to eq('foo')
end
it 'retries if creation races' do
expect(described_class)
.to receive(:find_or_create_by)
.with(name: 'default')
.and_raise(ActiveRecord::RecordNotUnique, 'fail')
.once
expect(described_class)
.to receive(:find_or_create_by)
.with(name: 'default')
.and_call_original
expect(described_class.by_name('default')).to eq(default_shard)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment