summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock10
-rw-r--r--app/controllers/admin/dashboard_controller.rb4
-rw-r--r--app/helpers/count_helper.rb8
-rw-r--r--app/models/concerns/diff_file.rb9
-rw-r--r--app/models/diff_note.rb67
-rw-r--r--app/models/merge_request_diff_file.rb7
-rw-r--r--app/models/note.rb4
-rw-r--r--app/models/note_diff_file.rb7
-rw-r--r--app/views/admin/dashboard/index.html.haml20
-rw-r--r--app/workers/all_queues.yml1
-rw-r--r--app/workers/create_note_diff_file_worker.rb9
-rw-r--r--changelogs/unreleased/45190-create-notes-diff-files.yml5
-rw-r--r--changelogs/unreleased/46846-update-redis-namespace-to-1-6-0.yml5
-rw-r--r--changelogs/unreleased/bvl-add-username-to-terms-message.yml5
-rw-r--r--changelogs/unreleased/ignore-writing-trace-if-it-already-archived.yml5
-rw-r--r--changelogs/unreleased/sh-fix-admin-page-counts-take-2.yml5
-rw-r--r--config/sidekiq_queues.yml1
-rw-r--r--db/migrate/20180515121227_create_notes_diff_files.rb21
-rw-r--r--db/schema.rb15
-rw-r--r--doc/administration/high_availability/database.md11
-rw-r--r--doc/administration/high_availability/gitlab.md24
-rw-r--r--lib/api/helpers/internal_helpers.rb6
-rw-r--r--lib/api/internal.rb6
-rw-r--r--lib/api/runner.rb5
-rw-r--r--lib/backup/repository.rb56
-rw-r--r--lib/gitlab/auth/user_access_denied_reason.rb8
-rw-r--r--lib/gitlab/database/count.rb72
-rw-r--r--lib/gitlab/diff/file.rb7
-rw-r--r--lib/gitlab/gitaly_client/storage_service.rb15
-rw-r--r--spec/lib/backup/repository_spec.rb34
-rw-r--r--spec/lib/gitlab/auth/user_access_denied_reason_spec.rb3
-rw-r--r--spec/lib/gitlab/database/count_spec.rb81
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb54
-rw-r--r--spec/lib/gitlab/git_access_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/concerns/discussion_on_diff_spec.rb2
-rw-r--r--spec/models/diff_note_spec.rb62
-rw-r--r--spec/models/note_diff_file_spec.rb11
-rw-r--r--spec/requests/api/helpers_spec.rb2
-rw-r--r--spec/requests/api/internal_spec.rb12
-rw-r--r--spec/requests/api/runner_spec.rb15
-rw-r--r--spec/services/notes/create_service_spec.rb82
-rw-r--r--spec/views/admin/dashboard/index.html.haml_spec.rb5
-rw-r--r--spec/workers/create_note_diff_file_worker_spec.rb16
-rw-r--r--yarn.lock307
47 files changed, 679 insertions, 434 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 7bb21aff834..89eba2c5b85 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.102.0
+0.103.0
diff --git a/Gemfile b/Gemfile
index cc0758f7c57..b6b82bad8a4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -162,7 +162,7 @@ gem 'acts-as-taggable-on', '~> 5.0'
# Background jobs
gem 'sidekiq', '~> 5.1'
gem 'sidekiq-cron', '~> 0.6.0'
-gem 'redis-namespace', '~> 1.5.2'
+gem 'redis-namespace', '~> 1.6.0'
gem 'sidekiq-limit_fetch', '~> 3.4', require: false
# Cron Parser
@@ -412,7 +412,7 @@ group :ed25519 do
end
# Gitaly GRPC client
-gem 'gitaly-proto', '~> 0.99.0', require: 'gitaly'
+gem 'gitaly-proto', '~> 0.100.0', require: 'gitaly'
gem 'grpc', '~> 1.11.0'
# Locked until https://github.com/google/protobuf/issues/4210 is closed
diff --git a/Gemfile.lock b/Gemfile.lock
index 537c377dccc..b0b7bb537a8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -281,7 +281,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- gitaly-proto (0.99.0)
+ gitaly-proto (0.100.0)
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-linguist (5.3.3)
@@ -709,8 +709,8 @@ GEM
redis-activesupport (5.0.4)
activesupport (>= 3, < 6)
redis-store (>= 1.3, < 2)
- redis-namespace (1.5.2)
- redis (~> 3.0, >= 3.0.4)
+ redis-namespace (1.6.0)
+ redis (>= 3.0.4)
redis-rack (2.0.4)
rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2)
@@ -1036,7 +1036,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly-proto (~> 0.99.0)
+ gitaly-proto (~> 0.100.0)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
@@ -1129,7 +1129,7 @@ DEPENDENCIES
recaptcha (~> 3.0)
redcarpet (~> 3.4)
redis (~> 3.2)
- redis-namespace (~> 1.5.2)
+ redis-namespace (~> 1.6.0)
redis-rails (~> 5.0.2)
request_store (~> 1.3)
responders (~> 2.0)
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index d6a6bc7d4a1..737942f3eb2 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -1,7 +1,11 @@
class Admin::DashboardController < Admin::ApplicationController
include CountHelper
+ COUNTED_ITEMS = [Project, User, Group, ForkedProjectLink, Issue, MergeRequest,
+ Note, Snippet, Key, Milestone].freeze
+
def index
+ @counts = Gitlab::Database::Count.approximate_counts(COUNTED_ITEMS)
@projects = Project.order_id_desc.without_deleted.with_route.limit(10)
@users = User.order_id_desc.limit(10)
@groups = Group.order_id_desc.with_route.limit(10)
diff --git a/app/helpers/count_helper.rb b/app/helpers/count_helper.rb
index 24ee62e68ba..5cd98f40f78 100644
--- a/app/helpers/count_helper.rb
+++ b/app/helpers/count_helper.rb
@@ -1,5 +1,9 @@
module CountHelper
- def approximate_count_with_delimiters(model)
- number_with_delimiter(Gitlab::Database::Count.approximate_count(model))
+ def approximate_count_with_delimiters(count_data, model)
+ count = count_data[model]
+
+ raise "Missing model #{model} from count data" unless count
+
+ number_with_delimiter(count)
end
end
diff --git a/app/models/concerns/diff_file.rb b/app/models/concerns/diff_file.rb
new file mode 100644
index 00000000000..72332072012
--- /dev/null
+++ b/app/models/concerns/diff_file.rb
@@ -0,0 +1,9 @@
+module DiffFile
+ extend ActiveSupport::Concern
+
+ def to_hash
+ keys = Gitlab::Git::Diff::SERIALIZE_KEYS - [:diff]
+
+ as_json(only: keys).merge(diff: diff).with_indifferent_access
+ end
+end
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 616a626419b..d752d5bcdee 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -3,6 +3,7 @@
# A note of this type can be resolvable.
class DiffNote < Note
include NoteOnDiff
+ include Gitlab::Utils::StrongMemoize
NOTEABLE_TYPES = %w(MergeRequest Commit).freeze
@@ -12,7 +13,6 @@ class DiffNote < Note
validates :original_position, presence: true
validates :position, presence: true
- validates :diff_line, presence: true, if: :on_text?
validates :line_code, presence: true, line_code: true, if: :on_text?
validates :noteable_type, inclusion: { in: NOTEABLE_TYPES }
validate :positions_complete
@@ -23,6 +23,7 @@ class DiffNote < Note
before_validation :update_position, on: :create, if: :on_text?
before_validation :set_line_code, if: :on_text?
after_save :keep_around_commits
+ after_commit :create_diff_file, on: :create
def discussion_class(*)
DiffDiscussion
@@ -53,21 +54,25 @@ class DiffNote < Note
position.position_type == "image"
end
+ def create_diff_file
+ return unless should_create_diff_file?
+
+ diff_file = fetch_diff_file
+ diff_line = diff_file.line_for_position(self.original_position)
+
+ creation_params = diff_file.diff.to_hash
+ .except(:too_large)
+ .merge(diff: diff_file.diff_hunk(diff_line))
+
+ create_note_diff_file(creation_params)
+ end
+
def diff_file
- @diff_file ||=
- begin
- if created_at_diff?(noteable.diff_refs)
- # We're able to use the already persisted diffs (Postgres) if we're
- # presenting a "current version" of the MR discussion diff.
- # So no need to make an extra Gitaly diff request for it.
- # As an extra benefit, the returned `diff_file` already
- # has `highlighted_diff_lines` data set from Redis on
- # `Diff::FileCollection::MergeRequestDiff`.
- noteable.diffs(paths: original_position.paths, expanded: true).diff_files.first
- else
- original_position.diff_file(self.project.repository)
- end
- end
+ strong_memoize(:diff_file) do
+ enqueue_diff_file_creation_job if should_create_diff_file?
+
+ fetch_diff_file
+ end
end
def diff_line
@@ -98,6 +103,38 @@ class DiffNote < Note
private
+ def enqueue_diff_file_creation_job
+ # Avoid enqueuing multiple file creation jobs at once for a note (i.e.
+ # parallel calls to `DiffNote#diff_file`).
+ lease = Gitlab::ExclusiveLease.new("note_diff_file_creation:#{id}", timeout: 1.hour.to_i)
+ return unless lease.try_obtain
+
+ CreateNoteDiffFileWorker.perform_async(id)
+ end
+
+ def should_create_diff_file?
+ on_text? && note_diff_file.nil? && self == discussion.first_note
+ end
+
+ def fetch_diff_file
+ if note_diff_file
+ diff = Gitlab::Git::Diff.new(note_diff_file.to_hash)
+ Gitlab::Diff::File.new(diff,
+ repository: project.repository,
+ diff_refs: original_position.diff_refs)
+ elsif created_at_diff?(noteable.diff_refs)
+ # We're able to use the already persisted diffs (Postgres) if we're
+ # presenting a "current version" of the MR discussion diff.
+ # So no need to make an extra Gitaly diff request for it.
+ # As an extra benefit, the returned `diff_file` already
+ # has `highlighted_diff_lines` data set from Redis on
+ # `Diff::FileCollection::MergeRequestDiff`.
+ noteable.diffs(paths: original_position.paths, expanded: true).diff_files.first
+ else
+ original_position.diff_file(self.project.repository)
+ end
+ end
+
def supported?
for_commit? || self.noteable.has_complete_diff_refs?
end
diff --git a/app/models/merge_request_diff_file.rb b/app/models/merge_request_diff_file.rb
index 1199ff5af22..cd8ba6b904d 100644
--- a/app/models/merge_request_diff_file.rb
+++ b/app/models/merge_request_diff_file.rb
@@ -1,5 +1,6 @@
class MergeRequestDiffFile < ActiveRecord::Base
include Gitlab::EncodingHelper
+ include DiffFile
belongs_to :merge_request_diff
@@ -12,10 +13,4 @@ class MergeRequestDiffFile < ActiveRecord::Base
def diff
binary? ? super.unpack('m0').first : super
end
-
- def to_hash
- keys = Gitlab::Git::Diff::SERIALIZE_KEYS - [:diff]
-
- as_json(only: keys).merge(diff: diff).with_indifferent_access
- end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 109405d3f17..02f7a9b1e4f 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -63,6 +63,7 @@ class Note < ActiveRecord::Base
has_many :todos
has_many :events, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :system_note_metadata
+ has_one :note_diff_file, inverse_of: :diff_note, foreign_key: :diff_note_id
delegate :gfm_reference, :local_reference, to: :noteable
delegate :name, to: :project, prefix: true
@@ -100,7 +101,8 @@ class Note < ActiveRecord::Base
scope :inc_author_project, -> { includes(:project, :author) }
scope :inc_author, -> { includes(:author) }
scope :inc_relations_for_view, -> do
- includes(:project, :author, :updated_by, :resolved_by, :award_emoji, :system_note_metadata)
+ includes(:project, :author, :updated_by, :resolved_by, :award_emoji,
+ :system_note_metadata, :note_diff_file)
end
scope :diff_notes, -> { where(type: %w(LegacyDiffNote DiffNote)) }
diff --git a/app/models/note_diff_file.rb b/app/models/note_diff_file.rb
new file mode 100644
index 00000000000..e688018a6d9
--- /dev/null
+++ b/app/models/note_diff_file.rb
@@ -0,0 +1,7 @@
+class NoteDiffFile < ActiveRecord::Base
+ include DiffFile
+
+ belongs_to :diff_note, inverse_of: :note_diff_file
+
+ validates :diff_note, presence: true
+end
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 3df4ce93fa8..3cdeb103bb8 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -12,7 +12,7 @@
= link_to admin_projects_path do
%h3.text-center
Projects:
- = approximate_count_with_delimiters(Project)
+ = approximate_count_with_delimiters(@counts, Project)
%hr
= link_to('New project', new_project_path, class: "btn btn-new")
.col-sm-4
@@ -21,7 +21,7 @@
= link_to admin_users_path do
%h3.text-center
Users:
- = approximate_count_with_delimiters(User)
+ = approximate_count_with_delimiters(@counts, User)
= render_if_exists 'users_statistics'
%hr
= link_to 'New user', new_admin_user_path, class: "btn btn-new"
@@ -31,7 +31,7 @@
= link_to admin_groups_path do
%h3.text-center
Groups:
- = approximate_count_with_delimiters(Group)
+ = approximate_count_with_delimiters(@counts, Group)
%hr
= link_to 'New group', new_admin_group_path, class: "btn btn-new"
.row
@@ -42,31 +42,31 @@
%p
Forks
%span.light.float-right
- = approximate_count_with_delimiters(ForkedProjectLink)
+ = approximate_count_with_delimiters(@counts, ForkedProjectLink)
%p
Issues
%span.light.float-right
- = approximate_count_with_delimiters(Issue)
+ = approximate_count_with_delimiters(@counts, Issue)
%p
Merge Requests
%span.light.float-right
- = approximate_count_with_delimiters(MergeRequest)
+ = approximate_count_with_delimiters(@counts, MergeRequest)
%p
Notes
%span.light.float-right
- = approximate_count_with_delimiters(Note)
+ = approximate_count_with_delimiters(@counts, Note)
%p
Snippets
%span.light.float-right
- = approximate_count_with_delimiters(Snippet)
+ = approximate_count_with_delimiters(@counts, Snippet)
%p
SSH Keys
%span.light.float-right
- = approximate_count_with_delimiters(Key)
+ = approximate_count_with_delimiters(@counts, Key)
%p
Milestones
%span.light.float-right
- = approximate_count_with_delimiters(Milestone)
+ = approximate_count_with_delimiters(@counts, Milestone)
%p
Active Users
%span.light.float-right
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index b6433eb3eff..d07865a4043 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -115,3 +115,4 @@
- upload_checksum
- web_hook
- repository_update_remote_mirror
+- create_note_diff_file
diff --git a/app/workers/create_note_diff_file_worker.rb b/app/workers/create_note_diff_file_worker.rb
new file mode 100644
index 00000000000..624b638a24e
--- /dev/null
+++ b/app/workers/create_note_diff_file_worker.rb
@@ -0,0 +1,9 @@
+class CreateNoteDiffFileWorker
+ include ApplicationWorker
+
+ def perform(diff_note_id)
+ diff_note = DiffNote.find(diff_note_id)
+
+ diff_note.create_diff_file
+ end
+end
diff --git a/changelogs/unreleased/45190-create-notes-diff-files.yml b/changelogs/unreleased/45190-create-notes-diff-files.yml
new file mode 100644
index 00000000000..efe322b682d
--- /dev/null
+++ b/changelogs/unreleased/45190-create-notes-diff-files.yml
@@ -0,0 +1,5 @@
+---
+title: Persist truncated note diffs on a new table
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/46846-update-redis-namespace-to-1-6-0.yml b/changelogs/unreleased/46846-update-redis-namespace-to-1-6-0.yml
new file mode 100644
index 00000000000..3707ad74b8f
--- /dev/null
+++ b/changelogs/unreleased/46846-update-redis-namespace-to-1-6-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update redis-namespace to 1.6.0
+merge_request: 19166
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/bvl-add-username-to-terms-message.yml b/changelogs/unreleased/bvl-add-username-to-terms-message.yml
new file mode 100644
index 00000000000..b95d87e9265
--- /dev/null
+++ b/changelogs/unreleased/bvl-add-username-to-terms-message.yml
@@ -0,0 +1,5 @@
+---
+title: Add username to terms message in git and API calls
+merge_request: 19126
+author:
+type: changed
diff --git a/changelogs/unreleased/ignore-writing-trace-if-it-already-archived.yml b/changelogs/unreleased/ignore-writing-trace-if-it-already-archived.yml
new file mode 100644
index 00000000000..5c342e2a131
--- /dev/null
+++ b/changelogs/unreleased/ignore-writing-trace-if-it-already-archived.yml
@@ -0,0 +1,5 @@
+---
+title: Disallow updating job status if the job is not running
+merge_request: 19101
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-admin-page-counts-take-2.yml b/changelogs/unreleased/sh-fix-admin-page-counts-take-2.yml
new file mode 100644
index 00000000000..d9bd1af9380
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-admin-page-counts-take-2.yml
@@ -0,0 +1,5 @@
+---
+title: Fix admin counters not working when PostgreSQL has secondaries
+merge_request:
+author:
+type: fixed
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index e1e8f36b663..d16060e8f45 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -75,4 +75,5 @@
- [pipeline_background, 1]
- [repository_update_remote_mirror, 1]
- [repository_remove_remote, 1]
+ - [create_note_diff_file, 1]
diff --git a/db/migrate/20180515121227_create_notes_diff_files.rb b/db/migrate/20180515121227_create_notes_diff_files.rb
new file mode 100644
index 00000000000..7108bc1a64b
--- /dev/null
+++ b/db/migrate/20180515121227_create_notes_diff_files.rb
@@ -0,0 +1,21 @@
+class CreateNotesDiffFiles < ActiveRecord::Migration
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def change
+ create_table :note_diff_files do |t|
+ t.references :diff_note, references: :notes, null: false, index: { unique: true }
+ t.text :diff, null: false
+ t.boolean :new_file, null: false
+ t.boolean :renamed_file, null: false
+ t.boolean :deleted_file, null: false
+ t.string :a_mode, null: false
+ t.string :b_mode, null: false
+ t.text :new_path, null: false
+ t.text :old_path, null: false
+ end
+
+ add_foreign_key :note_diff_files, :notes, column: :diff_note_id, on_delete: :cascade
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 37d336b9928..884e333874c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1302,6 +1302,20 @@ ActiveRecord::Schema.define(version: 20180521171529) do
add_index "namespaces", ["runners_token"], name: "index_namespaces_on_runners_token", unique: true, using: :btree
add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree
+ create_table "note_diff_files", force: :cascade do |t|
+ t.integer "diff_note_id", null: false
+ t.text "diff", null: false
+ t.boolean "new_file", null: false
+ t.boolean "renamed_file", null: false
+ t.boolean "deleted_file", null: false
+ t.string "a_mode", null: false
+ t.string "b_mode", null: false
+ t.text "new_path", null: false
+ t.text "old_path", null: false
+ end
+
+ add_index "note_diff_files", ["diff_note_id"], name: "index_note_diff_files_on_diff_note_id", unique: true, using: :btree
+
create_table "notes", force: :cascade do |t|
t.text "note"
t.string "noteable_type"
@@ -2243,6 +2257,7 @@ ActiveRecord::Schema.define(version: 20180521171529) do
add_foreign_key "merge_requests_closing_issues", "merge_requests", on_delete: :cascade
add_foreign_key "milestones", "namespaces", column: "group_id", name: "fk_95650a40d4", on_delete: :cascade
add_foreign_key "milestones", "projects", name: "fk_9bd0a0c791", on_delete: :cascade
+ add_foreign_key "note_diff_files", "notes", column: "diff_note_id", on_delete: :cascade
add_foreign_key "notes", "projects", name: "fk_99e097b079", on_delete: :cascade
add_foreign_key "oauth_openid_requests", "oauth_access_grants", column: "access_grant_id", name: "fk_oauth_openid_requests_oauth_access_grants_access_grant_id"
add_foreign_key "pages_domains", "projects", name: "fk_ea2f6dfc6f", on_delete: :cascade
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
index ca6d8d2de67..b5124b1d540 100644
--- a/doc/administration/high_availability/database.md
+++ b/doc/administration/high_availability/database.md
@@ -33,16 +33,7 @@ If you use a cloud-managed service, or provide your own PostgreSQL:
external_url 'https://gitlab.example.com'
# Disable all components except PostgreSQL
- postgresql['enable'] = true
- bootstrap['enable'] = false
- nginx['enable'] = false
- unicorn['enable'] = false
- sidekiq['enable'] = false
- redis['enable'] = false
- prometheus['enable'] = false
- gitaly['enable'] = false
- gitlab_workhorse['enable'] = false
- mailroom['enable'] = false
+ roles ['postgres_role']
# PostgreSQL configuration
gitlab_rails['db_password'] = 'DB password'
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
index e201848791c..b0348d1db10 100644
--- a/doc/administration/high_availability/gitlab.md
+++ b/doc/administration/high_availability/gitlab.md
@@ -75,25 +75,24 @@ for each GitLab application server in your environment.
servers should point to the external url that users will use to access GitLab.
In a typical HA setup, this will be the url of the load balancer which will
route traffic to all GitLab application servers in the HA cluster.
-
-1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+
+ > **Note:** When you specify `https` in the `external_url`, as in the example
+ above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
+ certificates are not present, Nginx will fail to start. See
+ [Nginx documentation](http://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
+ for more information.
## First GitLab application server
-As a final step, run the setup rake task on the first GitLab application server.
-It is not necessary to run this on additional application servers.
+As a final step, run the setup rake task **only on** the first GitLab application server.
+Do not run this on additional application servers.
1. Initialize the database by running `sudo gitlab-rake gitlab:setup`.
+1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
> **WARNING:** Only run this setup task on **NEW** GitLab instances because it
will wipe any existing data.
-> **Note:** When you specify `https` in the `external_url`, as in the example
- above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
- certificates are not present, Nginx will fail to start. See
- [Nginx documentation](http://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
- for more information.
-
## Extra configuration for additional GitLab application servers
Additional GitLab servers (servers configured **after** the first GitLab server)
@@ -101,8 +100,7 @@ need some extra configuration.
1. Configure shared secrets. These values can be obtained from the primary
GitLab server in `/etc/gitlab/gitlab-secrets.json`. Add these to
- `/etc/gitlab/gitlab.rb` **prior to** running the first `reconfigure` in
- the steps above.
+ `/etc/gitlab/gitlab.rb` **prior to** running the first `reconfigure`.
```ruby
gitlab_shell['secret_token'] = 'fbfb19c355066a9afb030992231c4a363357f77345edd0f2e772359e5be59b02538e1fa6cae8f93f7d23355341cea2b93600dab6d6c3edcdced558fc6d739860'
@@ -115,6 +113,8 @@ need some extra configuration.
from running on upgrade. Only the primary GitLab application server should
handle migrations.
+1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+
## Troubleshooting
- `mount: wrong fs type, bad option, bad superblock on`
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index abe3d353984..83151be82ad 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -89,12 +89,6 @@ module API
end
end
- # Return the repository full path so that gitlab-shell has it when
- # handling ssh commands
- def repository_path
- repository.path_to_repo
- end
-
# Return the Gitaly Address if it is enabled
def gitaly_payload(action)
return unless %w[git-receive-pack git-upload-pack git-upload-archive].include?(action)
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index a3dac36b8b6..a9803be9f69 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -59,7 +59,11 @@ module API
status: true,
gl_repository: gl_repository,
gl_username: user&.username,
- repository_path: repository_path,
+
+ # This repository_path is a bogus value but gitlab-shell still requires
+ # its presence. https://gitlab.com/gitlab-org/gitlab-shell/issues/135
+ repository_path: '/',
+
gitaly: gitaly_payload(params[:action])
}
end
diff --git a/lib/api/runner.rb b/lib/api/runner.rb
index a7f1cb1131f..5b7ae89440c 100644
--- a/lib/api/runner.rb
+++ b/lib/api/runner.rb
@@ -123,6 +123,7 @@ module API
end
put '/:id' do
job = authenticate_job!
+ forbidden!('Job is not running') unless job.running?
job.trace.set(params[:trace]) if params[:trace]
@@ -131,9 +132,9 @@ module API
case params[:state].to_s
when 'success'
- job.success
+ job.success!
when 'failed'
- job.drop(params[:failure_reason] || :unknown_failure)
+ job.drop!(params[:failure_reason] || :unknown_failure)
end
end
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index c3360c391af..84670d6582e 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -73,29 +73,40 @@ module Backup
end
def prepare_directories
- # TODO: Need to find a way to do this for gitaly
- # Gitaly discussion issue: https://gitlab.com/gitlab-org/gitaly/issues/1194
-
Gitlab.config.repositories.storages.each do |name, repository_storage|
- path = repository_storage.legacy_disk_path
- next unless File.exist?(path)
-
- # Move all files in the existing repos directory except . and .. to
- # repositories.old.<timestamp> directory
- bk_repos_path = File.join(Gitlab.config.backup.path, "tmp", "#{name}-repositories.old." + Time.now.to_i.to_s)
- FileUtils.mkdir_p(bk_repos_path, mode: 0700)
- files = Dir.glob(File.join(path, "*"), File::FNM_DOTMATCH) - [File.join(path, "."), File.join(path, "..")]
-
- begin
- FileUtils.mv(files, bk_repos_path)
- rescue Errno::EACCES
- access_denied_error(path)
- rescue Errno::EBUSY
- resource_busy_error(path)
+ delete_all_repositories(name, repository_storage)
+ end
+ end
+
+ def delete_all_repositories(name, repository_storage)
+ gitaly_migrate(:delete_all_repositories) do |is_enabled|
+ if is_enabled
+ Gitlab::GitalyClient::StorageService.new(name).delete_all_repositories
+ else
+ local_delete_all_repositories(name, repository_storage)
end
end
end
+ def local_delete_all_repositories(name, repository_storage)
+ path = repository_storage.legacy_disk_path
+ return unless File.exist?(path)
+
+ # Move all files in the existing repos directory except . and .. to
+ # repositories.old.<timestamp> directory
+ bk_repos_path = File.join(Gitlab.config.backup.path, "tmp", "#{name}-repositories.old." + Time.now.to_i.to_s)
+ FileUtils.mkdir_p(bk_repos_path, mode: 0700)
+ files = Dir.glob(File.join(path, "*"), File::FNM_DOTMATCH) - [File.join(path, "."), File.join(path, "..")]
+
+ begin
+ FileUtils.mv(files, bk_repos_path)
+ rescue Errno::EACCES
+ access_denied_error(path)
+ rescue Errno::EBUSY
+ resource_busy_error(path)
+ end
+ end
+
def restore_custom_hooks(project)
# TODO: Need to find a way to do this for gitaly
# Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/1195
@@ -113,6 +124,7 @@ module Backup
def restore
prepare_directories
gitlab_shell = Gitlab::Shell.new
+
Project.find_each(batch_size: 1000) do |project|
progress.print " * #{project.full_path} ... "
path_to_project_bundle = path_to_bundle(project)
@@ -121,7 +133,6 @@ module Backup
restore_repo_success = nil
if File.exist?(path_to_project_bundle)
begin
- gitlab_shell.remove_repository(project.repository_storage, project.disk_path) if project.repository_exists?
project.repository.create_from_bundle path_to_project_bundle
restore_repo_success = true
rescue => e
@@ -146,7 +157,6 @@ module Backup
if File.exist?(path_to_wiki_bundle)
progress.print " * #{wiki.full_path} ... "
begin
- gitlab_shell.remove_repository(wiki.repository_storage, wiki.disk_path) if wiki.repository_exists?
wiki.repository.create_from_bundle(path_to_wiki_bundle)
progress.puts "[DONE]".color(:green)
rescue => e
@@ -224,5 +234,11 @@ module Backup
def display_repo_path(project)
project.hashed_storage?(:repository) ? "#{project.full_path} (#{project.disk_path})" : project.full_path
end
+
+ def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
+ Gitlab::GitalyClient.migrate(method, status: status, &block)
+ rescue GRPC::NotFound, GRPC::BadStatus => e
+ raise Error, e
+ end
end
end
diff --git a/lib/gitlab/auth/user_access_denied_reason.rb b/lib/gitlab/auth/user_access_denied_reason.rb
index af310aa12fc..1893cb001b2 100644
--- a/lib/gitlab/auth/user_access_denied_reason.rb
+++ b/lib/gitlab/auth/user_access_denied_reason.rb
@@ -8,12 +8,12 @@ module Gitlab
def rejection_message
case rejection_type
when :internal
- 'This action cannot be performed by internal users'
+ "This action cannot be performed by internal users"
when :terms_not_accepted
- 'You must accept the Terms of Service in order to perform this action. '\
- 'Please access GitLab from a web browser to accept these terms.'
+ "You (#{@user.to_reference}) must accept the Terms of Service in order to perform this action. "\
+ "Please access GitLab from a web browser to accept these terms."
else
- 'Your account has been blocked.'
+ "Your account has been blocked."
end
end
diff --git a/lib/gitlab/database/count.rb b/lib/gitlab/database/count.rb
index 3374203960e..5f549ed2b3c 100644
--- a/lib/gitlab/database/count.rb
+++ b/lib/gitlab/database/count.rb
@@ -17,31 +17,69 @@ module Gitlab
].freeze
end
- def self.approximate_count(model)
- return model.count unless Gitlab::Database.postgresql?
+ # Takes in an array of models and returns a Hash for the approximate
+ # counts for them. If the model's table has not been vacuumed or
+ # analyzed recently, simply run the Model.count to get the data.
+ #
+ # @param [Array]
+ # @return [Hash] of Model -> count mapping
+ def self.approximate_counts(models)
+ table_to_model_map = models.each_with_object({}) do |model, hash|
+ hash[model.table_name] = model
+ end
- execute_estimate_if_updated_recently(model) || model.count
- end
+ table_names = table_to_model_map.keys
+ counts_by_table_name = Gitlab::Database.postgresql? ? reltuples_from_recently_updated(table_names) : {}
- def self.execute_estimate_if_updated_recently(model)
- ActiveRecord::Base.connection.select_value(postgresql_estimate_query(model)).to_i if reltuples_updated_recently?(model)
- rescue *CONNECTION_ERRORS
+ # Convert table -> count to Model -> count
+ counts_by_model = counts_by_table_name.each_with_object({}) do |pair, hash|
+ model = table_to_model_map[pair.first]
+ hash[model] = pair.second
+ end
+
+ missing_tables = table_names - counts_by_table_name.keys
+
+ missing_tables.each do |table|
+ model = table_to_model_map[table]
+ counts_by_model[model] = model.count
+ end
+
+ counts_by_model
end
- def self.reltuples_updated_recently?(model)
- time = "to_timestamp(#{1.hour.ago.to_i})"
- query = <<~SQL
- SELECT 1 FROM pg_stat_user_tables WHERE relname = '#{model.table_name}' AND
- (last_vacuum > #{time} OR last_autovacuum > #{time} OR last_analyze > #{time} OR last_autoanalyze > #{time})
- SQL
+ # Returns a hash of the table names that have recently updated tuples.
+ #
+ # @param [Array] table names
+ # @returns [Hash] Table name to count mapping (e.g. { 'projects' => 5, 'users' => 100 })
+ def self.reltuples_from_recently_updated(table_names)
+ query = postgresql_estimate_query(table_names)
+ rows = []
- ActiveRecord::Base.connection.select_all(query).count > 0
+ # Querying tuple stats only works on the primary. Due to load
+ # balancing, we need to ensure this query hits the load balancer. The
+ # easiest way to do this is to start a transaction.
+ ActiveRecord::Base.transaction do
+ rows = ActiveRecord::Base.connection.select_all(query)
+ end
+
+ rows.each_with_object({}) { |row, data| data[row['table_name']] = row['estimate'].to_i }
rescue *CONNECTION_ERRORS
- false
+ {}
end
- def self.postgresql_estimate_query(model)
- "SELECT reltuples::bigint AS estimate FROM pg_class where relname = '#{model.table_name}'"
+ # Generates the PostgreSQL query to return the tuples for tables
+ # that have been vacuumed or analyzed in the last hour.
+ #
+ # @param [Array] table names
+ # @returns [Hash] Table name to count mapping (e.g. { 'projects' => 5, 'users' => 100 })
+ def self.postgresql_estimate_query(table_names)
+ time = "to_timestamp(#{1.hour.ago.to_i})"
+ <<~SQL
+ SELECT pg_class.relname AS table_name, reltuples::bigint AS estimate FROM pg_class
+ LEFT JOIN pg_stat_user_tables ON pg_class.relname = pg_stat_user_tables.relname
+ WHERE pg_class.relname IN (#{table_names.map { |table| "'#{table}'" }.join(',')})
+ AND (last_vacuum > #{time} OR last_autovacuum > #{time} OR last_analyze > #{time} OR last_autoanalyze > #{time})
+ SQL
end
end
end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 014854da55c..765fb0289a8 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -76,6 +76,13 @@ module Gitlab
line_code(line) if line
end
+ # Returns the raw diff content up to the given line index
+ def diff_hunk(diff_line)
+ # Adding 2 because of the @@ diff header and Enum#take should consider
+ # an extra line, because we're passing an index.
+ raw_diff.each_line.take(diff_line.index + 2).join
+ end
+
def old_sha
diff_refs&.base_sha
end
diff --git a/lib/gitlab/gitaly_client/storage_service.rb b/lib/gitlab/gitaly_client/storage_service.rb
new file mode 100644
index 00000000000..eb0e910665b
--- /dev/null
+++ b/lib/gitlab/gitaly_client/storage_service.rb
@@ -0,0 +1,15 @@
+module Gitlab
+ module GitalyClient
+ class StorageService
+ def initialize(storage)
+ @storage = storage
+ end
+
+ # Delete all repositories in the storage. This is a slow and VERY DESTRUCTIVE operation.
+ def delete_all_repositories
+ request = Gitaly::DeleteAllRepositoriesRequest.new(storage_name: @storage)
+ GitalyClient.call(@storage, :storage_service, :delete_all_repositories, request)
+ end
+ end
+ end
+end
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
index a44243ac82d..023bedaaebb 100644
--- a/spec/lib/backup/repository_spec.rb
+++ b/spec/lib/backup/repository_spec.rb
@@ -71,6 +71,40 @@ describe Backup::Repository do
end
end
+ describe '#delete_all_repositories', :seed_helper do
+ shared_examples('delete_all_repositories') do
+ before do
+ allow(FileUtils).to receive(:mkdir_p).and_call_original
+ allow(FileUtils).to receive(:mv).and_call_original
+ end
+
+ after(:all) do
+ ensure_seeds
+ end
+
+ it 'removes all repositories' do
+ # Sanity check: there should be something for us to delete
+ expect(list_repositories).to include(File.join(SEED_STORAGE_PATH, TEST_REPO_PATH))
+
+ subject.delete_all_repositories('default', Gitlab.config.repositories.storages['default'])
+
+ expect(list_repositories).to be_empty
+ end
+
+ def list_repositories
+ Dir[SEED_STORAGE_PATH + '/*.git']
+ end
+ end
+
+ context 'with gitaly' do
+ it_behaves_like 'delete_all_repositories'
+ end
+
+ context 'without gitaly', :skip_gitaly_mock do
+ it_behaves_like 'delete_all_repositories'
+ end
+ end
+
describe '#empty_repo?' do
context 'for a wiki' do
let(:wiki) { create(:project_wiki) }
diff --git a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
index fa209bed74e..002ce776be9 100644
--- a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
+++ b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
@@ -22,7 +22,8 @@ describe Gitlab::Auth::UserAccessDeniedReason do
enforce_terms
end
- it { is_expected.to match /You must accept the Terms of Service/ }
+ it { is_expected.to match /must accept the Terms of Service/ }
+ it { is_expected.to include(user.username) }
end
context 'when the user is internal' do
diff --git a/spec/lib/gitlab/database/count_spec.rb b/spec/lib/gitlab/database/count_spec.rb
index 9d9caaabe16..407d9470785 100644
--- a/spec/lib/gitlab/database/count_spec.rb
+++ b/spec/lib/gitlab/database/count_spec.rb
@@ -3,59 +3,68 @@ require 'spec_helper'
describe Gitlab::Database::Count do
before do
create_list(:project, 3)
+ create(:identity)
end
- describe '.execute_estimate_if_updated_recently', :postgresql do
- context 'when reltuples have not been updated' do
- before do
- expect(described_class).to receive(:reltuples_updated_recently?).and_return(false)
- end
+ let(:models) { [Project, Identity] }
- it 'returns nil' do
- expect(described_class.execute_estimate_if_updated_recently(Project)).to be nil
- end
- end
+ describe '.approximate_counts' do
+ context 'with MySQL' do
+ context 'when reltuples have not been updated' do
+ it 'counts all models the normal way' do
+ expect(Gitlab::Database).to receive(:postgresql?).and_return(false)
- context 'when reltuples have been updated' do
- before do
- ActiveRecord::Base.connection.execute('ANALYZE projects')
- end
+ expect(Project).to receive(:count).and_call_original
+ expect(Identity).to receive(:count).and_call_original
- it 'calls postgresql_estimate_query' do
- expect(described_class).to receive(:postgresql_estimate_query).with(Project).and_call_original
- expect(described_class.execute_estimate_if_updated_recently(Project)).to eq(3)
+ expect(described_class.approximate_counts(models)).to eq({ Project => 3, Identity => 1 })
+ end
end
end
- end
- describe '.approximate_count' do
- context 'when reltuples have not been updated' do
- it 'counts all projects the normal way' do
- allow(described_class).to receive(:reltuples_updated_recently?).and_return(false)
+ context 'with PostgreSQL', :postgresql do
+ describe 'when reltuples have not been updated' do
+ it 'counts all models the normal way' do
+ expect(described_class).to receive(:reltuples_from_recently_updated).with(%w(projects identities)).and_return({})
- expect(Project).to receive(:count).and_call_original
- expect(described_class.approximate_count(Project)).to eq(3)
+ expect(Project).to receive(:count).and_call_original
+ expect(Identity).to receive(:count).and_call_original
+ expect(described_class.approximate_counts(models)).to eq({ Project => 3, Identity => 1 })
+ end
end
- end
- context 'no permission' do
- it 'falls back to standard query' do
- allow(described_class).to receive(:reltuples_updated_recently?).and_raise(PG::InsufficientPrivilege)
+ describe 'no permission' do
+ it 'falls back to standard query' do
+ allow(described_class).to receive(:postgresql_estimate_query).and_raise(PG::InsufficientPrivilege)
- expect(Project).to receive(:count).and_call_original
- expect(described_class.approximate_count(Project)).to eq(3)
+ expect(Project).to receive(:count).and_call_original
+ expect(Identity).to receive(:count).and_call_original
+ expect(described_class.approximate_counts(models)).to eq({ Project => 3, Identity => 1 })
+ end
end
- end
- describe 'when reltuples have been updated', :postgresql do
- before do
- ActiveRecord::Base.connection.execute('ANALYZE projects')
+ describe 'when some reltuples have been updated' do
+ it 'counts projects in the fast way' do
+ expect(described_class).to receive(:reltuples_from_recently_updated).with(%w(projects identities)).and_return({ 'projects' => 3 })
+
+ expect(Project).not_to receive(:count).and_call_original
+ expect(Identity).to receive(:count).and_call_original
+ expect(described_class.approximate_counts(models)).to eq({ Project => 3, Identity => 1 })
+ end
end
- it 'counts all projects in the fast way' do
- expect(described_class).to receive(:postgresql_estimate_query).with(Project).and_call_original
+ describe 'when all reltuples have been updated' do
+ before do
+ ActiveRecord::Base.connection.execute('ANALYZE projects')
+ ActiveRecord::Base.connection.execute('ANALYZE identities')
+ end
+
+ it 'counts models with the standard way' do
+ expect(Project).not_to receive(:count)
+ expect(Identity).not_to receive(:count)
- expect(described_class.approximate_count(Project)).to eq(3)
+ expect(described_class.approximate_counts(models)).to eq({ Project => 3, Identity => 1 })
+ end
end
end
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 0c2e18c268a..0588fe935c3 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -468,4 +468,58 @@ describe Gitlab::Diff::File do
end
end
end
+
+ describe '#diff_hunk' do
+ let(:raw_diff) do
+ <<EOS
+@@ -6,12 +6,18 @@ module Popen
+
+ def popen(cmd, path=nil)
+ unless cmd.is_a?(Array)
+- raise "System commands must be given as an array of strings"
++ raise RuntimeError, "System commands must be given as an array of strings"
+ end
+
+ path ||= Dir.pwd
+- vars = { "PWD" => path }
+- options = { chdir: path }
++
++ vars = {
++ "PWD" => path
++ }
++
++ options = {
++ chdir: path
++ }
+
+ unless File.directory?(path)
+ FileUtils.mkdir_p(path)
+@@ -19,6 +25,7 @@ module Popen
+
+ @cmd_output = ""
+ @cmd_status = 0
++
+ Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
+ @cmd_output << stdout.read
+ @cmd_output << stderr.read
+EOS
+ end
+
+ it 'returns raw diff up to given line index' do
+ allow(diff_file).to receive(:raw_diff) { raw_diff }
+ diff_line = instance_double(Gitlab::Diff::Line, index: 5)
+
+ diff_hunk = <<EOS
+@@ -6,12 +6,18 @@ module Popen
+
+ def popen(cmd, path=nil)
+ unless cmd.is_a?(Array)
+- raise "System commands must be given as an array of strings"
++ raise RuntimeError, "System commands must be given as an array of strings"
+ end
+EOS
+
+ expect(diff_file.diff_hunk(diff_line)).to eq(diff_hunk)
+ end
+ end
end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 317a932d5a6..dfffea7797f 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -1055,7 +1055,7 @@ describe Gitlab::GitAccess do
it 'blocks access when the user did not accept terms', :aggregate_failures do
actions.each do |action|
- expect { action.call }.to raise_unauthorized(/You must accept the Terms of Service in order to perform this action/)
+ expect { action.call }.to raise_unauthorized(/must accept the Terms of Service in order to perform this action/)
end
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 8b46b04b8b5..fb5fd300dbb 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -35,6 +35,7 @@ notes:
- todos
- events
- system_note_metadata
+- note_diff_file
label_links:
- target
- label
diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb
index 30572ce9332..8cd129dc851 100644
--- a/spec/models/concerns/discussion_on_diff_spec.rb
+++ b/spec/models/concerns/discussion_on_diff_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe DiscussionOnDiff do
- subject { create(:diff_note_on_merge_request).to_discussion }
+ subject { create(:diff_note_on_merge_request, line_number: 18).to_discussion }
describe "#truncated_diff_lines" do
let(:truncated_lines) { subject.truncated_diff_lines }
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index fb51c0172ab..8624f0daa4d 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -84,7 +84,47 @@ describe DiffNote do
end
end
- describe "#diff_file" do
+ describe '#create_diff_file callback' do
+ let(:noteable) { create(:merge_request) }
+ let(:project) { noteable.project }
+
+ context 'merge request' do
+ let!(:diff_note) { create(:diff_note_on_merge_request, project: project, noteable: noteable) }
+
+ it 'creates a diff note file' do
+ expect(diff_note.reload.note_diff_file).to be_present
+ end
+
+ it 'does not create diff note file if it is a reply' do
+ expect { create(:diff_note_on_merge_request, noteable: noteable, in_reply_to: diff_note) }
+ .not_to change(NoteDiffFile, :count)
+ end
+ end
+
+ context 'commit' do
+ let!(:diff_note) { create(:diff_note_on_commit, project: project) }
+
+ it 'creates a diff note file' do
+ expect(diff_note.reload.note_diff_file).to be_present
+ end
+
+ it 'does not create diff note file if it is a reply' do
+ expect { create(:diff_note_on_commit, in_reply_to: diff_note) }
+ .not_to change(NoteDiffFile, :count)
+ end
+ end
+ end
+
+ describe '#diff_file', :clean_gitlab_redis_shared_state do
+ context 'when note_diff_file association exists' do
+ it 'returns persisted diff file data' do
+ diff_file = subject.diff_file
+
+ expect(diff_file.diff.to_hash.with_indifferent_access)
+ .to include(subject.note_diff_file.to_hash)
+ end
+ end
+
context 'when the discussion was created in the diff' do
it 'returns correct diff file' do
diff_file = subject.diff_file
@@ -115,6 +155,26 @@ describe DiffNote do
expect(diff_file.diff_refs).to eq(position.diff_refs)
end
end
+
+ context 'note diff file creation enqueuing' do
+ it 'enqueues CreateNoteDiffFileWorker if it is the first note of a discussion' do
+ subject.note_diff_file.destroy!
+
+ expect(CreateNoteDiffFileWorker).to receive(:perform_async).with(subject.id)
+
+ subject.reload.diff_file
+ end
+
+ it 'does not enqueues CreateNoteDiffFileWorker if not first note of a discussion' do
+ mr = create(:merge_request)
+ diff_note = create(:diff_note_on_merge_request, project: mr.project, noteable: mr)
+ reply_diff_note = create(:diff_note_on_merge_request, in_reply_to: diff_note)
+
+ expect(CreateNoteDiffFileWorker).not_to receive(:perform_async).with(reply_diff_note.id)
+
+ reply_diff_note.reload.diff_file
+ end
+ end
end
describe "#diff_line" do
diff --git a/spec/models/note_diff_file_spec.rb b/spec/models/note_diff_file_spec.rb
new file mode 100644
index 00000000000..591c1a89748
--- /dev/null
+++ b/spec/models/note_diff_file_spec.rb
@@ -0,0 +1,11 @@
+require 'rails_helper'
+
+describe NoteDiffFile do
+ describe 'associations' do
+ it { is_expected.to belong_to(:diff_note) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:diff_note) }
+ end
+end
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index d3ab44c0d7e..d8a51f36dba 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -171,7 +171,7 @@ describe API::Helpers do
end
it 'returns a 403 when a user has not accepted the terms' do
- expect { current_user }.to raise_error /You must accept the Terms of Service/
+ expect { current_user }.to raise_error /must accept the Terms of Service/
end
it 'sets the current user when the user accepted the terms' do
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index db8c5f963d6..5dc3ddd4b36 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
describe API::Internal do
- let(:user) { create(:user) }
+ set(:user) { create(:user) }
let(:key) { create(:key, user: user) }
- let(:project) { create(:project, :repository, :wiki_repo) }
+ set(:project) { create(:project, :repository, :wiki_repo) }
let(:secret_token) { Gitlab::Shell.secret_token }
let(:gl_repository) { "project-#{project.id}" }
let(:reference_counter) { double('ReferenceCounter') }
@@ -277,7 +277,7 @@ describe API::Internal do
expect(response).to have_gitlab_http_status(200)
expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo)
+ expect(json_response["repository_path"]).to eq('/')
expect(json_response["gl_repository"]).to eq("wiki-#{project.id}")
expect(user).not_to have_an_activity_record
end
@@ -289,7 +289,7 @@ describe API::Internal do
expect(response).to have_gitlab_http_status(200)
expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo)
+ expect(json_response["repository_path"]).to eq('/')
expect(json_response["gl_repository"]).to eq("wiki-#{project.id}")
expect(user).to have_an_activity_record
end
@@ -301,7 +301,7 @@ describe API::Internal do
expect(response).to have_gitlab_http_status(200)
expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
+ expect(json_response["repository_path"]).to eq('/')
expect(json_response["gl_repository"]).to eq("project-#{project.id}")
expect(json_response["gitaly"]).not_to be_nil
expect(json_response["gitaly"]["repository"]).not_to be_nil
@@ -320,7 +320,7 @@ describe API::Internal do
expect(response).to have_gitlab_http_status(200)
expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
+ expect(json_response["repository_path"]).to eq('/')
expect(json_response["gl_repository"]).to eq("project-#{project.id}")
expect(json_response["gitaly"]).not_to be_nil
expect(json_response["gitaly"]["repository"]).not_to be_nil
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index efb9bddde44..827c6dd4af1 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -830,6 +830,21 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
end
+ context 'when job has already been finished' do
+ before do
+ job.trace.set('Job failed')
+ job.drop!(:script_failure)
+ end
+
+ it 'does not update job status and job trace' do
+ update_job(state: 'success', trace: 'BUILD TRACE UPDATED')
+
+ expect(response).to have_gitlab_http_status(403)
+ expect(job.trace.raw).to eq 'Job failed'
+ expect(job).to be_failed
+ end
+ end
+
def update_job(token = job.token, **params)
new_params = params.merge(token: token)
put api("/jobs/#{job.id}"), new_params
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index f5cff66de6d..2b2b983494f 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -57,6 +57,88 @@ describe Notes::CreateService do
end
end
+ context 'note diff file' do
+ let(:project_with_repo) { create(:project, :repository) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: project_with_repo,
+ target_project: project_with_repo)
+ end
+ let(:line_number) { 14 }
+ let(:position) do
+ Gitlab::Diff::Position.new(old_path: "files/ruby/popen.rb",
+ new_path: "files/ruby/popen.rb",
+ old_line: nil,
+ new_line: line_number,
+ diff_refs: merge_request.diff_refs)
+ end
+ let(:previous_note) do
+ create(:diff_note_on_merge_request, noteable: merge_request, project: project_with_repo)
+ end
+
+ context 'when eligible to have a note diff file' do
+ let(:new_opts) do
+ opts.merge(in_reply_to_discussion_id: nil,
+ type: 'DiffNote',
+ noteable_type: 'MergeRequest',
+ noteable_id: merge_request.id,
+ position: position.to_h)
+ end
+
+ it 'note is associated with a note diff file' do
+ note = described_class.new(project_with_repo, user, new_opts).execute
+
+ expect(note).to be_persisted
+ expect(note.note_diff_file).to be_present
+ end
+ end
+
+ context 'when DiffNote is a reply' do
+ let(:new_opts) do
+ opts.merge(in_reply_to_discussion_id: previous_note.discussion_id,
+ type: 'DiffNote',
+ noteable_type: 'MergeRequest',
+ noteable_id: merge_request.id,
+ position: position.to_h)
+ end
+
+ it 'note is not associated with a note diff file' do
+ note = described_class.new(project_with_repo, user, new_opts).execute
+
+ expect(note).to be_persisted
+ expect(note.note_diff_file).to be_nil
+ end
+
+ context 'when DiffNote from an image' do
+ let(:image_position) do
+ Gitlab::Diff::Position.new(old_path: "files/images/6049019_460s.jpg",
+ new_path: "files/images/6049019_460s.jpg",
+ width: 100,
+ height: 100,
+ x: 1,
+ y: 100,
+ diff_refs: merge_request.diff_refs,
+ position_type: 'image')
+ end
+
+ let(:new_opts) do
+ opts.merge(in_reply_to_discussion_id: nil,
+ type: 'DiffNote',
+ noteable_type: 'MergeRequest',
+ noteable_id: merge_request.id,
+ position: image_position.to_h)
+ end
+
+ it 'note is not associated with a note diff file' do
+ note = described_class.new(project_with_repo, user, new_opts).execute
+
+ expect(note).to be_persisted
+ expect(note.note_diff_file).to be_nil
+ end
+ end
+ end
+ end
+
context 'note with commands' do
context 'as a user who can update the target' do
context '/close, /label, /assign & /milestone' do
diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb
index 59c777ea338..0e8b7c82d3a 100644
--- a/spec/views/admin/dashboard/index.html.haml_spec.rb
+++ b/spec/views/admin/dashboard/index.html.haml_spec.rb
@@ -4,6 +4,11 @@ describe 'admin/dashboard/index.html.haml' do
include Devise::Test::ControllerHelpers
before do
+ counts = Admin::DashboardController::COUNTED_ITEMS.each_with_object({}) do |item, hash|
+ hash[item] = 100
+ end
+
+ assign(:counts, counts)
assign(:projects, create_list(:project, 1))
assign(:users, create_list(:user, 1))
assign(:groups, create_list(:group, 1))
diff --git a/spec/workers/create_note_diff_file_worker_spec.rb b/spec/workers/create_note_diff_file_worker_spec.rb
new file mode 100644
index 00000000000..0ac946a1232
--- /dev/null
+++ b/spec/workers/create_note_diff_file_worker_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+describe CreateNoteDiffFileWorker do
+ describe '#perform' do
+ let(:diff_note) { create(:diff_note_on_merge_request) }
+
+ it 'creates diff file' do
+ diff_note.note_diff_file.destroy!
+
+ expect_any_instance_of(DiffNote).to receive(:create_diff_file)
+ .and_call_original
+
+ described_class.new.perform(diff_note.id)
+ end
+ end
+end
diff --git a/yarn.lock b/yarn.lock
index af8785bbc66..4925fa8f373 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -385,14 +385,10 @@ ast-types@0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd"
-ast-types@0.11.3:
+ast-types@0.11.3, ast-types@0.x.x:
version "0.11.3"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8"
-ast-types@0.x.x:
- version "0.11.1"
- resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.1.tgz#5bb3a8d5ba292c3f4ae94d46df37afc30300b990"
-
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@@ -405,18 +401,12 @@ async@1.x, async@^1.4.0, async@^1.5.0, async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
-async@^2.0.0, async@^2.6.0:
+async@^2.0.0, async@^2.1.4, async@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
dependencies:
lodash "^4.14.0"
-async@^2.1.4:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
- dependencies:
- lodash "^4.14.0"
-
async@~2.1.2:
version "2.1.5"
resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc"
@@ -1581,7 +1571,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies:
@@ -1589,14 +1579,6 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^2.3.2:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52"
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
chalk@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
@@ -1775,14 +1757,10 @@ clone-stats@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
-clone@^1.0.0:
+clone@^1.0.0, clone@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f"
-clone@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
-
clone@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb"
@@ -2572,11 +2550,7 @@ di@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
-diff@^3.3.1, diff@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c"
-
-diff@^3.5.0:
+diff@^3.3.1, diff@^3.4.0, diff@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@@ -2716,11 +2690,7 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
-ejs@^2.5.7:
- version "2.5.7"
- resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.7.tgz#cc872c168880ae3c7189762fd5ffc00896c9518a"
-
-ejs@^2.5.9:
+ejs@^2.5.7, ejs@^2.5.9:
version "2.5.9"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5"
@@ -3319,14 +3289,6 @@ extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
-external-editor@^2.0.4:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48"
- dependencies:
- chardet "^0.4.0"
- iconv-lite "^0.4.17"
- tmp "^0.0.33"
-
external-editor@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
@@ -3779,18 +3741,7 @@ glob@^5.0.15:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.0, glob@^7.0.3:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.2"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.0.5, glob@^7.1.1, glob@^7.1.2:
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
@@ -3865,7 +3816,7 @@ globby@^7.1.1:
pify "^3.0.0"
slash "^1.0.0"
-globby@^8.0.0:
+globby@^8.0.0, globby@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50"
dependencies:
@@ -4032,10 +3983,6 @@ has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
-has-flag@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
-
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -4404,26 +4351,7 @@ inquirer@^0.12.0:
strip-ansi "^3.0.0"
through "^2.3.6"
-inquirer@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
- dependencies:
- ansi-escapes "^3.0.0"
- chalk "^2.0.0"
- cli-cursor "^2.1.0"
- cli-width "^2.0.0"
- external-editor "^2.0.4"
- figures "^2.0.0"
- lodash "^4.3.0"
- mute-stream "0.0.7"
- run-async "^2.2.0"
- rx-lite "^4.0.8"
- rx-lite-aggregates "^4.0.8"
- string-width "^2.1.0"
- strip-ansi "^4.0.0"
- through "^2.3.6"
-
-inquirer@^5.1.0:
+inquirer@^5.1.0, inquirer@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726"
dependencies:
@@ -4447,11 +4375,7 @@ internal-ip@1.2.0:
dependencies:
meow "^3.3.0"
-interpret@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
-
-interpret@^1.0.4:
+interpret@^1.0.0, interpret@^1.0.4:
version "1.1.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
@@ -4868,7 +4792,7 @@ istanbul-lib-hook@^1.1.0:
dependencies:
append-transform "^0.4.0"
-istanbul-lib-instrument@^1.10.1:
+istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.9.1:
version "1.10.1"
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b"
dependencies:
@@ -4880,18 +4804,6 @@ istanbul-lib-instrument@^1.10.1:
istanbul-lib-coverage "^1.2.0"
semver "^5.3.0"
-istanbul-lib-instrument@^1.9.1:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.1.tgz#250b30b3531e5d3251299fdd64b0b2c9db6b558e"
- dependencies:
- babel-generator "^6.18.0"
- babel-template "^6.16.0"
- babel-traverse "^6.18.0"
- babel-types "^6.18.0"
- babylon "^6.18.0"
- istanbul-lib-coverage "^1.1.1"
- semver "^5.3.0"
-
istanbul-lib-report@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.2.tgz#922be27c13b9511b979bd1587359f69798c1d425"
@@ -5455,11 +5367,7 @@ lodash@4.17.4:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
-lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0:
- version "4.17.5"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
-
-lodash@^4.17.10:
+lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0:
version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
@@ -5469,13 +5377,7 @@ log-symbols@^1.0.2:
dependencies:
chalk "^1.0.0"
-log-symbols@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.1.0.tgz#f35fa60e278832b538dc4dddcbb478a45d3e3be6"
- dependencies:
- chalk "^2.0.1"
-
-log-symbols@^2.2.0:
+log-symbols@^2.1.0, log-symbols@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
dependencies:
@@ -5548,14 +5450,7 @@ lru-cache@2.2.x:
version "2.2.4"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
-lru-cache@^4.0.1, lru-cache@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
- dependencies:
- pseudomap "^1.0.2"
- yallist "^2.1.2"
-
-lru-cache@^4.1.2:
+lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2:
version "4.1.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
dependencies:
@@ -5591,13 +5486,7 @@ mailgun-js@^0.7.0:
q "~1.4.0"
tsscmp "~1.0.0"
-make-dir@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978"
- dependencies:
- pify "^2.3.0"
-
-make-dir@^1.1.0:
+make-dir@^1.0.0, make-dir@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b"
dependencies:
@@ -5736,7 +5625,7 @@ micromatch@^2.1.5, micromatch@^2.3.7:
parse-glob "^3.0.4"
regex-cache "^0.4.2"
-micromatch@^3.1.10, micromatch@^3.1.9:
+micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
dependencies:
@@ -5754,42 +5643,6 @@ micromatch@^3.1.10, micromatch@^3.1.9:
snapdragon "^0.8.1"
to-regex "^3.0.2"
-micromatch@^3.1.4:
- version "3.1.6"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.6.tgz#8d7c043b48156f408ca07a4715182b79b99420bf"
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- braces "^2.3.1"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- extglob "^2.0.4"
- fragment-cache "^0.2.1"
- kind-of "^6.0.2"
- nanomatch "^1.2.9"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-micromatch@^3.1.8:
- version "3.1.9"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89"
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- braces "^2.3.1"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- extglob "^2.0.4"
- fragment-cache "^0.2.1"
- kind-of "^6.0.2"
- nanomatch "^1.2.9"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -5815,14 +5668,10 @@ mime@^1.3.4:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
-mime@^2.0.3:
+mime@^2.0.3, mime@^2.1.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369"
-mime@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.2.0.tgz#161e541965551d3b549fa1114391e3a3d55b923b"
-
mimic-fn@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
@@ -6926,15 +6775,7 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0
source-map "^0.5.6"
supports-color "^3.2.3"
-postcss@^6.0.1, postcss@^6.0.14:
- version "6.0.19"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.19.tgz#76a78386f670b9d9494a655bf23ac012effd1555"
- dependencies:
- chalk "^2.3.1"
- source-map "^0.6.1"
- supports-color "^5.2.0"
-
-postcss@^6.0.20:
+postcss@^6.0.1, postcss@^6.0.14, postcss@^6.0.20:
version "6.0.22"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.22.tgz#e23b78314905c3b90cbd61702121e7a78848f2a3"
dependencies:
@@ -6962,14 +6803,10 @@ prettier@1.11.1:
version "1.11.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75"
-prettier@^1.11.1:
+prettier@^1.11.1, prettier@^1.5.3:
version "1.12.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325"
-prettier@^1.5.3:
- version "1.10.2"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.10.2.tgz#1af8356d1842276a99a5b5529c82dd9e9ad3cc93"
-
pretty-bytes@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
@@ -7615,18 +7452,12 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"
-rimraf@2, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2:
+rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
glob "^7.0.5"
-rimraf@^2.2.8:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
- dependencies:
- glob "^7.0.5"
-
rimraf@~2.2.6:
version "2.2.8"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
@@ -7656,16 +7487,6 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
-rx-lite-aggregates@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
- dependencies:
- rx-lite "*"
-
-rx-lite@*, rx-lite@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
-
rx-lite@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
@@ -7737,11 +7558,7 @@ semver-diff@^2.0.0:
dependencies:
semver "^5.0.3"
-"semver@2 || 3 || 4 || 5", semver@^5.0.3:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
-
-semver@^5.1.0, semver@^5.3.0, semver@^5.5.0:
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
@@ -8075,11 +7892,7 @@ source-map@^0.4.4:
dependencies:
amdefine ">=0.0.4"
-source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1:
- version "0.5.6"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
-
-source-map@^0.5.7, source-map@~0.5.3, source-map@~0.5.6:
+source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@@ -8346,19 +8159,7 @@ supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3:
dependencies:
has-flag "^1.0.0"
-supports-color@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.1.0.tgz#058a021d1b619f7ddf3980d712ea3590ce7de3d5"
- dependencies:
- has-flag "^2.0.0"
-
-supports-color@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a"
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^5.3.0, supports-color@^5.4.0:
+supports-color@^5.1.0, supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
dependencies:
@@ -8555,15 +8356,7 @@ to-regex-range@^2.1.0:
is-number "^3.0.0"
repeat-string "^1.6.1"
-to-regex@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.1.tgz#15358bee4a2c83bd76377ba1dc049d0f18837aae"
- dependencies:
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- regex-not "^1.0.0"
-
-to-regex@^3.0.2:
+to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
dependencies:
@@ -9149,7 +8942,7 @@ webpack-dev-server@^3.1.4:
webpack-log "^1.1.2"
yargs "11.0.0"
-webpack-log@^1.0.1:
+webpack-log@^1.0.1, webpack-log@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d"
dependencies:
@@ -9158,23 +8951,7 @@ webpack-log@^1.0.1:
loglevelnext "^1.0.1"
uuid "^3.1.0"
-webpack-log@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.1.2.tgz#cdc76016537eed24708dc6aa3d1e52189efee107"
- dependencies:
- chalk "^2.1.0"
- log-symbols "^2.1.0"
- loglevelnext "^1.0.1"
- uuid "^3.1.0"
-
-webpack-sources@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf"
- dependencies:
- source-list-map "^2.0.0"
- source-map "~0.5.3"
-
-webpack-sources@^1.1.0:
+webpack-sources@^1.0.1, webpack-sources@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"
dependencies:
@@ -9415,39 +9192,23 @@ yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
-yeoman-environment@^2.0.0:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.5.tgz#84f22bafa84088971fe99ea85f654a3a3dd2b693"
- dependencies:
- chalk "^2.1.0"
- debug "^3.1.0"
- diff "^3.3.1"
- escape-string-regexp "^1.0.2"
- globby "^6.1.0"
- grouped-queue "^0.3.3"
- inquirer "^3.3.0"
- is-scoped "^1.0.0"
- lodash "^4.17.4"
- log-symbols "^2.1.0"
- mem-fs "^1.1.0"
- text-table "^0.2.0"
- untildify "^3.0.2"
-
-yeoman-environment@^2.0.5:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.6.tgz#ae1b21d826b363f3d637f88a7fc9ea7414cb5377"
+yeoman-environment@^2.0.0, yeoman-environment@^2.0.5:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.1.1.tgz#10a045f7fc4397873764882eae055a33e56ee1c5"
dependencies:
chalk "^2.1.0"
+ cross-spawn "^6.0.5"
debug "^3.1.0"
diff "^3.3.1"
escape-string-regexp "^1.0.2"
- globby "^6.1.0"
+ globby "^8.0.1"
grouped-queue "^0.3.3"
- inquirer "^3.3.0"
+ inquirer "^5.2.0"
is-scoped "^1.0.0"
- lodash "^4.17.4"
+ lodash "^4.17.10"
log-symbols "^2.1.0"
mem-fs "^1.1.0"
+ strip-ansi "^4.0.0"
text-table "^0.2.0"
untildify "^3.0.2"